refactor(ui): Refactor Devices screen UI

This commit is contained in:
Inex Code 2024-12-06 18:59:10 +03:00
parent 1168b2219f
commit c17d87c348
No known key found for this signature in database
15 changed files with 269 additions and 244 deletions

View file

@ -249,7 +249,7 @@
"autobackup_period_disable": "Disable automatic backups", "autobackup_period_disable": "Disable automatic backups",
"autobackup_set_period": "Set period", "autobackup_set_period": "Set period",
"backups_encryption_key": "Encryption key", "backups_encryption_key": "Encryption key",
"backups_encryption_key_subtitle": "Keep it in a safe place.", "backups_encryption_key_subtitle": "Keep it in a safe place",
"backups_encryption_key_copy": "Copy the encryption key", "backups_encryption_key_copy": "Copy the encryption key",
"backups_encryption_key_show": "Show the encryption key", "backups_encryption_key_show": "Show the encryption key",
"backups_encryption_key_description": "This key is used to encrypt your backups. If you lose it, you will not be able to restore your backups. Keep it in a safe place, as it will be useful if you ever need to restore from backups manually.", "backups_encryption_key_description": "This key is used to encrypt your backups. If you lose it, you will not be able to restore your backups. Keep it in a safe place, as it will be useful if you ever need to restore from backups manually.",
@ -598,7 +598,6 @@
"key_replace_button": "Generate new key", "key_replace_button": "Generate new key",
"key_receiving_description": "Write down this key and put to a safe place. It is used to restore full access to your server:", "key_receiving_description": "Write down this key and put to a safe place. It is used to restore full access to your server:",
"key_receiving_info": "The key will never ever be shown again, but you will be able to replace it with another one.", "key_receiving_info": "The key will never ever be shown again, but you will be able to replace it with another one.",
"key_receiving_done": "Done!",
"generation_error": "Couldn't generate a recovery key. {}" "generation_error": "Couldn't generate a recovery key. {}"
}, },
"modals": { "modals": {

View file

@ -1,15 +1,14 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SectionHeadline extends StatelessWidget { class SectionHeadline extends StatelessWidget {
const SectionHeadline({ const SectionHeadline({
required this.title, required this.title,
required this.subtitle, this.subtitle,
super.key, super.key,
}); });
final String title; final String title;
final String subtitle; final String? subtitle;
@override @override
Widget build(final BuildContext context) => ListTile( Widget build(final BuildContext context) => ListTile(
@ -19,9 +18,11 @@ class SectionHeadline extends StatelessWidget {
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
), ),
), ),
subtitle: Text( subtitle: subtitle != null
subtitle, ? Text(
style: Theme.of(context).textTheme.labelMedium, subtitle!,
), style: Theme.of(context).textTheme.labelMedium,
)
: null,
); );
} }

View file

@ -12,7 +12,10 @@ class SectionTitle extends StatelessWidget {
@override @override
Widget build(final BuildContext context) => Padding( Widget build(final BuildContext context) => Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
child: Text( child: Text(
title, title,
style: Theme.of(context).textTheme.labelLarge!.copyWith( style: Theme.of(context).textTheme.labelLarge!.copyWith(

View file

@ -19,7 +19,10 @@ class BrandHeroScreen extends StatelessWidget {
this.heroTitle = '', this.heroTitle = '',
this.heroSubtitle, this.heroSubtitle,
this.onBackButtonPressed, this.onBackButtonPressed,
this.bodyPadding = const EdgeInsets.all(16.0), this.bodyPadding = const EdgeInsets.symmetric(
vertical: 16.0,
horizontal: 8.0,
),
this.ignoreBreakpoints = false, this.ignoreBreakpoints = false,
this.hasSupportDrawer = false, this.hasSupportDrawer = false,
}); });
@ -80,7 +83,7 @@ class BrandHeroScreen extends StatelessWidget {
style: Theme.of(context).textTheme.bodyMedium!.copyWith( style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onSurface, color: Theme.of(context).colorScheme.onSurface,
), ),
textAlign: hasHeroIcon ? TextAlign.center : TextAlign.start, textAlign: TextAlign.center,
), ),
]), ]),
), ),

View file

