From efd546b823c15e4a981439183fc14f6219126c36 Mon Sep 17 00:00:00 2001 From: arafaysaleem Date: Sun, 20 Jun 2021 11:40:05 -0700 Subject: [PATCH 1/3] refact(Providers): add future state changing for changePassword method Signed-off-by: arafaysaleem --- lib/providers/all_providers.dart | 34 ++++++++----- lib/providers/auth_provider.dart | 51 ++++++++++++------- lib/providers/states/future_state.dart | 17 +++++++ .../repositories/auth_repository.dart | 6 +-- 4 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 lib/providers/states/future_state.dart diff --git a/lib/providers/all_providers.dart b/lib/providers/all_providers.dart index 6a2f9b1..6da8582 100644 --- a/lib/providers/all_providers.dart +++ b/lib/providers/all_providers.dart @@ -6,22 +6,22 @@ import '../services/networking/api_service.dart'; //repository imports import '../services/repositories/auth_repository.dart'; +import '../services/repositories/bookings_repository.dart'; import '../services/repositories/movies_repository.dart'; +import '../services/repositories/payments_repository.dart'; import '../services/repositories/shows_repository.dart'; import '../services/repositories/theaters_repository.dart'; -import '../services/repositories/bookings_repository.dart'; -import '../services/repositories/payments_repository.dart'; //provider imports import 'auth_provider.dart'; -import 'movies_provider.dart'; -import 'shows_provider.dart'; -import 'theaters_provider.dart'; import 'bookings_provider.dart'; +import 'movies_provider.dart'; import 'payments_provider.dart'; +import 'shows_provider.dart'; //states import 'states/auth_state.dart'; +import 'theaters_provider.dart'; //service providers final _apiServiceProvider = Provider((ref) => ApiService()); @@ -43,17 +43,17 @@ final _showsRepositoryProvider = Provider((ref) { return ShowsRepository(apiService: _apiService); }); -final _theatersRepositoryProvider = Provider((ref){ +final _theatersRepositoryProvider = Provider((ref) { final _apiService = ref.watch(_apiServiceProvider); return TheatersRepository(apiService: _apiService); }); -final _bookingsRepositoryProvider = Provider((ref){ +final _bookingsRepositoryProvider = Provider((ref) { final _apiService = ref.watch(_apiServiceProvider); return BookingsRepository(apiService: _apiService); }); -final _paymentsRepositoryProvider = Provider((ref){ +final _paymentsRepositoryProvider = Provider((ref) { final _apiService = ref.watch(_apiServiceProvider); return PaymentsRepository(apiService: _apiService); }); @@ -62,7 +62,11 @@ final _paymentsRepositoryProvider = Provider((ref){ final authProvider = StateNotifierProvider((ref) { final _authRepository = ref.watch(_authRepositoryProvider); final _prefsService = ref.watch(_prefsServiceProvider); - return AuthProvider(_authRepository, _prefsService); + return AuthProvider( + reader: ref.read, + authRepository: _authRepository, + prefsService: _prefsService, + ); }); //data providers @@ -76,17 +80,19 @@ final showsProvider = Provider((ref) { return ShowsProvider(_showsRepository); }); -final theatersProvider = ChangeNotifierProvider((ref){ +final theatersProvider = ChangeNotifierProvider((ref) { final _theatersRepository = ref.watch(_theatersRepositoryProvider); return TheatersProvider(_theatersRepository); }); -final bookingsProvider = Provider((ref){ +final bookingsProvider = Provider((ref) { final _bookingsRepository = ref.watch(_bookingsRepositoryProvider); - return BookingsProvider(read: ref.read, bookingsRepository: _bookingsRepository); + return BookingsProvider( + read: ref.read, bookingsRepository: _bookingsRepository); }); -final paymentsProvider = Provider((ref){ +final paymentsProvider = Provider((ref) { final _paymentsRepository = ref.watch(_paymentsRepositoryProvider); - return PaymentsProvider(read: ref.read, paymentsRepository: _paymentsRepository); + return PaymentsProvider( + read: ref.read, paymentsRepository: _paymentsRepository); }); diff --git a/lib/providers/auth_provider.dart b/lib/providers/auth_provider.dart index 811d8f1..63c6988 100644 --- a/lib/providers/auth_provider.dart +++ b/lib/providers/auth_provider.dart @@ -1,28 +1,39 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -//enums +//Enums import '../enums/user_role_enum.dart'; -//models +//Models import '../models/user_model.dart'; -//services +//Services import '../services/local_storage/prefs_service.dart'; import '../services/networking/network_exception.dart'; import '../services/repositories/auth_repository.dart'; - -//states import 'states/auth_state.dart'; +//States +import 'states/future_state.dart'; + +final changePasswordState = + StateProvider((ref) => const FutureState.idle()); + class AuthProvider extends StateNotifier { late UserModel? _currentUser; final AuthRepository _authRepository; final PrefsService _prefsService; + final Reader _reader; String _token = ""; String _password = ""; - AuthProvider(this._authRepository, this._prefsService) - : super(const AuthState.unauthenticated()) { + AuthProvider({ + required AuthRepository authRepository, + required PrefsService prefsService, + required Reader reader, + }) : _authRepository = authRepository, + _prefsService = prefsService, + _reader = reader, + super(const AuthState.unauthenticated()) { init(); } @@ -62,7 +73,7 @@ class AuthProvider extends StateNotifier { } } - void login({ + Future login({ required String email, required String password, }) async { @@ -81,7 +92,7 @@ class AuthProvider extends StateNotifier { } } - void register({ + Future register({ required String email, required String password, required String fullName, @@ -128,19 +139,21 @@ class AuthProvider extends StateNotifier { return result; } - Future changePassword({ - required String email, - required String oldPassword, - required String newPassword, - }) async { + Future changePassword({required String newPassword}) async { final data = { - "email": email, - "password": oldPassword, + "email": currentUserEmail, + "password": currentUserPassword, "new_password": newPassword, }; - final result = await _authRepository.sendChangePasswordData(data: data); - if (result) _updatePassword(newPassword); - return result; + final _changePasswordState = _reader(changePasswordState); + _changePasswordState.state = const FutureState.loading(); + try { + final result = await _authRepository.sendChangePasswordData(data: data); + _updatePassword(newPassword); + _changePasswordState.state = FutureState.data(data: result); + } on NetworkException catch (e) { + _changePasswordState.state = FutureState.failed(reason: e.message); + } } Future verifyOtp({required String email, required int otp}) async { diff --git a/lib/providers/states/future_state.dart b/lib/providers/states/future_state.dart new file mode 100644 index 0000000..d7b3bb5 --- /dev/null +++ b/lib/providers/states/future_state.dart @@ -0,0 +1,17 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'future_state.freezed.dart'; + +@freezed +class FutureState with _$FutureState { + + const factory FutureState.idle() = IDLE; + + const factory FutureState.loading() = LOADING; + + const factory FutureState.data({required T data}) = DATA; + + const factory FutureState.failed({required String reason}) = FAILED; +} + + diff --git a/lib/services/repositories/auth_repository.dart b/lib/services/repositories/auth_repository.dart index f8ec094..97ddc29 100644 --- a/lib/services/repositories/auth_repository.dart +++ b/lib/services/repositories/auth_repository.dart @@ -63,14 +63,14 @@ class AuthRepository { ); } - Future sendChangePasswordData({ + Future sendChangePasswordData({ required Map data, }) async { - return await _apiService.setData( + return await _apiService.setData( endpoint: ApiEndpoint.auth(AuthEndpoint.CHANGE_PASSWORD), data: data, requiresAuthToken: false, - converter: (response) => response["headers"]["success"] == 1, + converter: (response) => response["headers"]["message"], ); } From eae889a27061c0367c660b2adac9ebbda9fbf181 Mon Sep 17 00:00:00 2001 From: arafaysaleem Date: Sun, 20 Jun 2021 11:40:36 -0700 Subject: [PATCH 2/3] add(Screen/Widgets): Add a change password screen Signed-off-by: arafaysaleem --- lib/routes/app_router.dart | 2 + lib/views/screens/change_password_screen.dart | 142 ++++++++++++++++++ lib/views/screens/user_bookings_screen.dart | 2 +- .../change_password_fields.dart | 101 +++++++++++++ .../change_password/save_password_button.dart | 57 +++++++ .../widgets/common/custom_textfield.dart | 29 ++-- 6 files changed, 318 insertions(+), 15 deletions(-) create mode 100644 lib/views/screens/change_password_screen.dart create mode 100644 lib/views/widgets/change_password/change_password_fields.dart create mode 100644 lib/views/widgets/change_password/save_password_button.dart diff --git a/lib/routes/app_router.dart b/lib/routes/app_router.dart index 3b3b74c..2b23d12 100644 --- a/lib/routes/app_router.dart +++ b/lib/routes/app_router.dart @@ -12,6 +12,7 @@ import '../views/screens/ticket_summary_screen.dart'; import '../views/screens/payment_screen.dart'; import '../views/screens/confirmation_screen.dart'; import '../views/screens/user_bookings_screen.dart'; +import '../views/screens/change_password_screen.dart'; @MaterialAutoRouter( routes: [ @@ -27,6 +28,7 @@ import '../views/screens/user_bookings_screen.dart'; AutoRoute(page: PaymentScreen), AutoRoute(page: ConfirmationScreen), AutoRoute(page: UserBookingsScreen), + AutoRoute(page: ChangePasswordScreen), ], ) class $AppRouter{} diff --git a/lib/views/screens/change_password_screen.dart b/lib/views/screens/change_password_screen.dart new file mode 100644 index 0000000..07b54ad --- /dev/null +++ b/lib/views/screens/change_password_screen.dart @@ -0,0 +1,142 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +//Helpers +import '../../helper/extensions/context_extensions.dart'; +import '../../helper/utils/constants.dart'; + +//Providers +import '../../providers/all_providers.dart'; +import '../../providers/states/future_state.dart'; + +//Widgets +import '../widgets/change_password/change_password_fields.dart'; +import '../widgets/change_password/save_password_button.dart'; +import '../widgets/common/custom_dialog.dart'; +import '../widgets/common/scrollable_column.dart'; + +class ChangePasswordScreen extends HookWidget { + const ChangePasswordScreen(); + + @override + Widget build(BuildContext context) { + final currentPasswordController = useTextEditingController(); + final newPasswordController = useTextEditingController(); + final cNewPasswordController = useTextEditingController(); + late final _formKey = useMemoized(() => GlobalKey()); + return Scaffold( + body: ProviderListener( + provider: authProvider, + onChange: (_, changePasswordState) async { + (changePasswordState as FutureState).maybeWhen( + data: (message) async { + currentPasswordController.clear(); + newPasswordController.clear(); + cNewPasswordController.clear(); + await showDialog( + context: context, + barrierColor: Constants.barrierColor.withOpacity(0.75), + builder: (ctx) => CustomDialog.alert( + title: "Change Password Success", + body: message, + buttonText: "Okay", + ), + ); + }, + failed: (reason) async => await showDialog( + context: context, + barrierColor: Constants.barrierColor.withOpacity(0.75), + builder: (ctx) => CustomDialog.alert( + title: "Change Password Failed", + body: reason, + buttonText: "Retry", + ), + ), + orElse: () {}, + ); + }, + child: SafeArea( + child: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Form( + key: _formKey, + child: ScrollableColumn( + children: [ + const SizedBox(height: 20), + + //Back and title + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 15), + + //Back icon + InkResponse( + radius: 25, + child: const Icon(Icons.arrow_back_sharp, size: 26), + onTap: () { + context.router.pop(); + }, + ), + + const SizedBox(width: 20), + + //Page Title + Expanded( + child: Text( + "Your profile", + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: context.headline3.copyWith(fontSize: 22), + ), + ), + + const SizedBox(width: 50), + ], + ), + + const SizedBox(height: 20), + + //Password fields + Flexible( + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: ChangePasswordFields( + currentPasswordController: currentPasswordController, + newPasswordController: newPasswordController, + cNewPasswordController: cNewPasswordController, + ), + ), + ), + ), + + const SizedBox(height: 60), + + //Save Password Button + SavePasswordButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + final _authProv = context.read(authProvider.notifier); + _authProv.changePassword( + newPassword: newPasswordController.text, + ); + } + }, + ), + + const SizedBox(height: Constants.bottomInsetsLow + 5), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/views/screens/user_bookings_screen.dart b/lib/views/screens/user_bookings_screen.dart index fd37dba..72ac107 100644 --- a/lib/views/screens/user_bookings_screen.dart +++ b/lib/views/screens/user_bookings_screen.dart @@ -33,7 +33,7 @@ class UserBookingsScreen extends StatelessWidget { const SizedBox(width: 20), - //Movie Title + //Page Title Expanded( child: Text( "Your bookings", diff --git a/lib/views/widgets/change_password/change_password_fields.dart b/lib/views/widgets/change_password/change_password_fields.dart new file mode 100644 index 0000000..2caf5df --- /dev/null +++ b/lib/views/widgets/change_password/change_password_fields.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +//Helpers +import '../../../helper/utils/constants.dart'; +import '../../../helper/extensions/context_extensions.dart'; + +//Widgets +import '../common/custom_textfield.dart'; + +class ChangePasswordFields extends StatelessWidget { + final TextEditingController currentPasswordController; + final TextEditingController newPasswordController; + final TextEditingController cNewPasswordController; + + const ChangePasswordFields({ + required this.currentPasswordController, + required this.newPasswordController, + required this.cNewPasswordController, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + //Current Password Label + Text( + "Current Password", + style: context.bodyText1.copyWith( + color: Constants.primaryColor, + fontSize: 26, + fontWeight: FontWeight.bold + ), + ), + + //Current Password Field + CustomTextField( + controller: currentPasswordController, + hintText: "Enter current password", + keyboardType: TextInputType.visiblePassword, + textInputAction: TextInputAction.done, + validator: (cPassword) { + if (newPasswordController.text.trim() == cPassword) return null; + return "Passwords don't match"; + }, + ), + + const Spacer(), + + //New Password Label + Text( + "New Password", + style: context.bodyText1.copyWith( + color: Constants.primaryColor, + fontSize: 26, + fontWeight: FontWeight.bold + ), + ), + + //New Password Field + CustomTextField( + controller: newPasswordController, + hintText: "Type your password", + keyboardType: TextInputType.visiblePassword, + textInputAction: TextInputAction.next, + validator: (password) { + if (password!.isEmpty) return "Please enter a password"; + return null; + }, + ), + + const Spacer(), + + //Confirm New Password Label + Text( + "Confirm Password", + style: context.bodyText1.copyWith( + color: Constants.primaryColor, + fontSize: 26, + fontWeight: FontWeight.bold + ), + ), + + //Confirm New Password Field + CustomTextField( + controller: cNewPasswordController, + hintText: "Retype your password", + keyboardType: TextInputType.visiblePassword, + textInputAction: TextInputAction.done, + validator: (cPassword) { + if (newPasswordController.text.trim() == cPassword) return null; + return "Passwords don't match"; + }, + ), + ], + ); + } +} + + diff --git a/lib/views/widgets/change_password/save_password_button.dart b/lib/views/widgets/change_password/save_password_button.dart new file mode 100644 index 0000000..a94f439 --- /dev/null +++ b/lib/views/widgets/change_password/save_password_button.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; + +//Helpers +import '../../../helper/utils/constants.dart'; + +//Providers +import '../../../providers/auth_provider.dart'; + +//Widgets +import '../common/custom_text_button.dart'; + +class SavePasswordButton extends StatelessWidget { + final VoidCallback onPressed; + + const SavePasswordButton({ + Key? key, + required this.onPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return CustomTextButton.gradient( + width: double.infinity, + onPressed: onPressed, + gradient: Constants.buttonGradientOrange, + child: Consumer( + builder: (context, watch, child) { + final _changePasswordState = watch(changePasswordState).state; + return _changePasswordState.maybeWhen( + loading: () => const Center( + child: SpinKitRing( + color: Colors.white, + size: 30, + lineWidth: 4, + duration: Duration(milliseconds: 1100), + ), + ), + orElse: () => child!, + ); + }, + child: const Center( + child: Text( + "SAVE", + style: TextStyle( + color: Colors.white, + fontSize: 15, + letterSpacing: 0.7, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ); + } +} diff --git a/lib/views/widgets/common/custom_textfield.dart b/lib/views/widgets/common/custom_textfield.dart index 3ee39d2..b16ea73 100644 --- a/lib/views/widgets/common/custom_textfield.dart +++ b/lib/views/widgets/common/custom_textfield.dart @@ -2,13 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; - //Helpers import '../../../helper/extensions/context_extensions.dart'; import '../../../helper/utils/constants.dart'; class CustomTextField extends StatefulWidget { - final String floatingText, hintText; + final String? floatingText, hintText; final TextInputType keyboardType; final TextInputAction textInputAction; final TextEditingController controller; @@ -43,9 +42,9 @@ class CustomTextField extends StatefulWidget { color: Constants.textWhite80Color, ), this.fillColor = Constants.scaffoldColor, + this.floatingText, + this.hintText, required this.controller, - required this.floatingText, - required this.hintText, required this.keyboardType, required this.textInputAction, required this.validator, @@ -57,7 +56,7 @@ class CustomTextField extends StatefulWidget { class _CustomTextFieldState extends State { String? errorText; - bool showPassword = false; + bool hidePassword = true; bool get hasErrorText => errorText != null; @@ -108,15 +107,17 @@ class _CustomTextFieldState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ //Floating text - Text( - widget.floatingText, - style: widget.floatingStyle ?? context.bodyText1.copyWith( - color: Constants.textGreyColor, - fontSize: 17, + if (widget.floatingText != null) + Text( + widget.floatingText!, + style: widget.floatingStyle ?? + context.bodyText1.copyWith( + color: Constants.textGreyColor, + fontSize: 17, + ), ), - ), - const SizedBox(height: 2), + if (widget.floatingText != null) const SizedBox(height: 2), //TextField SizedBox( @@ -128,7 +129,7 @@ class _CustomTextFieldState extends State { maxLengthEnforcement: MaxLengthEnforcement.enforced, textAlignVertical: TextAlignVertical.center, showCursor: true, - obscureText: showPassword, + obscureText: hidePassword, cursorColor: Colors.white, autovalidateMode: AutovalidateMode.disabled, validator: _onValidate, @@ -154,7 +155,7 @@ class _CustomTextFieldState extends State { ? InkWell( onTap: () { setState(() { - showPassword = !showPassword; + hidePassword = !hidePassword; }); }, child: const Icon( From c8a158d6378e66fe083f77709e89a4c88dfff306 Mon Sep 17 00:00:00 2001 From: arafaysaleem Date: Thu, 1 Jul 2021 00:13:36 +0500 Subject: [PATCH 3/3] feat(Screen): Fix functionality of change password screen --- lib/providers/auth_provider.dart | 7 +- lib/views/screens/change_password_screen.dart | 129 +++++++----------- lib/views/screens/login_screen.dart | 9 +- lib/views/screens/welcome_screen.dart | 48 +++++-- .../change_password_fields.dart | 68 ++++----- .../change_password/save_password_button.dart | 2 +- .../widgets/common/custom_textfield.dart | 24 ++-- .../user_bookings/user_bookings_list.dart | 4 +- 8 files changed, 132 insertions(+), 159 deletions(-) diff --git a/lib/providers/auth_provider.dart b/lib/providers/auth_provider.dart index 63c6988..c77fcac 100644 --- a/lib/providers/auth_provider.dart +++ b/lib/providers/auth_provider.dart @@ -15,8 +15,9 @@ import 'states/auth_state.dart'; //States import 'states/future_state.dart'; -final changePasswordState = - StateProvider((ref) => const FutureState.idle()); +final changePasswordStateProvider = StateProvider( + (ref) => const FutureState.idle(), +); class AuthProvider extends StateNotifier { late UserModel? _currentUser; @@ -145,7 +146,7 @@ class AuthProvider extends StateNotifier { "password": currentUserPassword, "new_password": newPassword, }; - final _changePasswordState = _reader(changePasswordState); + final _changePasswordState = _reader(changePasswordStateProvider); _changePasswordState.state = const FutureState.loading(); try { final result = await _authRepository.sendChangePasswordData(data: data); diff --git a/lib/views/screens/change_password_screen.dart b/lib/views/screens/change_password_screen.dart index 07b54ad..84b4854 100644 --- a/lib/views/screens/change_password_screen.dart +++ b/lib/views/screens/change_password_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -9,13 +8,15 @@ import '../../helper/utils/constants.dart'; //Providers import '../../providers/all_providers.dart'; +import '../../providers/auth_provider.dart'; import '../../providers/states/future_state.dart'; //Widgets -import '../widgets/change_password/change_password_fields.dart'; -import '../widgets/change_password/save_password_button.dart'; import '../widgets/common/custom_dialog.dart'; import '../widgets/common/scrollable_column.dart'; +import '../widgets/common/rounded_bottom_container.dart'; +import '../widgets/change_password/change_password_fields.dart'; +import '../widgets/change_password/save_password_button.dart'; class ChangePasswordScreen extends HookWidget { const ChangePasswordScreen(); @@ -27,10 +28,11 @@ class ChangePasswordScreen extends HookWidget { final cNewPasswordController = useTextEditingController(); late final _formKey = useMemoized(() => GlobalKey()); return Scaffold( - body: ProviderListener( - provider: authProvider, - onChange: (_, changePasswordState) async { - (changePasswordState as FutureState).maybeWhen( + body: ProviderListener>>( + provider: changePasswordStateProvider, + onChange: (_, changePasswordStateController) async { + final changePasswordState = changePasswordStateController.state; + changePasswordState.maybeWhen( data: (message) async { currentPasswordController.clear(); newPasswordController.clear(); @@ -57,83 +59,54 @@ class ChangePasswordScreen extends HookWidget { orElse: () {}, ); }, - child: SafeArea( - child: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: Form( - key: _formKey, - child: ScrollableColumn( - children: [ - const SizedBox(height: 20), - - //Back and title - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 15), - - //Back icon - InkResponse( - radius: 25, - child: const Icon(Icons.arrow_back_sharp, size: 26), - onTap: () { - context.router.pop(); - }, - ), - - const SizedBox(width: 20), - - //Page Title - Expanded( - child: Text( - "Your profile", - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: context.headline3.copyWith(fontSize: 22), - ), - ), - - const SizedBox(width: 50), - ], - ), + child: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: ScrollableColumn( + children: [ + //Input card + Form( + key: _formKey, + child: RoundedBottomContainer( + children: [ + //Page name + Text( + "Your profile", + textAlign: TextAlign.center, + style: context.headline3.copyWith(fontSize: 22), + ), - const SizedBox(height: 20), + const SizedBox(height: 20), - //Password fields - Flexible( - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: ChangePasswordFields( - currentPasswordController: currentPasswordController, - newPasswordController: newPasswordController, - cNewPasswordController: cNewPasswordController, - ), - ), + //Password fields + ChangePasswordFields( + currentPasswordController: currentPasswordController, + newPasswordController: newPasswordController, + cNewPasswordController: cNewPasswordController, ), - ), - - const SizedBox(height: 60), + ], + ), + ), - //Save Password Button - SavePasswordButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); - final _authProv = context.read(authProvider.notifier); - _authProv.changePassword( - newPassword: newPasswordController.text, - ); - } - }, - ), + const Spacer(), - const SizedBox(height: Constants.bottomInsetsLow + 5), - ], + //Save Password Button + Padding( + padding: const EdgeInsets.fromLTRB(20, 40, 20, Constants.bottomInsets), + child: SavePasswordButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + final _authProv = context.read(authProvider.notifier); + _authProv.changePassword( + newPassword: newPasswordController.text, + ); + } + }, + ), ), - ), + + const SizedBox(height: 5), + ], ), ), ), diff --git a/lib/views/screens/login_screen.dart b/lib/views/screens/login_screen.dart index afc5a4d..0ffa92c 100644 --- a/lib/views/screens/login_screen.dart +++ b/lib/views/screens/login_screen.dart @@ -110,17 +110,16 @@ class LoginScreen extends HookWidget { //Login button Padding( - padding: const EdgeInsets.fromLTRB( - 20, 40, 20, Constants.bottomInsets), + padding: const EdgeInsets.fromLTRB(20, 40, 20, Constants.bottomInsets), child: CustomTextButton.gradient( width: double.infinity, onPressed: () async { if (formKey.currentState!.validate()) { formKey.currentState!.save(); context.read(authProvider.notifier).login( - email: emailController.text, - password: passwordController.text, - ); + email: emailController.text, + password: passwordController.text, + ); } }, gradient: Constants.buttonGradientOrange, diff --git a/lib/views/screens/welcome_screen.dart b/lib/views/screens/welcome_screen.dart index 835989a..3592ab9 100644 --- a/lib/views/screens/welcome_screen.dart +++ b/lib/views/screens/welcome_screen.dart @@ -10,6 +10,9 @@ import '../../helper/utils/constants.dart'; //Providers import '../../providers/all_providers.dart'; +//Routes +import '../../routes/app_router.gr.dart'; + //Widgets import '../widgets/welcome/user_profile_details.dart'; import '../widgets/welcome/view_bookings_button.dart'; @@ -30,20 +33,39 @@ class WelcomeScreen extends StatelessWidget { const SizedBox(height: 65), //Logout - RotatedBox( - quarterTurns: 2, - child: InkResponse( - radius: 26, - child: const Icon( - Icons.logout, - color: Constants.primaryColor, - size: 30, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + //Log out icon + RotatedBox( + quarterTurns: 2, + child: InkResponse( + radius: 26, + child: const Icon( + Icons.logout, + color: Constants.primaryColor, + size: 30, + ), + onTap: () { + context.read(authProvider.notifier).logout(); + context.router.popUntilRoot(); + }, + ), ), - onTap: () { - context.read(authProvider.notifier).logout(); - context.router.popUntilRoot(); - }, - ), + + //Edit profile icon + InkResponse( + radius: 26, + child: const Icon( + Icons.manage_accounts_sharp, + color: Constants.primaryColor, + size: 30, + ), + onTap: () { + context.router.push(const ChangePasswordScreenRoute()); + }, + ) + ], ), const SizedBox(height: 20), diff --git a/lib/views/widgets/change_password/change_password_fields.dart b/lib/views/widgets/change_password/change_password_fields.dart index 2caf5df..ce50de2 100644 --- a/lib/views/widgets/change_password/change_password_fields.dart +++ b/lib/views/widgets/change_password/change_password_fields.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -//Helpers -import '../../../helper/utils/constants.dart'; -import '../../../helper/extensions/context_extensions.dart'; +//Providers +import '../../../providers/all_providers.dart'; //Widgets import '../common/custom_textfield.dart'; @@ -22,70 +22,50 @@ class ChangePasswordFields extends StatelessWidget { Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - //Current Password Label - Text( - "Current Password", - style: context.bodyText1.copyWith( - color: Constants.primaryColor, - fontSize: 26, - fontWeight: FontWeight.bold - ), - ), //Current Password Field CustomTextField( - controller: currentPasswordController, hintText: "Enter current password", + floatingText: "Current Password", + controller: currentPasswordController, keyboardType: TextInputType.visiblePassword, - textInputAction: TextInputAction.done, - validator: (cPassword) { - if (newPasswordController.text.trim() == cPassword) return null; - return "Passwords don't match"; + textInputAction: TextInputAction.next, + validator: (currPassword) { + final authProv = context.read(authProvider.notifier); + if (authProv.currentUserPassword == currPassword) return null; + return "Invalid current password!"; }, ), - const Spacer(), - - //New Password Label - Text( - "New Password", - style: context.bodyText1.copyWith( - color: Constants.primaryColor, - fontSize: 26, - fontWeight: FontWeight.bold - ), - ), + const SizedBox(height: 25), //New Password Field CustomTextField( - controller: newPasswordController, hintText: "Type your password", + floatingText: "New Password", + controller: newPasswordController, keyboardType: TextInputType.visiblePassword, textInputAction: TextInputAction.next, validator: (password) { - if (password!.isEmpty) return "Please enter a password"; + final authProv = context.read(authProvider.notifier); + if (password!.isEmpty) { + return "Please enter a password"; + } + else if(authProv.currentUserPassword == password) { + return "Current and new password can't be same"; + } return null; }, ), - const Spacer(), - - //Confirm New Password Label - Text( - "Confirm Password", - style: context.bodyText1.copyWith( - color: Constants.primaryColor, - fontSize: 26, - fontWeight: FontWeight.bold - ), - ), + const SizedBox(height: 25), //Confirm New Password Field CustomTextField( - controller: cNewPasswordController, hintText: "Retype your password", + floatingText: "New Password", + controller: cNewPasswordController, keyboardType: TextInputType.visiblePassword, textInputAction: TextInputAction.done, validator: (cPassword) { @@ -97,5 +77,3 @@ class ChangePasswordFields extends StatelessWidget { ); } } - - diff --git a/lib/views/widgets/change_password/save_password_button.dart b/lib/views/widgets/change_password/save_password_button.dart index a94f439..064b51b 100644 --- a/lib/views/widgets/change_password/save_password_button.dart +++ b/lib/views/widgets/change_password/save_password_button.dart @@ -27,7 +27,7 @@ class SavePasswordButton extends StatelessWidget { gradient: Constants.buttonGradientOrange, child: Consumer( builder: (context, watch, child) { - final _changePasswordState = watch(changePasswordState).state; + final _changePasswordState = watch(changePasswordStateProvider).state; return _changePasswordState.maybeWhen( loading: () => const Center( child: SpinKitRing( diff --git a/lib/views/widgets/common/custom_textfield.dart b/lib/views/widgets/common/custom_textfield.dart index b16ea73..f19ffd2 100644 --- a/lib/views/widgets/common/custom_textfield.dart +++ b/lib/views/widgets/common/custom_textfield.dart @@ -126,31 +126,31 @@ class _CustomTextFieldState extends State { controller: widget.controller, autofocus: widget.autofocus, maxLength: widget.maxLength, + keyboardType: widget.keyboardType, + textInputAction: widget.textInputAction, + style: widget.inputStyle, maxLengthEnforcement: MaxLengthEnforcement.enforced, textAlignVertical: TextAlignVertical.center, - showCursor: true, - obscureText: hidePassword, - cursorColor: Colors.white, autovalidateMode: AutovalidateMode.disabled, + cursorColor: Colors.white, + obscureText: isPasswordField && hidePassword, + showCursor: true, validator: _onValidate, onSaved: _onSaved, onFieldSubmitted: _onFieldSubmitted, - keyboardType: widget.keyboardType, - textInputAction: widget.textInputAction, - style: widget.inputStyle, decoration: InputDecoration( - contentPadding: const EdgeInsets.fromLTRB(17, 10, 1, 10), - isDense: true, - counterText: "", hintText: widget.hintText, hintStyle: widget.hintStyle, errorStyle: widget.errorStyle, + fillColor: widget.fillColor, + prefixIcon: widget.prefix, + contentPadding: const EdgeInsets.fromLTRB(17, 10, 1, 10), + isDense: true, + filled: true, + counterText: "", border: _normalBorder(), focusedBorder: _focusedBorder(), focusedErrorBorder: _focusedBorder(), - fillColor: widget.fillColor, - filled: true, - prefixIcon: widget.prefix, suffixIcon: isPasswordField ? InkWell( onTap: () { diff --git a/lib/views/widgets/user_bookings/user_bookings_list.dart b/lib/views/widgets/user_bookings/user_bookings_list.dart index c91e992..7bb8614 100644 --- a/lib/views/widgets/user_bookings/user_bookings_list.dart +++ b/lib/views/widgets/user_bookings/user_bookings_list.dart @@ -58,15 +58,15 @@ class UserBookingsList extends StatelessWidget { return SizedBox( height: 140, child: GestureDetector( - onTap: () {}, + onTap: () => onTap(context,booking), child: Stack( alignment: Alignment.bottomCenter, children: [ //Booking overview BookingSummaryRow( total: total, - title: booking.title, noOfSeats: noOfSeats, + title: booking.title, showDateTime: booking.show.showDatetime, showType: booking.show.showType, ),