2023-02-24 16:45:32 +00:00
|
|
|
import 'package:auto_route/auto_route.dart';
|
2022-09-06 10:25:28 +00:00
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
2022-08-24 05:35:49 +00:00
|
|
|
import 'package:flutter/material.dart';
|
2022-08-29 20:35:06 +00:00
|
|
|
import 'package:flutter_svg/svg.dart';
|
2022-09-06 10:25:28 +00:00
|
|
|
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
2022-09-16 13:36:51 +00:00
|
|
|
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
|
2022-08-29 20:35:06 +00:00
|
|
|
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
2022-09-06 10:25:28 +00:00
|
|
|
import 'package:selfprivacy/logic/models/job.dart';
|
2022-08-29 20:35:06 +00:00
|
|
|
import 'package:selfprivacy/logic/models/service.dart';
|
2023-04-05 10:33:53 +00:00
|
|
|
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
2023-02-23 14:49:14 +00:00
|
|
|
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
2023-02-24 16:45:32 +00:00
|
|
|
import 'package:selfprivacy/ui/router/router.dart';
|
2023-01-17 13:23:26 +00:00
|
|
|
import 'package:selfprivacy/utils/launch_url.dart';
|
2022-08-24 05:35:49 +00:00
|
|
|
|
2023-03-22 11:38:18 +00:00
|
|
|
@RoutePage()
|
2022-08-24 05:35:49 +00:00
|
|
|
class ServicePage extends StatefulWidget {
|
2022-10-26 16:26:09 +00:00
|
|
|
const ServicePage({required this.serviceId, super.key});
|
2022-08-29 20:35:06 +00:00
|
|
|
|
|
|
|
final String serviceId;
|
2022-08-24 05:35:49 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
State<ServicePage> createState() => _ServicePageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _ServicePageState extends State<ServicePage> {
|
|
|
|
@override
|
2022-08-29 20:35:06 +00:00
|
|
|
Widget build(final BuildContext context) {
|
|
|
|
final Service? service =
|
|
|
|
context.watch<ServicesCubit>().state.getServiceById(widget.serviceId);
|
|
|
|
|
|
|
|
if (service == null) {
|
|
|
|
return const BrandHeroScreen(
|
2022-08-29 18:18:07 +00:00
|
|
|
hasBackButton: true,
|
|
|
|
children: [
|
2022-08-29 20:35:06 +00:00
|
|
|
Center(
|
|
|
|
child: CircularProgressIndicator(),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2022-09-06 10:25:28 +00:00
|
|
|
|
|
|
|
final bool serviceDisabled = service.status == ServiceStatus.inactive ||
|
|
|
|
service.status == ServiceStatus.off;
|
|
|
|
|
2022-09-19 00:21:08 +00:00
|
|
|
final bool serviceLocked =
|
|
|
|
context.watch<ServicesCubit>().state.isServiceLocked(service.id);
|
|
|
|
|
2022-08-29 20:35:06 +00:00
|
|
|
return BrandHeroScreen(
|
|
|
|
hasBackButton: true,
|
2023-03-22 12:13:47 +00:00
|
|
|
hasFlashButton: true,
|
2022-10-04 10:34:56 +00:00
|
|
|
heroIconWidget: SvgPicture.string(
|
|
|
|
service.svgIcon,
|
|
|
|
width: 48.0,
|
|
|
|
height: 48.0,
|
2023-02-23 14:49:14 +00:00
|
|
|
colorFilter: ColorFilter.mode(
|
|
|
|
Theme.of(context).colorScheme.onBackground,
|
|
|
|
BlendMode.srcIn,
|
2023-02-24 12:15:01 +00:00
|
|
|
),
|
2022-10-04 10:34:56 +00:00
|
|
|
),
|
|
|
|
heroTitle: service.displayName,
|
2022-08-29 20:35:06 +00:00
|
|
|
children: [
|
|
|
|
ServiceStatusCard(status: service.status),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
if (service.url != null)
|
|
|
|
ListTile(
|
|
|
|
iconColor: Theme.of(context).colorScheme.onBackground,
|
2023-01-17 13:23:26 +00:00
|
|
|
onTap: () => launchURL(service.url),
|
2022-08-29 20:35:06 +00:00
|
|
|
leading: const Icon(Icons.open_in_browser),
|
|
|
|
title: Text(
|
2022-10-03 23:32:35 +00:00
|
|
|
'service_page.open_in_browser'.tr(),
|
2022-08-29 20:35:06 +00:00
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
),
|
|
|
|
subtitle: Text(
|
|
|
|
service.url!.replaceAll('https://', ''),
|
|
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
2022-08-29 18:18:07 +00:00
|
|
|
),
|
2022-08-24 05:35:49 +00:00
|
|
|
),
|
2022-08-29 20:35:06 +00:00
|
|
|
const SizedBox(height: 8),
|
|
|
|
const Divider(),
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
ListTile(
|
|
|
|
iconColor: Theme.of(context).colorScheme.onBackground,
|
2022-09-06 10:25:28 +00:00
|
|
|
onTap: () => {
|
|
|
|
context.read<ServicesCubit>().restart(service.id),
|
|
|
|
},
|
2022-08-29 20:35:06 +00:00
|
|
|
leading: const Icon(Icons.restart_alt_outlined),
|
|
|
|
title: Text(
|
2022-10-03 23:32:35 +00:00
|
|
|
'service_page.restart'.tr(),
|
2022-08-29 20:35:06 +00:00
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
2022-08-24 05:35:49 +00:00
|
|
|
),
|
2022-09-19 00:21:08 +00:00
|
|
|
enabled: !serviceDisabled && !serviceLocked,
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
ListTile(
|
|
|
|
iconColor: Theme.of(context).colorScheme.onBackground,
|
2022-09-06 10:25:28 +00:00
|
|
|
onTap: () => {
|
2022-10-07 17:50:18 +00:00
|
|
|
context.read<JobsCubit>().addJob(
|
2022-09-06 10:25:28 +00:00
|
|
|
ServiceToggleJob(
|
2022-10-04 18:58:25 +00:00
|
|
|
service: service,
|
2022-09-06 10:25:28 +00:00
|
|
|
needToTurnOn: serviceDisabled,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
},
|
2022-08-29 20:35:06 +00:00
|
|
|
leading: const Icon(Icons.power_settings_new),
|
|
|
|
title: Text(
|
2022-09-06 10:25:28 +00:00
|
|
|
serviceDisabled
|
2022-10-03 23:32:35 +00:00
|
|
|
? 'service_page.enable'.tr()
|
|
|
|
: 'service_page.disable'.tr(),
|
2022-08-29 20:35:06 +00:00
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
),
|
2022-09-19 00:21:08 +00:00
|
|
|
enabled: !serviceLocked,
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
if (service.isMovable)
|
|
|
|
ListTile(
|
|
|
|
iconColor: Theme.of(context).colorScheme.onBackground,
|
2022-09-19 00:21:08 +00:00
|
|
|
// Open page ServicesMigrationPage
|
2023-02-24 16:45:32 +00:00
|
|
|
onTap: () => context.pushRoute(
|
|
|
|
ServicesMigrationRoute(
|
|
|
|
services: [service],
|
|
|
|
diskStatus:
|
|
|
|
context.read<ApiServerVolumeCubit>().state.diskStatus,
|
|
|
|
isMigration: false,
|
2022-09-19 00:21:08 +00:00
|
|
|
),
|
|
|
|
),
|
2022-08-29 20:35:06 +00:00
|
|
|
leading: const Icon(Icons.drive_file_move_outlined),
|
|
|
|
title: Text(
|
2022-10-03 23:32:35 +00:00
|
|
|
'service_page.move'.tr(),
|
2022-08-29 20:35:06 +00:00
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
2022-08-29 18:18:07 +00:00
|
|
|
),
|
2022-09-16 13:36:51 +00:00
|
|
|
subtitle: Text(
|
2022-10-03 23:32:35 +00:00
|
|
|
'service_page.uses'.tr(
|
2022-09-16 13:36:51 +00:00
|
|
|
namedArgs: {
|
|
|
|
'usage': service.storageUsage.used.toString(),
|
|
|
|
'volume': context
|
|
|
|
.read<ApiServerVolumeCubit>()
|
|
|
|
.state
|
|
|
|
.getVolume(service.storageUsage.volume ?? '')
|
2023-11-06 13:15:38 +00:00
|
|
|
.displayName,
|
2022-09-16 13:36:51 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
|
|
),
|
2023-07-25 21:56:47 +00:00
|
|
|
enabled: !serviceDisabled &&
|
|
|
|
!serviceLocked &&
|
|
|
|
service.storageUsage.volume != null,
|
2022-08-29 18:18:07 +00:00
|
|
|
),
|
2023-07-02 15:24:07 +00:00
|
|
|
if (service.canBeBackedUp)
|
|
|
|
ListTile(
|
|
|
|
iconColor: Theme.of(context).colorScheme.onBackground,
|
|
|
|
// Open page ServicesMigrationPage
|
|
|
|
onTap: () => context.pushRoute(
|
|
|
|
BackupsListRoute(service: service),
|
|
|
|
),
|
|
|
|
leading: const Icon(Icons.settings_backup_restore_outlined),
|
|
|
|
title: Text(
|
|
|
|
'service_page.snapshots'.tr(),
|
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
),
|
|
|
|
),
|
2022-08-29 20:35:06 +00:00
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ServiceStatusCard extends StatelessWidget {
|
|
|
|
const ServiceStatusCard({
|
|
|
|
required this.status,
|
2022-10-26 16:26:09 +00:00
|
|
|
super.key,
|
2022-08-29 20:35:06 +00:00
|
|
|
});
|
|
|
|
final ServiceStatus status;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) {
|
|
|
|
switch (status) {
|
|
|
|
case ServiceStatus.active:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.check_circle_outline,
|
|
|
|
size: 24,
|
2022-08-29 18:18:07 +00:00
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.active'.tr()),
|
2022-08-24 05:35:49 +00:00
|
|
|
),
|
2022-08-29 20:35:06 +00:00
|
|
|
);
|
|
|
|
case ServiceStatus.inactive:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
tertiary: true,
|
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.stop_circle_outlined,
|
|
|
|
size: 24,
|
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.inactive'.tr()),
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
case ServiceStatus.failed:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
error: true,
|
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.error_outline,
|
|
|
|
size: 24,
|
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.failed'.tr()),
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
case ServiceStatus.off:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
tertiary: true,
|
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.power_settings_new,
|
|
|
|
size: 24,
|
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.off'.tr()),
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
case ServiceStatus.activating:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
tertiary: true,
|
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.restart_alt_outlined,
|
|
|
|
size: 24,
|
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.activating'.tr()),
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
case ServiceStatus.deactivating:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
tertiary: true,
|
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.restart_alt_outlined,
|
|
|
|
size: 24,
|
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.deactivating'.tr()),
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
case ServiceStatus.reloading:
|
2022-10-04 08:05:26 +00:00
|
|
|
return FilledCard(
|
2022-09-15 16:57:26 +00:00
|
|
|
tertiary: true,
|
|
|
|
child: ListTile(
|
2022-10-04 08:05:26 +00:00
|
|
|
leading: const Icon(
|
2022-08-29 20:35:06 +00:00
|
|
|
Icons.restart_alt_outlined,
|
|
|
|
size: 24,
|
|
|
|
),
|
2022-10-04 08:05:26 +00:00
|
|
|
title: Text('service_page.status.reloading'.tr()),
|
2022-08-29 20:35:06 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|