mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-11 18:39:45 +00:00
Introduce ListTileOnSurfaceVariant and refactor TextDetails on server details screen.
This commit is contained in:
parent
3d34f0bb55
commit
5ca4ee27e3
|
@ -114,6 +114,19 @@
|
|||
"reboot_after_upgrade_hint": "Reboot without prompt after applying changes on server",
|
||||
"server_timezone": "Server timezone",
|
||||
"select_timezone": "Select timezone"
|
||||
},
|
||||
"info": {
|
||||
"server_id": "Server ID",
|
||||
"status": "Status",
|
||||
"cpu": "CPU",
|
||||
"ram": "Memory",
|
||||
"disk": "Disk local",
|
||||
"monthly_cost": "Monthly cost",
|
||||
"location": "Location",
|
||||
"core_count": {
|
||||
"one": "{} core",
|
||||
"other": "{} cores"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
|
|
|
@ -113,6 +113,22 @@
|
|||
"reboot_after_upgrade_hint": "Автоматически перезагружать сервер после применения обновлений",
|
||||
"server_timezone": "Часовой пояс сервера",
|
||||
"select_timezone": "Выберите часовой пояс"
|
||||
},
|
||||
"info": {
|
||||
"server_id": "ID сервера",
|
||||
"status": "Статус",
|
||||
"cpu": "Процессор",
|
||||
"ram": "Операивная память",
|
||||
"disk": "Диск",
|
||||
"monthly_cost": "Ежемесячная стоимость",
|
||||
"location": "Размещение",
|
||||
"core_count": {
|
||||
"one": "{} ядро",
|
||||
"two": "{} ядра",
|
||||
"few": "{} ядра",
|
||||
"many": "{} ядер",
|
||||
"other": "{} ядер"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ListTileOnSurfaceVariant extends StatelessWidget {
|
||||
const ListTileOnSurfaceVariant({
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.leadingIcon,
|
||||
this.onTap,
|
||||
this.disableSubtitleOverflow = false,
|
||||
final super.key,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final IconData? leadingIcon;
|
||||
final Function()? onTap;
|
||||
final bool disableSubtitleOverflow;
|
||||
|
||||
Widget? getSubtitle() {
|
||||
if (subtitle == null) {
|
||||
return null;
|
||||
}
|
||||
if (disableSubtitleOverflow) {
|
||||
return Text(
|
||||
subtitle!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
}
|
||||
return Text(
|
||||
subtitle!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) => ListTile(
|
||||
title: Text(title),
|
||||
subtitle: getSubtitle(),
|
||||
onTap: onTap,
|
||||
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
leading: leadingIcon != null ? Icon(leadingIcon) : null,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
);
|
||||
}
|
|
@ -15,10 +15,12 @@ import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.da
|
|||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
import 'package:selfprivacy/ui/components/list_tiles/list_tile_on_surface_variant.dart';
|
||||
import 'package:selfprivacy/ui/components/switch_block/switch_bloc.dart';
|
||||
import 'package:selfprivacy/ui/pages/server_storage/storage_card.dart';
|
||||
import 'package:selfprivacy/ui/pages/server_details/time_zone/lang.dart';
|
||||
import 'package:selfprivacy/utils/extensions/duration.dart';
|
||||
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
|
||||
import 'package:selfprivacy/utils/named_font_weight.dart';
|
||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||
import 'package:timezone/timezone.dart';
|
||||
|
|
|
@ -11,115 +11,53 @@ class _TextDetails extends StatelessWidget {
|
|||
return _TempMessage(message: 'basis.no_data'.tr());
|
||||
} else if (details is Loaded) {
|
||||
final data = details.serverInfo;
|
||||
final checkTime = details.checkTime;
|
||||
return Column(
|
||||
return FilledCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(child: BrandText.h3('providers.server.bottom_sheet.2'.tr())),
|
||||
const SizedBox(height: 10),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FractionColumnWidth(.5),
|
||||
1: FractionColumnWidth(.5),
|
||||
},
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Last check:'),
|
||||
getRowValue(formatter.format(checkTime)),
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'providers.server.bottom_sheet.2'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Server Id:'),
|
||||
getRowValue(data.id.toString()),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Status:'),
|
||||
getRowValue(
|
||||
data.status.toString().split('.')[1].toUpperCase(),
|
||||
isBold: true,
|
||||
),
|
||||
ListTileOnSurfaceVariant(
|
||||
leadingIcon: Icons.numbers_outlined,
|
||||
title: data.id.toString(),
|
||||
subtitle: 'providers.server.info.server_id'.tr(),
|
||||
),
|
||||
ListTileOnSurfaceVariant(
|
||||
leadingIcon: Icons.mode_standby_outlined,
|
||||
title: data.status.toString().split('.')[1].capitalize(),
|
||||
subtitle: 'providers.server.info.status'.tr(),
|
||||
),
|
||||
ListTileOnSurfaceVariant(
|
||||
leadingIcon: Icons.memory_outlined,
|
||||
title: 'providers.server.info.core_count'
|
||||
.plural(data.serverType.cores),
|
||||
subtitle: 'providers.server.info.cpu'.tr(),
|
||||
),
|
||||
ListTileOnSurfaceVariant(
|
||||
leadingIcon: Icons.memory_outlined,
|
||||
title: '${data.serverType.memory.toString()} GB',
|
||||
subtitle: 'providers.server.info.ram'.tr(),
|
||||
),
|
||||
ListTileOnSurfaceVariant(
|
||||
leadingIcon: Icons.euro_outlined,
|
||||
title: data.serverType.prices[1].monthly.toStringAsFixed(2),
|
||||
subtitle: 'providers.server.info.monthly_cost'.tr(),
|
||||
),
|
||||
// Server location
|
||||
ListTileOnSurfaceVariant(
|
||||
leadingIcon: Icons.location_on_outlined,
|
||||
title: '${data.location.city}, ${data.location.country}',
|
||||
subtitle: 'providers.server.info.location'.tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('CPU:'),
|
||||
getRowValue(
|
||||
data.serverType.cores.toString(),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Memory:'),
|
||||
getRowValue(
|
||||
'${data.serverType.memory.toString()} GB',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Disk Local:'),
|
||||
getRowValue(
|
||||
'${data.serverType.disk.toString()} GB',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Price monthly:'),
|
||||
getRowValue(
|
||||
data.serverType.prices[1].monthly.toString(),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Price hourly:'),
|
||||
getRowValue(
|
||||
data.serverType.prices[1].hourly.toString(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Center(child: BrandText.h3('providers.server.bottom_sheet.3'.tr())),
|
||||
const SizedBox(height: 10),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FractionColumnWidth(.5),
|
||||
1: FractionColumnWidth(.5),
|
||||
},
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Country:'),
|
||||
getRowValue(
|
||||
data.location.country,
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('City:'),
|
||||
getRowValue(data.location.city),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
getRowTitle('Description:'),
|
||||
getRowValue(data.location.description),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
throw Exception('wrong state');
|
||||
|
|
|
@ -133,12 +133,10 @@ class _UserLogins extends StatelessWidget {
|
|||
Widget build(final BuildContext context) => FilledCard(
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text('${user.login}@$domainName'),
|
||||
subtitle: Text('users.email_login'.tr()),
|
||||
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
leading: const Icon(Icons.alternate_email_outlined),
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
ListTileOnSurfaceVariant(
|
||||
title: '${user.login}@$domainName',
|
||||
subtitle: 'users.email_login'.tr(),
|
||||
leadingIcon: Icons.alternate_email_outlined,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -156,18 +154,13 @@ class _SshKeysCard extends StatelessWidget {
|
|||
Widget build(final BuildContext context) => FilledCard(
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text('ssh.title'.tr()),
|
||||
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
ListTileOnSurfaceVariant(
|
||||
title: 'ssh.title'.tr(),
|
||||
),
|
||||
const Divider(height: 0),
|
||||
ListTile(
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
title: Text(
|
||||
'ssh.create'.tr(),
|
||||
),
|
||||
leading: const Icon(Icons.add_circle_outlined),
|
||||
ListTileOnSurfaceVariant(
|
||||
title: 'ssh.create'.tr(),
|
||||
leadingIcon: Icons.add_circle_outline,
|
||||
onTap: () {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
|
@ -188,15 +181,11 @@ class _SshKeysCard extends StatelessWidget {
|
|||
final keyName = key.split(' ').length > 2
|
||||
? key.split(' ')[2]
|
||||
: 'ssh.no_key_name'.tr();
|
||||
return ListTile(
|
||||
textColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
title: Text('$keyName ($keyType)'),
|
||||
return ListTileOnSurfaceVariant(
|
||||
title: '$keyName ($keyType)',
|
||||
disableSubtitleOverflow: true,
|
||||
// do not overflow text
|
||||
subtitle: Text(
|
||||
publicKey,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: publicKey,
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
|
|
|
@ -20,6 +20,7 @@ import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.da
|
|||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
|
||||
import 'package:selfprivacy/ui/components/list_tiles/list_tile_on_surface_variant.dart';
|
||||
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
||||
import 'package:selfprivacy/utils/ui_helpers.dart';
|
||||
|
||||
|
|
4
lib/utils/extensions/string_extensions.dart
Normal file
4
lib/utils/extensions/string_extensions.dart
Normal file
|
@ -0,0 +1,4 @@
|
|||
extension StringExtension on String {
|
||||
String capitalize() =>
|
||||
'${this[0].toUpperCase()}${substring(1).toLowerCase()}';
|
||||
}
|
Loading…
Reference in a new issue