From 0739f345a9d1a7c3f922902c5d15af7877c52daa Mon Sep 17 00:00:00 2001 From: komekh Date: Thu, 12 Sep 2024 15:27:18 +0500 Subject: [PATCH] delete added --- assets/locale/ru-RU.json | 11 +- assets/locale/tr-TR.json | 11 +- lib/application/user_bloc/user_bloc.dart | 47 +++ lib/application/user_bloc/user_event.dart | 7 + lib/application/user_bloc/user_state.dart | 20 ++ lib/core/constants/api.dart | 8 +- lib/core/router/app_router.dart | 3 + .../remote/user_remote_data_source.dart | 39 ++- .../repositories/user_repository_impl.dart | 32 ++ lib/di/user.dart | 4 +- lib/domain/repositories/user_repository.dart | 2 + .../usecases/user/delete_account_usecase.dart | 14 + lib/domain/usecases/user/sign_up_usecase.dart | 46 +-- lib/domain/usecases/user/user.dart | 1 + lib/presentation/screens/login.dart | 53 ++- lib/presentation/screens/profile.dart | 35 +- lib/presentation/screens/register.dart | 314 ++++++++++++++++++ lib/presentation/screens/screens.dart | 1 + lib/presentation/widgets/error_dialog.dart | 5 +- 19 files changed, 617 insertions(+), 36 deletions(-) create mode 100644 lib/domain/usecases/user/delete_account_usecase.dart create mode 100644 lib/presentation/screens/register.dart diff --git a/assets/locale/ru-RU.json b/assets/locale/ru-RU.json index c53c55c..98245e0 100644 --- a/assets/locale/ru-RU.json +++ b/assets/locale/ru-RU.json @@ -51,5 +51,14 @@ "error_message": "Что-то пошло не так. Пожалуйста, попробуйте еще раз.", "follow_orders_banner": "Отслеживайте ваш груз в реальном времени", "order_empty": "У вас пока нет заказов", - "deliver_all": "Ваш надежный партнер в мире логистики!" + "deliver_all": "Ваш надежный партнер в мире логистики!", + "user_already_registered": "Пользователь зарегистрирован!", + "alert": "Внимание!", + "or": "Или", + "register": "Зарегистрироваться", + "register_header": "Для входа в личный кабинет", + "register_desc": "необходимо зарегистрироваться", + "registration_success": "Регистрация прошла успешно!", + "dismiss": "OK", + "delete": "Удалить аккаунт" } diff --git a/assets/locale/tr-TR.json b/assets/locale/tr-TR.json index 0aad631..cad59f3 100644 --- a/assets/locale/tr-TR.json +++ b/assets/locale/tr-TR.json @@ -51,5 +51,14 @@ "error_message": "Näsazlyk ýüze çykdy. Täzeden synanşyp görmegiňizi haýyş edýäris.", "follow_orders_banner": "Ýükiňizi 24 sagadyň dowamynda yzarlamak indi elýeterli", "order_empty": "Siziň entäk sargydyňyz ýok", - "deliver_all": "Ýükleri eltip bermekde siziň ynamly hyzmatdaşyňyz!" + "deliver_all": "Ýükleri eltip bermekde siziň ynamly hyzmatdaşyňyz!", + "user_already_registered": "Ulanyjy hasaba alnan!", + "alert": "Üns beriň", + "or": "Ýa-da", + "register": "Agza bol", + "register_header": "Şahsy otaga girmek üçin", + "register_desc": "hasaba alynmagyňyzy haýyş edýäris", + "registration_success": "Üstünlikli hasaba alyndy!", + "dismiss": "OK", + "delete": "Hasaby poz" } diff --git a/lib/application/user_bloc/user_bloc.dart b/lib/application/user_bloc/user_bloc.dart index ad14881..8299770 100644 --- a/lib/application/user_bloc/user_bloc.dart +++ b/lib/application/user_bloc/user_bloc.dart @@ -14,18 +14,24 @@ class UserBloc extends Bloc { final GetCachedUserUseCase _getCachedUserUseCase; final GetRemoteUserUsecase _getRemoteUserUseCase; final SignInUseCase _signInUseCase; + final SignUpUseCase _signUpUseCase; final SignOutUseCase _signOutUseCase; + final DeleteAccountUseCase _deleteAccountUseCase; UserBloc( this._signInUseCase, + this._signUpUseCase, this._getCachedUserUseCase, this._getRemoteUserUseCase, this._signOutUseCase, + this._deleteAccountUseCase, ) : super(UserInitial()) { on(_onSignIn); + on(_onSignUp); on(_onCheckUser); on(_onGetRemoteUser); on(_onSignOut); on(_onGetUser); + on(_onDeleteAccount); } void _onSignIn(SignInUser event, Emitter emit) async { @@ -42,6 +48,28 @@ class UserBloc extends Bloc { } } + void _onSignUp(SignUpUser event, Emitter emit) async { + try { + emit(UserLoading()); + // await Future.delayed(const Duration(seconds: 3)); + final result = await _signUpUseCase(event.params); + result.fold( + (failure) => emit(UserLoggedFail(failure)), + (code) { + if (code == 200) { + emit(UserRegistered()); + } else if (code == 409) { + emit(UserAlreadyRegistered()); + } else { + emit(UserLoggedFail(ExceptionFailure())); + } + }, + ); + } catch (e) { + emit(UserLoggedFail(ExceptionFailure())); + } + } + void _onCheckUser(CheckUser event, Emitter emit) async { try { emit(UserLoading()); @@ -65,6 +93,25 @@ class UserBloc extends Bloc { } } + void _onDeleteAccount(DeleteAccount event, Emitter emit) async { + try { + emit(DeleteLoading()); + final result = await _deleteAccountUseCase(NoParams()); + result.fold( + (failure) => emit(_mapFailureToState(failure)), + (code) { + if (code == 204) { + emit(AccountDeleted()); + } else { + emit(UserLoggedFail(ExceptionFailure())); + } + }, + ); + } catch (e) { + emit(UserLoggedFail(ExceptionFailure())); + } + } + FutureOr _onGetRemoteUser( GetRemoteUser event, Emitter emit, diff --git a/lib/application/user_bloc/user_event.dart b/lib/application/user_bloc/user_event.dart index 425074a..d3fe3cd 100644 --- a/lib/application/user_bloc/user_event.dart +++ b/lib/application/user_bloc/user_event.dart @@ -8,6 +8,11 @@ class SignInUser extends UserEvent { SignInUser(this.params); } +class SignUpUser extends UserEvent { + final SignUpParams params; + SignUpUser(this.params); +} + class SignOutUser extends UserEvent {} class CheckUser extends UserEvent {} @@ -15,3 +20,5 @@ class CheckUser extends UserEvent {} class GetRemoteUser extends UserEvent {} class GetUser extends UserEvent {} + +class DeleteAccount extends UserEvent {} diff --git a/lib/application/user_bloc/user_state.dart b/lib/application/user_bloc/user_state.dart index f61435a..894e740 100644 --- a/lib/application/user_bloc/user_state.dart +++ b/lib/application/user_bloc/user_state.dart @@ -38,3 +38,23 @@ class UserLoggedOut extends UserState { @override List get props => []; } + +class AccountDeleted extends UserState { + @override + List get props => []; +} + +class UserRegistered extends UserState { + @override + List get props => []; +} + +class UserAlreadyRegistered extends UserState { + @override + List get props => []; +} + +class DeleteLoading extends UserState { + @override + List get props => []; +} diff --git a/lib/core/constants/api.dart b/lib/core/constants/api.dart index 8884aeb..1606393 100644 --- a/lib/core/constants/api.dart +++ b/lib/core/constants/api.dart @@ -1,6 +1,6 @@ -const String baseUrl = 'https://192.168.99.64:5001/api'; -const String imageUrl = 'https://192.168.99.64:5001'; -// const String baseUrl = 'https://cargo.tpsadvertising.com/api'; -// const String imageUrl = 'https://cargo.tpsadvertising.com'; +// const String baseUrl = 'https://192.168.99.64:5001/api'; +// const String imageUrl = 'https://192.168.99.64:5001'; +const String baseUrl = 'https://cargo.tpsadvertising.com/api'; +const String imageUrl = 'https://cargo.tpsadvertising.com'; const String defaultApiKey = ''; const String defaultSources = ''; diff --git a/lib/core/router/app_router.dart b/lib/core/router/app_router.dart index c42f5ac..223d5f6 100644 --- a/lib/core/router/app_router.dart +++ b/lib/core/router/app_router.dart @@ -8,6 +8,7 @@ sealed class AppRouter { static const String splash = '/splash'; static const String splash2 = '/splash2'; static const String login = '/login'; + static const String register = '/register'; static const String root = '/root'; static const String orderDetails = '/order-details'; @@ -20,6 +21,8 @@ sealed class AppRouter { return MaterialPageRoute(builder: (_) => const Splash2Screen()); case login: return MaterialPageRoute(builder: (_) => const LoginScreen()); + case register: + return MaterialPageRoute(builder: (_) => const RegisterScreen()); case root: return MaterialPageRoute(builder: (_) => const RootScreen()); case orderDetails: diff --git a/lib/data/data_sources/remote/user_remote_data_source.dart b/lib/data/data_sources/remote/user_remote_data_source.dart index df15d22..3b35f5f 100644 --- a/lib/data/data_sources/remote/user_remote_data_source.dart +++ b/lib/data/data_sources/remote/user_remote_data_source.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:flutter/widgets.dart'; import 'package:http/http.dart' as http; import '../../../core/core.dart'; @@ -8,6 +9,8 @@ import '../../data.dart'; abstract class UserRemoteDataSource { Future signIn(SignInParams params); + Future signUp(SignUpParams params); + Future deleteAccount(String token); Future getUser(String token); Future registerFBToken(String token, String fbToken); } @@ -41,6 +44,23 @@ class UserRemoteDataSourceImpl implements UserRemoteDataSource { } } + @override + Future signUp(SignUpParams params) async { + final response = await client.post( + Uri.parse('$baseUrl/Client/Register'), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'accept': '*/*', + }, + body: { + 'username': params.username.trim(), + 'password': params.password, + }, + ); + + return response.statusCode; + } + @override Future getUser(String token) async { final response = await client.get( @@ -62,7 +82,8 @@ class UserRemoteDataSourceImpl implements UserRemoteDataSource { @override Future registerFBToken(String token, String fbToken) async { - final response = await client.post( + /* final response = */ + await client.post( Uri.parse('$baseUrl/Client/FirebaseToken?token=$fbToken'), headers: { 'accept': '*/*', @@ -75,4 +96,20 @@ class UserRemoteDataSourceImpl implements UserRemoteDataSource { throw ServerException(); } */ } + + @override + Future deleteAccount(String token) async { + final response = await client.delete( + Uri.parse('$baseUrl/Client/DeleteAccount'), + headers: { + 'accept': '*/*', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + debugPrint(response.body); + + return response.statusCode; + } } diff --git a/lib/data/repositories/user_repository_impl.dart b/lib/data/repositories/user_repository_impl.dart index 005fe5a..89132fb 100644 --- a/lib/data/repositories/user_repository_impl.dart +++ b/lib/data/repositories/user_repository_impl.dart @@ -38,6 +38,22 @@ class UserRepositoryImpl implements UserRepository { } } + @override + Future> signUp(params) async { + if (await networkInfo.isConnected) { + try { + /// register + final code = await remoteDataSource.signUp(params); + + return Right(code); + } on Failure catch (failure) { + return Left(failure); + } + } else { + return Left(NetworkFailure()); + } + } + @override Future> getCachedUser() async { try { @@ -62,6 +78,22 @@ class UserRepositoryImpl implements UserRepository { } } + @override + Future> deleteAccount() async { + try { + final String token = await localDataSource.getToken(); + final code = await remoteDataSource.deleteAccount(token); + if (code == 204) { + await localDataSource.clearCache(); + } + return Right(code); + } on CacheFailure { + return Left(CacheFailure()); + } catch (error) { + return Left(ExceptionFailure()); + } + } + @override Future> getRemoteUser() async { if (!await networkInfo.isConnected) { diff --git a/lib/di/user.dart b/lib/di/user.dart index 56fd587..9dfa471 100644 --- a/lib/di/user.dart +++ b/lib/di/user.dart @@ -7,10 +7,12 @@ import 'di.dart'; void registerUserFeature() { // User BLoC and Use Cases - sl.registerFactory(() => UserBloc(sl(), sl(), sl(), sl())); + sl.registerFactory(() => UserBloc(sl(), sl(), sl(), sl(), sl(), sl())); sl.registerLazySingleton(() => GetCachedUserUseCase(sl())); sl.registerLazySingleton(() => SignInUseCase(sl())); + sl.registerLazySingleton(() => SignUpUseCase(sl())); sl.registerLazySingleton(() => SignOutUseCase(sl())); + sl.registerLazySingleton(() => DeleteAccountUseCase(sl())); sl.registerLazySingleton(() => GetRemoteUserUsecase(sl())); // User Repository and Data Sources diff --git a/lib/domain/repositories/user_repository.dart b/lib/domain/repositories/user_repository.dart index 8245bb6..e1547c2 100644 --- a/lib/domain/repositories/user_repository.dart +++ b/lib/domain/repositories/user_repository.dart @@ -5,7 +5,9 @@ import '../domain.dart'; abstract class UserRepository { Future> signIn(SignInParams params); + Future> signUp(SignUpParams params); Future> signOut(); + Future> deleteAccount(); Future> getCachedUser(); Future> getRemoteUser(); } diff --git a/lib/domain/usecases/user/delete_account_usecase.dart b/lib/domain/usecases/user/delete_account_usecase.dart new file mode 100644 index 0000000..887cb96 --- /dev/null +++ b/lib/domain/usecases/user/delete_account_usecase.dart @@ -0,0 +1,14 @@ +import 'package:dartz/dartz.dart'; + +import '../../../core/core.dart'; +import '../../domain.dart'; + +class DeleteAccountUseCase implements UseCase { + final UserRepository repository; + DeleteAccountUseCase(this.repository); + + @override + Future> call(NoParams params) async { + return await repository.deleteAccount(); + } +} diff --git a/lib/domain/usecases/user/sign_up_usecase.dart b/lib/domain/usecases/user/sign_up_usecase.dart index abeaf13..8d62f2d 100644 --- a/lib/domain/usecases/user/sign_up_usecase.dart +++ b/lib/domain/usecases/user/sign_up_usecase.dart @@ -1,27 +1,27 @@ -// import 'package:dartz/dartz.dart'; +import 'package:dartz/dartz.dart'; -// import '../../../core/core.dart'; -// import '../../domain.dart'; +import '../../../core/core.dart'; +import '../../domain.dart'; -// class SignUpUseCase implements UseCase { -// final UserRepository repository; -// SignUpUseCase(this.repository); +class SignUpUseCase implements UseCase { + final UserRepository repository; + SignUpUseCase(this.repository); -// @override -// Future> call(SignUpParams params) async { -// return await repository.signUp(params); -// } -// } + @override + Future> call(SignUpParams params) async { + return await repository.signUp(params); + } +} -// class SignUpParams { -// final String firstName; -// final String lastName; -// final String email; -// final String password; -// const SignUpParams({ -// required this.firstName, -// required this.lastName, -// required this.email, -// required this.password, -// }); -// } +class SignUpParams { + // final String firstName; + // final String lastName; + final String username; + final String password; + const SignUpParams({ + // required this.firstName, + // required this.lastName, + required this.username, + required this.password, + }); +} diff --git a/lib/domain/usecases/user/user.dart b/lib/domain/usecases/user/user.dart index f58e643..d259dc9 100644 --- a/lib/domain/usecases/user/user.dart +++ b/lib/domain/usecases/user/user.dart @@ -2,4 +2,5 @@ export 'get_cached_user_usecase.dart'; export 'sign_in_usecase.dart'; export 'sign_out_usecase.dart'; export 'sign_up_usecase.dart'; +export 'delete_account_usecase.dart'; export 'get_remote_user_usecase.dart'; diff --git a/lib/presentation/screens/login.dart b/lib/presentation/screens/login.dart index 137f393..22c4347 100644 --- a/lib/presentation/screens/login.dart +++ b/lib/presentation/screens/login.dart @@ -7,6 +7,7 @@ import '../../configs/configs.dart'; import '../../core/core.dart'; import '../../domain/domain.dart'; import '../widgets/widgets.dart'; +import 'dart:io' show Platform; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -100,7 +101,7 @@ class _LoginScreenState extends State { /// form part SizedBox( - height: AppDimensions.normalize(165), + height: AppDimensions.normalize(190), child: Stack( clipBehavior: Clip.none, children: [ @@ -232,6 +233,56 @@ class _LoginScreenState extends State { ); }, ), + + if (Platform.isAndroid) + Align( + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + /// spacer + Space.yf(), + Text( + 'or'.tr(), + style: AppText.h3, + ), + Space.yf(), + Container( + padding: const EdgeInsets.symmetric(horizontal: 22), + height: 40, + decoration: BoxDecoration( + border: Border.all( + color: AppColors.primary, // Border color + width: 1.0, // Border width + ), + borderRadius: BorderRadius.circular(8.0), + ), + child: TextButton( + style: TextButton.styleFrom( + foregroundColor: AppColors.primary, + padding: EdgeInsets.zero, + textStyle: const TextStyle( + color: Colors.black, + ), + ), + onPressed: () { + debugPrint('register'); + Navigator.of(context).pushNamedAndRemoveUntil( + AppRouter.register, + (route) => false, + ); + }, + child: Text( + 'register'.tr(), + style: AppText.b1b, + ), + ), + ), + Space.yf(0.30), + ], + ), + ) ], ), ), diff --git a/lib/presentation/screens/profile.dart b/lib/presentation/screens/profile.dart index 805d89a..a9a58f6 100644 --- a/lib/presentation/screens/profile.dart +++ b/lib/presentation/screens/profile.dart @@ -34,7 +34,7 @@ class _ProfileScreenState extends State { backgroundColor: AppColors.surface, body: BlocConsumer( listener: (context, state) { - if (state is UserLoggedOut || state is UserLoggedFail) { + if (state is UserLoggedOut || state is UserLoggedFail || state is AccountDeleted) { _navigateToLoginScreen(context); } }, @@ -121,11 +121,42 @@ class _ProfileScreenState extends State { child: Text( 'logout'.tr(), style: AppText.b1!.copyWith( - color: Colors.red, + color: AppColors.primary, ), ), ), ), + + ///gap + Space.yf(3), + + BlocBuilder( + builder: (context, state) { + if (state is DeleteLoading) { + // Show loader when the state is DeleteLoading + return const Align( + alignment: Alignment.center, + child: CircularProgressIndicator(), // Loader + ); + } else { + // Show the delete button in other states + return Align( + alignment: Alignment.center, + child: TextButton( + onPressed: () { + context.read().add(DeleteAccount()); + }, + child: Text( + 'delete'.tr(), + style: AppText.b1!.copyWith( + color: Colors.red, + ), + ), + ), + ); + } + }, + ), ], ), ), diff --git a/lib/presentation/screens/register.dart b/lib/presentation/screens/register.dart new file mode 100644 index 0000000..5549485 --- /dev/null +++ b/lib/presentation/screens/register.dart @@ -0,0 +1,314 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../application/user_bloc/user_bloc.dart'; +import '../../configs/configs.dart'; +import '../../core/core.dart'; +import '../../domain/domain.dart'; +import '../widgets/widgets.dart'; +import 'dart:io' show Platform; + +class RegisterScreen extends StatefulWidget { + const RegisterScreen({super.key}); + + @override + State createState() => _RegisterScreenState(); +} + +class _RegisterScreenState extends State { + final TextEditingController _userNameController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + final _formKey = GlobalKey(); + bool _obscureText = true; + + void _nextScreen() { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('registration_success'.tr()), + backgroundColor: Colors.green, + duration: const Duration(seconds: 2), + ), + ); + + Navigator.of(context).pushNamedAndRemoveUntil( + AppRouter.login, + (route) => false, + ); + } + + void _onEyeTapped() { + setState(() { + _obscureText = !_obscureText; + }); + } + + @override + void dispose() { + _userNameController.dispose(); + _passwordController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + App.init(context); + return Scaffold( + body: SingleChildScrollView( + child: Column( + children: [ + /// image part + Container( + height: AppDimensions.normalize(155), + color: AppColors.primary, + child: SingleChildScrollView( + physics: const NeverScrollableScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + padding: const EdgeInsets.only(top: 20, bottom: 20), + child: Column( + children: [ + // SvgPicture.asset( + // AppAssets.logo, + // height: AppDimensions.normalize(30), + // ), + Space.yf(4), + + Image.asset( + AppAssets.logoLogin, + ), + Space.yf(0.50), + Text( + appTitle, + style: AppText.h1b?.copyWith( + color: Colors.white, + ), + ), + Space.yf(0.30), + Text( + 'deliver_all'.tr(), + style: AppText.b1?.copyWith( + color: AppColors.yellow, + ), + ), + Image.asset( + AppAssets.trucksPng, + height: AppDimensions.normalize(52), + width: double.infinity, + fit: BoxFit.fill, + ), + ], + ), + ), + ], + ), + ), + ), + + /// form part + SizedBox( + height: AppDimensions.normalize(190), + child: Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + top: -20, + left: 0, + right: 0, + bottom: 0, + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: Padding( + padding: Space.hf().copyWith(top: 30), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'register_header'.tr(), + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + + Space.yf(0.5), + + Text( + 'register_desc'.tr(), + style: const TextStyle( + color: Colors.grey, + ), + ), + + /// gap + Space.yf(), + + /// username field + Text('login'.tr()), + Space.y!, + TextFormField( + controller: _userNameController, + decoration: InputDecoration( + hintText: 'login_hint'.tr(), + prefixIcon: const Icon(Icons.person_outline), + border: const OutlineInputBorder(), + ), + validator: (val) => FormValidator.validateField(val), + ), + + /// gap + Space.yf(), + + /// password field + Text('password'.tr()), + Space.y!, + TextFormField( + controller: _passwordController, + obscureText: _obscureText, + decoration: InputDecoration( + hintText: 'password_hint'.tr(), + prefixIcon: const Icon(Icons.lock_outline), + suffixIcon: GestureDetector( + onTap: _onEyeTapped, + child: _obscureText + ? const Icon(Icons.visibility_off) + : const Icon( + Icons.visibility, + ), + ), + border: const OutlineInputBorder(), + ), + validator: (val) => FormValidator.validateField(val), + ), + + /// gap + Space.yf(), + + BlocConsumer( + listener: (context, state) { + if (state is UserRegistered) { + _nextScreen(); + } else if (state is UserAlreadyRegistered) { + showErrorDialog( + context: context, + header: 'alert'.tr(), + body: 'user_already_registered'.tr(), + ); + } else if (state is UserLoggedFail) { + if (state.failure is CredentialFailure) { + showErrorDialog( + context: context, + header: 'credentials_validation_header'.tr(), + body: 'credentials_validation_body'.tr(), + ); + } else { + showAuthErrorDialog(context); + } + } + }, + builder: (context, state) { + if (state is UserLoading) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return SizedBox( + width: double.infinity, + child: AppButton( + textColor: Colors.white, + btnColor: AppColors.primary, + onPressed: () { + if (_formKey.currentState!.validate()) { + Keyboard.hide(context); + + /// sign in + context.read().add( + SignUpUser( + SignUpParams( + username: _userNameController.text, + password: _passwordController.text, + ), + ), + ); + } + }, + text: 'register'.tr(), + ), + ); + }, + ), + + if (Platform.isAndroid) + Align( + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + /// spacer + Space.yf(), + Text( + 'or'.tr(), + style: AppText.h3, + ), + Space.yf(), + Container( + padding: const EdgeInsets.symmetric(horizontal: 22), + height: 40, + decoration: BoxDecoration( + border: Border.all( + color: AppColors.primary, // Border color + width: 1.0, // Border width + ), + borderRadius: BorderRadius.circular(8.0), + ), + child: TextButton( + style: TextButton.styleFrom( + foregroundColor: AppColors.primary, + padding: EdgeInsets.zero, + textStyle: const TextStyle( + color: Colors.black, + ), + ), + onPressed: () { + debugPrint('login'); + Navigator.of(context).pushNamedAndRemoveUntil( + AppRouter.login, + (route) => false, + ); + }, + child: Text( + 'start_tracking'.tr(), + style: AppText.b1b, + ), + ), + ), + Space.yf(0.30), + ], + ), + ) + ], + ), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/screens/screens.dart b/lib/presentation/screens/screens.dart index 68646c7..cd046f3 100644 --- a/lib/presentation/screens/screens.dart +++ b/lib/presentation/screens/screens.dart @@ -7,3 +7,4 @@ export 'root.dart'; export 'splash.dart'; export 'splash2.dart'; export 'image_full.dart'; +export 'register.dart'; diff --git a/lib/presentation/widgets/error_dialog.dart b/lib/presentation/widgets/error_dialog.dart index ca046dc..396d5e1 100644 --- a/lib/presentation/widgets/error_dialog.dart +++ b/lib/presentation/widgets/error_dialog.dart @@ -1,3 +1,4 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import '../../configs/configs.dart'; @@ -7,7 +8,7 @@ Future showErrorDialog({ required BuildContext context, required String header, required String body, - String dismissButtonText = 'Dismiss', + String dismissButtonText = 'dismiss', VoidCallback? onDismiss, }) async { return showDialog( @@ -52,7 +53,7 @@ Future showErrorDialog({ } }, child: Text( - dismissButtonText, + dismissButtonText.tr(), style: AppText.h3b?.copyWith( color: AppColors.primary, ),