Skip to content

Commit

Permalink
Merge branch 'dev' into feat#59/adiciona-requestButton
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielCostaDeOliveira committed Jan 10, 2025
2 parents c3105bc + 3d334cb commit b9998c3
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 181 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/code-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ jobs:
restore-keys: ${{ runner.os }}-sonar
- name: Build
run: flutter build
- name: Execute tests
run: flutter test --coverage
- name: Download sonar-scanner
run: |
curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.1.4610-linux-x64.zip
unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- name: Execute tests
run: |
flutter test --coverage
ls coverage/
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
Expand Down
3 changes: 1 addition & 2 deletions lib/ui/home/view/HomeView.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ class HomeView extends StatelessWidget {

@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
return const Text('Home', style: TextStyle(fontSize: 20));
}


Expand Down
111 changes: 52 additions & 59 deletions lib/ui/login/view/login_view.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:aranduapp/core/log/Log.dart';
import 'package:aranduapp/ui/navbar/view/navBarView.dart';
import 'package:aranduapp/ui/shared/TextAndLink.dart';
import 'package:aranduapp/ui/shared/requestbutton.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
Expand All @@ -21,61 +23,49 @@ class Login extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => LoginViewModel(context),
create: (context) => LoginViewModel(),
child: const LoginScreen(),
);
}
}

class LoginScreen extends StatefulWidget {
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});

@override
State<StatefulWidget> createState() {
return _LoginScreenState();
}
}

class _LoginScreenState extends State<LoginScreen> {
late Future<void> _future;

@override
void initState() {
super.initState();
_future =
Provider.of<LoginViewModel>(context, listen: false).validateToken();
}

@override
Widget build(BuildContext context) {
LoginViewModel viewModel = Provider.of<LoginViewModel>(context);

return Scaffold(
body: FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return _loadingScreen(viewModel);
} else if (!snapshot.hasError) {
return _authDevice(viewModel);
} else {
return _emailAndPassword(viewModel);
}
}));
body: ListenableBuilder(
listenable: viewModel.validadeTokenCommand,
builder: (context, child) {
if (viewModel.validadeTokenCommand.isOk) {
return _authDevice(viewModel, context);
} else if (viewModel.validadeTokenCommand.isError) {
return _emailAndPassword(viewModel, context);
} else {
return _loadingScreen(viewModel, context);
}
},
),
);
}

