refactor: Rewrite backups cubit to bloc, using ApiRepo streams
parent
b1be3f24d6
commit
a5e7725733
|
@ -1,15 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/connection_status/connection_status_bloc.dart';
|
import 'package:selfprivacy/logic/cubit/connection_status/connection_status_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/devices/devices_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/recovery_key/recovery_key_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
|
||||||
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
|
||||||
|
@ -29,7 +29,7 @@ class BlocAndProviderConfig extends StatelessWidget {
|
||||||
final supportSystemCubit = SupportSystemCubit();
|
final supportSystemCubit = SupportSystemCubit();
|
||||||
final usersCubit = UsersCubit(serverInstallationCubit);
|
final usersCubit = UsersCubit(serverInstallationCubit);
|
||||||
final servicesCubit = ServicesCubit(serverInstallationCubit);
|
final servicesCubit = ServicesCubit(serverInstallationCubit);
|
||||||
final backupsCubit = BackupsCubit(serverInstallationCubit);
|
final backupsBloc = BackupsBloc();
|
||||||
final dnsRecordsCubit = DnsRecordsCubit(serverInstallationCubit);
|
final dnsRecordsCubit = DnsRecordsCubit(serverInstallationCubit);
|
||||||
final recoveryKeyCubit = RecoveryKeyCubit(serverInstallationCubit);
|
final recoveryKeyCubit = RecoveryKeyCubit(serverInstallationCubit);
|
||||||
final apiDevicesCubit = ApiDevicesCubit(serverInstallationCubit);
|
final apiDevicesCubit = ApiDevicesCubit(serverInstallationCubit);
|
||||||
|
@ -65,8 +65,7 @@ class BlocAndProviderConfig extends StatelessWidget {
|
||||||
lazy: false,
|
lazy: false,
|
||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (final _) => backupsCubit,
|
create: (final _) => backupsBloc,
|
||||||
lazy: false,
|
|
||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (final _) => dnsRecordsCubit,
|
create: (final _) => dnsRecordsCubit,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:selfprivacy/logic/get_it/navigation.dart';
|
||||||
export 'package:selfprivacy/logic/get_it/api_config.dart';
|
export 'package:selfprivacy/logic/get_it/api_config.dart';
|
||||||
export 'package:selfprivacy/logic/get_it/console.dart';
|
export 'package:selfprivacy/logic/get_it/console.dart';
|
||||||
export 'package:selfprivacy/logic/get_it/navigation.dart';
|
export 'package:selfprivacy/logic/get_it/navigation.dart';
|
||||||
|
export 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
||||||
|
|
||||||
final GetIt getIt = GetIt.instance;
|
final GetIt getIt = GetIt.instance;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,396 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
|
import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/backup.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/initialize_repository_input.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/service.dart';
|
||||||
|
|
||||||
|
part 'backups_event.dart';
|
||||||
|
part 'backups_state.dart';
|
||||||
|
|
||||||
|
class BackupsBloc extends Bloc<BackupsEvent, BackupsState> {
|
||||||
|
BackupsBloc() : super(BackupsInitial()) {
|
||||||
|
final connectionRepository = getIt<ApiConnectionRepository>();
|
||||||
|
|
||||||
|
_apiStatusSubscription = connectionRepository.connectionStatusStream
|
||||||
|
.listen((final ConnectionStatus connectionStatus) {
|
||||||
|
switch (connectionStatus) {
|
||||||
|
case ConnectionStatus.nonexistent:
|
||||||
|
add(const BackupsServerReset());
|
||||||
|
isLoaded = false;
|
||||||
|
break;
|
||||||
|
case ConnectionStatus.connected:
|
||||||
|
if (!isLoaded) {
|
||||||
|
add(const BackupsServerLoaded());
|
||||||
|
isLoaded = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_apiDataSubscription = connectionRepository.dataStream.listen(
|
||||||
|
(final ApiData apiData) {
|
||||||
|
if (apiData.backups.data == null || apiData.backupConfig.data == null) {
|
||||||
|
add(const BackupsServerReset());
|
||||||
|
isLoaded = false;
|
||||||
|
} else {
|
||||||
|
add(
|
||||||
|
BackupsStateChanged(
|
||||||
|
apiData.backups.data!,
|
||||||
|
apiData.backupConfig.data,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
isLoaded = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (connectionRepository.connectionStatus == ConnectionStatus.connected) {
|
||||||
|
add(const BackupsServerLoaded());
|
||||||
|
isLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
on<BackupsServerLoaded>(
|
||||||
|
_loadState,
|
||||||
|
);
|
||||||
|
on<BackupsServerReset>(
|
||||||
|
_resetState,
|
||||||
|
);
|
||||||
|
on<BackupsStateChanged>(
|
||||||
|
_updateState,
|
||||||
|
);
|
||||||
|
on<InitializeBackupsRepository>(
|
||||||
|
_initializeRepository,
|
||||||
|
);
|
||||||
|
on<ForceSnapshotListUpdate>(
|
||||||
|
_forceSnapshotListUpdate,
|
||||||
|
);
|
||||||
|
on<CreateBackups>(
|
||||||
|
_createBackups,
|
||||||
|
);
|
||||||
|
on<RestoreBackup>(
|
||||||
|
_restoreBackup,
|
||||||
|
);
|
||||||
|
on<SetAutobackupPeriod>(
|
||||||
|
_setAutobackupPeriod,
|
||||||
|
);
|
||||||
|
on<SetAutobackupQuotas>(
|
||||||
|
_setAutobackupQuotas,
|
||||||
|
);
|
||||||
|
on<ForgetSnapshot>(
|
||||||
|
_forgetSnapshot,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final BackblazeApi backblaze = BackblazeApi();
|
||||||
|
|
||||||
|
Future<void> _loadState(
|
||||||
|
final BackupsServerLoaded event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||||
|
final backups = getIt<ApiConnectionRepository>().apiData.backups;
|
||||||
|
final backupConfig = getIt<ApiConnectionRepository>().apiData.backupConfig;
|
||||||
|
if (backupConfig.data == null || backups.data == null) {
|
||||||
|
emit(BackupsLoading());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bucket != null &&
|
||||||
|
backupConfig.data!.encryptionKey != bucket.encryptionKey) {
|
||||||
|
bucket = bucket.copyWith(
|
||||||
|
encryptionKey: backupConfig.data!.encryptionKey,
|
||||||
|
);
|
||||||
|
await getIt<ApiConfigModel>().setBackblazeBucket(bucket);
|
||||||
|
}
|
||||||
|
if (backupConfig.data!.isInitialized) {
|
||||||
|
emit(
|
||||||
|
BackupsInitialized(
|
||||||
|
backblazeBucket: bucket,
|
||||||
|
backupConfig: backupConfig.data,
|
||||||
|
backups: backups.data ?? [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
emit(BackupsUnititialized());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _resetState(
|
||||||
|
final BackupsServerReset event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
emit(BackupsInitial());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeRepository(
|
||||||
|
final InitializeBackupsRepository event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
if (state is! BackupsUnititialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit(BackupsInitializing());
|
||||||
|
final String? encryptionKey = getIt<ApiConnectionRepository>()
|
||||||
|
.apiData
|
||||||
|
.backupConfig
|
||||||
|
.data
|
||||||
|
?.encryptionKey;
|
||||||
|
if (encryptionKey == null) {
|
||||||
|
emit(BackupsUnititialized());
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar("Couldn't get encryption key from your server.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BackblazeBucket bucket;
|
||||||
|
|
||||||
|
if (state.backblazeBucket == null) {
|
||||||
|
final String domain = getIt<ApiConnectionRepository>()
|
||||||
|
.serverDomain!
|
||||||
|
.domainName
|
||||||
|
.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||||
|
final int serverId = getIt<ApiConnectionRepository>().serverDetails!.id;
|
||||||
|
String bucketName =
|
||||||
|
'${DateTime.now().millisecondsSinceEpoch}-$serverId-$domain';
|
||||||
|
if (bucketName.length > 49) {
|
||||||
|
bucketName = bucketName.substring(0, 49);
|
||||||
|
}
|
||||||
|
final String bucketId = await backblaze.createBucket(bucketName);
|
||||||
|
|
||||||
|
final BackblazeApplicationKey key = await backblaze.createKey(bucketId);
|
||||||
|
bucket = BackblazeBucket(
|
||||||
|
bucketId: bucketId,
|
||||||
|
bucketName: bucketName,
|
||||||
|
applicationKey: key.applicationKey,
|
||||||
|
applicationKeyId: key.applicationKeyId,
|
||||||
|
encryptionKey: encryptionKey,
|
||||||
|
);
|
||||||
|
|
||||||
|
await getIt<ApiConfigModel>().setBackblazeBucket(bucket);
|
||||||
|
emit(state.copyWith(backblazeBucket: bucket));
|
||||||
|
} else {
|
||||||
|
bucket = state.backblazeBucket!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final GenericResult result =
|
||||||
|
await getIt<ApiConnectionRepository>().api.initializeRepository(
|
||||||
|
InitializeRepositoryInput(
|
||||||
|
provider: BackupsProviderType.backblaze,
|
||||||
|
locationId: bucket.bucketId,
|
||||||
|
locationName: bucket.bucketName,
|
||||||
|
login: bucket.applicationKeyId,
|
||||||
|
password: bucket.applicationKey,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result.success == false) {
|
||||||
|
getIt<NavigationService>().showSnackBar(
|
||||||
|
result.message ?? "Couldn't initialize repository on your server.");
|
||||||
|
emit(BackupsUnititialized());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getIt<ApiConnectionRepository>().apiData.backupConfig.invalidate();
|
||||||
|
getIt<ApiConnectionRepository>().apiData.backups.invalidate();
|
||||||
|
await getIt<ApiConnectionRepository>().reload(null);
|
||||||
|
|
||||||
|
getIt<NavigationService>().showSnackBar(
|
||||||
|
'Backups repository is now initializing. It may take a while.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateState(
|
||||||
|
final BackupsStateChanged event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
if (event.backupConfiguration == null ||
|
||||||
|
event.backupConfiguration!.isInitialized == false) {
|
||||||
|
emit(BackupsUnititialized());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||||
|
emit(
|
||||||
|
BackupsInitialized(
|
||||||
|
backblazeBucket: bucket,
|
||||||
|
backupConfig: event.backupConfiguration,
|
||||||
|
backups: event.backups,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _forceSnapshotListUpdate(
|
||||||
|
final ForceSnapshotListUpdate event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is BackupsInitialized) {
|
||||||
|
emit(BackupsBusy.fromState(currentState));
|
||||||
|
getIt<NavigationService>().showSnackBar('backup.refetching_list'.tr());
|
||||||
|
await getIt<ApiConnectionRepository>().api.forceBackupListReload();
|
||||||
|
getIt<ApiConnectionRepository>().apiData.backups.invalidate();
|
||||||
|
emit(currentState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _createBackups(
|
||||||
|
final CreateBackups event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is BackupsInitialized) {
|
||||||
|
emit(BackupsBusy.fromState(currentState));
|
||||||
|
for (final service in event.services) {
|
||||||
|
final GenericResult<ServerJob?> result =
|
||||||
|
await getIt<ApiConnectionRepository>().api.startBackup(
|
||||||
|
service.id,
|
||||||
|
);
|
||||||
|
if (result.success == false) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar(result.message ?? 'Unknown error');
|
||||||
|
}
|
||||||
|
if (result.data != null) {
|
||||||
|
getIt<ApiConnectionRepository>()
|
||||||
|
.apiData
|
||||||
|
.serverJobs
|
||||||
|
.data
|
||||||
|
?.add(result.data!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit(currentState);
|
||||||
|
getIt<ApiConnectionRepository>().emitData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _restoreBackup(
|
||||||
|
final RestoreBackup event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is BackupsInitialized) {
|
||||||
|
emit(BackupsBusy.fromState(currentState));
|
||||||
|
final GenericResult result =
|
||||||
|
await getIt<ApiConnectionRepository>().api.restoreBackup(
|
||||||
|
event.backupId,
|
||||||
|
event.restoreStrategy,
|
||||||
|
);
|
||||||
|
if (result.success == false) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar(result.message ?? 'Unknown error');
|
||||||
|
}
|
||||||
|
emit(currentState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setAutobackupPeriod(
|
||||||
|
final SetAutobackupPeriod event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is BackupsInitialized) {
|
||||||
|
emit(BackupsBusy.fromState(currentState));
|
||||||
|
final GenericResult result =
|
||||||
|
await getIt<ApiConnectionRepository>().api.setAutobackupPeriod(
|
||||||
|
period: event.period?.inMinutes,
|
||||||
|
);
|
||||||
|
if (result.success == false) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar(result.message ?? 'Unknown error');
|
||||||
|
}
|
||||||
|
if (result.success == true) {
|
||||||
|
getIt<ApiConnectionRepository>().apiData.backupConfig.data =
|
||||||
|
getIt<ApiConnectionRepository>()
|
||||||
|
.apiData
|
||||||
|
.backupConfig
|
||||||
|
.data
|
||||||
|
?.copyWith(
|
||||||
|
autobackupPeriod: event.period,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
emit(currentState);
|
||||||
|
getIt<ApiConnectionRepository>().emitData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setAutobackupQuotas(
|
||||||
|
final SetAutobackupQuotas event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is BackupsInitialized) {
|
||||||
|
emit(BackupsBusy.fromState(currentState));
|
||||||
|
final GenericResult result =
|
||||||
|
await getIt<ApiConnectionRepository>().api.setAutobackupQuotas(
|
||||||
|
event.quotas,
|
||||||
|
);
|
||||||
|
if (result.success == false) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar(result.message ?? 'Unknown error');
|
||||||
|
}
|
||||||
|
if (result.success == true) {
|
||||||
|
getIt<ApiConnectionRepository>().apiData.backupConfig.data =
|
||||||
|
getIt<ApiConnectionRepository>()
|
||||||
|
.apiData
|
||||||
|
.backupConfig
|
||||||
|
.data
|
||||||
|
?.copyWith(
|
||||||
|
autobackupQuotas: event.quotas,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
emit(currentState);
|
||||||
|
getIt<ApiConnectionRepository>().emitData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _forgetSnapshot(
|
||||||
|
final ForgetSnapshot event,
|
||||||
|
final Emitter<BackupsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is BackupsInitialized) {
|
||||||
|
emit(BackupsBusy.fromState(currentState));
|
||||||
|
final GenericResult result =
|
||||||
|
await getIt<ApiConnectionRepository>().api.forgetSnapshot(
|
||||||
|
event.backupId,
|
||||||
|
);
|
||||||
|
if (result.success == false) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar(result.message ?? 'jobs.generic_error'.tr());
|
||||||
|
} else if (result.data == false) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar('backup.forget_snapshot_error'.tr());
|
||||||
|
} else {
|
||||||
|
final backups = getIt<ApiConnectionRepository>().apiData.backups.data;
|
||||||
|
if (backups != null) {
|
||||||
|
getIt<ApiConnectionRepository>().apiData.backups.data = backups
|
||||||
|
.where((final Backup backup) => backup.id != event.backupId)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit(currentState);
|
||||||
|
getIt<ApiConnectionRepository>().emitData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
_apiStatusSubscription.cancel();
|
||||||
|
_apiDataSubscription.cancel();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onChange(final Change<BackupsState> change) {
|
||||||
|
super.onChange(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
late StreamSubscription _apiStatusSubscription;
|
||||||
|
late StreamSubscription _apiDataSubscription;
|
||||||
|
bool isLoaded = false;
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
part of 'backups_bloc.dart';
|
||||||
|
|
||||||
|
sealed class BackupsEvent extends Equatable {
|
||||||
|
const BackupsEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsServerLoaded extends BackupsEvent {
|
||||||
|
const BackupsServerLoaded();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsServerReset extends BackupsEvent {
|
||||||
|
const BackupsServerReset();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class InitializeBackupsRepository extends BackupsEvent {
|
||||||
|
const InitializeBackupsRepository();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsStateChanged extends BackupsEvent {
|
||||||
|
const BackupsStateChanged(this.backups, this.backupConfiguration);
|
||||||
|
|
||||||
|
final List<Backup> backups;
|
||||||
|
final BackupConfiguration? backupConfiguration;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [backups, backupConfiguration];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ForceSnapshotListUpdate extends BackupsEvent {
|
||||||
|
const ForceSnapshotListUpdate();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateBackups extends BackupsEvent {
|
||||||
|
const CreateBackups(this.services);
|
||||||
|
|
||||||
|
final List<Service> services;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [services];
|
||||||
|
}
|
||||||
|
|
||||||
|
class RestoreBackup extends BackupsEvent {
|
||||||
|
const RestoreBackup(this.backupId, this.restoreStrategy);
|
||||||
|
|
||||||
|
final String backupId;
|
||||||
|
final BackupRestoreStrategy restoreStrategy;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [backupId, restoreStrategy];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SetAutobackupPeriod extends BackupsEvent {
|
||||||
|
const SetAutobackupPeriod(this.period);
|
||||||
|
|
||||||
|
final Duration? period;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [period];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SetAutobackupQuotas extends BackupsEvent {
|
||||||
|
const SetAutobackupQuotas(this.quotas);
|
||||||
|
|
||||||
|
final AutobackupQuotas quotas;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [quotas];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ForgetSnapshot extends BackupsEvent {
|
||||||
|
const ForgetSnapshot(this.backupId);
|
||||||
|
|
||||||
|
final String backupId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [backupId];
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
part of 'backups_bloc.dart';
|
||||||
|
|
||||||
|
sealed class BackupsState extends Equatable {
|
||||||
|
BackupsState({
|
||||||
|
this.backblazeBucket,
|
||||||
|
});
|
||||||
|
final apiConnectionRepository = getIt<ApiConnectionRepository>();
|
||||||
|
final BackblazeBucket? backblazeBucket;
|
||||||
|
|
||||||
|
@Deprecated('Infer the initializations status from state')
|
||||||
|
bool get isInitialized => false;
|
||||||
|
|
||||||
|
@Deprecated('Infer the loading status from state')
|
||||||
|
bool get refreshing => false;
|
||||||
|
|
||||||
|
@Deprecated('Infer the prevent actions status from state')
|
||||||
|
bool get preventActions => true;
|
||||||
|
|
||||||
|
List<Backup> get backups => [];
|
||||||
|
|
||||||
|
List<Backup> serviceBackups(final String serviceId) => [];
|
||||||
|
|
||||||
|
Duration? get autobackupPeriod => null;
|
||||||
|
|
||||||
|
AutobackupQuotas? get autobackupQuotas => null;
|
||||||
|
|
||||||
|
BackupsState copyWith({required final BackblazeBucket backblazeBucket});
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsInitial extends BackupsState {
|
||||||
|
BackupsInitial({
|
||||||
|
super.backblazeBucket,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
BackupsInitial copyWith({
|
||||||
|
final BackblazeBucket? backblazeBucket,
|
||||||
|
}) =>
|
||||||
|
BackupsInitial(backblazeBucket: backblazeBucket ?? this.backblazeBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsLoading extends BackupsState {
|
||||||
|
BackupsLoading({
|
||||||
|
super.backblazeBucket,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
@Deprecated('Infer the loading status from state')
|
||||||
|
bool get refreshing => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
BackupsLoading copyWith({
|
||||||
|
final BackblazeBucket? backblazeBucket,
|
||||||
|
}) =>
|
||||||
|
BackupsLoading(backblazeBucket: backblazeBucket ?? this.backblazeBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsUnititialized extends BackupsState {
|
||||||
|
BackupsUnititialized({
|
||||||
|
super.backblazeBucket,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
BackupsUnititialized copyWith({
|
||||||
|
final BackblazeBucket? backblazeBucket,
|
||||||
|
}) =>
|
||||||
|
BackupsUnititialized(
|
||||||
|
backblazeBucket: backblazeBucket ?? this.backblazeBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsInitializing extends BackupsState {
|
||||||
|
BackupsInitializing({
|
||||||
|
super.backblazeBucket,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
BackupsInitializing copyWith({
|
||||||
|
final BackblazeBucket? backblazeBucket,
|
||||||
|
}) =>
|
||||||
|
BackupsInitializing(
|
||||||
|
backblazeBucket: backblazeBucket ?? this.backblazeBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsInitialized extends BackupsState {
|
||||||
|
BackupsInitialized({
|
||||||
|
final List<Backup> backups = const [],
|
||||||
|
final BackupConfiguration? backupConfig,
|
||||||
|
super.backblazeBucket,
|
||||||
|
}) : _backupsHashCode = Object.hashAll(backups),
|
||||||
|
_backupConfigHashCode = Object.hashAll([backupConfig]);
|
||||||
|
|
||||||
|
final int _backupsHashCode;
|
||||||
|
final int _backupConfigHashCode;
|
||||||
|
|
||||||
|
List<Backup> get _backupList =>
|
||||||
|
apiConnectionRepository.apiData.backups.data ?? [];
|
||||||
|
|
||||||
|
BackupConfiguration? get _backupConfig =>
|
||||||
|
apiConnectionRepository.apiData.backupConfig.data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutobackupQuotas? get autobackupQuotas => _backupConfig?.autobackupQuotas;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Duration? get autobackupPeriod =>
|
||||||
|
_backupConfig?.autobackupPeriod?.inMinutes == 0
|
||||||
|
? null
|
||||||
|
: _backupConfig?.autobackupPeriod;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@Deprecated('Infer the initializations status from state')
|
||||||
|
bool get isInitialized => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@Deprecated('Infer the prevent actions status from state')
|
||||||
|
bool get preventActions => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Backup> get backups {
|
||||||
|
try {
|
||||||
|
final List<Backup> list = _backupList;
|
||||||
|
list.sort((final a, final b) => b.time.compareTo(a.time));
|
||||||
|
return list;
|
||||||
|
} on UnsupportedError {
|
||||||
|
return _backupList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Backup> serviceBackups(final String serviceId) => backups
|
||||||
|
.where((final backup) => backup.serviceId == serviceId)
|
||||||
|
.toList(growable: false);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [_backupsHashCode, _backupConfigHashCode];
|
||||||
|
|
||||||
|
@override
|
||||||
|
BackupsState copyWith({required final BackblazeBucket backblazeBucket}) =>
|
||||||
|
BackupsInitialized(
|
||||||
|
backups: backups,
|
||||||
|
backupConfig: _backupConfig,
|
||||||
|
backblazeBucket: backblazeBucket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackupsBusy extends BackupsInitialized {
|
||||||
|
BackupsBusy.fromState(final BackupsInitialized state)
|
||||||
|
: super(
|
||||||
|
backups: state.backups,
|
||||||
|
backupConfig: state._backupConfig,
|
||||||
|
backblazeBucket: state.backblazeBucket,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
@Deprecated('Infer the prevent actions status from state')
|
||||||
|
bool get preventActions => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ import 'dart:async';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
|
|
||||||
export 'package:provider/provider.dart';
|
export 'package:provider/provider.dart';
|
|
@ -1,278 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart';
|
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
|
||||||
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/backup.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/initialize_repository_input.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/service.dart';
|
|
||||||
|
|
||||||
part 'backups_state.dart';
|
|
||||||
|
|
||||||
class BackupsCubit extends ServerConnectionDependentCubit<BackupsState> {
|
|
||||||
BackupsCubit(final ServerInstallationCubit serverInstallationCubit)
|
|
||||||
: super(
|
|
||||||
const BackupsState(preventActions: true),
|
|
||||||
);
|
|
||||||
|
|
||||||
final ServerApi api = ServerApi();
|
|
||||||
final BackblazeApi backblaze = BackblazeApi();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> load() async {
|
|
||||||
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
|
||||||
final BackupConfiguration? backupConfig =
|
|
||||||
await api.getBackupsConfiguration();
|
|
||||||
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,
|
|
||||||
backups: backups,
|
|
||||||
preventActions: false,
|
|
||||||
refreshing: false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> initializeBackups() async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
final String? encryptionKey =
|
|
||||||
(await api.getBackupsConfiguration())?.encryptionKey;
|
|
||||||
if (encryptionKey == null) {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar("Couldn't get encryption key from your server.");
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final BackblazeBucket bucket;
|
|
||||||
|
|
||||||
if (state.backblazeBucket == null) {
|
|
||||||
final String domain = getIt<ApiConnectionRepository>()
|
|
||||||
.serverDomain!
|
|
||||||
.domainName
|
|
||||||
.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
|
||||||
final int serverId = getIt<ApiConnectionRepository>().serverDetails!.id;
|
|
||||||
String bucketName =
|
|
||||||
'${DateTime.now().millisecondsSinceEpoch}-$serverId-$domain';
|
|
||||||
if (bucketName.length > 49) {
|
|
||||||
bucketName = bucketName.substring(0, 49);
|
|
||||||
}
|
|
||||||
final String bucketId = await backblaze.createBucket(bucketName);
|
|
||||||
|
|
||||||
final BackblazeApplicationKey key = await backblaze.createKey(bucketId);
|
|
||||||
bucket = BackblazeBucket(
|
|
||||||
bucketId: bucketId,
|
|
||||||
bucketName: bucketName,
|
|
||||||
applicationKey: key.applicationKey,
|
|
||||||
applicationKeyId: key.applicationKeyId,
|
|
||||||
encryptionKey: encryptionKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
await getIt<ApiConfigModel>().storeBackblazeBucket(bucket);
|
|
||||||
emit(state.copyWith(backblazeBucket: bucket));
|
|
||||||
} else {
|
|
||||||
bucket = state.backblazeBucket!;
|
|
||||||
}
|
|
||||||
|
|
||||||
final GenericResult result = await api.initializeRepository(
|
|
||||||
InitializeRepositoryInput(
|
|
||||||
provider: BackupsProviderType.backblaze,
|
|
||||||
locationId: bucket.bucketId,
|
|
||||||
locationName: bucket.bucketName,
|
|
||||||
login: bucket.applicationKeyId,
|
|
||||||
password: bucket.applicationKey,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.success == false) {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar(result.message ?? 'Unknown error');
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await updateBackups();
|
|
||||||
getIt<NavigationService>().showSnackBar(
|
|
||||||
'Backups repository is now initializing. It may take a while.',
|
|
||||||
);
|
|
||||||
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> reuploadKey() async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
|
||||||
if (bucket == null) {
|
|
||||||
emit(state.copyWith(isInitialized: false));
|
|
||||||
} else {
|
|
||||||
String login = bucket.applicationKeyId;
|
|
||||||
String password = bucket.applicationKey;
|
|
||||||
if (login.isEmpty || password.isEmpty) {
|
|
||||||
final BackblazeApplicationKey key =
|
|
||||||
await backblaze.createKey(bucket.bucketId);
|
|
||||||
login = key.applicationKeyId;
|
|
||||||
password = key.applicationKey;
|
|
||||||
bucket = BackblazeBucket(
|
|
||||||
bucketId: bucket.bucketId,
|
|
||||||
bucketName: bucket.bucketName,
|
|
||||||
encryptionKey: bucket.encryptionKey,
|
|
||||||
applicationKey: password,
|
|
||||||
applicationKeyId: login,
|
|
||||||
);
|
|
||||||
await getIt<ApiConfigModel>().storeBackblazeBucket(bucket);
|
|
||||||
emit(state.copyWith(backblazeBucket: bucket));
|
|
||||||
}
|
|
||||||
final GenericResult result = await api.initializeRepository(
|
|
||||||
InitializeRepositoryInput(
|
|
||||||
provider: BackupsProviderType.backblaze,
|
|
||||||
locationId: bucket.bucketId,
|
|
||||||
locationName: bucket.bucketName,
|
|
||||||
login: login,
|
|
||||||
password: password,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.success == false) {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar(result.message ?? 'Unknown error');
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
getIt<NavigationService>().showSnackBar('backup.reuploaded_key'.tr());
|
|
||||||
await updateBackups();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("we don't have states")
|
|
||||||
Duration refreshTimeFromState() => const Duration(seconds: 60);
|
|
||||||
|
|
||||||
Future<void> updateBackups({final bool useTimer = false}) async {
|
|
||||||
emit(state.copyWith(refreshing: true));
|
|
||||||
final backups = await api.getBackups();
|
|
||||||
backups.sort((final a, final b) => b.time.compareTo(a.time));
|
|
||||||
final backupConfig = await api.getBackupsConfiguration();
|
|
||||||
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
backups: backups,
|
|
||||||
refreshTimer: refreshTimeFromState(),
|
|
||||||
refreshing: false,
|
|
||||||
isInitialized: backupConfig?.isInitialized ?? false,
|
|
||||||
autobackupPeriod: backupConfig?.autobackupPeriod,
|
|
||||||
autobackupQuotas: backupConfig?.autobackupQuotas,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (useTimer) {
|
|
||||||
Timer(state.refreshTimer, () => updateBackups(useTimer: true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> forceUpdateBackups() async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
getIt<NavigationService>().showSnackBar('backup.refetching_list'.tr());
|
|
||||||
await api.forceBackupListReload();
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> createMultipleBackups(final List<Service> services) async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
for (final service in services) {
|
|
||||||
await api.startBackup(service.id);
|
|
||||||
}
|
|
||||||
await updateBackups();
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> createBackup(final String serviceId) async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
await api.startBackup(serviceId);
|
|
||||||
await updateBackups();
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> restoreBackup(
|
|
||||||
final String backupId,
|
|
||||||
final BackupRestoreStrategy strategy,
|
|
||||||
) async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
await api.restoreBackup(backupId, strategy);
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setAutobackupPeriod(final Duration? period) async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
final result = await api.setAutobackupPeriod(period: period?.inMinutes);
|
|
||||||
if (result.success == false) {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar(result.message ?? 'Unknown error');
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
} else {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar('backup.autobackup_period_set'.tr());
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
preventActions: false,
|
|
||||||
autobackupPeriod: period ?? Duration.zero,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await updateBackups();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setAutobackupQuotas(final AutobackupQuotas quotas) async {
|
|
||||||
emit(state.copyWith(preventActions: true));
|
|
||||||
final result = await api.setAutobackupQuotas(quotas);
|
|
||||||
if (result.success == false) {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar(result.message ?? 'Unknown error');
|
|
||||||
emit(state.copyWith(preventActions: false));
|
|
||||||
} else {
|
|
||||||
getIt<NavigationService>().showSnackBar('backup.quotas_set'.tr());
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
preventActions: false,
|
|
||||||
autobackupQuotas: quotas,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await updateBackups();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> forgetSnapshot(final String snapshotId) async {
|
|
||||||
final result = await api.forgetSnapshot(snapshotId);
|
|
||||||
if (!result.success) {
|
|
||||||
getIt<NavigationService>().showSnackBar('jobs.generic_error'.tr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.data == false) {
|
|
||||||
getIt<NavigationService>()
|
|
||||||
.showSnackBar('backup.forget_snapshot_error'.tr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimistic update
|
|
||||||
final backups = state.backups;
|
|
||||||
final index =
|
|
||||||
backups.indexWhere((final snapshot) => snapshot.id == snapshotId);
|
|
||||||
if (index != -1) {
|
|
||||||
backups.removeAt(index);
|
|
||||||
emit(state.copyWith(backups: backups));
|
|
||||||
}
|
|
||||||
|
|
||||||
await updateBackups();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void clear() async {
|
|
||||||
emit(const BackupsState());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
part of 'backups_cubit.dart';
|
|
||||||
|
|
||||||
class BackupsState extends ServerInstallationDependendState {
|
|
||||||
const BackupsState({
|
|
||||||
this.isInitialized = false,
|
|
||||||
this.backups = const [],
|
|
||||||
this.preventActions = true,
|
|
||||||
this.refreshTimer = const Duration(seconds: 60),
|
|
||||||
this.refreshing = true,
|
|
||||||
this.autobackupPeriod,
|
|
||||||
this.backblazeBucket,
|
|
||||||
this.autobackupQuotas,
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
List<Backup> serviceBackups(final String serviceId) => backups
|
|
||||||
.where((final backup) => backup.serviceId == serviceId)
|
|
||||||
.toList(growable: false);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [
|
|
||||||
isInitialized,
|
|
||||||
backups,
|
|
||||||
preventActions,
|
|
||||||
refreshTimer,
|
|
||||||
refreshing,
|
|
||||||
];
|
|
||||||
|
|
||||||
BackupsState copyWith({
|
|
||||||
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,
|
|
||||||
}) =>
|
|
||||||
BackupsState(
|
|
||||||
isInitialized: isInitialized ?? this.isInitialized,
|
|
||||||
backups: backups ?? this.backups,
|
|
||||||
preventActions: preventActions ?? this.preventActions,
|
|
||||||
refreshTimer: refreshTimer ?? this.refreshTimer,
|
|
||||||
refreshing: refreshing ?? this.refreshing,
|
|
||||||
// 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,
|
|
||||||
backblazeBucket: backblazeBucket ?? this.backblazeBucket,
|
|
||||||
autobackupQuotas: autobackupQuotas ?? this.autobackupQuotas,
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
|
|
||||||
part 'connection_status_event.dart';
|
part 'connection_status_event.dart';
|
||||||
part 'connection_status_state.dart';
|
part 'connection_status_state.dart';
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:cubit_form/cubit_form.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
|
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
|
|
||||||
export 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
export 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart';
|
import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/tls_options.dart';
|
import 'package:selfprivacy/logic/api_maps/tls_options.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/disk_size.dart';
|
import 'package:selfprivacy/logic/models/disk_size.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
||||||
|
@ -234,7 +233,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
try {
|
try {
|
||||||
bucket = await BackblazeApi()
|
bucket = await BackblazeApi()
|
||||||
.fetchBucket(backblazeCredential, configuration);
|
.fetchBucket(backblazeCredential, configuration);
|
||||||
await getIt<ApiConfigModel>().storeBackblazeBucket(bucket!);
|
await getIt<ApiConfigModel>().setBackblazeBucket(bucket!);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,7 +470,7 @@ class ServerInstallationRepository {
|
||||||
Future<void> saveServerDetails(
|
Future<void> saveServerDetails(
|
||||||
final ServerHostingDetails serverDetails,
|
final ServerHostingDetails serverDetails,
|
||||||
) async {
|
) async {
|
||||||
await getIt<ApiConfigModel>().storeServerDetails(serverDetails);
|
await getIt<ApiConfigModel>().setServerDetails(serverDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteServerDetails() async {
|
Future<void> deleteServerDetails() async {
|
||||||
|
@ -483,18 +483,18 @@ class ServerInstallationRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveDnsProviderType(final DnsProviderType type) async {
|
Future<void> saveDnsProviderType(final DnsProviderType type) async {
|
||||||
await getIt<ApiConfigModel>().storeDnsProviderType(type);
|
await getIt<ApiConfigModel>().setDnsProviderType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveServerProviderKey(final String key) async {
|
Future<void> saveServerProviderKey(final String key) async {
|
||||||
await getIt<ApiConfigModel>().storeServerProviderKey(key);
|
await getIt<ApiConfigModel>().setServerProviderKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveServerType(final ServerType serverType) async {
|
Future<void> saveServerType(final ServerType serverType) async {
|
||||||
await getIt<ApiConfigModel>().storeServerTypeIdentifier(
|
await getIt<ApiConfigModel>().setServerTypeIdentifier(
|
||||||
serverType.identifier,
|
serverType.identifier,
|
||||||
);
|
);
|
||||||
await getIt<ApiConfigModel>().storeServerLocation(
|
await getIt<ApiConfigModel>().setServerLocation(
|
||||||
serverType.location.identifier,
|
serverType.location.identifier,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ class ServerInstallationRepository {
|
||||||
Future<void> saveBackblazeKey(
|
Future<void> saveBackblazeKey(
|
||||||
final BackupsCredential backblazeCredential,
|
final BackupsCredential backblazeCredential,
|
||||||
) async {
|
) async {
|
||||||
await getIt<ApiConfigModel>().storeBackblazeCredential(backblazeCredential);
|
await getIt<ApiConfigModel>().setBackblazeCredential(backblazeCredential);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteBackblazeKey() async {
|
Future<void> deleteBackblazeKey() async {
|
||||||
|
@ -516,7 +516,7 @@ class ServerInstallationRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setDnsApiToken(final String key) async {
|
Future<void> setDnsApiToken(final String key) async {
|
||||||
await getIt<ApiConfigModel>().storeDnsProviderKey(key);
|
await getIt<ApiConfigModel>().setDnsProviderKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteDnsProviderKey() async {
|
Future<void> deleteDnsProviderKey() async {
|
||||||
|
@ -525,7 +525,7 @@ class ServerInstallationRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveDomain(final ServerDomain serverDomain) async {
|
Future<void> saveDomain(final ServerDomain serverDomain) async {
|
||||||
await getIt<ApiConfigModel>().storeServerDomain(serverDomain);
|
await getIt<ApiConfigModel>().setServerDomain(serverDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteDomain() async {
|
Future<void> deleteDomain() async {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/config/hive_config.dart';
|
import 'package:selfprivacy/config/hive_config.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
|
|
||||||
export 'package:provider/provider.dart';
|
export 'package:provider/provider.dart';
|
||||||
|
|
|
@ -42,47 +42,47 @@ class ApiConfigModel {
|
||||||
_serverProvider = value;
|
_serverProvider = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeDnsProviderType(final DnsProviderType value) async {
|
Future<void> setDnsProviderType(final DnsProviderType value) async {
|
||||||
await _box.put(BNames.dnsProvider, value);
|
await _box.put(BNames.dnsProvider, value);
|
||||||
_dnsProvider = value;
|
_dnsProvider = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeServerProviderKey(final String value) async {
|
Future<void> setServerProviderKey(final String value) async {
|
||||||
await _box.put(BNames.hetznerKey, value);
|
await _box.put(BNames.hetznerKey, value);
|
||||||
_serverProviderKey = value;
|
_serverProviderKey = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeDnsProviderKey(final String value) async {
|
Future<void> setDnsProviderKey(final String value) async {
|
||||||
await _box.put(BNames.cloudFlareKey, value);
|
await _box.put(BNames.cloudFlareKey, value);
|
||||||
_dnsProviderKey = value;
|
_dnsProviderKey = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeServerTypeIdentifier(final String typeIdentifier) async {
|
Future<void> setServerTypeIdentifier(final String typeIdentifier) async {
|
||||||
await _box.put(BNames.serverTypeIdentifier, typeIdentifier);
|
await _box.put(BNames.serverTypeIdentifier, typeIdentifier);
|
||||||
_serverType = typeIdentifier;
|
_serverType = typeIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeServerLocation(final String serverLocation) async {
|
Future<void> setServerLocation(final String serverLocation) async {
|
||||||
await _box.put(BNames.serverLocation, serverLocation);
|
await _box.put(BNames.serverLocation, serverLocation);
|
||||||
_serverLocation = serverLocation;
|
_serverLocation = serverLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeBackblazeCredential(final BackupsCredential value) async {
|
Future<void> setBackblazeCredential(final BackupsCredential value) async {
|
||||||
await _box.put(BNames.backblazeCredential, value);
|
await _box.put(BNames.backblazeCredential, value);
|
||||||
_backblazeCredential = value;
|
_backblazeCredential = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeServerDomain(final ServerDomain value) async {
|
Future<void> setServerDomain(final ServerDomain value) async {
|
||||||
await _box.put(BNames.serverDomain, value);
|
await _box.put(BNames.serverDomain, value);
|
||||||
_serverDomain = value;
|
_serverDomain = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeServerDetails(final ServerHostingDetails value) async {
|
Future<void> setServerDetails(final ServerHostingDetails value) async {
|
||||||
await _box.put(BNames.serverDetails, value);
|
await _box.put(BNames.serverDetails, value);
|
||||||
_serverDetails = value;
|
_serverDetails = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeBackblazeBucket(final BackblazeBucket value) async {
|
Future<void> setBackblazeBucket(final BackblazeBucket value) async {
|
||||||
await _box.put(BNames.backblazeBucket, value);
|
await _box.put(BNames.backblazeBucket, value);
|
||||||
_backblazeBucket = value;
|
_backblazeBucket = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:pub_semver/pub_semver.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/config/hive_config.dart';
|
import 'package:selfprivacy/config/hive_config.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.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/server_details.dart';
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
|
@ -15,7 +16,7 @@ class ApiConnectionRepository {
|
||||||
Box box = Hive.box(BNames.serverInstallationBox);
|
Box box = Hive.box(BNames.serverInstallationBox);
|
||||||
final ServerApi api = ServerApi();
|
final ServerApi api = ServerApi();
|
||||||
|
|
||||||
final ApiData _apiData = ApiData();
|
final ApiData _apiData = ApiData(ServerApi());
|
||||||
|
|
||||||
ApiData get apiData => _apiData;
|
ApiData get apiData => _apiData;
|
||||||
|
|
||||||
|
@ -66,15 +67,18 @@ class ApiConnectionRepository {
|
||||||
_connectionStatusStream.add(connectionStatus);
|
_connectionStatusStream.add(connectionStatus);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
connectionStatus = ConnectionStatus.connected;
|
|
||||||
_connectionStatusStream.add(connectionStatus);
|
|
||||||
_apiData.apiVersion.data = apiVersion;
|
_apiData.apiVersion.data = apiVersion;
|
||||||
_dataStream.add(_apiData);
|
_dataStream.add(_apiData);
|
||||||
}
|
}
|
||||||
|
|
||||||
_apiData.serverJobs.data = await api.getServerJobs();
|
_apiData.serverJobs.data = await api.getServerJobs();
|
||||||
|
_apiData.backupConfig.data = await api.getBackupsConfiguration();
|
||||||
|
_apiData.backups.data = await api.getBackups();
|
||||||
_dataStream.add(_apiData);
|
_dataStream.add(_apiData);
|
||||||
|
|
||||||
|
connectionStatus = ConnectionStatus.connected;
|
||||||
|
_connectionStatusStream.add(connectionStatus);
|
||||||
|
|
||||||
// Use timer to periodically check for new jobs
|
// Use timer to periodically check for new jobs
|
||||||
_timer = Timer.periodic(
|
_timer = Timer.periodic(
|
||||||
const Duration(seconds: 10),
|
const Duration(seconds: 10),
|
||||||
|
@ -82,7 +86,7 @@ class ApiConnectionRepository {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reload(final Timer timer) async {
|
Future<void> reload(final Timer? timer) async {
|
||||||
final serverDetails = getIt<ApiConfigModel>().serverDetails;
|
final serverDetails = getIt<ApiConfigModel>().serverDetails;
|
||||||
if (serverDetails == null) {
|
if (serverDetails == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -98,26 +102,42 @@ class ApiConnectionRepository {
|
||||||
_connectionStatusStream.add(connectionStatus);
|
_connectionStatusStream.add(connectionStatus);
|
||||||
_apiData.apiVersion.data = apiVersion;
|
_apiData.apiVersion.data = apiVersion;
|
||||||
}
|
}
|
||||||
|
final Version version = Version.parse(apiVersion);
|
||||||
|
await _apiData.serverJobs
|
||||||
|
.refetchData(version, () => _dataStream.add(_apiData));
|
||||||
|
await _apiData.backups
|
||||||
|
.refetchData(version, () => _dataStream.add(_apiData));
|
||||||
|
await _apiData.backupConfig
|
||||||
|
.refetchData(version, () => _dataStream.add(_apiData));
|
||||||
|
}
|
||||||
|
|
||||||
if (VersionConstraint.parse(_apiData.apiVersion.requiredApiVersion)
|
void emitData() {
|
||||||
.allows(Version.parse(apiVersion))) {
|
|
||||||
final jobs = await api.getServerJobs();
|
|
||||||
if (Object.hashAll(_apiData.serverJobs.data ?? []) !=
|
|
||||||
Object.hashAll(jobs)) {
|
|
||||||
_apiData.serverJobs.data = [...jobs];
|
|
||||||
_dataStream.add(_apiData);
|
_dataStream.add(_apiData);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApiData {
|
class ApiData {
|
||||||
ApiData()
|
ApiData(final ServerApi api)
|
||||||
: serverJobs = ApiDataElement<List<ServerJob>>(null),
|
: apiVersion = ApiDataElement<String>(
|
||||||
apiVersion = ApiDataElement<String>(null);
|
fetchData: () async => api.getApiVersion(),
|
||||||
|
),
|
||||||
|
serverJobs = ApiDataElement<List<ServerJob>>(
|
||||||
|
fetchData: () async => api.getServerJobs(),
|
||||||
|
ttl: 10,
|
||||||
|
),
|
||||||
|
backupConfig = ApiDataElement<BackupConfiguration>(
|
||||||
|
fetchData: () async => api.getBackupsConfiguration(),
|
||||||
|
requiredApiVersion: '>=2.4.2',
|
||||||
|
),
|
||||||
|
backups = ApiDataElement<List<Backup>>(
|
||||||
|
fetchData: () async => api.getBackups(),
|
||||||
|
requiredApiVersion: '>=2.4.2',
|
||||||
|
);
|
||||||
|
|
||||||
ApiDataElement<List<ServerJob>> serverJobs;
|
ApiDataElement<List<ServerJob>> serverJobs;
|
||||||
ApiDataElement<String> apiVersion;
|
ApiDataElement<String> apiVersion;
|
||||||
|
ApiDataElement<BackupConfiguration> backupConfig;
|
||||||
|
ApiDataElement<List<Backup>> backups;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ConnectionStatus {
|
enum ConnectionStatus {
|
||||||
|
@ -129,8 +149,9 @@ enum ConnectionStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApiDataElement<T> {
|
class ApiDataElement<T> {
|
||||||
ApiDataElement(
|
ApiDataElement({
|
||||||
final T? data, {
|
required this.fetchData,
|
||||||
|
final T? data,
|
||||||
this.requiredApiVersion = '>=2.3.0',
|
this.requiredApiVersion = '>=2.3.0',
|
||||||
this.ttl = 60,
|
this.ttl = 60,
|
||||||
}) : _data = data,
|
}) : _data = data,
|
||||||
|
@ -139,9 +160,40 @@ class ApiDataElement<T> {
|
||||||
T? _data;
|
T? _data;
|
||||||
final String requiredApiVersion;
|
final String requiredApiVersion;
|
||||||
|
|
||||||
|
final Future<T?> Function() fetchData;
|
||||||
|
|
||||||
|
Future<void> refetchData(
|
||||||
|
final Version version, final Function callback) async {
|
||||||
|
if (VersionConstraint.parse(requiredApiVersion).allows(version)) {
|
||||||
|
print('Fetching data for $runtimeType');
|
||||||
|
if (isExpired) {
|
||||||
|
print('Data is expired');
|
||||||
|
final newData = await fetchData();
|
||||||
|
print(newData);
|
||||||
|
if (T is List) {
|
||||||
|
if (Object.hashAll(newData as Iterable<Object?>) !=
|
||||||
|
Object.hashAll(_data as Iterable<Object?>)) {
|
||||||
|
_data = [...newData] as T?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (newData.hashCode != _data.hashCode) {
|
||||||
|
_data = newData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// TTL of the data in seconds
|
/// TTL of the data in seconds
|
||||||
final int ttl;
|
final int ttl;
|
||||||
|
|
||||||
|
Type get type => T;
|
||||||
|
|
||||||
|
void invalidate() {
|
||||||
|
_lastUpdated = DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
|
}
|
||||||
|
|
||||||
/// Timestamp of when the data was last updated
|
/// Timestamp of when the data was last updated
|
||||||
DateTime _lastUpdated;
|
DateTime _lastUpdated;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/backups.graphql.dart';
|
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/backups.graphql.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart';
|
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart';
|
||||||
|
@ -40,7 +41,7 @@ extension BackupReasonExtension on Enum$BackupReason {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class BackupConfiguration {
|
class BackupConfiguration extends Equatable {
|
||||||
BackupConfiguration.fromGraphQL(
|
BackupConfiguration.fromGraphQL(
|
||||||
final Query$BackupConfiguration$backup$configuration configuration,
|
final Query$BackupConfiguration$backup$configuration configuration,
|
||||||
) : this(
|
) : this(
|
||||||
|
@ -58,7 +59,7 @@ class BackupConfiguration {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
BackupConfiguration({
|
const BackupConfiguration({
|
||||||
required this.autobackupPeriod,
|
required this.autobackupPeriod,
|
||||||
required this.encryptionKey,
|
required this.encryptionKey,
|
||||||
required this.isInitialized,
|
required this.isInitialized,
|
||||||
|
@ -75,9 +76,39 @@ class BackupConfiguration {
|
||||||
final String? locationName;
|
final String? locationName;
|
||||||
final BackupsProviderType provider;
|
final BackupsProviderType provider;
|
||||||
final AutobackupQuotas autobackupQuotas;
|
final AutobackupQuotas autobackupQuotas;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
autobackupPeriod,
|
||||||
|
encryptionKey,
|
||||||
|
isInitialized,
|
||||||
|
locationId,
|
||||||
|
locationName,
|
||||||
|
provider,
|
||||||
|
autobackupQuotas,
|
||||||
|
];
|
||||||
|
|
||||||
|
BackupConfiguration copyWith({
|
||||||
|
final Duration? autobackupPeriod,
|
||||||
|
final String? encryptionKey,
|
||||||
|
final bool? isInitialized,
|
||||||
|
final String? locationId,
|
||||||
|
final String? locationName,
|
||||||
|
final BackupsProviderType? provider,
|
||||||
|
final AutobackupQuotas? autobackupQuotas,
|
||||||
|
}) =>
|
||||||
|
BackupConfiguration(
|
||||||
|
autobackupPeriod: autobackupPeriod ?? this.autobackupPeriod,
|
||||||
|
encryptionKey: encryptionKey ?? this.encryptionKey,
|
||||||
|
isInitialized: isInitialized ?? this.isInitialized,
|
||||||
|
locationId: locationId ?? this.locationId,
|
||||||
|
locationName: locationName ?? this.locationName,
|
||||||
|
provider: provider ?? this.provider,
|
||||||
|
autobackupQuotas: autobackupQuotas ?? this.autobackupQuotas,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutobackupQuotas {
|
class AutobackupQuotas extends Equatable {
|
||||||
AutobackupQuotas.fromGraphQL(
|
AutobackupQuotas.fromGraphQL(
|
||||||
final Query$BackupConfiguration$backup$configuration$autobackupQuotas
|
final Query$BackupConfiguration$backup$configuration$autobackupQuotas
|
||||||
autobackupQuotas,
|
autobackupQuotas,
|
||||||
|
@ -89,7 +120,7 @@ class AutobackupQuotas {
|
||||||
yearly: autobackupQuotas.yearly,
|
yearly: autobackupQuotas.yearly,
|
||||||
);
|
);
|
||||||
|
|
||||||
AutobackupQuotas({
|
const AutobackupQuotas({
|
||||||
required this.last,
|
required this.last,
|
||||||
required this.daily,
|
required this.daily,
|
||||||
required this.weekly,
|
required this.weekly,
|
||||||
|
@ -117,6 +148,15 @@ class AutobackupQuotas {
|
||||||
monthly: monthly ?? this.monthly,
|
monthly: monthly ?? this.monthly,
|
||||||
yearly: yearly ?? this.yearly,
|
yearly: yearly ?? this.yearly,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
last,
|
||||||
|
daily,
|
||||||
|
weekly,
|
||||||
|
monthly,
|
||||||
|
yearly,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BackupRestoreStrategy {
|
enum BackupRestoreStrategy {
|
||||||
|
|
|
@ -29,4 +29,19 @@ class BackblazeBucket {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => bucketName;
|
String toString() => bucketName;
|
||||||
|
|
||||||
|
BackblazeBucket copyWith({
|
||||||
|
final String? bucketId,
|
||||||
|
final String? applicationKeyId,
|
||||||
|
final String? applicationKey,
|
||||||
|
final String? bucketName,
|
||||||
|
final String? encryptionKey,
|
||||||
|
}) =>
|
||||||
|
BackblazeBucket(
|
||||||
|
bucketId: bucketId ?? this.bucketId,
|
||||||
|
applicationKeyId: applicationKeyId ?? this.applicationKeyId,
|
||||||
|
applicationKey: applicationKey ?? this.applicationKey,
|
||||||
|
bucketName: bucketName ?? this.bucketName,
|
||||||
|
encryptionKey: encryptionKey ?? this.encryptionKey,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart';
|
import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart';
|
||||||
|
|
|
@ -2,9 +2,9 @@ import 'package:auto_route/auto_route.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';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.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/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
|
||||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/backup.dart';
|
import 'package:selfprivacy/logic/models/backup.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
|
@ -31,14 +31,13 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
Widget build(final BuildContext context) {
|
Widget build(final BuildContext context) {
|
||||||
final bool isReady = context.watch<ServerInstallationCubit>().state
|
final bool isReady = context.watch<ServerInstallationCubit>().state
|
||||||
is ServerInstallationFinished;
|
is ServerInstallationFinished;
|
||||||
final BackupsState backupsState = context.watch<BackupsCubit>().state;
|
final BackupsState backupsState = context.watch<BackupsBloc>().state;
|
||||||
final bool isBackupInitialized = backupsState.isInitialized;
|
final bool isBackupInitialized = backupsState.isInitialized;
|
||||||
final StateType providerState = isReady && isBackupInitialized
|
final StateType providerState = isReady && isBackupInitialized
|
||||||
? StateType.stable
|
? StateType.stable
|
||||||
: StateType.uninitialized;
|
: StateType.uninitialized;
|
||||||
final bool preventActions = backupsState.preventActions;
|
final bool preventActions = backupsState.preventActions;
|
||||||
final List<Backup> backups = backupsState.backups;
|
final List<Backup> backups = backupsState.backups;
|
||||||
final bool refreshing = backupsState.refreshing;
|
|
||||||
final List<Service> services =
|
final List<Service> services =
|
||||||
context.watch<ServicesCubit>().state.servicesThatCanBeBackedUp;
|
context.watch<ServicesCubit>().state.servicesThatCanBeBackedUp;
|
||||||
final Duration? autobackupPeriod = backupsState.autobackupPeriod;
|
final Duration? autobackupPeriod = backupsState.autobackupPeriod;
|
||||||
|
@ -75,8 +74,10 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: preventActions
|
onPressed: preventActions
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () {
|
||||||
await context.read<BackupsCubit>().initializeBackups();
|
context
|
||||||
|
.read<BackupsBloc>()
|
||||||
|
.add(const InitializeBackupsRepository());
|
||||||
},
|
},
|
||||||
text: 'backup.initialize'.tr(),
|
text: 'backup.initialize'.tr(),
|
||||||
),
|
),
|
||||||
|
@ -335,9 +336,11 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
actionButtonTitle:
|
actionButtonTitle:
|
||||||
'backup.forget_snapshot'.tr(),
|
'backup.forget_snapshot'.tr(),
|
||||||
actionButtonOnPressed: () => {
|
actionButtonOnPressed: () => {
|
||||||
context.read<BackupsCubit>().forgetSnapshot(
|
context.read<BackupsBloc>().add(
|
||||||
|
ForgetSnapshot(
|
||||||
backup.id,
|
backup.id,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -391,18 +394,6 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 8),
|
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)
|
if (providerState != StateType.uninitialized)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -425,7 +416,11 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
onTap: preventActions
|
onTap: preventActions
|
||||||
? null
|
? null
|
||||||
: () => {context.read<BackupsCubit>().forceUpdateBackups()},
|
: () => {
|
||||||
|
context
|
||||||
|
.read<BackupsBloc>()
|
||||||
|
.add(const ForceSnapshotListUpdate())
|
||||||
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
@ -447,9 +442,9 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
Icons.warning_amber_outlined,
|
Icons.warning_amber_outlined,
|
||||||
color: overrideColor,
|
color: overrideColor,
|
||||||
),
|
),
|
||||||
onTap: preventActions
|
// onTap: preventActions
|
||||||
? null
|
// ? null
|
||||||
: () => {context.read<BackupsCubit>().reuploadKey()},
|
// : () => {context.read<BackupsCubit>().reuploadKey()},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/backup.dart';
|
import 'package:selfprivacy/logic/models/backup.dart';
|
||||||
import 'package:selfprivacy/logic/models/service.dart';
|
import 'package:selfprivacy/logic/models/service.dart';
|
||||||
|
@ -25,10 +25,10 @@ class BackupsListPage extends StatelessWidget {
|
||||||
// If the service is null, get all backups from state. If not null, call the
|
// If the service is null, get all backups from state. If not null, call the
|
||||||
// serviceBackups(serviceId) on the backups state.
|
// serviceBackups(serviceId) on the backups state.
|
||||||
final List<Backup> backups = service == null
|
final List<Backup> backups = service == null
|
||||||
? context.watch<BackupsCubit>().state.backups
|
? context.watch<BackupsBloc>().state.backups
|
||||||
: context.watch<BackupsCubit>().state.serviceBackups(service!.id);
|
: context.watch<BackupsBloc>().state.serviceBackups(service!.id);
|
||||||
final bool preventActions =
|
final bool preventActions =
|
||||||
context.watch<BackupsCubit>().state.preventActions;
|
context.watch<BackupsBloc>().state.preventActions;
|
||||||
return BrandHeroScreen(
|
return BrandHeroScreen(
|
||||||
heroTitle: 'backup.snapshots_title'.tr(),
|
heroTitle: 'backup.snapshots_title'.tr(),
|
||||||
hasFlashButton: true,
|
hasFlashButton: true,
|
||||||
|
@ -76,9 +76,9 @@ class BackupsListPage extends StatelessWidget {
|
||||||
description: 'backup.forget_snapshot_alert'.tr(),
|
description: 'backup.forget_snapshot_alert'.tr(),
|
||||||
actionButtonTitle: 'backup.forget_snapshot'.tr(),
|
actionButtonTitle: 'backup.forget_snapshot'.tr(),
|
||||||
actionButtonOnPressed: () => {
|
actionButtonOnPressed: () => {
|
||||||
context.read<BackupsCubit>().forgetSnapshot(
|
context
|
||||||
backup.id,
|
.read<BackupsBloc>()
|
||||||
),
|
.add(ForgetSnapshot(backup.id)),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.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/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
|
||||||
import 'package:selfprivacy/utils/extensions/duration.dart';
|
import 'package:selfprivacy/utils/extensions/duration.dart';
|
||||||
|
|
||||||
class ChangeAutobackupsPeriodModal extends StatefulWidget {
|
class ChangeAutobackupsPeriodModal extends StatefulWidget {
|
||||||
|
@ -34,13 +34,13 @@ class _ChangeAutobackupsPeriodModalState
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
selectedPeriod = context.read<BackupsCubit>().state.autobackupPeriod;
|
selectedPeriod = context.read<BackupsBloc>().state.autobackupPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) {
|
Widget build(final BuildContext context) {
|
||||||
final Duration? initialAutobackupPeriod =
|
final Duration? initialAutobackupPeriod =
|
||||||
context.watch<BackupsCubit>().state.autobackupPeriod;
|
context.watch<BackupsBloc>().state.autobackupPeriod;
|
||||||
return ListView(
|
return ListView(
|
||||||
controller: widget.scrollController,
|
controller: widget.scrollController,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
@ -91,8 +91,8 @@ class _ChangeAutobackupsPeriodModalState
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
context
|
context
|
||||||
.read<BackupsCubit>()
|
.read<BackupsBloc>()
|
||||||
.setAutobackupPeriod(selectedPeriod);
|
.add(SetAutobackupPeriod(selectedPeriod));
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.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/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/backup.dart';
|
import 'package:selfprivacy/logic/models/backup.dart';
|
||||||
|
|
||||||
class ChangeRotationQuotasModal extends StatefulWidget {
|
class ChangeRotationQuotasModal extends StatefulWidget {
|
||||||
|
@ -27,7 +27,7 @@ enum QuotaUnits {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChangeRotationQuotasModalState extends State<ChangeRotationQuotasModal> {
|
class _ChangeRotationQuotasModalState extends State<ChangeRotationQuotasModal> {
|
||||||
AutobackupQuotas selectedQuotas = AutobackupQuotas(
|
AutobackupQuotas selectedQuotas = const AutobackupQuotas(
|
||||||
last: 3,
|
last: 3,
|
||||||
daily: 7,
|
daily: 7,
|
||||||
weekly: 4,
|
weekly: 4,
|
||||||
|
@ -40,7 +40,7 @@ class _ChangeRotationQuotasModalState extends State<ChangeRotationQuotasModal> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
selectedQuotas =
|
selectedQuotas =
|
||||||
context.read<BackupsCubit>().state.autobackupQuotas ?? selectedQuotas;
|
context.read<BackupsBloc>().state.autobackupQuotas ?? selectedQuotas;
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateSubtitle(final int value, final QuotaUnits unit) {
|
String generateSubtitle(final int value, final QuotaUnits unit) {
|
||||||
|
@ -83,7 +83,7 @@ class _ChangeRotationQuotasModalState extends State<ChangeRotationQuotasModal> {
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) {
|
Widget build(final BuildContext context) {
|
||||||
final AutobackupQuotas? initialAutobackupQuotas =
|
final AutobackupQuotas? initialAutobackupQuotas =
|
||||||
context.watch<BackupsCubit>().state.autobackupQuotas;
|
context.watch<BackupsBloc>().state.autobackupQuotas;
|
||||||
return ListView(
|
return ListView(
|
||||||
controller: widget.scrollController,
|
controller: widget.scrollController,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
@ -190,8 +190,8 @@ class _ChangeRotationQuotasModalState extends State<ChangeRotationQuotasModal> {
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
context
|
context
|
||||||
.read<BackupsCubit>()
|
.read<BackupsBloc>()
|
||||||
.setAutobackupQuotas(selectedQuotas);
|
.add(SetAutobackupQuotas(selectedQuotas));
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -2,9 +2,9 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.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/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
|
||||||
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
|
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
|
||||||
import 'package:selfprivacy/utils/platform_adapter.dart';
|
import 'package:selfprivacy/utils/platform_adapter.dart';
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class _CopyEncryptionKeyModalState extends State<CopyEncryptionKeyModal> {
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) {
|
Widget build(final BuildContext context) {
|
||||||
final String? encryptionKey =
|
final String? encryptionKey =
|
||||||
context.watch<BackupsCubit>().state.backblazeBucket?.encryptionKey;
|
context.watch<BackupsBloc>().state.backblazeBucket?.encryptionKey;
|
||||||
if (encryptionKey == null) {
|
if (encryptionKey == null) {
|
||||||
return ListView(
|
return ListView(
|
||||||
controller: widget.scrollController,
|
controller: widget.scrollController,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
import 'package:selfprivacy/logic/models/service.dart';
|
import 'package:selfprivacy/logic/models/service.dart';
|
||||||
|
|
||||||
|
@ -147,8 +147,8 @@ class _CreateBackupsModalState extends State<CreateBackupsModal> {
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
context
|
context
|
||||||
.read<BackupsCubit>()
|
.read<BackupsBloc>()
|
||||||
.createMultipleBackups(selectedServices);
|
.add(CreateBackups(selectedServices));
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/backup.dart';
|
import 'package:selfprivacy/logic/models/backup.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
|
@ -153,10 +153,8 @@ class _SnapshotModalState extends State<SnapshotModal> {
|
||||||
onPressed: isServiceBusy
|
onPressed: isServiceBusy
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
context.read<BackupsCubit>().restoreBackup(
|
context.read<BackupsBloc>().add(RestoreBackup(
|
||||||
widget.snapshot.id,
|
widget.snapshot.id, selectedStrategy));
|
||||||
selectedStrategy,
|
|
||||||
);
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
getIt<NavigationService>()
|
getIt<NavigationService>()
|
||||||
.showSnackBar('backup.restore_started'.tr());
|
.showSnackBar('backup.restore_started'.tr());
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'package:selfprivacy/logic/api_maps/tls_options.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/devices/devices_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/recovery_key/recovery_key_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/get_it/api_connection_repository.dart';
|
|
||||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.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';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
|
||||||
|
@ -30,7 +30,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
|
||||||
final bool isReady = context.watch<ServerInstallationCubit>().state
|
final bool isReady = context.watch<ServerInstallationCubit>().state
|
||||||
is ServerInstallationFinished;
|
is ServerInstallationFinished;
|
||||||
final bool isBackupInitialized =
|
final bool isBackupInitialized =
|
||||||
context.watch<BackupsCubit>().state.isInitialized;
|
context.watch<BackupsBloc>().state.isInitialized;
|
||||||
final DnsRecordsStatus dnsStatus =
|
final DnsRecordsStatus dnsStatus =
|
||||||
context.watch<DnsRecordsCubit>().state.dnsState;
|
context.watch<DnsRecordsCubit>().state.dnsState;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.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';
|
||||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/disk_size.dart';
|
import 'package:selfprivacy/logic/models/disk_size.dart';
|
||||||
import 'package:selfprivacy/logic/models/service.dart';
|
import 'package:selfprivacy/logic/models/service.dart';
|
||||||
|
|
Loading…
Reference in New Issue