diff --git a/assets/translations/en.json b/assets/translations/en.json index 82f682ba..8c7f97ba 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -287,6 +287,11 @@ "other": "Last {} yearly backups will be kept" }, "yearly_infinite": "All yearly backups will be kept" + }, + "steps": { + "hosting": "Storage Provider", + "period": "Automatic backups", + "rotation": "Rotation settings" } }, "storage": { @@ -462,7 +467,6 @@ "hosting": "Hosting", "server_type": "Server type", "dns_provider": "DNS provider", - "backups_provider": "Backups", "domain": "Domain", "master_account": "Master account", "server": "Server", diff --git a/lib/config/bloc_config.dart b/lib/config/bloc_config.dart index 381261fe..b692d5ad 100644 --- a/lib/config/bloc_config.dart +++ b/lib/config/bloc_config.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:selfprivacy/logic/cubit/backups_wizard/backups_wizard_cubit.dart'; import 'package:selfprivacy/logic/cubit/devices/devices_cubit.dart'; import 'package:selfprivacy/logic/cubit/recovery_key/recovery_key_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart'; @@ -27,6 +28,7 @@ class BlocAndProviderConfig extends StatelessWidget { const isAutoDark = true; final serverInstallationCubit = ServerInstallationCubit()..load(); final supportSystemCubit = SupportSystemCubit(); + final backupsWizardCubit = BackupsWizardCubit(); final usersCubit = UsersCubit(serverInstallationCubit); final servicesCubit = ServicesCubit(serverInstallationCubit); final backupsCubit = BackupsCubit(serverInstallationCubit); @@ -97,6 +99,9 @@ class BlocAndProviderConfig extends StatelessWidget { servicesCubit: servicesCubit, ), ), + BlocProvider( + create: (final _) => backupsWizardCubit..load(), + ), ], child: child, ); diff --git a/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart b/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart new file mode 100644 index 00000000..d43ac54a --- /dev/null +++ b/lib/logic/cubit/backups_wizard/backups_wizard_cubit.dart @@ -0,0 +1,52 @@ +import 'dart:async'; + +import 'package:cubit_form/cubit_form.dart'; +import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart'; +import 'package:selfprivacy/logic/models/backup.dart'; +import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; + +part 'backups_wizard_state.dart'; + +class BackupsWizardCubit extends Cubit { + BackupsWizardCubit() : super(const BackupsWizardState()); + + Future load() async { + final BackupConfiguration? backupConfig = + await ServerApi().getBackupsConfiguration(); + + /// If config already exists, then user only lacks credentials, + /// we don't need full re-initialization + if (backupConfig != null) { + emit(state.copyWith(currentStep: BackupsWizardStep.hostingRecovery)); + } + } + + void setBackupsCredential(final BackupsCredential backupsCredential) { + emit( + state.copyWith( + backupsCredential: backupsCredential, + currentStep: state.currentStep == BackupsWizardStep.hostingRecovery + ? BackupsWizardStep.finished + : BackupsWizardStep.period, + ), + ); + } + + void setAutobackupPeriod(final Duration? autobackupPeriod) { + emit( + state.copyWith( + autobackupPeriod: autobackupPeriod, + currentStep: BackupsWizardStep.quotas, + ), + ); + } + + void setAutobackupQuotas(final AutobackupQuotas autobackupQuotas) { + emit( + state.copyWith( + autobackupQuotas: autobackupQuotas, + currentStep: BackupsWizardStep.confirmation, + ), + ); + } +} diff --git a/lib/logic/cubit/backups_wizard/backups_wizard_state.dart b/lib/logic/cubit/backups_wizard/backups_wizard_state.dart new file mode 100644 index 00000000..826979de --- /dev/null +++ b/lib/logic/cubit/backups_wizard/backups_wizard_state.dart @@ -0,0 +1,48 @@ +part of 'backups_wizard_cubit.dart'; + +/// Temporary attributes of backups configuration. +/// +/// After backups wizard is finished, this data is to be converted +/// to actual backups state and set to the app config and its server permanently. +class BackupsWizardState { + const BackupsWizardState({ + this.autobackupPeriod, + this.autobackupQuotas, + this.backupsCredential, + this.currentStep = BackupsWizardStep.hostingInitialization, + }); + + final BackupsWizardStep currentStep; + final Duration? autobackupPeriod; + final AutobackupQuotas? autobackupQuotas; + final BackupsCredential? backupsCredential; + + BackupsWizardState copyWith({ + final Duration? autobackupPeriod, + final AutobackupQuotas? autobackupQuotas, + final BackupsCredential? backupsCredential, + final BackupsWizardStep? currentStep, + }) => + BackupsWizardState( + backupsCredential: backupsCredential ?? this.backupsCredential, + autobackupQuotas: autobackupQuotas ?? this.autobackupQuotas, + autobackupPeriod: autobackupPeriod ?? this.autobackupPeriod, + currentStep: currentStep ?? this.currentStep, + ); +} + +/// The state machine is expected to follow: +/// +/// (Initialize backups) -> hostingInitialization -> period -> rotation -> confirmation +/// +/// or +/// +/// (Recovery access) -> hostingRecovery +enum BackupsWizardStep { + hostingRecovery, + hostingInitialization, + period, + quotas, + confirmation, + finished, +}