mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-11-14 12:43:16 +00:00
283 lines
9.4 KiB
Dart
283 lines
9.4 KiB
Dart
import 'package:auto_route/auto_route.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:gap/gap.dart';
|
|
import 'package:selfprivacy/logic/bloc/tokens/tokens_bloc.dart';
|
|
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
|
import 'package:selfprivacy/logic/models/hive/dns_provider_credential.dart';
|
|
import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart';
|
|
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
|
import 'package:selfprivacy/ui/components/list_tiles/list_tile_on_surface_variant.dart';
|
|
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
|
import 'package:selfprivacy/ui/router/router.dart';
|
|
|
|
@RoutePage()
|
|
class TokensPage extends StatelessWidget {
|
|
const TokensPage({super.key});
|
|
|
|
@override
|
|
Widget build(final BuildContext context) {
|
|
final TokensState state = context.watch<TokensBloc>().state;
|
|
return BrandHeroScreen(
|
|
heroTitle: 'tokens.title'.tr(),
|
|
heroSubtitle: 'tokens.description'.tr(),
|
|
heroIcon: Icons.token_outlined,
|
|
children: [
|
|
FilledCard(
|
|
child: Column(
|
|
children: [
|
|
ListTileOnSurfaceVariant(
|
|
title: 'tokens.server_provider_tokens'.tr(),
|
|
),
|
|
const Divider(height: 0),
|
|
if (state.serverProviderCredentials.isEmpty)
|
|
ListTileOnSurfaceVariant(
|
|
title: 'tokens.no_tokens'.tr(),
|
|
leadingIcon: Icons.warning_amber_outlined,
|
|
),
|
|
Column(
|
|
children: state.serverProviderCredentials
|
|
.map(
|
|
(final serverProviderCredential) =>
|
|
_ServerProviderListItem(
|
|
serverProviderCredential: serverProviderCredential,
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
if (state.serversWithoutProviderCredentials.isNotEmpty)
|
|
Column(
|
|
children: [
|
|
const Divider(height: 0),
|
|
Column(
|
|
children: state.serversWithoutProviderCredentials
|
|
.map(
|
|
(final server) => ListTileOnSurfaceVariant(
|
|
title: 'tokens.server_without_token'.tr(
|
|
namedArgs: {
|
|
'server_domain': server.domain.domainName,
|
|
'provider': server
|
|
.hostingDetails.provider.displayName,
|
|
},
|
|
),
|
|
subtitle: 'tokens.tap_to_add_token'.tr(),
|
|
leadingIcon: Icons.add_circle_outline,
|
|
onTap: () => context.router.push(
|
|
AddServerProviderTokenRoute(
|
|
server: server,
|
|
),
|
|
),
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Gap(16),
|
|
FilledCard(
|
|
child: Column(
|
|
children: [
|
|
ListTileOnSurfaceVariant(
|
|
title: 'tokens.dns_provider_tokens'.tr(),
|
|
),
|
|
const Divider(height: 0),
|
|
if (state.dnsProviderCredentials.isEmpty)
|
|
ListTileOnSurfaceVariant(
|
|
title: 'tokens.no_tokens'.tr(),
|
|
leadingIcon: Icons.warning_amber_outlined,
|
|
),
|
|
Column(
|
|
children: state.dnsProviderCredentials
|
|
.map(
|
|
(final dnsProviderCredential) => _DnsProviderListItem(
|
|
dnsProviderCredential: dnsProviderCredential,
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Gap(16),
|
|
FilledCard(
|
|
child: Column(
|
|
children: [
|
|
ListTileOnSurfaceVariant(
|
|
title: 'tokens.backup_provider_tokens'.tr(),
|
|
),
|
|
const Divider(height: 0),
|
|
if (state.backupsCredentials.isEmpty)
|
|
ListTileOnSurfaceVariant(
|
|
title: 'tokens.no_tokens'.tr(),
|
|
leadingIcon: Icons.warning_amber_outlined,
|
|
),
|
|
Column(
|
|
children: state.backupsCredentials
|
|
.map(
|
|
(final backupProviderCredential) =>
|
|
_BackupProviderListItem(
|
|
backupProviderCredential: backupProviderCredential,
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Gap(16),
|
|
ListTile(
|
|
title: Text('tokens.check_again'.tr()),
|
|
onTap: (state is TokensInitial)
|
|
? null
|
|
: () => context.read<TokensBloc>().add(const RevalidateTokens()),
|
|
leading: const Icon(Icons.refresh_outlined),
|
|
enabled: state is! TokensInitial,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ServerProviderListItem extends StatelessWidget {
|
|
const _ServerProviderListItem({
|
|
required this.serverProviderCredential,
|
|
});
|
|
|
|
final TokenStatusWrapper<ServerProviderCredential> serverProviderCredential;
|
|
|
|
String getSubtitle(final BuildContext context) {
|
|
String subtitle = '';
|
|
subtitle += serverProviderCredential.status.statusText;
|
|
if (serverProviderCredential.data.associatedServerIds.isNotEmpty) {
|
|
final String serverDomains =
|
|
serverProviderCredential.data.associatedServerIds
|
|
.map(
|
|
(final int serverId) => context
|
|
.read<TokensBloc>()
|
|
.state
|
|
.getServerById(serverId)
|
|
.domain
|
|
.domainName,
|
|
)
|
|
.join(', ');
|
|
subtitle +=
|
|
'. ${'tokens.used_by'.tr(namedArgs: {'servers': serverDomains})}';
|
|
}
|
|
return subtitle;
|
|
}
|
|
|
|
@override
|
|
Widget build(final BuildContext context) => Column(
|
|
children: [
|
|
ListTileOnSurfaceVariant(
|
|
title:
|
|
'${serverProviderCredential.data.provider.displayName} (${serverProviderCredential.data.tokenPrefix}...)',
|
|
subtitle: getSubtitle(context),
|
|
leadingIcon: serverProviderCredential.status.icon,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
class _DnsProviderListItem extends StatelessWidget {
|
|
const _DnsProviderListItem({
|
|
required this.dnsProviderCredential,
|
|
});
|
|
|
|
final TokenStatusWrapper<DnsProviderCredential> dnsProviderCredential;
|
|
|
|
String getSubtitle(final BuildContext context) {
|
|
String subtitle = '';
|
|
subtitle += dnsProviderCredential.status.statusText;
|
|
if (dnsProviderCredential.data.associatedDomainNames.isNotEmpty) {
|
|
final String serverDomains =
|
|
dnsProviderCredential.data.associatedDomainNames.join(', ');
|
|
subtitle +=
|
|
'. ${'tokens.used_by'.tr(namedArgs: {'servers': serverDomains})}';
|
|
}
|
|
return subtitle;
|
|
}
|
|
|
|
@override
|
|
Widget build(final BuildContext context) => Column(
|
|
children: [
|
|
ListTileOnSurfaceVariant(
|
|
title:
|
|
'${dnsProviderCredential.data.provider.displayName} (${dnsProviderCredential.data.tokenPrefix}...)',
|
|
subtitle: getSubtitle(context),
|
|
leadingIcon: dnsProviderCredential.status.icon,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
class _BackupProviderListItem extends StatelessWidget {
|
|
const _BackupProviderListItem({
|
|
required this.backupProviderCredential,
|
|
});
|
|
|
|
final TokenStatusWrapper<BackupsCredential> backupProviderCredential;
|
|
|
|
String getSubtitle(final BuildContext context) {
|
|
String subtitle = '';
|
|
subtitle += backupProviderCredential.status.statusText;
|
|
return subtitle;
|
|
}
|
|
|
|
@override
|
|
Widget build(final BuildContext context) => Column(
|
|
children: [
|
|
ListTileOnSurfaceVariant(
|
|
title:
|
|
'${backupProviderCredential.data.provider.name} (${backupProviderCredential.data.tokenPrefix})',
|
|
subtitle: getSubtitle(context),
|
|
leadingIcon: backupProviderCredential.status.icon,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
extension on TokenStatus {
|
|
String get statusText {
|
|
switch (this) {
|
|
case TokenStatus.valid:
|
|
return 'tokens.valid'.tr();
|
|
case TokenStatus.invalid:
|
|
return 'tokens.invalid'.tr();
|
|
case TokenStatus.noAccess:
|
|
return 'tokens.no_access'.tr();
|
|
case TokenStatus.loading:
|
|
return 'tokens.loading'.tr();
|
|
}
|
|
}
|
|
|
|
IconData get icon {
|
|
switch (this) {
|
|
case TokenStatus.valid:
|
|
return Icons.check_circle_outlined;
|
|
case TokenStatus.invalid:
|
|
return Icons.error_outline_outlined;
|
|
case TokenStatus.noAccess:
|
|
return Icons.no_encryption_outlined;
|
|
case TokenStatus.loading:
|
|
return Icons.sync_outlined;
|
|
}
|
|
}
|
|
}
|
|
|
|
extension on ServerProviderCredential {
|
|
String get tokenPrefix => tokenId ?? token.substring(0, 8);
|
|
}
|
|
|
|
extension on DnsProviderCredential {
|
|
String get tokenPrefix => tokenId ?? token.substring(0, 8);
|
|
}
|
|
|
|
extension on BackupsCredential {
|
|
String get tokenPrefix => keyId;
|
|
}
|