diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart
index 61a8af82..ef966d3f 100644
--- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart
+++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart
@@ -443,6 +443,12 @@ abstract class S {
/// **'Files'**
String get files;
+ /// No description provided for @font.
+ ///
+ /// In en, this message translates to:
+ /// **'Font'**
+ String get font;
+
/// No description provided for @fontSize.
///
/// In en, this message translates to:
@@ -1007,11 +1013,11 @@ abstract class S {
/// **'Are you sure to delete server [{server}]?'**
String sureToDeleteServer(Object server);
- /// No description provided for @termTheme.
+ /// No description provided for @theme.
///
/// In en, this message translates to:
- /// **'Terminal theme'**
- String get termTheme;
+ /// **'Theme'**
+ String get theme;
/// No description provided for @themeMode.
///
diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart
index 8013f6c5..efb81504 100644
--- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart
+++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart
@@ -192,6 +192,9 @@ class SDe extends S {
@override
String get files => 'Dateien';
+ @override
+ String get font => 'Schriftarten';
+
@override
String get fontSize => 'Schriftgröße';
@@ -495,7 +498,7 @@ class SDe extends S {
}
@override
- String get termTheme => 'Farbschema des Terminals';
+ String get theme => 'Themen';
@override
String get themeMode => 'Thememodus';
diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart
index de91a140..4b309dc6 100644
--- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart
+++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart
@@ -192,6 +192,9 @@ class SEn extends S {
@override
String get files => 'Files';
+ @override
+ String get font => 'Font';
+
@override
String get fontSize => 'Font size';
@@ -495,7 +498,7 @@ class SEn extends S {
}
@override
- String get termTheme => 'Terminal theme';
+ String get theme => 'Theme';
@override
String get themeMode => 'Theme mode';
diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart
index 19fe19dc..fe8fbd30 100644
--- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart
+++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart
@@ -192,6 +192,9 @@ class SZh extends S {
@override
String get files => '文件';
+ @override
+ String get font => '字体';
+
@override
String get fontSize => '字体大小';
@@ -495,7 +498,7 @@ class SZh extends S {
}
@override
- String get termTheme => '终端主题';
+ String get theme => '主题';
@override
String get themeMode => '主题模式';
diff --git a/README.md b/README.md
index 7773d513..a7facf1a 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ English | [简体中文](README_zh.md)
-A Flutter project which provide charts to display server status and tools to manage server.
+A Flutter project which provide charts to display Linux[](../../issues/43) server status and tools to manage server.
Especially thanks to dartssh2 & xterm.dart.
diff --git a/lib/data/model/server/cpu_status.dart b/lib/data/model/server/cpu_status.dart
index 297923c6..4b6a69aa 100644
--- a/lib/data/model/server/cpu_status.dart
+++ b/lib/data/model/server/cpu_status.dart
@@ -1,8 +1,7 @@
class CpuStatus {
List _pre;
List _now;
- String temp;
- CpuStatus(this._pre, this._now, this.temp);
+ CpuStatus(this._pre, this._now);
double usedPercent({int coreIdx = 0}) {
if (_now.length != _pre.length) return 0;
@@ -12,10 +11,9 @@ class CpuStatus {
return used.isNaN ? 0 : 100 - used * 100;
}
- void update(List newStatus, String newTemp) {
+ void update(List newStatus) {
_pre = _now;
_now = newStatus;
- temp = newTemp;
}
int get coresCount => _now.length;
@@ -96,27 +94,3 @@ List parseCPU(String raw) {
}
return cpus;
}
-
-final cpuTempReg = RegExp(r'(x86_pkg_temp|cpu_thermal)');
-
-String parseCPUTemp(String type, String value) {
- const noMatch = "/sys/class/thermal/thermal_zone*/type";
- // Not support to get CPU temperature
- if (type.contains(noMatch) || value.isEmpty || type.isEmpty) {
- return '';
- }
- final split = type.split('\n');
- // if no match, use idx 0
- int idx = 0;
- for (var item in split) {
- if (item.contains(cpuTempReg)) {
- break;
- }
- idx++;
- }
- final valueSplited = value.split('\n');
- if (idx >= valueSplited.length) return '';
- final temp = int.tryParse(valueSplited[idx].trim());
- if (temp == null) return '';
- return '${(temp / 1000).toStringAsFixed(1)}°C';
-}
diff --git a/lib/data/model/server/server_status.dart b/lib/data/model/server/server_status.dart
index bb399229..e8bde5e7 100644
--- a/lib/data/model/server/server_status.dart
+++ b/lib/data/model/server/server_status.dart
@@ -1,3 +1,5 @@
+import 'package:toolbox/data/model/server/temp.dart';
+
import 'cpu_status.dart';
import 'disk_info.dart';
import 'memory.dart';
@@ -13,6 +15,7 @@ class ServerStatus {
List disk;
ConnStatus tcp;
NetSpeed netSpeed;
+ Temperatures temps;
String? failedInfo;
ServerStatus({
@@ -24,6 +27,7 @@ class ServerStatus {
required this.tcp,
required this.netSpeed,
required this.swap,
+ required this.temps,
this.failedInfo,
});
}
diff --git a/lib/data/model/server/server_status_update_req.dart b/lib/data/model/server/server_status_update_req.dart
index 755faa57..06492e24 100644
--- a/lib/data/model/server/server_status_update_req.dart
+++ b/lib/data/model/server/server_status_update_req.dart
@@ -24,6 +24,7 @@ extension _SegmentsExt on List {
Future getStatus(ServerStatusUpdateReq req) async {
final net = parseNetSpeed(req.segments.at(CmdType.net));
req.ss.netSpeed.update(net);
+
final sys = _parseSysVer(
req.segments.at(CmdType.sys),
req.segments.at(CmdType.host),
@@ -32,22 +33,29 @@ Future getStatus(ServerStatusUpdateReq req) async {
if (sys != null) {
req.ss.sysVer = sys;
}
+
final cpus = parseCPU(req.segments.at(CmdType.cpu));
- final cpuTemp = parseCPUTemp(
+ req.ss.cpu.update(cpus);
+
+ req.ss.temps.parse(
req.segments.at(CmdType.tempType),
req.segments.at(CmdType.tempVal),
);
- req.ss.cpu.update(cpus, cpuTemp);
+
final tcp = parseConn(req.segments.at(CmdType.conn));
if (tcp != null) {
req.ss.tcp = tcp;
}
+
req.ss.disk = parseDisk(req.segments.at(CmdType.disk));
+
req.ss.mem = parseMem(req.segments.at(CmdType.mem));
+
final uptime = _parseUpTime(req.segments.at(CmdType.uptime));
if (uptime != null) {
req.ss.uptime = uptime;
}
+
req.ss.swap = parseSwap(req.segments.at(CmdType.mem));
return req.ss;
}
diff --git a/lib/data/model/server/temp.dart b/lib/data/model/server/temp.dart
new file mode 100644
index 00000000..9e3e1a0f
--- /dev/null
+++ b/lib/data/model/server/temp.dart
@@ -0,0 +1,61 @@
+class Temperatures {
+ final Map _map = {};
+
+ Temperatures();
+
+ void parse(String type, String value) {
+ const noMatch = "/sys/class/thermal/thermal_zone*/type";
+ // Not support to get CPU temperature
+ if (type.contains(noMatch) || value.isEmpty || type.isEmpty) {
+ return;
+ }
+ final typeSplited = type.split('\n');
+ final valueSplited = value.split('\n');
+ if (typeSplited.length != valueSplited.length) {
+ return;
+ }
+ for (var i = 0; i < typeSplited.length; i++) {
+ final t = typeSplited[i];
+ final v = valueSplited[i];
+ if (t.isEmpty || v.isEmpty) {
+ continue;
+ }
+ final name = t.split('/').last;
+ final temp = double.tryParse(v);
+ if (temp == null) {
+ continue;
+ }
+ _map[name] = temp / 1000;
+ }
+ }
+
+ void add(String name, double value) {
+ _map[name] = value;
+ }
+
+ double? get(String name) {
+ return _map[name];
+ }
+
+ Iterable get devices {
+ return _map.keys;
+ }
+
+ bool get isEmpty {
+ return _map.isEmpty;
+ }
+
+ double? get first {
+ if (_map.isEmpty) {
+ return null;
+ }
+ for (final key in _map.keys) {
+ if (cpuTempReg.hasMatch(key)) {
+ return _map[key];
+ }
+ }
+ return _map.values.first;
+ }
+}
+
+final cpuTempReg = RegExp(r'(x86_pkg_temp|cpu_thermal)');
diff --git a/lib/data/provider/debug.dart b/lib/data/provider/debug.dart
index b0dd8c06..f9607c1d 100644
--- a/lib/data/provider/debug.dart
+++ b/lib/data/provider/debug.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:toolbox/data/res/ui.dart';
import '../../data/res/misc.dart';
@@ -51,7 +52,7 @@ class DebugProvider extends ChangeNotifier {
void _addWidget(Widget widget) {
widgets.add(widget);
- widgets.add(const SizedBox(height: 13));
+ widgets.add(height13);
if (widgets.length > maxDebugLogLines) {
widgets.removeRange(0, widgets.length - maxDebugLogLines);
}
diff --git a/lib/data/res/status.dart b/lib/data/res/status.dart
index 2fffcf39..a017a695 100644
--- a/lib/data/res/status.dart
+++ b/lib/data/res/status.dart
@@ -1,3 +1,5 @@
+import 'package:toolbox/data/model/server/temp.dart';
+
import '../model/server/cpu_status.dart';
import '../model/server/disk_info.dart';
import '../model/server/memory.dart';
@@ -24,7 +26,6 @@ OneTimeCpuStatus get _initOneTimeCpuStatus => OneTimeCpuStatus(
CpuStatus get initCpuStatus => CpuStatus(
[_initOneTimeCpuStatus],
[_initOneTimeCpuStatus],
- '',
);
NetSpeedPart get _initNetSpeedPart => NetSpeedPart(
'',
@@ -50,4 +51,5 @@ ServerStatus get initStatus => ServerStatus(
tcp: ConnStatus(0, 0, 0, 0),
netSpeed: initNetSpeed,
swap: _initSwap,
+ temps: Temperatures(),
);
diff --git a/lib/data/res/ui.dart b/lib/data/res/ui.dart
index 3ac0b4e6..f6d21c6b 100644
--- a/lib/data/res/ui.dart
+++ b/lib/data/res/ui.dart
@@ -22,6 +22,7 @@ const roundRectCardPadding = EdgeInsets.symmetric(horizontal: 17, vertical: 13);
/// SizedBox
+const placeholder = SizedBox.shrink();
const height13 = SizedBox(height: 13);
const width13 = SizedBox(width: 13);
const width7 = SizedBox(width: 7);
diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb
index 5b41cbbd..20745a3c 100644
--- a/lib/l10n/app_de.arb
+++ b/lib/l10n/app_de.arb
@@ -57,6 +57,7 @@
"fileNotExist": "{file} existiert nicht",
"fileTooLarge": "Datei '{file}' ist zu groß {size}, max {sizeMax}",
"files": "Dateien",
+ "font": "Schriftarten",
"fontSize": "Schriftgröße",
"foundNUpdate": "Update {count} gefunden",
"getPushTokenFailed": "Push-Token kann nicht abgerufen werden",
@@ -151,7 +152,7 @@
"sureDirEmpty": "Stelle sicher, dass der Ordner leer ist.",
"sureNoPwd": "Bist du sicher, dass du kein Passwort verwenden willst?",
"sureToDeleteServer": "Bist du sicher, dass du [{server}] löschen willst?",
- "termTheme": "Farbschema des Terminals",
+ "theme": "Themen",
"themeMode": "Thememodus",
"times": "x",
"ttl": "ttl",
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index d7a83682..555259bd 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -57,6 +57,7 @@
"fileNotExist": "{file} not exist",
"fileTooLarge": "File '{file}' too large {size}, max {sizeMax}",
"files": "Files",
+ "font": "Font",
"fontSize": "Font size",
"foundNUpdate": "Found {count} update",
"getPushTokenFailed": "Can't fetch push token",
@@ -151,7 +152,7 @@
"sureDirEmpty": "Make sure dir is empty.",
"sureNoPwd": "Are you sure to use no password?",
"sureToDeleteServer": "Are you sure to delete server [{server}]?",
- "termTheme": "Terminal theme",
+ "theme": "Theme",
"themeMode": "Theme mode",
"times": "Times",
"ttl": "ttl",
diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb
index 41670f3c..6a26070d 100644
--- a/lib/l10n/app_zh.arb
+++ b/lib/l10n/app_zh.arb
@@ -57,6 +57,7 @@
"fileNotExist": "{file} 不存在",
"fileTooLarge": "文件 '{file}' 过大 '{size}',超过了 {sizeMax}",
"files": "文件",
+ "font": "字体",
"fontSize": "字体大小",
"foundNUpdate": "找到 {count} 个更新",
"getPushTokenFailed": "未能获取到推送token",
@@ -151,7 +152,7 @@
"sureDirEmpty": "请确保文件夹为空",
"sureNoPwd": "确认使用无密码?",
"sureToDeleteServer": "你确定要删除服务器 [{server}] 吗?",
- "termTheme": "终端主题",
+ "theme": "主题",
"themeMode": "主题模式",
"times": "次",
"ttl": "缓存时间",
diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart
index 570a620f..f6e6c17e 100644
--- a/lib/view/page/backup.dart
+++ b/lib/view/page/backup.dart
@@ -55,9 +55,7 @@ class BackupPage extends StatelessWidget {
textAlign: TextAlign.center,
),
),
- const SizedBox(
- height: 107,
- ),
+ const SizedBox(height: 107),
_buildCard(s.restore, Icons.download, media, () async {
final path = await pickOneFile();
if (path == null) {
@@ -72,12 +70,12 @@ class BackupPage extends StatelessWidget {
final text = await file.readAsString();
_import(text, context, s);
}),
- const SizedBox(height: 17),
+ height13,
const SizedBox(
width: 37,
child: Divider(),
),
- const SizedBox(height: 17),
+ height13,
_buildCard(
s.backup,
Icons.file_upload,
@@ -122,7 +120,7 @@ class BackupPage extends StatelessWidget {
icon,
color: textColor,
),
- const SizedBox(width: 7),
+ width7,
Text(text, style: TextStyle(color: textColor)),
],
),
diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart
index 3767352e..bfd5d4e7 100644
--- a/lib/view/page/convert.dart
+++ b/lib/view/page/convert.dart
@@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
+import 'package:toolbox/data/res/ui.dart';
import '../../core/utils/ui.dart';
import '../widget/input_field.dart';
@@ -48,7 +49,7 @@ class _ConvertPageState extends State
controller: ScrollController(),
child: Column(
children: [
- const SizedBox(height: 13),
+ height13,
_buildInputTop(),
_buildMiddleBtns(),
_buildResult(),
diff --git a/lib/view/page/docker.dart b/lib/view/page/docker.dart
index 142d9ea6..5eae5dd3 100644
--- a/lib/view/page/docker.dart
+++ b/lib/view/page/docker.dart
@@ -277,7 +277,7 @@ class _DockerManagePageState extends State {
Widget _buildImages() {
if (_docker.images == null) {
- return const SizedBox();
+ return placeholder;
}
final items = _docker.images!
.map(
@@ -336,7 +336,7 @@ class _DockerManagePageState extends State {
}
Widget _buildLoading() {
- if (!_docker.isBusy) return const SizedBox();
+ if (!_docker.isBusy) return placeholder;
return Padding(
padding: const EdgeInsets.all(17),
child: Column(
@@ -344,7 +344,7 @@ class _DockerManagePageState extends State {
const Center(
child: CircularProgressIndicator(),
),
- const SizedBox(height: 17),
+ height13,
Text(_docker.runLog ?? '...'),
],
),
@@ -353,7 +353,7 @@ class _DockerManagePageState extends State {
Widget _buildEditHost() {
if (_docker.items!.isNotEmpty || _docker.images!.isNotEmpty) {
- return const SizedBox();
+ return placeholder;
}
return Padding(
padding: const EdgeInsets.fromLTRB(17, 17, 17, 0),
diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart
index 7102d099..734f56ee 100644
--- a/lib/view/page/ping.dart
+++ b/lib/view/page/ping.dart
@@ -53,7 +53,7 @@ class _PingPageState extends State
padding: const EdgeInsets.symmetric(horizontal: 7),
child: Column(
children: [
- const SizedBox(height: 13),
+ height13,
Input(
controller: _textEditingController,
hint: s.inputDomainHere,
diff --git a/lib/view/page/pkg.dart b/lib/view/page/pkg.dart
index a281171b..c63d5b07 100644
--- a/lib/view/page/pkg.dart
+++ b/lib/view/page/pkg.dart
@@ -133,7 +133,7 @@ class _PkgManagePageState extends State
Widget _buildFAB(PkgProvider pkg) {
if (pkg.isBusy || (pkg.upgradeable?.isEmpty ?? true)) {
- return const SizedBox();
+ return placeholder;
}
return FloatingActionButton(
onPressed: () {
diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart
index d3a46aae..cfefbb65 100644
--- a/lib/view/page/private_key/edit.dart
+++ b/lib/view/page/private_key/edit.dart
@@ -42,13 +42,13 @@ class _PrivateKeyEditPageState extends State
late PrivateKeyProvider _provider;
late S _s;
- Widget _loading = const SizedBox();
+ Widget _loading = placeholder;
@override
void initState() {
super.initState();
_provider = locator();
- _loading = const SizedBox();
+ _loading = placeholder;
}
@override
@@ -79,7 +79,7 @@ class _PrivateKeyEditPageState extends State
context.pop();
},
icon: const Icon(Icons.delete))
- : const SizedBox()
+ : placeholder
],
);
}
@@ -112,7 +112,7 @@ class _PrivateKeyEditPageState extends State
rethrow;
} finally {
setState(() {
- _loading = const SizedBox();
+ _loading = placeholder;
});
}
if (widget.info != null) {
diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart
index c719469e..8611abc9 100644
--- a/lib/view/page/server/detail.dart
+++ b/lib/view/page/server/detail.dart
@@ -60,47 +60,38 @@ class _ServerDetailPageState extends State
body: ListView(
padding: const EdgeInsets.all(13),
children: [
- ...(_buildLinuxIcon(si.status.sysVer) ?? []),
+ _buildLinuxIcon(si.status.sysVer),
_buildUpTimeAndSys(si.status),
_buildCPUView(si.status),
_buildMemView(si.status),
_buildSwapView(si.status),
_buildDiskView(si.status),
_buildNetView(si.status.netSpeed),
- // avoid the hieght of navigation bar
+ _buildTemperature(si.status),
+ // height of navigation bar
SizedBox(height: _media.padding.bottom),
],
),
);
}
- List? _buildLinuxIcon(String sysVer) {
- if (!_showDistLogo) return null;
+ Widget _buildLinuxIcon(String sysVer) {
+ if (!_showDistLogo) return placeholder;
final iconPath = sysVer.dist?.iconPath;
- if (iconPath == null) return null;
- return [
- SizedBox(height: _media.size.height * 0.03),
- ConstrainedBox(
- constraints: BoxConstraints(
- maxHeight: _media.size.height * 0.13,
- maxWidth: _media.size.width * 0.6,
- ),
- child: Image.asset(
- iconPath,
- fit: BoxFit.contain,
- ),
+ if (iconPath == null) return placeholder;
+ return ConstrainedBox(
+ constraints: BoxConstraints(
+ maxHeight: _media.size.height * 0.13,
+ maxWidth: _media.size.width * 0.6,
),
- SizedBox(height: _media.size.height * 0.03),
- ];
+ child: Image.asset(
+ iconPath,
+ fit: BoxFit.contain,
+ ),
+ );
}
Widget _buildCPUView(ServerStatus ss) {
- final tempWidget = ss.cpu.temp.isEmpty
- ? const SizedBox()
- : Text(
- ss.cpu.temp,
- style: textSize13Grey,
- );
return RoundRectCard(
Padding(
padding: roundRectCardPadding,
@@ -108,16 +99,10 @@ class _ServerDetailPageState extends State
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Row(
- children: [
- Text(
- '${ss.cpu.usedPercent(coreIdx: 0).toInt()}%',
- style: textSize27,
- textScaleFactor: 1.0,
- ),
- width7,
- tempWidget
- ],
+ Text(
+ '${ss.cpu.usedPercent(coreIdx: 0).toInt()}%',
+ style: textSize27,
+ textScaleFactor: 1.0,
),
Row(
children: [
@@ -244,7 +229,7 @@ class _ServerDetailPageState extends State
}
Widget _buildSwapView(ServerStatus ss) {
- if (ss.swap.total == 0) return const SizedBox();
+ if (ss.swap.total == 0) return placeholder;
final used = ss.swap.usedPercent * 100;
final cached = ss.swap.cached / ss.swap.total * 100;
return RoundRectCard(
@@ -396,5 +381,40 @@ class _ServerDetailPageState extends State
);
}
+ Widget _buildTemperature(ServerStatus ss) {
+ if (ss.temps.isEmpty) {
+ return placeholder;
+ }
+ final List children = [
+ const Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Icon(Icons.device_hub, size: 17),
+ Icon(Icons.arrow_downward, size: 17),
+ ],
+ ),
+ const Padding(padding: EdgeInsets.symmetric(vertical: 3), child: Divider(height: 7),),
+ ];
+ children.addAll(ss.temps.devices.map((key) => Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ key,
+ style: textSize11,
+ textScaleFactor: 1.0,
+ ),
+ Text(
+ '${ss.temps.get(key)}°C',
+ style: textSize11,
+ textScaleFactor: 1.0,
+ ),
+ ],
+ )));
+ return RoundRectCard(Padding(
+ padding: roundRectCardPadding,
+ child: Column(children: children),
+ ));
+ }
+
static const _ignorePath = ['udev', 'tmpfs', 'devtmpfs'];
}
diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart
index 4020e978..37110d28 100644
--- a/lib/view/page/server/edit.dart
+++ b/lib/view/page/server/edit.dart
@@ -96,7 +96,7 @@ class _ServerEditPageState extends State with AfterLayoutMixin {
return AppBar(
title: Text(_s.edit, style: textSize18),
actions: [
- widget.spi != null ? delBtn : const SizedBox(),
+ widget.spi != null ? delBtn : placeholder,
],
);
}
@@ -165,8 +165,8 @@ class _ServerEditPageState extends State with AfterLayoutMixin {
hint: _s.pwd,
onSubmitted: (_) => {},
)
- : const SizedBox(),
- usePublicKey ? _buildKeyAuth() : const SizedBox()
+ : placeholder,
+ usePublicKey ? _buildKeyAuth() : placeholder
],
),
);
diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart
index 4407b879..1f8b2f01 100644
--- a/lib/view/page/server/tab.dart
+++ b/lib/view/page/server/tab.dart
@@ -108,20 +108,20 @@ class _ServerPageState extends State
Widget _buildEachServerCard(Server? si) {
if (si == null) {
- return const SizedBox();
+ return placeholder;
}
- return RoundRectCard(
- GestureDetector(
- child: Padding(
+ return GestureDetector(
+ key: Key(si.spi.id),
+ onTap: () => AppRoute(
+ ServerDetailPage(si.spi.id),
+ 'server detail page',
+ ).go(context),
+ child: RoundRectCard(
+ Padding(
padding: const EdgeInsets.all(13),
child: _buildRealServerCard(si.status, si.state, si.spi),
),
- onTap: () => AppRoute(
- ServerDetailPage(si.spi.id),
- 'server detail page',
- ).go(context),
),
- key: Key(si.spi.id),
);
}
@@ -136,9 +136,7 @@ class _ServerPageState extends State
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildServerCardTitle(ss, cs, spi),
- const SizedBox(
- height: 17,
- ),
+ height13,
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
@@ -149,7 +147,7 @@ class _ServerPageState extends State
'Total:\n${rootDisk.size}', 'Used:\n${rootDisk.usedPercent}%')
],
),
- const SizedBox(height: 13),
+ height13,
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
@@ -169,9 +167,6 @@ class _ServerPageState extends State
ServerState cs,
ServerPrivateInfo spi,
) {
- final topRightStr =
- getTopRightStr(cs, ss.cpu.temp, ss.uptime, ss.failedInfo);
- final hasError = cs == ServerState.failed && ss.failedInfo != null;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 7),
child: Row(
@@ -194,32 +189,8 @@ class _ServerPageState extends State
),
Row(
children: [
- hasError
- ? GestureDetector(
- onTap: () => showRoundDialog(
- context: context,
- title: Text(_s.error),
- child: Text(ss.failedInfo ?? _s.unknownError),
- actions: [
- TextButton(
- onPressed: () => copy2Clipboard(
- ss.failedInfo ?? _s.unknownError),
- child: Text(_s.copy),
- )
- ],
- ),
- child: Text(
- _s.viewErr,
- style: textSize12Grey,
- textScaleFactor: 1.0,
- ),
- )
- : Text(
- topRightStr,
- style: textSize12Grey,
- textScaleFactor: 1.0,
- ),
- const SizedBox(width: 9),
+ _buildTopRightText(ss, cs),
+ width7,
_buildSSHBtn(spi),
_buildMoreBtn(spi),
],
@@ -229,6 +200,41 @@ class _ServerPageState extends State
);
}
+ Widget _buildTopRightText(ServerStatus ss, ServerState cs) {
+ final topRightStr = getTopRightStr(
+ cs,
+ ss.temps.first,
+ ss.uptime,
+ ss.failedInfo,
+ );
+ final hasError = cs == ServerState.failed && ss.failedInfo != null;
+ return hasError
+ ? GestureDetector(
+ onTap: () => showRoundDialog(
+ context: context,
+ title: Text(_s.error),
+ child: Text(ss.failedInfo ?? _s.unknownError),
+ actions: [
+ TextButton(
+ onPressed: () =>
+ copy2Clipboard(ss.failedInfo ?? _s.unknownError),
+ child: Text(_s.copy),
+ )
+ ],
+ ),
+ child: Text(
+ _s.viewErr,
+ style: textSize12Grey,
+ textScaleFactor: 1.0,
+ ),
+ )
+ : Text(
+ topRightStr,
+ style: textSize12Grey,
+ textScaleFactor: 1.0,
+ );
+ }
+
Widget _buildSSHBtn(ServerPrivateInfo spi) {
return GestureDetector(
child: const Icon(
@@ -311,24 +317,18 @@ class _ServerPageState extends State
}
String getTopRightStr(
- ServerState cs, String temp, String upTime, String? failedInfo) {
+ ServerState cs,
+ double? temp,
+ String upTime,
+ String? failedInfo,
+ ) {
switch (cs) {
case ServerState.disconnected:
return _s.disconnected;
case ServerState.connected:
- if (temp == '') {
- if (upTime == '') {
- return _s.serverTabLoading;
- } else {
- return upTime;
- }
- } else {
- if (upTime == '') {
- return temp;
- } else {
- return '$temp | $upTime';
- }
- }
+ final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C';
+ final items = [tempStr, upTime];
+ return items.where((element) => element.isNotEmpty).join(' | ');
case ServerState.connecting:
return _s.serverTabConnecting;
case ServerState.failed:
diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart
index 346c123d..5d903bbe 100644
--- a/lib/view/page/setting.dart
+++ b/lib/view/page/setting.dart
@@ -317,7 +317,7 @@ class _SettingPageState extends State {
.toList();
return ListTile(
title: Text(
- _s.termTheme,
+ _s.theme,
),
onTap: () {
termThemeKey.currentState?.showButtonMenu();
@@ -465,7 +465,7 @@ class _SettingPageState extends State {
Widget _buildFont() {
final fontName = getFileName(_setting.fontPath.fetch());
return ListTile(
- title: Text(_s.choose),
+ title: Text(_s.font),
trailing: Text(
fontName ?? _s.notSelected,
style: textSize15,
diff --git a/lib/view/page/sftp/view.dart b/lib/view/page/sftp/view.dart
index 99ecac62..d2bf29b1 100644
--- a/lib/view/page/sftp/view.dart
+++ b/lib/view/page/sftp/view.dart
@@ -266,7 +266,7 @@ class _SFTPPageState extends State {
title: Text(_s.download),
onTap: () => download(context, file),
)
- : const SizedBox()
+ : placeholder
],
),
actions: [
diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart
index bd93bb85..56059e31 100644
--- a/lib/view/page/snippet/edit.dart
+++ b/lib/view/page/snippet/edit.dart
@@ -54,7 +54,7 @@ class _SnippetEditPageState extends State
},
tooltip: _s.delete,
icon: const Icon(Icons.delete))
- : const SizedBox()
+ : placeholder
],
),
body: _buildBody(),