From bfd6f789f560735a6178e758dd7533a46c346851 Mon Sep 17 00:00:00 2001 From: Benjamin Canape Date: Tue, 6 Feb 2024 00:09:20 +0100 Subject: [PATCH] improve loaders (#44) * improve loading activity * improve edit profile and password screen loading * improve remove activity loader * improve logout loader * improve delete account loader * fix loader position * fix imports --- .../activity_item_like_view_model.dart | 3 +- .../view_model/activity_item_view_model.dart | 6 + .../activity_item_user_informations.dart | 2 +- .../common/user/screens/profile_screen.dart | 10 +- .../community/screens/community_screen.dart | 4 +- .../screens/pending_requests_screen.dart | 4 +- .../screens/activity_details_screen.dart | 26 +- .../screens/activity_list_screen.dart | 4 +- .../activity_details_view_model.dart | 1 - .../view_model/activity_list_view_model.dart | 4 + .../screens/edit_password_screen.dart | 48 ++-- .../settings/screens/edit_profile_screen.dart | 260 +++++++++--------- .../settings/screens/settings_screen.dart | 2 +- .../view_model/edit_profile_view_model.dart | 2 +- .../view_model/settings_view_model.dart | 20 +- 15 files changed, 213 insertions(+), 183 deletions(-) diff --git a/lib/presentation/common/activity/view_model/activity_item_like_view_model.dart b/lib/presentation/common/activity/view_model/activity_item_like_view_model.dart index 0ee37f2e..139223a3 100644 --- a/lib/presentation/common/activity/view_model/activity_item_like_view_model.dart +++ b/lib/presentation/common/activity/view_model/activity_item_like_view_model.dart @@ -1,9 +1,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../../core/widgets/view_model/infinite_scroll_list_view_model.dart'; + import '../../../../data/repositories/activity_repository_impl.dart'; import '../../../../domain/entities/activity.dart'; import '../../core/enums/infinite_scroll_list.enum.dart'; import '../../core/utils/activity_utils.dart'; +import '../../core/widgets/view_model/infinite_scroll_list_view_model.dart'; import 'state/activity_item_like_state.dart'; /// Provider for the activity item like view model. diff --git a/lib/presentation/common/activity/view_model/activity_item_view_model.dart b/lib/presentation/common/activity/view_model/activity_item_view_model.dart index 0d9eae96..b1a9b6b7 100644 --- a/lib/presentation/common/activity/view_model/activity_item_view_model.dart +++ b/lib/presentation/common/activity/view_model/activity_item_view_model.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../../user/view_model/profile_picture_view_model.dart'; +import '../../../my_activities/view_model/activity_list_view_model.dart'; import '../../../../data/repositories/activity_repository_impl.dart'; import '../../../../domain/entities/activity.dart'; import '../../../../main.dart'; @@ -37,6 +38,7 @@ class ActivityItemViewModel extends StateNotifier { /// Retrieves the details of an activity. Future getActivityDetails(Activity activity) async { try { + ref.read(activityListViewModelProvider.notifier).setIsLoading(true); final activityDetails = await ref .read(activityRepositoryProvider) .getActivityById(id: activity.id); @@ -49,6 +51,10 @@ class ActivityItemViewModel extends StateNotifier { /// Navigates to the activity details screen. void goToActivity(Activity activityDetails) { + Future.delayed(const Duration(milliseconds: 500), () { + ref.read(activityListViewModelProvider.notifier).setIsLoading(false); + }); + navigatorKey.currentState?.push( PageRouteBuilder( transitionDuration: const Duration(milliseconds: 500), diff --git a/lib/presentation/common/activity/widgets/activity_item_user_informations.dart b/lib/presentation/common/activity/widgets/activity_item_user_informations.dart index bfe01550..bb71b08c 100644 --- a/lib/presentation/common/activity/widgets/activity_item_user_informations.dart +++ b/lib/presentation/common/activity/widgets/activity_item_user_informations.dart @@ -2,12 +2,12 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../../user/view_model/profile_picture_view_model.dart'; import '../../../../domain/entities/activity.dart'; import '../../core/utils/color_utils.dart'; import '../../core/utils/ui_utils.dart'; import '../../core/utils/user_utils.dart'; +import '../../user/view_model/profile_picture_view_model.dart'; import '../view_model/activity_item_view_model.dart'; class ActivityItemUserInformation extends HookConsumerWidget { diff --git a/lib/presentation/common/user/screens/profile_screen.dart b/lib/presentation/common/user/screens/profile_screen.dart index 587c468b..206d9bc5 100644 --- a/lib/presentation/common/user/screens/profile_screen.dart +++ b/lib/presentation/common/user/screens/profile_screen.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../view_model/profile_picture_view_model.dart'; import '../../../../domain/entities/activity.dart'; import '../../../../domain/entities/enum/friend_request_status.dart'; @@ -10,6 +9,7 @@ import '../../activity/widgets/activity_list.dart'; import '../../core/enums/infinite_scroll_list.enum.dart'; import '../../core/utils/ui_utils.dart'; import '../../core/utils/user_utils.dart'; +import '../view_model/profile_picture_view_model.dart'; import '../view_model/profile_view_model.dart'; import '../widgets/friend_request.dart'; @@ -47,7 +47,7 @@ class ProfileScreen extends HookConsumerWidget { var activitiesStateProvider = ref.watch(activitiesDataFutureProvider(user)); return state.isLoading - ? Center(child: UIUtils.loader) + ? Expanded(child: Center(child: UIUtils.loader)) : Scaffold( body: SafeArea( child: Column( @@ -93,7 +93,8 @@ class ProfileScreen extends HookConsumerWidget { return widget; }, loading: () { - return Center(child: UIUtils.loader); + return Expanded( + child: Center(child: UIUtils.loader)); }, error: (error, stackTrace) { return Text('$error'); @@ -126,7 +127,8 @@ class ProfileScreen extends HookConsumerWidget { provider.fetchActivities); }, loading: () { - return Center(child: UIUtils.loader); + return Expanded( + child: Center(child: UIUtils.loader)); }, error: (error, stackTrace) { return Text('$error'); diff --git a/lib/presentation/community/screens/community_screen.dart b/lib/presentation/community/screens/community_screen.dart index 1d92a53a..84aa0d91 100644 --- a/lib/presentation/community/screens/community_screen.dart +++ b/lib/presentation/community/screens/community_screen.dart @@ -107,7 +107,7 @@ class CommunityScreen extends HookConsumerWidget { : Container(); }, loading: () { - return Center(child: UIUtils.loader); + return Expanded(child: Center(child: UIUtils.loader)); }, error: (error, stackTrace) { return Text('$error'); @@ -134,7 +134,7 @@ class CommunityScreen extends HookConsumerWidget { ); }, loading: () { - return Center(child: UIUtils.loader); + return Expanded(child: Center(child: UIUtils.loader)); }, error: (error, stackTrace) { return Text('$error'); diff --git a/lib/presentation/community/screens/pending_requests_screen.dart b/lib/presentation/community/screens/pending_requests_screen.dart index 5afa4552..8db0ea3e 100644 --- a/lib/presentation/community/screens/pending_requests_screen.dart +++ b/lib/presentation/community/screens/pending_requests_screen.dart @@ -27,7 +27,7 @@ class PendingRequestsScreen extends HookConsumerWidget { ref.watch(pendingRequestsDataFutureProvider); return state.isLoading - ? Center(child: UIUtils.loader) + ? Expanded(child: Center(child: UIUtils.loader)) : Scaffold( body: SafeArea( child: Column(children: [ @@ -46,7 +46,7 @@ class PendingRequestsScreen extends HookConsumerWidget { ); }, loading: () { - return Center(child: UIUtils.loader); + return Expanded(child: Center(child: UIUtils.loader)); }, error: (error, stackTrace) { return Text('$error'); diff --git a/lib/presentation/my_activities/screens/activity_details_screen.dart b/lib/presentation/my_activities/screens/activity_details_screen.dart index b6ae68ff..55b154cf 100644 --- a/lib/presentation/my_activities/screens/activity_details_screen.dart +++ b/lib/presentation/my_activities/screens/activity_details_screen.dart @@ -65,18 +65,20 @@ class ActivityDetailsScreen extends HookConsumerWidget { tooltip: 'Remove', onPressed: () { QuickAlert.show( - context: context, - type: QuickAlertType.confirm, - title: AppLocalizations.of(context)! - .ask_activity_removal, - confirmBtnText: - AppLocalizations.of(context)!.delete, - cancelBtnText: AppLocalizations.of(context)!.cancel, - confirmBtnColor: ColorUtils.red, - onCancelBtnTap: () => Navigator.of(context).pop(), - onConfirmBtnTap: () => - provider.removeActivity(displayedActivity), - ); + context: context, + type: QuickAlertType.confirm, + title: AppLocalizations.of(context)! + .ask_activity_removal, + confirmBtnText: + AppLocalizations.of(context)!.delete, + cancelBtnText: + AppLocalizations.of(context)!.cancel, + confirmBtnColor: ColorUtils.red, + onCancelBtnTap: () => Navigator.of(context).pop(), + onConfirmBtnTap: () { + Navigator.of(context).pop(); + provider.removeActivity(displayedActivity); + }); }, icon: Icon( Icons.delete, diff --git a/lib/presentation/my_activities/screens/activity_list_screen.dart b/lib/presentation/my_activities/screens/activity_list_screen.dart index 44ec3626..8fb9eed8 100644 --- a/lib/presentation/my_activities/screens/activity_list_screen.dart +++ b/lib/presentation/my_activities/screens/activity_list_screen.dart @@ -27,7 +27,7 @@ class ActivityListScreen extends HookConsumerWidget { return Scaffold( body: isLoading - ? Center(child: UIUtils.loader) + ? Expanded(child: Center(child: UIUtils.loader)) : SafeArea( child: Column( children: [ @@ -41,7 +41,7 @@ class ActivityListScreen extends HookConsumerWidget { ); }, loading: () { - return Center(child: UIUtils.loader); + return Expanded(child: Center(child: UIUtils.loader)); }, error: (error, stackTrace) { return Text('$error'); diff --git a/lib/presentation/my_activities/view_model/activity_details_view_model.dart b/lib/presentation/my_activities/view_model/activity_details_view_model.dart index 3d40291d..cf32b87c 100644 --- a/lib/presentation/my_activities/view_model/activity_details_view_model.dart +++ b/lib/presentation/my_activities/view_model/activity_details_view_model.dart @@ -66,7 +66,6 @@ class ActivityDetailsViewModel extends StateNotifier { ActivityUtils.updateActivity( ref, activityWithoutLocations, ActivityUpdateActionEnum.remove); - navigatorKey.currentState?.pop(); navigatorKey.currentState?.pop(); ref.read(homeViewModelProvider.notifier).setCurrentIndex(Tabs.list.index); navigatorKey.currentState?.pushReplacement( diff --git a/lib/presentation/my_activities/view_model/activity_list_view_model.dart b/lib/presentation/my_activities/view_model/activity_list_view_model.dart index 92592e7f..63ed23fd 100644 --- a/lib/presentation/my_activities/view_model/activity_list_view_model.dart +++ b/lib/presentation/my_activities/view_model/activity_list_view_model.dart @@ -69,4 +69,8 @@ class ActivityListViewModel extends StateNotifier { ), ); } + + void setIsLoading(bool isLoading) { + state = state.copyWith(isLoading: isLoading); + } } diff --git a/lib/presentation/settings/screens/edit_password_screen.dart b/lib/presentation/settings/screens/edit_password_screen.dart index 14297c74..8dfc17b3 100644 --- a/lib/presentation/settings/screens/edit_password_screen.dart +++ b/lib/presentation/settings/screens/edit_password_screen.dart @@ -100,30 +100,32 @@ class EditPasswordScreen extends HookConsumerWidget { ], ), ), - floatingActionButton: Stack( - children: [ - Positioned( - bottom: 16, - right: 80, - child: FloatingActionButton( - backgroundColor: ColorUtils.main, - elevation: 4.0, - child: Icon( - Icons.save, - color: ColorUtils.white, - ), - onPressed: () { - provider.submitForm(context, formKey); - }, + floatingActionButton: state.isEditing + ? Container() + : Stack( + children: [ + Positioned( + bottom: 16, + right: 80, + child: FloatingActionButton( + backgroundColor: ColorUtils.main, + elevation: 4.0, + child: Icon( + Icons.save, + color: ColorUtils.white, + ), + onPressed: () { + provider.submitForm(context, formKey); + }, + ), + ), + Positioned( + bottom: 16, + left: 80, + child: UIUtils.createBackButton(context), + ), + ], ), - ), - Positioned( - bottom: 16, - left: 80, - child: UIUtils.createBackButton(context), - ), - ], - ), ); } } diff --git a/lib/presentation/settings/screens/edit_profile_screen.dart b/lib/presentation/settings/screens/edit_profile_screen.dart index 384132b7..4921070c 100644 --- a/lib/presentation/settings/screens/edit_profile_screen.dart +++ b/lib/presentation/settings/screens/edit_profile_screen.dart @@ -3,7 +3,6 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../../common/user/view_model/profile_picture_view_model.dart'; import '../../../domain/entities/user.dart'; import '../../common/core/utils/color_utils.dart'; @@ -11,6 +10,7 @@ import '../../common/core/utils/form_utils.dart'; import '../../common/core/utils/ui_utils.dart'; import '../../common/core/validators/login_validators.dart'; import '../../common/core/widgets/upload_file.dart'; +import '../../common/user/view_model/profile_picture_view_model.dart'; import '../view_model/edit_profile_view_model.dart'; class EditProfileScreen extends HookConsumerWidget { @@ -34,130 +34,142 @@ class EditProfileScreen extends HookConsumerWidget { var editProfileStateProvider = ref.watch(editProfileFutureProvider); - return editProfileStateProvider.when( - data: (user) { - Uint8List? profilePicture; - user != null - ? profilePicture = ref - .watch(profilePictureViewModelProvider(user.id)) - .profilePicture - : profilePicture = null; - return Scaffold( - resizeToAvoidBottomInset: true, - body: state.isEditing - ? Center(child: UIUtils.loader) - : SafeArea( - child: Padding( - padding: const EdgeInsets.only(bottom: 100.0), - child: ListView( - keyboardDismissBehavior: - ScrollViewKeyboardDismissBehavior.onDrag, - children: [ - Column( - children: [ - UIUtils.createHeader( - AppLocalizations.of(context)!.edit_profile), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.all(10), - child: Form( - key: formKey, - child: Column( - children: [ - state.errorOnRequest - ? Column(children: [ - Text( - AppLocalizations.of(context)! - .edit_profile_error, - style: TextStyle( - color: ColorUtils.red, - fontSize: 18), - ), - const SizedBox(height: 20) - ]) - : Container(), - const SizedBox(height: 10), - UploadFileWidget( - image: profilePicture, - callbackFunc: - provider.chooseNewProfilePicture), - // Firstname TextFormField - TextFormField( - style: FormUtils.textFormFieldStyle, - decoration: - FormUtils.createInputDecorative( - AppLocalizations.of(context)! - .firstname, - dark: false, - icon: Icons.person, + return Scaffold( + body: state.isEditing + ? Center(child: UIUtils.loader) + : editProfileStateProvider.when( + data: (user) { + Uint8List? profilePicture; + user != null + ? profilePicture = ref + .watch(profilePictureViewModelProvider(user.id)) + .profilePicture + : profilePicture = null; + return Scaffold( + resizeToAvoidBottomInset: true, + body: state.isEditing + ? Center(child: UIUtils.loader) + : SafeArea( + child: Padding( + padding: const EdgeInsets.only(bottom: 100.0), + child: ListView( + keyboardDismissBehavior: + ScrollViewKeyboardDismissBehavior.onDrag, + children: [ + Column( + children: [ + UIUtils.createHeader( + AppLocalizations.of(context)! + .edit_profile), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: Column( + children: [ + state.errorOnRequest + ? Column(children: [ + Text( + AppLocalizations.of( + context)! + .edit_profile_error, + style: TextStyle( + color: ColorUtils + .red, + fontSize: 18), + ), + const SizedBox( + height: 20) + ]) + : Container(), + const SizedBox(height: 10), + UploadFileWidget( + image: profilePicture, + callbackFunc: provider + .chooseNewProfilePicture), + // Firstname TextFormField + TextFormField( + style: FormUtils + .textFormFieldStyle, + decoration: FormUtils + .createInputDecorative( + AppLocalizations.of( + context)! + .firstname, + dark: false, + icon: Icons.person, + ), + validator: (value) => + LoginValidators.name( + context, value), + onSaved: (value) { + provider + .setFirstname(value); + }, + initialValue: state.firstname, + ), + // Lastname TextFormField + TextFormField( + style: FormUtils + .textFormFieldStyle, + decoration: FormUtils + .createInputDecorative( + AppLocalizations.of( + context)! + .lastname, + dark: false, + icon: Icons.person, + ), + validator: (value) => + LoginValidators.name( + context, value), + onChanged: (value) { + provider.setLastname(value); + }, + initialValue: state.lastname, + ), + ], + ), + ), ), - validator: (value) => - LoginValidators.name( - context, value), - onSaved: (value) { - provider.setFirstname(value); - }, - initialValue: state.firstname, - ), - // Lastname TextFormField - TextFormField( - style: FormUtils.textFormFieldStyle, - decoration: - FormUtils.createInputDecorative( - AppLocalizations.of(context)! - .lastname, - dark: false, - icon: Icons.person, - ), - validator: (value) => - LoginValidators.name( - context, value), - onChanged: (value) { - provider.setLastname(value); - }, - initialValue: state.lastname, - ), - ], - ), - ), - ), - ], + ], + ), + ]), + ), + ), + floatingActionButton: Stack( + children: [ + Positioned( + bottom: 16, + right: 80, + child: FloatingActionButton( + backgroundColor: ColorUtils.main, + elevation: 4.0, + child: Icon( + Icons.save, + color: ColorUtils.white, + ), + onPressed: () { + provider.submitForm(context, formKey); + }, ), - ]), - ), - ), - floatingActionButton: Stack( - children: [ - Positioned( - bottom: 16, - right: 80, - child: FloatingActionButton( - backgroundColor: ColorUtils.main, - elevation: 4.0, - child: Icon( - Icons.save, - color: ColorUtils.white, - ), - onPressed: () { - provider.submitForm(context, formKey); - }, - ), - ), - Positioned( - bottom: 16, - left: 80, - child: UIUtils.createBackButton(context), - ), - ], - ), - ); - }, - loading: () { - return Center(child: UIUtils.loader); - }, - error: (error, stackTrace) { - return Text('$error'); - }, - ); + ), + Positioned( + bottom: 16, + left: 80, + child: UIUtils.createBackButton(context), + ), + ], + ), + ); + }, + loading: () { + return Center(child: UIUtils.loader); + }, + error: (error, stackTrace) { + return Text('$error'); + }, + )); } } diff --git a/lib/presentation/settings/screens/settings_screen.dart b/lib/presentation/settings/screens/settings_screen.dart index 1064ce12..a472c453 100644 --- a/lib/presentation/settings/screens/settings_screen.dart +++ b/lib/presentation/settings/screens/settings_screen.dart @@ -62,7 +62,7 @@ class SettingsScreen extends HookConsumerWidget { return Scaffold( body: Center( child: state.isLoading - ? UIUtils.loader + ? Center(child: UIUtils.loader) : Column( children: [ const SizedBox(height: 40), diff --git a/lib/presentation/settings/view_model/edit_profile_view_model.dart b/lib/presentation/settings/view_model/edit_profile_view_model.dart index ec70eb72..01129d3c 100644 --- a/lib/presentation/settings/view_model/edit_profile_view_model.dart +++ b/lib/presentation/settings/view_model/edit_profile_view_model.dart @@ -70,7 +70,7 @@ class EditProfileViewModel extends StateNotifier { state = state.copyWith(errorOnRequest: false); if (formKey.currentState!.validate()) { formKey.currentState!.save(); - state.copyWith(isEditing: true); + state = state.copyWith(isEditing: true); final userRepository = ref.read(userRepositoryProvider); final editProfileRequest = EditProfileRequest( diff --git a/lib/presentation/settings/view_model/settings_view_model.dart b/lib/presentation/settings/view_model/settings_view_model.dart index ef3e04e3..feb95bf9 100644 --- a/lib/presentation/settings/view_model/settings_view_model.dart +++ b/lib/presentation/settings/view_model/settings_view_model.dart @@ -55,15 +55,17 @@ class SettingsViewModel extends StateNotifier { void showDeleteAccountAlert(BuildContext context, String title, String confirmBtnText, String cancelBtnText) { QuickAlert.show( - context: context, - type: QuickAlertType.confirm, - title: title, - confirmBtnText: confirmBtnText, - cancelBtnText: cancelBtnText, - confirmBtnColor: ColorUtils.red, - onCancelBtnTap: () => Navigator.of(context).pop(), - onConfirmBtnTap: () => deleteUserAccount(), - ); + context: context, + type: QuickAlertType.confirm, + title: title, + confirmBtnText: confirmBtnText, + cancelBtnText: cancelBtnText, + confirmBtnColor: ColorUtils.red, + onCancelBtnTap: () => Navigator.of(context).pop(), + onConfirmBtnTap: () { + Navigator.of(context).pop(); + deleteUserAccount(); + }); } /// Clears the local storage.