opt.: use ValueBuilder

This commit is contained in:
lollipopkit
2023-06-05 16:39:54 +08:00
parent 88cc6542a9
commit d66e570e01
13 changed files with 264 additions and 191 deletions

View File

@@ -360,7 +360,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 345; CURRENT_PROJECT_VERSION = 347;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -368,7 +368,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.345; MARKETING_VERSION = 1.0.347;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -491,7 +491,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 345; CURRENT_PROJECT_VERSION = 347;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -499,7 +499,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.345; MARKETING_VERSION = 1.0.347;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -516,7 +516,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 345; CURRENT_PROJECT_VERSION = 347;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -524,7 +524,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.345; MARKETING_VERSION = 1.0.347;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View File

@@ -1,9 +1,13 @@
import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:r_upgrade/r_upgrade.dart'; import 'package:r_upgrade/r_upgrade.dart';
import 'package:toolbox/core/extension/navigator.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/provider/app.dart';
import '../data/res/build_data.dart'; import '../data/res/build_data.dart';
@@ -25,6 +29,8 @@ Future<bool> isFileAvailable(String url) async {
} }
Future<void> doUpdate(BuildContext context, {bool force = false}) async { Future<void> doUpdate(BuildContext context, {bool force = false}) async {
_rmDownloadApks();
final update = await locator<AppService>().getUpdate(); final update = await locator<AppService>().getUpdate();
final newest = update.build.last.current; final newest = update.build.last.current;
@@ -95,3 +101,11 @@ Future<void> _doUpdate(String url, BuildContext context, S s) async {
); );
} }
} }
// rmdir Download
Future<void> _rmDownloadApks() async {
final dlDir = Directory(pathJoin((await docDir).path, 'Download'));
if (await dlDir.exists()) {
await dlDir.delete(recursive: true);
}
}

View File

@@ -6,8 +6,22 @@ import 'package:xterm/core.dart';
class VirtualKeyboard extends TerminalInputHandler with ChangeNotifier { class VirtualKeyboard extends TerminalInputHandler with ChangeNotifier {
VirtualKeyboard(); VirtualKeyboard();
bool ctrl = false; bool _ctrl = false;
bool alt = 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<SettingStore>(); final _setting = locator<SettingStore>();

View File

@@ -2,8 +2,8 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 344; static const int build = 347;
static const String engine = "3.10.2"; static const String engine = "3.10.3";
static const String buildAt = "2023-06-02 22:02:47.585289"; static const String buildAt = "2023-06-04 22:37:44.679072";
static const int modifications = 4; static const int modifications = 7;
} }

View File

@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/value_notifier.dart';
import '../../core/utils/ui.dart'; import '../../core/utils/ui.dart';
import '../widget/input_field.dart'; import '../widget/input_field.dart';
@@ -24,7 +25,7 @@ class _ConvertPageState extends State<ConvertPage>
late MediaQueryData _media; late MediaQueryData _media;
late S _s; late S _s;
int _typeOptionIndex = 0; final _typeOptionIndex = ValueNotifier(0);
@override @override
void initState() { void initState() {
@@ -76,7 +77,7 @@ class _ConvertPageState extends State<ConvertPage>
String doConvert() { String doConvert() {
final text = _textEditingController.text.trim(); final text = _textEditingController.text.trim();
switch (_typeOptionIndex) { switch (_typeOptionIndex.value) {
case 0: case 0:
return utf8.decode(base64.decode(text)); return utf8.decode(base64.decode(text));
case 1: case 1:
@@ -136,30 +137,31 @@ class _ConvertPageState extends State<ConvertPage>
) )
], ],
), ),
trailing: PopupMenu<int>( trailing: ValueBuilder(
items: items, listenable: _typeOptionIndex,
initialValue: _typeOptionIndex, build: () => PopupMenu<int>(
onSelected: (p0) { items: items,
setState(() { initialValue: _typeOptionIndex.value,
_typeOptionIndex = p0; onSelected: (p0) {
}); _typeOptionIndex.value = p0;
}, },
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
typeOption[_typeOptionIndex], typeOption[_typeOptionIndex.value],
textScaleFactor: 1.0, textScaleFactor: 1.0,
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey, color: Colors.grey,
),
), ),
), const Icon(Icons.keyboard_arrow_down, color: Colors.grey)
const Icon(Icons.keyboard_arrow_down, color: Colors.grey) ],
], ),
), ),
), ),
), ),

