mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-11-08 01:43:13 +00:00
feat: Implement backups initializing wizard
This commit is contained in:
parent
8f6cb77cc4
commit
a19f0dc2ef
|
@ -25,27 +25,33 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
|||
|
||||
@override
|
||||
Future<void> load() async {
|
||||
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
||||
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||
final BackupConfiguration? backupConfig =
|
||||
await api.getBackupsConfiguration();
|
||||
final BackupsCredential? backupsCredential =
|
||||
getIt<ApiConfigModel>().backblazeCredential;
|
||||
final List<Backup> backups = await api.getBackups();
|
||||
backups.sort((final a, final b) => b.time.compareTo(a.time));
|
||||
emit(
|
||||
state.copyWith(
|
||||
backblazeBucket: bucket,
|
||||
isInitialized: backupConfig?.isInitialized,
|
||||
autobackupPeriod: backupConfig?.autobackupPeriod ?? Duration.zero,
|
||||
autobackupQuotas: backupConfig?.autobackupQuotas,
|
||||
backupsCredential: backupsCredential,
|
||||
backups: backups,
|
||||
preventActions: false,
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
if (serverInstallationCubit.state is! ServerInstallationFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||
final BackupConfiguration? backupConfig =
|
||||
await api.getBackupsConfiguration();
|
||||
final BackupsCredential? backupsCredential =
|
||||
getIt<ApiConfigModel>().backblazeCredential;
|
||||
final List<Backup> backups = await api.getBackups();
|
||||
backups.sort((final a, final b) => b.time.compareTo(a.time));
|
||||
final bool? initialized = backupConfig?.isInitialized;
|
||||
final nextState = state.copyWith(
|
||||
backblazeBucket: bucket,
|
||||
isInitialized: initialized,
|
||||
autobackupPeriod: backupConfig?.autobackupPeriod ?? Duration.zero,
|
||||
autobackupQuotas: backupConfig?.autobackupQuotas,
|
||||
backupsCredential: backupsCredential,
|
||||
backups: backups,
|
||||
preventActions: false,
|
||||
refreshing: false,
|
||||
);
|
||||
emit(
|
||||
(initialized == null || initialized == false)
|
||||
? BackupsNotFinishedState.fromBackupsState(nextState)
|
||||
: nextState,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setBackupsKey(
|
||||
|
@ -58,7 +64,20 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
|||
provider: BackupsProviderType.backblaze,
|
||||
);
|
||||
await getIt<ApiConfigModel>().storeBackblazeCredential(backupsCredential);
|
||||
emit(state.copyWith(backupsCredential: backupsCredential));
|
||||
if (state is BackupsNotFinishedState) {
|
||||
emit(
|
||||
(state as BackupsNotFinishedState).copyNotFinishedWith(
|
||||
backupsCredential: backupsCredential,
|
||||
step: BackupsInitializingStep.period,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
emit(
|
||||
state.copyWith(
|
||||
backupsCredential: backupsCredential,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initializeBackups() async {
|
||||
|
@ -290,6 +309,6 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
|||
|
||||
@override
|
||||
void clear() async {
|
||||
emit(const BackupsState());
|
||||
emit(BackupsNotFinishedState.fromBackupsState(const BackupsState()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,3 +63,81 @@ class BackupsState extends ServerInstallationDependendState {
|
|||
: autobackupPeriod ?? this.autobackupPeriod,
|
||||
);
|
||||
}
|
||||
|
||||
class BackupsNotFinishedState extends BackupsState {
|
||||
BackupsNotFinishedState.fromBackupsState(final BackupsState backupsState)
|
||||
: this(
|
||||
step: BackupsInitializingStep.hosting,
|
||||
isInitialized: false,
|
||||
autobackupPeriod: backupsState.autobackupPeriod,
|
||||
autobackupQuotas: backupsState.autobackupQuotas,
|
||||
backblazeBucket: backupsState.backblazeBucket,
|
||||
backups: backupsState.backups,
|
||||
backupsCredential: backupsState.backupsCredential,
|
||||
preventActions: backupsState.preventActions,
|
||||
refreshTimer: backupsState.refreshTimer,
|
||||
refreshing: backupsState.refreshing,
|
||||
);
|
||||
|
||||
const BackupsNotFinishedState({
|
||||
required this.step,
|
||||
super.isInitialized = false,
|
||||
super.backups = const [],
|
||||
super.preventActions = true,
|
||||
super.refreshTimer = const Duration(seconds: 60),
|
||||
super.refreshing = true,
|
||||
super.autobackupPeriod,
|
||||
super.backblazeBucket,
|
||||
super.autobackupQuotas,
|
||||
super.backupsCredential,
|
||||
});
|
||||
|
||||
final BackupsInitializingStep step;
|
||||
|
||||
BackupsNotFinishedState copyNotFinishedWith({
|
||||
required final BackupsInitializingStep step,
|
||||
final bool? isInitialized,
|
||||
final List<Backup>? backups,
|
||||
final bool? preventActions,
|
||||
final Duration? refreshTimer,
|
||||
final bool? refreshing,
|
||||
final Duration? autobackupPeriod,
|
||||
final BackblazeBucket? backblazeBucket,
|
||||
final AutobackupQuotas? autobackupQuotas,
|
||||
final BackupsCredential? backupsCredential,
|
||||
}) =>
|
||||
BackupsNotFinishedState(
|
||||
isInitialized: isInitialized ?? this.isInitialized,
|
||||
backups: backups ?? this.backups,
|
||||
preventActions: preventActions ?? this.preventActions,
|
||||
refreshTimer: refreshTimer ?? this.refreshTimer,
|
||||
refreshing: refreshing ?? this.refreshing,
|
||||
backupsCredential: backupsCredential ?? this.backupsCredential,
|
||||
backblazeBucket: backblazeBucket ?? this.backblazeBucket,
|
||||
autobackupQuotas: autobackupQuotas ?? this.autobackupQuotas,
|
||||
step: step,
|
||||
// The autobackupPeriod might be null, so if the duration is set to 0, we
|
||||
// set it to null.
|
||||
autobackupPeriod: autobackupPeriod?.inSeconds == 0
|
||||
? null
|
||||
: autobackupPeriod ?? this.autobackupPeriod,
|
||||
);
|
||||
|
||||
BackupsState finish() => BackupsState(
|
||||
isInitialized: true,
|
||||
autobackupPeriod: autobackupPeriod,
|
||||
autobackupQuotas: autobackupQuotas,
|
||||
backblazeBucket: backblazeBucket,
|
||||
backups: backups,
|
||||
backupsCredential: backupsCredential,
|
||||
preventActions: preventActions,
|
||||
refreshTimer: refreshTimer,
|
||||
refreshing: refreshing,
|
||||
);
|
||||
}
|
||||
|
||||
enum BackupsInitializingStep {
|
||||
hosting,
|
||||
period,
|
||||
rotation,
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ class BackupDetailsPage extends StatelessWidget {
|
|||
BrandButton.rised(
|
||||
onPressed: preventActions
|
||||
? null
|
||||
: () => context.pushRoute(const BackupProviderPickerRoute()),
|
||||
: () => context.pushRoute(const BackupsInitializingRoute()),
|
||||
text: 'backup.initialize'.tr(),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
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';
|
||||
|
@ -7,9 +6,8 @@ import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart
|
|||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/layouts/responsive_layout_with_infobox.dart';
|
||||
|
||||
@RoutePage()
|
||||
class BackupProviderPickerPage extends StatelessWidget {
|
||||
const BackupProviderPickerPage({
|
||||
class BackupProviderPicker extends StatelessWidget {
|
||||
const BackupProviderPicker({
|
||||
super.key,
|
||||
});
|
||||
|
146
lib/ui/pages/backups/setup/backups_initializing.dart
Normal file
146
lib/ui/pages/backups/setup/backups_initializing.dart
Normal file
|
@ -0,0 +1,146 @@
|
|||
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/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/outlined_button.dart';
|
||||
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/router/router.dart';
|
||||
import 'package:selfprivacy/utils/breakpoints.dart';
|
||||
|
||||
@RoutePage()
|
||||
class BackupsInitializingPage extends StatelessWidget {
|
||||
const BackupsInitializingPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
final Widget actualInitializingPage;
|
||||
final cubit = context.watch<BackupsCubit>();
|
||||
final currentStep = ((cubit.state) as BackupsNotFinishedState).step;
|
||||
switch (currentStep) {
|
||||
case BackupsInitializingStep.period:
|
||||
actualInitializingPage = const BackupProviderPicker();
|
||||
break;
|
||||
case BackupsInitializingStep.rotation:
|
||||
actualInitializingPage = const BackupProviderPicker();
|
||||
break;
|
||||
case BackupsInitializingStep.hosting:
|
||||
default:
|
||||
actualInitializingPage = const BackupProviderPicker();
|
||||
break;
|
||||
}
|
||||
|
||||
final List<String> titles = [
|
||||
'backup.steps.hosting',
|
||||
'backup.steps.period',
|
||||
'backup.steps.rotation',
|
||||
];
|
||||
|
||||
return BlocListener<BackupsCubit, BackupsState>(
|
||||
listener: (final context, final state) {
|
||||
if (cubit.state is! BackupsNotFinishedState) {
|
||||
context.router.pop();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
endDrawer: const SupportDrawer(),
|
||||
endDrawerEnableOpenDragGesture: false,
|
||||
appBar: Breakpoints.large.isActive(context)
|
||||
? null
|
||||
: AppBar(
|
||||
actions: [
|
||||
if (cubit.state is! BackupsNotFinishedState)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
context.router.pop();
|
||||
},
|
||||
),
|
||||
const SizedBox.shrink(),
|
||||
],
|
||||
title: Text(
|
||||
'more_page.configuration_wizard'.tr(),
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(28),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: ProgressBar(
|
||||
steps: const [
|
||||
'Hosting',
|
||||
'Automatic backups',
|
||||
'Rotation settings',
|
||||
],
|
||||
activeIndex: currentStep.index,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: LayoutBuilder(
|
||||
builder: (final context, final constraints) => Row(
|
||||
children: [
|
||||
if (Breakpoints.large.isActive(context))
|
||||
ProgressDrawer(
|
||||
steps: titles,
|
||||
currentStep: currentStep.index,
|
||||
title: 'more_page.configuration_wizard'.tr(),
|
||||
constraints: constraints,
|
||||
trailing: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (cubit.state is ServerInstallationEmpty ||
|
||||
cubit.state is ServerInstallationNotFinished)
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: BrandButton.filled(
|
||||
text: 'basis.connect_to_existing'.tr(),
|
||||
onPressed: () {
|
||||
context.router.replace(const RecoveryRoute());
|
||||
},
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 8),
|
||||
BrandOutlinedButton(
|
||||
child: Text(
|
||||
'basis.later'.tr(),
|
||||
),
|
||||
onPressed: () {
|
||||
context.router.pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: constraints.maxWidth -
|
||||
(Breakpoints.large.isActive(context) ? 300 : 0),
|
||||
height: constraints.maxHeight,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: Breakpoints.large.isActive(context)
|
||||
? const EdgeInsets.all(16.0)
|
||||
: const EdgeInsets.fromLTRB(16.0, 0, 16.0, 0.0),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: actualInitializingPage,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -54,7 +54,6 @@ class InitializingPage extends StatelessWidget {
|
|||
'initializing.steps.hosting',
|
||||
'initializing.steps.server_type',
|
||||
'initializing.steps.dns_provider',
|
||||
'initializing.steps.backups_provider',
|
||||
'initializing.steps.domain',
|
||||
'initializing.steps.master_account',
|
||||
'initializing.steps.server',
|
||||
|
|
|
@ -5,6 +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/devices/devices.dart';
|
||||
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
|
||||
import 'package:selfprivacy/ui/pages/more/about_application.dart';
|
||||
|
@ -25,7 +26,6 @@ import 'package:selfprivacy/ui/pages/services/services.dart';
|
|||
import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
|
||||
import 'package:selfprivacy/ui/pages/users/users.dart';
|
||||
import 'package:selfprivacy/ui/pages/backups/backup_provider_picker_page.dart';
|
||||
|
||||
part 'router.gr.dart';
|
||||
|
||||
|
@ -101,7 +101,7 @@ class RootRouter extends _$RootRouter {
|
|||
AutoRoute(page: BackupsListRoute.page),
|
||||
AutoRoute(page: ServerStorageRoute.page),
|
||||
AutoRoute(page: ExtendingVolumeRoute.page),
|
||||
AutoRoute(page: BackupProviderPickerRoute.page),
|
||||
AutoRoute(page: BackupsInitializingRoute.page),
|
||||
],
|
||||
),
|
||||
AutoRoute(page: ServicesMigrationRoute.page),
|
||||
|
|
|
@ -186,10 +186,10 @@ abstract class _$RootRouter extends RootStackRouter {
|
|||
child: const RecoveryRouting(),
|
||||
);
|
||||
},
|
||||
BackupProviderPickerRoute.name: (routeData) {
|
||||
BackupsInitializingRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
child: const BackupProviderPickerPage(),
|
||||
child: const BackupsInitializingPage(),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
@ -691,15 +691,15 @@ class RecoveryRoute extends PageRouteInfo<void> {
|
|||
}
|
||||
|
||||
/// generated route for
|
||||
/// [BackupProviderPickerPage]
|
||||
class BackupProviderPickerRoute extends PageRouteInfo<void> {
|
||||
const BackupProviderPickerRoute({List<PageRouteInfo>? children})
|
||||
/// [BackupsInitializingPage]
|
||||
class BackupsInitializingRoute extends PageRouteInfo<void> {
|
||||
const BackupsInitializingRoute({List<PageRouteInfo>? children})
|
||||
: super(
|
||||
BackupProviderPickerRoute.name,
|
||||
BackupsInitializingRoute.name,
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'BackupProviderPickerRoute';
|
||||
static const String name = 'BackupsInitializingRoute';
|
||||
|
||||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue