From ffae93cc72d9e64ff2cb7cbd2ba470a71456c09e Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Sun, 7 May 2023 18:25:30 +0800 Subject: [PATCH] #29 opt. for `TextInput` --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 2 +- .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 +- lib/data/res/build_data.dart | 6 +- lib/l10n/app_en.arb | 2 +- lib/view/page/backup.dart | 9 +- lib/view/page/convert.dart | 8 +- lib/view/page/docker.dart | 66 +-- lib/view/page/home.dart | 25 +- lib/view/page/ping.dart | 3 +- lib/view/page/pkg.dart | 9 +- lib/view/page/private_key/edit.dart | 34 +- lib/view/page/server/edit.dart | 417 +++++++++---------- lib/view/page/setting.dart | 7 +- lib/view/page/sftp/view.dart | 137 +++--- lib/view/page/snippet/edit.dart | 21 +- lib/view/page/ssh.dart | 1 - lib/view/widget/input_decoration.dart | 16 - lib/view/widget/input_field.dart | 39 +- make.dart | 9 +- 20 files changed, 414 insertions(+), 411 deletions(-) delete mode 100644 lib/view/widget/input_decoration.dart diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index 57a97dfb..d5f10aae 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -1062,7 +1062,7 @@ abstract class S { /// No description provided for @unknown. /// /// In en, this message translates to: - /// **'unknown'** + /// **'Unknown'** String get unknown; /// No description provided for @unknownError. diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index bbbd27d9..6bc2477b 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -522,7 +522,7 @@ class SEn extends S { String get ttl => 'ttl'; @override - String get unknown => 'unknown'; + String get unknown => 'Unknown'; @override String get unknownError => 'Unknown error'; diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 403ff15d..35f98ed5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -359,7 +359,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 286; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -367,7 +367,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.284; + MARKETING_VERSION = 1.0.286; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -490,7 +490,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 286; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -498,7 +498,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.284; + MARKETING_VERSION = 1.0.286; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -515,7 +515,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 286; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -523,7 +523,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.284; + MARKETING_VERSION = 1.0.286; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 288fb470..8b208ab1 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 = 284; + static const int build = 286; static const String engine = "3.7.11"; - static const String buildAt = "2023-05-07 00:52:57.124037"; - static const int modifications = 23; + static const String buildAt = "2023-05-07 18:10:41.721685"; + static const int modifications = 19; } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 89b5941b..32edd598 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -160,7 +160,7 @@ "themeMode": "Theme mode", "times": "Times", "ttl": "ttl", - "unknown": "unknown", + "unknown": "Unknown", "unknownError": "Unknown error", "unkownConvertMode": "Unknown convert mode", "update": "Update", diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index 1f1b0489..eddab4c2 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -67,9 +67,12 @@ class BackupPage extends StatelessWidget { final text = await file.readAsString(); _import(text, context, s); }), - const SizedBox(height: 7), - const Divider(), - const SizedBox(height: 7), + const SizedBox(height: 17), + const SizedBox( + width: 37, + child: Divider(), + ), + const SizedBox(height: 17), _buildCard( s.backup, Icons.file_upload, diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart index 2ecc077d..aab3207d 100644 --- a/lib/view/page/convert.dart +++ b/lib/view/page/convert.dart @@ -89,7 +89,7 @@ class _ConvertPageState extends State Widget _buildInputTop() { return SizedBox( height: _media.size.height * 0.33, - child: buildInput(context, _textEditingController), + child: buildInput(controller: _textEditingController), ); } @@ -150,9 +150,7 @@ class _ConvertPageState extends State textScaleFactor: 1.0, textAlign: TextAlign.right, style: const TextStyle( - fontWeight: FontWeight.w500, - color: Colors.grey - ), + fontWeight: FontWeight.w500, color: Colors.grey), ), ], ), @@ -165,7 +163,7 @@ class _ConvertPageState extends State Widget _buildResult() { return SizedBox( height: _media.size.height * 0.33, - child: buildInput(context, _textEditingControllerResult), + child: buildInput(controller: _textEditingControllerResult), ); } diff --git a/lib/view/page/docker.dart b/lib/view/page/docker.dart index 5cdb682c..987eddb7 100644 --- a/lib/view/page/docker.dart +++ b/lib/view/page/docker.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/utils/navigator.dart'; +import 'package:toolbox/view/widget/input_field.dart'; import '../../core/utils/ui.dart'; import '../../data/model/docker/ps.dart'; @@ -94,27 +95,26 @@ class _DockerManagePageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - TextField( - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: _s.dockerImage, hintText: 'ubuntu:22.10'), + buildInput( + type: TextInputType.text, + label: _s.dockerImage, + hint: 'xxx:1.1', controller: imageCtrl, - autocorrect: false, + autoCorrect: false, ), - TextField( - keyboardType: TextInputType.text, + buildInput( + type: TextInputType.text, controller: nameCtrl, - decoration: InputDecoration( - labelText: _s.dockerContainerName, hintText: 'ubuntu22'), - autocorrect: false, + label: _s.dockerContainerName, + hint: 'xxx', + autoCorrect: false, ), - TextField( - keyboardType: TextInputType.text, + buildInput( + type: TextInputType.text, controller: argsCtrl, - decoration: InputDecoration( - labelText: _s.extraArgs, - hintText: '-p 2222:22 -v ~/.xxx/:/xxx'), - autocorrect: false, + label: _s.extraArgs, + hint: '-p 2222:22 -v ~/.xxx/:/xxx', + autoCorrect: false, ), ], ), @@ -206,14 +206,12 @@ class _DockerManagePageState extends State { await showRoundDialog( context: context, title: Text(widget.spi.user), - child: TextField( + child: buildInput( controller: _textController, - keyboardType: TextInputType.visiblePassword, + type: TextInputType.visiblePassword, obscureText: true, onSubmitted: (_) => onSubmitted(), - decoration: InputDecoration( - labelText: _s.pwd, - ), + label: _s.pwd, ), actions: [ TextButton( @@ -262,17 +260,21 @@ class _DockerManagePageState extends State { return centerLoading; } + final items = []; + items.addAll([ + _buildLoading(), + _buildVersion( + _docker.edition ?? _s.unknown, + _docker.version ?? _s.unknown, + ), + _buildPsItems(), + _buildImages(), + _buildEditHost(), + ].map((e) => RoundRectCard(e))); + items.add(const SizedBox(height: 37)); return ListView( padding: const EdgeInsets.all(7), - children: [ - _buildLoading(), - _buildVersion( - _docker.edition ?? _s.unknown, _docker.version ?? _s.unknown), - _buildPsItems(), - _buildImages(), - _buildEditHost(), - const SizedBox(height: 37), - ].map((e) => RoundRectCard(e)).toList(), + children: items, ); } @@ -377,9 +379,9 @@ class _DockerManagePageState extends State { await showRoundDialog( context: context, title: Text(_s.dockerEditHost), - child: TextField( + child: buildInput( maxLines: 1, - autocorrect: false, + autoCorrect: false, controller: TextEditingController(text: 'unix:///run/user/1000/docker.sock'), onSubmitted: (value) { diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart index cbe79338..fbe48fb1 100644 --- a/lib/view/page/home.dart +++ b/lib/view/page/home.dart @@ -191,8 +191,10 @@ class _MyHomePageState extends State ListTile( leading: const Icon(Icons.settings), title: Text(_s.setting), - onTap: () => - AppRoute(const SettingPage(), 'Setting').go(context), + onTap: () => AppRoute( + const SettingPage(), + 'Setting', + ).go(context), ), ListTile( leading: const Icon(Icons.vpn_key), @@ -205,21 +207,26 @@ class _MyHomePageState extends State ListTile( leading: const Icon(Icons.download), title: Text(_s.download), - onTap: () => - AppRoute(const SFTPDownloadedPage(), 'snippet list') - .go(context), + onTap: () => AppRoute( + const SFTPDownloadedPage(), + 'snippet list', + ).go(context), ), ListTile( leading: const Icon(Icons.import_export), title: Text(_s.backup), - onTap: () => - AppRoute(BackupPage(), 'backup page').go(context), + onTap: () => AppRoute( + BackupPage(), + 'backup page', + ).go(context), ), ListTile( leading: const Icon(Icons.snippet_folder), title: Text(_s.snippet), - onTap: () => AppRoute(const SnippetListPage(), 'snippet list') - .go(context), + onTap: () => AppRoute( + const SnippetListPage(), + 'snippet list', + ).go(context), ), ListTile( leading: const Icon(Icons.text_snippet), diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index 20fd167d..26bc4fde 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -58,8 +58,7 @@ class _PingPageState extends State children: [ const SizedBox(height: 13), buildInput( - context, - _textEditingController, + controller: _textEditingController, hint: s.inputDomainHere, maxLines: 1, onSubmitted: (_) => doPing(), diff --git a/lib/view/page/pkg.dart b/lib/view/page/pkg.dart index a394f15c..ff2f0ff9 100644 --- a/lib/view/page/pkg.dart +++ b/lib/view/page/pkg.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/utils/navigator.dart'; +import 'package:toolbox/view/widget/input_field.dart'; import '../../data/model/pkg/upgrade_info.dart'; import '../../data/model/server/dist.dart'; @@ -91,14 +92,12 @@ class _PkgManagePageState extends State await showRoundDialog( context: context, title: Text(widget.spi.user), - child: TextField( + child: buildInput( controller: _textController, - keyboardType: TextInputType.visiblePassword, + type: TextInputType.visiblePassword, obscureText: true, onSubmitted: (_) => onSubmitted(), - decoration: InputDecoration( - labelText: _s.pwd, - ), + label: _s.pwd, ), actions: [ TextButton( diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index fa1b1aae..dcc36ade 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -9,6 +9,7 @@ import 'package:toolbox/core/extension/numx.dart'; import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/navigator.dart'; import 'package:toolbox/data/res/misc.dart'; +import 'package:toolbox/view/widget/input_field.dart'; import '../../../core/utils/server.dart'; import '../../../core/utils/ui.dart'; @@ -16,7 +17,6 @@ import '../../../data/model/server/private_key_info.dart'; import '../../../data/provider/private_key.dart'; import '../../../data/res/ui.dart'; import '../../../locator.dart'; -import '../../widget/input_decoration.dart'; const _format = 'text/plain'; @@ -78,23 +78,24 @@ class _PrivateKeyEditPageState extends State body: ListView( padding: const EdgeInsets.all(13), children: [ - TextField( + buildInput( controller: _nameController, - keyboardType: TextInputType.text, - focusNode: _nameNode, + type: TextInputType.text, + node: _nameNode, onSubmitted: (_) => _focusScope.requestFocus(_keyNode), - decoration: buildDecoration(_s.name, icon: Icons.info), + label: _s.name, + icon: Icons.info, ), - TextField( + buildInput( controller: _keyController, - autocorrect: false, + autoCorrect: false, minLines: 3, maxLines: 10, - keyboardType: TextInputType.text, - focusNode: _keyNode, + type: TextInputType.text, + node: _keyNode, onSubmitted: (_) => _focusScope.requestFocus(_pwdNode), - enableSuggestions: false, - decoration: buildDecoration(_s.privateKey, icon: Icons.vpn_key), + label: _s.privateKey, + icon: Icons.vpn_key, ), TextButton( onPressed: () async { @@ -128,13 +129,14 @@ class _PrivateKeyEditPageState extends State }, child: Text(_s.pickFile), ), - TextField( + buildInput( controller: _pwdController, - autocorrect: false, - keyboardType: TextInputType.text, - focusNode: _pwdNode, + autoCorrect: false, + type: TextInputType.text, + node: _pwdNode, obscureText: true, - decoration: buildDecoration(_s.pwd, icon: Icons.password), + label: _s.pwd, + icon: Icons.password, ), SizedBox(height: MediaQuery.of(context).size.height * 0.1), _loading diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 8ea6cd51..fd11698b 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/utils/navigator.dart'; +import 'package:toolbox/view/widget/input_field.dart'; import '../../../core/route.dart'; import '../../../core/utils/ui.dart'; @@ -10,11 +11,9 @@ import '../../../data/model/server/private_key_info.dart'; import '../../../data/model/server/server_private_info.dart'; import '../../../data/provider/private_key.dart'; import '../../../data/provider/server.dart'; -import '../../../data/res/color.dart'; import '../../../data/res/ui.dart'; import '../../../data/store/private_key.dart'; import '../../../locator.dart'; -import '../../widget/input_decoration.dart'; import '../private_key/edit.dart'; class ServerEditPage extends StatefulWidget { @@ -61,224 +60,220 @@ class _ServerEditPageState extends State with AfterLayoutMixin { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(_s.edit, style: textSize18), - actions: [ - widget.spi != null - ? IconButton( - onPressed: () { - showRoundDialog( - context: context, - child: Text(_s.sureToDeleteServer(widget.spi!.name)), - actions: [ - TextButton( - onPressed: () { - _serverProvider.delServer(widget.spi!.id); - context.pop(); - context.pop(); - }, - child: Text( - _s.ok, - style: const TextStyle(color: Colors.red), - ), - ), - TextButton( - onPressed: () => context.pop(), - child: Text(_s.cancel), - ) - ], - ); - }, - icon: const Icon(Icons.delete), + appBar: _buildAppBar(), + body: _buildForm(), + floatingActionButton: _buildFAB(), + ); + } + + PreferredSizeWidget _buildAppBar() { + final delBtn = IconButton( + onPressed: () { + showRoundDialog( + context: context, + child: Text(_s.sureToDeleteServer(widget.spi!.name)), + actions: [ + TextButton( + onPressed: () { + _serverProvider.delServer(widget.spi!.id); + context.pop(); + context.pop(); + }, + child: Text( + _s.ok, + style: const TextStyle(color: Colors.red), + ), + ), + TextButton( + onPressed: () => context.pop(), + child: Text(_s.cancel), + ) + ], + ); + }, + icon: const Icon(Icons.delete), + ); + return AppBar( + title: Text(_s.edit, style: textSize18), + actions: [ + widget.spi != null ? delBtn : const SizedBox(), + ], + ); + } + + Widget _buildForm() { + return SingleChildScrollView( + padding: const EdgeInsets.all(17), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildInput( + controller: _nameController, + type: TextInputType.text, + node: _nameFocus, + onSubmitted: (_) => _focusScope.requestFocus(_ipFocus), + hint: _s.exampleName, + label: _s.name, + icon: Icons.info, + ), + buildInput( + controller: _ipController, + type: TextInputType.text, + onSubmitted: (_) => _focusScope.requestFocus(_portFocus), + node: _ipFocus, + autoCorrect: false, + label: _s.host, + icon: Icons.storage, + hint: 'example.com', + ), + buildInput( + controller: _portController, + type: TextInputType.number, + node: _portFocus, + onSubmitted: (_) => _focusScope.requestFocus(_usernameFocus), + label: _s.port, + icon: Icons.format_list_numbered, + hint: '22', + ), + buildInput( + controller: _usernameController, + type: TextInputType.text, + node: _usernameFocus, + autoCorrect: false, + label: _s.user, + icon: Icons.account_box, + hint: 'root', + ), + width7, + Row( + children: [ + width13, + Text(_s.keyAuth), + width13, + Switch( + value: usePublicKey, + onChanged: (val) => setState(() => usePublicKey = val), + ), + ], + ), + !usePublicKey + ? buildInput( + controller: _passwordController, + obscureText: true, + type: TextInputType.text, + label: _s.pwd, + icon: Icons.password, + hint: _s.pwd, + onSubmitted: (_) => {}, ) - : const SizedBox() + : const SizedBox(), + usePublicKey ? _buildKeyAuth() : const SizedBox() ], ), - body: SingleChildScrollView( - padding: const EdgeInsets.all(17), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextField( - controller: _nameController, - keyboardType: TextInputType.text, - focusNode: _nameFocus, - onSubmitted: (_) => _focusScope.requestFocus(_ipFocus), - decoration: buildDecoration( - _s.name, - icon: Icons.info, - hint: _s.exampleName, - ), - ), - TextField( - controller: _ipController, - keyboardType: TextInputType.text, - onSubmitted: (_) => _focusScope.requestFocus(_portFocus), - focusNode: _ipFocus, - autocorrect: false, - enableSuggestions: false, - decoration: buildDecoration( - _s.host, - icon: Icons.storage, - hint: 'example.com', - ), - ), - TextField( - controller: _portController, - keyboardType: TextInputType.number, - focusNode: _portFocus, - onSubmitted: (_) => _focusScope.requestFocus(_usernameFocus), - decoration: buildDecoration( - _s.port, - icon: Icons.format_list_numbered, - hint: '22', - ), - ), - TextField( - controller: _usernameController, - keyboardType: TextInputType.text, - focusNode: _usernameFocus, - autocorrect: false, - enableSuggestions: false, - decoration: buildDecoration( - _s.user, - icon: Icons.account_box, - hint: 'root', - ), - ), - width7, - Row( - children: [ - Text(_s.keyAuth), - width13, - Switch( - value: usePublicKey, - onChanged: (val) => setState(() => usePublicKey = val), - ), - ], - ), - !usePublicKey - ? TextField( - controller: _passwordController, - obscureText: true, - keyboardType: TextInputType.text, - decoration: buildDecoration( - _s.pwd, - icon: Icons.password, - hint: _s.pwd, - ), - onSubmitted: (_) => {}, - ) - : const SizedBox(), - usePublicKey - ? Consumer( - builder: (_, key, __) { - for (var item in key.infos) { - if (item.id == widget.spi?.pubKeyId) { - _pubKeyIndex ??= key.infos.indexOf(item); - } - } - final tiles = key.infos - .map( - (e) => ListTile( - contentPadding: EdgeInsets.zero, - title: Text(e.id, textAlign: TextAlign.start), - trailing: _buildRadio(key.infos.indexOf(e), e), - ), - ) - .toList(); - tiles.add( - ListTile( - title: Text(_s.addPrivateKey), - contentPadding: EdgeInsets.zero, - trailing: IconButton( - icon: const Icon(Icons.add), - onPressed: () => AppRoute( - const PrivateKeyEditPage(), - 'private key edit page', - ).go(context), - ), - ), - ); - return ExpansionTile( - textColor: primaryColor, - iconColor: primaryColor, - tilePadding: EdgeInsets.zero, - childrenPadding: EdgeInsets.zero, - initiallyExpanded: true, - title: Text( - _s.choosePrivateKey, - style: const TextStyle(fontSize: 14), - ), - children: tiles, - ); - }, - ) - : const SizedBox() - ], - ), - ), - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.send), - onPressed: () async { - if (_ipController.text == '') { - showSnackBar(context, Text(_s.plzEnterHost)); - return; - } - if (!usePublicKey && _passwordController.text == '') { - final cancel = await showRoundDialog( - context: context, - child: Text(_s.sureNoPwd), - actions: [ - TextButton( - onPressed: () => context.pop(false), - child: Text(_s.ok), - ), - TextButton( - onPressed: () => context.pop(true), - child: Text(_s.cancel), - ) - ], - ); - if (cancel ?? true) { - return; - } - } - if (usePublicKey && _pubKeyIndex == -1) { - showSnackBar(context, Text(_s.plzSelectKey)); - return; - } - if (_usernameController.text.isEmpty) { - _usernameController.text = 'root'; - } - if (_portController.text.isEmpty) { - _portController.text = '22'; - } + ); + } - if (widget.spi != null && widget.spi!.pubKeyId != null) { - _keyInfo ??= locator().get(widget.spi!.pubKeyId!); + Widget _buildKeyAuth() { + return Consumer( + builder: (_, key, __) { + for (var item in key.infos) { + if (item.id == widget.spi?.pubKeyId) { + _pubKeyIndex ??= key.infos.indexOf(item); } + } + final tiles = key.infos + .map( + (e) => ListTile( + contentPadding: EdgeInsets.zero, + title: Text(e.id, textAlign: TextAlign.start), + trailing: _buildRadio(key.infos.indexOf(e), e), + ), + ) + .toList(); + tiles.add( + ListTile( + title: Text(_s.addPrivateKey), + contentPadding: EdgeInsets.zero, + trailing: IconButton( + icon: const Icon(Icons.add), + onPressed: () => AppRoute( + const PrivateKeyEditPage(), + 'private key edit page', + ).go(context), + ), + ), + ); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 17), + child: Column( + children: tiles, + ), + ); + }, + ); + } - final authorization = _passwordController.text; - final spi = ServerPrivateInfo( - name: _nameController.text, - ip: _ipController.text, - port: int.parse(_portController.text), - user: _usernameController.text, - pwd: authorization, - pubKeyId: usePublicKey ? _keyInfo!.id : null, + Widget _buildFAB() { + return FloatingActionButton( + child: const Icon(Icons.send), + onPressed: () async { + if (_ipController.text == '') { + showSnackBar(context, Text(_s.plzEnterHost)); + return; + } + if (!usePublicKey && _passwordController.text == '') { + final cancel = await showRoundDialog( + context: context, + child: Text(_s.sureNoPwd), + actions: [ + TextButton( + onPressed: () => context.pop(false), + child: Text(_s.ok), + ), + TextButton( + onPressed: () => context.pop(true), + child: Text(_s.cancel), + ) + ], ); - - if (widget.spi == null) { - _serverProvider.addServer(spi); - } else { - _serverProvider.updateServer(widget.spi!, spi); + if (cancel ?? true) { + return; } + } + if (usePublicKey && _pubKeyIndex == -1) { + showSnackBar(context, Text(_s.plzSelectKey)); + return; + } + if (_usernameController.text.isEmpty) { + _usernameController.text = 'root'; + } + if (_portController.text.isEmpty) { + _portController.text = '22'; + } - context.pop(); - }, - ), + if (widget.spi != null && widget.spi!.pubKeyId != null) { + _keyInfo ??= locator().get(widget.spi!.pubKeyId!); + } + + final authorization = _passwordController.text; + final spi = ServerPrivateInfo( + name: _nameController.text, + ip: _ipController.text, + port: int.parse(_portController.text), + user: _usernameController.text, + pwd: authorization, + pubKeyId: usePublicKey ? _keyInfo!.id : null, + ); + + if (widget.spi == null) { + _serverProvider.addServer(spi); + } else { + _serverProvider.updateServer(widget.spi!, spi); + } + + context.pop(); + }, ); } diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index 2ed524d4..d702fe49 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -147,6 +147,7 @@ class _SettingPageState extends State { _s.onServerDetailPage, style: grey, ), + contentPadding: const EdgeInsets.only(left: 17, right: 11), trailing: buildSwitch(context, _setting.showDistLogo), ); } @@ -382,8 +383,10 @@ class _SettingPageState extends State { title: Text( _s.pushToken, ), - trailing: TextButton( - child: Text(_s.copy), + trailing: IconButton( + icon: const Icon(Icons.copy), + alignment: Alignment.centerRight, + padding: EdgeInsets.zero, onPressed: () { if (_pushToken != null) { copy(_pushToken!); diff --git a/lib/view/page/sftp/view.dart b/lib/view/page/sftp/view.dart index 3dbe3f35..f5a562d3 100644 --- a/lib/view/page/sftp/view.dart +++ b/lib/view/page/sftp/view.dart @@ -4,6 +4,7 @@ import 'package:dartssh2/dartssh2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/utils/navigator.dart'; +import 'package:toolbox/view/widget/input_field.dart'; import '../../../core/extension/numx.dart'; import '../../../core/extension/stringx.dart'; @@ -64,67 +65,73 @@ class _SFTPPageState extends State { actions: [ IconButton( icon: const Icon(Icons.downloading), - onPressed: () => - AppRoute(const SFTPDownloadingPage(), 'sftp downloading') - .go(context), + onPressed: () => AppRoute( + const SFTPDownloadingPage(), + 'sftp downloading', + ).go(context), ), ], ), body: _buildFileView(), - bottomNavigationBar: SafeArea(child: _buildBottom()), + bottomNavigationBar: _buildBottom(), ); } Widget _buildBottom() { return SafeArea( - child: Container( - padding: const EdgeInsets.fromLTRB(11, 7, 11, 11), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Divider(), - (_status.path?.path ?? _s.loadingFiles).omitStartStr(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - IconButton( - padding: const EdgeInsets.all(0), - onPressed: () async { - await backward(); - }, - icon: const Icon(Icons.arrow_back), - ), - IconButton( - onPressed: (() => showRoundDialog( - context: context, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - leading: const Icon(Icons.folder), - title: Text(_s.createFolder), - onTap: () => mkdir(context)), - ListTile( - leading: const Icon(Icons.insert_drive_file), - title: Text(_s.createFile), - onTap: () => newFile(context)), - ], - ), - actions: [ - TextButton( - onPressed: () => context.pop(), - child: Text(_s.close), - ) - ], - )), - icon: const Icon(Icons.add), - ), - _buildGotoBtn(), - ], - ) - ], + child: Container( + padding: const EdgeInsets.fromLTRB(11, 7, 11, 11), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Divider(), + (_status.path?.path ?? _s.loadingFiles).omitStartStr(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton( + padding: const EdgeInsets.all(0), + onPressed: () async { + await backward(); + }, + icon: const Icon(Icons.arrow_back), + ), + _buildAddBtn(), + _buildGotoBtn(), + ], + ) + ], + ), ), - )); + ); + } + + Widget _buildAddBtn() { + return IconButton( + onPressed: (() => showRoundDialog( + context: context, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.folder), + title: Text(_s.createFolder), + onTap: () => mkdir(context)), + ListTile( + leading: const Icon(Icons.insert_drive_file), + title: Text(_s.createFile), + onTap: () => newFile(context)), + ], + ), + actions: [ + TextButton( + onPressed: () => context.pop(), + child: Text(_s.close), + ) + ], + )), + icon: const Icon(Icons.add), + ); } Widget _buildGotoBtn() { @@ -137,11 +144,9 @@ class _SFTPPageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - TextField( - decoration: InputDecoration( - labelText: _s.path, - hintText: '/', - ), + buildInput( + label: _s.path, + hint: '/', onSubmitted: (value) => context.pop(value), ), ], @@ -179,7 +184,7 @@ class _SFTPPageState extends State { if (_status.files == null) { _status.path = AbsolutePath('/'); listDir(path: '/', client: _client); - return centerLoading; + return centerSizedLoading; } else { return RefreshIndicator( child: FadeIn( @@ -373,11 +378,9 @@ class _SFTPPageState extends State { showRoundDialog( context: context, title: Text(_s.createFolder), - child: TextField( + child: buildInput( controller: textController, - decoration: InputDecoration( - labelText: _s.name, - ), + label: _s.name, ), actions: [ TextButton( @@ -419,11 +422,9 @@ class _SFTPPageState extends State { showRoundDialog( context: context, title: Text(_s.createFile), - child: TextField( + child: buildInput( controller: textController, - decoration: InputDecoration( - labelText: _s.name, - ), + label: _s.name, ), actions: [ TextButton( @@ -466,11 +467,9 @@ class _SFTPPageState extends State { showRoundDialog( context: context, title: Text(_s.rename), - child: TextField( + child: buildInput( controller: textController, - decoration: InputDecoration( - labelText: _s.name, - ), + label: _s.name, ), actions: [ TextButton(onPressed: () => context.pop(), child: Text(_s.cancel)), diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart index 81d20439..db791bc4 100644 --- a/lib/view/page/snippet/edit.dart +++ b/lib/view/page/snippet/edit.dart @@ -2,13 +2,13 @@ import 'package:after_layout/after_layout.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/utils/navigator.dart'; +import 'package:toolbox/view/widget/input_field.dart'; import '../../../core/utils/ui.dart'; import '../../../data/model/server/snippet.dart'; import '../../../data/provider/snippet.dart'; import '../../../data/res/ui.dart'; import '../../../locator.dart'; -import '../../widget/input_decoration.dart'; class SnippetEditPage extends StatefulWidget { const SnippetEditPage({Key? key, this.snippet}) : super(key: key); @@ -60,22 +60,23 @@ class _SnippetEditPageState extends State body: ListView( padding: const EdgeInsets.all(13), children: [ - TextField( + buildInput( controller: _nameController, - keyboardType: TextInputType.text, + type: TextInputType.text, onSubmitted: (_) => FocusScope.of(context).requestFocus(_scriptNode), - decoration: buildDecoration(_s.name, icon: Icons.info), + label: _s.name, + icon: Icons.info, ), - TextField( + buildInput( controller: _scriptController, - autocorrect: false, - focusNode: _scriptNode, + autoCorrect: false, + node: _scriptNode, minLines: 3, maxLines: 10, - keyboardType: TextInputType.text, - enableSuggestions: false, - decoration: buildDecoration(_s.snippet, icon: Icons.code), + type: TextInputType.text, + label: _s.snippet, + icon: Icons.code, ), ], ), diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index 63453705..25b0fc52 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -156,7 +156,6 @@ class _SSHPageState extends State { child: TerminalView( _terminal, controller: _terminalController, - keyboardType: TextInputType.visiblePassword, textStyle: _terminalStyle, theme: _terminalTheme, deleteDetection: isIOS, diff --git a/lib/view/widget/input_decoration.dart b/lib/view/widget/input_decoration.dart deleted file mode 100644 index 58f3cf9c..00000000 --- a/lib/view/widget/input_decoration.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../data/res/color.dart'; - -InputDecoration buildDecoration(String label, - {TextStyle? textStyle, IconData? icon, String? hint}) { - return InputDecoration( - labelText: label, - labelStyle: textStyle, - hintText: hint, - icon: Icon( - icon, - color: primaryColor, - ), - ); -} diff --git a/lib/view/widget/input_field.dart b/lib/view/widget/input_field.dart index 1a2c15f1..082aad97 100644 --- a/lib/view/widget/input_field.dart +++ b/lib/view/widget/input_field.dart @@ -1,27 +1,38 @@ import 'package:flutter/material.dart'; import 'package:toolbox/view/widget/round_rect_card.dart'; -Widget buildInput( - BuildContext context, - TextEditingController controller, { - int maxLines = 20, +Widget buildInput({ + TextEditingController? controller, + int maxLines = 1, + int? minLines, String? hint, + String? label, Function(String)? onSubmitted, bool obscureText = false, IconData? icon, + TextInputType? type, + FocusNode? node, + bool autoCorrect = true, }) { return RoundRectCard( - TextField( - maxLines: maxLines, - onSubmitted: onSubmitted, - decoration: InputDecoration( - hintText: hint, - icon: icon != null ? Icon(icon) : null, - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(horizontal: 13, vertical: 7) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 17), + child: TextField( + maxLines: maxLines, + minLines: minLines, + onSubmitted: onSubmitted, + keyboardType: type, + focusNode: node, + autocorrect: autoCorrect, + decoration: InputDecoration( + label: label != null ? Text(label) : null, + hintText: hint, + icon: icon != null ? Icon(icon) : null, + border: InputBorder.none, + ), + controller: controller, + obscureText: obscureText, ), - controller: controller, - obscureText: obscureText, ), ); } diff --git a/make.dart b/make.dart index 0d2cd19f..025575f1 100755 --- a/make.dart +++ b/make.dart @@ -10,6 +10,7 @@ const buildDataFilePath = 'lib/data/res/build_data.dart'; const apkPath = 'build/app/outputs/flutter-apk/app-release.apk'; const xcarchivePath = 'build/ios/archive/Runner.xcarchive'; const appleXCConfigPath = 'Runner.xcodeproj/project.pbxproj'; +const releaseDirPath = '/Volumes/pm981/flutter_releases'; var regAppleProjectVer = RegExp(r'CURRENT_PROJECT_VERSION = .+;'); var regAppleMarketVer = RegExp(r'MARKETING_VERSION = .+'); @@ -127,6 +128,7 @@ Future flutterBuild( if (exitCode == 0) { target = target.replaceFirst('build', build.toString()); + target = '$releaseDirPath/$target'; print('Copying from $source to $target'); if (isAndroid) { await File(source).copy(target); @@ -146,17 +148,16 @@ Future flutterBuild( } Future flutterBuildIOS() async { - await flutterBuild( - xcarchivePath, './release/${appName}_ios_build.xcarchive', 'ipa'); + await flutterBuild(xcarchivePath, '${appName}_ios_build.xcarchive', 'ipa'); } Future flutterBuildMacOS() async { await flutterBuild( - xcarchivePath, './release/${appName}_macos_build.xcarchive', 'macos'); + xcarchivePath, '${appName}_macos_build.xcarchive', 'macos'); } Future flutterBuildAndroid() async { - await flutterBuild(apkPath, './release/${appName}_build_Arm64.apk', 'apk'); + await flutterBuild(apkPath, '${appName}_build_Arm64.apk', 'apk'); await killJava(); }