mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
feat: Wake On LAN
This commit is contained in:
@@ -690,7 +690,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -700,7 +700,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -826,7 +826,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -836,7 +836,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -854,7 +854,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -864,7 +864,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -885,7 +885,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -898,7 +898,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||
@@ -924,7 +924,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -937,7 +937,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -960,7 +960,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -973,7 +973,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -996,7 +996,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1008,7 +1008,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||
@@ -1037,7 +1037,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1049,7 +1049,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||
PRODUCT_NAME = ServerBox;
|
||||
@@ -1075,7 +1075,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1087,7 +1087,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||
PRODUCT_NAME = ServerBox;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:toolbox/data/model/server/custom.dart';
|
||||
import 'package:toolbox/data/model/server/server.dart';
|
||||
import 'package:toolbox/data/model/server/wol_cfg.dart';
|
||||
import 'package:toolbox/data/res/provider.dart';
|
||||
|
||||
import '../app/error.dart';
|
||||
@@ -38,6 +39,9 @@ class ServerPrivateInfo {
|
||||
@HiveField(10)
|
||||
final ServerCustom? custom;
|
||||
|
||||
@HiveField(11)
|
||||
final WakeOnLanCfg? wolCfg;
|
||||
|
||||
final String id;
|
||||
|
||||
const ServerPrivateInfo({
|
||||
@@ -52,6 +56,7 @@ class ServerPrivateInfo {
|
||||
this.autoConnect,
|
||||
this.jumpId,
|
||||
this.custom,
|
||||
this.wolCfg,
|
||||
}) : id = '$user@$ip:$port';
|
||||
|
||||
static ServerPrivateInfo fromJson(Map<String, dynamic> json) {
|
||||
@@ -68,6 +73,9 @@ class ServerPrivateInfo {
|
||||
final custom = json["customCmd"] == null
|
||||
? null
|
||||
: ServerCustom.fromJson(json["custom"].cast<String, dynamic>());
|
||||
final wolCfg = json["wolCfg"] == null
|
||||
? null
|
||||
: WakeOnLanCfg.fromJson(json["wolCfg"].cast<String, dynamic>());
|
||||
|
||||
return ServerPrivateInfo(
|
||||
name: name,
|
||||
@@ -81,6 +89,7 @@ class ServerPrivateInfo {
|
||||
autoConnect: autoConnect,
|
||||
jumpId: jumpId,
|
||||
custom: custom,
|
||||
wolCfg: wolCfg,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,6 +120,9 @@ class ServerPrivateInfo {
|
||||
if (custom != null) {
|
||||
data["custom"] = custom?.toJson();
|
||||
}
|
||||
if (wolCfg != null) {
|
||||
data["wolCfg"] = wolCfg?.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,13 +28,14 @@ class ServerPrivateInfoAdapter extends TypeAdapter<ServerPrivateInfo> {
|
||||
autoConnect: fields[8] as bool?,
|
||||
jumpId: fields[9] as String?,
|
||||
custom: fields[10] as ServerCustom?,
|
||||
wolCfg: fields[11] as WakeOnLanCfg?,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, ServerPrivateInfo obj) {
|
||||
writer
|
||||
..writeByte(11)
|
||||
..writeByte(12)
|
||||
..writeByte(0)
|
||||
..write(obj.name)
|
||||
..writeByte(1)
|
||||
@@ -56,7 +57,9 @@ class ServerPrivateInfoAdapter extends TypeAdapter<ServerPrivateInfo> {
|
||||
..writeByte(9)
|
||||
..write(obj.jumpId)
|
||||
..writeByte(10)
|
||||
..write(obj.custom);
|
||||
..write(obj.custom)
|
||||
..writeByte(11)
|
||||
..write(obj.wolCfg);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
71
lib/data/model/server/wol_cfg.dart
Normal file
71
lib/data/model/server/wol_cfg.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:wake_on_lan/wake_on_lan.dart';
|
||||
|
||||
@HiveType(typeId: 8)
|
||||
final class WakeOnLanCfg {
|
||||
@HiveField(0)
|
||||
final String mac;
|
||||
@HiveField(1)
|
||||
final String ip;
|
||||
@HiveField(2)
|
||||
final String? pwd;
|
||||
|
||||
const WakeOnLanCfg({
|
||||
required this.mac,
|
||||
required this.ip,
|
||||
this.pwd,
|
||||
});
|
||||
|
||||
(Object?, bool) validate() {
|
||||
final macValidation = MACAddress.validate(mac);
|
||||
final ipValidation = IPAddress.validate(
|
||||
ip,
|
||||
type: ip.contains(':')
|
||||
? InternetAddressType.IPv6
|
||||
: InternetAddressType.IPv4,
|
||||
);
|
||||
final pwdValidation = SecureONPassword.validate(pwd);
|
||||
|
||||
final valid =
|
||||
macValidation.state && ipValidation.state && pwdValidation.state;
|
||||
final err =
|
||||
macValidation.error ?? ipValidation.error ?? pwdValidation.error;
|
||||
return (err, valid);
|
||||
}
|
||||
|
||||
Future<void> wake() async {
|
||||
if (!validate().$2) {
|
||||
throw Exception('Invalid WakeOnLanCfg');
|
||||
}
|
||||
|
||||
final ip_ = IPAddress(ip);
|
||||
final mac_ = MACAddress(mac);
|
||||
final pwd_ = pwd != null ? SecureONPassword(pwd!) : null;
|
||||
final obj = WakeOnLAN(ip_, mac_, password: pwd_);
|
||||
await obj.wake(
|
||||
repeat: 3,
|
||||
repeatDelay: const Duration(milliseconds: 500),
|
||||
);
|
||||
}
|
||||
|
||||
static WakeOnLanCfg fromJson(Map<String, dynamic> json) {
|
||||
return WakeOnLanCfg(
|
||||
mac: json['mac'] as String,
|
||||
ip: json['ip'] as String,
|
||||
pwd: json['pwd'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{
|
||||
'mac': mac,
|
||||
'ip': ip,
|
||||
};
|
||||
if (pwd != null) {
|
||||
map['pwd'] = pwd;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -141,8 +141,7 @@ class ServerProvider extends ChangeNotifier {
|
||||
TryLimiter.reset(s.spi.id);
|
||||
}
|
||||
|
||||
if (!(s.spi.autoConnect ?? true) &&
|
||||
s.conn == ServerConn.disconnected ||
|
||||
if (!(s.spi.autoConnect ?? true) && s.conn == ServerConn.disconnected ||
|
||||
_manualDisconnectedIds.contains(s.spi.id)) {
|
||||
return;
|
||||
}
|
||||
@@ -277,6 +276,23 @@ class ServerProvider extends ChangeNotifier {
|
||||
if (s.needGenClient || (s.client?.isClosed ?? true)) {
|
||||
_setServerState(s, ServerConn.connecting);
|
||||
|
||||
final wol = spi.wolCfg;
|
||||
if (wol != null) {
|
||||
/// TODO: test it
|
||||
try {
|
||||
await wol.wake();
|
||||
} catch (e) {
|
||||
// TryLimiter.inc(sid);
|
||||
// s.status.err = SSHErr(
|
||||
// type: SSHErrType.connect,
|
||||
// message: 'Wake on lan failed: $e',
|
||||
// );
|
||||
// _setServerState(s, ServerConn.failed);
|
||||
// Loggers.app.warning('Wake on lan failed', e);
|
||||
// return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final time1 = DateTime.now();
|
||||
s.client = await genClient(
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
class BuildData {
|
||||
static const String name = "ServerBox";
|
||||
static const int build = 884;
|
||||
static const int build = 887;
|
||||
static const String engine = "3.19.6";
|
||||
static const String buildAt = "2024-05-09 17:08:49";
|
||||
static const int modifications = 4;
|
||||
static const String buildAt = "2024-05-09 23:08:15";
|
||||
static const int modifications = 22;
|
||||
static const int script = 46;
|
||||
}
|
||||
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Webdav-Einstellungen sind leer",
|
||||
"whenOpenApp": "Beim Öffnen der App",
|
||||
"willTakEeffectImmediately": "Wird sofort angewendet",
|
||||
"wolTip": "Nach der Konfiguration von WOL (Wake-on-LAN) wird jedes Mal, wenn der Server verbunden wird, eine WOL-Anfrage gesendet.",
|
||||
"write": "Schreiben",
|
||||
"writeScriptFailTip": "Das Schreiben des Skripts ist fehlgeschlagen, möglicherweise aufgrund fehlender Berechtigungen oder das Verzeichnis existiert nicht."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Webdav setting is empty",
|
||||
"whenOpenApp": "When opening the app",
|
||||
"willTakEeffectImmediately": "Will take effect immediately",
|
||||
"wolTip": "After configuring WOL (Wake-on-LAN), a WOL request is sent each time the server is connected.",
|
||||
"write": "Write",
|
||||
"writeScriptFailTip": "Writing to the script failed, possibly due to lack of permissions or the directory does not exist."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "La configuración de Webdav está vacía",
|
||||
"whenOpenApp": "Al abrir la App",
|
||||
"willTakEeffectImmediately": "Los cambios tendrán efecto inmediatamente",
|
||||
"wolTip": "Después de configurar WOL (Wake-on-LAN), se envía una solicitud de WOL cada vez que se conecta el servidor.",
|
||||
"write": "Escribir",
|
||||
"writeScriptFailTip": "La escritura en el script falló, posiblemente por falta de permisos o porque el directorio no existe."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "La configuration Webdav est vide",
|
||||
"whenOpenApp": "À l'ouverture de l'application",
|
||||
"willTakEeffectImmediately": "Prendra effet immédiatement",
|
||||
"wolTip": "Après avoir configuré WOL (Wake-on-LAN), une requête WOL est envoyée à chaque connexion au serveur.",
|
||||
"write": "Écrire",
|
||||
"writeScriptFailTip": "L'écriture du script a échoué, peut-être en raison d'un manque de permissions ou parce que le répertoire n'existe pas."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Pengaturan webdav kosong",
|
||||
"whenOpenApp": "Saat membuka aplikasi",
|
||||
"willTakEeffectImmediately": "Akan segera berlaku",
|
||||
"wolTip": "Setelah mengonfigurasi WOL (Wake-on-LAN), permintaan WOL dikirim setiap kali server terhubung.",
|
||||
"write": "Tulis",
|
||||
"writeScriptFailTip": "Penulisan ke skrip gagal, mungkin karena tidak ada izin atau direktori tidak ada."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Webdavの設定が空です",
|
||||
"whenOpenApp": "アプリを開くとき",
|
||||
"willTakEeffectImmediately": "変更は即座に有効になります",
|
||||
"wolTip": "WOL(Wake-on-LAN)を設定した後、サーバーに接続するたびにWOLリクエストが送信されます。",
|
||||
"write": "書き込み",
|
||||
"writeScriptFailTip": "スクリプトの書き込みに失敗しました。権限がないかディレクトリが存在しない可能性があります。"
|
||||
}
|
||||
@@ -327,6 +327,7 @@
|
||||
"webdavSettingEmpty": "Webdav-instelling is leeg",
|
||||
"whenOpenApp": "Bij het openen van de app",
|
||||
"willTakEeffectImmediately": "Zal onmiddellijk van kracht worden",
|
||||
"wolTip": "Na het configureren van WOL (Wake-on-LAN), wordt elke keer dat de server wordt verbonden een WOL-verzoek verzonden.",
|
||||
"write": "Schrijven",
|
||||
"writeScriptFailTip": "Het schrijven naar het script is mislukt, mogelijk door gebrek aan rechten of omdat de map niet bestaat."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Configurações de Webdav estão vazias",
|
||||
"whenOpenApp": "Ao abrir o app",
|
||||
"willTakEeffectImmediately": "As alterações serão aplicadas imediatamente",
|
||||
"wolTip": "Após configurar o WOL (Wake-on-LAN), um pedido de WOL é enviado cada vez que o servidor é conectado.",
|
||||
"write": "Escrita",
|
||||
"writeScriptFailTip": "Falha ao escrever no script, possivelmente devido à falta de permissões ou o diretório não existe."
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Настройки Webdav пусты",
|
||||
"whenOpenApp": "при открытии приложения",
|
||||
"willTakEeffectImmediately": "Изменения вступят в силу немедленно",
|
||||
"wolTip": "После настройки WOL (Wake-on-LAN) при каждом подключении к серверу отправляется запрос WOL.",
|
||||
"write": "запись",
|
||||
"writeScriptFailTip": "Запись в скрипт не удалась, возможно, из-за отсутствия прав или директории не существует."
|
||||
}
|
||||
@@ -323,11 +323,12 @@
|
||||
"virtKeyHelpIME": "打开/关闭键盘",
|
||||
"virtKeyHelpSFTP": "在 SFTP 中打开当前路径。",
|
||||
"waitConnection": "请等待连接建立",
|
||||
"wakeLock": "保持喚醒",
|
||||
"wakeLock": "保持唤醒",
|
||||
"watchNotPaired": "没有已配对的 Apple Watch",
|
||||
"webdavSettingEmpty": "Webdav 设置项为空",
|
||||
"whenOpenApp": "当打开 App 时",
|
||||
"willTakEeffectImmediately": "更改将会立即生效",
|
||||
"wolTip": "在配置 WOL 后,每次连接服务器都会先发送一次 WOl 请求",
|
||||
"write": "写",
|
||||
"writeScriptFailTip": "写入脚本失败,可能是没有权限/目录不存在等"
|
||||
}
|
||||
@@ -328,6 +328,7 @@
|
||||
"webdavSettingEmpty": "Webdav 設置項爲空",
|
||||
"whenOpenApp": "當打開 App 時",
|
||||
"willTakEeffectImmediately": "更改將會立即生效",
|
||||
"wolTip": "在配置WOL(網絡喚醒)後,每次連接伺服器都會先發送一次WOL請求。",
|
||||
"write": "写",
|
||||
"writeScriptFailTip": "寫入腳本失敗,可能是沒有權限/目錄不存在等。"
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import 'package:toolbox/core/extension/widget.dart';
|
||||
import 'package:toolbox/core/utils/ui.dart';
|
||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||
import 'package:toolbox/data/model/server/custom.dart';
|
||||
import 'package:toolbox/data/model/server/wol_cfg.dart';
|
||||
import 'package:toolbox/data/res/provider.dart';
|
||||
import 'package:toolbox/view/widget/expand_tile.dart';
|
||||
|
||||
@@ -44,6 +45,9 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
final _customCmdCtrl = TextEditingController();
|
||||
final _preferTempDevCtrl = TextEditingController();
|
||||
final _logoUrlCtrl = TextEditingController();
|
||||
final _wolMacCtrl = TextEditingController();
|
||||
final _wolIpCtrl = TextEditingController();
|
||||
final _wolPwdCtrl = TextEditingController();
|
||||
|
||||
final _nameFocus = FocusNode();
|
||||
final _ipFocus = FocusNode();
|
||||
@@ -99,6 +103,13 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
_preferTempDevCtrl.text = custom.preferTempDev ?? '';
|
||||
_logoUrlCtrl.text = custom.logoUrl ?? '';
|
||||
}
|
||||
|
||||
final wol = spi.wolCfg;
|
||||
if (wol != null) {
|
||||
_wolMacCtrl.text = wol.mac;
|
||||
_wolIpCtrl.text = wol.ip;
|
||||
_wolPwdCtrl.text = wol.pwd ?? '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +131,9 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
_customCmdCtrl.dispose();
|
||||
_preferTempDevCtrl.dispose();
|
||||
_logoUrlCtrl.dispose();
|
||||
_wolMacCtrl.dispose();
|
||||
_wolIpCtrl.dispose();
|
||||
_wolPwdCtrl.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -380,52 +394,9 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
hint: 'https://example.com/logo.png',
|
||||
),
|
||||
UIs.height7,
|
||||
const Text('PVE', style: UIs.text13Grey),
|
||||
..._buildPVEs(),
|
||||
UIs.height7,
|
||||
Input(
|
||||
controller: _pveAddrCtrl,
|
||||
type: TextInputType.url,
|
||||
icon: MingCute.web_line,
|
||||
label: l10n.addr,
|
||||
hint: 'https://example.com:8006',
|
||||
),
|
||||
ListTile(
|
||||
leading: const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Icon(MingCute.certificate_line),
|
||||
),
|
||||
title: Text('PVE ${l10n.ignoreCert}'),
|
||||
subtitle: Text(l10n.pveIgnoreCertTip, style: UIs.text12Grey),
|
||||
trailing: ListenableBuilder(
|
||||
listenable: _pveIgnoreCert,
|
||||
builder: (_, __) => Switch(
|
||||
value: _pveIgnoreCert.value,
|
||||
onChanged: (val) {
|
||||
_pveIgnoreCert.value = val;
|
||||
},
|
||||
),
|
||||
),
|
||||
).card,
|
||||
UIs.height7,
|
||||
Text(l10n.customCmd, style: UIs.text13Grey),
|
||||
UIs.height7,
|
||||
Input(
|
||||
controller: _customCmdCtrl,
|
||||
type: TextInputType.text,
|
||||
maxLines: 3,
|
||||
label: 'JSON',
|
||||
icon: Icons.code,
|
||||
hint: '{${l10n.customCmdHint}}',
|
||||
),
|
||||
ListTile(
|
||||
leading: const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Icon(MingCute.doc_line),
|
||||
),
|
||||
title: Text(l10n.doc),
|
||||
trailing: const Icon(Icons.open_in_new, size: 17),
|
||||
onTap: () => openUrl(l10n.customCmdDocUrl),
|
||||
).card,
|
||||
..._buildCustomCmds(),
|
||||
UIs.height7,
|
||||
Text(l10n.temperature, style: UIs.text13Grey),
|
||||
UIs.height7,
|
||||
@@ -436,10 +407,101 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
icon: MingCute.low_temperature_line,
|
||||
hint: 'nvme-pci-0400',
|
||||
),
|
||||
UIs.height7,
|
||||
..._buildWOLs(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildPVEs() {
|
||||
return [
|
||||
const Text('PVE', style: UIs.text13Grey),
|
||||
UIs.height7,
|
||||
Input(
|
||||
controller: _pveAddrCtrl,
|
||||
type: TextInputType.url,
|
||||
icon: MingCute.web_line,
|
||||
label: l10n.addr,
|
||||
hint: 'https://example.com:8006',
|
||||
),
|
||||
ListTile(
|
||||
leading: const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Icon(MingCute.certificate_line),
|
||||
),
|
||||
title: Text('PVE ${l10n.ignoreCert}'),
|
||||
subtitle: Text(l10n.pveIgnoreCertTip, style: UIs.text12Grey),
|
||||
trailing: ListenableBuilder(
|
||||
listenable: _pveIgnoreCert,
|
||||
builder: (_, __) => Switch(
|
||||
value: _pveIgnoreCert.value,
|
||||
onChanged: (val) {
|
||||
_pveIgnoreCert.value = val;
|
||||
},
|
||||
),
|
||||
),
|
||||
).card,
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildCustomCmds() {
|
||||
return [
|
||||
Text(l10n.customCmd, style: UIs.text13Grey),
|
||||
UIs.height7,
|
||||
Input(
|
||||
controller: _customCmdCtrl,
|
||||
type: TextInputType.text,
|
||||
maxLines: 3,
|
||||
label: 'JSON',
|
||||
icon: Icons.code,
|
||||
hint: '{${l10n.customCmdHint}}',
|
||||
),
|
||||
ListTile(
|
||||
leading: const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Icon(MingCute.doc_line),
|
||||
),
|
||||
title: Text(l10n.doc),
|
||||
trailing: const Icon(Icons.open_in_new, size: 17),
|
||||
onTap: () => openUrl(l10n.customCmdDocUrl),
|
||||
).card,
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildWOLs() {
|
||||
return [
|
||||
const Text('Wake On LAN', style: UIs.text13Grey),
|
||||
UIs.height7,
|
||||
ListTile(
|
||||
leading: const Icon(BoxIcons.bxs_help_circle),
|
||||
title: Text(l10n.about),
|
||||
subtitle: Text(l10n.wolTip, style: UIs.text12Grey),
|
||||
).card,
|
||||
Input(
|
||||
controller: _wolMacCtrl,
|
||||
type: TextInputType.text,
|
||||
label: 'Mac ${l10n.addr}',
|
||||
icon: Icons.computer,
|
||||
hint: '00:11:22:33:44:55',
|
||||
),
|
||||
Input(
|
||||
controller: _wolIpCtrl,
|
||||
type: TextInputType.text,
|
||||
label: 'IP ${l10n.addr}',
|
||||
icon: Icons.network_cell,
|
||||
hint: '192.168.1.x',
|
||||
),
|
||||
Input(
|
||||
controller: _wolPwdCtrl,
|
||||
type: TextInputType.text,
|
||||
obscureText: true,
|
||||
label: l10n.pwd,
|
||||
icon: Icons.password,
|
||||
hint: l10n.pwd,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _buildFAB() {
|
||||
return FloatingActionButton(
|
||||
onPressed: _onSave,
|
||||
@@ -544,6 +606,17 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
logoUrl: _logoUrlCtrl.text.selfIfNotNullEmpty,
|
||||
);
|
||||
|
||||
final wol = WakeOnLanCfg(
|
||||
mac: _wolMacCtrl.text,
|
||||
ip: _wolIpCtrl.text,
|
||||
pwd: _wolPwdCtrl.text.selfIfNotNullEmpty,
|
||||
);
|
||||
final wolValidation = wol.validate();
|
||||
if (!wolValidation.$2) {
|
||||
context.showSnackBar('${l10n.failed}: ${wolValidation.$1}');
|
||||
return;
|
||||
}
|
||||
|
||||
final spi = ServerPrivateInfo(
|
||||
name: _nameController.text.isEmpty
|
||||
? _ipController.text
|
||||
@@ -560,6 +633,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
||||
autoConnect: _autoConnect.value,
|
||||
jumpId: _jumpServer.value,
|
||||
custom: custom,
|
||||
wolCfg: wol,
|
||||
);
|
||||
|
||||
if (widget.spi == null) {
|
||||
|
||||
@@ -1135,7 +1135,6 @@ class _SettingPageState extends State<SettingPage> {
|
||||
|
||||
Widget _buildWakeLock() {
|
||||
return ListTile(
|
||||
leading: const Icon(MingCute.lock_fill),
|
||||
title: Text(l10n.wakeLock),
|
||||
trailing: StoreSwitch(prop: _setting.generalWakeLock),
|
||||
);
|
||||
|
||||
@@ -18,21 +18,22 @@ final class IconTextBtn extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: onPressed,
|
||||
tooltip: text,
|
||||
icon: orientation == Orientation.landscape ? Row(
|
||||
children: [
|
||||
Icon(icon),
|
||||
UIs.width7,
|
||||
Text(text, style: UIs.text13Grey),
|
||||
],
|
||||
) : Column(
|
||||
children: [
|
||||
Icon(icon),
|
||||
UIs.height7,
|
||||
Text(text, style: UIs.text13Grey),
|
||||
],
|
||||
)
|
||||
);
|
||||
onPressed: onPressed,
|
||||
tooltip: text,
|
||||
icon: orientation == Orientation.landscape
|
||||
? Row(
|
||||
children: [
|
||||
Icon(icon),
|
||||
UIs.width7,
|
||||
Text(text, style: UIs.text13Grey),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
Icon(icon),
|
||||
UIs.height7,
|
||||
Text(text, style: UIs.text13Grey),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
|
||||
@@ -481,7 +481,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "Server Box";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -608,7 +608,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
|
||||
@@ -618,7 +618,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "Server Box";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -638,7 +638,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 884;
|
||||
CURRENT_PROJECT_VERSION = 887;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -649,7 +649,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.884;
|
||||
MARKETING_VERSION = 1.0.887;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "Server Box";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@@ -1333,6 +1333,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
wake_on_lan:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: wake_on_lan
|
||||
sha256: a0db43df0cd05181f476f38ec63345a763b7d3b9d8ab25cabbff45881780cb8e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1+3"
|
||||
wakelock_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -78,6 +78,7 @@ dependencies:
|
||||
fl_chart: ^0.67.0
|
||||
wakelock_plus: ^1.2.4
|
||||
extended_image: ^8.2.0
|
||||
wake_on_lan: ^4.1.1+3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_native_splash: ^2.1.6
|
||||
|
||||
Reference in New Issue
Block a user