From d66e570e01d2b7d069c6544de09f4996cf002176 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Mon, 5 Jun 2023 16:39:54 +0800 Subject: [PATCH] opt.: use `ValueBuilder` --- ios/Runner.xcodeproj/project.pbxproj | 12 +- lib/core/update.dart | 14 ++ lib/data/provider/virtual_keyboard.dart | 18 ++- lib/data/res/build_data.dart | 8 +- lib/view/page/convert.dart | 52 ++++---- lib/view/page/editor.dart | 8 +- lib/view/page/ping.dart | 140 ++++++++++++-------- lib/view/page/setting.dart | 163 +++++++++++------------- lib/view/page/ssh.dart | 2 - lib/view/widget/value_notifier.dart | 16 +++ macos/Runner.xcodeproj/project.pbxproj | 12 +- pubspec.lock | 7 +- pubspec.yaml | 3 +- 13 files changed, 264 insertions(+), 191 deletions(-) create mode 100644 lib/view/widget/value_notifier.dart diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1da7f000..9acdffbb 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 345; + CURRENT_PROJECT_VERSION = 347; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -368,7 +368,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.345; + MARKETING_VERSION = 1.0.347; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -491,7 +491,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 345; + CURRENT_PROJECT_VERSION = 347; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -499,7 +499,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.345; + MARKETING_VERSION = 1.0.347; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -516,7 +516,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 345; + CURRENT_PROJECT_VERSION = 347; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -524,7 +524,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.345; + MARKETING_VERSION = 1.0.347; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/core/update.dart b/lib/core/update.dart index c3bb30ee..f3601dc8 100644 --- a/lib/core/update.dart +++ b/lib/core/update.dart @@ -1,9 +1,13 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:logging/logging.dart'; import 'package:r_upgrade/r_upgrade.dart'; import 'package:toolbox/core/extension/navigator.dart'; +import 'package:toolbox/core/utils/misc.dart'; +import 'package:toolbox/data/res/path.dart'; import '../data/provider/app.dart'; import '../data/res/build_data.dart'; @@ -25,6 +29,8 @@ Future isFileAvailable(String url) async { } Future doUpdate(BuildContext context, {bool force = false}) async { + _rmDownloadApks(); + final update = await locator().getUpdate(); final newest = update.build.last.current; @@ -95,3 +101,11 @@ Future _doUpdate(String url, BuildContext context, S s) async { ); } } + +// rmdir Download +Future _rmDownloadApks() async { + final dlDir = Directory(pathJoin((await docDir).path, 'Download')); + if (await dlDir.exists()) { + await dlDir.delete(recursive: true); + } +} diff --git a/lib/data/provider/virtual_keyboard.dart b/lib/data/provider/virtual_keyboard.dart index b7cf5505..39e17128 100644 --- a/lib/data/provider/virtual_keyboard.dart +++ b/lib/data/provider/virtual_keyboard.dart @@ -6,8 +6,22 @@ import 'package:xterm/core.dart'; class VirtualKeyboard extends TerminalInputHandler with ChangeNotifier { VirtualKeyboard(); - bool ctrl = false; - bool alt = false; + bool _ctrl = false; + bool get ctrl => _ctrl; + set ctrl(bool value) { + if (value != _ctrl) { + _ctrl = value; + notifyListeners(); + } + } + bool _alt = false; + bool get alt => _alt; + set alt(bool value) { + if (value != _alt) { + _alt = value; + notifyListeners(); + } + } final _setting = locator(); diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 5354f5f4..1c35d1d8 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,8 +2,8 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 344; - static const String engine = "3.10.2"; - static const String buildAt = "2023-06-02 22:02:47.585289"; - static const int modifications = 4; + static const int build = 347; + static const String engine = "3.10.3"; + static const String buildAt = "2023-06-04 22:37:44.679072"; + static const int modifications = 7; } diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart index f5ec4e0f..ec6b3335 100644 --- a/lib/view/page/convert.dart +++ b/lib/view/page/convert.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/data/res/ui.dart'; +import 'package:toolbox/view/widget/value_notifier.dart'; import '../../core/utils/ui.dart'; import '../widget/input_field.dart'; @@ -24,7 +25,7 @@ class _ConvertPageState extends State late MediaQueryData _media; late S _s; - int _typeOptionIndex = 0; + final _typeOptionIndex = ValueNotifier(0); @override void initState() { @@ -76,7 +77,7 @@ class _ConvertPageState extends State String doConvert() { final text = _textEditingController.text.trim(); - switch (_typeOptionIndex) { + switch (_typeOptionIndex.value) { case 0: return utf8.decode(base64.decode(text)); case 1: @@ -136,30 +137,31 @@ class _ConvertPageState extends State ) ], ), - trailing: PopupMenu( - items: items, - initialValue: _typeOptionIndex, - onSelected: (p0) { - setState(() { - _typeOptionIndex = p0; - }); - }, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - typeOption[_typeOptionIndex], - textScaleFactor: 1.0, - textAlign: TextAlign.right, - style: const TextStyle( - fontWeight: FontWeight.w500, - color: Colors.grey, + trailing: ValueBuilder( + listenable: _typeOptionIndex, + build: () => PopupMenu( + items: items, + initialValue: _typeOptionIndex.value, + onSelected: (p0) { + _typeOptionIndex.value = p0; + }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + typeOption[_typeOptionIndex.value], + textScaleFactor: 1.0, + textAlign: TextAlign.right, + style: const TextStyle( + fontWeight: FontWeight.w500, + color: Colors.grey, + ), ), - ), - const Icon(Icons.keyboard_arrow_down, color: Colors.grey) - ], + const Icon(Icons.keyboard_arrow_down, color: Colors.grey) + ], + ), ), ), ), diff --git a/lib/view/page/editor.dart b/lib/view/page/editor.dart index a1c72294..d0230a7a 100644 --- a/lib/view/page/editor.dart +++ b/lib/view/page/editor.dart @@ -87,6 +87,10 @@ class _EditorPageState extends State with AfterLayoutMixin { child: CodeField( focusNode: _focusNode, controller: _controller, + lineNumberStyle: const LineNumberStyle( + width: 47, + margin: 7, + ), ), ), ), @@ -104,9 +108,7 @@ class _EditorPageState extends State with AfterLayoutMixin { if (widget.path != null) { await Future.delayed(const Duration(milliseconds: 233)); final code = await File(widget.path!).readAsString(); - setState(() { - _controller.text = code; - }); + _controller.text = code; } } } diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index 11091b65..10c8935a 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -3,6 +3,9 @@ import 'dart:async'; import 'package:after_layout/after_layout.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:toolbox/core/extension/navigator.dart'; +import 'package:toolbox/core/utils/misc.dart'; +import 'package:toolbox/view/widget/value_notifier.dart'; import '../../core/extension/uint8list.dart'; import '../../core/utils/ui.dart'; @@ -27,10 +30,11 @@ class PingPage extends StatefulWidget { class _PingPageState extends State with AutomaticKeepAliveClientMixin, AfterLayoutMixin { late TextEditingController _textEditingController; - late MediaQueryData _media; - final List _results = []; + final _results = ValueNotifier([]); final _serverProvider = locator(); - late S s; + late S _s; + + bool get isInit => _results.value.isEmpty; @override void initState() { @@ -41,58 +45,85 @@ class _PingPageState extends State @override void didChangeDependencies() { super.didChangeDependencies(); - _media = MediaQuery.of(context); - s = S.of(context)!; + _s = S.of(context)!; } @override Widget build(BuildContext context) { super.build(context); return Scaffold( - body: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 7), - child: Column( - children: [ - height13, - Input( - controller: _textEditingController, - hint: s.inputDomainHere, - maxLines: 1, - onSubmitted: (_) => doPing(), - ), - SizedBox( - width: double.infinity, - height: _media.size.height * 0.6, - child: ListView.builder( - controller: ScrollController(), - itemCount: _results.length, - itemBuilder: (context, index) { - final result = _results[index]; - return _buildResultItem(result); - }, - ), - ), + body: ValueBuilder( + listenable: _results, + build: _buildBody, + ), + floatingActionButton: _buildFAB(), + ); + } + + Widget _buildFAB() { + return FloatingActionButton( + heroTag: 'ping', + onPressed: () { + showRoundDialog( + context: context, + title: Text(_s.choose), + child: Input( + controller: _textEditingController, + hint: _s.inputDomainHere, + maxLines: 1, + onSubmitted: (_) => _doPing(), + ), + actions: [ + TextButton(onPressed: _doPing, child: Text(_s.ok)), ], + ); + }, + child: const Icon(Icons.search), + ); + } + + void _doPing() { + context.pop(); + try { + doPing(); + } catch (e) { + showRoundDialog( + context: context, + child: Text(e.toString()), + actions: [ + TextButton( + onPressed: () => copy2Clipboard(e.toString()), + child: Text(_s.copy), + ), + ], + ); + rethrow; + } + } + + Widget _buildBody() { + if (isInit) { + return Center( + child: Text( + _s.noResult, + style: TextStyle( + fontSize: 18, + color: primaryColor, + ), ), - ), - floatingActionButton: FloatingActionButton( - heroTag: 'ping', - onPressed: () { - try { - doPing(); - } catch (e) { - showSnackBar(context, Text('Error: \n$e')); - rethrow; - } - }, - child: const Icon(Icons.play_arrow), - ), + ); + } + return ListView.builder( + padding: const EdgeInsets.all(11), + controller: ScrollController(), + itemCount: _results.value.length, + itemBuilder: (_, index) => _buildResultItem(_results.value[index]), ); } Widget _buildResultItem(PingResult result) { - final unknown = s.unknown; - final ms = s.ms; + final unknown = _s.unknown; + final ms = _s.ms; return RoundRectCard( ListTile( contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17), @@ -109,7 +140,7 @@ class _PingPageState extends State style: textSize11, ), trailing: Text( - '${s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? s.unknown} $ms', + '${_s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? _s.unknown} $ms', style: TextStyle( fontSize: 14, color: primaryColor, @@ -122,32 +153,32 @@ class _PingPageState extends State String _buildPingSummary(PingResult result, String unknown, String ms) { final ip = result.ip ?? unknown; if (result.results == null || result.results!.isEmpty) { - return '$ip - ${s.noResult}'; + return '$ip - ${_s.noResult}'; } final ttl = result.results?.first.ttl ?? unknown; final loss = result.statistic?.loss ?? unknown; final min = result.statistic?.min ?? unknown; final max = result.statistic?.max ?? unknown; - return '$ip\n${s.ttl}: $ttl, ${s.loss}: $loss%\n${s.min}: $min $ms, ${s.max}: $max $ms'; + return '$ip\n${_s.ttl}: $ttl, ${_s.loss}: $loss%\n${_s.min}: $min $ms, ${_s.max}: $max $ms'; } Future doPing() async { FocusScope.of(context).requestFocus(FocusNode()); - _results.clear(); + _results.value.clear(); final target = _textEditingController.text.trim(); if (target.isEmpty) { - showSnackBar(context, Text(s.pingInputIP)); + showSnackBar(context, Text(_s.pingInputIP)); return; } if (_serverProvider.servers.isEmpty) { - showSnackBar(context, Text(s.pingNoServer)); + showSnackBar(context, Text(_s.pingNoServer)); return; } /// avoid ping command injection if (!targetReg.hasMatch(target)) { - showSnackBar(context, Text(s.pingInputIP)); + showSnackBar(context, Text(_s.pingInputIP)); return; } @@ -156,8 +187,13 @@ class _PingPageState extends State return; } final result = await e.client!.run('ping -c 3 $target').string; - _results.add(PingResult.parse(e.spi.name, result)); - setState(() {}); + _results.value.add(PingResult.parse(e.spi.name, result)); + // [ValueNotifier] only notify when value is changed + // But we just add a element to list without changing the list itself + // So we need to notify manually + // + // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member + _results.notifyListeners(); })); } diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index 0d2301d9..925073ce 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -10,6 +10,7 @@ import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/data/model/app/tab.dart'; import 'package:toolbox/view/widget/input_field.dart'; +import 'package:toolbox/view/widget/value_notifier.dart'; import '../../core/utils/misc.dart'; import '../../core/utils/platform.dart'; @@ -47,23 +48,23 @@ class _SettingPageState extends State { late MediaQueryData _media; late S _s; - late int _selectedColorValue; - late int _launchPageIdx; - late int _nightMode; - late int _maxRetryCount; - late int _updateInterval; - late double _fontSize; - late String _localeCode; - late String _editorTheme; + final _selectedColorValue = ValueNotifier(0); + final _launchPageIdx = ValueNotifier(0); + final _nightMode = ValueNotifier(0); + final _maxRetryCount = ValueNotifier(0); + final _updateInterval = ValueNotifier(0); + final _fontSize = ValueNotifier(0.0); + final _localeCode = ValueNotifier(''); + final _editorTheme = ValueNotifier(''); - String? _pushToken; + final _pushToken = ValueNotifier(null); @override void didChangeDependencies() { super.didChangeDependencies(); _media = MediaQuery.of(context); _s = S.of(context)!; - _localeCode = _setting.locale.fetch() ?? _s.localeName; + _localeCode.value = _setting.locale.fetch() ?? _s.localeName; } @override @@ -71,13 +72,13 @@ class _SettingPageState extends State { super.initState(); _serverProvider = locator(); _setting = locator(); - _launchPageIdx = _setting.launchPage.fetch()!; - _nightMode = _setting.themeMode.fetch()!; - _updateInterval = _setting.serverStatusUpdateInterval.fetch()!; - _maxRetryCount = _setting.maxRetryCount.fetch()!; - _selectedColorValue = _setting.primaryColor.fetch()!; - _fontSize = _setting.termFontSize.fetch()!; - _editorTheme = _setting.editorTheme.fetch()!; + _launchPageIdx.value = _setting.launchPage.fetch()!; + _nightMode.value = _setting.themeMode.fetch()!; + _updateInterval.value = _setting.serverStatusUpdateInterval.fetch()!; + _maxRetryCount.value = _setting.maxRetryCount.fetch()!; + _selectedColorValue.value = _setting.primaryColor.fetch()!; + _fontSize.value = _setting.termFontSize.fetch()!; + _editorTheme.value = _setting.editorTheme.fetch()!; } @override @@ -225,23 +226,24 @@ class _SettingPageState extends State { onTap: () { updateIntervalKey.currentState?.showButtonMenu(); }, - trailing: PopupMenuButton( - key: updateIntervalKey, - itemBuilder: (_) => items, - initialValue: _updateInterval, - onSelected: (int val) { - setState(() { - _updateInterval = val; - }); - _setting.serverStatusUpdateInterval.put(_updateInterval.toInt()); - _serverProvider.startAutoRefresh(); - if (val == 0) { - showSnackBar(context, Text(_s.updateIntervalEqual0)); - } - }, - child: Text( - '${_updateInterval.toInt()} ${_s.second}', - style: textSize15, + trailing: ValueBuilder( + listenable: _updateInterval, + build: () => PopupMenuButton( + key: updateIntervalKey, + itemBuilder: (_) => items, + initialValue: _updateInterval.value, + onSelected: (int val) { + _updateInterval.value = val; + _setting.serverStatusUpdateInterval.put(val); + _serverProvider.startAutoRefresh(); + if (val == 0) { + showSnackBar(context, Text(_s.updateIntervalEqual0)); + } + }, + child: Text( + '${_updateInterval.value} ${_s.second}', + style: textSize15, + ), ), ), ); @@ -267,14 +269,14 @@ class _SettingPageState extends State { shrinkWrap: true, allowShades: true, onColorChange: (color) { - _selectedColorValue = color.value; + _selectedColorValue.value = color.value; }, selectedColor: primaryColor, ), actions: [ TextButton( onPressed: () { - _setting.primaryColor.put(_selectedColorValue); + _setting.primaryColor.put(_selectedColorValue.value); Navigator.pop(context); _showRestartSnackbar(); }, @@ -303,25 +305,23 @@ class _SettingPageState extends State { onTap: () { startPageKey.currentState?.showButtonMenu(); }, - trailing: PopupMenuButton( + trailing: ValueBuilder(listenable: _launchPageIdx, build: () => PopupMenuButton( key: startPageKey, itemBuilder: (BuildContext context) => items, - initialValue: _launchPageIdx, + initialValue: _launchPageIdx.value, onSelected: (int idx) { - setState(() { - _launchPageIdx = idx; - }); - _setting.launchPage.put(_launchPageIdx); + _launchPageIdx.value = idx; + _setting.launchPage.put(_launchPageIdx.value); }, child: ConstrainedBox( constraints: BoxConstraints(maxWidth: _media.size.width * 0.35), child: Text( - tabTitleName(context, AppTab.values[_launchPageIdx]), + tabTitleName(context, AppTab.values[_launchPageIdx.value]), textAlign: TextAlign.right, style: textSize15, ), ), - ), + )), ); } @@ -335,7 +335,7 @@ class _SettingPageState extends State { growable: false, ).toList(); final help = - _maxRetryCount == 0 ? _s.maxRetryCountEqual0 : _s.canPullRefresh; + _maxRetryCount.value == 0 ? _s.maxRetryCountEqual0 : _s.canPullRefresh; return ListTile( title: Text( @@ -346,21 +346,19 @@ class _SettingPageState extends State { onTap: () { maxRetryKey.currentState?.showButtonMenu(); }, - trailing: PopupMenuButton( + trailing: ValueBuilder(build: () => PopupMenuButton( key: maxRetryKey, itemBuilder: (BuildContext context) => items, - initialValue: _maxRetryCount, + initialValue: _maxRetryCount.value, onSelected: (int val) { - setState(() { - _maxRetryCount = val; - }); - _setting.maxRetryCount.put(_maxRetryCount); + _maxRetryCount.value = val; + _setting.maxRetryCount.put(_maxRetryCount.value); }, child: Text( - '${_maxRetryCount.toInt()} ${_s.times}', + '${_maxRetryCount.value} ${_s.times}', style: textSize15, ), - ), + ), listenable: _maxRetryCount,), ); } @@ -384,21 +382,19 @@ class _SettingPageState extends State { onTap: () { themeKey.currentState?.showButtonMenu(); }, - trailing: PopupMenuButton( + trailing: ValueBuilder(listenable: _nightMode, build: () => PopupMenuButton( key: themeKey, itemBuilder: (BuildContext context) => items, - initialValue: _nightMode, + initialValue: _nightMode.value, onSelected: (int idx) { - setState(() { - _nightMode = idx; - }); - _setting.themeMode.put(_nightMode); + _nightMode.value = idx; + _setting.themeMode.put(_nightMode.value); }, child: Text( - _buildThemeModeStr(_nightMode), + _buildThemeModeStr(_nightMode.value), style: textSize15, ), - ), + ),), ); } @@ -425,8 +421,8 @@ class _SettingPageState extends State { alignment: Alignment.centerRight, padding: EdgeInsets.zero, onPressed: () { - if (_pushToken != null) { - copy2Clipboard(_pushToken!); + if (_pushToken.value != null) { + copy2Clipboard(_pushToken.value!); showSnackBar(context, Text(_s.success)); } else { showSnackBar(context, Text(_s.getPushTokenFailed)); @@ -439,7 +435,7 @@ class _SettingPageState extends State { error: (error, trace) => Text('${_s.error}: $error'), noData: Text(_s.nullToken), success: (text) { - _pushToken = text; + _pushToken.value = text; return Text( text ?? _s.nullToken, style: grey, @@ -469,11 +465,11 @@ class _SettingPageState extends State { child: Text(_s.pickFile), ), TextButton( - onPressed: () => setState(() { + onPressed: () { _setting.fontPath.delete(); context.pop(); _showRestartSnackbar(); - }), + }, child: Text(_s.clear), ) ], @@ -497,7 +493,6 @@ class _SettingPageState extends State { } context.pop(); - setState(() {}); _showRestartSnackbar(); return; } @@ -521,14 +516,14 @@ class _SettingPageState extends State { } Widget _buildTermFontSize() { - return ListTile( + return ValueBuilder(listenable: _fontSize, build: () => ListTile( title: Text(_s.fontSize), trailing: Text( - _fontSize.toString(), + _fontSize.value.toString(), style: textSize15, ), onTap: () { - final ctrller = TextEditingController(text: _fontSize.toString()); + final ctrller = TextEditingController(text: _fontSize.value.toString()); showRoundDialog( context: context, title: Text(_s.fontSize), @@ -546,15 +541,15 @@ class _SettingPageState extends State { showRoundDialog(context: context, child: Text(_s.failed)); return; } - _fontSize = fontSize; - _setting.termFontSize.put(_fontSize); + _fontSize.value = fontSize; + _setting.termFontSize.put(_fontSize.value); }, child: Text(_s.ok), ), ], ); }, - ); + ),); } Widget _buildDiskIgnorePath() { @@ -607,14 +602,12 @@ class _SettingPageState extends State { onTap: () { localeKey.currentState?.showButtonMenu(); }, - trailing: PopupMenuButton( + trailing: ValueBuilder(listenable: _localeCode, build: () => PopupMenuButton( key: localeKey, itemBuilder: (BuildContext context) => items, - initialValue: _localeCode, + initialValue: _localeCode.value, onSelected: (String idx) { - setState(() { - _localeCode = idx; - }); + _localeCode.value = idx; _setting.locale.put(idx); _showRestartSnackbar(); }, @@ -622,7 +615,7 @@ class _SettingPageState extends State { _s.languageName, style: textSize15, ), - ), + )), ); } @@ -645,21 +638,19 @@ class _SettingPageState extends State { ).toList(); return ListTile( title: Text(_s.editor + _s.theme), - trailing: PopupMenuButton( + trailing: ValueBuilder(listenable: _editorTheme, build: () => PopupMenuButton( key: editorThemeKey, itemBuilder: (BuildContext context) => items, - initialValue: _editorTheme, + initialValue: _editorTheme.value, onSelected: (String idx) { - setState(() { - _editorTheme = idx; - }); + _editorTheme.value = idx; _setting.editorTheme.put(idx); }, child: Text( - _editorTheme, + _editorTheme.value, style: textSize15, ), - ), + ),), onTap: () { editorThemeKey.currentState?.showButtonMenu(); }, diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index ddf5b4ca..a959bb05 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -200,11 +200,9 @@ class _SSHPageState extends State { switch (key) { case TerminalKey.control: _keyboard.ctrl = !_keyboard.ctrl; - setState(() {}); break; case TerminalKey.alt: _keyboard.alt = !_keyboard.alt; - setState(() {}); break; default: _terminal.keyInput(key); diff --git a/lib/view/widget/value_notifier.dart b/lib/view/widget/value_notifier.dart new file mode 100644 index 00000000..423b8e85 --- /dev/null +++ b/lib/view/widget/value_notifier.dart @@ -0,0 +1,16 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class ValueBuilder extends ValueListenableBuilder { + final ValueListenable listenable; + final Widget Function() build; + + ValueBuilder({ + super.key, + required this.listenable, + required this.build, + }) : super( + valueListenable: listenable, + builder: (_, __, ___) => build(), + ); +} diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index c7bf1590..bc48d2a2 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -475,9 +475,9 @@ baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 345; + CURRENT_PROJECT_VERSION = 347; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.345; + MARKETING_VERSION = 1.0.347; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -490,9 +490,9 @@ baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 345; + CURRENT_PROJECT_VERSION = 347; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.345; + MARKETING_VERSION = 1.0.347; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -505,9 +505,9 @@ baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 345; + CURRENT_PROJECT_VERSION = 347; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.345; + MARKETING_VERSION = 1.0.347; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/pubspec.lock b/pubspec.lock index ec4a60a1..d1c54e14 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -173,10 +173,9 @@ packages: code_text_field: dependency: "direct main" description: - name: code_text_field - sha256: "0cbffbb2932cf82e1d022996388041de3493a476acad3fbb13e5917cac0fc5f2" - url: "https://pub.dev" - source: hosted + path: "../code_field" + relative: true + source: path version: "1.1.0" collection: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index f355a719..725f3a27 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,7 +65,8 @@ dependencies: plain_notification_token: ^0.0.4 highlight: ^0.7.0 flutter_highlight: ^0.7.0 - code_text_field: ^1.1.0 + code_text_field: + path: ../code_field dev_dependencies: flutter_native_splash: ^2.1.6