Widget _loadingScreen(LoginViewModel viewModel) {
Widget _loadingScreen(LoginViewModel viewModel, BuildContext context) {
return const Center(
child: CircularProgressIndicator(value: null),
);
}

Widget _authDevice(LoginViewModel viewModel) {
Widget _authDevice(LoginViewModel viewModel, BuildContext context) {
Log.d("Mostrando tela de autorização do dispositivo");

viewModel.loginWithDeviceAuth().then((ok) {
if (ok) {
viewModel.goToHome();
WidgetsBinding.instance.addPostFrameCallback((_) {
goToNavbar(context);
});
}
});

Expand All @@ -99,7 +89,9 @@ class _LoginScreenState extends State<LoginScreen> {
child: ElevatedButton(
onPressed: () async {
viewModel.loginWithDeviceAuth().then((ok) {
viewModel.goToHome();
WidgetsBinding.instance.addPostFrameCallback((_) {
goToNavbar(context);
});
});
},
child: const Text('Usar senha do celular'),
Expand All @@ -110,7 +102,7 @@ class _LoginScreenState extends State<LoginScreen> {
);
}

Widget _emailAndPassword(LoginViewModel viewModel) {
Widget _emailAndPassword(LoginViewModel viewModel, BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
Expand All @@ -120,11 +112,11 @@ class _LoginScreenState extends State<LoginScreen> {
const SizedBox(height: 80),
const SizedBox(height: 10),
_formSection(viewModel),
_forgotPasswordLink(),
_forgotPasswordLink(context),
const SizedBox(height: 80),
_loginButtonSection(),
_loginButtonSection(context),
const OrDivider(),
_loggingInWithOther(),
_loggingInWithOther(context),
TextAndLink(
text: 'É novo pro aqui?',
link: 'Cria a sua conta',
Expand Down Expand Up @@ -157,7 +149,7 @@ class _LoginScreenState extends State<LoginScreen> {
);
}

Widget _forgotPasswordLink() {
Widget _forgotPasswordLink(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(
Expand All @@ -182,31 +174,24 @@ class _LoginScreenState extends State<LoginScreen> {
);
}

Widget _loginButtonSection() {
Widget _loginButtonSection(BuildContext context) {
LoginViewModel viewModel = Provider.of<LoginViewModel>(context);

return SizedBox(
width: 291,
height: 64,
child: ElevatedButton(
onPressed: () {
viewModel.loginWithEmailAndPassword().then((_) {
viewModel.goToHome();
}).catchError((e) => showDialog<Object>(
context: context,
builder: (BuildContext context) =>
ErrorPopUp(content: Text('$e')),
));
},
child: Consumer<LoginViewModel>(
builder: (context, value, child) => value.isLoading
? const CircularProgressIndicator(value: null)
: const Text('Entrar'),
)),
);
return Requestbutton(
command: viewModel.loginCommand,
onErrorCallback: (String e) {
showDialog<Object>(
context: context,
builder: (BuildContext context) => ErrorPopUp(content: Text(e)),
);
},
onSuccessCallback: () {
goToNavbar(context);
},
nameButton: 'Entrar');
}

Widget _loggingInWithOther() {
Widget _loggingInWithOther(BuildContext context) {
return GestureDetector(
onTap: () => Log.d(""),
child: Container(
Expand All @@ -225,4 +210,12 @@ class _LoginScreenState extends State<LoginScreen> {
),
);
}

void goToNavbar(BuildContext context) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const NavbarView(),
),
);
}
}
63 changes: 22 additions & 41 deletions lib/ui/login/viewModel/login_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,71 +1,52 @@
import 'package:aranduapp/core/log/Log.dart';
import 'package:aranduapp/core/state/command.dart';
import 'package:aranduapp/ui/navbar/view/navBarView.dart';
import 'package:async/async.dart';
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:aranduapp/ui/login/service/LoginService.dart';
import 'package:aranduapp/ui/login/model/LoginRequest.dart';

class LoginViewModel extends ChangeNotifier {
final BuildContext context;

bool isLoading;
late Command0<void> loginCommand;
late Command0<void> validadeTokenCommand;

final GlobalKey<FormState> formKey;
final TextEditingController emailController;
final TextEditingController passwordController;

LoginViewModel(this.context)
: isLoading = false,
formKey = GlobalKey<FormState>(),
LoginViewModel()
: formKey = GlobalKey<FormState>(),
emailController = TextEditingController(),
passwordController = TextEditingController();
passwordController = TextEditingController() {

Future<void> loginWithEmailAndPassword() async {
// TODO use mutex to make this
if (isLoading) {
return;
}

try {
isLoading = true;
super.notifyListeners();
loginCommand = Command0<void>(loginWithEmailAndPassword);

if (!formKey.currentState!.validate()) {
throw Exception('Valores inválidos');
}
validadeTokenCommand = Command0<void>(validateToken);
validadeTokenCommand.execute();
}

await LoginService.login(
LoginRequest(emailController.text, passwordController.text));
} catch (e) {
rethrow;
} finally {
isLoading = false;
notifyListeners();
Future<Result<void>> loginWithEmailAndPassword() async {
if (!formKey.currentState!.validate()) {
return Result.error(Exception('Valores inválidos'));
}

await LoginService.login(
LoginRequest(emailController.text, passwordController.text));

return Result.value(null);
}

Future<void> validateToken() async {
Future<Result<void>> validateToken() async {
await LoginService.validateToken();

return Result.value(null);
}

Future<bool> loginWithDeviceAuth() async {
Log.d('init loginWithDeviceAuth');
return await LocalAuthentication()
.authenticate(localizedReason: 'Toque com o dedo no sensor para logar');
}

void goToHome() {
try {
if (context.mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const NavbarView(),
),
);
}
} catch (e) {
Log.e(e);
rethrow;
}
}
}
Loading

0 comments on commit b9998c3

Please sign in to comment.