mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-09-28 22:37:50 +00:00
feat: Implement backups initializing wizard
This commit is contained in:
parent
8f6cb77cc4
commit
a19f0dc2ef
|
@ -25,7 +25,10 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> load() async {
|
Future<void> load() async {
|
||||||
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
if (serverInstallationCubit.state is! ServerInstallationFinished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||||
final BackupConfiguration? backupConfig =
|
final BackupConfiguration? backupConfig =
|
||||||
await api.getBackupsConfiguration();
|
await api.getBackupsConfiguration();
|
||||||
|
@ -33,19 +36,22 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
||||||
getIt<ApiConfigModel>().backblazeCredential;
|
getIt<ApiConfigModel>().backblazeCredential;
|
||||||
final List<Backup> backups = await api.getBackups();
|
final List<Backup> backups = await api.getBackups();
|
||||||
backups.sort((final a, final b) => b.time.compareTo(a.time));
|
backups.sort((final a, final b) => b.time.compareTo(a.time));
|
||||||
emit(
|
final bool? initialized = backupConfig?.isInitialized;
|
||||||
state.copyWith(
|
final nextState = state.copyWith(
|
||||||
backblazeBucket: bucket,
|
backblazeBucket: bucket,
|
||||||
isInitialized: backupConfig?.isInitialized,
|
isInitialized: initialized,
|
||||||
autobackupPeriod: backupConfig?.autobackupPeriod ?? Duration.zero,
|
autobackupPeriod: backupConfig?.autobackupPeriod ?? Duration.zero,
|
||||||
autobackupQuotas: backupConfig?.autobackupQuotas,
|
autobackupQuotas: backupConfig?.autobackupQuotas,
|
||||||
backupsCredential: backupsCredential,
|
backupsCredential: backupsCredential,
|
||||||
backups: backups,
|
backups: backups,
|
||||||
preventActions: false,
|
preventActions: false,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
emit(
|
||||||
|
(initialized == null || initialized == false)
|
||||||
|
? BackupsNotFinishedState.fromBackupsState(nextState)
|
||||||
|
: nextState,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setBackupsKey(
|
Future<void> setBackupsKey(
|
||||||
|
@ -58,7 +64,20 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
||||||
provider: BackupsProviderType.backblaze,
|
provider: BackupsProviderType.backblaze,
|
||||||
);
|
);
|
||||||
await getIt<ApiConfigModel>().storeBackblazeCredential(backupsCredential);
|
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 {
|
Future<void> initializeBackups() async {
|
||||||
|
@ -290,6 +309,6 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void clear() async {
|
void clear() async {
|
||||||
emit(const BackupsState());
|
emit(BackupsNotFinishedState.fromBackupsState(const BackupsState()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,3 +63,81 @@ class BackupsState extends ServerInstallationDependendState {
|
||||||
: autobackupPeriod ?? this.autobackupPeriod,
|
: 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(
|
BrandButton.rised(
|
||||||
onPressed: preventActions
|
onPressed: preventActions
|
||||||
? null
|
? null
|
||||||
: () => context.pushRoute(const BackupProviderPickerRoute()),
|
: () => context.pushRoute(const BackupsInitializingRoute()),
|
||||||
text: 'backup.initialize'.tr(),
|
text: 'backup.initialize'.tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:cubit_form/cubit_form.dart';
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.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/components/buttons/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/layouts/responsive_layout_with_infobox.dart';
|
import 'package:selfprivacy/ui/layouts/responsive_layout_with_infobox.dart';
|
||||||
|
|
||||||
@RoutePage()
|
class BackupProviderPicker extends StatelessWidget {
|
||||||
class BackupProviderPickerPage extends StatelessWidget {
|
const BackupProviderPicker({
|
||||||
const BackupProviderPickerPage({
|
|
||||||
super.key,
|
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.hosting',
|
||||||
'initializing.steps.server_type',
|
'initializing.steps.server_type',
|
||||||
'initializing.steps.dns_provider',
|
'initializing.steps.dns_provider',
|
||||||
'initializing.steps.backups_provider',
|
|
||||||
'initializing.steps.domain',
|
'initializing.steps.domain',
|
||||||
'initializing.steps.master_account',
|
'initializing.steps.master_account',
|
||||||
'initializing.steps.server',
|
'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/logic/models/service.dart';
|
||||||
import 'package:selfprivacy/ui/pages/backups/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/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/devices/devices.dart';
|
||||||
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
|
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
|
||||||
import 'package:selfprivacy/ui/pages/more/about_application.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/initializing/initializing.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
|
||||||
import 'package:selfprivacy/ui/pages/users/users.dart';
|
import 'package:selfprivacy/ui/pages/users/users.dart';
|
||||||
import 'package:selfprivacy/ui/pages/backups/backup_provider_picker_page.dart';
|
|
||||||
|
|
||||||
part 'router.gr.dart';
|
part 'router.gr.dart';
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ class RootRouter extends _$RootRouter {
|
||||||
AutoRoute(page: BackupsListRoute.page),
|
AutoRoute(page: BackupsListRoute.page),
|
||||||
AutoRoute(page: ServerStorageRoute.page),
|
AutoRoute(page: ServerStorageRoute.page),
|
||||||
AutoRoute(page: ExtendingVolumeRoute.page),
|
AutoRoute(page: ExtendingVolumeRoute.page),
|
||||||
AutoRoute(page: BackupProviderPickerRoute.page),
|
AutoRoute(page: BackupsInitializingRoute.page),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
AutoRoute(page: ServicesMigrationRoute.page),
|
AutoRoute(page: ServicesMigrationRoute.page),
|
||||||
|
|
|
@ -186,10 +186,10 @@ abstract class _$RootRouter extends RootStackRouter {
|
||||||
child: const RecoveryRouting(),
|
child: const RecoveryRouting(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
BackupProviderPickerRoute.name: (routeData) {
|
BackupsInitializingRoute.name: (routeData) {
|
||||||
return AutoRoutePage<dynamic>(
|
return AutoRoutePage<dynamic>(
|
||||||
routeData: routeData,
|
routeData: routeData,
|
||||||
child: const BackupProviderPickerPage(),
|
child: const BackupsInitializingPage(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -691,15 +691,15 @@ class RecoveryRoute extends PageRouteInfo<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [BackupProviderPickerPage]
|
/// [BackupsInitializingPage]
|
||||||
class BackupProviderPickerRoute extends PageRouteInfo<void> {
|
class BackupsInitializingRoute extends PageRouteInfo<void> {
|
||||||
const BackupProviderPickerRoute({List<PageRouteInfo>? children})
|
const BackupsInitializingRoute({List<PageRouteInfo>? children})
|
||||||
: super(
|
: super(
|
||||||
BackupProviderPickerRoute.name,
|
BackupsInitializingRoute.name,
|
||||||
initialChildren: children,
|
initialChildren: children,
|
||||||
);
|
);
|
||||||
|
|
||||||
static const String name = 'BackupProviderPickerRoute';
|
static const String name = 'BackupsInitializingRoute';
|
||||||
|
|
||||||
static const PageInfo<void> page = PageInfo<void>(name);
|
static const PageInfo<void> page = PageInfo<void>(name);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue