feat(backups): Backups screens

pull/228/head
Inex Code 2023-07-02 18:24:07 +03:00
parent df214a07bc
commit a4dbba0968
9 changed files with 901 additions and 522 deletions

View File

@ -162,6 +162,7 @@
},
"backup": {
"card_title": "Backup",
"card_subtitle": "Manage your backups",
"description": "Will save your day in case of incident: hackers attack, server deletion, etc.",
"reupload_key": "Force reupload key",
"reuploaded_key": "Key reuploaded",
@ -176,7 +177,27 @@
"restore_alert": "You are about to restore from backup created on {}. All current data will be lost. Are you sure?",
"refresh": "Refresh status",
"refetch_backups": "Refetch backup list",
"refetching_list": "In a few minutes list will be updated"
"refetch_backups_subtitle": "Invalidate cache and refetch data from your storage provider. May cause additional charges.",
"reupload_key_subtitle": "Will instruct the server to initialize backup storage again. Use if something is broken.",
"refetching_list": "In a few minutes list will be updated",
"select_all": "Backup everything",
"create_new_select_heading": "Select what to backup",
"start": "Start backup",
"service_busy": "Another backup operation is in progress",
"latest_snapshots": "Latest snapshots",
"latest_snapshots_subtitle": "Showing last 15 snapshots",
"show_more": "Show more",
"autobackup_period_title": "Automatic backups period",
"autobackup_period_subtitle": "Backups created every {period}",
"autobackup_period_never": "Automatic backups are disabled",
"autobackup_period_every": "Every {period}",
"autobackup_period_disable": "Disable automatic backups",
"autobackup_custom": "Custom",
"autobackup_custom_hint": "Enter custom period in minutes",
"autobackup_set_period": "Set period",
"autobackup_period_set": "Period set",
"pending_jobs": "Currently running backup jobs",
"snapshots_title": "Snapshot list"
},
"storage": {
"card_title": "Server Storage",
@ -210,6 +231,7 @@
"enable": "Enable service",
"move": "Move to another volume",
"uses": "Uses {usage} on {volume}",
"snapshots": "Backup snapshots",
"status": {
"active": "Up and running",
"inactive": "Stopped",
@ -514,4 +536,4 @@
"reset_onboarding_description": "Reset onboarding switch to show onboarding screen again",
"cubit_statuses": "Cubit loading statuses"
}
}
}

View File

