mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
optimized apt experience
This commit is contained in:
@@ -31,9 +31,9 @@ class AppUpdate {
|
||||
});
|
||||
AppUpdate.fromJson(Map<String, dynamic> json) {
|
||||
newest = json["newest"]?.toInt();
|
||||
newest = json["macbuild"]?.toInt();
|
||||
newest = json["iosbuild"]?.toInt();
|
||||
newest = json["androidbuild"]?.toInt();
|
||||
macbuild = json["macbuild"]?.toInt();
|
||||
iosbuild = json["iosbuild"]?.toInt();
|
||||
androidbuild = json["androidbuild"]?.toInt();
|
||||
android = json["android"].toString();
|
||||
ios = json["ios"].toString();
|
||||
min = json["min"].toInt();
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dartssh2/dartssh2.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:toolbox/core/extension/uint8list.dart';
|
||||
import 'package:toolbox/core/provider_base.dart';
|
||||
import 'package:toolbox/data/model/apt/upgrade_pkg_info.dart';
|
||||
import 'package:toolbox/data/model/distribution.dart';
|
||||
|
||||
typedef PwdRequestFunc = Future<String> Function(String? userName);
|
||||
final pwdRequestWithUserReg = RegExp(r'\[sudo\] password for (.+):');
|
||||
|
||||
class AptProvider extends BusyProvider {
|
||||
final logger = Logger('AptProvider');
|
||||
|
||||
SSHClient? client;
|
||||
Distribution? dist;
|
||||
Function()? onUpgrade;
|
||||
Function()? onUpdate;
|
||||
PwdRequestFunc? onPasswordRequest;
|
||||
|
||||
String? whoami;
|
||||
List<UpgradePkgInfo>? upgradeable;
|
||||
String? error;
|
||||
String? upgradeLog;
|
||||
String? updateLog;
|
||||
Function()? onUpgrade;
|
||||
String? savedPwd;
|
||||
|
||||
AptProvider();
|
||||
|
||||
Future<void> init(
|
||||
SSHClient client, Distribution dist, Function() onUpgrade) async {
|
||||
Future<void> init(SSHClient client, Distribution dist, Function() onUpgrade,
|
||||
Function() onUpdate, PwdRequestFunc onPasswordRequest) async {
|
||||
this.client = client;
|
||||
this.dist = dist;
|
||||
this.onUpgrade = onUpgrade;
|
||||
this.onPasswordRequest = onPasswordRequest;
|
||||
whoami = (await client.run('whoami').string).trim();
|
||||
}
|
||||
|
||||
@@ -30,8 +46,12 @@ class AptProvider extends BusyProvider {
|
||||
dist = null;
|
||||
upgradeable = null;
|
||||
error = null;
|
||||
updateLog = null;
|
||||
whoami = null;
|
||||
upgradeLog = null;
|
||||
updateLog = whoami = null;
|
||||
savedPwd = null;
|
||||
onUpgrade = null;
|
||||
onUpdate = null;
|
||||
onPasswordRequest = null;
|
||||
}
|
||||
|
||||
Future<void> refreshInstalled() async {
|
||||
@@ -44,38 +64,43 @@ class AptProvider extends BusyProvider {
|
||||
try {
|
||||
getUpgradeableList(result);
|
||||
} catch (e) {
|
||||
error = e.toString();
|
||||
error = '[Server Raw]:\n$result\n[App Error]:\n$e';
|
||||
} finally {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void getUpgradeableList(String raw) {
|
||||
void getUpgradeableList(String? raw) {
|
||||
if (raw == null) return;
|
||||
var list = raw.split('\n');
|
||||
switch (dist) {
|
||||
case Distribution.rehl:
|
||||
var list = raw.split('\n').sublist(2);
|
||||
list = list.sublist(2);
|
||||
list.removeWhere((element) => element.isEmpty);
|
||||
final endLine = list.lastIndexWhere(
|
||||
(element) => element.contains('Obsoleting Packages'));
|
||||
list = list.sublist(0, endLine);
|
||||
upgradeable = list.map((e) => UpgradePkgInfo(e, dist!)).toList();
|
||||
break;
|
||||
case Distribution.debian:
|
||||
case Distribution.unknown:
|
||||
default:
|
||||
final list = raw.split('\n').sublist(4);
|
||||
list = list.sublist(4);
|
||||
list.removeWhere((element) => element.isEmpty);
|
||||
upgradeable = list.map((e) => UpgradePkgInfo(e, dist!)).toList();
|
||||
}
|
||||
upgradeable = list.map((e) => UpgradePkgInfo(e, dist!)).toList();
|
||||
}
|
||||
|
||||
Future<String> _update() async {
|
||||
switch (dist) {
|
||||
case Distribution.rehl:
|
||||
return await client!.run('yum check-update').string;
|
||||
case Distribution.debian:
|
||||
return await client!.run(_wrap('yum check-update')).string;
|
||||
default:
|
||||
await client!.run('apt update');
|
||||
final session = await client!.execute(_wrap('apt update'));
|
||||
session.stderr.listen((event) => _onPwd(event, session.stdin));
|
||||
session.stdout.listen((event) {
|
||||
updateLog = (updateLog ?? '') + event.string;
|
||||
notifyListeners();
|
||||
onUpdate!();
|
||||
});
|
||||
await session.done;
|
||||
return await client!.run('apt list --upgradeable').string;
|
||||
}
|
||||
}
|
||||
@@ -85,24 +110,50 @@ class AptProvider extends BusyProvider {
|
||||
error = 'No client';
|
||||
return;
|
||||
}
|
||||
updateLog = null;
|
||||
|
||||
final session = await client!.execute(upgradeCmd);
|
||||
session.stdout.listen((data) {
|
||||
updateLog = (updateLog ?? '') + data.string;
|
||||
notifyListeners();
|
||||
onUpgrade!();
|
||||
});
|
||||
refreshInstalled();
|
||||
}
|
||||
|
||||
String get upgradeCmd {
|
||||
final upgradeCmd = () {
|
||||
switch (dist) {
|
||||
case Distribution.rehl:
|
||||
return 'yum upgrade -y';
|
||||
case Distribution.debian:
|
||||
default:
|
||||
return 'apt upgrade -y';
|
||||
}
|
||||
}();
|
||||
|
||||
final session = await client!.execute(_wrap(upgradeCmd));
|
||||
session.stderr.listen((e) => _onPwd(e, session.stdin));
|
||||
|
||||
session.stdout.listen((data) async {
|
||||
upgradeLog = (upgradeLog ?? '') + data.string;
|
||||
notifyListeners();
|
||||
onUpgrade!();
|
||||
});
|
||||
|
||||
upgradeLog = null;
|
||||
await session.done;
|
||||
refreshInstalled();
|
||||
}
|
||||
|
||||
Future<void> _onPwd(Uint8List e, StreamSink<Uint8List> stdin) async {
|
||||
final event = e.string;
|
||||
if (event.contains('[sudo] password for ')) {
|
||||
final user = pwdRequestWithUserReg.firstMatch(event)?.group(1);
|
||||
logger.info('sudo password request for $user');
|
||||
final pwd = await () async {
|
||||
if (savedPwd != null) return savedPwd!;
|
||||
final inputPwd = await (onPasswordRequest ?? (_) async => '')(user);
|
||||
if (inputPwd.isNotEmpty) {
|
||||
savedPwd = inputPwd;
|
||||
}
|
||||
return inputPwd;
|
||||
}();
|
||||
if (pwd.isEmpty) {
|
||||
logger.info('sudo password request cancelled');
|
||||
}
|
||||
stdin.add(Uint8List.fromList(utf8.encode(pwd + '\n')));
|
||||
}
|
||||
}
|
||||
|
||||
String _wrap(String cmd) =>
|
||||
'export LANG=en_US.utf-8 && ${isSU ? "" : "sudo -S "}$cmd';
|
||||
}
|
||||
|
||||
@@ -327,9 +327,7 @@ class ServerProvider extends BusyProvider {
|
||||
void _getMem(ServerPrivateInfo spi, String raw) {
|
||||
final info = _servers.firstWhere((e) => e.info == spi);
|
||||
for (var item in raw.split('\n')) {
|
||||
var found = false;
|
||||
if (item.contains(memPrefix)) {
|
||||
found = true;
|
||||
final split = item.replaceFirst(memPrefix, '').split(' ');
|
||||
split.removeWhere((e) => e == '');
|
||||
final memList = split.map((e) => int.parse(e)).toList();
|
||||
@@ -342,7 +340,6 @@ class ServerProvider extends BusyProvider {
|
||||
avail: memList[5]);
|
||||
break;
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,17 +38,19 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m7(myGithub) => "\nMade with ❤️ by ${myGithub}";
|
||||
|
||||
static String m8(time) => "Spent time: ${time}";
|
||||
static String m8(user) => "Password for ${user}";
|
||||
|
||||
static String m9(name) => "Are you sure to delete [${name}]?";
|
||||
static String m9(time) => "Spent time: ${time}";
|
||||
|
||||
static String m10(server) => "Are you sure to delete server [${server}]?";
|
||||
static String m10(name) => "Are you sure to delete [${name}]?";
|
||||
|
||||
static String m11(build) => "Found: v1.0.${build}, click to update";
|
||||
static String m11(server) => "Are you sure to delete server [${server}]?";
|
||||
|
||||
static String m12(build) => "Current: v1.0.${build}";
|
||||
static String m12(build) => "Found: v1.0.${build}, click to update";
|
||||
|
||||
static String m13(build) => "Current: v1.0.${build}, is up to date";
|
||||
static String m13(build) => "Current: v1.0.${build}";
|
||||
|
||||
static String m14(build) => "Current: v1.0.${build}, is up to date";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -140,6 +142,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"pingAvg": MessageLookupByLibrary.simpleMessage("Avg:"),
|
||||
"pingInputIP": MessageLookupByLibrary.simpleMessage(
|
||||
"Please input a target IP/domain."),
|
||||
"platformNotSupportUpdate": MessageLookupByLibrary.simpleMessage(
|
||||
"Current platform does not support in app update.\nPlease build from source and install it."),
|
||||
"plzEnterHost":
|
||||
MessageLookupByLibrary.simpleMessage("Please enter host."),
|
||||
"plzEnterPwd":
|
||||
@@ -149,6 +153,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"port": MessageLookupByLibrary.simpleMessage("Port"),
|
||||
"privateKey": MessageLookupByLibrary.simpleMessage("Private Key"),
|
||||
"pwd": MessageLookupByLibrary.simpleMessage("Password"),
|
||||
"pwdForUser": m8,
|
||||
"rename": MessageLookupByLibrary.simpleMessage("Rename"),
|
||||
"reportBugsOnGithubIssue": MessageLookupByLibrary.simpleMessage(
|
||||
"Please report bugs on https://github.com/LollipopKit/flutter_server_box/issues"),
|
||||
@@ -175,11 +180,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"sftpSSHConnected":
|
||||
MessageLookupByLibrary.simpleMessage("SFTP Connected"),
|
||||
"snippet": MessageLookupByLibrary.simpleMessage("Snippet"),
|
||||
"spentTime": m8,
|
||||
"spentTime": m9,
|
||||
"start": MessageLookupByLibrary.simpleMessage("Start"),
|
||||
"stop": MessageLookupByLibrary.simpleMessage("Stop"),
|
||||
"sureDelete": m9,
|
||||
"sureToDeleteServer": m10,
|
||||
"sureDelete": m10,
|
||||
"sureToDeleteServer": m11,
|
||||
"ttl": MessageLookupByLibrary.simpleMessage("TTL"),
|
||||
"unknown": MessageLookupByLibrary.simpleMessage("unknown"),
|
||||
"unknownError": MessageLookupByLibrary.simpleMessage("Unknown error"),
|
||||
@@ -193,9 +198,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"upsideDown": MessageLookupByLibrary.simpleMessage("Upside Down"),
|
||||
"urlOrJson": MessageLookupByLibrary.simpleMessage("URL or JSON"),
|
||||
"user": MessageLookupByLibrary.simpleMessage("User"),
|
||||
"versionHaveUpdate": m11,
|
||||
"versionUnknownUpdate": m12,
|
||||
"versionUpdated": m13,
|
||||
"versionHaveUpdate": m12,
|
||||
"versionUnknownUpdate": m13,
|
||||
"versionUpdated": m14,
|
||||
"waitConnection": MessageLookupByLibrary.simpleMessage(
|
||||
"Please wait for the connection to be established."),
|
||||
"willTakEeffectImmediately":
|
||||
|
||||
@@ -38,17 +38,19 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m7(myGithub) => "\n用❤️制作 by ${myGithub}";
|
||||
|
||||
static String m8(time) => "耗时: ${time}";
|
||||
static String m8(user) => "用户${user}的密码";
|
||||
|
||||
static String m9(name) => "确定删除[${name}]?";
|
||||
static String m9(time) => "耗时: ${time}";
|
||||
|
||||
static String m10(server) => "你确定要删除服务器 [${server}] 吗?";
|
||||
static String m10(name) => "确定删除[${name}]?";
|
||||
|
||||
static String m11(build) => "找到新版本:v1.0.${build}, 点击更新";
|
||||
static String m11(server) => "你确定要删除服务器 [${server}] 吗?";
|
||||
|
||||
static String m12(build) => "当前:v1.0.${build}";
|
||||
static String m12(build) => "找到新版本:v1.0.${build}, 点击更新";
|
||||
|
||||
static String m13(build) => "当前:v1.0.${build}, 已是最新版本";
|
||||
static String m13(build) => "当前:v1.0.${build}";
|
||||
|
||||
static String m14(build) => "当前:v1.0.${build}, 已是最新版本";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -122,12 +124,15 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"ping": MessageLookupByLibrary.simpleMessage("Ping"),
|
||||
"pingAvg": MessageLookupByLibrary.simpleMessage("平均:"),
|
||||
"pingInputIP": MessageLookupByLibrary.simpleMessage("请输入目标IP或域名"),
|
||||
"platformNotSupportUpdate":
|
||||
MessageLookupByLibrary.simpleMessage("当前平台不支持更新,请编译最新源码后手动安装"),
|
||||
"plzEnterHost": MessageLookupByLibrary.simpleMessage("请输入主机"),
|
||||
"plzEnterPwd": MessageLookupByLibrary.simpleMessage("请输入密码"),
|
||||
"plzSelectKey": MessageLookupByLibrary.simpleMessage("请选择私钥"),
|
||||
"port": MessageLookupByLibrary.simpleMessage("端口"),
|
||||
"privateKey": MessageLookupByLibrary.simpleMessage("私钥"),
|
||||
"pwd": MessageLookupByLibrary.simpleMessage("密码"),
|
||||
"pwdForUser": m8,
|
||||
"rename": MessageLookupByLibrary.simpleMessage("重命名"),
|
||||
"reportBugsOnGithubIssue": MessageLookupByLibrary.simpleMessage(
|
||||
"请到 https://github.com/LollipopKit/flutter_server_box/issues 提交问题"),
|
||||
@@ -149,11 +154,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"sftpSSHConnected":
|
||||
MessageLookupByLibrary.simpleMessage("SFTP 已连接,即将开始下载..."),
|
||||
"snippet": MessageLookupByLibrary.simpleMessage("代码片段"),
|
||||
"spentTime": m8,
|
||||
"spentTime": m9,
|
||||
"start": MessageLookupByLibrary.simpleMessage("开始"),
|
||||
"stop": MessageLookupByLibrary.simpleMessage("停止"),
|
||||
"sureDelete": m9,
|
||||
"sureToDeleteServer": m10,
|
||||
"sureDelete": m10,
|
||||
"sureToDeleteServer": m11,
|
||||
"ttl": MessageLookupByLibrary.simpleMessage("缓存时间"),
|
||||
"unknown": MessageLookupByLibrary.simpleMessage("未知"),
|
||||
"unknownError": MessageLookupByLibrary.simpleMessage("未知错误"),
|
||||
@@ -166,9 +171,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"upsideDown": MessageLookupByLibrary.simpleMessage("上下交换"),
|
||||
"urlOrJson": MessageLookupByLibrary.simpleMessage("链接或JSON"),
|
||||
"user": MessageLookupByLibrary.simpleMessage("用户"),
|
||||
"versionHaveUpdate": m11,
|
||||
"versionUnknownUpdate": m12,
|
||||
"versionUpdated": m13,
|
||||
"versionHaveUpdate": m12,
|
||||
"versionUnknownUpdate": m13,
|
||||
"versionUpdated": m14,
|
||||
"waitConnection": MessageLookupByLibrary.simpleMessage("请等待连接建立"),
|
||||
"willTakEeffectImmediately":
|
||||
MessageLookupByLibrary.simpleMessage("更改将会立即生效")
|
||||
|
||||
@@ -1180,6 +1180,26 @@ class S {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Password for {user}`
|
||||
String pwdForUser(Object user) {
|
||||
return Intl.message(
|
||||
'Password for $user',
|
||||
name: 'pwdForUser',
|
||||
desc: '',
|
||||
args: [user],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Current platform does not support in app update.\nPlease build from source and install it.`
|
||||
String get platformNotSupportUpdate {
|
||||
return Intl.message(
|
||||
'Current platform does not support in app update.\nPlease build from source and install it.',
|
||||
name: 'platformNotSupportUpdate',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -111,5 +111,7 @@
|
||||
"reportBugsOnGithubIssue": "Please report bugs on https://github.com/LollipopKit/flutter_server_box/issues",
|
||||
"noUpdateAvailable": "No update available",
|
||||
"foundNUpdate": "Found {count} update",
|
||||
"updateAll": "Update all"
|
||||
"updateAll": "Update all",
|
||||
"pwdForUser": "Password for {user}",
|
||||
"platformNotSupportUpdate": "Current platform does not support in app update.\nPlease build from source and install it."
|
||||
}
|
||||
@@ -111,5 +111,7 @@
|
||||
"reportBugsOnGithubIssue": "请到 https://github.com/LollipopKit/flutter_server_box/issues 提交问题",
|
||||
"noUpdateAvailable": "没有可用更新",
|
||||
"foundNUpdate": "找到 {count} 个更新",
|
||||
"updateAll": "更新全部"
|
||||
"updateAll": "更新全部",
|
||||
"pwdForUser": "用户{user}的密码",
|
||||
"platformNotSupportUpdate": "当前平台不支持更新,请编译最新源码后手动安装"
|
||||
}
|
||||
@@ -27,6 +27,8 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
late MediaQueryData _media;
|
||||
final greyStyle = const TextStyle(color: Colors.grey);
|
||||
final scrollController = ScrollController();
|
||||
final scrollControllerUpdate = ScrollController();
|
||||
final _aptProvider = locator<AptProvider>();
|
||||
late S s;
|
||||
|
||||
@override
|
||||
@@ -34,6 +36,7 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
super.didChangeDependencies();
|
||||
_media = MediaQuery.of(context);
|
||||
s = S.of(context);
|
||||
_aptProvider.refreshInstalled();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -53,11 +56,52 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
locator<AptProvider>().init(
|
||||
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
PwdRequestFunc onPwdRequest = (user) async {
|
||||
final textController = TextEditingController();
|
||||
await showRoundDialog(
|
||||
context,
|
||||
s.pwdForUser(user ?? s.unknown),
|
||||
TextField(
|
||||
controller: textController,
|
||||
decoration: InputDecoration(
|
||||
labelText: s.pwd,
|
||||
),
|
||||
),
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(s.cancel)),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (textController.text == '') {
|
||||
showRoundDialog(
|
||||
context, s.attention, Text(s.fieldMustNotEmpty), [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(s.ok)),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
s.ok,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
)),
|
||||
]);
|
||||
return textController.text.trim();
|
||||
};
|
||||
|
||||
_aptProvider.init(
|
||||
si.client!,
|
||||
si.status.sysVer.dist,
|
||||
() =>
|
||||
scrollController.jumpTo(scrollController.position.maxScrollExtent));
|
||||
scrollController.jumpTo(scrollController.position.maxScrollExtent),
|
||||
() => scrollControllerUpdate
|
||||
.jumpTo(scrollControllerUpdate.position.maxScrollExtent),
|
||||
onPwdRequest);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -68,10 +112,40 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
title: TwoLineText(up: 'Apt', down: widget.spi.name),
|
||||
),
|
||||
body: Consumer<AptProvider>(builder: (_, apt, __) {
|
||||
if (apt.upgradeable == null) {
|
||||
apt.refreshInstalled();
|
||||
if (apt.error != null) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.redAccent,
|
||||
size: 37,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 37,
|
||||
),
|
||||
Text(
|
||||
apt.error!,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
if (apt.updateLog == null && apt.upgradeable == null) {
|
||||
return centerLoading;
|
||||
}
|
||||
if (apt.updateLog != null && apt.upgradeable == null) {
|
||||
return SizedBox(
|
||||
height: _media.size.height * 0.7,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.expand(),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(18),
|
||||
controller: scrollControllerUpdate,
|
||||
child: Text(apt.updateLog!),
|
||||
),
|
||||
));
|
||||
}
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(13),
|
||||
children: [
|
||||
@@ -111,7 +185,7 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: greyStyle,
|
||||
),
|
||||
children: apt.updateLog == null
|
||||
children: apt.upgradeLog == null
|
||||
? [
|
||||
TextButton(
|
||||
child: Text(s.updateAll),
|
||||
@@ -121,6 +195,7 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
SizedBox(
|
||||
height: _media.size.height * 0.73,
|
||||
child: ListView(
|
||||
controller: scrollController,
|
||||
children: apt.upgradeable!
|
||||
.map((e) => _buildUpdateItem(e, apt))
|
||||
.toList()),
|
||||
@@ -129,10 +204,13 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
: [
|
||||
SizedBox(
|
||||
height: _media.size.height * 0.7,
|
||||
child: ListView(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.expand(),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(18),
|
||||
controller: scrollController,
|
||||
children: [Text(apt.updateLog!)],
|
||||
child: Text(apt.upgradeLog!),
|
||||
),
|
||||
))
|
||||
],
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
||||
widget.spi != null
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
showRoundDialog(context, 'Attention',
|
||||
showRoundDialog(context, s.attention,
|
||||
Text(s.sureToDeleteServer(widget.spi!.name)), [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
|
||||
@@ -90,8 +90,7 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
||||
const Divider(),
|
||||
(_path?.path ?? s.loadingFiles).omitStartStr(
|
||||
style: TextStyle(
|
||||
color:
|
||||
color.isBrightColor ? Colors.black : Colors.white),
|
||||
color: color.isBrightColor ? Colors.black : Colors.white),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@@ -689,5 +689,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.15.1 <3.0.0"
|
||||
dart: ">=2.16.0 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
||||
|
||||
@@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
sdk: ">=2.16.0 <3.0.0"
|
||||
|
||||
# Dependencies specify other packages that your package needs in order to work.
|
||||
# To automatically upgrade your package dependencies to the latest versions
|
||||
|
||||
Reference in New Issue
Block a user