diff --git a/assets/translations/en.json b/assets/translations/en.json index 8c7f97ba..5e9c5896 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -292,6 +292,9 @@ "hosting": "Storage Provider", "period": "Automatic backups", "rotation": "Rotation settings" + }, + "settings": { + "initialize_settings_title": "Backup Settings" } }, "storage": { diff --git a/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart b/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart index d43ac54a..caabef04 100644 --- a/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart +++ b/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart @@ -27,7 +27,7 @@ class BackupsWizardCubit extends Cubit { backupsCredential: backupsCredential, currentStep: state.currentStep == BackupsWizardStep.hostingRecovery ? BackupsWizardStep.finished - : BackupsWizardStep.period, + : BackupsWizardStep.settingsInitialization, ), ); } @@ -36,7 +36,6 @@ class BackupsWizardCubit extends Cubit { emit( state.copyWith( autobackupPeriod: autobackupPeriod, - currentStep: BackupsWizardStep.quotas, ), ); } @@ -45,7 +44,14 @@ class BackupsWizardCubit extends Cubit { emit( state.copyWith( autobackupQuotas: autobackupQuotas, - currentStep: BackupsWizardStep.confirmation, + ), + ); + } + + void confirmSettings() { + emit( + state.copyWith( + currentStep: BackupsWizardStep.confirmInitialization, ), ); } diff --git a/lib/logic/cubit/backups_wizard/backups_wizard_state.dart b/lib/logic/cubit/backups_wizard/backups_wizard_state.dart index 826979de..b2323c14 100644 --- a/lib/logic/cubit/backups_wizard/backups_wizard_state.dart +++ b/lib/logic/cubit/backups_wizard/backups_wizard_state.dart @@ -41,8 +41,8 @@ class BackupsWizardState { enum BackupsWizardStep { hostingRecovery, hostingInitialization, - period, - quotas, - confirmation, + settingsInitialization, + confirmInitialization, + confirmRecovery, finished, } diff --git a/lib/ui/pages/backups/backup_details.dart b/lib/ui/pages/backups/backup_details.dart index d3ef4ed8..f4637ec8 100644 --- a/lib/ui/pages/backups/backup_details.dart +++ b/lib/ui/pages/backups/backup_details.dart @@ -140,6 +140,12 @@ class BackupDetailsPage extends StatelessWidget { builder: (final context, final scrollController) => ChangeAutobackupsPeriodModal( scrollController: scrollController, + initialAutobackupPeriod: + context.read().state.autobackupPeriod, + onSetPeriodCallback: (final Duration? selectedPeriod) => + context + .read() + .setAutobackupPeriod(selectedPeriod), ), ), ); @@ -183,6 +189,14 @@ class BackupDetailsPage extends StatelessWidget { initialChildSize: 0.6, builder: (final context, final scrollController) => ChangeRotationQuotasModal( + onSetAutobackupQuotasCallback: ( + final AutobackupQuotas selectedAutobackupQuotas, + ) => + context + .read() + .setAutobackupQuotas(selectedAutobackupQuotas), + initialAutobackupQuotas: + context.read().state.autobackupQuotas, scrollController: scrollController, ), ), diff --git a/lib/ui/pages/backups/change_period_modal.dart b/lib/ui/pages/backups/change_period_modal.dart index dbee981e..5f30e751 100644 --- a/lib/ui/pages/backups/change_period_modal.dart +++ b/lib/ui/pages/backups/change_period_modal.dart @@ -1,17 +1,18 @@ 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, + required this.initialAutobackupPeriod, + required this.onSetPeriodCallback, + this.scrollController, super.key, }); - final ScrollController scrollController; + final ScrollController? scrollController; + final Duration? initialAutobackupPeriod; + final Function(Duration? selectedPeriod) onSetPeriodCallback; @override State createState() => @@ -34,72 +35,66 @@ class _ChangeAutobackupsPeriodModalState @override void initState() { super.initState(); - selectedPeriod = context.read().state.autobackupPeriod; + selectedPeriod = widget.initialAutobackupPeriod; } @override - Widget build(final BuildContext context) { - final Duration? initialAutobackupPeriod = - context.watch().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( - onChanged: (final Duration? value) { - setState(() { - selectedPeriod = value; - }); - }, - title: Text( - 'backup.autobackup_period_disable'.tr(), + Widget build(final BuildContext context) => 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, ), - value: null, - groupValue: selectedPeriod, - ), - const Divider( - height: 1.0, - ), - ...autobackupPeriods.map( - (final Duration period) => RadioListTile( + const SizedBox(height: 16), + // Select all services tile + RadioListTile( onChanged: (final Duration? value) { setState(() { selectedPeriod = value; }); }, title: Text( - 'backup.autobackup_period_every'.tr( - namedArgs: {'period': period.toPrettyString(context.locale)}, - ), + 'backup.autobackup_period_disable'.tr(), ), - value: period, + value: null, groupValue: selectedPeriod, ), - ), - const SizedBox(height: 16), - // Create backup button - FilledButton( - onPressed: selectedPeriod == initialAutobackupPeriod - ? null - : () { - context - .read() - .setAutobackupPeriod(selectedPeriod); - Navigator.of(context).pop(); - }, - child: Text( - 'backup.autobackup_set_period'.tr(), + const Divider( + height: 1.0, ), - ), - ], - ); - } + ...autobackupPeriods.map( + (final Duration period) => RadioListTile( + 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 == widget.initialAutobackupPeriod + ? null + : () { + widget.onSetPeriodCallback(selectedPeriod); + Navigator.of(context).pop(); + }, + child: Text( + 'backup.autobackup_set_period'.tr(), + ), + ), + ], + ); } diff --git a/lib/ui/pages/backups/change_rotation_quotas_modal.dart b/lib/ui/pages/backups/change_rotation_quotas_modal.dart index 0ce97eee..8c3016d2 100644 --- a/lib/ui/pages/backups/change_rotation_quotas_modal.dart +++ b/lib/ui/pages/backups/change_rotation_quotas_modal.dart @@ -1,17 +1,19 @@ 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/logic/models/backup.dart'; class ChangeRotationQuotasModal extends StatefulWidget { const ChangeRotationQuotasModal({ - required this.scrollController, + required this.initialAutobackupQuotas, + required this.onSetAutobackupQuotasCallback, + this.scrollController, super.key, }); - final ScrollController scrollController; + final ScrollController? scrollController; + final AutobackupQuotas? initialAutobackupQuotas; + final Function(AutobackupQuotas selectedAutobackupQuotas) + onSetAutobackupQuotasCallback; @override State createState() => @@ -39,8 +41,7 @@ class _ChangeRotationQuotasModalState extends State { @override void initState() { super.initState(); - selectedQuotas = - context.read().state.autobackupQuotas ?? selectedQuotas; + selectedQuotas = widget.initialAutobackupQuotas ?? selectedQuotas; } String generateSubtitle(final int value, final QuotaUnits unit) { @@ -81,126 +82,123 @@ class _ChangeRotationQuotasModalState extends State { } @override - Widget build(final BuildContext context) { - final AutobackupQuotas? initialAutobackupQuotas = - context.watch().state.autobackupQuotas; - return ListView( - controller: widget.scrollController, - padding: const EdgeInsets.all(16), - children: [ - const SizedBox(height: 16), - Text( - 'backup.rotation_quotas_title'.tr(), - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - const SizedBox(height: 8), - Text( - 'backup.quotas_only_applied_to_autobackups'.tr(), - style: Theme.of(context).textTheme.bodyMedium, - textAlign: TextAlign.center, - ), - const SizedBox(height: 16), - // Accordions for each quota type. When tapped allows to enter a new int value - // for the quota. - QuotaSelectionTile( - title: 'backup.quota_titles.last'.tr(), - subtitle: generateSubtitle(selectedQuotas.last, QuotaUnits.last), - value: selectedQuotas.last, - min: 1, - max: 30, - callback: (final double value) { - setState(() { - if (value == 31) { - selectedQuotas = selectedQuotas.copyWith(last: -1); - return; - } - selectedQuotas = selectedQuotas.copyWith(last: value.toInt()); - }); - }, - ), - QuotaSelectionTile( - title: 'backup.quota_titles.daily'.tr(), - subtitle: generateSubtitle(selectedQuotas.daily, QuotaUnits.daily), - value: selectedQuotas.daily, - min: 0, - max: 30, - callback: (final double value) { - setState(() { - if (value == 31) { - selectedQuotas = selectedQuotas.copyWith(daily: -1); - return; - } - selectedQuotas = selectedQuotas.copyWith(daily: value.toInt()); - }); - }, - ), - QuotaSelectionTile( - title: 'backup.quota_titles.weekly'.tr(), - subtitle: generateSubtitle(selectedQuotas.weekly, QuotaUnits.weekly), - value: selectedQuotas.weekly, - min: 0, - max: 15, - callback: (final double value) { - setState(() { - if (value == 16) { - selectedQuotas = selectedQuotas.copyWith(weekly: -1); - return; - } - selectedQuotas = selectedQuotas.copyWith(weekly: value.toInt()); - }); - }, - ), - QuotaSelectionTile( - title: 'backup.quota_titles.monthly'.tr(), - subtitle: - generateSubtitle(selectedQuotas.monthly, QuotaUnits.monthly), - value: selectedQuotas.monthly, - min: 0, - max: 24, - callback: (final double value) { - setState(() { - if (value == 25) { - selectedQuotas = selectedQuotas.copyWith(monthly: -1); - return; - } - selectedQuotas = selectedQuotas.copyWith(monthly: value.toInt()); - }); - }, - ), - QuotaSelectionTile( - title: 'backup.quota_titles.yearly'.tr(), - subtitle: generateSubtitle(selectedQuotas.yearly, QuotaUnits.yearly), - value: selectedQuotas.yearly, - min: 0, - max: 5, - callback: (final double value) { - setState(() { - if (value == 6) { - selectedQuotas = selectedQuotas.copyWith(yearly: -1); - return; - } - selectedQuotas = selectedQuotas.copyWith(yearly: value.toInt()); - }); - }, - ), - const SizedBox(height: 16), - FilledButton( - onPressed: selectedQuotas == initialAutobackupQuotas - ? null - : () { - context - .read() - .setAutobackupQuotas(selectedQuotas); - Navigator.of(context).pop(); - }, - child: Text( - 'backup.set_rotation_quotas'.tr(), + Widget build(final BuildContext context) => ListView( + controller: widget.scrollController, + padding: const EdgeInsets.all(16), + children: [ + const SizedBox(height: 16), + Text( + 'backup.rotation_quotas_title'.tr(), + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, ), - ), - ], - ); - } + const SizedBox(height: 8), + Text( + 'backup.quotas_only_applied_to_autobackups'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + // Accordions for each quota type. When tapped allows to enter a new int value + // for the quota. + QuotaSelectionTile( + title: 'backup.quota_titles.last'.tr(), + subtitle: generateSubtitle(selectedQuotas.last, QuotaUnits.last), + value: selectedQuotas.last, + min: 1, + max: 30, + callback: (final double value) { + setState(() { + if (value == 31) { + selectedQuotas = selectedQuotas.copyWith(last: -1); + return; + } + selectedQuotas = selectedQuotas.copyWith(last: value.toInt()); + }); + }, + ), + QuotaSelectionTile( + title: 'backup.quota_titles.daily'.tr(), + subtitle: generateSubtitle(selectedQuotas.daily, QuotaUnits.daily), + value: selectedQuotas.daily, + min: 0, + max: 30, + callback: (final double value) { + setState(() { + if (value == 31) { + selectedQuotas = selectedQuotas.copyWith(daily: -1); + return; + } + selectedQuotas = selectedQuotas.copyWith(daily: value.toInt()); + }); + }, + ), + QuotaSelectionTile( + title: 'backup.quota_titles.weekly'.tr(), + subtitle: + generateSubtitle(selectedQuotas.weekly, QuotaUnits.weekly), + value: selectedQuotas.weekly, + min: 0, + max: 15, + callback: (final double value) { + setState(() { + if (value == 16) { + selectedQuotas = selectedQuotas.copyWith(weekly: -1); + return; + } + selectedQuotas = selectedQuotas.copyWith(weekly: value.toInt()); + }); + }, + ), + QuotaSelectionTile( + title: 'backup.quota_titles.monthly'.tr(), + subtitle: + generateSubtitle(selectedQuotas.monthly, QuotaUnits.monthly), + value: selectedQuotas.monthly, + min: 0, + max: 24, + callback: (final double value) { + setState(() { + if (value == 25) { + selectedQuotas = selectedQuotas.copyWith(monthly: -1); + return; + } + selectedQuotas = + selectedQuotas.copyWith(monthly: value.toInt()); + }); + }, + ), + QuotaSelectionTile( + title: 'backup.quota_titles.yearly'.tr(), + subtitle: + generateSubtitle(selectedQuotas.yearly, QuotaUnits.yearly), + value: selectedQuotas.yearly, + min: 0, + max: 5, + callback: (final double value) { + setState(() { + if (value == 6) { + selectedQuotas = selectedQuotas.copyWith(yearly: -1); + return; + } + selectedQuotas = selectedQuotas.copyWith(yearly: value.toInt()); + }); + }, + ), + const SizedBox(height: 16), + FilledButton( + onPressed: selectedQuotas == widget.initialAutobackupQuotas + ? null + : () { + widget.onSetAutobackupQuotasCallback(selectedQuotas); + Navigator.of(context).pop(); + }, + child: Text( + 'backup.set_rotation_quotas'.tr(), + ), + ), + ], + ); } class QuotaSelectionTile extends StatelessWidget { diff --git a/lib/ui/pages/backups/setup/backup_confirmation.dart b/lib/ui/pages/backups/setup/backup_confirmation.dart new file mode 100644 index 00000000..c4e0fe76 --- /dev/null +++ b/lib/ui/pages/backups/setup/backup_confirmation.dart @@ -0,0 +1,36 @@ +import 'package:cubit_form/cubit_form.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:selfprivacy/logic/cubit/forms/setup/initializing/backblaze_form_cubit.dart'; +import 'package:selfprivacy/ui/components/buttons/brand_button.dart'; +import 'package:selfprivacy/ui/layouts/responsive_layout_with_infobox.dart'; + +class BackupProviderPicker extends StatelessWidget { + const BackupProviderPicker({ + super.key, + }); + + @override + Widget build(final BuildContext context) => ResponsiveLayoutWithInfobox( + topChild: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${'initializing.connect_to_server_provider'.tr()}Backblaze', + style: Theme.of(context).textTheme.headlineSmall, + ), + ], + ), + primaryColumn: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 32), + BrandButton.rised( + onPressed: () => context.read().trySubmit(), + text: 'basis.connect'.tr(), + ), + const SizedBox(height: 10), + ], + ), + ); +} diff --git a/lib/ui/pages/backups/setup/backups_initializing.dart b/lib/ui/pages/backups/setup/backup_initializing.dart similarity index 88% rename from lib/ui/pages/backups/setup/backups_initializing.dart rename to lib/ui/pages/backups/setup/backup_initializing.dart index 78ced1f1..a3c4c649 100644 --- a/lib/ui/pages/backups/setup/backups_initializing.dart +++ b/lib/ui/pages/backups/setup/backup_initializing.dart @@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart'; +import 'package:selfprivacy/logic/cubit/backups_wizard/backups_wizard_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/ui/components/buttons/brand_button.dart'; import 'package:selfprivacy/ui/components/buttons/outlined_button.dart'; @@ -10,6 +10,7 @@ import 'package:selfprivacy/ui/components/drawers/progress_drawer.dart'; import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart'; import 'package:selfprivacy/ui/components/drawers/support_drawer.dart'; import 'package:selfprivacy/ui/pages/backups/setup/backup_provider_picker.dart'; +import 'package:selfprivacy/ui/pages/backups/setup/backup_settings_page.dart'; import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/breakpoints.dart'; @@ -20,16 +21,14 @@ class BackupsInitializingPage extends StatelessWidget { @override Widget build(final BuildContext context) { final Widget actualInitializingPage; - final cubit = context.watch(); - final currentStep = ((cubit.state) as BackupsNotFinishedState).step; + final cubit = context.watch(); + final currentStep = cubit.state.currentStep; switch (currentStep) { - case BackupsInitializingStep.period: - actualInitializingPage = const BackupProviderPicker(); + case BackupsWizardStep.settingsInitialization: + actualInitializingPage = const BackupSettingsPage(); break; - case BackupsInitializingStep.rotation: - actualInitializingPage = const BackupProviderPicker(); - break; - case BackupsInitializingStep.hosting: + case BackupsWizardStep.hostingRecovery: + case BackupsWizardStep.hostingInitialization: default: actualInitializingPage = const BackupProviderPicker(); break; @@ -41,9 +40,9 @@ class BackupsInitializingPage extends StatelessWidget { 'backup.steps.rotation', ]; - return BlocListener( + return BlocListener( listener: (final context, final state) { - if (cubit.state is! BackupsNotFinishedState) { + if (cubit.state.currentStep == BackupsWizardStep.finished) { context.router.pop(); } }, @@ -54,7 +53,7 @@ class BackupsInitializingPage extends StatelessWidget { ? null : AppBar( actions: [ - if (cubit.state is! BackupsNotFinishedState) + if (cubit.state.currentStep == BackupsWizardStep.finished) IconButton( icon: const Icon(Icons.check), onPressed: () { diff --git a/lib/ui/pages/backups/setup/backup_settings_page.dart b/lib/ui/pages/backups/setup/backup_settings_page.dart new file mode 100644 index 00000000..770f5b9a --- /dev/null +++ b/lib/ui/pages/backups/setup/backup_settings_page.dart @@ -0,0 +1,119 @@ +import 'package:cubit_form/cubit_form.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:selfprivacy/logic/cubit/backups_wizard/backups_wizard_cubit.dart'; +import 'package:selfprivacy/logic/models/backup.dart'; +import 'package:selfprivacy/ui/layouts/responsive_layout_with_infobox.dart'; +import 'package:selfprivacy/ui/pages/backups/change_period_modal.dart'; +import 'package:selfprivacy/ui/pages/backups/change_rotation_quotas_modal.dart'; +import 'package:selfprivacy/utils/extensions/duration.dart'; + +class BackupSettingsPage extends StatelessWidget { + const BackupSettingsPage({ + super.key, + }); + + @override + Widget build(final BuildContext context) { + final cubit = context.watch(); + final autobackupPeriod = cubit.state.autobackupPeriod; + return ResponsiveLayoutWithInfobox( + topChild: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'backup.settings.initialize_settings_title'.tr(), + style: Theme.of(context).textTheme.headlineSmall, + ), + ], + ), + primaryColumn: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 32), + ListTile( + onTap: () { + 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( + initialAutobackupPeriod: null, + onSetPeriodCallback: (final Duration? selectedPeriod) => + context + .read() + .setAutobackupPeriod(selectedPeriod), + 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(), + ), + ), + ListTile( + onTap: () { + 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) => + ChangeRotationQuotasModal( + initialAutobackupQuotas: null, + onSetAutobackupQuotasCallback: + (final AutobackupQuotas selectedAutobackupQuotas) => + context + .read() + .setAutobackupQuotas(selectedAutobackupQuotas), + scrollController: scrollController, + ), + ), + ); + }, + leading: const Icon( + Icons.auto_delete_outlined, + ), + title: Text( + 'backup.rotation_quotas_title'.tr(), + ), + ), + const SizedBox(height: 16), + FilledButton( + onPressed: () => + context.read().confirmSettings(), + child: Text( + 'backup.set_rotation_quotas'.tr(), + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/router/router.dart b/lib/ui/router/router.dart index 2610ca86..47391936 100644 --- a/lib/ui/router/router.dart +++ b/lib/ui/router/router.dart @@ -5,7 +5,7 @@ import 'package:selfprivacy/logic/models/disk_status.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/pages/backups/backup_details.dart'; import 'package:selfprivacy/ui/pages/backups/backups_list.dart'; -import 'package:selfprivacy/ui/pages/backups/setup/backups_initializing.dart'; +import 'package:selfprivacy/ui/pages/backups/setup/backup_initializing.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';