@ -11,10 +11,14 @@ import 'package:selfprivacy/logic/models/json/server_job.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/logic/models/state_types.dart';
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
import 'package:selfprivacy/ui/components/cards/outlined_card.dart';
import 'package:selfprivacy/ui/components/jobs_content/server_job_card.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:selfprivacy/ui/helpers/modals.dart';
import 'package:selfprivacy/ui/pages/backups/change_period_modal.dart';
import 'package:selfprivacy/ui/pages/backups/create_backups_modal.dart';
import 'package:selfprivacy/ui/router/router.dart';
import 'package:selfprivacy/utils/extensions/duration.dart';
GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@ -43,13 +47,30 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
final bool refreshing = context.watch<BackupsCubit>().state.refreshing;
final List<Service> services =
context.watch<ServicesCubit>().state.servicesThatCanBeBackedUp;
final Duration? autobackupPeriod =
context.watch<BackupsCubit>().state.autobackupPeriod;
final List<ServerJob> backupJobs = context
.watch<ServerJobsCubit>()
.state
.backupJobList
.where((final job) => job.status != JobStatusEnum.finished)
.toList();
return BrandHeroScreen(
heroIcon: BrandIcons.save,
heroTitle: 'backup.card_title'.tr(),
heroSubtitle: 'backup.description'.tr(),
children: [
if (isReady && !isBackupInitialized)
if (!isReady) {
return BrandHeroScreen(
heroIcon: BrandIcons.save,
heroTitle: 'backup.card_title'.tr(),
heroSubtitle: 'not_ready_card.in_menu'.tr(),
children: const [],
);
}
if (!isBackupInitialized) {
return BrandHeroScreen(
heroIcon: BrandIcons.save,
heroTitle: 'backup.card_title'.tr(),
heroSubtitle: 'backup.description'.tr(),
children: [
BrandButton.rised(
onPressed: preventActions
? null
@ -58,11 +79,19 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
},
text: 'backup.initialize'.tr(),
),
],
);
}
return BrandHeroScreen(
heroIcon: BrandIcons.save,
heroTitle: 'backup.card_title'.tr(),
heroSubtitle: 'backup.description'.tr(),
children: [
ListTile(
onTap: preventActions
? null
: () {
// await context.read<BackupsCubit>().createBackup();
showModalBottomSheet(
useRootNavigator: true,
context: context,
@ -88,7 +117,66 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
'backup.create_new'.tr(),
),
),
ListTile(
onTap: preventActions
? null
: () {
// await context.read<BackupsCubit>().createBackup();
showModalBottomSheet(
useRootNavigator: true,
context: context,
isScrollControlled: true,
builder: (final BuildContext context) =>
DraggableScrollableSheet(
expand: false,
maxChildSize: 0.9,
minChildSize: 0.4,
initialChildSize: 0.6,
builder: (final context, final scrollController) =>
ChangeAutobackupsPeriodModal(
scrollController: scrollController,
),
),
);
},
leading: const Icon(
Icons.manage_history_outlined,
),
title: Text(
'backup.autobackup_period_title'.tr(),
),
subtitle: Text(
autobackupPeriod != null
? 'backup.autobackup_period_subtitle'.tr(
namedArgs: {
'period': autobackupPeriod.toPrettyString(context.locale)
},
)
: 'backup.autobackup_period_never'.tr(),
),
),
const SizedBox(height: 16),
if (backupJobs.isNotEmpty)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: Text(
'backup.pending_jobs'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
for (final job in backupJobs)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ServerJobCard(
serverJob: job,
),
),
],
),
// Card with a list of existing backups
// Each list item has a date
// When clicked, starts the restore action
@ -98,13 +186,13 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
children: [
ListTile(
title: Text(
'backups.latest_snapshots'.tr(),
'backup.latest_snapshots'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
subtitle: Text(
'backups.latest_snapshots_subtitle'.tr(),
'backup.latest_snapshots_subtitle'.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
),
@ -117,7 +205,7 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
),
if (backups.isNotEmpty)
Column(
children: backups.take(20).map(
children: backups.take(15).map(
(final Backup backup) {
final service = context
.read<ServicesCubit>()
@ -163,221 +251,71 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
},
).toList(),
),
if (backups.isNotEmpty && backups.length > 20)
if (backups.isNotEmpty && backups.length > 15)
ListTile(
title: Text(
'backups.show_more'.tr(),
'backup.show_more'.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
leading: const Icon(
Icons.arrow_drop_down,
),
onTap: null,
onTap: () =>
context.pushRoute(BackupsListRoute(service: null)),
)
],
),
const SizedBox(height: 16),
OutlinedCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
const SizedBox(height: 8),
const Divider(),
const SizedBox(height: 8),
ListTile(
title: Text(
'backup.refresh'.tr(),
),
onTap: refreshing
? null
: () => {context.read<BackupsCubit>().updateBackups()},
enabled: !refreshing,
leading: const Icon(
Icons.refresh_outlined,
),
),
if (providerState != StateType.uninitialized)
Column(
children: [
ListTile(
title: Text(
'backup.refresh'.tr(),
'backup.refetch_backups'.tr(),
),
onTap: refreshing
subtitle: Text(
'backup.refetch_backups_subtitle'.tr(),
),
leading: const Icon(
Icons.cached_outlined,
),
onTap: preventActions
? null
: () => {context.read<BackupsCubit>().updateBackups()},
enabled: !refreshing,
: () => {context.read<BackupsCubit>().forceUpdateBackups()},
),
if (providerState != StateType.uninitialized)
Column(
children: [
const Divider(
height: 1.0,
),
ListTile(
title: Text(
'backup.refetch_backups'.tr(),
),
onTap: preventActions
? null
: () => {
context
.read<BackupsCubit>()
.forceUpdateBackups()
},
),
const Divider(
height: 1.0,
),
ListTile(
title: Text(
'backup.reupload_key'.tr(),
),
onTap: preventActions
? null
: () => {context.read<BackupsCubit>().reuploadKey()},
),
],
const SizedBox(height: 8),
const Divider(),
const SizedBox(height: 8),
ListTile(
title: Text(
'backup.reupload_key'.tr(),
),
subtitle: Text(
'backup.reupload_key_subtitle'.tr(),
),
leading: const Icon(
Icons.warning_amber_outlined,
),
onTap: preventActions
? null
: () => {context.read<BackupsCubit>().reuploadKey()},
),
],
),
),
],
);
}
}
class CreateBackupsModal extends StatefulWidget {
const CreateBackupsModal({
required this.services,
required this.scrollController,
super.key,
});
final List<Service> services;
final ScrollController scrollController;
@override
State<CreateBackupsModal> createState() => _CreateBackupsModalState();
}
class _CreateBackupsModalState extends State<CreateBackupsModal> {
// Store in state the selected services to backup
List<Service> selectedServices = [];
// Select all services on modal open
@override
void initState() {
super.initState();
final List<String> busyServices = context
.read<ServerJobsCubit>()
.state
.backupJobList
.where(
(final ServerJob job) =>
job.status == JobStatusEnum.running ||
job.status == JobStatusEnum.created,
)
.map((final ServerJob job) => job.typeId.split('.')[1])
.toList();
selectedServices.addAll(
widget.services
.where((final Service service) => !busyServices.contains(service.id)),
);
}
@override
Widget build(final BuildContext context) {
final List<String> busyServices = context
.watch<ServerJobsCubit>()
.state
.backupJobList
.where(
(final ServerJob job) =>
job.status == JobStatusEnum.running ||
job.status == JobStatusEnum.created,
)
.map((final ServerJob job) => job.typeId.split('.')[1])
.toList();
return ListView(
controller: widget.scrollController,
padding: const EdgeInsets.all(16),
children: [
const SizedBox(height: 16),
Text(
'backup.create_new_select_heading'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
// Select all services tile
CheckboxListTile(
onChanged: (final bool? value) {
setState(() {
if (value ?? true) {
setState(() {
selectedServices.clear();
selectedServices.addAll(
widget.services.where(
(final service) => !busyServices.contains(service.id),
),
);
});
} else {
selectedServices.clear();
}
});
},
title: Text(
'backup.select_all'.tr(),
),
secondary: const Icon(
Icons.checklist_outlined,
),
value: selectedServices.length >=
widget.services.length - busyServices.length,
),
const Divider(
height: 1.0,
),
...widget.services.map(
(final Service service) {
final bool busy = busyServices.contains(service.id);
return CheckboxListTile(
onChanged: !busy
? (final bool? value) {
setState(() {
if (value ?? true) {
setState(() {
selectedServices.add(service);
});
} else {
setState(() {
selectedServices.remove(service);
});
}
});
}
: null,
title: Text(
service.displayName,
),
subtitle: Text(
busy ? 'backup.service_busy'.tr() : service.backupDescription,
),
secondary: SvgPicture.string(
service.svgIcon,
height: 24,
width: 24,
colorFilter: ColorFilter.mode(
busy
? Theme.of(context).colorScheme.outlineVariant
: Theme.of(context).colorScheme.onBackground,
BlendMode.srcIn,
),
),
value: selectedServices.contains(service),
);
},
),
const SizedBox(height: 16),
// Create backup button
FilledButton(
onPressed: selectedServices.isEmpty
? null
: () {
context
.read<BackupsCubit>()
.createMultipleBackups(selectedServices);
Navigator.of(context).pop();
},
child: Text(
'backup.start'.tr(),
),
),
],
);
}

View File

@ -0,0 +1,85 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/backup.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/helpers/modals.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
@RoutePage()
class BackupsListPage extends StatelessWidget {
const BackupsListPage({
required this.service,
super.key,
});
final Service? service;
@override
Widget build(final BuildContext context) {
// If the service is null, get all backups from state. If not null, call the
// serviceBackups(serviceId) on the backups state.
final List<Backup> backups = service == null
? context.watch<BackupsCubit>().state.backups
: context.watch<BackupsCubit>().state.serviceBackups(service!.id);
final bool preventActions =
context.watch<BackupsCubit>().state.preventActions;
return BrandHeroScreen(
heroTitle: 'backup.snapshots_title'.tr(),
children: [
if (backups.isEmpty)
Center(
child: Text(
'backup.no_backups'.tr(),
),
)
else
...backups.map((final Backup backup) {
final service = context
.read<ServicesCubit>()
.state
.getServiceById(backup.serviceId);
return ListTile(
onTap: preventActions
? null
: () {
showPopUpAlert(
alertTitle: 'backup.restoring'.tr(),
description: 'backup.restore_alert'.tr(
args: [backup.time.toString()],
),
actionButtonTitle: 'modals.yes'.tr(),
actionButtonOnPressed: () => {
context.read<BackupsCubit>().restoreBackup(backup.id)
},
);
},
title: Text(
'${MaterialLocalizations.of(context).formatShortDate(backup.time)} ${TimeOfDay.fromDateTime(backup.time).format(context)}',
),
subtitle: Text(
service?.displayName ?? backup.fallbackServiceName,
),
leading: service != null
? SvgPicture.string(
service.svgIcon,
height: 24,
width: 24,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onBackground,
BlendMode.srcIn,
),
)
: const Icon(
Icons.question_mark_outlined,
),
);
})
],
);
}
}

View File

@ -0,0 +1,108 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
import 'package:selfprivacy/utils/extensions/duration.dart';
class ChangeAutobackupsPeriodModal extends StatefulWidget {
const ChangeAutobackupsPeriodModal({
required this.scrollController,
super.key,
});
final ScrollController scrollController;
@override
State<ChangeAutobackupsPeriodModal> createState() =>
_ChangeAutobackupsPeriodModalState();
}
class _ChangeAutobackupsPeriodModalState
extends State<ChangeAutobackupsPeriodModal> {
// This is a modal with radio buttons to select the autobackup period
// Period might be none, selected from predefined list or custom
// Store in state the selected period
Duration? selectedPeriod;
static const List<Duration> autobackupPeriods = [
Duration(hours: 12),
Duration(days: 1),
Duration(days: 2),
Duration(days: 3),
Duration(days: 7),
];
// Set initial period to the one currently set
@override
void initState() {
super.initState();
selectedPeriod = context.read<BackupsCubit>().state.autobackupPeriod;
}
@override
Widget build(final BuildContext context) {
final Duration? initialAutobackupPeriod =
context.watch<BackupsCubit>().state.autobackupPeriod;
return ListView(
controller: widget.scrollController,
padding: const EdgeInsets.all(16),
children: [
const SizedBox(height: 16),
Text(
'backup.autobackup_period_title'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
// Select all services tile
RadioListTile<Duration?>(
onChanged: (final Duration? value) {
setState(() {
selectedPeriod = value;
});
},
title: Text(
'backup.autobackup_period_disable'.tr(),
),
value: null,
groupValue: selectedPeriod,
),
const Divider(
height: 1.0,
),
...autobackupPeriods.map(
(final Duration period) => RadioListTile<Duration?>(
onChanged: (final Duration? value) {
setState(() {
selectedPeriod = value;
});
},
title: Text(
'backup.autobackup_period_every'.tr(
namedArgs: {'period': period.toPrettyString(context.locale)},
),
),
value: period,
groupValue: selectedPeriod,
),
),
const SizedBox(height: 16),
// Create backup button
FilledButton(
onPressed: selectedPeriod == initialAutobackupPeriod
? null
: () {
context
.read<BackupsCubit>()
.setAutobackupPeriod(selectedPeriod);
Navigator.of(context).pop();
},
child: Text(
'backup.autobackup_set_period'.tr(),
),
),
],
);
}
}

View File

@ -0,0 +1,161 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart';
import 'package:selfprivacy/logic/models/service.dart';
class CreateBackupsModal extends StatefulWidget {
const CreateBackupsModal({
required this.services,
required this.scrollController,
super.key,
});
final List<Service> services;
final ScrollController scrollController;
@override
State<CreateBackupsModal> createState() => _CreateBackupsModalState();
}
class _CreateBackupsModalState extends State<CreateBackupsModal> {
// Store in state the selected services to backup
List<Service> selectedServices = [];
// Select all services on modal open
@override
void initState() {
super.initState();
final List<String> busyServices = context
.read<ServerJobsCubit>()
.state
.backupJobList
.where(
(final ServerJob job) =>
job.status == JobStatusEnum.running ||
job.status == JobStatusEnum.created,
)
.map((final ServerJob job) => job.typeId.split('.')[1])
.toList();
selectedServices.addAll(
widget.services
.where((final Service service) => !busyServices.contains(service.id)),
);
}
@override
Widget build(final BuildContext context) {
final List<String> busyServices = context
.watch<ServerJobsCubit>()
.state
.backupJobList
.where(
(final ServerJob job) =>
job.status == JobStatusEnum.running ||
job.status == JobStatusEnum.created,
)
.map((final ServerJob job) => job.typeId.split('.')[1])
.toList();
return ListView(
controller: widget.scrollController,
padding: const EdgeInsets.all(16),
children: [
const SizedBox(height: 16),
Text(
'backup.create_new_select_heading'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
// Select all services tile
CheckboxListTile(
onChanged: (final bool? value) {
setState(() {
if (value ?? true) {
setState(() {
selectedServices.clear();
selectedServices.addAll(
widget.services.where(
(final service) => !busyServices.contains(service.id),
),
);
});
} else {
selectedServices.clear();
}
});
},
title: Text(
'backup.select_all'.tr(),
),
secondary: const Icon(
Icons.checklist_outlined,
),
value: selectedServices.length >=
widget.services.length - busyServices.length,
),
const Divider(
height: 1.0,
),
...widget.services.map(
(final Service service) {
final bool busy = busyServices.contains(service.id);
return CheckboxListTile(
onChanged: !busy
? (final bool? value) {
setState(() {
if (value ?? true) {
setState(() {
selectedServices.add(service);
});
} else {
setState(() {
selectedServices.remove(service);
});
}
});
}
: null,
title: Text(
service.displayName,
),
subtitle: Text(
busy ? 'backup.service_busy'.tr() : service.backupDescription,
),
secondary: SvgPicture.string(
service.svgIcon,
height: 24,
width: 24,
colorFilter: ColorFilter.mode(
busy
? Theme.of(context).colorScheme.outlineVariant
: Theme.of(context).colorScheme.onBackground,
BlendMode.srcIn,
),
),
value: selectedServices.contains(service),
);
},
),
const SizedBox(height: 16),
// Create backup button
FilledButton(
onPressed: selectedServices.isEmpty
? null
: () {
context
.read<BackupsCubit>()
.createMultipleBackups(selectedServices);
Navigator.of(context).pop();
},
child: Text(
'backup.start'.tr(),
),
),
],
);
}
}

View File

@ -107,7 +107,7 @@ class _SelectTimezoneState extends State<SelectTimezone> {
Duration(
milliseconds: location.currentTimeZone.offset,
)
.toDayHourMinuteFormat()
.toTimezoneOffsetFormat()
.contains(timezoneFilterValue!),
)
.toList()
@ -137,7 +137,7 @@ class _SelectTimezoneState extends State<SelectTimezone> {
location.name,
),
subtitle: Text(
'GMT ${duration.toDayHourMinuteFormat()} ${area.isNotEmpty ? '($area)' : ''}',
'GMT ${duration.toTimezoneOffsetFormat()} ${area.isNotEmpty ? '($area)' : ''}',
),
onTap: () {
context.read<ServerDetailsCubit>().repository.setTimezone(

View File

@ -141,6 +141,19 @@ class _ServicePageState extends State<ServicePage> {
),
enabled: !serviceDisabled && !serviceLocked,
),
if (service.canBeBackedUp)
ListTile(
iconColor: Theme.of(context).colorScheme.onBackground,
// Open page ServicesMigrationPage
onTap: () => context.pushRoute(
BackupsListRoute(service: service),
),
leading: const Icon(Icons.settings_backup_restore_outlined),
title: Text(
'service_page.snapshots'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
),
],
);
}

View File

@ -3,7 +3,8 @@ 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/backups/backup_details.dart';
import 'package:selfprivacy/ui/pages/backups/backups_list.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';
@ -96,6 +97,7 @@ class RootRouter extends _$RootRouter {
AutoRoute(page: ServerDetailsRoute.page),
AutoRoute(page: DnsDetailsRoute.page),
AutoRoute(page: BackupDetailsRoute.page),
AutoRoute(page: BackupsListRoute.page),
AutoRoute(page: ServerStorageRoute.page),
AutoRoute(page: ExtendingVolumeRoute.page),
],
@ -141,6 +143,8 @@ String getRouteTitle(final String routeName) {
return 'server.card_title';
case 'BackupDetailsRoute':
return 'backup.card_title';
case 'BackupsListRoute':
return 'backup.snapshots_title';
case 'ServerStorageRoute':
return 'storage.card_title';
case 'ExtendingVolumeRoute':

View File

@ -15,16 +15,103 @@ abstract class _$RootRouter extends RootStackRouter {
@override
final Map<String, PageFactory> pagesMap = {
BackupDetailsRoute.name: (routeData) {
DevicesRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const BackupDetailsPage(),
child: const DevicesScreen(),
);
},
RootRoute.name: (routeData) {
DnsDetailsRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: WrappedRoute(child: const RootPage()),
child: const DnsDetailsPage(),
);
},
AppSettingsRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const AppSettingsPage(),
);
},
DeveloperSettingsRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const DeveloperSettingsPage(),
);
},
AboutApplicationRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const AboutApplicationPage(),
);
},
MoreRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const MorePage(),
);
},
ConsoleRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const ConsolePage(),
);
},
OnboardingRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const OnboardingPage(),
);
},
ProvidersRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const ProvidersPage(),
);
},
RecoveryKeyRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const RecoveryKeyPage(),
);
},
ServerDetailsRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const ServerDetailsScreen(),
);
},
ServicesMigrationRoute.name: (routeData) {
final args = routeData.argsAs<ServicesMigrationRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: ServicesMigrationPage(
services: args.services,
diskStatus: args.diskStatus,
isMigration: args.isMigration,
key: args.key,
),
);
},
ServerStorageRoute.name: (routeData) {
final args = routeData.argsAs<ServerStorageRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: ServerStoragePage(
diskStatus: args.diskStatus,
key: args.key,
),
);
},
ExtendingVolumeRoute.name: (routeData) {
final args = routeData.argsAs<ExtendingVolumeRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: ExtendingVolumePage(
diskVolumeToResize: args.diskVolumeToResize,
diskStatus: args.diskStatus,
key: args.key,
),
);
},
ServiceRoute.name: (routeData) {
@ -43,10 +130,16 @@ abstract class _$RootRouter extends RootStackRouter {
child: const ServicesPage(),
);
},
ServerDetailsRoute.name: (routeData) {
InitializingRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const ServerDetailsScreen(),
child: const InitializingPage(),
);
},
RecoveryRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const RecoveryRouting(),
);
},
UsersRoute.name: (routeData) {
@ -71,274 +164,59 @@ abstract class _$RootRouter extends RootStackRouter {
),
);
},
AppSettingsRoute.name: (routeData) {
RootRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const AppSettingsPage(),
child: WrappedRoute(child: const RootPage()),
);
},
DeveloperSettingsRoute.name: (routeData) {
BackupDetailsRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const DeveloperSettingsPage(),
child: const BackupDetailsPage(),
);
},
MoreRoute.name: (routeData) {
BackupsListRoute.name: (routeData) {
final args = routeData.argsAs<BackupsListRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const MorePage(),
);
},
AboutApplicationRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const AboutApplicationPage(),
);
},
ConsoleRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const ConsolePage(),
);
},
ProvidersRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const ProvidersPage(),
);
},
RecoveryKeyRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const RecoveryKeyPage(),
);
},
DnsDetailsRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const DnsDetailsPage(),
);
},
RecoveryRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const RecoveryRouting(),
);
},
InitializingRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const InitializingPage(),
);
},
ServerStorageRoute.name: (routeData) {
final args = routeData.argsAs<ServerStorageRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: ServerStoragePage(
diskStatus: args.diskStatus,
child: BackupsListPage(
service: args.service,
key: args.key,
),
);
},
ExtendingVolumeRoute.name: (routeData) {
final args = routeData.argsAs<ExtendingVolumeRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: ExtendingVolumePage(
diskVolumeToResize: args.diskVolumeToResize,
diskStatus: args.diskStatus,
key: args.key,
),
);
},
ServicesMigrationRoute.name: (routeData) {
final args = routeData.argsAs<ServicesMigrationRouteArgs>();
return AutoRoutePage<dynamic>(
routeData: routeData,
child: ServicesMigrationPage(
services: args.services,
diskStatus: args.diskStatus,
isMigration: args.isMigration,
key: args.key,
),
);
},
DevicesRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const DevicesScreen(),
);
},
OnboardingRoute.name: (routeData) {
return AutoRoutePage<dynamic>(
routeData: routeData,
child: const OnboardingPage(),
);
},
};
}
/// generated route for
/// [BackupDetailsPage]
class BackupDetailsRoute extends PageRouteInfo<void> {
const BackupDetailsRoute({List<PageRouteInfo>? children})
/// [DevicesScreen]
class DevicesRoute extends PageRouteInfo<void> {
const DevicesRoute({List<PageRouteInfo>? children})
: super(
BackupDetailsRoute.name,
DevicesRoute.name,
initialChildren: children,
);
static const String name = 'BackupDetailsRoute';
static const String name = 'DevicesRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [RootPage]
class RootRoute extends PageRouteInfo<void> {
const RootRoute({List<PageRouteInfo>? children})
/// [DnsDetailsPage]
class DnsDetailsRoute extends PageRouteInfo<void> {
const DnsDetailsRoute({List<PageRouteInfo>? children})
: super(
RootRoute.name,
DnsDetailsRoute.name,
initialChildren: children,
);
static const String name = 'RootRoute';
static const String name = 'DnsDetailsRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [ServicePage]
class ServiceRoute extends PageRouteInfo<ServiceRouteArgs> {
ServiceRoute({
required String serviceId,
Key? key,
List<PageRouteInfo>? children,
}) : super(
ServiceRoute.name,
args: ServiceRouteArgs(
serviceId: serviceId,
key: key,
),
initialChildren: children,
);
static const String name = 'ServiceRoute';
static const PageInfo<ServiceRouteArgs> page =
PageInfo<ServiceRouteArgs>(name);
}
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
/// [ServicesPage]
class ServicesRoute extends PageRouteInfo<void> {
const ServicesRoute({List<PageRouteInfo>? children})
: super(
ServicesRoute.name,
initialChildren: children,
);
static const String name = 'ServicesRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [ServerDetailsScreen]
class ServerDetailsRoute extends PageRouteInfo<void> {
const ServerDetailsRoute({List<PageRouteInfo>? children})
: super(
ServerDetailsRoute.name,
initialChildren: children,
);
static const String name = 'ServerDetailsRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [UsersPage]
class UsersRoute extends PageRouteInfo<void> {
const UsersRoute({List<PageRouteInfo>? children})
: super(
UsersRoute.name,
initialChildren: children,
);
static const String name = 'UsersRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [NewUserPage]
class NewUserRoute extends PageRouteInfo<void> {
const NewUserRoute({List<PageRouteInfo>? children})
: super(
NewUserRoute.name,
initialChildren: children,
);
static const String name = 'NewUserRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [UserDetailsPage]
class UserDetailsRoute extends PageRouteInfo<UserDetailsRouteArgs> {
UserDetailsRoute({
required String login,
Key? key,
List<PageRouteInfo>? children,
}) : super(
UserDetailsRoute.name,
args: UserDetailsRouteArgs(
login: login,
key: key,
),
initialChildren: children,
);
static const String name = 'UserDetailsRoute';
static const PageInfo<UserDetailsRouteArgs> page =
PageInfo<UserDetailsRouteArgs>(name);
}
class UserDetailsRouteArgs {
const UserDetailsRouteArgs({
required this.login,
this.key,
});
final String login;
final Key? key;
@override
String toString() {
return 'UserDetailsRouteArgs{login: $login, key: $key}';
}
}
/// generated route for
/// [AppSettingsPage]
class AppSettingsRoute extends PageRouteInfo<void> {
@ -367,20 +245,6 @@ class DeveloperSettingsRoute extends PageRouteInfo<void> {
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [MorePage]
class MoreRoute extends PageRouteInfo<void> {
const MoreRoute({List<PageRouteInfo>? children})
: super(
MoreRoute.name,
initialChildren: children,
);
static const String name = 'MoreRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [AboutApplicationPage]
class AboutApplicationRoute extends PageRouteInfo<void> {
@ -395,6 +259,20 @@ class AboutApplicationRoute extends PageRouteInfo<void> {
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [MorePage]
class MoreRoute extends PageRouteInfo<void> {
const MoreRoute({List<PageRouteInfo>? children})
: super(
MoreRoute.name,
initialChildren: children,
);
static const String name = 'MoreRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [ConsolePage]
class ConsoleRoute extends PageRouteInfo<void> {
@ -409,6 +287,20 @@ class ConsoleRoute extends PageRouteInfo<void> {
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [OnboardingPage]
class OnboardingRoute extends PageRouteInfo<void> {
const OnboardingRoute({List<PageRouteInfo>? children})
: super(
OnboardingRoute.name,
initialChildren: children,
);
static const String name = 'OnboardingRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [ProvidersPage]
class ProvidersRoute extends PageRouteInfo<void> {
@ -438,45 +330,65 @@ class RecoveryKeyRoute extends PageRouteInfo<void> {
}
/// generated route for
/// [DnsDetailsPage]
class DnsDetailsRoute extends PageRouteInfo<void> {
const DnsDetailsRoute({List<PageRouteInfo>? children})
/// [ServerDetailsScreen]
class ServerDetailsRoute extends PageRouteInfo<void> {
const ServerDetailsRoute({List<PageRouteInfo>? children})
: super(
DnsDetailsRoute.name,
ServerDetailsRoute.name,
initialChildren: children,
);
static const String name = 'DnsDetailsRoute';
static const String name = 'ServerDetailsRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [RecoveryRouting]
class RecoveryRoute extends PageRouteInfo<void> {
const RecoveryRoute({List<PageRouteInfo>? children})
: super(
RecoveryRoute.name,
/// [ServicesMigrationPage]
class ServicesMigrationRoute extends PageRouteInfo<ServicesMigrationRouteArgs> {
ServicesMigrationRoute({
required List<Service> services,
required DiskStatus diskStatus,
required bool isMigration,
Key? key,
List<PageRouteInfo>? children,
}) : super(
ServicesMigrationRoute.name,
args: ServicesMigrationRouteArgs(
services: services,
diskStatus: diskStatus,
isMigration: isMigration,
key: key,
),
initialChildren: children,
);
static const String name = 'RecoveryRoute';
static const String name = 'ServicesMigrationRoute';
static const PageInfo<void> page = PageInfo<void>(name);
static const PageInfo<ServicesMigrationRouteArgs> page =
PageInfo<ServicesMigrationRouteArgs>(name);
}
/// generated route for
/// [InitializingPage]
class InitializingRoute extends PageRouteInfo<void> {
const InitializingRoute({List<PageRouteInfo>? children})
: super(
InitializingRoute.name,
initialChildren: children,
);
class ServicesMigrationRouteArgs {
const ServicesMigrationRouteArgs({
required this.services,
required this.diskStatus,
required this.isMigration,
this.key,
});
static const String name = 'InitializingRoute';
final List<Service> services;
static const PageInfo<void> page = PageInfo<void>(name);
final DiskStatus diskStatus;
final bool isMigration;
final Key? key;
@override
String toString() {
return 'ServicesMigrationRouteArgs{services: $services, diskStatus: $diskStatus, isMigration: $isMigration, key: $key}';
}
}
/// generated route for
@ -561,77 +473,213 @@ class ExtendingVolumeRouteArgs {
}
/// generated route for
/// [ServicesMigrationPage]
class ServicesMigrationRoute extends PageRouteInfo<ServicesMigrationRouteArgs> {
ServicesMigrationRoute({
required List<Service> services,
required DiskStatus diskStatus,
required bool isMigration,
/// [ServicePage]
class ServiceRoute extends PageRouteInfo<ServiceRouteArgs> {
ServiceRoute({
required String serviceId,
Key? key,
List<PageRouteInfo>? children,
}) : super(
ServicesMigrationRoute.name,
args: ServicesMigrationRouteArgs(
services: services,
diskStatus: diskStatus,
isMigration: isMigration,
ServiceRoute.name,
args: ServiceRouteArgs(
serviceId: serviceId,
key: key,
),
initialChildren: children,
);
static const String name = 'ServicesMigrationRoute';
static const String name = 'ServiceRoute';
static const PageInfo<ServicesMigrationRouteArgs> page =
PageInfo<ServicesMigrationRouteArgs>(name);
static const PageInfo<ServiceRouteArgs> page =
PageInfo<ServiceRouteArgs>(name);
}
class ServicesMigrationRouteArgs {
const ServicesMigrationRouteArgs({
required this.services,
required this.diskStatus,
required this.isMigration,
class ServiceRouteArgs {
const ServiceRouteArgs({
required this.serviceId,
this.key,
});
final List<Service> services;
final DiskStatus diskStatus;
final bool isMigration;
final String serviceId;
final Key? key;
@override
String toString() {
return 'ServicesMigrationRouteArgs{services: $services, diskStatus: $diskStatus, isMigration: $isMigration, key: $key}';
return 'ServiceRouteArgs{serviceId: $serviceId, key: $key}';
}
}
/// generated route for
/// [DevicesScreen]
class DevicesRoute extends PageRouteInfo<void> {
const DevicesRoute({List<PageRouteInfo>? children})
/// [ServicesPage]
class ServicesRoute extends PageRouteInfo<void> {
const ServicesRoute({List<PageRouteInfo>? children})
: super(
DevicesRoute.name,
ServicesRoute.name,
initialChildren: children,
);
static const String name = 'DevicesRoute';
static const String name = 'ServicesRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [OnboardingPage]
class OnboardingRoute extends PageRouteInfo<void> {
const OnboardingRoute({List<PageRouteInfo>? children})
/// [InitializingPage]
class InitializingRoute extends PageRouteInfo<void> {
const InitializingRoute({List<PageRouteInfo>? children})
: super(
OnboardingRoute.name,
InitializingRoute.name,
initialChildren: children,
);
static const String name = 'OnboardingRoute';
static const String name = 'InitializingRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [RecoveryRouting]
class RecoveryRoute extends PageRouteInfo<void> {
const RecoveryRoute({List<PageRouteInfo>? children})
: super(
RecoveryRoute.name,
initialChildren: children,
);
static const String name = 'RecoveryRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [UsersPage]
class UsersRoute extends PageRouteInfo<void> {
const UsersRoute({List<PageRouteInfo>? children})
: super(
UsersRoute.name,
initialChildren: children,
);
static const String name = 'UsersRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [NewUserPage]
class NewUserRoute extends PageRouteInfo<void> {
const NewUserRoute({List<PageRouteInfo>? children})
: super(
NewUserRoute.name,
initialChildren: children,
);
static const String name = 'NewUserRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [UserDetailsPage]
class UserDetailsRoute extends PageRouteInfo<UserDetailsRouteArgs> {
UserDetailsRoute({
required String login,
Key? key,
List<PageRouteInfo>? children,
}) : super(
UserDetailsRoute.name,
args: UserDetailsRouteArgs(
login: login,
key: key,
),
initialChildren: children,
);
static const String name = 'UserDetailsRoute';
static const PageInfo<UserDetailsRouteArgs> page =
PageInfo<UserDetailsRouteArgs>(name);
}
class UserDetailsRouteArgs {
const UserDetailsRouteArgs({
required this.login,
this.key,
});
final String login;
final Key? key;
@override
String toString() {
return 'UserDetailsRouteArgs{login: $login, key: $key}';
}
}
/// generated route for
/// [RootPage]
class RootRoute extends PageRouteInfo<void> {
const RootRoute({List<PageRouteInfo>? children})
: super(
RootRoute.name,
initialChildren: children,
);
static const String name = 'RootRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [BackupDetailsPage]
class BackupDetailsRoute extends PageRouteInfo<void> {
const BackupDetailsRoute({List<PageRouteInfo>? children})
: super(
BackupDetailsRoute.name,
initialChildren: children,
);
static const String name = 'BackupDetailsRoute';
static const PageInfo<void> page = PageInfo<void>(name);
}
/// generated route for
/// [BackupsListPage]
class BackupsListRoute extends PageRouteInfo<BackupsListRouteArgs> {
BackupsListRoute({
required Service? service,
Key? key,
List<PageRouteInfo>? children,
}) : super(
BackupsListRoute.name,
args: BackupsListRouteArgs(
service: service,
key: key,
),
initialChildren: children,
);
static const String name = 'BackupsListRoute';
static const PageInfo<BackupsListRouteArgs> page =
PageInfo<BackupsListRouteArgs>(name);
}
class BackupsListRouteArgs {
const BackupsListRouteArgs({
required this.service,
this.key,
});
final Service? service;
final Key? key;
@override
String toString() {
return 'BackupsListRouteArgs{service: $service, key: $key}';
}
}