mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-23 09:16:54 +00:00
feat(backups): Backups screens
This commit is contained in:
parent
df214a07bc
commit
a4dbba0968
|
@ -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",
|
||||
|
|
|
@ -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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
85
lib/ui/pages/backups/backups_list.dart
Normal file
85
lib/ui/pages/backups/backups_list.dart
Normal 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,
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
108
lib/ui/pages/backups/change_period_modal.dart
Normal file
108
lib/ui/pages/backups/change_period_modal.dart
Normal 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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
161
lib/ui/pages/backups/create_backups_modal.dart
Normal file
161
lib/ui/pages/backups/create_backups_modal.dart
Normal 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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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}';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue