diff --git a/lib/logic/api_maps/rest_maps/server.dart b/lib/logic/api_maps/rest_maps/server.dart index f7e78eba..1cef3dfc 100644 --- a/lib/logic/api_maps/rest_maps/server.dart +++ b/lib/logic/api_maps/rest_maps/server.dart @@ -13,6 +13,7 @@ import 'package:selfprivacy/logic/models/json/api_token.dart'; import 'package:selfprivacy/logic/models/json/backup.dart'; import 'package:selfprivacy/logic/models/json/device_token.dart'; import 'package:selfprivacy/logic/models/json/recovery_token_status.dart'; +import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/logic/models/timezone_settings.dart'; class ApiResponse { @@ -380,13 +381,13 @@ class ServerApi extends ApiMap { } Future switchService( - final ServiceTypes type, + final Service service, final bool needToTurnOn, ) async { final Dio client = await getClient(); try { client.post( - '/services/${type.url}/${needToTurnOn ? 'enable' : 'disable'}', + '/services/${service.id}/${needToTurnOn ? 'enable' : 'disable'}', ); } on DioError catch (e) { print(e.message); @@ -395,7 +396,7 @@ class ServerApi extends ApiMap { } } - Future> servicesPowerCheck() async { + Future> servicesPowerCheck() async { Response response; final Dio client = await getClient(); @@ -409,11 +410,11 @@ class ServerApi extends ApiMap { } return { - ServiceTypes.bitwarden: response.data['bitwarden'] == 0, - ServiceTypes.gitea: response.data['gitea'] == 0, - ServiceTypes.nextcloud: response.data['nextcloud'] == 0, - ServiceTypes.ocserv: response.data['ocserv'] == 0, - ServiceTypes.pleroma: response.data['pleroma'] == 0, + 'bitwarden': response.data['bitwarden'] == 0, + 'gitea': response.data['gitea'] == 0, + 'nextcloud': response.data['nextcloud'] == 0, + 'ocserv': response.data['ocserv'] == 0, + 'pleroma': response.data['pleroma'] == 0, }; } @@ -867,28 +868,3 @@ class ServerApi extends ApiMap { return ApiResponse(statusCode: code, data: null); } } - -extension UrlServerExt on ServiceTypes { - String get url { - switch (this) { - // case ServiceTypes.mail: - // return ''; // cannot be switch off - // case ServiceTypes.messenger: - // return ''; // external service - // case ServiceTypes.video: - // return ''; // jitsi meet not working - case ServiceTypes.bitwarden: - return 'bitwarden'; - case ServiceTypes.nextcloud: - return 'nextcloud'; - case ServiceTypes.pleroma: - return 'pleroma'; - case ServiceTypes.gitea: - return 'gitea'; - case ServiceTypes.ocserv: - return 'ocserv'; - default: - throw Exception('wrong state'); - } - } -} diff --git a/lib/logic/common_enum/common_enum.dart b/lib/logic/common_enum/common_enum.dart index b1d0b730..69686978 100644 --- a/lib/logic/common_enum/common_enum.dart +++ b/lib/logic/common_enum/common_enum.dart @@ -1,7 +1,3 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; - enum LoadingStatus { uninitialized, refreshing, @@ -36,111 +32,3 @@ enum Period { } } } - -enum ServiceTypes { - mailserver, - bitwarden, - jitsi, - nextcloud, - pleroma, - gitea, - ocserv, -} - -extension ServiceTypesExt on ServiceTypes { - String get title { - switch (this) { - case ServiceTypes.mailserver: - return 'mail.title'.tr(); - case ServiceTypes.bitwarden: - return 'password_manager.title'.tr(); - case ServiceTypes.jitsi: - return 'video.title'.tr(); - case ServiceTypes.nextcloud: - return 'cloud.title'.tr(); - case ServiceTypes.pleroma: - return 'social_network.title'.tr(); - case ServiceTypes.gitea: - return 'git.title'.tr(); - case ServiceTypes.ocserv: - return 'vpn.title'.tr(); - } - } - - String get subtitle { - switch (this) { - case ServiceTypes.mailserver: - return 'mail.subtitle'.tr(); - case ServiceTypes.bitwarden: - return 'password_manager.subtitle'.tr(); - case ServiceTypes.jitsi: - return 'video.subtitle'.tr(); - case ServiceTypes.nextcloud: - return 'cloud.subtitle'.tr(); - case ServiceTypes.pleroma: - return 'social_network.subtitle'.tr(); - case ServiceTypes.gitea: - return 'git.subtitle'.tr(); - case ServiceTypes.ocserv: - return 'vpn.subtitle'.tr(); - } - } - - String get loginInfo { - switch (this) { - case ServiceTypes.mailserver: - return 'mail.login_info'.tr(); - case ServiceTypes.bitwarden: - return 'password_manager.login_info'.tr(); - case ServiceTypes.jitsi: - return 'video.login_info'.tr(); - case ServiceTypes.nextcloud: - return 'cloud.login_info'.tr(); - case ServiceTypes.pleroma: - return 'social_network.login_info'.tr(); - case ServiceTypes.gitea: - return 'git.login_info'.tr(); - case ServiceTypes.ocserv: - return ''; - } - } - - String get subdomain { - switch (this) { - case ServiceTypes.bitwarden: - return 'password'; - case ServiceTypes.jitsi: - return 'meet'; - case ServiceTypes.nextcloud: - return 'cloud'; - case ServiceTypes.pleroma: - return 'social'; - case ServiceTypes.gitea: - return 'git'; - case ServiceTypes.ocserv: - default: - return ''; - } - } - - IconData get icon { - switch (this) { - case ServiceTypes.mailserver: - return BrandIcons.envelope; - case ServiceTypes.bitwarden: - return BrandIcons.key; - case ServiceTypes.jitsi: - return BrandIcons.webcam; - case ServiceTypes.nextcloud: - return BrandIcons.upload; - case ServiceTypes.pleroma: - return BrandIcons.social; - case ServiceTypes.gitea: - return BrandIcons.git; - case ServiceTypes.ocserv: - return Icons.vpn_lock_outlined; - } - } - - String get txt => toString().split('.')[1]; -} diff --git a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart index a6d23a23..ca3733fd 100644 --- a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart +++ b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart @@ -45,10 +45,10 @@ class JobsCubit extends Cubit { newJobsList.addAll((state as JobsStateWithJobs).clientJobList); } final bool needToRemoveJob = newJobsList - .any((final el) => el is ServiceToggleJob && el.type == job.type); + .any((final el) => el is ServiceToggleJob && el.id == job.id); if (needToRemoveJob) { final ClientJob removingJob = newJobsList.firstWhere( - (final el) => el is ServiceToggleJob && el.type == job.type, + (final el) => el is ServiceToggleJob && el.id == job.id, ); removeJob(removingJob.id); } else { @@ -114,7 +114,7 @@ class JobsCubit extends Cubit { } if (job is ServiceToggleJob) { hasServiceJobs = true; - await api.switchService(job.type.name, job.needToTurnOn); + await api.switchService(job.service.id, job.needToTurnOn); } if (job is CreateSSHKeyJob) { await usersCubit.addSshKey(job.user, job.publicKey); diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index c941b9d1..a83e9deb 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -15,7 +15,6 @@ import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/dns_provider_ import 'package:selfprivacy/logic/api_maps/rest_maps/server.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider_factory.dart'; -import 'package:selfprivacy/logic/common_enum/common_enum.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; @@ -571,7 +570,7 @@ class ServerInstallationRepository { ); final String serverIp = await getServerIpFromDomain(serverDomain); if (recoveryCapabilities == ServerRecoveryCapabilities.legacy) { - final Map apiResponse = + final Map apiResponse = await serverApi.servicesPowerCheck(); if (apiResponse.isNotEmpty) { return ServerHostingDetails( diff --git a/lib/logic/cubit/services/services_cubit.dart b/lib/logic/cubit/services/services_cubit.dart index 4bb575a6..13d3e84d 100644 --- a/lib/logic/cubit/services/services_cubit.dart +++ b/lib/logic/cubit/services/services_cubit.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server.dart'; -import 'package:selfprivacy/logic/common_enum/common_enum.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; import 'package:selfprivacy/logic/models/service.dart'; diff --git a/lib/logic/cubit/services/services_state.dart b/lib/logic/cubit/services/services_state.dart index d5aa95eb..2d99880a 100644 --- a/lib/logic/cubit/services/services_state.dart +++ b/lib/logic/cubit/services/services_state.dart @@ -63,17 +63,17 @@ class ServicesState extends ServerInstallationDependendState { lockedServices, ]; - bool isEnableByType(final ServiceTypes type) { - switch (type) { - case ServiceTypes.bitwarden: + bool isEnableByType(final Service service) { + switch (service.id) { + case 'bitwarden': return isPasswordManagerEnable; - case ServiceTypes.nextcloud: + case 'nextcloud': return isCloudEnable; - case ServiceTypes.pleroma: + case 'pleroma': return isSocialNetworkEnable; - case ServiceTypes.gitea: + case 'gitea': return isGitEnable; - case ServiceTypes.ocserv: + case 'ocserv': return isVpnEnable; default: throw Exception('wrong state'); diff --git a/lib/logic/models/job.dart b/lib/logic/models/job.dart index c3748daa..7938dae7 100644 --- a/lib/logic/models/job.dart +++ b/lib/logic/models/job.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/common_enum/common_enum.dart'; +import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/utils/password_generator.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; @@ -62,23 +63,23 @@ class DeleteUserJob extends ClientJob { class ToggleJob extends ClientJob { ToggleJob({ - required this.type, + required final this.service, required final super.title, }); - final ServiceTypes type; + final Service service; @override - List get props => [...super.props, type]; + List get props => [...super.props, service]; } class ServiceToggleJob extends ToggleJob { ServiceToggleJob({ - required final super.type, + required super.service, required this.needToTurnOn, }) : super( title: - '${needToTurnOn ? "jobs.service_turn_on".tr() : "jobs.service_turn_off".tr()} ${type.title}', + '${needToTurnOn ? "jobs.service_turn_on".tr() : "jobs.service_turn_off".tr()} ${service.displayName}', ); final bool needToTurnOn; diff --git a/lib/logic/models/service.dart b/lib/logic/models/service.dart index 33475588..04c5c6d3 100644 --- a/lib/logic/models/service.dart +++ b/lib/logic/models/service.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:easy_localization/easy_localization.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'; @@ -20,6 +21,25 @@ class Service { this.url, }); + /// TODO Turn loginInfo into dynamic data, not static! + String get loginInfo { + switch (id) { + case 'mailserver': + return 'mail.login_info'.tr(); + case 'bitwarden': + return 'password_manager.login_info'.tr(); + case 'jitsi': + return 'video.login_info'.tr(); + case 'nextcloud': + return 'cloud.login_info'.tr(); + case 'pleroma': + return 'social_network.login_info'.tr(); + case 'gitea': + return 'git.login_info'.tr(); + } + return ''; + } + Service.fromGraphQL(final Query$AllServices$services$allServices service) : this( id: service.id, diff --git a/lib/ui/components/icon_status_mask/icon_status_mask.dart b/lib/ui/components/icon_status_mask/icon_status_mask.dart index cda75049..8c7a2379 100644 --- a/lib/ui/components/icon_status_mask/icon_status_mask.dart +++ b/lib/ui/components/icon_status_mask/icon_status_mask.dart @@ -4,11 +4,11 @@ import 'package:selfprivacy/logic/models/state_types.dart'; class IconStatusMask extends StatelessWidget { const IconStatusMask({ - required this.child, + required this.icon, required this.status, final super.key, }); - final Icon child; + final Widget icon; final StateType status; @@ -42,7 +42,7 @@ class IconStatusMask extends StatelessWidget { colors: colors, tileMode: TileMode.mirror, ).createShader(bounds), - child: child, + child: icon, ); } } diff --git a/lib/ui/pages/providers/providers.dart b/lib/ui/pages/providers/providers.dart index 988b609a..0de06295 100644 --- a/lib/ui/pages/providers/providers.dart +++ b/lib/ui/pages/providers/providers.dart @@ -148,12 +148,12 @@ class _Card extends StatelessWidget { children: [ IconStatusMask( status: state, - child: Icon(icon, size: 30, color: Colors.white), + icon: Icon(icon, size: 30, color: Colors.white), ), if (state != StateType.uninitialized) IconStatusMask( status: state, - child: Icon( + icon: Icon( state == StateType.stable ? Icons.check_circle_outline : state == StateType.warning diff --git a/lib/ui/pages/server_storage/storage_card.dart b/lib/ui/pages/server_storage/storage_card.dart index a18e4f86..33a23b9b 100644 --- a/lib/ui/pages/server_storage/storage_card.dart +++ b/lib/ui/pages/server_storage/storage_card.dart @@ -80,7 +80,7 @@ class StorageCard extends StatelessWidget { if (state != StateType.uninitialized) IconStatusMask( status: state, - child: Icon( + icon: Icon( diskStatus.isDiskOkay ? Icons.check_circle_outline : Icons.error_outline, diff --git a/lib/ui/pages/services/service_page.dart b/lib/ui/pages/services/service_page.dart index f4685802..6cd49f28 100644 --- a/lib/ui/pages/services/service_page.dart +++ b/lib/ui/pages/services/service_page.dart @@ -91,7 +91,7 @@ class _ServicePageState extends State { onTap: () => { context.read().createOrRemoveServiceToggleJob( ServiceToggleJob( - type: _idToLegacyType(service.id), + service: service, needToTurnOn: serviceDisabled, ), ), @@ -142,28 +142,6 @@ class _ServicePageState extends State { ], ); } - -// TODO: Get rid as soon as possible - ServiceTypes _idToLegacyType(final String serviceId) { - switch (serviceId) { - case 'mailserver': - return ServiceTypes.mailserver; - case 'jitsi': - return ServiceTypes.jitsi; - case 'bitwarden': - return ServiceTypes.bitwarden; - case 'nextcloud': - return ServiceTypes.nextcloud; - case 'pleroma': - return ServiceTypes.pleroma; - case 'gitea': - return ServiceTypes.gitea; - case 'ocserv': - return ServiceTypes.ocserv; - default: - throw Exception('wrong state'); - } - } } class ServiceStatusCard extends StatelessWidget { diff --git a/lib/ui/pages/services/services.dart b/lib/ui/pages/services/services.dart index 4909af13..22fd3c91 100644 --- a/lib/ui/pages/services/services.dart +++ b/lib/ui/pages/services/services.dart @@ -1,12 +1,14 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:selfprivacy/config/brand_theme.dart'; import 'package:selfprivacy/logic/common_enum/common_enum.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart'; import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; import 'package:selfprivacy/logic/models/job.dart'; +import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/logic/models/state_types.dart'; import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; @@ -21,11 +23,11 @@ import 'package:selfprivacy/utils/ui_helpers.dart'; import 'package:url_launcher/url_launcher.dart'; const switchableServices = [ - ServiceTypes.bitwarden, - ServiceTypes.nextcloud, - ServiceTypes.pleroma, - ServiceTypes.gitea, - ServiceTypes.ocserv, + 'bitwarden', + 'nextcloud', + 'pleroma', + 'gitea', + 'ocserv', ]; class ServicesPage extends StatefulWidget { @@ -70,13 +72,16 @@ class _ServicesPageState extends State { BrandText.body1('basis.services_title'.tr()), const SizedBox(height: 24), if (!isReady) ...[const NotReadyCard(), const SizedBox(height: 24)], - ...ServiceTypes.values + ...context + .read() + .state + .services .map( - (final t) => Padding( + (final service) => Padding( padding: const EdgeInsets.only( bottom: 30, ), - child: _Card(serviceType: t), + child: _Card(service: service), ), ) .toList() @@ -88,9 +93,9 @@ class _ServicesPageState extends State { } class _Card extends StatelessWidget { - const _Card({required this.serviceType}); + const _Card({required this.service}); - final ServiceTypes serviceType; + final Service service; @override Widget build(final BuildContext context) { final isReady = context.watch().state @@ -100,16 +105,16 @@ class _Card extends StatelessWidget { final jobsCubit = context.watch(); final jobState = jobsCubit.state; - final switchableService = switchableServices.contains(serviceType); + final switchableService = switchableServices.contains(service.id); final hasSwitchJob = switchableService && jobState is JobsStateWithJobs && jobState.clientJobList.any( - (final el) => el is ServiceToggleJob && el.type == serviceType, + (final el) => el is ServiceToggleJob && el.id == service.id, ); final isSwitchOn = isReady && - (!switchableServices.contains(serviceType) || - serviceState.isEnableByType(serviceType)); + (!switchableServices.contains(service.id) || + serviceState.isEnableByType(service)); final config = context.watch().state; final domainName = UiHelpers.getDomainName(config); @@ -117,7 +122,7 @@ class _Card extends StatelessWidget { return GestureDetector( onTap: isReady ? () => Navigator.of(context) - .push(materialRoute(ServicePage(serviceId: serviceType.name))) + .push(materialRoute(ServicePage(serviceId: service.id))) : null, child: BrandCards.big( child: Column( @@ -128,7 +133,12 @@ class _Card extends StatelessWidget { IconStatusMask( status: isSwitchOn ? StateType.stable : StateType.uninitialized, - child: Icon(serviceType.icon, size: 30, color: Colors.white), + icon: SvgPicture.string( + service.svgIcon, + width: 30.0, + height: 30.0, + color: Theme.of(context).colorScheme.onBackground, + ), ), if (isReady && switchableService) ...[ const Spacer(), @@ -138,11 +148,11 @@ class _Card extends StatelessWidget { if (hasSwitchJob) { isActive = (jobState.clientJobList.firstWhere( (final el) => - el is ServiceToggleJob && el.type == serviceType, + el is ServiceToggleJob && el.id == service.id, ) as ServiceToggleJob) .needToTurnOn; } else { - isActive = serviceState.isEnableByType(serviceType); + isActive = serviceState.isEnableByType(service); } return BrandSwitch( @@ -150,7 +160,7 @@ class _Card extends StatelessWidget { onChanged: (final value) => jobsCubit.createOrRemoveServiceToggleJob( ServiceToggleJob( - type: serviceType, + service: service, needToTurnOn: value, ), ), @@ -167,17 +177,17 @@ class _Card extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 10), - BrandText.h2(serviceType.title), + BrandText.h2(service.displayName), const SizedBox(height: 10), - if (serviceType.subdomain != '') + if (service.url != '' && service.url != null) Column( children: [ GestureDetector( onTap: () => _launchURL( - 'https://${serviceType.subdomain}.$domainName', + 'https://${service.url}', ), child: Text( - '${serviceType.subdomain}.$domainName', + '${service.url}', style: TextStyle( color: Theme.of(context).colorScheme.secondary, @@ -188,7 +198,7 @@ class _Card extends StatelessWidget { const SizedBox(height: 10), ], ), - if (serviceType == ServiceTypes.mailserver) + if (service.id == 'mailserver') Column( children: [ Text( @@ -201,9 +211,9 @@ class _Card extends StatelessWidget { const SizedBox(height: 10), ], ), - BrandText.body2(serviceType.loginInfo), + BrandText.body2(service.loginInfo), const SizedBox(height: 10), - BrandText.body2(serviceType.subtitle), + BrandText.body2(service.description), const SizedBox(height: 10), ], ),