From ee9b8a4e315062a9b18fb70af00e3b9c515027fc Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 24 Feb 2023 19:45:32 +0300 Subject: [PATCH] refactor(router): Move more pages to new router --- assets/translations/en.json | 1 + .../components/brand_header/brand_header.dart | 3 + .../root_scaffold_with_navigation.dart | 9 +- .../pages/backup_details/backup_details.dart | 8 +- lib/ui/pages/providers/providers.dart | 18 +- .../server_storage/extending_volume.dart | 8 +- .../pages/server_storage/server_storage.dart | 14 +- lib/ui/pages/server_storage/storage_card.dart | 13 +- lib/ui/pages/services/service_page.dart | 18 +- lib/ui/pages/services/services.dart | 145 ++++++----- lib/ui/pages/users/add_user_fab.dart | 22 -- lib/ui/pages/users/new_user.dart | 179 ++++++------- lib/ui/pages/users/user.dart | 4 +- lib/ui/pages/users/user_details.dart | 8 +- lib/ui/pages/users/users.dart | 42 ++- lib/ui/router/router.dart | 30 ++- lib/ui/router/router.gr.dart | 245 ++++++++++++++++++ 17 files changed, 500 insertions(+), 267 deletions(-) delete mode 100644 lib/ui/pages/users/add_user_fab.dart diff --git a/assets/translations/en.json b/assets/translations/en.json index 15727826..a6a2f05c 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -255,6 +255,7 @@ "subtitle": "Private VPN server" }, "users": { + "details_title": "User details", "add_new_user": "Add a first user", "new_user": "New user", "delete_user": "Delete user", diff --git a/lib/ui/components/brand_header/brand_header.dart b/lib/ui/components/brand_header/brand_header.dart index abdabc6f..3151aff7 100644 --- a/lib/ui/components/brand_header/brand_header.dart +++ b/lib/ui/components/brand_header/brand_header.dart @@ -25,5 +25,8 @@ class BrandHeader extends StatelessWidget { onBackButtonPressed ?? () => Navigator.of(context).pop(), ) : null, + actions: const [ + SizedBox.shrink(), + ], ); } diff --git a/lib/ui/layouts/root_scaffold_with_navigation.dart b/lib/ui/layouts/root_scaffold_with_navigation.dart index ae4574fe..8fd3d7a7 100644 --- a/lib/ui/layouts/root_scaffold_with_navigation.dart +++ b/lib/ui/layouts/root_scaffold_with_navigation.dart @@ -53,9 +53,10 @@ class RootScaffoldWithNavigation extends StatelessWidget { hidden: !(Breakpoints.small.isActive(context) && showBottomBar), key: const Key('bottomBar'), ), - floatingActionButton: showFab && Breakpoints.small.isActive(context) - ? const BrandFab() - : null, + floatingActionButton: + showFab && Breakpoints.small.isActive(context) && showBottomBar + ? const BrandFab() + : null, ); } } @@ -190,8 +191,6 @@ class _BottomBar extends StatelessWidget { .any((final route) => route.name == destination.route.routeName), ); - print(prevActiveIndex); - return AnimatedContainer( duration: const Duration(milliseconds: 500), height: hidden ? 0 : 80, diff --git a/lib/ui/pages/backup_details/backup_details.dart b/lib/ui/pages/backup_details/backup_details.dart index fd2757f8..8ba7ad30 100644 --- a/lib/ui/pages/backup_details/backup_details.dart +++ b/lib/ui/pages/backup_details/backup_details.dart @@ -13,14 +13,14 @@ import 'package:selfprivacy/ui/helpers/modals.dart'; GlobalKey navigatorKey = GlobalKey(); -class BackupDetails extends StatefulWidget { - const BackupDetails({super.key}); +class BackupDetailsPage extends StatefulWidget { + const BackupDetailsPage({super.key}); @override - State createState() => _BackupDetailsState(); + State createState() => _BackupDetailsPageState(); } -class _BackupDetailsState extends State +class _BackupDetailsPageState extends State with SingleTickerProviderStateMixin { @override Widget build(final BuildContext context) { diff --git a/lib/ui/pages/providers/providers.dart b/lib/ui/pages/providers/providers.dart index 1b9ffb47..c6cb3179 100644 --- a/lib/ui/pages/providers/providers.dart +++ b/lib/ui/pages/providers/providers.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/config/brand_theme.dart'; @@ -10,11 +11,8 @@ import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart'; import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; -import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart'; -import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart'; -import 'package:selfprivacy/ui/pages/server_details/server_details_screen.dart'; +import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/breakpoints.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; GlobalKey navigatorKey = GlobalKey(); @@ -84,8 +82,7 @@ class _ProvidersPageState extends State { subtitle: diskStatus.isDiskOkay ? 'storage.status_ok'.tr() : 'storage.status_error'.tr(), - onTap: () => Navigator.of(context) - .push(materialRoute(const ServerDetailsScreen())), + onTap: () => context.pushRoute(const ServerDetailsRoute()), ), const SizedBox(height: 16), _Card( @@ -95,11 +92,7 @@ class _ProvidersPageState extends State { subtitle: appConfig.isDomainSelected ? appConfig.serverDomain!.domainName : '', - onTap: () => Navigator.of(context).push( - materialRoute( - const DnsDetailsPage(), - ), - ), + onTap: () => context.pushRoute(const DnsDetailsRoute()), ), const SizedBox(height: 16), // TODO: When backups are fixed, show this card @@ -111,8 +104,7 @@ class _ProvidersPageState extends State { icon: BrandIcons.save, title: 'backup.card_title'.tr(), subtitle: isBackupInitialized ? 'backup.card_subtitle'.tr() : '', - onTap: () => Navigator.of(context) - .push(materialRoute(const BackupDetails())), + onTap: () => context.pushRoute(const BackupDetailsRoute()), ), ], ), diff --git a/lib/ui/pages/server_storage/extending_volume.dart b/lib/ui/pages/server_storage/extending_volume.dart index 808cd6d5..41b7b36f 100644 --- a/lib/ui/pages/server_storage/extending_volume.dart +++ b/lib/ui/pages/server_storage/extending_volume.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; @@ -8,8 +9,6 @@ import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/logic/models/disk_status.dart'; -import 'package:selfprivacy/ui/pages/root_route.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; class ExtendingVolumePage extends StatefulWidget { const ExtendingVolumePage({ @@ -155,10 +154,7 @@ class _ExtendingVolumePageState extends State { DiskSize.fromGibibyte(_currentSliderGbValue), context.read().reload, ); - Navigator.of(context).pushAndRemoveUntil( - materialRoute(const RootPage()), - (final predicate) => false, - ); + context.router.popUntilRoot(); }, child: Text('storage.extend_volume_button.title'.tr()), ), diff --git a/lib/ui/pages/server_storage/server_storage.dart b/lib/ui/pages/server_storage/server_storage.dart index 313fb5de..c7606b8e 100644 --- a/lib/ui/pages/server_storage/server_storage.dart +++ b/lib/ui/pages/server_storage/server_storage.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -7,9 +8,8 @@ import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/components/brand_button/outlined_button.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/logic/models/disk_status.dart'; -import 'package:selfprivacy/ui/pages/server_storage/extending_volume.dart'; import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:selfprivacy/ui/router/router.dart'; class ServerStoragePage extends StatefulWidget { const ServerStoragePage({ @@ -105,12 +105,10 @@ class ServerStorageSection extends StatelessWidget { const SizedBox(height: 16), BrandOutlinedButton( title: 'storage.extend_volume_button.title'.tr(), - onPressed: () => Navigator.of(context).push( - materialRoute( - ExtendingVolumePage( - diskVolumeToResize: volume, - diskStatus: diskStatus, - ), + onPressed: () => context.pushRoute( + ExtendingVolumeRoute( + diskVolumeToResize: volume, + diskStatus: diskStatus, ), ), ), diff --git a/lib/ui/pages/server_storage/storage_card.dart b/lib/ui/pages/server_storage/storage_card.dart index ae0c2369..ac633463 100644 --- a/lib/ui/pages/server_storage/storage_card.dart +++ b/lib/ui/pages/server_storage/storage_card.dart @@ -1,12 +1,12 @@ +import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart'; import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart'; import 'package:selfprivacy/logic/models/disk_status.dart'; -import 'package:selfprivacy/ui/pages/server_storage/server_storage.dart'; import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:selfprivacy/ui/router/router.dart'; class StorageCard extends StatelessWidget { const StorageCard({ @@ -45,13 +45,8 @@ class StorageCard extends StatelessWidget { clipBehavior: Clip.antiAlias, child: InkResponse( highlightShape: BoxShape.rectangle, - onTap: () => Navigator.of(context).push( - materialRoute( - ServerStoragePage( - diskStatus: diskStatus, - ), - ), - ), + onTap: () => + context.pushRoute(ServerStorageRoute(diskStatus: diskStatus)), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( diff --git a/lib/ui/pages/services/service_page.dart b/lib/ui/pages/services/service_page.dart index 289af2b1..88fedddd 100644 --- a/lib/ui/pages/services/service_page.dart +++ b/lib/ui/pages/services/service_page.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -8,9 +9,8 @@ import 'package:selfprivacy/logic/models/job.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; -import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart'; +import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/launch_url.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; class ServicePage extends StatefulWidget { const ServicePage({required this.serviceId, super.key}); @@ -111,14 +111,12 @@ class _ServicePageState extends State { ListTile( iconColor: Theme.of(context).colorScheme.onBackground, // Open page ServicesMigrationPage - onTap: () => Navigator.of(context).push( - materialRoute( - ServicesMigrationPage( - services: [service], - diskStatus: - context.read().state.diskStatus, - isMigration: false, - ), + onTap: () => context.pushRoute( + ServicesMigrationRoute( + services: [service], + diskStatus: + context.read().state.diskStatus, + isMigration: false, ), ), leading: const Icon(Icons.drive_file_move_outlined), diff --git a/lib/ui/pages/services/services.dart b/lib/ui/pages/services/services.dart index 3e919158..3d6b185e 100644 --- a/lib/ui/pages/services/services.dart +++ b/lib/ui/pages/services/services.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:selfprivacy/config/brand_theme.dart'; @@ -5,16 +6,14 @@ import 'package:selfprivacy/logic/cubit/server_installation/server_installation_ import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/logic/models/state_types.dart'; -import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart'; import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:selfprivacy/ui/pages/services/service_page.dart'; +import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/breakpoints.dart'; import 'package:selfprivacy/utils/launch_url.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; import 'package:selfprivacy/utils/ui_helpers.dart'; class ServicesPage extends StatefulWidget { @@ -101,79 +100,81 @@ class _Card extends StatelessWidget { } } - return GestureDetector( - onTap: isReady - ? () => Navigator.of(context) - .push(materialRoute(ServicePage(serviceId: service.id))) - : null, - child: BrandCards.big( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - IconStatusMask( - status: getStatus(service.status), - icon: SvgPicture.string( - service.svgIcon, - width: 30.0, - height: 30.0, - color: Theme.of(context).colorScheme.onBackground, - ), - ), - ], - ), - ClipRect( - child: Stack( + return Card( + clipBehavior: Clip.antiAlias, + child: InkResponse( + highlightShape: BoxShape.rectangle, + onTap: isReady + ? () => context.pushRoute( + ServiceRoute(serviceId: service.id), + ) + : null, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 10), - BrandText.h2(service.displayName), - const SizedBox(height: 10), - if (service.url != '' && service.url != null) - Column( - children: [ - GestureDetector( - onTap: () => launchURL( - service.url, - ), - child: Text( - '${service.url}', - style: TextStyle( - color: - Theme.of(context).colorScheme.secondary, - decoration: TextDecoration.underline, - ), - ), - ), - const SizedBox(height: 10), - ], - ), - if (service.id == 'mailserver') - Column( - children: [ - Text( - domainName, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - decoration: TextDecoration.underline, - ), - ), - const SizedBox(height: 10), - ], - ), - BrandText.body2(service.loginInfo), - const SizedBox(height: 10), - BrandText.body2(service.description), - const SizedBox(height: 10), - ], + IconStatusMask( + status: getStatus(service.status), + icon: SvgPicture.string( + service.svgIcon, + width: 30.0, + height: 30.0, + colorFilter: const ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), + ), ), ], ), - ) - ], + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + BrandText.h2(service.displayName), + const SizedBox(height: 10), + if (service.url != '' && service.url != null) + Column( + children: [ + GestureDetector( + onTap: () => launchURL( + service.url, + ), + child: Text( + '${service.url}', + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + decoration: TextDecoration.underline, + ), + ), + ), + const SizedBox(height: 10), + ], + ), + if (service.id == 'mailserver') + Column( + children: [ + Text( + domainName, + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + decoration: TextDecoration.underline, + ), + ), + const SizedBox(height: 10), + ], + ), + BrandText.body2(service.loginInfo), + const SizedBox(height: 10), + BrandText.body2(service.description), + const SizedBox(height: 10), + ], + ) + ], + ), ), ), ); diff --git a/lib/ui/pages/users/add_user_fab.dart b/lib/ui/pages/users/add_user_fab.dart deleted file mode 100644 index 7e87e51d..00000000 --- a/lib/ui/pages/users/add_user_fab.dart +++ /dev/null @@ -1,22 +0,0 @@ -part of 'users.dart'; - -class AddUserFab extends StatelessWidget { - const AddUserFab({super.key}); - - @override - Widget build(final BuildContext context) => FloatingActionButton.small( - heroTag: 'new_user_fab', - onPressed: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (final BuildContext context) => Padding( - padding: MediaQuery.of(context).viewInsets, - child: const NewUser(), - ), - ); - }, - child: const Icon(Icons.person_add_outlined), - ); -} diff --git a/lib/ui/pages/users/new_user.dart b/lib/ui/pages/users/new_user.dart index 7c393296..484ce174 100644 --- a/lib/ui/pages/users/new_user.dart +++ b/lib/ui/pages/users/new_user.dart @@ -1,7 +1,7 @@ part of 'users.dart'; -class NewUser extends StatelessWidget { - const NewUser({super.key}); +class NewUserPage extends StatelessWidget { + const NewUserPage({super.key}); @override Widget build(final BuildContext context) { @@ -10,108 +10,89 @@ class NewUser extends StatelessWidget { final String domainName = UiHelpers.getDomainName(config); - return BrandBottomSheet( - child: BlocProvider( - create: (final BuildContext context) { - final jobCubit = context.read(); - final jobState = jobCubit.state; - final users = []; - users.addAll(context.read().state.users); - if (jobState is JobsStateWithJobs) { - final jobs = jobState.clientJobList; - for (final job in jobs) { - if (job is CreateUserJob) { - users.add(job.user); - } + return BlocProvider( + create: (final BuildContext context) { + final jobCubit = context.read(); + final jobState = jobCubit.state; + final users = []; + users.addAll(context.read().state.users); + if (jobState is JobsStateWithJobs) { + final jobs = jobState.clientJobList; + for (final job in jobs) { + if (job is CreateUserJob) { + users.add(job.user); } } - return UserFormCubit( - jobsCubit: jobCubit, - fieldFactory: FieldCubitFactory(context), - ); - }, - child: Builder( - builder: (final BuildContext context) { - final FormCubitState formCubitState = - context.watch().state; + } + return UserFormCubit( + jobsCubit: jobCubit, + fieldFactory: FieldCubitFactory(context), + ); + }, + child: Builder( + builder: (final BuildContext context) { + final FormCubitState formCubitState = + context.watch().state; - return BlocListener( - listener: - (final BuildContext context, final FormCubitState state) { - if (state.isSubmitted) { - Navigator.pop(context); - } - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - BrandHeader( - title: 'users.new_user'.tr(), - ), - const SizedBox(width: 14), - Padding( - padding: paddingH15V0, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (formCubitState.isErrorShown) - Text( - 'users.username_rule'.tr(), - style: TextStyle( - color: Theme.of(context).colorScheme.error, - ), - ), - const SizedBox(width: 14), - IntrinsicHeight( - child: CubitFormTextField( - formFieldCubit: context.read().login, - decoration: InputDecoration( - labelText: 'users.login'.tr(), - suffixText: '@$domainName', - ), - ), - ), - const SizedBox(height: 20), - CubitFormTextField( - formFieldCubit: - context.read().password, - decoration: InputDecoration( - alignLabelWithHint: false, - labelText: 'basis.password'.tr(), - suffixIcon: Padding( - padding: const EdgeInsets.only(right: 8), - child: IconButton( - icon: Icon( - BrandIcons.refresh, - color: - Theme.of(context).colorScheme.secondary, - ), - onPressed: context - .read() - .genNewPassword, - ), - ), - ), - ), - const SizedBox(height: 30), - BrandButton.rised( - onPressed: formCubitState.isSubmitting - ? null - : () => context.read().trySubmit(), - text: 'basis.create'.tr(), - ), - const SizedBox(height: 40), - Text('users.new_user_info_note'.tr()), - const SizedBox(height: 30), - ], + return BlocListener( + listener: (final BuildContext context, final FormCubitState state) { + if (state.isSubmitted) { + context.router.pop(); + } + }, + child: BrandHeroScreen( + heroTitle: 'users.new_user'.tr(), + heroIcon: Icons.person_add_outlined, + children: [ + if (formCubitState.isErrorShown) + Text( + 'users.username_rule'.tr(), + style: TextStyle( + color: Theme.of(context).colorScheme.error, ), ), - ], - ), - ); - }, - ), + const SizedBox(width: 14), + IntrinsicHeight( + child: CubitFormTextField( + formFieldCubit: context.read().login, + decoration: InputDecoration( + labelText: 'users.login'.tr(), + suffixText: '@$domainName', + ), + ), + ), + const SizedBox(height: 20), + CubitFormTextField( + formFieldCubit: context.read().password, + decoration: InputDecoration( + alignLabelWithHint: false, + labelText: 'basis.password'.tr(), + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: IconButton( + icon: Icon( + BrandIcons.refresh, + color: Theme.of(context).colorScheme.secondary, + ), + onPressed: context.read().genNewPassword, + ), + ), + ), + ), + const SizedBox(height: 30), + BrandButton.rised( + onPressed: formCubitState.isSubmitting + ? null + : () => context.read().trySubmit(), + text: 'basis.create'.tr(), + ), + const SizedBox(height: 40), + Text('users.new_user_info_note'.tr()), + const SizedBox(height: 30), + ], + ), + ); + }, ), ); } diff --git a/lib/ui/pages/users/user.dart b/lib/ui/pages/users/user.dart index 2658d3cc..0ce6d8cc 100644 --- a/lib/ui/pages/users/user.dart +++ b/lib/ui/pages/users/user.dart @@ -11,9 +11,7 @@ class _User extends StatelessWidget { @override Widget build(final BuildContext context) => InkWell( onTap: () { - Navigator.of(context).push( - materialRoute(UserDetailsPage(login: user.login)), - ); + context.pushRoute(UserDetailsRoute(login: user.login)); }, child: Container( padding: paddingH15V0, diff --git a/lib/ui/pages/users/user_details.dart b/lib/ui/pages/users/user_details.dart index 0fc0447c..e7bb1995 100644 --- a/lib/ui/pages/users/user_details.dart +++ b/lib/ui/pages/users/user_details.dart @@ -87,6 +87,7 @@ class _DeleteUserTile extends StatelessWidget { onTap: () => { showDialog( context: context, + // useRootNavigator: false, builder: (final BuildContext context) => AlertDialog( title: Text('basis.confirmation'.tr()), content: SingleChildScrollView( @@ -102,7 +103,7 @@ class _DeleteUserTile extends StatelessWidget { TextButton( child: Text('basis.cancel'.tr()), onPressed: () { - Navigator.of(context).pop(); + context.router.pop(); }, ), TextButton( @@ -114,9 +115,8 @@ class _DeleteUserTile extends StatelessWidget { ), onPressed: () { context.read().addJob(DeleteUserJob(user: user)); - Navigator.of(context) - ..pop() - ..pop(); + context.router.childControllers.first.pop(); + context.router.pop(); }, ), ], diff --git a/lib/ui/pages/users/users.dart b/lib/ui/pages/users/users.dart index 51b29828..7ed3d929 100644 --- a/lib/ui/pages/users/users.dart +++ b/lib/ui/pages/users/users.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -22,16 +23,14 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/info_box/info_box.dart'; import 'package:selfprivacy/ui/components/list_tiles/list_tile_on_surface_variant.dart'; import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; +import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/breakpoints.dart'; import 'package:selfprivacy/utils/ui_helpers.dart'; -import 'package:selfprivacy/utils/route_transitions/basic.dart'; - part 'empty.dart'; part 'new_user.dart'; part 'user.dart'; part 'user_details.dart'; -part 'add_user_fab.dart'; part 'reset_password.dart'; class UsersPage extends StatelessWidget { @@ -93,13 +92,36 @@ class UsersPage extends StatelessWidget { onRefresh: () async { context.read().refresh(); }, - child: ListView.builder( - itemCount: users.length, - itemBuilder: (final BuildContext context, final int index) => - _User( - user: users[index], - isRootUser: users[index].type == UserType.primary, - ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: FilledButton.tonal( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.person_add_outlined), + const SizedBox(width: 8), + Text('users.new_user'.tr()), + ], + ), + onPressed: () { + context.pushRoute(const NewUserRoute()); + }, + ), + ), + Expanded( + child: ListView.builder( + itemCount: users.length, + itemBuilder: + (final BuildContext context, final int index) => _User( + user: users[index], + isRootUser: users[index].type == UserType.primary, + ), + ), + ), + ], ), ); }, diff --git a/lib/ui/router/router.dart b/lib/ui/router/router.dart index d6f8043f..13141fd5 100644 --- a/lib/ui/router/router.dart +++ b/lib/ui/router/router.dart @@ -3,7 +3,9 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/models/disk_status.dart'; import 'package:selfprivacy/logic/models/service.dart'; +import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart'; import 'package:selfprivacy/ui/pages/devices/devices.dart'; +import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart'; import 'package:selfprivacy/ui/pages/more/about_application.dart'; import 'package:selfprivacy/ui/pages/more/app_settings/app_settings.dart'; import 'package:selfprivacy/ui/pages/more/app_settings/developer_settings.dart'; @@ -13,7 +15,11 @@ import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart'; import 'package:selfprivacy/ui/pages/providers/providers.dart'; import 'package:selfprivacy/ui/pages/recovery_key/recovery_key.dart'; import 'package:selfprivacy/ui/pages/root_route.dart'; +import 'package:selfprivacy/ui/pages/server_details/server_details_screen.dart'; import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart'; +import 'package:selfprivacy/ui/pages/server_storage/extending_volume.dart'; +import 'package:selfprivacy/ui/pages/server_storage/server_storage.dart'; +import 'package:selfprivacy/ui/pages/services/service_page.dart'; import 'package:selfprivacy/ui/pages/services/services.dart'; import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart'; import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart'; @@ -75,10 +81,17 @@ Widget fadeThroughTransition( ), AutoRoute(page: AppSettingsPage), AutoRoute(page: UserDetailsPage), + AutoRoute(page: NewUserPage), AutoRoute(page: RecoveryKeyPage), AutoRoute(page: DevicesScreen), AutoRoute(page: AboutApplicationPage), AutoRoute(page: DeveloperSettingsPage), + AutoRoute(page: ServicePage), + AutoRoute(page: ServerDetailsScreen), + AutoRoute(page: DnsDetailsPage), + AutoRoute(page: BackupDetailsPage), + AutoRoute(page: ServerStoragePage), + AutoRoute(page: ExtendingVolumePage), ], ), AutoRoute(page: ServicesMigrationPage), @@ -97,6 +110,7 @@ String getRouteTitle(final String routeName) { case 'ProvidersRoute': return 'basis.providers_title'; case 'ServicesRoute': + case 'ServiceRoute': return 'basis.services'; case 'UsersRoute': return 'basis.users'; @@ -105,7 +119,9 @@ String getRouteTitle(final String routeName) { case 'AppSettingsRoute': return 'application_settings.title'; case 'UserDetailsRoute': - return '[User Details]'; + return 'users.details_title'; + case 'NewUserRoute': + return 'users.new_user'; case 'RecoveryKeyRoute': return 'recovery_key.key_main_header'; case 'DevicesRoute': @@ -113,9 +129,19 @@ String getRouteTitle(final String routeName) { case 'AboutApplicationRoute': return 'about_us_page.title'; case 'ConsoleRoute': - return '[Console]'; + return 'console_page.title'; case 'DeveloperSettingsRoute': return 'developer_settings.title'; + case 'DnsDetailsRoute': + return 'domain.screen_title'; + case 'ServerDetailsRoute': + return 'server.card_title'; + case 'BackupDetailsRoute': + return 'backup.card_title'; + case 'ServerStorageRoute': + return 'storage.card_title'; + case 'ExtendingVolumeRoute': + return 'storage.extending_volume_title'; default: return routeName; } diff --git a/lib/ui/router/router.gr.dart b/lib/ui/router/router.gr.dart index e2655f39..acbc7830 100644 --- a/lib/ui/router/router.gr.dart +++ b/lib/ui/router/router.gr.dart @@ -115,6 +115,12 @@ class _$RootRouter extends RootStackRouter { ), ); }, + NewUserRoute.name: (routeData) { + return MaterialPageX( + routeData: routeData, + child: const NewUserPage(), + ); + }, RecoveryKeyRoute.name: (routeData) { return MaterialPageX( routeData: routeData, @@ -139,6 +145,55 @@ class _$RootRouter extends RootStackRouter { child: const DeveloperSettingsPage(), ); }, + ServiceRoute.name: (routeData) { + final args = routeData.argsAs(); + return MaterialPageX( + routeData: routeData, + child: ServicePage( + serviceId: args.serviceId, + key: args.key, + ), + ); + }, + ServerDetailsRoute.name: (routeData) { + return MaterialPageX( + routeData: routeData, + child: const ServerDetailsScreen(), + ); + }, + DnsDetailsRoute.name: (routeData) { + return MaterialPageX( + routeData: routeData, + child: const DnsDetailsPage(), + ); + }, + BackupDetailsRoute.name: (routeData) { + return MaterialPageX( + routeData: routeData, + child: const BackupDetailsPage(), + ); + }, + ServerStorageRoute.name: (routeData) { + final args = routeData.argsAs(); + return MaterialPageX( + routeData: routeData, + child: ServerStoragePage( + diskStatus: args.diskStatus, + key: args.key, + ), + ); + }, + ExtendingVolumeRoute.name: (routeData) { + final args = routeData.argsAs(); + return MaterialPageX( + routeData: routeData, + child: ExtendingVolumePage( + diskVolumeToResize: args.diskVolumeToResize, + diskStatus: args.diskStatus, + key: args.key, + ), + ); + }, }; @override @@ -193,6 +248,11 @@ class _$RootRouter extends RootStackRouter { path: 'user-details-page', parent: RootRoute.name, ), + RouteConfig( + NewUserRoute.name, + path: 'new-user-page', + parent: RootRoute.name, + ), RouteConfig( RecoveryKeyRoute.name, path: 'recovery-key-page', @@ -213,6 +273,36 @@ class _$RootRouter extends RootStackRouter { path: 'developer-settings-page', parent: RootRoute.name, ), + RouteConfig( + ServiceRoute.name, + path: 'service-page', + parent: RootRoute.name, + ), + RouteConfig( + ServerDetailsRoute.name, + path: 'server-details-screen', + parent: RootRoute.name, + ), + RouteConfig( + DnsDetailsRoute.name, + path: 'dns-details-page', + parent: RootRoute.name, + ), + RouteConfig( + BackupDetailsRoute.name, + path: 'backup-details-page', + parent: RootRoute.name, + ), + RouteConfig( + ServerStorageRoute.name, + path: 'server-storage-page', + parent: RootRoute.name, + ), + RouteConfig( + ExtendingVolumeRoute.name, + path: 'extending-volume-page', + parent: RootRoute.name, + ), ], ), RouteConfig( @@ -425,6 +515,18 @@ class UserDetailsRouteArgs { } } +/// generated route for +/// [NewUserPage] +class NewUserRoute extends PageRouteInfo { + const NewUserRoute() + : super( + NewUserRoute.name, + path: 'new-user-page', + ); + + static const String name = 'NewUserRoute'; +} + /// generated route for /// [RecoveryKeyPage] class RecoveryKeyRoute extends PageRouteInfo { @@ -472,3 +574,146 @@ class DeveloperSettingsRoute extends PageRouteInfo { static const String name = 'DeveloperSettingsRoute'; } + +/// generated route for +/// [ServicePage] +class ServiceRoute extends PageRouteInfo { + ServiceRoute({ + required String serviceId, + Key? key, + }) : super( + ServiceRoute.name, + path: 'service-page', + args: ServiceRouteArgs( + serviceId: serviceId, + key: key, + ), + ); + + static const String name = 'ServiceRoute'; +} + +class ServiceRouteArgs { + const ServiceRouteArgs({ + required this.serviceId, + this.key, + }); + + final String serviceId; + + final Key? key; + + @override + String toString() { + return 'ServiceRouteArgs{serviceId: $serviceId, key: $key}'; + } +} + +/// generated route for +/// [ServerDetailsScreen] +class ServerDetailsRoute extends PageRouteInfo { + const ServerDetailsRoute() + : super( + ServerDetailsRoute.name, + path: 'server-details-screen', + ); + + static const String name = 'ServerDetailsRoute'; +} + +/// generated route for +/// [DnsDetailsPage] +class DnsDetailsRoute extends PageRouteInfo { + const DnsDetailsRoute() + : super( + DnsDetailsRoute.name, + path: 'dns-details-page', + ); + + static const String name = 'DnsDetailsRoute'; +} + +/// generated route for +/// [BackupDetailsPage] +class BackupDetailsRoute extends PageRouteInfo { + const BackupDetailsRoute() + : super( + BackupDetailsRoute.name, + path: 'backup-details-page', + ); + + static const String name = 'BackupDetailsRoute'; +} + +/// generated route for +/// [ServerStoragePage] +class ServerStorageRoute extends PageRouteInfo { + ServerStorageRoute({ + required DiskStatus diskStatus, + Key? key, + }) : super( + ServerStorageRoute.name, + path: 'server-storage-page', + args: ServerStorageRouteArgs( + diskStatus: diskStatus, + key: key, + ), + ); + + static const String name = 'ServerStorageRoute'; +} + +class ServerStorageRouteArgs { + const ServerStorageRouteArgs({ + required this.diskStatus, + this.key, + }); + + final DiskStatus diskStatus; + + final Key? key; + + @override + String toString() { + return 'ServerStorageRouteArgs{diskStatus: $diskStatus, key: $key}'; + } +} + +/// generated route for +/// [ExtendingVolumePage] +class ExtendingVolumeRoute extends PageRouteInfo { + ExtendingVolumeRoute({ + required DiskVolume diskVolumeToResize, + required DiskStatus diskStatus, + Key? key, + }) : super( + ExtendingVolumeRoute.name, + path: 'extending-volume-page', + args: ExtendingVolumeRouteArgs( + diskVolumeToResize: diskVolumeToResize, + diskStatus: diskStatus, + key: key, + ), + ); + + static const String name = 'ExtendingVolumeRoute'; +} + +class ExtendingVolumeRouteArgs { + const ExtendingVolumeRouteArgs({ + required this.diskVolumeToResize, + required this.diskStatus, + this.key, + }); + + final DiskVolume diskVolumeToResize; + + final DiskStatus diskStatus; + + final Key? key; + + @override + String toString() { + return 'ExtendingVolumeRouteArgs{diskVolumeToResize: $diskVolumeToResize, diskStatus: $diskStatus, key: $key}'; + } +}