opt.: custom terminal emulator (#771)

This commit is contained in:
lollipopkit🏳️‍⚧️
2025-06-04 19:13:31 +08:00
committed by GitHub
parent 7127c960f7
commit f6d394c71e
30 changed files with 303 additions and 61 deletions

View File

@@ -14,11 +14,7 @@ class SftpProvider extends Provider {
}
static int add(SftpReq req, {Completer? completer}) {
final reqStat = SftpReqStatus(
notifyListeners: status.notify,
completer: completer,
req: req,
);
final reqStat = SftpReqStatus(notifyListeners: status.notify, completer: completer, req: req);
status.value.add(reqStat);
status.notify();
return reqStat.id;
@@ -34,6 +30,10 @@ class SftpProvider extends Provider {
static void cancel(int id) {
final idx = status.value.indexWhere((e) => e.id == id);
if (idx < 0 || idx >= status.value.length) {
dprint('SftpProvider.cancel: id $id not found');
return;
}
status.value[idx].dispose();
status.value.removeAt(idx);
status.notify();

View File

@@ -73,14 +73,20 @@ class SettingStore extends HiveStore {
late final locale = propertyDefault('locale', '');
// SSH virtual key (ctrl | alt) auto turn off
late final sshVirtualKeyAutoOff = propertyDefault('sshVirtualKeyAutoOff', true);
late final sshVirtualKeyAutoOff = propertyDefault(
'sshVirtualKeyAutoOff',
true,
);
late final editorFontSize = propertyDefault('editorFontSize', 12.5);
// Editor theme
late final editorTheme = propertyDefault('editorTheme', Defaults.editorTheme);
late final editorDarkTheme = propertyDefault('editorDarkTheme', Defaults.editorDarkTheme);
late final editorDarkTheme = propertyDefault(
'editorDarkTheme',
Defaults.editorDarkTheme,
);
late final fullScreen = propertyDefault('fullScreen', false);
@@ -110,20 +116,29 @@ class SettingStore extends HiveStore {
);
// Only valid on iOS
late final autoUpdateHomeWidget = propertyDefault('autoUpdateHomeWidget', isIOS);
late final autoUpdateHomeWidget = propertyDefault(
'autoUpdateHomeWidget',
isIOS,
);
late final autoCheckAppUpdate = propertyDefault('autoCheckAppUpdate', true);
/// Display server tab function buttons on the bottom of each server card if [true]
///
/// Otherwise, display them on the top of server detail page
late final moveServerFuncs = propertyDefault('moveOutServerTabFuncBtns', false);
late final moveServerFuncs = propertyDefault(
'moveOutServerTabFuncBtns',
false,
);
/// Whether use `rm -r` to delete directory on SFTP
late final sftpRmrDir = propertyDefault('sftpRmrDir', false);
/// Whether use system's primary color as the app's primary color
late final useSystemPrimaryColor = propertyDefault('useSystemPrimaryColor', false);
late final useSystemPrimaryColor = propertyDefault(
'useSystemPrimaryColor',
false,
);
/// Only valid on iOS / Android / Windows
late final useBioAuth = propertyDefault('useBioAuth', false);
@@ -135,7 +150,10 @@ class SettingStore extends HiveStore {
late final sftpOpenLastPath = propertyDefault('sftpOpenLastPath', true);
/// Show folders first in SFTP file browser
late final sftpShowFoldersFirst = propertyDefault('sftpShowFoldersFirst', true);
late final sftpShowFoldersFirst = propertyDefault(
'sftpShowFoldersFirst',
true,
);
/// Show tip of suspend
late final showSuspendTip = propertyDefault('showSuspendTip', true);
@@ -161,7 +179,10 @@ class SettingStore extends HiveStore {
late final containerParseStat = propertyDefault('containerParseStat', true);
/// Auto refresh container status
late final contaienrAutoRefresh = propertyDefault('contaienrAutoRefresh', true);
late final contaienrAutoRefresh = propertyDefault(
'contaienrAutoRefresh',
true,
);
/// Use double column servers page on Desktop
late final doubleColumnServersPage = propertyDefault(
@@ -219,7 +240,8 @@ class SettingStore extends HiveStore {
/// Record the position and size of the window.
late final windowState = property<WindowState>(
'windowState',
fromObj: (raw) => WindowState.fromJson(jsonDecode(raw as String) as Map<String, dynamic>),
fromObj: (raw) =>
WindowState.fromJson(jsonDecode(raw as String) as Map<String, dynamic>),
toObj: (state) => state == null ? null : jsonEncode(state.toJson()),
);
@@ -231,6 +253,12 @@ class SettingStore extends HiveStore {
/// Set it empty to use local editor GUI.
late final sftpEditor = propertyDefault('sftpEditor', '');
/// Preferred terminal emulator command on desktop
late final desktopTerminal = propertyDefault(
'desktopTerminal',
'x-terminal-emulator',
);
/// Run foreground service on Android, if the SSH terminal is running
late final fgService = propertyDefault('fgService', false);

View File

@@ -311,6 +311,12 @@ abstract class AppLocalizations {
/// **'Batch delete servers'**
String get deleteServers;
/// No description provided for @desktopTerminalTip.
///
/// In en, this message translates to:
/// **'Command used to open the terminal emulator when launching SSH sessions.'**
String get desktopTerminalTip;
/// No description provided for @dirEmpty.
///
/// In en, this message translates to:
@@ -410,6 +416,12 @@ abstract class AppLocalizations {
/// **'The current code highlighting performance is not ideal and can be optionally turned off to improve.'**
String get editorHighlightTip;
/// No description provided for @emulator.
///
/// In en, this message translates to:
/// **'Emulator'**
String get emulator;
/// No description provided for @encode.
///
/// In en, this message translates to:

View File

@@ -115,6 +115,10 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get deleteServers => 'Batch-Löschung von Servern';
@override
String get desktopTerminalTip =>
'Befehl zum Öffnen des Terminal-Emulators beim Starten von SSH-Sitzungen.';
@override
String get dirEmpty => 'Stelle sicher, dass der Ordner leer ist.';
@@ -177,6 +181,9 @@ class AppLocalizationsDe extends AppLocalizations {
String get editorHighlightTip =>
'Die Leistung der aktuellen Codehervorhebung ist schlechter und kann zur Verbesserung optional ausgeschaltet werden.';
@override
String get emulator => 'Emulator';
@override
String get encode => 'Encode';

View File

@@ -114,6 +114,10 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get deleteServers => 'Batch delete servers';
@override
String get desktopTerminalTip =>
'Command used to open the terminal emulator when launching SSH sessions.';
@override
String get dirEmpty => 'Make sure the folder is empty.';
@@ -176,6 +180,9 @@ class AppLocalizationsEn extends AppLocalizations {
String get editorHighlightTip =>
'The current code highlighting performance is not ideal and can be optionally turned off to improve.';
@override
String get emulator => 'Emulator';
@override
String get encode => 'Encode';

View File

@@ -115,6 +115,10 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get deleteServers => 'Eliminar servidores en lote';
@override
String get desktopTerminalTip =>
'Comando utilizado para abrir el emulador de terminal al iniciar sesiones SSH.';
@override
String get dirEmpty => 'Asegúrate de que el directorio esté vacío';
@@ -177,6 +181,9 @@ class AppLocalizationsEs extends AppLocalizations {
String get editorHighlightTip =>
'El rendimiento del resaltado de código es bastante pobre actualmente, puedes elegir desactivarlo para mejorar.';
@override
String get emulator => 'Emulador';
@override
String get encode => 'Codificar';

View File

@@ -115,6 +115,10 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get deleteServers => 'Supprimer des serveurs en lot';
@override
String get desktopTerminalTip =>
'Commande utilisée pour ouvrir lémulateur de terminal lors du lancement de sessions SSH.';
@override
String get dirEmpty => 'Assurez-vous que le répertoire est vide.';
@@ -177,6 +181,9 @@ class AppLocalizationsFr extends AppLocalizations {
String get editorHighlightTip =>
'La performance actuelle de mise en surbrillance du code est pire et peut être désactivée en option pour s\'améliorer.';
@override
String get emulator => 'Émulateur';
@override
String get encode => 'Encoder';

View File

@@ -114,6 +114,10 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get deleteServers => 'Penghapusan server secara batch';
@override
String get desktopTerminalTip =>
'Perintah yang digunakan untuk membuka emulator terminal saat memulai sesi SSH.';
@override
String get dirEmpty => 'Pastikan dir kosong.';
@@ -176,6 +180,9 @@ class AppLocalizationsId extends AppLocalizations {
String get editorHighlightTip =>
'Performa penyorotan kode saat ini lebih buruk, dan dapat dimatikan secara opsional untuk perbaikan.';
@override
String get emulator => 'Emulator';
@override
String get encode => 'Menyandi';

View File

@@ -108,6 +108,9 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get deleteServers => 'サーバーを一括削除';
@override
String get desktopTerminalTip => 'SSHセッションを起動する際に使用されるターミナルエミュレーターを開くコマンド。';
@override
String get dirEmpty => 'フォルダーが空であることを確認してください';
@@ -170,6 +173,9 @@ class AppLocalizationsJa extends AppLocalizations {
String get editorHighlightTip =>
'現在のコードハイライトのパフォーマンスはかなり悪いため、改善するために無効にすることを選択できます。';
@override
String get emulator => 'エミュレーター';
@override
String get encode => 'エンコード';

View File

@@ -114,6 +114,10 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get deleteServers => 'Servers batchgewijs verwijderen';
@override
String get desktopTerminalTip =>
'Opdracht die wordt gebruikt om de terminalemulator te openen bij het starten van SSH-sessies.';
@override
String get dirEmpty => 'Zorg ervoor dat de map leeg is.';
@@ -176,6 +180,9 @@ class AppLocalizationsNl extends AppLocalizations {
String get editorHighlightTip =>
'De huidige codehighlighting-prestaties zijn slechter en kunnen optioneel worden uitgeschakeld om te verbeteren.';
@override
String get emulator => 'Emulator';
@override
String get encode => 'Coderen';

View File

@@ -114,6 +114,10 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get deleteServers => 'Excluir servidores em lote';
@override
String get desktopTerminalTip =>
'Comando usado para abrir o emulador de terminal ao iniciar sessões SSH.';
@override
String get dirEmpty => 'Certifique-se de que a pasta está vazia';
@@ -176,6 +180,9 @@ class AppLocalizationsPt extends AppLocalizations {
String get editorHighlightTip =>
'O desempenho do destaque de código atualmente é ruim, pode optar por desativá-lo para melhorar.';
@override
String get emulator => 'Emulador';
@override
String get encode => 'Codificar';

View File

@@ -114,6 +114,10 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get deleteServers => 'Удалить серверы пакетно';
@override
String get desktopTerminalTip =>
'Команда для открытия эмулятора терминала при запуске SSH-сеансов.';
@override
String get dirEmpty => 'Пожалуйста, убедитесь, что папка пуста';
@@ -176,6 +180,9 @@ class AppLocalizationsRu extends AppLocalizations {
String get editorHighlightTip =>
'Текущая производительность подсветки кода неудовлетворительна, можно отключить для улучшения.';
@override
String get emulator => 'Эмулятор';
@override
String get encode => 'Кодировать';

View File

@@ -113,6 +113,10 @@ class AppLocalizationsTr extends AppLocalizations {
@override
String get deleteServers => 'Sunucuları toplu sil';
@override
String get desktopTerminalTip =>
'SSH oturumları başlatılırken terminal öykünücüsünü açmak için kullanılan komut.';
@override
String get dirEmpty => 'Klasörün boş olduğundan emin olun.';
@@ -175,6 +179,9 @@ class AppLocalizationsTr extends AppLocalizations {
String get editorHighlightTip =>
'Mevcut kod vurgulama performansı ideal değil ve isteğe bağlı olarak kapatılabilir.';
@override
String get emulator => 'Emülatör';
@override
String get encode => 'Kodla';

View File

@@ -115,6 +115,10 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get deleteServers => 'Масове видалення серверів';
@override
String get desktopTerminalTip =>
'Команда для відкриття емулятора термінала під час запуску SSH-сеансів.';
@override
String get dirEmpty => 'Переконайтеся, що директорія пуста.';
@@ -177,6 +181,9 @@ class AppLocalizationsUk extends AppLocalizations {
String get editorHighlightTip =>
'Поточна підсвітка коду не ідеальна і може бути вимкнена для покращення.';
@override
String get emulator => 'Емулятор';
@override
String get encode => 'Кодувати';

View File

@@ -107,6 +107,9 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get deleteServers => '批量删除服务器';
@override
String get desktopTerminalTip => '启动 SSH 连接所用的终端模拟器命令';
@override
String get dirEmpty => '请确保文件夹为空';
@@ -167,6 +170,9 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get editorHighlightTip => '目前的代码高亮性能较为糟糕,可以选择关闭以改善。';
@override
String get emulator => '模拟器';
@override
String get encode => '编码';
@@ -826,6 +832,9 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
@override
String get deleteServers => '批量刪除伺服器';
@override
String get desktopTerminalTip => '啟動 SSH 連線時用於打開終端機模擬器的指令。';
@override
String get dirEmpty => '請確保資料夾為空';
@@ -886,6 +895,9 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
@override
String get editorHighlightTip => '目前的代碼高亮性能較為糟糕,可以選擇關閉以改善。';
@override
String get emulator => '模擬器';
@override
String get encode => '編碼';

View File

@@ -32,6 +32,7 @@
"decode": "Decode",
"decompress": "Dekomprimieren",
"deleteServers": "Batch-Löschung von Servern",
"desktopTerminalTip": "Befehl zum Öffnen des Terminal-Emulators beim Starten von SSH-Sitzungen.",
"dirEmpty": "Stelle sicher, dass der Ordner leer ist.",
"disconnected": "Disconnected",
"disk": "Festplatte",
@@ -48,6 +49,7 @@
"editVirtKeys": "Virtuelle Tasten bearbeiten",
"editor": "Editor",
"editorHighlightTip": "Die Leistung der aktuellen Codehervorhebung ist schlechter und kann zur Verbesserung optional ausgeschaltet werden.",
"emulator": "Emulator",
"encode": "Encode",
"envVars": "Umgebungsvariable",
"experimentalFeature": "Experimentelles Feature",

View File

@@ -32,6 +32,7 @@
"decode": "Decode",
"decompress": "Decompress",
"deleteServers": "Batch delete servers",
"desktopTerminalTip": "Command used to open the terminal emulator when launching SSH sessions.",
"dirEmpty": "Make sure the folder is empty.",
"disconnected": "Disconnected",
"disk": "Disk",
@@ -48,6 +49,7 @@
"editVirtKeys": "Edit virtual keys",
"editor": "Editor",
"editorHighlightTip": "The current code highlighting performance is not ideal and can be optionally turned off to improve.",
"emulator": "Emulator",
"encode": "Encode",
"envVars": "Environment variable",
"experimentalFeature": "Experimental feature",

View File

@@ -32,6 +32,7 @@
"decode": "Decodificar",
"decompress": "Descomprimir",
"deleteServers": "Eliminar servidores en lote",
"desktopTerminalTip": "Comando utilizado para abrir el emulador de terminal al iniciar sesiones SSH.",
"dirEmpty": "Asegúrate de que el directorio esté vacío",
"disconnected": "Desconectado",
"disk": "Disco",
@@ -48,6 +49,7 @@
"editVirtKeys": "Editar teclas virtuales",
"editor": "Editor",
"editorHighlightTip": "El rendimiento del resaltado de código es bastante pobre actualmente, puedes elegir desactivarlo para mejorar.",
"emulator": "Emulador",
"encode": "Codificar",
"envVars": "Variable de entorno",
"experimentalFeature": "Función experimental",

View File

@@ -32,6 +32,7 @@
"decode": "Décoder",
"decompress": "Décompresser",
"deleteServers": "Supprimer des serveurs en lot",
"desktopTerminalTip": "Commande utilisée pour ouvrir lémulateur de terminal lors du lancement de sessions SSH.",
"dirEmpty": "Assurez-vous que le répertoire est vide.",
"disconnected": "Déconnecté",
"disk": "Disque",
@@ -48,6 +49,7 @@
"editVirtKeys": "Modifier les touches virtuelles",
"editor": "Éditeur",
"editorHighlightTip": "La performance actuelle de mise en surbrillance du code est pire et peut être désactivée en option pour s'améliorer.",
"emulator": "Émulateur",
"encode": "Encoder",
"envVars": "Variable denvironnement",
"experimentalFeature": "Fonctionnalité expérimentale",

View File

@@ -32,6 +32,7 @@
"decode": "Membaca sandi",
"decompress": "Dekompresi",
"deleteServers": "Penghapusan server secara batch",
"desktopTerminalTip": "Perintah yang digunakan untuk membuka emulator terminal saat memulai sesi SSH.",
"dirEmpty": "Pastikan dir kosong.",
"disconnected": "Terputus",
"disk": "Disk",
@@ -48,6 +49,7 @@
"editVirtKeys": "Edit kunci virtual",
"editor": "Editor",
"editorHighlightTip": "Performa penyorotan kode saat ini lebih buruk, dan dapat dimatikan secara opsional untuk perbaikan.",
"emulator": "Emulator",
"encode": "Menyandi",
"envVars": "Variabel lingkungan",
"experimentalFeature": "Fitur eksperimental",

View File

@@ -32,6 +32,7 @@
"decode": "デコード",
"decompress": "解凍",
"deleteServers": "サーバーを一括削除",
"desktopTerminalTip": "SSHセッションを起動する際に使用されるターミナルエミュレーターを開くコマンド。",
"dirEmpty": "フォルダーが空であることを確認してください",
"disconnected": "接続が切断されました",
"disk": "ディスク",
@@ -48,6 +49,7 @@
"editVirtKeys": "仮想キーを編集",
"editor": "エディター",
"editorHighlightTip": "現在のコードハイライトのパフォーマンスはかなり悪いため、改善するために無効にすることを選択できます。",
"emulator": "エミュレーター",
"encode": "エンコード",
"envVars": "環境変数",
"experimentalFeature": "実験的な機能",

View File

@@ -32,6 +32,7 @@
"decode": "Decoderen",
"decompress": "Decomprimeren",
"deleteServers": "Servers batchgewijs verwijderen",
"desktopTerminalTip": "Opdracht die wordt gebruikt om de terminalemulator te openen bij het starten van SSH-sessies.",
"dirEmpty": "Zorg ervoor dat de map leeg is.",
"disconnected": "Verbroken",
"disk": "Schijf",
@@ -48,6 +49,7 @@
"editVirtKeys": "Virtuele toetsen bewerken",
"editor": "Editor",
"editorHighlightTip": "De huidige codehighlighting-prestaties zijn slechter en kunnen optioneel worden uitgeschakeld om te verbeteren.",
"emulator": "Emulator",
"encode": "Coderen",
"envVars": "Omgevingsvariabele",
"experimentalFeature": "Experimentele functie",

View File

@@ -32,6 +32,7 @@
"decode": "Decodificar",
"decompress": "Descomprimir",
"deleteServers": "Excluir servidores em lote",
"desktopTerminalTip": "Comando usado para abrir o emulador de terminal ao iniciar sessões SSH.",
"dirEmpty": "Certifique-se de que a pasta está vazia",
"disconnected": "Desconectado",
"disk": "Disco",
@@ -48,6 +49,7 @@
"editVirtKeys": "Editar teclas virtuais",
"editor": "Editor",
"editorHighlightTip": "O desempenho do destaque de código atualmente é ruim, pode optar por desativá-lo para melhorar.",
"emulator": "Emulador",
"encode": "Codificar",
"envVars": "Variável de ambiente",
"experimentalFeature": "Recurso experimental",

View File

@@ -32,6 +32,7 @@
"decode": "Декодировать",
"decompress": "Разархивировать",
"deleteServers": "Удалить серверы пакетно",
"desktopTerminalTip": "Команда для открытия эмулятора терминала при запуске SSH-сеансов.",
"dirEmpty": "Пожалуйста, убедитесь, что папка пуста",
"disconnected": "Отключено",
"disk": "Диск",
@@ -48,6 +49,7 @@
"editVirtKeys": "Редактировать виртуальные клавиши",
"editor": "Редактор",
"editorHighlightTip": "Текущая производительность подсветки кода неудовлетворительна, можно отключить для улучшения.",
"emulator": "Эмулятор",
"encode": "Кодировать",
"envVars": "Переменная окружения",
"experimentalFeature": "Экспериментальная функция",

View File

@@ -32,6 +32,7 @@
"decode": "Çöz",
"decompress": "Sıkıştırmayı aç",
"deleteServers": "Sunucuları toplu sil",
"desktopTerminalTip": "SSH oturumları başlatılırken terminal öykünücüsünü açmak için kullanılan komut.",
"dirEmpty": "Klasörün boş olduğundan emin olun.",
"disconnected": "Bağlantı kesildi",
"disk": "Disk",
@@ -48,6 +49,7 @@
"editVirtKeys": "Sanal tuşları düzenle",
"editor": "Düzenleyici",
"editorHighlightTip": "Mevcut kod vurgulama performansı ideal değil ve isteğe bağlı olarak kapatılabilir.",
"emulator": "Emülatör",
"encode": "Kodla",
"envVars": "Ortam değişkeni",
"experimentalFeature": "Deneysel özellik",

View File

@@ -32,6 +32,7 @@
"decode": "Декодувати",
"decompress": "Розпакувати",
"deleteServers": "Масове видалення серверів",
"desktopTerminalTip": "Команда для відкриття емулятора термінала під час запуску SSH-сеансів.",
"dirEmpty": "Переконайтеся, що директорія пуста.",
"disconnected": "Відключено",
"disk": "Диск",
@@ -48,6 +49,7 @@
"editVirtKeys": "Редагувати віртуальні клавіші",
"editor": "Редактор",
"editorHighlightTip": "Поточна підсвітка коду не ідеальна і може бути вимкнена для покращення.",
"emulator": "Емулятор",
"encode": "Кодувати",
"envVars": "Змінні середовища",
"experimentalFeature": "Експериментальна функція",

View File

@@ -32,6 +32,7 @@
"decode": "解码",
"decompress": "解压缩",
"deleteServers": "批量删除服务器",
"desktopTerminalTip": "启动 SSH 连接所用的终端模拟器命令",
"dirEmpty": "请确保文件夹为空",
"disconnected": "连接断开",
"disk": "磁盘",
@@ -48,6 +49,7 @@
"editVirtKeys": "编辑虚拟按键",
"editor": "编辑器",
"editorHighlightTip": "目前的代码高亮性能较为糟糕,可以选择关闭以改善。",
"emulator": "模拟器",
"encode": "编码",
"envVars": "环境变量",
"experimentalFeature": "实验性功能",

View File

@@ -32,6 +32,7 @@
"decode": "解碼",
"decompress": "解壓縮",
"deleteServers": "批量刪除伺服器",
"desktopTerminalTip": "啟動 SSH 連線時用於打開終端機模擬器的指令。",
"dirEmpty": "請確保資料夾為空",
"disconnected": "連接斷開",
"disk": "磁碟",
@@ -48,6 +49,7 @@
"editVirtKeys": "編輯虛擬按鍵",
"editor": "編輯器",
"editorHighlightTip": "目前的代碼高亮性能較為糟糕,可以選擇關閉以改善。",
"emulator": "模擬器",
"encode": "編碼",
"envVars": "環境變量",
"experimentalFeature": "實驗性功能",

View File

@@ -9,6 +9,7 @@ extension _SSH on _AppSettingsPageState {
_buildTermTheme(),
_buildFont(),
_buildTermFontSize(),
if (isDesktop) _buildDesktopTerminal(),
_buildSSHVirtualKeyAutoOff(),
if (isMobile) _buildSSHVirtKeys(),
].map((e) => CardX(child: e)).toList(),
@@ -37,15 +38,10 @@ extension _SSH on _AppSettingsPageState {
return ListTile(
leading: const Icon(MingCute.font_fill),
title: Text(l10n.font),
trailing: _setting.fontPath.listenable().listenVal(
(val) {
trailing: _setting.fontPath.listenable().listenVal((val) {
final fontName = val.getFileName();
return Text(
fontName ?? libL10n.empty,
style: UIs.text15,
);
},
),
return Text(fontName ?? libL10n.empty, style: UIs.text15);
}),
onTap: () {
context.showRoundDialog(
title: l10n.font,
@@ -61,7 +57,7 @@ extension _SSH on _AppSettingsPageState {
RNodes.app.notify();
},
child: Text(libL10n.clear),
)
),
],
);
},
@@ -85,6 +81,42 @@ extension _SSH on _AppSettingsPageState {
RNodes.app.notify();
}
Widget _buildDesktopTerminal() {
return _setting.desktopTerminal.listenable().listenVal((val) {
return ListTile(
leading: const Icon(Icons.terminal),
title: TipText(l10n.terminal, l10n.desktopTerminalTip),
trailing: Text(
val,
style: UIs.text15,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onTap: () async {
final ctrl = TextEditingController(text: val);
void onSave() {
_setting.desktopTerminal.put(ctrl.text.trim());
context.pop();
}
context.showRoundDialog<bool>(
title: libL10n.select,
child: Input(
controller: ctrl,
autoFocus: true,
label: l10n.terminal,
hint: 'x-terminal-emulator / gnome-terminal',
icon: Icons.edit,
suggestion: false,
onSubmitted: (_) => onSave(),
),
actions: Btn.ok(onTap: onSave).toList,
);
},
);
});
}
Widget _buildTermTheme() {
String index2Str(int index) {
switch (index) {
@@ -104,10 +136,7 @@ extension _SSH on _AppSettingsPageState {
title: Text(l10n.theme),
trailing: ValBuilder(
listenable: _setting.termTheme.listenable(),
builder: (val) => Text(
index2Str(val),
style: UIs.text15,
),
builder: (val) => Text(index2Str(val), style: UIs.text15),
),
onTap: () async {
final selected = await context.showPickSingleDialog(
@@ -140,7 +169,9 @@ extension _SSH on _AppSettingsPageState {
// style: UIs.textGrey,
// ),
title: TipText(
l10n.letterCache, '${l10n.letterCacheTip}\n${l10n.needRestart}'),
l10n.letterCache,
'${l10n.letterCacheTip}\n${l10n.needRestart}',
),
trailing: StoreSwitch(prop: _setting.letterCache),
);
}

View File

@@ -22,10 +22,7 @@ import 'package:server_box/view/page/systemd.dart';
class ServerFuncBtnsTopRight extends StatelessWidget {
final Spi spi;
const ServerFuncBtnsTopRight({
super.key,
required this.spi,
});
const ServerFuncBtnsTopRight({super.key, required this.spi});
@override
Widget build(BuildContext context) {
@@ -38,10 +35,7 @@ class ServerFuncBtnsTopRight extends StatelessWidget {
}
class ServerFuncBtns extends StatelessWidget {
const ServerFuncBtns({
super.key,
required this.spi,
});
const ServerFuncBtns({super.key, required this.spi});
final Spi spi;
@@ -86,7 +80,7 @@ class ServerFuncBtns extends StatelessWidget {
padding: EdgeInsets.zero,
icon: Icon(e.icon, size: 17),
),
Text(e.toStr, style: UIs.text11Grey)
Text(e.toStr, style: UIs.text11Grey),
],
),
);
@@ -107,11 +101,7 @@ class ServerFuncBtns extends StatelessWidget {
}
}
void _onTapMoreBtns(
ServerFuncBtn value,
Spi spi,
BuildContext context,
) async {
void _onTapMoreBtns(ServerFuncBtn value, Spi spi, BuildContext context) async {
// final isMobile = ResponsiveBreakpoints.of(context).isMobile;
switch (value) {
// case ServerFuncBtn.pkg:
@@ -153,16 +143,8 @@ void _onTapMoreBtns(
final fmted = snippet.fmtWithSpi(spi);
final sure = await context.showRoundDialog<bool>(
title: libL10n.attention,
child: SingleChildScrollView(
child: SimpleMarkdown(data: '```shell\n$fmted\n```'),
),
actions: [
CountDownBtn(
onTap: () => context.pop(true),
text: l10n.run,
afterColor: Colors.red,
),
],
child: SingleChildScrollView(child: SimpleMarkdown(data: '```shell\n$fmted\n```')),
actions: [CountDownBtn(onTap: () => context.pop(true), text: l10n.run, afterColor: Colors.red)],
);
if (sure != true) return;
if (!_checkClient(context, spi.id)) return;
@@ -178,13 +160,13 @@ void _onTapMoreBtns(
case ServerFuncBtn.container:
if (!_checkClient(context, spi.id)) return;
final args = SpiRequiredArgs(spi);
if (isMobile) {
// if (isMobile) {
ContainerPage.route.go(context, args);
} else {
SplitViewNavigator.of(context)?.replace(
ContainerPage.route.toWidget(args: args),
);
}
// } else {
// SplitViewNavigator.of(
// context,
// )?.replace(ContainerPage.route.toWidget(args: args));
// }
break;
case ServerFuncBtn.process:
if (!_checkClient(context, spi.id)) return;
@@ -260,7 +242,23 @@ void _gotoSSH(Spi spi, BuildContext context) async {
await Process.start('cmd', ['/c', 'start'] + sshCommand);
break;
case Pfs.linux:
await Process.start('x-terminal-emulator', ['-e'] + sshCommand);
final scriptFile = File('${Directory.systemTemp.path}/srvbox_launch_term.sh');
await scriptFile.writeAsString(_runEmulatorShell);
if (Platform.isLinux || Platform.isMacOS) {
await Process.run('chmod', ['+x', scriptFile.path]);
}
try {
var terminal = Stores.setting.desktopTerminal.fetch();
if (terminal.isEmpty) terminal = 'x-terminal-emulator';
await Process.start(scriptFile.path, [terminal, ...sshCommand]);
} catch (e, s) {
context.showErrDialog(e, s, l10n.emulator);
} finally {
await scriptFile.delete();
}
break;
default:
context.showSnackBar('Mismatch system: $system');
@@ -280,3 +278,62 @@ bool _checkClient(BuildContext context, String id) {
}
return true;
}
const _runEmulatorShell = '''
#!/bin/sh
# launch_terminal.sh
TERMINAL="\$1"
shift # Remove the first argument (terminal name)
# Auto detect terminal if not provided
if [ -z "\$TERMINAL" ] || [ "\$TERMINAL" = "x-terminal-emulator" ]; then
# Follow the order of preference
for term in kitty alacritty gnome-terminal konsole xfce4-terminal terminator tilix wezterm foot; do
if command -v "\$term" >/dev/null 2>&1; then
TERMINAL="\$term"
break
fi
done
[ -z "\$TERMINAL" ] && TERMINAL="x-terminal-emulator"
fi
case "\$TERMINAL" in
gnome-terminal)
exec "\$TERMINAL" -- "\$@"
;;
konsole|terminator|tilix)
exec "\$TERMINAL" -e "\$@"
;;
xfce4-terminal)
exec "\$TERMINAL" -e "\$*"
;;
alacritty)
# Check alacritty version
if "\$TERMINAL" --version 2>&1 | grep -q "alacritty 0\\.1[3-9]"; then
# 0.13.0+
exec "\$TERMINAL" --command "\$@"
else
# Old versions
exec "\$TERMINAL" -e "\$@"
fi
;;
kitty)
exec "\$TERMINAL" "\$@"
;;
wezterm)
exec "\$TERMINAL" start -- "\$@"
;;
foot)
exec "\$TERMINAL" "\$@"
;;
urxvt|rxvt-unicode)
exec "\$TERMINAL" -e "\$@"
;;
x-terminal-emulator|*)
# Default
exec "\$TERMINAL" -e "\$@"
;;
esac
''';