mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-09-19 01:47:51 +00:00
a9a7b04ad5
Turns out, there are still servers that didn't perform the binds migration. The can't perform it anymore because email changed the id. I'm getting back the option to perform the binds migration, with some fallback defaults.
218 lines
7.4 KiB
Dart
218 lines
7.4 KiB
Dart
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/bloc/services/services_bloc.dart';
|
|
import 'package:selfprivacy/logic/models/disk_size.dart';
|
|
import 'package:selfprivacy/logic/models/disk_status.dart';
|
|
import 'package:selfprivacy/logic/models/service.dart';
|
|
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
|
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
|
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
|
|
import 'package:selfprivacy/ui/components/jobs_content/jobs_content.dart';
|
|
import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart';
|
|
import 'package:selfprivacy/ui/components/storage_list_items/service_migration_list_item.dart';
|
|
|
|
@RoutePage()
|
|
class ServicesMigrationPage extends StatefulWidget {
|
|
const ServicesMigrationPage({
|
|
required this.services,
|
|
required this.diskStatus,
|
|
required this.isMigration,
|
|
super.key,
|
|
});
|
|
|
|
final DiskStatus diskStatus;
|
|
final List<Service> services;
|
|
final bool isMigration;
|
|
|
|
@override
|
|
State<ServicesMigrationPage> createState() => _ServicesMigrationPageState();
|
|
}
|
|
|
|
class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
|
|
/// Service id to target migration disk name
|
|
final Map<String, String> serviceToDisk = {};
|
|
|
|
static const headerHeight = 52.0;
|
|
static const headerVerticalPadding = 8.0;
|
|
static const listItemHeight = 62.0;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
for (final Service service in widget.services) {
|
|
if (service.storageUsage.volume != null) {
|
|
serviceToDisk[service.id] = service.storageUsage.volume!;
|
|
}
|
|
}
|
|
}
|
|
|
|
void onChange(final String volumeName, final String serviceId) {
|
|
setState(() {
|
|
serviceToDisk[serviceId] = volumeName;
|
|
});
|
|
}
|
|
|
|
bool get isVolumePicked {
|
|
bool isChangeFound = false;
|
|
for (final Service service in widget.services) {
|
|
for (final String serviceId in serviceToDisk.keys) {
|
|
if (serviceId == service.id &&
|
|
serviceToDisk[serviceId] != service.storageUsage.volume!) {
|
|
isChangeFound = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return isChangeFound;
|
|
}
|
|
|
|
/// Check the services and if a service is moved (in a serviceToDisk entry)
|
|
/// subtract the used storage from the old volume and add it to the new volume.
|
|
/// The old volume is the volume the service is currently on, shown in services list.
|
|
DiskVolume recalculatedDiskUsages(
|
|
final DiskVolume volume,
|
|
final List<Service> services,
|
|
) {
|
|
DiskSize used = volume.sizeUsed;
|
|
|
|
for (final Service service in services) {
|
|
if (service.storageUsage.volume != null) {
|
|
if (service.storageUsage.volume == volume.name) {
|
|
if (serviceToDisk[service.id] != null &&
|
|
serviceToDisk[service.id] != volume.name) {
|
|
used -= service.storageUsage.used;
|
|
}
|
|
} else {
|
|
if (serviceToDisk[service.id] != null &&
|
|
serviceToDisk[service.id] == volume.name) {
|
|
used += service.storageUsage.used;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return volume.copyWith(sizeUsed: used);
|
|
}
|
|
|
|
@override
|
|
Widget build(final BuildContext context) {
|
|
final Size appBarHeight = Size.fromHeight(
|
|
headerHeight +
|
|
headerVerticalPadding * 2 +
|
|
listItemHeight * widget.diskStatus.diskVolumes.length +
|
|
headerVerticalPadding * widget.diskStatus.diskVolumes.length,
|
|
);
|
|
return SafeArea(
|
|
child: Scaffold(
|
|
appBar: PreferredSize(
|
|
preferredSize: appBarHeight,
|
|
child: Column(
|
|
children: [
|
|
BrandHeader(
|
|
title: 'storage.data_migration_title'.tr(),
|
|
hasBackButton: true,
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 16.0,
|
|
vertical: headerVerticalPadding,
|
|
),
|
|
child: Column(
|
|
children: [
|
|
...widget.diskStatus.diskVolumes.map(
|
|
(final volume) => Column(
|
|
children: [
|
|
ServerStorageListItem(
|
|
volume: recalculatedDiskUsages(
|
|
volume,
|
|
widget.services,
|
|
),
|
|
dense: true,
|
|
),
|
|
const SizedBox(height: headerVerticalPadding),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 0),
|
|
],
|
|
),
|
|
),
|
|
body: ListView(
|
|
padding: const EdgeInsets.all(16.0),
|
|
children: <Widget>[
|
|
if (widget.services.isEmpty)
|
|
const Center(child: CircularProgressIndicator()),
|
|
...widget.services.map(
|
|
(final service) => Column(
|
|
children: [
|
|
const SizedBox(height: 8),
|
|
ServiceMigrationListItem(
|
|
service: service,
|
|
diskStatus: widget.diskStatus,
|
|
selectedVolume: serviceToDisk[service.id]!,
|
|
onChange: onChange,
|
|
),
|
|
const SizedBox(height: 4),
|
|
const Divider(),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: InfoBox(
|
|
text: 'storage.data_migration_notice'.tr(),
|
|
isWarning: true,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
if (widget.isMigration || (!widget.isMigration && isVolumePicked))
|
|
BrandButton.filled(
|
|
child: Text('storage.start_migration_button'.tr()),
|
|
onPressed: () {
|
|
if (widget.isMigration) {
|
|
context.read<ServerJobsBloc>().migrateToBinds(
|
|
serviceToDisk,
|
|
);
|
|
} else {
|
|
for (final service in widget.services) {
|
|
if (serviceToDisk[service.id] != null) {
|
|
context.read<ServicesBloc>().add(
|
|
ServiceMove(
|
|
service,
|
|
serviceToDisk[service.id]!,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
context.router.popUntilRoot();
|
|
showModalBottomSheet(
|
|
context: context,
|
|
useRootNavigator: true,
|
|
isScrollControlled: true,
|
|
builder: (final BuildContext context) =>
|
|
DraggableScrollableSheet(
|
|
expand: false,
|
|
maxChildSize: 0.9,
|
|
minChildSize: 0.4,
|
|
initialChildSize: 0.6,
|
|
builder: (final context, final scrollController) =>
|
|
JobsContent(controller: scrollController),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
const SizedBox(height: 32),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|