Introduce ListTileOnSurfaceVariant and refactor TextDetails on server details screen.

pull/116/head
Inex Code 2022-09-18 16:24:17 +03:00
parent 3d34f0bb55
commit 5ca4ee27e3
8 changed files with 139 additions and 132 deletions

View File

@ -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": {

View File

@ -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": {

View File

@ -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,
);
}

View File

@ -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';

View File

@ -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(
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)),
],
return FilledCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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,
),
],
),
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),
],
),
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(),
),
],
),
);
} else {
throw Exception('wrong state');

View File

@ -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,

View File

@ -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';

View File

@ -0,0 +1,4 @@
extension StringExtension on String {
String capitalize() =>
'${this[0].toUpperCase()}${substring(1).toLowerCase()}';
}