@ -0,0 +1,131 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/bloc/devices/devices_bloc.dart';
import 'package:selfprivacy/logic/bloc/tokens/tokens_bloc.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/json/api_token.dart';
class DeviceItem extends StatelessWidget {
const DeviceItem({
required this.device,
super.key,
});
final ApiToken device;
@override
Widget build(final BuildContext context) => ListTile(
title: Text(device.name),
subtitle: Text(
'devices.main_screen.access_granted_on'
.tr(args: [DateFormat.yMMMMd().format(device.date)]),
),
onTap: device.isCaller
? () => _showTokenRefreshDialog(context, device)
: () => _showConfirmationDialog(context, device),
);
Future _showConfirmationDialog(
final BuildContext context,
final ApiToken device,
) =>
showDialog(
context: context,
builder: (final context) => AlertDialog(
title: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.link_off_outlined),
const SizedBox(height: 16),
Text(
'devices.revoke_device_alert.header'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'devices.revoke_device_alert.description'
.tr(args: [device.name]),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
actions: <Widget>[
TextButton(
child: Text('devices.revoke_device_alert.no'.tr()),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text(
'devices.revoke_device_alert.yes'.tr(),
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: Theme.of(context).colorScheme.error,
),
),
onPressed: () {
context.read<DevicesBloc>().add(DeleteDevice(device));
Navigator.of(context).pop();
},
),
],
),
);
Future _showTokenRefreshDialog(
final BuildContext context,
final ApiToken device,
) =>
showDialog(
context: context,
builder: (final context) => AlertDialog(
title: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.update_outlined),
const SizedBox(height: 16),
Text(
'devices.refresh_token_alert.header'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'devices.refresh_token_alert.description'
.tr(args: [device.name]),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
actions: <Widget>[
TextButton(
child: Text('devices.refresh_token_alert.no'.tr()),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('devices.refresh_token_alert.yes'.tr()),
onPressed: () {
context
.read<TokensBloc>()
.add(const RefreshServerApiTokenEvent());
Navigator.of(context).pop();
},
),
],
),
);
}

View file

@ -0,0 +1,60 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
import 'package:selfprivacy/ui/molecules/info_box/info_box.dart';
class KeyDisplay extends StatelessWidget {
const KeyDisplay({
required this.keyToDisplay,
required this.canCopy,
required this.infoboxText,
super.key,
});
final String keyToDisplay;
final bool canCopy;
final String infoboxText;
@override
Widget build(final BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(),
const SizedBox(height: 16),
if (canCopy)
SelectableText(
keyToDisplay,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 24,
fontFamily: 'RobotoMono',
),
textAlign: TextAlign.center,
),
if (!canCopy)
Text(
keyToDisplay,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 24,
fontFamily: 'RobotoMono',
),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 16),
InfoBox(
text: infoboxText,
),
const SizedBox(height: 16),
BrandButton.filled(
child: Text(
'basis.done'.tr(),
),
onPressed: () {
Navigator.of(context).popUntil((final route) => route.isFirst);
},
),
const SizedBox(height: 24),
],
);
}

View file

