diff --git a/lib/config/bloc_config.dart b/lib/config/bloc_config.dart index b7d87f2e..ff7a8236 100644 --- a/lib/config/bloc_config.dart +++ b/lib/config/bloc_config.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart'; +import 'package:selfprivacy/logic/bloc/services/services_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/recovery_key/recovery_key_cubit.dart'; @@ -11,7 +12,6 @@ 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/bloc/server_jobs/server_jobs_bloc.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/support_system/support_system_cubit.dart'; import 'package:selfprivacy/logic/cubit/users/users_cubit.dart'; import 'package:selfprivacy/logic/cubit/provider_volumes/provider_volume_cubit.dart'; @@ -28,7 +28,7 @@ class BlocAndProviderConfig extends StatelessWidget { final serverInstallationCubit = ServerInstallationCubit()..load(); final supportSystemCubit = SupportSystemCubit(); final usersCubit = UsersCubit(serverInstallationCubit); - final servicesCubit = ServicesCubit(serverInstallationCubit); + final servicesBloc = ServicesBloc(); final backupsBloc = BackupsBloc(); final dnsRecordsCubit = DnsRecordsCubit(serverInstallationCubit); final recoveryKeyCubit = RecoveryKeyCubit(serverInstallationCubit); @@ -61,8 +61,7 @@ class BlocAndProviderConfig extends StatelessWidget { lazy: false, ), BlocProvider( - create: (final _) => servicesCubit..load(), - lazy: false, + create: (final _) => servicesBloc, ), BlocProvider( create: (final _) => backupsBloc, @@ -92,7 +91,7 @@ class BlocAndProviderConfig extends StatelessWidget { BlocProvider( create: (final _) => JobsCubit( usersCubit: usersCubit, - servicesCubit: servicesCubit, + servicesBloc: servicesBloc, ), ), ], diff --git a/lib/logic/bloc/backups/backups_bloc.dart b/lib/logic/bloc/backups/backups_bloc.dart index 55d4753a..fcdedfeb 100644 --- a/lib/logic/bloc/backups/backups_bloc.dart +++ b/lib/logic/bloc/backups/backups_bloc.dart @@ -193,7 +193,8 @@ class BackupsBloc extends Bloc { ); if (result.success == false) { getIt().showSnackBar( - result.message ?? "Couldn't initialize repository on your server."); + result.message ?? "Couldn't initialize repository on your server.", + ); emit(BackupsUnititialized()); return; } diff --git a/lib/logic/bloc/backups/backups_state.dart b/lib/logic/bloc/backups/backups_state.dart index 153b1e4e..e41c3b74 100644 --- a/lib/logic/bloc/backups/backups_state.dart +++ b/lib/logic/bloc/backups/backups_state.dart @@ -71,7 +71,8 @@ class BackupsUnititialized extends BackupsState { final BackblazeBucket? backblazeBucket, }) => BackupsUnititialized( - backblazeBucket: backblazeBucket ?? this.backblazeBucket); + backblazeBucket: backblazeBucket ?? this.backblazeBucket, + ); } class BackupsInitializing extends BackupsState { @@ -86,7 +87,8 @@ class BackupsInitializing extends BackupsState { final BackblazeBucket? backblazeBucket, }) => BackupsInitializing( - backblazeBucket: backblazeBucket ?? this.backblazeBucket); + backblazeBucket: backblazeBucket ?? this.backblazeBucket, + ); } class BackupsInitialized extends BackupsState { diff --git a/lib/logic/bloc/services/services_bloc.dart b/lib/logic/bloc/services/services_bloc.dart new file mode 100644 index 00000000..1d5293fd --- /dev/null +++ b/lib/logic/bloc/services/services_bloc.dart @@ -0,0 +1,144 @@ +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/models/service.dart'; + +part 'services_event.dart'; +part 'services_state.dart'; + +class ServicesBloc extends Bloc { + ServicesBloc() : super(ServicesInitial()) { + final connectionRepository = getIt(); + + _apiDataSubscription = connectionRepository.dataStream.listen( + (final ApiData apiData) { + add( + ServicesListUpdate([...apiData.services.data ?? []]), + ); + }, + ); + + if (connectionRepository.connectionStatus == ConnectionStatus.connected) { + add( + ServicesListUpdate( + [...connectionRepository.apiData.services.data ?? []], + ), + ); + } + + on( + _updateList, + ); + on( + _reload, + ); + on( + _restart, + ); + on( + _move, + ); + } + + Future _updateList( + final ServicesListUpdate event, + final Emitter emit, + ) async { + if (event.services.isEmpty) { + emit(ServicesInitial()); + return; + } + final newState = ServicesLoaded( + services: event.services, + lockedServices: state._lockedServices, + ); + emit(newState); + } + + Future _reload( + final ServicesReload event, + final Emitter emit, + ) async { + final currentState = state; + if (currentState is ServicesLoaded) { + emit(ServicesReloading.fromState(currentState)); + getIt().apiData.services.invalidate(); + await getIt().reload(null); + } + } + + Future awaitReload() async { + final currentState = state; + if (currentState is ServicesLoaded) { + getIt().apiData.services.invalidate(); + await getIt().reload(null); + } + } + + Future _restart( + final ServiceRestart event, + final Emitter emit, + ) async { + emit( + state.copyWith( + lockedServices: [ + ...state._lockedServices, + ServiceLock( + serviceId: event.service.id, + lockDuration: const Duration(seconds: 15), + ), + ], + ), + ); + final result = await getIt() + .api + .restartService(event.service.id); + if (!result.success) { + getIt().showSnackBar('jobs.generic_error'.tr()); + return; + } + if (!result.data) { + getIt() + .showSnackBar(result.message ?? 'jobs.generic_error'.tr()); + return; + } + } + + Future _move( + final ServiceMove event, + final Emitter emit, + ) async { + final migrationJob = await getIt() + .api + .moveService(event.service.id, event.destination); + if (!migrationJob.success) { + getIt() + .showSnackBar(migrationJob.message ?? 'jobs.generic_error'.tr()); + } + if (migrationJob.data != null) { + getIt() + .apiData + .serverJobs + .data + ?.add(migrationJob.data!); + getIt().emitData(); + } + } + + late StreamSubscription _apiDataSubscription; + + @override + void onChange(final Change change) { + super.onChange(change); + } + + @override + Future close() { + _apiDataSubscription.cancel(); + return super.close(); + } +} diff --git a/lib/logic/bloc/services/services_event.dart b/lib/logic/bloc/services/services_event.dart new file mode 100644 index 00000000..c8239152 --- /dev/null +++ b/lib/logic/bloc/services/services_event.dart @@ -0,0 +1,40 @@ +part of 'services_bloc.dart'; + +abstract class ServicesEvent extends Equatable { + const ServicesEvent(); +} + +class ServicesListUpdate extends ServicesEvent { + const ServicesListUpdate(this.services); + + final List services; + + @override + List get props => [services]; +} + +class ServicesReload extends ServicesEvent { + const ServicesReload(); + + @override + List get props => []; +} + +class ServiceRestart extends ServicesEvent { + const ServiceRestart(this.service); + + final Service service; + + @override + List get props => [service]; +} + +class ServiceMove extends ServicesEvent { + const ServiceMove(this.service, this.destination); + + final Service service; + final String destination; + + @override + List get props => [service, destination]; +} diff --git a/lib/logic/bloc/services/services_state.dart b/lib/logic/bloc/services/services_state.dart new file mode 100644 index 00000000..05d6bc89 --- /dev/null +++ b/lib/logic/bloc/services/services_state.dart @@ -0,0 +1,115 @@ +part of 'services_bloc.dart'; + +abstract class ServicesState extends Equatable { + ServicesState({final List lockedServices = const []}) + : _lockedServices = + lockedServices.where((final lock) => lock.isLocked).toList(); + final List _lockedServices; + List get services; + List get lockedServices => _lockedServices + .where((final lock) => lock.isLocked) + .map((final lock) => lock.serviceId) + .toList(); + + List get servicesThatCanBeBackedUp => services + .where( + (final service) => service.canBeBackedUp, + ) + .toList(); + + bool isServiceLocked(final String serviceId) => + lockedServices.contains(serviceId); + + Service? getServiceById(final String id) { + final service = services.firstWhere( + (final service) => service.id == id, + orElse: () => Service.empty, + ); + if (service.id == 'empty') { + return null; + } + return service; + } + + ServicesState copyWith({ + final List? services, + final List? lockedServices, + }); +} + +class ServiceLock extends Equatable { + ServiceLock({ + required this.serviceId, + required this.lockDuration, + }) : lockTime = DateTime.now(); + + final String serviceId; + final Duration lockDuration; + final DateTime lockTime; + + bool get isLocked => DateTime.now().isBefore(lockTime.add(lockDuration)); + + @override + List get props => [serviceId, lockDuration, lockTime]; +} + +class ServicesInitial extends ServicesState { + @override + List get props => []; + + @override + List get services => []; + + @override + ServicesState copyWith({ + final List? services, + final List? lockedServices, + }) => + ServicesInitial(); +} + +class ServicesLoaded extends ServicesState { + ServicesLoaded({ + required final List services, + required super.lockedServices, + }) : _servicesHachCode = Object.hashAll([...services]); + + final int _servicesHachCode; + + final apiConnectionRepository = getIt(); + + List get _services => + apiConnectionRepository.apiData.services.data ?? []; + + @override + List get services => _services; + + @override + List get props => [_servicesHachCode, _lockedServices]; + + @override + ServicesLoaded copyWith({ + final List? services, + final List? lockedServices, + }) => + ServicesLoaded( + services: services ?? this.services, + lockedServices: lockedServices ?? _lockedServices, + ); +} + +class ServicesReloading extends ServicesLoaded { + ServicesReloading({ + required super.services, + required super.lockedServices, + }); + + ServicesReloading.fromState(final ServicesLoaded state) + : super( + services: state.services, + lockedServices: state._lockedServices, + ); + + @override + List get props => [services, lockedServices]; +} diff --git a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart index 59a33673..f9188985 100644 --- a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart +++ b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart @@ -5,7 +5,7 @@ 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/graphql_maps/server_api/server_api.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; +import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/cubit/users/users_cubit.dart'; import 'package:selfprivacy/logic/models/job.dart'; @@ -16,12 +16,12 @@ part 'client_jobs_state.dart'; class JobsCubit extends Cubit { JobsCubit({ required this.usersCubit, - required this.servicesCubit, + required this.servicesBloc, }) : super(JobsStateEmpty()); final ServerApi api = ServerApi(); final UsersCubit usersCubit; - final ServicesCubit servicesCubit; + final ServicesBloc servicesBloc; void addJob(final ClientJob job) { final jobs = currentJobList; @@ -90,7 +90,7 @@ class JobsCubit extends Cubit { await api.pullConfigurationUpdate(); await api.apply(); - await servicesCubit.load(); + servicesBloc.add(const ServicesReload()); emit(JobsStateEmpty()); } diff --git a/lib/logic/cubit/services/services_cubit.dart b/lib/logic/cubit/services/services_cubit.dart deleted file mode 100644 index a9849700..00000000 --- a/lib/logic/cubit/services/services_cubit.dart +++ /dev/null @@ -1,81 +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/graphql_maps/server_api/server_api.dart'; -import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart'; -import 'package:selfprivacy/logic/models/service.dart'; - -part 'services_state.dart'; - -class ServicesCubit extends ServerConnectionDependentCubit { - ServicesCubit(final ServerInstallationCubit serverInstallationCubit) - : super(const ServicesState.empty()); - final ServerApi api = ServerApi(); - Timer? timer; - @override - Future load() async { - final List services = await api.getAllServices(); - emit( - ServicesState( - services: services, - lockedServices: const [], - ), - ); - timer = Timer(const Duration(seconds: 10), () => reload(useTimer: true)); - } - - Future reload({final bool useTimer = false}) async { - final List services = await api.getAllServices(); - emit( - state.copyWith( - services: services, - ), - ); - if (useTimer) { - timer = Timer(const Duration(seconds: 60), () => reload(useTimer: true)); - } - } - - Future restart(final String serviceId) async { - emit(state.copyWith(lockedServices: [...state.lockedServices, serviceId])); - final result = await api.restartService(serviceId); - if (!result.success) { - getIt().showSnackBar('jobs.generic_error'.tr()); - return; - } - if (!result.data) { - getIt() - .showSnackBar(result.message ?? 'jobs.generic_error'.tr()); - return; - } - - await Future.delayed(const Duration(seconds: 2)); - unawaited(reload()); - await Future.delayed(const Duration(seconds: 10)); - emit( - state.copyWith( - lockedServices: state.lockedServices - .where((final element) => element != serviceId) - .toList(), - ), - ); - unawaited(reload()); - } - - Future moveService( - final String serviceId, - final String destination, - ) async { - await api.moveService(serviceId, destination); - } - - @override - void clear() async { - emit(const ServicesState.empty()); - if (timer != null && timer!.isActive) { - timer!.cancel(); - timer = null; - } - } -} diff --git a/lib/logic/cubit/services/services_state.dart b/lib/logic/cubit/services/services_state.dart deleted file mode 100644 index 7a136b54..00000000 --- a/lib/logic/cubit/services/services_state.dart +++ /dev/null @@ -1,49 +0,0 @@ -part of 'services_cubit.dart'; - -class ServicesState extends ServerInstallationDependendState { - const ServicesState({ - required this.services, - required this.lockedServices, - }); - - const ServicesState.empty() - : this(services: const [], lockedServices: const []); - - final List services; - final List lockedServices; - - List get servicesThatCanBeBackedUp => services - .where( - (final service) => service.canBeBackedUp, - ) - .toList(); - - bool isServiceLocked(final String serviceId) => - lockedServices.contains(serviceId); - - Service? getServiceById(final String id) { - final service = services.firstWhere( - (final service) => service.id == id, - orElse: () => Service.empty, - ); - if (service.id == 'empty') { - return null; - } - return service; - } - - @override - List get props => [ - services, - lockedServices, - ]; - - ServicesState copyWith({ - final List? services, - final List? lockedServices, - }) => - ServicesState( - services: services ?? this.services, - lockedServices: lockedServices ?? this.lockedServices, - ); -} diff --git a/lib/logic/get_it/api_connection_repository.dart b/lib/logic/get_it/api_connection_repository.dart index 72e9fb65..8503acbc 100644 --- a/lib/logic/get_it/api_connection_repository.dart +++ b/lib/logic/get_it/api_connection_repository.dart @@ -9,6 +9,7 @@ import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/server_job.dart'; +import 'package:selfprivacy/logic/models/service.dart'; /// Repository for all API calls /// Stores the current state of all data from API and exposes it to Blocs. @@ -74,6 +75,7 @@ class ApiConnectionRepository { _apiData.serverJobs.data = await api.getServerJobs(); _apiData.backupConfig.data = await api.getBackupsConfiguration(); _apiData.backups.data = await api.getBackups(); + _apiData.services.data = await api.getAllServices(); _dataStream.add(_apiData); connectionStatus = ConnectionStatus.connected; @@ -109,6 +111,8 @@ class ApiConnectionRepository { .refetchData(version, () => _dataStream.add(_apiData)); await _apiData.backupConfig .refetchData(version, () => _dataStream.add(_apiData)); + await _apiData.services + .refetchData(version, () => _dataStream.add(_apiData)); } void emitData() { @@ -132,12 +136,17 @@ class ApiData { backups = ApiDataElement>( fetchData: () async => api.getBackups(), requiredApiVersion: '>=2.4.2', + ), + services = ApiDataElement>( + fetchData: () async => api.getAllServices(), + requiredApiVersion: '>=2.4.3', ); ApiDataElement> serverJobs; ApiDataElement apiVersion; ApiDataElement backupConfig; ApiDataElement> backups; + ApiDataElement> services; } enum ConnectionStatus { @@ -163,7 +172,9 @@ class ApiDataElement { final Future Function() fetchData; Future refetchData( - final Version version, final Function callback) async { + final Version version, + final Function callback, + ) async { if (VersionConstraint.parse(requiredApiVersion).allows(version)) { print('Fetching data for $runtimeType'); if (isExpired) { diff --git a/lib/logic/models/service.dart b/lib/logic/models/service.dart index 702b94db..5f2364e9 100644 --- a/lib/logic/models/service.dart +++ b/lib/logic/models/service.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; +import 'package:equatable/equatable.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.dart'; import 'package:selfprivacy/logic/models/disk_size.dart'; @@ -8,7 +9,7 @@ import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart'; -class Service { +class Service extends Equatable { Service.fromGraphQL(final Query$AllServices$services$allServices service) : this( id: service.id, @@ -37,7 +38,7 @@ class Service { [], url: service.url, ); - Service({ + const Service({ required this.id, required this.displayName, required this.description, @@ -72,7 +73,7 @@ class Service { return ''; } - static Service empty = Service( + static Service empty = const Service( id: 'empty', displayName: '', description: '', @@ -83,7 +84,7 @@ class Service { backupDescription: '', status: ServiceStatus.off, storageUsage: ServiceStorageUsage( - used: const DiskSize(byte: 0), + used: DiskSize(byte: 0), volume: '', ), svgIcon: '', @@ -104,16 +105,36 @@ class Service { final String svgIcon; final String? url; final List dnsRecords; + + @override + List get props => [ + id, + displayName, + description, + isEnabled, + isRequired, + isMovable, + canBeBackedUp, + backupDescription, + status, + storageUsage, + svgIcon, + dnsRecords, + url, + ]; } -class ServiceStorageUsage { - ServiceStorageUsage({ +class ServiceStorageUsage extends Equatable { + const ServiceStorageUsage({ required this.used, required this.volume, }); final DiskSize used; final String? volume; + + @override + List get props => [used, volume]; } enum ServiceStatus { diff --git a/lib/ui/pages/backups/backup_details.dart b/lib/ui/pages/backups/backup_details.dart index a99d6385..d5dbe4e4 100644 --- a/lib/ui/pages/backups/backup_details.dart +++ b/lib/ui/pages/backups/backup_details.dart @@ -5,7 +5,7 @@ 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/bloc/server_jobs/server_jobs_bloc.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; +import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/json/server_job.dart'; import 'package:selfprivacy/logic/models/service.dart'; @@ -39,7 +39,7 @@ class BackupDetailsPage extends StatelessWidget { final bool preventActions = backupsState.preventActions; final List backups = backupsState.backups; final List services = - context.watch().state.servicesThatCanBeBackedUp; + context.watch().state.servicesThatCanBeBackedUp; final Duration? autobackupPeriod = backupsState.autobackupPeriod; final List backupJobs = context .watch() @@ -298,7 +298,7 @@ class BackupDetailsPage extends StatelessWidget { children: backups.take(15).map( (final Backup backup) { final service = context - .read() + .read() .state .getServiceById(backup.serviceId); return ListTile( @@ -419,7 +419,7 @@ class BackupDetailsPage extends StatelessWidget { : () => { context .read() - .add(const ForceSnapshotListUpdate()) + .add(const ForceSnapshotListUpdate()), }, ), const SizedBox(height: 8), diff --git a/lib/ui/pages/backups/backups_list.dart b/lib/ui/pages/backups/backups_list.dart index 79eb7a95..fd2b541e 100644 --- a/lib/ui/pages/backups/backups_list.dart +++ b/lib/ui/pages/backups/backups_list.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; +import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/helpers/modals.dart'; @@ -43,7 +43,7 @@ class BackupsListPage extends StatelessWidget { ...backups.map( (final Backup backup) { final service = context - .read() + .read() .state .getServiceById(backup.serviceId); return ListTile( diff --git a/lib/ui/pages/backups/snapshot_modal.dart b/lib/ui/pages/backups/snapshot_modal.dart index 3236ddc1..54dbaae4 100644 --- a/lib/ui/pages/backups/snapshot_modal.dart +++ b/lib/ui/pages/backups/snapshot_modal.dart @@ -4,7 +4,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/bloc/backups/backups_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/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/json/server_job.dart'; import 'package:selfprivacy/logic/models/service.dart'; @@ -48,7 +48,7 @@ class _SnapshotModalState extends State { final bool isServiceBusy = busyServices.contains(widget.snapshot.serviceId); final Service? service = context - .read() + .read() .state .getServiceById(widget.snapshot.serviceId); @@ -153,8 +153,12 @@ class _SnapshotModalState extends State { onPressed: isServiceBusy ? null : () { - context.read().add(RestoreBackup( - widget.snapshot.id, selectedStrategy)); + context.read().add( + RestoreBackup( + widget.snapshot.id, + selectedStrategy, + ), + ); Navigator.of(context).pop(); getIt() .showSnackBar('backup.restore_started'.tr()); diff --git a/lib/ui/pages/server_storage/binds_migration/services_migration.dart b/lib/ui/pages/server_storage/binds_migration/services_migration.dart index 453e7067..171fb53d 100644 --- a/lib/ui/pages/server_storage/binds_migration/services_migration.dart +++ b/lib/ui/pages/server_storage/binds_migration/services_migration.dart @@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/components/buttons/brand_button.dart'; @@ -175,9 +175,11 @@ class _ServicesMigrationPageState extends State { onPressed: () { for (final service in widget.services) { if (serviceToDisk[service.id] != null) { - context.read().moveService( - service.id, - serviceToDisk[service.id]!, + context.read().add( + ServiceMove( + service, + serviceToDisk[service.id]!, + ), ); } } diff --git a/lib/ui/pages/server_storage/server_storage.dart b/lib/ui/pages/server_storage/server_storage.dart index eb7a586b..fb1602b9 100644 --- a/lib/ui/pages/server_storage/server_storage.dart +++ b/lib/ui/pages/server_storage/server_storage.dart @@ -3,7 +3,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; +import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/components/buttons/outlined_button.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; @@ -30,8 +30,7 @@ class _ServerStoragePageState extends State { final bool isReady = context.watch().state is ServerInstallationFinished; - final List services = - context.watch().state.services; + final List services = context.watch().state.services; if (!isReady) { return BrandHeroScreen( diff --git a/lib/ui/pages/services/service_page.dart b/lib/ui/pages/services/service_page.dart index 96560db0..4291c6e2 100644 --- a/lib/ui/pages/services/service_page.dart +++ b/lib/ui/pages/services/service_page.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_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/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/job.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/ui/components/cards/filled_card.dart'; @@ -26,7 +26,7 @@ class _ServicePageState extends State { @override Widget build(final BuildContext context) { final Service? service = - context.watch().state.getServiceById(widget.serviceId); + context.watch().state.getServiceById(widget.serviceId); if (service == null) { return const BrandHeroScreen( @@ -43,7 +43,7 @@ class _ServicePageState extends State { service.status == ServiceStatus.off; final bool serviceLocked = - context.watch().state.isServiceLocked(service.id); + context.watch().state.isServiceLocked(service.id); return BrandHeroScreen( hasBackButton: true, @@ -81,7 +81,7 @@ class _ServicePageState extends State { ListTile( iconColor: Theme.of(context).colorScheme.onBackground, onTap: () => { - context.read().restart(service.id), + context.read().add(ServiceRestart(service)), }, leading: const Icon(Icons.restart_alt_outlined), title: Text( diff --git a/lib/ui/pages/services/services.dart b/lib/ui/pages/services/services.dart index 2aa31d8b..3bc0de48 100644 --- a/lib/ui/pages/services/services.dart +++ b/lib/ui/pages/services/services.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:selfprivacy/config/brand_theme.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; +import 'package:selfprivacy/logic/bloc/services/services_bloc.dart'; import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/logic/models/state_types.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; @@ -30,7 +30,7 @@ class _ServicesPageState extends State { final isReady = context.watch().state is ServerInstallationFinished; - final services = [...context.watch().state.services]; + final services = [...context.watch().state.services]; services .sort((final a, final b) => a.status.index.compareTo(b.status.index)); @@ -52,7 +52,8 @@ class _ServicesPageState extends State { ) : RefreshIndicator( onRefresh: () async { - await context.read().reload(); + // Create a ServicesRelaod event and wait for the state to change. + await context.read().awaitReload(); }, child: ListView( padding: paddingH15V0,