fix & opt

- fix sftp downloaded page bottom path bg color error
- apt/yum add chinese
- urltext add textalign
This commit is contained in:
Junyuan Feng
2022-05-08 09:55:07 +08:00
parent 6f30976ef7
commit 50762d585c
10 changed files with 154 additions and 71 deletions

View File

@@ -1,7 +1,17 @@
# Server Monitor & Toolbox
A new Flutter project which provide a chart view to display server status data and a manager toolbox.
## Milestone
- [x] Status chart view
- [x] Base64/Url En/Decode
- [x] Ping
- [x] Desktop support
- [x] Apt/Yum manager
- [x] SFTP
- [ ] Snippet market
- [x] Docker manager
- [x] i18n (English, Chinese)
## ScreenShots
<table>
<tr>
@@ -43,25 +53,12 @@ Status|Platform
Full Support|Android/iOS/macOS
Support, but not tested|Windows/Linux
## Milestone
- [x] SSH connect
- [x] Server info store
- [x] Status chart view
- [x] Base64/Url En/Decode
- [x] Server status detail page
- [x] Theme switch
- [x] Migrate from `ssh2` to `dartssh2`
- [x] Desktop support
- [x] Apt manager
- [x] SFTP
- [ ] Snippet market
- [x] Docker manager
## Build
Please use `make.dart` to build.
```shell
# build android apk
./make.dart build android
# build android apk and ios archive
./make.dart build
# Run in release mode
./make.dart run release
```

View File

