mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
new: setting of termCursor type
This commit is contained in:
12
lib/core/extension/enum.dart
Normal file
12
lib/core/extension/enum.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
extension EnumListX<T> on List<T> {
|
||||||
|
T fromIndex(int index, [T? defaultValue]) {
|
||||||
|
try {
|
||||||
|
return this[index];
|
||||||
|
} catch (e) {
|
||||||
|
if (defaultValue != null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw Exception('Invalid index: $index');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:toolbox/core/persistant_store.dart';
|
import 'package:toolbox/core/persistant_store.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
import 'package:toolbox/core/utils/platform/base.dart';
|
||||||
import 'package:toolbox/data/model/app/menu/server_func.dart';
|
import 'package:toolbox/data/model/app/menu/server_func.dart';
|
||||||
|
import 'package:xterm/ui.dart';
|
||||||
|
|
||||||
import '../model/app/net_view.dart';
|
import '../model/app/net_view.dart';
|
||||||
import '../res/default.dart';
|
import '../res/default.dart';
|
||||||
@@ -255,6 +256,10 @@ class SettingStore extends PersistentStore {
|
|||||||
/// 0: unset, 1: use, 2: not use
|
/// 0: unset, 1: use, 2: not use
|
||||||
late final useCdn = property('useCdn', 0);
|
late final useCdn = property('useCdn', 0);
|
||||||
|
|
||||||
|
/// Index of terminal cursor type
|
||||||
|
late final termCursor =
|
||||||
|
property('termCursor', TerminalCursorType.block.index);
|
||||||
|
|
||||||
// Never show these settings for users
|
// Never show these settings for users
|
||||||
//
|
//
|
||||||
// ------BEGIN------
|
// ------BEGIN------
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "Pfad kopieren",
|
"copyPath": "Pfad kopieren",
|
||||||
"createFile": "Datei erstellen",
|
"createFile": "Datei erstellen",
|
||||||
"createFolder": "Ordner erstellen",
|
"createFolder": "Ordner erstellen",
|
||||||
|
"cursorType": "Cursor-Typ",
|
||||||
"dark": "Dunkel",
|
"dark": "Dunkel",
|
||||||
"debug": "Debug",
|
"debug": "Debug",
|
||||||
"decode": "Decode",
|
"decode": "Decode",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "Copy path",
|
"copyPath": "Copy path",
|
||||||
"createFile": "Create file",
|
"createFile": "Create file",
|
||||||
"createFolder": "Create folder",
|
"createFolder": "Create folder",
|
||||||
|
"cursorType": "Cursor type",
|
||||||
"dark": "Dark",
|
"dark": "Dark",
|
||||||
"debug": "Debug",
|
"debug": "Debug",
|
||||||
"decode": "Decode",
|
"decode": "Decode",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "Copiar ruta",
|
"copyPath": "Copiar ruta",
|
||||||
"createFile": "Crear archivo",
|
"createFile": "Crear archivo",
|
||||||
"createFolder": "Crear carpeta",
|
"createFolder": "Crear carpeta",
|
||||||
|
"cursorType": "Tipo de cursor",
|
||||||
"dark": "Oscuro",
|
"dark": "Oscuro",
|
||||||
"debug": "Depurar",
|
"debug": "Depurar",
|
||||||
"decode": "Decodificar",
|
"decode": "Decodificar",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "Copier le chemin",
|
"copyPath": "Copier le chemin",
|
||||||
"createFile": "Créer un fichier",
|
"createFile": "Créer un fichier",
|
||||||
"createFolder": "Créer un dossier",
|
"createFolder": "Créer un dossier",
|
||||||
|
"cursorType": "Type de curseur",
|
||||||
"dark": "Sombre",
|
"dark": "Sombre",
|
||||||
"debug": "Déboguer",
|
"debug": "Déboguer",
|
||||||
"decode": "Décoder",
|
"decode": "Décoder",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "Path Copy",
|
"copyPath": "Path Copy",
|
||||||
"createFile": "Buat file",
|
"createFile": "Buat file",
|
||||||
"createFolder": "Membuat folder",
|
"createFolder": "Membuat folder",
|
||||||
|
"cursorType": "Jenis kursor",
|
||||||
"dark": "Gelap",
|
"dark": "Gelap",
|
||||||
"debug": "Debug",
|
"debug": "Debug",
|
||||||
"decode": "Membaca sandi",
|
"decode": "Membaca sandi",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "パスをコピー",
|
"copyPath": "パスをコピー",
|
||||||
"createFile": "ファイルを作成",
|
"createFile": "ファイルを作成",
|
||||||
"createFolder": "フォルダーを作成",
|
"createFolder": "フォルダーを作成",
|
||||||
|
"cursorType": "カーソルタイプ",
|
||||||
"dark": "ダーク",
|
"dark": "ダーク",
|
||||||
"debug": "デバッグ",
|
"debug": "デバッグ",
|
||||||
"decode": "デコード",
|
"decode": "デコード",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "Copiar caminho",
|
"copyPath": "Copiar caminho",
|
||||||
"createFile": "Criar arquivo",
|
"createFile": "Criar arquivo",
|
||||||
"createFolder": "Criar pasta",
|
"createFolder": "Criar pasta",
|
||||||
|
"cursorType": "Tipo de cursor",
|
||||||
"dark": "Escuro",
|
"dark": "Escuro",
|
||||||
"debug": "Debugar",
|
"debug": "Debugar",
|
||||||
"decode": "Decodificar",
|
"decode": "Decodificar",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "копировать путь",
|
"copyPath": "копировать путь",
|
||||||
"createFile": "создать файл",
|
"createFile": "создать файл",
|
||||||
"createFolder": "создать папку",
|
"createFolder": "создать папку",
|
||||||
|
"cursorType": "Тип курсора",
|
||||||
"dark": "темная",
|
"dark": "темная",
|
||||||
"debug": "отладка",
|
"debug": "отладка",
|
||||||
"decode": "декодировать",
|
"decode": "декодировать",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "复制路径",
|
"copyPath": "复制路径",
|
||||||
"createFile": "创建文件",
|
"createFile": "创建文件",
|
||||||
"createFolder": "创建文件夹",
|
"createFolder": "创建文件夹",
|
||||||
|
"cursorType": "光标类型",
|
||||||
"dark": "暗",
|
"dark": "暗",
|
||||||
"debug": "调试",
|
"debug": "调试",
|
||||||
"decode": "解码",
|
"decode": "解码",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"copyPath": "複製路徑",
|
"copyPath": "複製路徑",
|
||||||
"createFile": "創建文件",
|
"createFile": "創建文件",
|
||||||
"createFolder": "創建文件夾",
|
"createFolder": "創建文件夾",
|
||||||
|
"cursorType": "光標類型",
|
||||||
"dark": "暗",
|
"dark": "暗",
|
||||||
"debug": "調試",
|
"debug": "調試",
|
||||||
"decode": "解碼",
|
"decode": "解碼",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:toolbox/core/extension/colorx.dart';
|
|||||||
import 'package:toolbox/core/extension/context/common.dart';
|
import 'package:toolbox/core/extension/context/common.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/core/extension/context/snackbar.dart';
|
import 'package:toolbox/core/extension/context/snackbar.dart';
|
||||||
|
import 'package:toolbox/core/extension/enum.dart';
|
||||||
import 'package:toolbox/core/extension/locale.dart';
|
import 'package:toolbox/core/extension/locale.dart';
|
||||||
import 'package:toolbox/core/extension/context/dialog.dart';
|
import 'package:toolbox/core/extension/context/dialog.dart';
|
||||||
import 'package:toolbox/core/extension/stringx.dart';
|
import 'package:toolbox/core/extension/stringx.dart';
|
||||||
@@ -17,6 +18,7 @@ import 'package:toolbox/data/res/provider.dart';
|
|||||||
import 'package:toolbox/data/res/rebuild.dart';
|
import 'package:toolbox/data/res/rebuild.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
import 'package:toolbox/view/widget/expand_tile.dart';
|
import 'package:toolbox/view/widget/expand_tile.dart';
|
||||||
|
import 'package:xterm/ui.dart';
|
||||||
|
|
||||||
import '../../../core/persistant_store.dart';
|
import '../../../core/persistant_store.dart';
|
||||||
import '../../../core/route.dart';
|
import '../../../core/route.dart';
|
||||||
@@ -42,44 +44,8 @@ class SettingPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SettingPageState extends State<SettingPage> {
|
class _SettingPageState extends State<SettingPage> {
|
||||||
final _themeKey = GlobalKey<PopupMenuButtonState<int>>();
|
|
||||||
final _updateIntervalKey = GlobalKey<PopupMenuButtonState<int>>();
|
|
||||||
final _maxRetryKey = GlobalKey<PopupMenuButtonState<int>>();
|
|
||||||
final _localeKey = GlobalKey<PopupMenuButtonState<String>>();
|
|
||||||
final _editorThemeKey = GlobalKey<PopupMenuButtonState<String>>();
|
|
||||||
final _editorDarkThemeKey = GlobalKey<PopupMenuButtonState<String>>();
|
|
||||||
final _keyboardTypeKey = GlobalKey<PopupMenuButtonState<int>>();
|
|
||||||
//final _rotateQuarterKey = GlobalKey<PopupMenuButtonState<int>>();
|
|
||||||
final _netViewTypeKey = GlobalKey<PopupMenuButtonState<NetViewType>>();
|
|
||||||
final _setting = Stores.setting;
|
final _setting = Stores.setting;
|
||||||
|
|
||||||
late final _selectedColorValue = ValueNotifier(_setting.primaryColor.fetch());
|
|
||||||
late final _nightMode = ValueNotifier(_setting.themeMode.fetch());
|
|
||||||
late final _maxRetryCount = ValueNotifier(_setting.maxRetryCount.fetch());
|
|
||||||
late final _updateInterval =
|
|
||||||
ValueNotifier(_setting.serverStatusUpdateInterval.fetch());
|
|
||||||
late final _termFontSize = ValueNotifier(_setting.termFontSize.fetch());
|
|
||||||
late final _editorFontSize = ValueNotifier(_setting.editorFontSize.fetch());
|
|
||||||
late final _localeCode = ValueNotifier('');
|
|
||||||
late final _editorTheme = ValueNotifier(_setting.editorTheme.fetch());
|
|
||||||
late final _editorDarkTheme = ValueNotifier(_setting.editorDarkTheme.fetch());
|
|
||||||
late final _keyboardType = ValueNotifier(_setting.keyboardType.fetch());
|
|
||||||
// late final _rotateQuarter =
|
|
||||||
// ValueNotifier(_setting.fullScreenRotateQuarter.fetch());
|
|
||||||
late final _netViewType = ValueNotifier(_setting.netViewType.fetch());
|
|
||||||
late final _textScaler = ValueNotifier(_setting.textFactor.fetch());
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
final localeSettingVal = _setting.locale.fetch();
|
|
||||||
if (localeSettingVal.isEmpty) {
|
|
||||||
_localeCode.value = l10n.localeName;
|
|
||||||
} else {
|
|
||||||
_localeCode.value = localeSettingVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -206,6 +172,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
children: [
|
children: [
|
||||||
_buildFont(),
|
_buildFont(),
|
||||||
_buildTermFontSize(),
|
_buildTermFontSize(),
|
||||||
|
_buildTermCursor(),
|
||||||
_buildSSHVirtualKeyAutoOff(),
|
_buildSSHVirtualKeyAutoOff(),
|
||||||
// Use hardware keyboard on desktop, so there is no need to set it
|
// Use hardware keyboard on desktop, so there is no need to set it
|
||||||
if (isMobile) _buildKeyboardType(),
|
if (isMobile) _buildKeyboardType(),
|
||||||
@@ -249,17 +216,6 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildUpdateInterval() {
|
Widget _buildUpdateInterval() {
|
||||||
final items = List.generate(
|
|
||||||
10,
|
|
||||||
(index) => PopupMenuItem(
|
|
||||||
value: index,
|
|
||||||
child: Text(index == 0 ? l10n.manual : '$index ${l10n.second}'),
|
|
||||||
),
|
|
||||||
growable: false,
|
|
||||||
).toList();
|
|
||||||
// 1 second is too fast, so remove it
|
|
||||||
items.removeAt(1);
|
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
l10n.updateServerStatusInterval,
|
l10n.updateServerStatusInterval,
|
||||||
@@ -268,39 +224,33 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
l10n.willTakEeffectImmediately,
|
l10n.willTakEeffectImmediately,
|
||||||
style: UIs.textGrey,
|
style: UIs.textGrey,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
_updateIntervalKey.currentState?.showButtonMenu();
|
final val = await context.showPickSingleDialog(
|
||||||
},
|
items: List.generate(10, (idx) => idx == 1 ? null : idx),
|
||||||
trailing: ListenableBuilder(
|
initial: _setting.serverStatusUpdateInterval.fetch(),
|
||||||
listenable: _updateInterval,
|
name: (p0) => p0 == 0 ? l10n.manual : '$p0 ${l10n.second}',
|
||||||
builder: (_, __) => PopupMenuButton(
|
);
|
||||||
key: _updateIntervalKey,
|
if (val != null) {
|
||||||
itemBuilder: (_) => items,
|
|
||||||
initialValue: _updateInterval.value,
|
|
||||||
onSelected: (int val) {
|
|
||||||
_updateInterval.value = val;
|
|
||||||
_setting.serverStatusUpdateInterval.put(val);
|
_setting.serverStatusUpdateInterval.put(val);
|
||||||
Pros.server.startAutoRefresh();
|
|
||||||
if (val == 0) {
|
|
||||||
context.showSnackBar(l10n.updateIntervalEqual0);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
trailing: ValueListenableBuilder(
|
||||||
'${_updateInterval.value} ${l10n.second}',
|
valueListenable: _setting.serverStatusUpdateInterval.listenable(),
|
||||||
|
builder: (_, val, __) => Text(
|
||||||
|
'$val ${l10n.second}',
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAppColor() {
|
Widget _buildAppColor() {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
trailing: ClipOval(
|
trailing: ClipOval(
|
||||||
child: ListenableBuilder(
|
child: ValueListenableBuilder(
|
||||||
listenable: _selectedColorValue,
|
valueListenable: _setting.primaryColor.listenable(),
|
||||||
builder: (_, __) => Container(
|
builder: (_, val, __) => Container(
|
||||||
color: primaryColor,
|
color: Color(val),
|
||||||
height: 27,
|
height: 27,
|
||||||
width: 27,
|
width: 27,
|
||||||
),
|
),
|
||||||
@@ -362,8 +312,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
// Change [primaryColor] first, then change [_selectedColorValue],
|
// Change [primaryColor] first, then change [_selectedColorValue],
|
||||||
// So the [ValueBuilder] will be triggered with the new value
|
// So the [ValueBuilder] will be triggered with the new value
|
||||||
primaryColor = color;
|
primaryColor = color;
|
||||||
_selectedColorValue.value = color.value;
|
_setting.primaryColor.put(color.value);
|
||||||
_setting.primaryColor.put(_selectedColorValue.value);
|
|
||||||
context.pop();
|
context.pop();
|
||||||
RebuildNodes.app.rebuild();
|
RebuildNodes.app.rebuild();
|
||||||
}
|
}
|
||||||
@@ -409,91 +358,59 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
Widget _buildMaxRetry() {
|
Widget _buildMaxRetry() {
|
||||||
final items = List.generate(
|
return ValueListenableBuilder(
|
||||||
10,
|
valueListenable: _setting.maxRetryCount.listenable(),
|
||||||
(index) => PopupMenuItem(
|
builder: (_, val, __) => ListTile(
|
||||||
value: index,
|
|
||||||
child: Text('$index ${l10n.times}'),
|
|
||||||
),
|
|
||||||
growable: false,
|
|
||||||
).toList();
|
|
||||||
final help = _maxRetryCount.value == 0
|
|
||||||
? l10n.maxRetryCountEqual0
|
|
||||||
: l10n.canPullRefresh;
|
|
||||||
|
|
||||||
return ListTile(
|
|
||||||
title: Text(
|
title: Text(
|
||||||
l10n.maxRetryCount,
|
l10n.maxRetryCount,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
),
|
),
|
||||||
subtitle: Text(help, style: UIs.textGrey),
|
subtitle: Text(
|
||||||
onTap: () {
|
val == 0 ? l10n.maxRetryCountEqual0 : l10n.canPullRefresh,
|
||||||
_maxRetryKey.currentState?.showButtonMenu();
|
style: UIs.textGrey),
|
||||||
|
onTap: () async {
|
||||||
|
final selected = await context.showPickSingleDialog(
|
||||||
|
items: List.generate(10, (index) => index),
|
||||||
|
name: (p0) => '$p0 ${l10n.times}',
|
||||||
|
initial: val,
|
||||||
|
);
|
||||||
|
if (selected != null) {
|
||||||
|
_setting.maxRetryCount.put(selected);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
trailing: ListenableBuilder(
|
trailing: Text(
|
||||||
builder: (_, __) => PopupMenuButton(
|
'$val ${l10n.times}',
|
||||||
key: _maxRetryKey,
|
|
||||||
itemBuilder: (BuildContext context) => items,
|
|
||||||
initialValue: _maxRetryCount.value,
|
|
||||||
onSelected: (int val) {
|
|
||||||
_maxRetryCount.value = val;
|
|
||||||
_setting.maxRetryCount.put(_maxRetryCount.value);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'${_maxRetryCount.value} ${l10n.times}',
|
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
listenable: _maxRetryCount,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildThemeMode() {
|
Widget _buildThemeMode() {
|
||||||
final items = ThemeMode.values
|
|
||||||
.map(
|
|
||||||
(e) => PopupMenuItem(
|
|
||||||
value: e.index,
|
|
||||||
child: Text(_buildThemeModeStr(e.index)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
// Issue #57
|
// Issue #57
|
||||||
final len = ThemeMode.values.length;
|
final len = ThemeMode.values.length;
|
||||||
|
|
||||||
/// Add AMOLED theme
|
|
||||||
items.add(PopupMenuItem(value: len, child: Text(_buildThemeModeStr(len))));
|
|
||||||
|
|
||||||
/// Add AUTO-AMOLED theme
|
|
||||||
items.add(
|
|
||||||
PopupMenuItem(value: len + 1, child: Text(_buildThemeModeStr(len + 1))),
|
|
||||||
);
|
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
l10n.themeMode,
|
l10n.themeMode,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
_themeKey.currentState?.showButtonMenu();
|
final selected = await context.showPickSingleDialog(
|
||||||
},
|
items: List.generate(len + 2, (index) => index),
|
||||||
trailing: ListenableBuilder(
|
name: (p0) => _buildThemeModeStr(p0),
|
||||||
listenable: _nightMode,
|
initial: _setting.themeMode.fetch(),
|
||||||
builder: (_, __) => PopupMenuButton(
|
);
|
||||||
key: _themeKey,
|
if (selected != null) {
|
||||||
itemBuilder: (BuildContext context) => items,
|
_setting.themeMode.put(selected);
|
||||||
initialValue: _nightMode.value,
|
|
||||||
onSelected: (int idx) {
|
|
||||||
_nightMode.value = idx;
|
|
||||||
_setting.themeMode.put(_nightMode.value);
|
|
||||||
|
|
||||||
RebuildNodes.app.rebuild();
|
RebuildNodes.app.rebuild();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
trailing: ValueListenableBuilder(
|
||||||
_buildThemeModeStr(_nightMode.value),
|
valueListenable: _setting.themeMode.listenable(),
|
||||||
|
builder: (_, val, __) => Text(
|
||||||
|
_buildThemeModeStr(val),
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,7 +490,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => _showFontSizeDialog(_termFontSize, _setting.termFontSize),
|
onTap: () => _showFontSizeDialog(_setting.termFontSize),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,37 +532,27 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
Widget _buildLocale() {
|
Widget _buildLocale() {
|
||||||
final items = S.supportedLocales
|
|
||||||
.map(
|
|
||||||
(e) => PopupMenuItem<String>(
|
|
||||||
value: e.code,
|
|
||||||
child: Text(e.code),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(l10n.language),
|
title: Text(l10n.language),
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
_localeKey.currentState?.showButtonMenu();
|
final selected = await context.showPickSingleDialog(
|
||||||
},
|
items: S.supportedLocales,
|
||||||
trailing: ListenableBuilder(
|
name: (p0) => p0.code,
|
||||||
listenable: _localeCode,
|
initial: _setting.locale.fetch().toLocale,
|
||||||
builder: (_, __) => PopupMenuButton(
|
);
|
||||||
key: _localeKey,
|
if (selected != null) {
|
||||||
itemBuilder: (BuildContext context) => items,
|
_setting.locale.put(selected.code);
|
||||||
initialValue: _localeCode.value,
|
|
||||||
onSelected: (String idx) {
|
|
||||||
_localeCode.value = idx;
|
|
||||||
_setting.locale.put(idx);
|
|
||||||
RebuildNodes.app.rebuild();
|
|
||||||
context.pop();
|
context.pop();
|
||||||
|
RebuildNodes.app.rebuild();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
trailing: ValueListenableBuilder(
|
||||||
|
valueListenable: _setting.locale.listenable(),
|
||||||
|
builder: (_, ___, __) => Text(
|
||||||
l10n.languageName,
|
l10n.languageName,
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,67 +565,41 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEditorTheme() {
|
Widget _buildEditorTheme() {
|
||||||
final items = themeMap.keys.map(
|
|
||||||
(key) {
|
|
||||||
return PopupMenuItem<String>(
|
|
||||||
value: key,
|
|
||||||
child: Text(key),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).toList();
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text('${l10n.light} ${l10n.theme.toLowerCase()}'),
|
title: Text('${l10n.light} ${l10n.theme.toLowerCase()}'),
|
||||||
trailing: ListenableBuilder(
|
trailing: ValueListenableBuilder(
|
||||||
listenable: _editorTheme,
|
valueListenable: _setting.editorTheme.listenable(),
|
||||||
builder: (_, __) => PopupMenuButton(
|
builder: (_, val, __) => Text(val, style: UIs.text15),
|
||||||
key: _editorThemeKey,
|
|
||||||
itemBuilder: (BuildContext context) => items,
|
|
||||||
initialValue: _editorTheme.value,
|
|
||||||
onSelected: (String idx) {
|
|
||||||
_editorTheme.value = idx;
|
|
||||||
_setting.editorTheme.put(idx);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
_editorTheme.value,
|
|
||||||
style: UIs.text15,
|
|
||||||
),
|
),
|
||||||
),
|
onTap: () async {
|
||||||
),
|
final selected = await context.showPickSingleDialog(
|
||||||
onTap: () {
|
items: themeMap.keys.toList(),
|
||||||
_editorThemeKey.currentState?.showButtonMenu();
|
name: (p0) => p0,
|
||||||
|
initial: _setting.editorTheme.fetch(),
|
||||||
|
);
|
||||||
|
if (selected != null) {
|
||||||
|
_setting.editorTheme.put(selected);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEditorDarkTheme() {
|
Widget _buildEditorDarkTheme() {
|
||||||
final items = themeMap.keys.map(
|
|
||||||
(key) {
|
|
||||||
return PopupMenuItem<String>(
|
|
||||||
value: key,
|
|
||||||
child: Text(key),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).toList();
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text('${l10n.dark} ${l10n.theme.toLowerCase()}'),
|
title: Text('${l10n.dark} ${l10n.theme.toLowerCase()}'),
|
||||||
trailing: ListenableBuilder(
|
trailing: ValueListenableBuilder(
|
||||||
listenable: _editorDarkTheme,
|
valueListenable: _setting.editorDarkTheme.listenable(),
|
||||||
builder: (_, __) => PopupMenuButton(
|
builder: (_, val, __) => Text(val, style: UIs.text15),
|
||||||
key: _editorDarkThemeKey,
|
|
||||||
itemBuilder: (BuildContext context) => items,
|
|
||||||
initialValue: _editorDarkTheme.value,
|
|
||||||
onSelected: (String idx) {
|
|
||||||
_editorDarkTheme.value = idx;
|
|
||||||
_setting.editorDarkTheme.put(idx);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
_editorDarkTheme.value,
|
|
||||||
style: UIs.text15,
|
|
||||||
),
|
),
|
||||||
),
|
onTap: () async {
|
||||||
),
|
final selected = await context.showPickSingleDialog(
|
||||||
onTap: () {
|
items: themeMap.keys.toList(),
|
||||||
_editorDarkThemeKey.currentState?.showButtonMenu();
|
name: (p0) => p0,
|
||||||
|
initial: _setting.editorDarkTheme.fetch(),
|
||||||
|
);
|
||||||
|
if (selected != null) {
|
||||||
|
_setting.editorDarkTheme.put(selected);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -788,39 +669,28 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
'address',
|
'address',
|
||||||
'none',
|
'none',
|
||||||
];
|
];
|
||||||
if (names.length != TextInputType.values.length) {
|
|
||||||
// This notify me to update the code
|
|
||||||
throw Exception('names.length != TextInputType.values.length');
|
|
||||||
}
|
|
||||||
final items = TextInputType.values.map(
|
|
||||||
(key) {
|
|
||||||
return PopupMenuItem<int>(
|
|
||||||
value: key.index,
|
|
||||||
child: Text(names[key.index]),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).toList();
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(l10n.keyboardType),
|
title: Text(l10n.keyboardType),
|
||||||
subtitle: Text(l10n.keyboardCompatibility, style: UIs.textGrey),
|
subtitle: Text(l10n.keyboardCompatibility, style: UIs.textGrey),
|
||||||
trailing: ListenableBuilder(
|
trailing: ValueListenableBuilder(
|
||||||
listenable: _keyboardType,
|
valueListenable: _setting.keyboardType.listenable(),
|
||||||
builder: (_, __) => PopupMenuButton<int>(
|
builder: (_, val, __) => Text(
|
||||||
key: _keyboardTypeKey,
|
names[val],
|
||||||
itemBuilder: (BuildContext context) => items,
|
|
||||||
initialValue: _keyboardType.value,
|
|
||||||
onSelected: (idx) {
|
|
||||||
_keyboardType.value = idx;
|
|
||||||
_setting.keyboardType.put(idx);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
names[_keyboardType.value],
|
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
onTap: () async {
|
||||||
onTap: () {
|
if (names.length != TextInputType.values.length) {
|
||||||
_keyboardTypeKey.currentState?.showButtonMenu();
|
// This notify me to update the code
|
||||||
|
context.showSnackBar('names.length != TextInputType.values.length');
|
||||||
|
}
|
||||||
|
final selected = await context.showPickSingleDialog(
|
||||||
|
items: names,
|
||||||
|
initial: names.fromIndex(_setting.keyboardType.fetch()),
|
||||||
|
);
|
||||||
|
if (selected != null) {
|
||||||
|
_setting.keyboardType.put(names.indexOf(selected));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -859,32 +729,24 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildNetViewType() {
|
Widget _buildNetViewType() {
|
||||||
final items = NetViewType.values
|
|
||||||
.map((e) => PopupMenuItem(
|
|
||||||
value: e,
|
|
||||||
child: Text(e.toStr),
|
|
||||||
))
|
|
||||||
.toList();
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(l10n.netViewType),
|
title: Text(l10n.netViewType),
|
||||||
trailing: ListenableBuilder(
|
trailing: ValueListenableBuilder(
|
||||||
listenable: _netViewType,
|
valueListenable: _setting.netViewType.listenable(),
|
||||||
builder: (_, __) => PopupMenuButton<NetViewType>(
|
builder: (_, val, __) => Text(
|
||||||
key: _netViewTypeKey,
|
val.toStr,
|
||||||
itemBuilder: (BuildContext context) => items,
|
|
||||||
initialValue: _netViewType.value,
|
|
||||||
onSelected: (idx) {
|
|
||||||
_netViewType.value = idx;
|
|
||||||
_setting.netViewType.put(idx);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
_netViewType.value.toStr,
|
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
onTap: () async {
|
||||||
onTap: () {
|
final selected = await context.showPickSingleDialog(
|
||||||
_netViewTypeKey.currentState?.showButtonMenu();
|
items: NetViewType.values,
|
||||||
|
name: (p0) => p0.toStr,
|
||||||
|
initial: _setting.netViewType.fetch(),
|
||||||
|
);
|
||||||
|
if (selected != null) {
|
||||||
|
_setting.netViewType.put(selected);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -933,14 +795,14 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTextScaler() {
|
Widget _buildTextScaler() {
|
||||||
final ctrl = TextEditingController(text: _textScaler.value.toString());
|
final ctrl = TextEditingController(text: _setting.textFactor.toString());
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(l10n.textScaler),
|
title: Text(l10n.textScaler),
|
||||||
subtitle: Text(l10n.textScalerTip, style: UIs.textGrey),
|
subtitle: Text(l10n.textScalerTip, style: UIs.textGrey),
|
||||||
trailing: ListenableBuilder(
|
trailing: ValueListenableBuilder(
|
||||||
listenable: _textScaler,
|
valueListenable: _setting.textFactor.listenable(),
|
||||||
builder: (_, __) => Text(
|
builder: (_, val, __) => Text(
|
||||||
_textScaler.value.toString(),
|
val.toString(),
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -970,7 +832,6 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
context.showSnackBar(l10n.failed);
|
context.showSnackBar(l10n.failed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_textScaler.value = val;
|
|
||||||
_setting.textFactor.put(val);
|
_setting.textFactor.put(val);
|
||||||
RebuildNodes.app.rebuild();
|
RebuildNodes.app.rebuild();
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -1019,25 +880,23 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEditorFontSize() {
|
Widget _buildEditorFontSize() {
|
||||||
return ListenableBuilder(
|
return ListTile(
|
||||||
listenable: _editorFontSize,
|
|
||||||
builder: (_, __) => ListTile(
|
|
||||||
title: Text(l10n.fontSize),
|
title: Text(l10n.fontSize),
|
||||||
trailing: Text(
|
trailing: ValueListenableBuilder(
|
||||||
_editorFontSize.value.toString(),
|
valueListenable: _setting.editorFontSize.listenable(),
|
||||||
|
builder: (_, val, __) => Text(
|
||||||
|
val.toString(),
|
||||||
style: UIs.text15,
|
style: UIs.text15,
|
||||||
),
|
),
|
||||||
onTap: () =>
|
|
||||||
_showFontSizeDialog(_editorFontSize, _setting.editorFontSize),
|
|
||||||
),
|
),
|
||||||
|
onTap: () => _showFontSizeDialog(_setting.editorFontSize),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showFontSizeDialog(
|
void _showFontSizeDialog(
|
||||||
ValueNotifier<double> notifier,
|
|
||||||
StorePropertyBase<double> property,
|
StorePropertyBase<double> property,
|
||||||
) {
|
) {
|
||||||
final ctrller = TextEditingController(text: notifier.value.toString());
|
final ctrller = TextEditingController(text: property.fetch().toString());
|
||||||
void onSave() {
|
void onSave() {
|
||||||
context.pop();
|
context.pop();
|
||||||
final fontSize = double.tryParse(ctrller.text);
|
final fontSize = double.tryParse(ctrller.text);
|
||||||
@@ -1048,7 +907,6 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notifier.value = fontSize;
|
|
||||||
property.put(fontSize);
|
property.put(fontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1199,4 +1057,28 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildTermCursor() {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(l10n.cursorType),
|
||||||
|
trailing: ValueListenableBuilder(
|
||||||
|
valueListenable: _setting.termCursor.listenable(),
|
||||||
|
builder: (_, val, __) => Text(
|
||||||
|
TerminalCursorType.values.fromIndex(val).name,
|
||||||
|
style: UIs.text15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
final selected = await context.showPickSingleDialog(
|
||||||
|
items: TerminalCursorType.values,
|
||||||
|
name: (p0) => p0.name,
|
||||||
|
initial:
|
||||||
|
TerminalCursorType.values.fromIndex(_setting.termCursor.fetch()),
|
||||||
|
);
|
||||||
|
if (selected != null) {
|
||||||
|
_setting.termCursor.put(selected.index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import 'package:toolbox/core/extension/context/locale.dart';
|
|||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
import 'package:toolbox/core/utils/platform/base.dart';
|
||||||
import 'package:toolbox/core/utils/server.dart';
|
import 'package:toolbox/core/utils/server.dart';
|
||||||
import 'package:toolbox/core/utils/share.dart';
|
import 'package:toolbox/core/utils/share.dart';
|
||||||
import 'package:toolbox/data/model/server/server.dart';
|
|
||||||
import 'package:toolbox/data/model/server/snippet.dart';
|
import 'package:toolbox/data/model/server/snippet.dart';
|
||||||
import 'package:toolbox/data/provider/virtual_keyboard.dart';
|
import 'package:toolbox/data/provider/virtual_keyboard.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
@@ -61,11 +60,11 @@ class _SSHPageState extends State<SSHPage> with AutomaticKeepAliveClientMixin {
|
|||||||
late double _originTextSize;
|
late double _originTextSize;
|
||||||
double _virtKeyWidth = 0;
|
double _virtKeyWidth = 0;
|
||||||
double _virtKeysHeight = 0;
|
double _virtKeysHeight = 0;
|
||||||
|
late final TerminalCursorType _termCursor;
|
||||||
|
|
||||||
bool _isDark = false;
|
bool _isDark = false;
|
||||||
Timer? _virtKeyLongPressTimer;
|
Timer? _virtKeyLongPressTimer;
|
||||||
late final Server? _server = widget.spi.server;
|
late SSHClient? _client = widget.spi.server?.client;
|
||||||
late SSHClient? _client = _server?.client;
|
|
||||||
Timer? _discontinuityTimer;
|
Timer? _discontinuityTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -84,13 +83,6 @@ class _SSHPageState extends State<SSHPage> with AutomaticKeepAliveClientMixin {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
_virtKeyLongPressTimer?.cancel();
|
_virtKeyLongPressTimer?.cancel();
|
||||||
_terminalController.dispose();
|
_terminalController.dispose();
|
||||||
|
|
||||||
/// Use the same [SSHClient], so don't close it
|
|
||||||
// if (_client?.isClosed == false) {
|
|
||||||
// try {
|
|
||||||
// _client?.close();
|
|
||||||
// } catch (_) {}
|
|
||||||
// }
|
|
||||||
_discontinuityTimer?.cancel();
|
_discontinuityTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +149,7 @@ class _SSHPageState extends State<SSHPage> with AutomaticKeepAliveClientMixin {
|
|||||||
deleteDetection: isMobile,
|
deleteDetection: isMobile,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
keyboardAppearance: _isDark ? Brightness.dark : Brightness.light,
|
keyboardAppearance: _isDark ? Brightness.dark : Brightness.light,
|
||||||
|
cursorType: _termCursor,
|
||||||
//hideScrollBar: false,
|
//hideScrollBar: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -377,7 +370,7 @@ class _SSHPageState extends State<SSHPage> with AutomaticKeepAliveClientMixin {
|
|||||||
//_setupDiscontinuityTimer();
|
//_setupDiscontinuityTimer();
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
_writeLn(_server?.status.err ?? 'Null session');
|
_writeLn('Null session');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,6 +487,15 @@ class _SSHPageState extends State<SSHPage> with AutomaticKeepAliveClientMixin {
|
|||||||
|
|
||||||
_terminalStyle = TerminalStyle.fromTextStyle(textStyle);
|
_terminalStyle = TerminalStyle.fromTextStyle(textStyle);
|
||||||
_keyboardType = TextInputType.values[Stores.setting.keyboardType.fetch()];
|
_keyboardType = TextInputType.values[Stores.setting.keyboardType.fetch()];
|
||||||
|
|
||||||
|
final termCursor = Stores.setting.termCursor.fetch();
|
||||||
|
_termCursor = () {
|
||||||
|
try {
|
||||||
|
return TerminalCursorType.values[termCursor];
|
||||||
|
} catch (_) {
|
||||||
|
return TerminalCursorType.block;
|
||||||
|
}
|
||||||
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user