diff --git a/assets/translations/en.json b/assets/translations/en.json index 5e813da5..b68c6b82 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -283,6 +283,8 @@ "account": "Account", "send_registration_data": "Share login credentials", "could_not_fetch_users": "Couldn't fetch users list", + "could_not_fetch_description": "Please check your internet connection and try again", + "refresh_users": "Refresh users list", "could_not_create_user": "Couldn't create user", "could_not_delete_user": "Couldn't delete user", "could_not_add_ssh_key": "Couldn't add SSH key" diff --git a/lib/logic/api_maps/graphql_maps/server_api/users_api.dart b/lib/logic/api_maps/graphql_maps/server_api/users_api.dart index 359967b7..be7d4fb0 100644 --- a/lib/logic/api_maps/graphql_maps/server_api/users_api.dart +++ b/lib/logic/api_maps/graphql_maps/server_api/users_api.dart @@ -31,7 +31,6 @@ mixin UsersApi on ApiMap { } } catch (e) { print(e); - print("Could not"); } return users; } diff --git a/lib/logic/cubit/services/services_state.dart b/lib/logic/cubit/services/services_state.dart index 752347c2..07b82e45 100644 --- a/lib/logic/cubit/services/services_state.dart +++ b/lib/logic/cubit/services/services_state.dart @@ -9,29 +9,41 @@ class ServicesState extends ServerInstallationDependendState { final List services; bool get isPasswordManagerEnable => services - .firstWhere((final service) => service.id == 'bitwarden', - orElse: () => Service.empty) + .firstWhere( + (final service) => service.id == 'bitwarden', + orElse: () => Service.empty, + ) .isEnabled; bool get isCloudEnable => services - .firstWhere((final service) => service.id == 'nextcloud', - orElse: () => Service.empty) + .firstWhere( + (final service) => service.id == 'nextcloud', + orElse: () => Service.empty, + ) .isEnabled; bool get isGitEnable => services - .firstWhere((final service) => service.id == 'gitea', - orElse: () => Service.empty) + .firstWhere( + (final service) => service.id == 'gitea', + orElse: () => Service.empty, + ) .isEnabled; bool get isSocialNetworkEnable => services - .firstWhere((final service) => service.id == 'pleroma', - orElse: () => Service.empty) + .firstWhere( + (final service) => service.id == 'pleroma', + orElse: () => Service.empty, + ) .isEnabled; bool get isVpnEnable => services - .firstWhere((final service) => service.id == 'ocserv', - orElse: () => Service.empty) + .firstWhere( + (final service) => service.id == 'ocserv', + orElse: () => Service.empty, + ) .isEnabled; Service? getServiceById(final String id) { - final service = services.firstWhere((final service) => service.id == id, - orElse: () => Service.empty); + final service = services.firstWhere( + (final service) => service.id == id, + orElse: () => Service.empty, + ); if (service.id == 'empty') { return null; } diff --git a/lib/logic/cubit/users/users_cubit.dart b/lib/logic/cubit/users/users_cubit.dart index c9f8e804..1ff0e9a3 100644 --- a/lib/logic/cubit/users/users_cubit.dart +++ b/lib/logic/cubit/users/users_cubit.dart @@ -16,6 +16,7 @@ class UsersCubit extends ServerInstallationDependendCubit { serverInstallationCubit, const UsersState( [], + false, ), ); Box box = Hive.box(BNames.usersBox); @@ -33,6 +34,7 @@ class UsersCubit extends ServerInstallationDependendCubit { emit( UsersState( loadedUsers, + false, ), ); } @@ -44,11 +46,15 @@ class UsersCubit extends ServerInstallationDependendCubit { if (serverInstallationCubit.state is! ServerInstallationFinished) { return; } + emit(state.copyWith(isLoading: true)); + // sleep for 10 seconds to simulate a slow connection + await Future.delayed(const Duration(seconds: 10)); final List usersFromServer = await api.getAllUsers(); if (usersFromServer.isNotEmpty) { emit( UsersState( usersFromServer, + false, ), ); // Update the users it the box @@ -57,6 +63,7 @@ class UsersCubit extends ServerInstallationDependendCubit { } else { getIt() .showSnackBar('users.could_not_fetch_users'.tr()); + emit(state.copyWith(isLoading: false)); } } @@ -110,7 +117,9 @@ class UsersCubit extends ServerInstallationDependendCubit { } Future changeUserPassword( - final User user, final String newPassword) async { + final User user, + final String newPassword, + ) async { if (user.type == UserType.root) { getIt() .showSnackBar('users.could_not_change_password'.tr()); @@ -120,7 +129,8 @@ class UsersCubit extends ServerInstallationDependendCubit { await api.updateUser(user.login, newPassword); if (!result.success) { getIt().showSnackBar( - result.message ?? 'users.could_not_change_password'.tr()); + result.message ?? 'users.could_not_change_password'.tr(), + ); } } @@ -160,6 +170,7 @@ class UsersCubit extends ServerInstallationDependendCubit { emit( const UsersState( [], + false, ), ); } diff --git a/lib/logic/cubit/users/users_state.dart b/lib/logic/cubit/users/users_state.dart index 1065afc0..dbd931d7 100644 --- a/lib/logic/cubit/users/users_state.dart +++ b/lib/logic/cubit/users/users_state.dart @@ -1,9 +1,10 @@ part of 'users_cubit.dart'; class UsersState extends ServerInstallationDependendState { - const UsersState(this.users); + const UsersState(this.users, this.isLoading); final List users; + final bool isLoading; User get rootUser => users.firstWhere((final user) => user.type == UserType.root); @@ -15,13 +16,15 @@ class UsersState extends ServerInstallationDependendState { users.where((final user) => user.type == UserType.normal).toList(); @override - List get props => [users]; + List get props => [users, isLoading]; UsersState copyWith({ final List? users, + final bool? isLoading, }) => UsersState( users ?? this.users, + isLoading ?? this.isLoading, ); bool isLoginRegistered(final String login) => diff --git a/lib/ui/pages/users/empty.dart b/lib/ui/pages/users/empty.dart index 847003d3..dc2d292b 100644 --- a/lib/ui/pages/users/empty.dart +++ b/lib/ui/pages/users/empty.dart @@ -31,3 +31,35 @@ class _NoUsers extends StatelessWidget { ), ); } + +class _CouldNotLoadUsers extends StatelessWidget { + const _CouldNotLoadUsers({required this.text}); + + final String text; + + @override + Widget build(final BuildContext context) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(BrandIcons.users, size: 50, color: BrandColors.grey7), + const SizedBox(height: 20), + BrandText.h2( + 'users.could_not_fetch_users'.tr(), + style: const TextStyle( + color: BrandColors.grey7, + ), + ), + const SizedBox(height: 10), + BrandText.medium( + text, + textAlign: TextAlign.center, + style: const TextStyle( + color: BrandColors.grey7, + ), + ), + ], + ), + ); +} diff --git a/lib/ui/pages/users/users.dart b/lib/ui/pages/users/users.dart index 3ccb696a..fb526970 100644 --- a/lib/ui/pages/users/users.dart +++ b/lib/ui/pages/users/users.dart @@ -14,6 +14,7 @@ import 'package:selfprivacy/logic/models/job.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; +import 'package:selfprivacy/ui/components/brand_button/outlined_button.dart'; import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; @@ -46,10 +47,47 @@ class UsersPage extends StatelessWidget { } else { child = BlocBuilder( builder: (final BuildContext context, final UsersState state) { - print('Rebuild users page'); - final primaryUser = state.primaryUser; - final users = [primaryUser, ...state.users]; + final List users = state.users + .where((final user) => user.type != UserType.root) + .toList(); + // final List users = []; + users.sort( + (final User a, final User b) => + a.login.toLowerCase().compareTo(b.login.toLowerCase()), + ); + if (users.isEmpty) { + if (state.isLoading) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return RefreshIndicator( + onRefresh: () async { + context.read().refresh(); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _CouldNotLoadUsers( + text: 'users.could_not_fetch_description'.tr(), + ), + const SizedBox(height: 18), + BrandOutlinedButton( + onPressed: () { + context.read().refresh(); + }, + title: 'users.refresh_users'.tr(), + ), + ], + ), + ), + ), + ); + } return RefreshIndicator( onRefresh: () async { context.read().refresh(); @@ -59,7 +97,7 @@ class UsersPage extends StatelessWidget { itemBuilder: (final BuildContext context, final int index) => _User( user: users[index], - isRootUser: index == 0, + isRootUser: users[index].type == UserType.primary, ), ), );