@@ -32,21 +32,23 @@ class MessageLookup extends MessageLookupByLibrary {
static String m4(percent, size) => "${percent}% of ${size}";
static String m5(code) => "request failed, status code: ${code}";
static String m5(count) => "Found ${count} update";
static String m6(myGithub) => "\nMade with ❤️ by ${myGithub}";
static String m6(code) => "request failed, status code: ${code}";
static String m7(time) => "Spent time: ${time}";
static String m7(myGithub) => "\nMade with ❤️ by ${myGithub}";
static String m8(name) => "Are you sure to delete [${name}]?";
static String m8(time) => "Spent time: ${time}";
static String m9(server) => "Are you sure to delete server [${server}]?";
static String m9(name) => "Are you sure to delete [${name}]?";
static String m10(build) => "Found: v1.0.${build}, click to update";
static String m10(server) => "Are you sure to delete server [${server}]?";
static String m11(build) => "Current: v1.0.${build}";
static String m11(build) => "Found: v1.0.${build}, click to update";
static String m12(build) => "Current: v1.0.${build}, is up to date";
static String m12(build) => "Current: v1.0.${build}";
static String m13(build) => "Current: v1.0.${build}, is up to date";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
@@ -83,8 +85,6 @@ class MessageLookup extends MessageLookupByLibrary {
"dl2Local": m1,
"dockerStatusRunningAndStoppedFmt": m2,
"dockerStatusRunningFmt": m3,
"dockerWaitConnection": MessageLookupByLibrary.simpleMessage(
"Please wait for the connection to be established."),
"download": MessageLookupByLibrary.simpleMessage("Download"),
"downloadFinished":
MessageLookupByLibrary.simpleMessage("Download finished"),
@@ -93,15 +93,18 @@ class MessageLookup extends MessageLookupByLibrary {
"encode": MessageLookupByLibrary.simpleMessage("Encode"),
"error": MessageLookupByLibrary.simpleMessage("Error"),
"exampleName": MessageLookupByLibrary.simpleMessage("Example name"),
"experimentalFeature":
MessageLookupByLibrary.simpleMessage("Experimental feature"),
"export": MessageLookupByLibrary.simpleMessage("Export"),
"fieldMustNotEmpty": MessageLookupByLibrary.simpleMessage(
"These fields must not be empty."),
"files": MessageLookupByLibrary.simpleMessage("Files"),
"foundNUpdate": m5,
"go": MessageLookupByLibrary.simpleMessage("Go"),
"goSftpDlPage":
MessageLookupByLibrary.simpleMessage("Go to SFTP download page?"),
"host": MessageLookupByLibrary.simpleMessage("Host"),
"httpFailedWithCode": m5,
"httpFailedWithCode": m6,
"import": MessageLookupByLibrary.simpleMessage("Import"),
"importAndExport":
MessageLookupByLibrary.simpleMessage("Import and Export"),
@@ -116,7 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
"loadingFiles":
MessageLookupByLibrary.simpleMessage("Loading files..."),
"loss": MessageLookupByLibrary.simpleMessage("Loss"),
"madeWithLove": m6,
"madeWithLove": m7,
"max": MessageLookupByLibrary.simpleMessage("max"),
"min": MessageLookupByLibrary.simpleMessage("min"),
"ms": MessageLookupByLibrary.simpleMessage("ms"),
@@ -129,6 +132,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("No saved snippets."),
"noServerAvailable":
MessageLookupByLibrary.simpleMessage("No server available."),
"noUpdateAvailable":
MessageLookupByLibrary.simpleMessage("No update available"),
"ok": MessageLookupByLibrary.simpleMessage("OK"),
"open": MessageLookupByLibrary.simpleMessage("Open"),
"ping": MessageLookupByLibrary.simpleMessage("Ping"),
@@ -145,6 +150,8 @@ class MessageLookup extends MessageLookupByLibrary {
"privateKey": MessageLookupByLibrary.simpleMessage("Private Key"),
"pwd": MessageLookupByLibrary.simpleMessage("Password"),
"rename": MessageLookupByLibrary.simpleMessage("Rename"),
"reportBugsOnGithubIssue": MessageLookupByLibrary.simpleMessage(
"Please report bugs on https://github.com/LollipopKit/flutter_server_box/issues"),
"result": MessageLookupByLibrary.simpleMessage("Result"),
"run": MessageLookupByLibrary.simpleMessage("Run"),
"save": MessageLookupByLibrary.simpleMessage("Save"),
@@ -168,16 +175,17 @@ class MessageLookup extends MessageLookupByLibrary {
"sftpSSHConnected":
MessageLookupByLibrary.simpleMessage("SFTP Connected"),
"snippet": MessageLookupByLibrary.simpleMessage("Snippet"),
"spentTime": m7,
"spentTime": m8,
"start": MessageLookupByLibrary.simpleMessage("Start"),
"stop": MessageLookupByLibrary.simpleMessage("Stop"),
"sureDelete": m8,
"sureToDeleteServer": m9,
"sureDelete": m9,
"sureToDeleteServer": m10,
"ttl": MessageLookupByLibrary.simpleMessage("TTL"),
"unknown": MessageLookupByLibrary.simpleMessage("unknown"),
"unknownError": MessageLookupByLibrary.simpleMessage("Unknown error"),
"unkownConvertMode":
MessageLookupByLibrary.simpleMessage("Unknown convert mode"),
"updateAll": MessageLookupByLibrary.simpleMessage("Update all"),
"updateIntervalEqual0": MessageLookupByLibrary.simpleMessage(
"You set to 0, will not update automatically.\nYou can pull to refresh manually."),
"updateServerStatusInterval": MessageLookupByLibrary.simpleMessage(
@@ -185,9 +193,11 @@ class MessageLookup extends MessageLookupByLibrary {
"upsideDown": MessageLookupByLibrary.simpleMessage("Upside Down"),
"urlOrJson": MessageLookupByLibrary.simpleMessage("URL or JSON"),
"user": MessageLookupByLibrary.simpleMessage("User"),
"versionHaveUpdate": m10,
"versionUnknownUpdate": m11,
"versionUpdated": m12,
"versionHaveUpdate": m11,
"versionUnknownUpdate": m12,
"versionUpdated": m13,
"waitConnection": MessageLookupByLibrary.simpleMessage(
"Please wait for the connection to be established."),
"willTakEeffectImmediately":
MessageLookupByLibrary.simpleMessage("Will take effect immediately")
};

View File

@@ -32,21 +32,23 @@ class MessageLookup extends MessageLookupByLibrary {
static String m4(percent, size) => "${size}${percent}%";
static String m5(code) => "请求失败, 状态码: ${code}";
static String m5(count) => "找到 ${count} 个更新";
static String m6(myGithub) => "\n用❤️制作 by ${myGithub}";
static String m6(code) => "请求失败, 状态码: ${code}";
static String m7(time) => "耗时: ${time}";
static String m7(myGithub) => "\n用❤️制作 by ${myGithub}";
static String m8(name) => "确定删除[${name}]";
static String m8(time) => "耗时: ${time}";
static String m9(server) => "确定删除服务器 [${server}]";
static String m9(name) => "确定删除[${name}]";
static String m10(build) => "找到新版本v1.0.${build}, 点击更新";
static String m10(server) => "你确定要删除服务器 [${server}] 吗?";
static String m11(build) => "当前v1.0.${build}";
static String m11(build) => "找到新版本v1.0.${build}, 点击更新";
static String m12(build) => "当前v1.0.${build}, 已是最新版本";
static String m12(build) => "当前v1.0.${build}";
static String m13(build) => "当前v1.0.${build}, 已是最新版本";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
@@ -77,7 +79,6 @@ class MessageLookup extends MessageLookupByLibrary {
"dl2Local": m1,
"dockerStatusRunningAndStoppedFmt": m2,
"dockerStatusRunningFmt": m3,
"dockerWaitConnection": MessageLookupByLibrary.simpleMessage("请等待连接建立"),
"download": MessageLookupByLibrary.simpleMessage("下载"),
"downloadFinished": MessageLookupByLibrary.simpleMessage("下载完成!"),
"downloadStatus": m4,
@@ -85,13 +86,15 @@ class MessageLookup extends MessageLookupByLibrary {
"encode": MessageLookupByLibrary.simpleMessage("编码"),
"error": MessageLookupByLibrary.simpleMessage("出错了"),
"exampleName": MessageLookupByLibrary.simpleMessage("名称示例"),
"experimentalFeature": MessageLookupByLibrary.simpleMessage("实验性功能"),
"export": MessageLookupByLibrary.simpleMessage("导出"),
"fieldMustNotEmpty": MessageLookupByLibrary.simpleMessage("这些输入框不能为空。"),
"files": MessageLookupByLibrary.simpleMessage("文件"),
"foundNUpdate": m5,
"go": MessageLookupByLibrary.simpleMessage("开始"),
"goSftpDlPage": MessageLookupByLibrary.simpleMessage("前往下载页?"),
"host": MessageLookupByLibrary.simpleMessage("主机"),
"httpFailedWithCode": m5,
"httpFailedWithCode": m6,
"import": MessageLookupByLibrary.simpleMessage("导入"),
"importAndExport": MessageLookupByLibrary.simpleMessage("导入或导出"),
"install": MessageLookupByLibrary.simpleMessage("安装"),
@@ -103,7 +106,7 @@ class MessageLookup extends MessageLookupByLibrary {
"license": MessageLookupByLibrary.simpleMessage("开源证书"),
"loadingFiles": MessageLookupByLibrary.simpleMessage("正在加载目录。。。"),
"loss": MessageLookupByLibrary.simpleMessage("丢包率"),
"madeWithLove": m6,
"madeWithLove": m7,
"max": MessageLookupByLibrary.simpleMessage("最大"),
"min": MessageLookupByLibrary.simpleMessage("最小"),
"ms": MessageLookupByLibrary.simpleMessage("毫秒"),
@@ -113,6 +116,7 @@ class MessageLookup extends MessageLookupByLibrary {
"noSavedPrivateKey": MessageLookupByLibrary.simpleMessage("没有已保存的私钥。"),
"noSavedSnippet": MessageLookupByLibrary.simpleMessage("没有已保存的代码片段。"),
"noServerAvailable": MessageLookupByLibrary.simpleMessage("没有可用的服务器。"),
"noUpdateAvailable": MessageLookupByLibrary.simpleMessage("没有可用更新"),
"ok": MessageLookupByLibrary.simpleMessage(""),
"open": MessageLookupByLibrary.simpleMessage("打开"),
"ping": MessageLookupByLibrary.simpleMessage("Ping"),
@@ -125,6 +129,8 @@ class MessageLookup extends MessageLookupByLibrary {
"privateKey": MessageLookupByLibrary.simpleMessage("私钥"),
"pwd": MessageLookupByLibrary.simpleMessage("密码"),
"rename": MessageLookupByLibrary.simpleMessage("重命名"),
"reportBugsOnGithubIssue": MessageLookupByLibrary.simpleMessage(
"请到 https://github.com/LollipopKit/flutter_server_box/issues 提交问题"),
"result": MessageLookupByLibrary.simpleMessage("结果"),
"run": MessageLookupByLibrary.simpleMessage("运行"),
"save": MessageLookupByLibrary.simpleMessage("保存"),
@@ -143,15 +149,16 @@ class MessageLookup extends MessageLookupByLibrary {
"sftpSSHConnected":
MessageLookupByLibrary.simpleMessage("SFTP 已连接,即将开始下载..."),
"snippet": MessageLookupByLibrary.simpleMessage("代码片段"),
"spentTime": m7,
"spentTime": m8,
"start": MessageLookupByLibrary.simpleMessage("开始"),
"stop": MessageLookupByLibrary.simpleMessage("停止"),
"sureDelete": m8,
"sureToDeleteServer": m9,
"sureDelete": m9,
"sureToDeleteServer": m10,
"ttl": MessageLookupByLibrary.simpleMessage("缓存时间"),
"unknown": MessageLookupByLibrary.simpleMessage("未知"),
"unknownError": MessageLookupByLibrary.simpleMessage("未知错误"),
"unkownConvertMode": MessageLookupByLibrary.simpleMessage("未知转换模式"),
"updateAll": MessageLookupByLibrary.simpleMessage("更新全部"),
"updateIntervalEqual0": MessageLookupByLibrary.simpleMessage(
"你设置为0服务器状态不会自动刷新。\n你可以手动下拉刷新。"),
"updateServerStatusInterval":
@@ -159,9 +166,10 @@ class MessageLookup extends MessageLookupByLibrary {
"upsideDown": MessageLookupByLibrary.simpleMessage("上下交换"),
"urlOrJson": MessageLookupByLibrary.simpleMessage("链接或JSON"),
"user": MessageLookupByLibrary.simpleMessage("用户"),
"versionHaveUpdate": m10,
"versionUnknownUpdate": m11,
"versionUpdated": m12,
"versionHaveUpdate": m11,
"versionUnknownUpdate": m12,
"versionUpdated": m13,
"waitConnection": MessageLookupByLibrary.simpleMessage("请等待连接建立"),
"willTakEeffectImmediately":
MessageLookupByLibrary.simpleMessage("更改将会立即生效")
};

View File

@@ -981,10 +981,10 @@ class S {
}
/// `Please wait for the connection to be established.`
String get dockerWaitConnection {
String get waitConnection {
return Intl.message(
'Please wait for the connection to be established.',
name: 'dockerWaitConnection',
name: 'waitConnection',
desc: '',
args: [],
);
@@ -1130,6 +1130,56 @@ class S {
args: [],
);
}
/// `Experimental feature`
String get experimentalFeature {
return Intl.message(
'Experimental feature',
name: 'experimentalFeature',
desc: '',
args: [],
);
}
/// `Please report bugs on https://github.com/LollipopKit/flutter_server_box/issues`
String get reportBugsOnGithubIssue {
return Intl.message(
'Please report bugs on https://github.com/LollipopKit/flutter_server_box/issues',
name: 'reportBugsOnGithubIssue',
desc: '',
args: [],
);
}
/// `No update available`
String get noUpdateAvailable {
return Intl.message(
'No update available',
name: 'noUpdateAvailable',
desc: '',
args: [],
);
}
/// `Found {count} update`
String foundNUpdate(Object count) {
return Intl.message(
'Found $count update',
name: 'foundNUpdate',
desc: '',
args: [count],
);
}
/// `Update all`
String get updateAll {
return Intl.message(
'Update all',
name: 'updateAll',
desc: '',
args: [],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@@ -92,7 +92,7 @@
"containerStatus": "Container status",
"noClient": "No client",
"installDockerWithUrl": "Please https://docs.docker.com/engine/install docker first.",
"dockerWaitConnection": "Please wait for the connection to be established.",
"waitConnection": "Please wait for the connection to be established.",
"unknownError": "Unknown error",
"dockerStatusRunningFmt": "{count} container running.",
"dockerStatusRunningAndStoppedFmt": "{runningCount} running, {stoppedCount} container stopped.",
@@ -106,5 +106,10 @@
"dl2Local": "Download [{fileName}] to local?",
"error": "Error",
"disconnected": "Disconnected",
"files": "Files"
"files": "Files",
"experimentalFeature": "Experimental feature",
"reportBugsOnGithubIssue": "Please report bugs on https://github.com/LollipopKit/flutter_server_box/issues",
"noUpdateAvailable": "No update available",
"foundNUpdate": "Found {count} update",
"updateAll": "Update all"
}

View File

@@ -92,7 +92,7 @@
"containerStatus": "容器状态",
"noClient": "没有SSH连接",
"installDockerWithUrl": "请先 https://docs.docker.com/engine/install docker",
"dockerWaitConnection": "请等待连接建立",
"waitConnection": "请等待连接建立",
"unknownError": "未知错误",
"dockerStatusRunningFmt": "{count}个容器正在运行",
"dockerStatusRunningAndStoppedFmt": "{runningCount}个正在运行, {stoppedCount}个已停止",
@@ -106,5 +106,10 @@
"dl2Local": "下载 [{fileName}] 到本地?",
"error": "出错了",
"disconnected": "连接断开",
"files": "文件"
"files": "文件",
"experimentalFeature": "实验性功能",
"reportBugsOnGithubIssue": "请到 https://github.com/LollipopKit/flutter_server_box/issues 提交问题",
"noUpdateAvailable": "没有可用更新",
"foundNUpdate": "找到 {count} 个更新",
"updateAll": "更新全部"
}

View File

@@ -6,10 +6,12 @@ import 'package:toolbox/data/model/apt/upgrade_pkg_info.dart';
import 'package:toolbox/data/model/server/server_private_info.dart';
import 'package:toolbox/data/provider/apt.dart';
import 'package:toolbox/data/provider/server.dart';
import 'package:toolbox/generated/l10n.dart';
import 'package:toolbox/locator.dart';
import 'package:toolbox/view/widget/center_loading.dart';
import 'package:toolbox/view/widget/round_rect_card.dart';
import 'package:toolbox/view/widget/two_line_text.dart';
import 'package:toolbox/view/widget/url_text.dart';
class AptManagePage extends StatefulWidget {
const AptManagePage(this.spi, {Key? key}) : super(key: key);
@@ -25,11 +27,13 @@ class _AptManagePageState extends State<AptManagePage>
late MediaQueryData _media;
final greyStyle = const TextStyle(color: Colors.grey);
final scrollController = ScrollController();
late S s;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_media = MediaQuery.of(context);
s = S.of(context);
}
@override
@@ -45,7 +49,7 @@ class _AptManagePageState extends State<AptManagePage>
.servers
.firstWhere((e) => e.info == widget.spi);
if (si.client == null) {
showSnackBar(context, const Text('Plz wait for ssh connection'));
showSnackBar(context, Text(s.waitConnection));
Navigator.of(context).pop();
return;
}
@@ -71,10 +75,11 @@ class _AptManagePageState extends State<AptManagePage>
return ListView(
padding: const EdgeInsets.all(13),
children: [
const Padding(
padding: EdgeInsets.all(17),
child: Text(
'Experimental features.\nPlease report bugs on Github Issue.',
Padding(
padding: const EdgeInsets.all(17),
child: UrlText(
text: '${s.experimentalFeature}\n${s.reportBugsOnGithubIssue}',
replace: 'Github Issue',
textAlign: TextAlign.center,
),
),
@@ -87,19 +92,19 @@ class _AptManagePageState extends State<AptManagePage>
Widget _buildUpdatePanel(AptProvider apt) {
if (apt.upgradeable!.isEmpty) {
return const ListTile(
return ListTile(
title: Text(
'No update available',
s.noUpdateAvailable,
textAlign: TextAlign.center,
),
subtitle: Text('>_<', textAlign: TextAlign.center),
subtitle: const Text('>_<', textAlign: TextAlign.center),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ExpansionTile(
title: Text('Found ${apt.upgradeable!.length} update'),
title: Text(s.foundNUpdate(apt.upgradeable!.length)),
subtitle: Text(
apt.upgradeable!.map((e) => e.package).join(', '),
maxLines: 1,
@@ -109,7 +114,7 @@ class _AptManagePageState extends State<AptManagePage>
children: apt.updateLog == null
? [
TextButton(
child: const Text('Update all'),
child: Text(s.updateAll),
onPressed: () {
apt.upgrade();
}),

View File

@@ -105,7 +105,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
replace: s.install,
);
case 'no client':
return Text(s.dockerWaitConnection);
return Text(s.waitConnection);
default:
return Text(s.unknownError);
}

View File

@@ -7,7 +7,6 @@ import 'package:toolbox/core/extension/stringx.dart';
import 'package:toolbox/core/route.dart';
import 'package:toolbox/core/utils.dart';
import 'package:toolbox/data/model/app/path_with_prefix.dart';
import 'package:toolbox/data/res/color.dart';
import 'package:toolbox/data/res/font_style.dart';
import 'package:toolbox/data/res/path.dart';
import 'package:toolbox/generated/l10n.dart';
@@ -81,8 +80,9 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
}
Widget _buildPath() {
final color = _theme.scaffoldBackgroundColor;
return Container(
color: _theme.appBarTheme.foregroundColor,
color: color,
padding: const EdgeInsets.fromLTRB(11, 7, 11, 11),
child: Column(
mainAxisSize: MainAxisSize.min,
@@ -91,7 +91,7 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
(_path?.path ?? s.loadingFiles).omitStartStr(
style: TextStyle(
color:
primaryColor.isBrightColor ? Colors.black : Colors.white),
color.isBrightColor ? Colors.black : Colors.white),
)
],
),

View File

@@ -8,12 +8,14 @@ const regUrl =
class UrlText extends StatelessWidget {
final String text;
final String? replace;
final TextAlign? textAlign;
final TextStyle style;
const UrlText(
{Key? key,
required this.text,
this.replace,
this.textAlign,
this.style = const TextStyle()})
: super(key: key);
@@ -69,6 +71,7 @@ class UrlText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RichText(
textAlign: textAlign ?? TextAlign.start,
text: TextSpan(children: _getTextSpans(isDarkMode(context))),
);
}