@ -257,13 +257,8 @@ class BackupDetailsPage extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ListTile( SectionHeadline(
title: Text( title: 'backup.pending_jobs'.tr(),
'backup.pending_jobs'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
), ),
for (final job in backupJobs) for (final job in backupJobs)
Padding( Padding(
@ -312,7 +307,6 @@ class BackupDetailsPage extends StatelessWidget {
ListTile( ListTile(
title: Text( title: Text(
'backup.show_more'.tr(), 'backup.show_more'.tr(),
style: Theme.of(context).textTheme.labelMedium,
), ),
leading: const Icon( leading: const Icon(
Icons.arrow_drop_down, Icons.arrow_drop_down,
@ -345,6 +339,7 @@ class BackupDetailsPage extends StatelessWidget {
Icons.cached_outlined, Icons.cached_outlined,
color: overrideColor, color: overrideColor,
), ),
isThreeLine: true,
onTap: preventActions onTap: preventActions
? null ? null
: () => context : () => context

View file

@ -3,23 +3,22 @@ import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/bloc/devices/devices_bloc.dart'; import 'package:selfprivacy/logic/bloc/devices/devices_bloc.dart';
import 'package:selfprivacy/logic/bloc/tokens/tokens_bloc.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/json/api_token.dart'; import 'package:selfprivacy/ui/atoms/list_tiles/section_title.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/molecules/info_box/info_box.dart'; import 'package:selfprivacy/ui/molecules/info_box/info_box.dart';
import 'package:selfprivacy/ui/pages/devices/new_device.dart'; import 'package:selfprivacy/ui/molecules/list_items/device_item.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart'; import 'package:selfprivacy/ui/router/router.dart';
@RoutePage() @RoutePage()
class DevicesScreen extends StatefulWidget { class DevicesPage extends StatefulWidget {
const DevicesScreen({super.key}); const DevicesPage({super.key});
@override @override
State<DevicesScreen> createState() => _DevicesScreenState(); State<DevicesPage> createState() => _DevicesPageState();
} }
class _DevicesScreenState extends State<DevicesScreen> { class _DevicesPageState extends State<DevicesPage> {
@override @override
Widget build(final BuildContext context) { Widget build(final BuildContext context) {
final DevicesState devicesStatus = context.watch<DevicesBloc>().state; final DevicesState devicesStatus = context.watch<DevicesBloc>().state;
@ -31,6 +30,7 @@ class _DevicesScreenState extends State<DevicesScreen> {
child: BrandHeroScreen( child: BrandHeroScreen(
heroTitle: 'devices.main_screen.header'.tr(), heroTitle: 'devices.main_screen.header'.tr(),
heroSubtitle: 'devices.main_screen.description'.tr(), heroSubtitle: 'devices.main_screen.description'.tr(),
heroIcon: Icons.devices_outlined,
hasBackButton: true, hasBackButton: true,
hasFlashButton: false, hasFlashButton: false,
children: [ children: [
@ -46,8 +46,7 @@ class _DevicesScreenState extends State<DevicesScreen> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
OutlinedButton( OutlinedButton(
onPressed: () => Navigator.of(context) onPressed: () => context.pushRoute(const NewDeviceRoute()),
.push(materialRoute(const NewDeviceScreen())),
child: Text('devices.main_screen.authorize_new_device'.tr()), child: Text('devices.main_screen.authorize_new_device'.tr()),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@ -75,22 +74,17 @@ class _DevicesInfo extends StatelessWidget {
Widget build(final BuildContext context) => Column( Widget build(final BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( SectionTitle(
'devices.main_screen.this_device'.tr(), title: 'devices.main_screen.this_device'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
), ),
_DeviceTile( DeviceItem(
device: devicesStatus.thisDevice, device: devicesStatus.thisDevice,
), ),
const SizedBox(height: 8),
const Divider(height: 1), const Divider(height: 1),
const SizedBox(height: 16), const SizedBox(height: 8),
Text( SectionTitle(
'devices.main_screen.other_devices'.tr(), title: 'devices.main_screen.other_devices'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
), ),
if (devicesStatus is DevicesDeleting) ...[ if (devicesStatus is DevicesDeleting) ...[
const Center( const Center(
@ -100,127 +94,10 @@ class _DevicesInfo extends StatelessWidget {
], ],
if (devicesStatus is! DevicesDeleting) if (devicesStatus is! DevicesDeleting)
...devicesStatus.otherDevices.map( ...devicesStatus.otherDevices.map(
(final device) => _DeviceTile( (final device) => DeviceItem(
device: device, device: device,
), ),
), ),
], ],
); );
} }
class _DeviceTile extends StatelessWidget {
const _DeviceTile({required this.device});
final ApiToken device;
@override
Widget build(final BuildContext context) => ListTile(
contentPadding: EdgeInsets.zero,
title: Text(device.name),
subtitle: Text(
'devices.main_screen.access_granted_on'
.tr(args: [DateFormat.yMMMMd().format(device.date)]),
),
onTap: device.isCaller
? () => _showTokenRefreshDialog(context, device)
: () => _showConfirmationDialog(context, device),
);
Future _showConfirmationDialog(
final BuildContext context,
final ApiToken device,
) =>
showDialog(
context: context,
builder: (final context) => AlertDialog(
title: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.link_off_outlined),
const SizedBox(height: 16),
Text(
'devices.revoke_device_alert.header'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'devices.revoke_device_alert.description'
.tr(args: [device.name]),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
actions: <Widget>[
TextButton(
child: Text('devices.revoke_device_alert.no'.tr()),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('devices.revoke_device_alert.yes'.tr()),
onPressed: () {
context.read<DevicesBloc>().add(DeleteDevice(device));
Navigator.of(context).pop();
},
),
],
),
);
Future _showTokenRefreshDialog(
final BuildContext context,
final ApiToken device,
) =>
showDialog(
context: context,
builder: (final context) => AlertDialog(
title: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.update_outlined),
const SizedBox(height: 16),
Text(
'devices.refresh_token_alert.header'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'devices.refresh_token_alert.description'
.tr(args: [device.name]),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
actions: <Widget>[
TextButton(
child: Text('devices.refresh_token_alert.no'.tr()),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('devices.refresh_token_alert.yes'.tr()),
onPressed: () {
context
.read<TokensBloc>()
.add(const RefreshServerApiTokenEvent());
Navigator.of(context).pop();
},
),
],
),
);
}

View file

@ -1,13 +1,15 @@
import 'package:auto_route/auto_route.dart';
import 'package:cubit_form/cubit_form.dart'; import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/bloc/devices/devices_bloc.dart'; import 'package:selfprivacy/logic/bloc/devices/devices_bloc.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/organisms/displays/key_display.dart';
class NewDeviceScreen extends StatelessWidget { @RoutePage()
const NewDeviceScreen({super.key}); class NewDevicePage extends StatelessWidget {
const NewDevicePage({super.key});
@override @override
Widget build(final BuildContext context) => BrandHeroScreen( Widget build(final BuildContext context) => BrandHeroScreen(
@ -23,8 +25,10 @@ class NewDeviceScreen extends StatelessWidget {
final AsyncSnapshot<Object?> snapshot, final AsyncSnapshot<Object?> snapshot,
) { ) {
if (snapshot.hasData) { if (snapshot.hasData) {
return _KeyDisplay( return KeyDisplay(
newDeviceKey: snapshot.data.toString(), keyToDisplay: snapshot.data.toString(),
canCopy: true,
infoboxText: 'devices.add_new_device_screen.tip'.tr(),
); );
} else { } else {
return const Center( return const Center(
@ -36,51 +40,3 @@ class NewDeviceScreen extends StatelessWidget {
], ],
); );
} }
class _KeyDisplay extends StatelessWidget {
const _KeyDisplay({required this.newDeviceKey});
final String newDeviceKey;
@override
Widget build(final BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(),
const SizedBox(height: 16),
SelectableText(
newDeviceKey,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 24,
fontFamily: 'RobotoMono',
),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.info_outline,
color: Theme.of(context).colorScheme.onSurface,
),
const SizedBox(height: 16),
Text(
'devices.add_new_device_screen.tip'.tr(),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
const SizedBox(height: 16),
BrandButton.filled(
child: Text(
'basis.done'.tr(),
),
onPressed: () => Navigator.of(context).pop(),
),
const SizedBox(height: 24),
],
);
}

View file

@ -43,7 +43,6 @@ class AboutApplicationPage extends StatelessWidget {
hasBackButton: true, hasBackButton: true,
hasFlashButton: false, hasFlashButton: false,
heroTitle: 'about_application_page.title'.tr(), heroTitle: 'about_application_page.title'.tr(),
bodyPadding: const EdgeInsets.symmetric(vertical: 16),
children: [ children: [
SectionTitle(title: 'about_application_page.versions'.tr()), SectionTitle(title: 'about_application_page.versions'.tr()),
FutureBuilder( FutureBuilder(

View file

@ -25,7 +25,6 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
Widget build(final BuildContext context) => BrandHeroScreen( Widget build(final BuildContext context) => BrandHeroScreen(
hasBackButton: true, hasBackButton: true,
hasFlashButton: false, hasFlashButton: false,
bodyPadding: const EdgeInsets.symmetric(vertical: 16),
heroTitle: 'developer_settings.title'.tr(), heroTitle: 'developer_settings.title'.tr(),
heroSubtitle: 'developer_settings.subtitle'.tr(), heroSubtitle: 'developer_settings.subtitle'.tr(),
children: [ children: [

View file

@ -250,7 +250,7 @@ class _RecoveryKeyConfigurationState extends State<RecoveryKeyConfiguration> {
}); });
await Navigator.of(context).push( await Navigator.of(context).push(
materialRoute( materialRoute(
RecoveryKeyReceiving(recoveryKey: token), NewRecoveryKeyPage(recoveryKey: token),
), ),
); );
} on GenerationError catch (e) { } on GenerationError catch (e) {

View file

@ -1,11 +1,10 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:selfprivacy/ui/atoms/buttons/brand_button.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/molecules/info_box/info_box.dart'; import 'package:selfprivacy/ui/organisms/displays/key_display.dart';
class RecoveryKeyReceiving extends StatelessWidget { class NewRecoveryKeyPage extends StatelessWidget {
const RecoveryKeyReceiving({required this.recoveryKey, super.key}); const NewRecoveryKeyPage({required this.recoveryKey, super.key});
final String recoveryKey; final String recoveryKey;
@ -16,28 +15,10 @@ class RecoveryKeyReceiving extends StatelessWidget {
hasBackButton: false, hasBackButton: false,
hasFlashButton: false, hasFlashButton: false,
children: [ children: [
const Divider(), KeyDisplay(
const SizedBox(height: 16), keyToDisplay: recoveryKey,
Text( canCopy: false,
recoveryKey, infoboxText: 'recovery_key.key_receiving_info'.tr(),
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 24,
fontFamily: 'RobotoMono',
),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 16),
InfoBox(
text: 'recovery_key.key_receiving_info'.tr(),
),
const SizedBox(height: 16),
BrandButton.filled(
child: Text('recovery_key.key_receiving_done'.tr()),
onPressed: () {
Navigator.of(context).popUntil((final route) => route.isFirst);
},
), ),
], ],
); );

View file

@ -7,6 +7,7 @@ import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/pages/backups/backup_details.dart'; import 'package:selfprivacy/ui/pages/backups/backup_details.dart';
import 'package:selfprivacy/ui/pages/backups/backups_list.dart'; import 'package:selfprivacy/ui/pages/backups/backups_list.dart';
import 'package:selfprivacy/ui/pages/devices/devices.dart'; import 'package:selfprivacy/ui/pages/devices/devices.dart';
import 'package:selfprivacy/ui/pages/devices/new_device.dart';
import 'package:selfprivacy/ui/pages/dns_details/dns_details.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/about_application.dart';
import 'package:selfprivacy/ui/pages/more/app_settings/app_settings.dart'; import 'package:selfprivacy/ui/pages/more/app_settings/app_settings.dart';
@ -101,6 +102,7 @@ class RootRouter extends RootStackRouter {
AutoRoute(page: NewUserRoute.page), AutoRoute(page: NewUserRoute.page),
AutoRoute(page: RecoveryKeyRoute.page), AutoRoute(page: RecoveryKeyRoute.page),
AutoRoute(page: DevicesRoute.page), AutoRoute(page: DevicesRoute.page),
AutoRoute(page: NewDeviceRoute.page),
AutoRoute(page: AboutApplicationRoute.page), AutoRoute(page: AboutApplicationRoute.page),
AutoRoute(page: DeveloperSettingsRoute.page), AutoRoute(page: DeveloperSettingsRoute.page),
AutoRoute(page: ServiceRoute.page), AutoRoute(page: ServiceRoute.page),

View file

@ -198,7 +198,7 @@ class DeveloperSettingsRoute extends PageRouteInfo<void> {
} }
/// generated route for /// generated route for
/// [DevicesScreen] /// [DevicesPage]
class DevicesRoute extends PageRouteInfo<void> { class DevicesRoute extends PageRouteInfo<void> {
const DevicesRoute({List<PageRouteInfo>? children}) const DevicesRoute({List<PageRouteInfo>? children})
: super( : super(
@ -211,7 +211,7 @@ class DevicesRoute extends PageRouteInfo<void> {
static PageInfo page = PageInfo( static PageInfo page = PageInfo(
name, name,
builder: (data) { builder: (data) {
return const DevicesScreen(); return const DevicesPage();
}, },
); );
} }
@ -344,6 +344,25 @@ class MoreRoute extends PageRouteInfo<void> {
); );
} }
/// generated route for
/// [NewDevicePage]
class NewDeviceRoute extends PageRouteInfo<void> {
const NewDeviceRoute({List<PageRouteInfo>? children})
: super(
NewDeviceRoute.name,
initialChildren: children,
);
static const String name = 'NewDeviceRoute';
static PageInfo page = PageInfo(
name,
builder: (data) {
return const NewDevicePage();
},
);
}
/// generated route for /// generated route for
/// [NewUserPage] /// [NewUserPage]
class NewUserRoute extends PageRouteInfo<void> { class NewUserRoute extends PageRouteInfo<void> {