View File

@@ -87,6 +87,10 @@ class _EditorPageState extends State<EditorPage> with AfterLayoutMixin {
child: CodeField( child: CodeField(
focusNode: _focusNode, focusNode: _focusNode,
controller: _controller, controller: _controller,
lineNumberStyle: const LineNumberStyle(
width: 47,
margin: 7,
),
), ),
), ),
), ),
@@ -104,9 +108,7 @@ class _EditorPageState extends State<EditorPage> with AfterLayoutMixin {
if (widget.path != null) { if (widget.path != null) {
await Future.delayed(const Duration(milliseconds: 233)); await Future.delayed(const Duration(milliseconds: 233));
final code = await File(widget.path!).readAsString(); final code = await File(widget.path!).readAsString();
setState(() { _controller.text = code;
_controller.text = code;
});
} }
} }
} }

View File

@@ -3,6 +3,9 @@ import 'dart:async';
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.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/extension/uint8list.dart';
import '../../core/utils/ui.dart'; import '../../core/utils/ui.dart';
@@ -27,10 +30,11 @@ class PingPage extends StatefulWidget {
class _PingPageState extends State<PingPage> class _PingPageState extends State<PingPage>
with AutomaticKeepAliveClientMixin, AfterLayoutMixin { with AutomaticKeepAliveClientMixin, AfterLayoutMixin {
late TextEditingController _textEditingController; late TextEditingController _textEditingController;
late MediaQueryData _media; final _results = ValueNotifier(<PingResult>[]);
final List<PingResult> _results = [];
final _serverProvider = locator<ServerProvider>(); final _serverProvider = locator<ServerProvider>();
late S s; late S _s;
bool get isInit => _results.value.isEmpty;
@override @override
void initState() { void initState() {
@@ -41,58 +45,85 @@ class _PingPageState extends State<PingPage>
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_media = MediaQuery.of(context); _s = S.of(context)!;
s = S.of(context)!;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return Scaffold( return Scaffold(
body: SingleChildScrollView( body: ValueBuilder(
padding: const EdgeInsets.symmetric(horizontal: 7), listenable: _results,
child: Column( build: _buildBody,
children: [ ),
height13, floatingActionButton: _buildFAB(),
Input( );
controller: _textEditingController, }
hint: s.inputDomainHere,
maxLines: 1, Widget _buildFAB() {
onSubmitted: (_) => doPing(), return FloatingActionButton(
), heroTag: 'ping',
SizedBox( onPressed: () {
width: double.infinity, showRoundDialog(
height: _media.size.height * 0.6, context: context,
child: ListView.builder( title: Text(_s.choose),
controller: ScrollController(), child: Input(
itemCount: _results.length, controller: _textEditingController,
itemBuilder: (context, index) { hint: _s.inputDomainHere,
final result = _results[index]; maxLines: 1,
return _buildResultItem(result); 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', return ListView.builder(
onPressed: () { padding: const EdgeInsets.all(11),
try { controller: ScrollController(),
doPing(); itemCount: _results.value.length,
} catch (e) { itemBuilder: (_, index) => _buildResultItem(_results.value[index]),
showSnackBar(context, Text('Error: \n$e'));
rethrow;
}
},
child: const Icon(Icons.play_arrow),
),
); );
} }
Widget _buildResultItem(PingResult result) { Widget _buildResultItem(PingResult result) {
final unknown = s.unknown; final unknown = _s.unknown;
final ms = s.ms; final ms = _s.ms;
return RoundRectCard( return RoundRectCard(
ListTile( ListTile(
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17), contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
@@ -109,7 +140,7 @@ class _PingPageState extends State<PingPage>
style: textSize11, style: textSize11,
), ),
trailing: Text( trailing: Text(
'${s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? s.unknown} $ms', '${_s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? _s.unknown} $ms',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: primaryColor, color: primaryColor,
@@ -122,32 +153,32 @@ class _PingPageState extends State<PingPage>
String _buildPingSummary(PingResult result, String unknown, String ms) { String _buildPingSummary(PingResult result, String unknown, String ms) {
final ip = result.ip ?? unknown; final ip = result.ip ?? unknown;
if (result.results == null || result.results!.isEmpty) { if (result.results == null || result.results!.isEmpty) {
return '$ip - ${s.noResult}'; return '$ip - ${_s.noResult}';
} }
final ttl = result.results?.first.ttl ?? unknown; final ttl = result.results?.first.ttl ?? unknown;
final loss = result.statistic?.loss ?? unknown; final loss = result.statistic?.loss ?? unknown;
final min = result.statistic?.min ?? unknown; final min = result.statistic?.min ?? unknown;
final max = result.statistic?.max ?? 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<void> doPing() async { Future<void> doPing() async {
FocusScope.of(context).requestFocus(FocusNode()); FocusScope.of(context).requestFocus(FocusNode());
_results.clear(); _results.value.clear();
final target = _textEditingController.text.trim(); final target = _textEditingController.text.trim();
if (target.isEmpty) { if (target.isEmpty) {
showSnackBar(context, Text(s.pingInputIP)); showSnackBar(context, Text(_s.pingInputIP));
return; return;
} }
if (_serverProvider.servers.isEmpty) { if (_serverProvider.servers.isEmpty) {
showSnackBar(context, Text(s.pingNoServer)); showSnackBar(context, Text(_s.pingNoServer));
return; return;
} }
/// avoid ping command injection /// avoid ping command injection
if (!targetReg.hasMatch(target)) { if (!targetReg.hasMatch(target)) {
showSnackBar(context, Text(s.pingInputIP)); showSnackBar(context, Text(_s.pingInputIP));
return; return;
} }
@@ -156,8 +187,13 @@ class _PingPageState extends State<PingPage>
return; return;
} }
final result = await e.client!.run('ping -c 3 $target').string; final result = await e.client!.run('ping -c 3 $target').string;
_results.add(PingResult.parse(e.spi.name, result)); _results.value.add(PingResult.parse(e.spi.name, result));
setState(() {}); // [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();
})); }));
} }

View File

@@ -10,6 +10,7 @@ import 'package:toolbox/core/extension/locale.dart';
import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/core/extension/navigator.dart';
import 'package:toolbox/data/model/app/tab.dart'; import 'package:toolbox/data/model/app/tab.dart';
import 'package:toolbox/view/widget/input_field.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/misc.dart';
import '../../core/utils/platform.dart'; import '../../core/utils/platform.dart';
@@ -47,23 +48,23 @@ class _SettingPageState extends State<SettingPage> {
late MediaQueryData _media; late MediaQueryData _media;
late S _s; late S _s;
late int _selectedColorValue; final _selectedColorValue = ValueNotifier(0);
late int _launchPageIdx; final _launchPageIdx = ValueNotifier(0);
late int _nightMode; final _nightMode = ValueNotifier(0);
late int _maxRetryCount; final _maxRetryCount = ValueNotifier(0);
late int _updateInterval; final _updateInterval = ValueNotifier(0);
late double _fontSize; final _fontSize = ValueNotifier(0.0);
late String _localeCode; final _localeCode = ValueNotifier('');
late String _editorTheme; final _editorTheme = ValueNotifier('');
String? _pushToken; final _pushToken = ValueNotifier<String?>(null);
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
_s = S.of(context)!; _s = S.of(context)!;
_localeCode = _setting.locale.fetch() ?? _s.localeName; _localeCode.value = _setting.locale.fetch() ?? _s.localeName;
} }
@override @override
@@ -71,13 +72,13 @@ class _SettingPageState extends State<SettingPage> {
super.initState(); super.initState();
_serverProvider = locator<ServerProvider>(); _serverProvider = locator<ServerProvider>();
_setting = locator<SettingStore>(); _setting = locator<SettingStore>();
_launchPageIdx = _setting.launchPage.fetch()!; _launchPageIdx.value = _setting.launchPage.fetch()!;
_nightMode = _setting.themeMode.fetch()!; _nightMode.value = _setting.themeMode.fetch()!;
_updateInterval = _setting.serverStatusUpdateInterval.fetch()!; _updateInterval.value = _setting.serverStatusUpdateInterval.fetch()!;
_maxRetryCount = _setting.maxRetryCount.fetch()!; _maxRetryCount.value = _setting.maxRetryCount.fetch()!;
_selectedColorValue = _setting.primaryColor.fetch()!; _selectedColorValue.value = _setting.primaryColor.fetch()!;
_fontSize = _setting.termFontSize.fetch()!; _fontSize.value = _setting.termFontSize.fetch()!;
_editorTheme = _setting.editorTheme.fetch()!; _editorTheme.value = _setting.editorTheme.fetch()!;
} }
@override @override
@@ -225,23 +226,24 @@ class _SettingPageState extends State<SettingPage> {
onTap: () { onTap: () {
updateIntervalKey.currentState?.showButtonMenu(); updateIntervalKey.currentState?.showButtonMenu();
}, },
trailing: PopupMenuButton( trailing: ValueBuilder(
key: updateIntervalKey, listenable: _updateInterval,
itemBuilder: (_) => items, build: () => PopupMenuButton(
initialValue: _updateInterval, key: updateIntervalKey,
onSelected: (int val) { itemBuilder: (_) => items,
setState(() { initialValue: _updateInterval.value,
_updateInterval = val; onSelected: (int val) {
}); _updateInterval.value = val;
_setting.serverStatusUpdateInterval.put(_updateInterval.toInt()); _setting.serverStatusUpdateInterval.put(val);
_serverProvider.startAutoRefresh(); _serverProvider.startAutoRefresh();
if (val == 0) { if (val == 0) {
showSnackBar(context, Text(_s.updateIntervalEqual0)); showSnackBar(context, Text(_s.updateIntervalEqual0));
} }
}, },
child: Text( child: Text(
'${_updateInterval.toInt()} ${_s.second}', '${_updateInterval.value} ${_s.second}',
style: textSize15, style: textSize15,
),
), ),
), ),
); );
@@ -267,14 +269,14 @@ class _SettingPageState extends State<SettingPage> {
shrinkWrap: true, shrinkWrap: true,
allowShades: true, allowShades: true,
onColorChange: (color) { onColorChange: (color) {
_selectedColorValue = color.value; _selectedColorValue.value = color.value;
}, },
selectedColor: primaryColor, selectedColor: primaryColor,
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
_setting.primaryColor.put(_selectedColorValue); _setting.primaryColor.put(_selectedColorValue.value);
Navigator.pop(context); Navigator.pop(context);
_showRestartSnackbar(); _showRestartSnackbar();
}, },
@@ -303,25 +305,23 @@ class _SettingPageState extends State<SettingPage> {
onTap: () { onTap: () {
startPageKey.currentState?.showButtonMenu(); startPageKey.currentState?.showButtonMenu();
}, },
trailing: PopupMenuButton( trailing: ValueBuilder(listenable: _launchPageIdx, build: () => PopupMenuButton(
key: startPageKey, key: startPageKey,
itemBuilder: (BuildContext context) => items, itemBuilder: (BuildContext context) => items,
initialValue: _launchPageIdx, initialValue: _launchPageIdx.value,
onSelected: (int idx) { onSelected: (int idx) {
setState(() { _launchPageIdx.value = idx;
_launchPageIdx = idx; _setting.launchPage.put(_launchPageIdx.value);
});
_setting.launchPage.put(_launchPageIdx);
}, },
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: _media.size.width * 0.35), constraints: BoxConstraints(maxWidth: _media.size.width * 0.35),
child: Text( child: Text(
tabTitleName(context, AppTab.values[_launchPageIdx]), tabTitleName(context, AppTab.values[_launchPageIdx.value]),
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: textSize15, style: textSize15,
), ),
), ),
), )),
); );
} }
@@ -335,7 +335,7 @@ class _SettingPageState extends State<SettingPage> {
growable: false, growable: false,
).toList(); ).toList();
final help = final help =
_maxRetryCount == 0 ? _s.maxRetryCountEqual0 : _s.canPullRefresh; _maxRetryCount.value == 0 ? _s.maxRetryCountEqual0 : _s.canPullRefresh;
return ListTile( return ListTile(
title: Text( title: Text(
@@ -346,21 +346,19 @@ class _SettingPageState extends State<SettingPage> {
onTap: () { onTap: () {
maxRetryKey.currentState?.showButtonMenu(); maxRetryKey.currentState?.showButtonMenu();
}, },
trailing: PopupMenuButton( trailing: ValueBuilder(build: () => PopupMenuButton(
key: maxRetryKey, key: maxRetryKey,
itemBuilder: (BuildContext context) => items, itemBuilder: (BuildContext context) => items,
initialValue: _maxRetryCount, initialValue: _maxRetryCount.value,
onSelected: (int val) { onSelected: (int val) {
setState(() { _maxRetryCount.value = val;
_maxRetryCount = val; _setting.maxRetryCount.put(_maxRetryCount.value);
});
_setting.maxRetryCount.put(_maxRetryCount);
}, },
child: Text( child: Text(
'${_maxRetryCount.toInt()} ${_s.times}', '${_maxRetryCount.value} ${_s.times}',
style: textSize15, style: textSize15,
), ),
), ), listenable: _maxRetryCount,),
); );
} }
@@ -384,21 +382,19 @@ class _SettingPageState extends State<SettingPage> {
onTap: () { onTap: () {
themeKey.currentState?.showButtonMenu(); themeKey.currentState?.showButtonMenu();
}, },
trailing: PopupMenuButton( trailing: ValueBuilder(listenable: _nightMode, build: () => PopupMenuButton(
key: themeKey, key: themeKey,
itemBuilder: (BuildContext context) => items, itemBuilder: (BuildContext context) => items,
initialValue: _nightMode, initialValue: _nightMode.value,
onSelected: (int idx) { onSelected: (int idx) {
setState(() { _nightMode.value = idx;
_nightMode = idx; _setting.themeMode.put(_nightMode.value);
});
_setting.themeMode.put(_nightMode);
}, },
child: Text( child: Text(
_buildThemeModeStr(_nightMode), _buildThemeModeStr(_nightMode.value),
style: textSize15, style: textSize15,
), ),
), ),),
); );
} }
@@ -425,8 +421,8 @@ class _SettingPageState extends State<SettingPage> {
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onPressed: () { onPressed: () {
if (_pushToken != null) { if (_pushToken.value != null) {
copy2Clipboard(_pushToken!); copy2Clipboard(_pushToken.value!);
showSnackBar(context, Text(_s.success)); showSnackBar(context, Text(_s.success));
} else { } else {
showSnackBar(context, Text(_s.getPushTokenFailed)); showSnackBar(context, Text(_s.getPushTokenFailed));
@@ -439,7 +435,7 @@ class _SettingPageState extends State<SettingPage> {
error: (error, trace) => Text('${_s.error}: $error'), error: (error, trace) => Text('${_s.error}: $error'),
noData: Text(_s.nullToken), noData: Text(_s.nullToken),
success: (text) { success: (text) {
_pushToken = text; _pushToken.value = text;
return Text( return Text(
text ?? _s.nullToken, text ?? _s.nullToken,
style: grey, style: grey,
@@ -469,11 +465,11 @@ class _SettingPageState extends State<SettingPage> {
child: Text(_s.pickFile), child: Text(_s.pickFile),
), ),
TextButton( TextButton(
onPressed: () => setState(() { onPressed: () {
_setting.fontPath.delete(); _setting.fontPath.delete();
context.pop(); context.pop();
_showRestartSnackbar(); _showRestartSnackbar();
}), },
child: Text(_s.clear), child: Text(_s.clear),
) )
], ],
@@ -497,7 +493,6 @@ class _SettingPageState extends State<SettingPage> {
} }
context.pop(); context.pop();
setState(() {});
_showRestartSnackbar(); _showRestartSnackbar();
return; return;
} }
@@ -521,14 +516,14 @@ class _SettingPageState extends State<SettingPage> {
} }
Widget _buildTermFontSize() { Widget _buildTermFontSize() {
return ListTile( return ValueBuilder(listenable: _fontSize, build: () => ListTile(
title: Text(_s.fontSize), title: Text(_s.fontSize),
trailing: Text( trailing: Text(
_fontSize.toString(), _fontSize.value.toString(),
style: textSize15, style: textSize15,
), ),
onTap: () { onTap: () {
final ctrller = TextEditingController(text: _fontSize.toString()); final ctrller = TextEditingController(text: _fontSize.value.toString());
showRoundDialog( showRoundDialog(
context: context, context: context,
title: Text(_s.fontSize), title: Text(_s.fontSize),
@@ -546,15 +541,15 @@ class _SettingPageState extends State<SettingPage> {
showRoundDialog(context: context, child: Text(_s.failed)); showRoundDialog(context: context, child: Text(_s.failed));
return; return;
} }
_fontSize = fontSize; _fontSize.value = fontSize;
_setting.termFontSize.put(_fontSize); _setting.termFontSize.put(_fontSize.value);
}, },
child: Text(_s.ok), child: Text(_s.ok),
), ),
], ],
); );
}, },
); ),);
} }
Widget _buildDiskIgnorePath() { Widget _buildDiskIgnorePath() {
@@ -607,14 +602,12 @@ class _SettingPageState extends State<SettingPage> {
onTap: () { onTap: () {
localeKey.currentState?.showButtonMenu(); localeKey.currentState?.showButtonMenu();
}, },
trailing: PopupMenuButton( trailing: ValueBuilder(listenable: _localeCode, build: () => PopupMenuButton(
key: localeKey, key: localeKey,
itemBuilder: (BuildContext context) => items, itemBuilder: (BuildContext context) => items,
initialValue: _localeCode, initialValue: _localeCode.value,
onSelected: (String idx) { onSelected: (String idx) {
setState(() { _localeCode.value = idx;
_localeCode = idx;
});
_setting.locale.put(idx); _setting.locale.put(idx);
_showRestartSnackbar(); _showRestartSnackbar();
}, },
@@ -622,7 +615,7 @@ class _SettingPageState extends State<SettingPage> {
_s.languageName, _s.languageName,
style: textSize15, style: textSize15,
), ),
), )),
); );
} }
@@ -645,21 +638,19 @@ class _SettingPageState extends State<SettingPage> {
).toList(); ).toList();
return ListTile( return ListTile(
title: Text(_s.editor + _s.theme), title: Text(_s.editor + _s.theme),
trailing: PopupMenuButton( trailing: ValueBuilder(listenable: _editorTheme, build: () => PopupMenuButton(
key: editorThemeKey, key: editorThemeKey,
itemBuilder: (BuildContext context) => items, itemBuilder: (BuildContext context) => items,
initialValue: _editorTheme, initialValue: _editorTheme.value,
onSelected: (String idx) { onSelected: (String idx) {
setState(() { _editorTheme.value = idx;
_editorTheme = idx;
});
_setting.editorTheme.put(idx); _setting.editorTheme.put(idx);
}, },
child: Text( child: Text(
_editorTheme, _editorTheme.value,
style: textSize15, style: textSize15,
), ),
), ),),
onTap: () { onTap: () {
editorThemeKey.currentState?.showButtonMenu(); editorThemeKey.currentState?.showButtonMenu();
}, },

View File

@@ -200,11 +200,9 @@ class _SSHPageState extends State<SSHPage> {
switch (key) { switch (key) {
case TerminalKey.control: case TerminalKey.control:
_keyboard.ctrl = !_keyboard.ctrl; _keyboard.ctrl = !_keyboard.ctrl;
setState(() {});
break; break;
case TerminalKey.alt: case TerminalKey.alt:
_keyboard.alt = !_keyboard.alt; _keyboard.alt = !_keyboard.alt;
setState(() {});
break; break;
default: default:
_terminal.keyInput(key); _terminal.keyInput(key);

View File

@@ -0,0 +1,16 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class ValueBuilder<T> extends ValueListenableBuilder<T> {
final ValueListenable<T> listenable;
final Widget Function() build;
ValueBuilder({
super.key,
required this.listenable,
required this.build,
}) : super(
valueListenable: listenable,
builder: (_, __, ___) => build(),
);
}

View File

@@ -475,9 +475,9 @@
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 345; CURRENT_PROJECT_VERSION = 347;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.345; MARKETING_VERSION = 1.0.347;
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -490,9 +490,9 @@
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 345; CURRENT_PROJECT_VERSION = 347;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.345; MARKETING_VERSION = 1.0.347;
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -505,9 +505,9 @@
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 345; CURRENT_PROJECT_VERSION = 347;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.345; MARKETING_VERSION = 1.0.347;
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

View File

@@ -173,10 +173,9 @@ packages:
code_text_field: code_text_field:
dependency: "direct main" dependency: "direct main"
description: description:
name: code_text_field path: "../code_field"
sha256: "0cbffbb2932cf82e1d022996388041de3493a476acad3fbb13e5917cac0fc5f2" relative: true
url: "https://pub.dev" source: path
source: hosted
version: "1.1.0" version: "1.1.0"
collection: collection:
dependency: transitive dependency: transitive

View File

@@ -65,7 +65,8 @@ dependencies:
plain_notification_token: ^0.0.4 plain_notification_token: ^0.0.4
highlight: ^0.7.0 highlight: ^0.7.0
flutter_highlight: ^0.7.0 flutter_highlight: ^0.7.0
code_text_field: ^1.1.0 code_text_field:
path: ../code_field
dev_dependencies: dev_dependencies:
flutter_native_splash: ^2.1.6 flutter_native_splash: ^2.1.6