#29 opt. for TextInput

This commit is contained in:
lollipopkit
2023-05-07 18:25:30 +08:00
parent 29ea43a10f
commit ffae93cc72
20 changed files with 414 additions and 411 deletions

View File

@@ -1062,7 +1062,7 @@ abstract class S {
/// No description provided for @unknown. /// No description provided for @unknown.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'unknown'** /// **'Unknown'**
String get unknown; String get unknown;
/// No description provided for @unknownError. /// No description provided for @unknownError.

View File

@@ -522,7 +522,7 @@ class SEn extends S {
String get ttl => 'ttl'; String get ttl => 'ttl';
@override @override
String get unknown => 'unknown'; String get unknown => 'Unknown';
@override @override
String get unknownError => 'Unknown error'; String get unknownError => 'Unknown error';

View File

@@ -359,7 +359,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 = 284; CURRENT_PROJECT_VERSION = 286;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -367,7 +367,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.284; MARKETING_VERSION = 1.0.286;
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";
@@ -490,7 +490,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 = 284; CURRENT_PROJECT_VERSION = 286;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -498,7 +498,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.284; MARKETING_VERSION = 1.0.286;
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";
@@ -515,7 +515,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 = 284; CURRENT_PROJECT_VERSION = 286;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -523,7 +523,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.284; MARKETING_VERSION = 1.0.286;
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

@@ -2,8 +2,8 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; 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 engine = "3.7.11";
static const String buildAt = "2023-05-07 00:52:57.124037"; static const String buildAt = "2023-05-07 18:10:41.721685";
static const int modifications = 23; static const int modifications = 19;
} }

View File

@@ -160,7 +160,7 @@
"themeMode": "Theme mode", "themeMode": "Theme mode",
"times": "Times", "times": "Times",
"ttl": "ttl", "ttl": "ttl",
"unknown": "unknown", "unknown": "Unknown",
"unknownError": "Unknown error", "unknownError": "Unknown error",
"unkownConvertMode": "Unknown convert mode", "unkownConvertMode": "Unknown convert mode",
"update": "Update", "update": "Update",

View File

@@ -67,9 +67,12 @@ class BackupPage extends StatelessWidget {
final text = await file.readAsString(); final text = await file.readAsString();
_import(text, context, s); _import(text, context, s);
}), }),
const SizedBox(height: 7), const SizedBox(height: 17),
const Divider(), const SizedBox(
const SizedBox(height: 7), width: 37,
child: Divider(),
),
const SizedBox(height: 17),
_buildCard( _buildCard(
s.backup, s.backup,
Icons.file_upload, Icons.file_upload,

View File

@@ -89,7 +89,7 @@ class _ConvertPageState extends State<ConvertPage>
Widget _buildInputTop() { Widget _buildInputTop() {
return SizedBox( return SizedBox(
height: _media.size.height * 0.33, height: _media.size.height * 0.33,
child: buildInput(context, _textEditingController), child: buildInput(controller: _textEditingController),
); );
} }
@@ -150,9 +150,7 @@ class _ConvertPageState extends State<ConvertPage>
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
),
), ),
], ],
), ),
@@ -165,7 +163,7 @@ class _ConvertPageState extends State<ConvertPage>
Widget _buildResult() { Widget _buildResult() {
return SizedBox( return SizedBox(
height: _media.size.height * 0.33, height: _media.size.height * 0.33,
child: buildInput(context, _textEditingControllerResult), child: buildInput(controller: _textEditingControllerResult),
); );
} }

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/utils/navigator.dart'; import 'package:toolbox/core/utils/navigator.dart';
import 'package:toolbox/view/widget/input_field.dart';
import '../../core/utils/ui.dart'; import '../../core/utils/ui.dart';
import '../../data/model/docker/ps.dart'; import '../../data/model/docker/ps.dart';
@@ -94,27 +95,26 @@ class _DockerManagePageState extends State<DockerManagePage> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
TextField( buildInput(
keyboardType: TextInputType.text, type: TextInputType.text,
decoration: InputDecoration( label: _s.dockerImage,
labelText: _s.dockerImage, hintText: 'ubuntu:22.10'), hint: 'xxx:1.1',
controller: imageCtrl, controller: imageCtrl,
autocorrect: false, autoCorrect: false,
), ),
TextField( buildInput(
keyboardType: TextInputType.text, type: TextInputType.text,
controller: nameCtrl, controller: nameCtrl,
decoration: InputDecoration( label: _s.dockerContainerName,
labelText: _s.dockerContainerName, hintText: 'ubuntu22'), hint: 'xxx',
autocorrect: false, autoCorrect: false,
), ),
TextField( buildInput(
keyboardType: TextInputType.text, type: TextInputType.text,
controller: argsCtrl, controller: argsCtrl,
decoration: InputDecoration( label: _s.extraArgs,
labelText: _s.extraArgs, hint: '-p 2222:22 -v ~/.xxx/:/xxx',
hintText: '-p 2222:22 -v ~/.xxx/:/xxx'), autoCorrect: false,
autocorrect: false,
), ),
], ],
), ),
@@ -206,14 +206,12 @@ class _DockerManagePageState extends State<DockerManagePage> {
await showRoundDialog( await showRoundDialog(
context: context, context: context,
title: Text(widget.spi.user), title: Text(widget.spi.user),
child: TextField( child: buildInput(
controller: _textController, controller: _textController,
keyboardType: TextInputType.visiblePassword, type: TextInputType.visiblePassword,
obscureText: true, obscureText: true,
onSubmitted: (_) => onSubmitted(), onSubmitted: (_) => onSubmitted(),
decoration: InputDecoration( label: _s.pwd,
labelText: _s.pwd,
),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -262,17 +260,21 @@ class _DockerManagePageState extends State<DockerManagePage> {
return centerLoading; return centerLoading;
} }
final items = <Widget>[];
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( return ListView(
padding: const EdgeInsets.all(7), padding: const EdgeInsets.all(7),
children: [ children: items,
_buildLoading(),
_buildVersion(
_docker.edition ?? _s.unknown, _docker.version ?? _s.unknown),
_buildPsItems(),
_buildImages(),
_buildEditHost(),
const SizedBox(height: 37),
].map((e) => RoundRectCard(e)).toList(),
); );
} }
@@ -377,9 +379,9 @@ class _DockerManagePageState extends State<DockerManagePage> {
await showRoundDialog( await showRoundDialog(
context: context, context: context,
title: Text(_s.dockerEditHost), title: Text(_s.dockerEditHost),
child: TextField( child: buildInput(
maxLines: 1, maxLines: 1,
autocorrect: false, autoCorrect: false,
controller: controller:
TextEditingController(text: 'unix:///run/user/1000/docker.sock'), TextEditingController(text: 'unix:///run/user/1000/docker.sock'),
onSubmitted: (value) { onSubmitted: (value) {

View File

@@ -191,8 +191,10 @@ class _MyHomePageState extends State<MyHomePage>
ListTile( ListTile(
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: Text(_s.setting), title: Text(_s.setting),
onTap: () => onTap: () => AppRoute(
AppRoute(const SettingPage(), 'Setting').go(context), const SettingPage(),
'Setting',
).go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.vpn_key), leading: const Icon(Icons.vpn_key),
@@ -205,21 +207,26 @@ class _MyHomePageState extends State<MyHomePage>
ListTile( ListTile(
leading: const Icon(Icons.download), leading: const Icon(Icons.download),
title: Text(_s.download), title: Text(_s.download),
onTap: () => onTap: () => AppRoute(
AppRoute(const SFTPDownloadedPage(), 'snippet list') const SFTPDownloadedPage(),
.go(context), 'snippet list',
).go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.import_export), leading: const Icon(Icons.import_export),
title: Text(_s.backup), title: Text(_s.backup),
onTap: () => onTap: () => AppRoute(
AppRoute(BackupPage(), 'backup page').go(context), BackupPage(),
'backup page',
).go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.snippet_folder), leading: const Icon(Icons.snippet_folder),
title: Text(_s.snippet), title: Text(_s.snippet),
onTap: () => AppRoute(const SnippetListPage(), 'snippet list') onTap: () => AppRoute(
.go(context), const SnippetListPage(),
'snippet list',
).go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.text_snippet), leading: const Icon(Icons.text_snippet),

View File

@@ -58,8 +58,7 @@ class _PingPageState extends State<PingPage>
children: [ children: [
const SizedBox(height: 13), const SizedBox(height: 13),
buildInput( buildInput(
context, controller: _textEditingController,
_textEditingController,
hint: s.inputDomainHere, hint: s.inputDomainHere,
maxLines: 1, maxLines: 1,
onSubmitted: (_) => doPing(), onSubmitted: (_) => doPing(),

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/utils/navigator.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/pkg/upgrade_info.dart';
import '../../data/model/server/dist.dart'; import '../../data/model/server/dist.dart';
@@ -91,14 +92,12 @@ class _PkgManagePageState extends State<PkgManagePage>
await showRoundDialog( await showRoundDialog(
context: context, context: context,
title: Text(widget.spi.user), title: Text(widget.spi.user),
child: TextField( child: buildInput(
controller: _textController, controller: _textController,
keyboardType: TextInputType.visiblePassword, type: TextInputType.visiblePassword,
obscureText: true, obscureText: true,
onSubmitted: (_) => onSubmitted(), onSubmitted: (_) => onSubmitted(),
decoration: InputDecoration( label: _s.pwd,
labelText: _s.pwd,
),
), ),
actions: [ actions: [
TextButton( TextButton(

View File

@@ -9,6 +9,7 @@ import 'package:toolbox/core/extension/numx.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
import 'package:toolbox/core/utils/navigator.dart'; import 'package:toolbox/core/utils/navigator.dart';
import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/misc.dart';
import 'package:toolbox/view/widget/input_field.dart';
import '../../../core/utils/server.dart'; import '../../../core/utils/server.dart';
import '../../../core/utils/ui.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/provider/private_key.dart';
import '../../../data/res/ui.dart'; import '../../../data/res/ui.dart';
import '../../../locator.dart'; import '../../../locator.dart';
import '../../widget/input_decoration.dart';
const _format = 'text/plain'; const _format = 'text/plain';
@@ -78,23 +78,24 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage>
body: ListView( body: ListView(
padding: const EdgeInsets.all(13), padding: const EdgeInsets.all(13),
children: [ children: [
TextField( buildInput(
controller: _nameController, controller: _nameController,
keyboardType: TextInputType.text, type: TextInputType.text,
focusNode: _nameNode, node: _nameNode,
onSubmitted: (_) => _focusScope.requestFocus(_keyNode), onSubmitted: (_) => _focusScope.requestFocus(_keyNode),
decoration: buildDecoration(_s.name, icon: Icons.info), label: _s.name,
icon: Icons.info,
), ),
TextField( buildInput(
controller: _keyController, controller: _keyController,
autocorrect: false, autoCorrect: false,
minLines: 3, minLines: 3,
maxLines: 10, maxLines: 10,
keyboardType: TextInputType.text, type: TextInputType.text,
focusNode: _keyNode, node: _keyNode,
onSubmitted: (_) => _focusScope.requestFocus(_pwdNode), onSubmitted: (_) => _focusScope.requestFocus(_pwdNode),
enableSuggestions: false, label: _s.privateKey,
decoration: buildDecoration(_s.privateKey, icon: Icons.vpn_key), icon: Icons.vpn_key,
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -128,13 +129,14 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage>
}, },
child: Text(_s.pickFile), child: Text(_s.pickFile),
), ),
TextField( buildInput(
controller: _pwdController, controller: _pwdController,
autocorrect: false, autoCorrect: false,
keyboardType: TextInputType.text, type: TextInputType.text,
focusNode: _pwdNode, node: _pwdNode,
obscureText: true, obscureText: true,
decoration: buildDecoration(_s.pwd, icon: Icons.password), label: _s.pwd,
icon: Icons.password,
), ),
SizedBox(height: MediaQuery.of(context).size.height * 0.1), SizedBox(height: MediaQuery.of(context).size.height * 0.1),
_loading _loading

View File

@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/utils/navigator.dart'; import 'package:toolbox/core/utils/navigator.dart';
import 'package:toolbox/view/widget/input_field.dart';
import '../../../core/route.dart'; import '../../../core/route.dart';
import '../../../core/utils/ui.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/model/server/server_private_info.dart';
import '../../../data/provider/private_key.dart'; import '../../../data/provider/private_key.dart';
import '../../../data/provider/server.dart'; import '../../../data/provider/server.dart';
import '../../../data/res/color.dart';
import '../../../data/res/ui.dart'; import '../../../data/res/ui.dart';
import '../../../data/store/private_key.dart'; import '../../../data/store/private_key.dart';
import '../../../locator.dart'; import '../../../locator.dart';
import '../../widget/input_decoration.dart';
import '../private_key/edit.dart'; import '../private_key/edit.dart';
class ServerEditPage extends StatefulWidget { class ServerEditPage extends StatefulWidget {
@@ -61,224 +60,220 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: _buildAppBar(),
title: Text(_s.edit, style: textSize18), body: _buildForm(),
actions: [ floatingActionButton: _buildFAB(),
widget.spi != null );
? IconButton( }
onPressed: () {
showRoundDialog( PreferredSizeWidget _buildAppBar() {
context: context, final delBtn = IconButton(
child: Text(_s.sureToDeleteServer(widget.spi!.name)), onPressed: () {
actions: [ showRoundDialog(
TextButton( context: context,
onPressed: () { child: Text(_s.sureToDeleteServer(widget.spi!.name)),
_serverProvider.delServer(widget.spi!.id); actions: [
context.pop(); TextButton(
context.pop(); onPressed: () {
}, _serverProvider.delServer(widget.spi!.id);
child: Text( context.pop();
_s.ok, context.pop();
style: const TextStyle(color: Colors.red), },
), child: Text(
), _s.ok,
TextButton( style: const TextStyle(color: Colors.red),
onPressed: () => context.pop(), ),
child: Text(_s.cancel), ),
) TextButton(
], onPressed: () => context.pop(),
); child: Text(_s.cancel),
}, )
icon: const Icon(Icons.delete), ],
);
},
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<PrivateKeyProvider>(
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<bool>(
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) { Widget _buildKeyAuth() {
_keyInfo ??= locator<PrivateKeyStore>().get(widget.spi!.pubKeyId!); return Consumer<PrivateKeyProvider>(
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; Widget _buildFAB() {
final spi = ServerPrivateInfo( return FloatingActionButton(
name: _nameController.text, child: const Icon(Icons.send),
ip: _ipController.text, onPressed: () async {
port: int.parse(_portController.text), if (_ipController.text == '') {
user: _usernameController.text, showSnackBar(context, Text(_s.plzEnterHost));
pwd: authorization, return;
pubKeyId: usePublicKey ? _keyInfo!.id : null, }
if (!usePublicKey && _passwordController.text == '') {
final cancel = await showRoundDialog<bool>(
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) {
if (widget.spi == null) { return;
_serverProvider.addServer(spi);
} else {
_serverProvider.updateServer(widget.spi!, spi);
} }
}
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<PrivateKeyStore>().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();
},
); );
} }

View File

@@ -147,6 +147,7 @@ class _SettingPageState extends State<SettingPage> {
_s.onServerDetailPage, _s.onServerDetailPage,
style: grey, style: grey,
), ),
contentPadding: const EdgeInsets.only(left: 17, right: 11),
trailing: buildSwitch(context, _setting.showDistLogo), trailing: buildSwitch(context, _setting.showDistLogo),
); );
} }
@@ -382,8 +383,10 @@ class _SettingPageState extends State<SettingPage> {
title: Text( title: Text(
_s.pushToken, _s.pushToken,
), ),
trailing: TextButton( trailing: IconButton(
child: Text(_s.copy), icon: const Icon(Icons.copy),
alignment: Alignment.centerRight,
padding: EdgeInsets.zero,
onPressed: () { onPressed: () {
if (_pushToken != null) { if (_pushToken != null) {
copy(_pushToken!); copy(_pushToken!);

View File

@@ -4,6 +4,7 @@ import 'package:dartssh2/dartssh2.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/utils/navigator.dart'; import 'package:toolbox/core/utils/navigator.dart';
import 'package:toolbox/view/widget/input_field.dart';
import '../../../core/extension/numx.dart'; import '../../../core/extension/numx.dart';
import '../../../core/extension/stringx.dart'; import '../../../core/extension/stringx.dart';
@@ -64,67 +65,73 @@ class _SFTPPageState extends State<SFTPPage> {
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.downloading), icon: const Icon(Icons.downloading),
onPressed: () => onPressed: () => AppRoute(
AppRoute(const SFTPDownloadingPage(), 'sftp downloading') const SFTPDownloadingPage(),
.go(context), 'sftp downloading',
).go(context),
), ),
], ],
), ),
body: _buildFileView(), body: _buildFileView(),
bottomNavigationBar: SafeArea(child: _buildBottom()), bottomNavigationBar: _buildBottom(),
); );
} }
Widget _buildBottom() { Widget _buildBottom() {
return SafeArea( return SafeArea(
child: Container( child: Container(
padding: const EdgeInsets.fromLTRB(11, 7, 11, 11), padding: const EdgeInsets.fromLTRB(11, 7, 11, 11),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Divider(), const Divider(),
(_status.path?.path ?? _s.loadingFiles).omitStartStr(), (_status.path?.path ?? _s.loadingFiles).omitStartStr(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
IconButton( IconButton(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
onPressed: () async { onPressed: () async {
await backward(); await backward();
}, },
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
), ),
IconButton( _buildAddBtn(),
onPressed: (() => showRoundDialog( _buildGotoBtn(),
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(),
],
)
],
), ),
)); );
}
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() { Widget _buildGotoBtn() {
@@ -137,11 +144,9 @@ class _SFTPPageState extends State<SFTPPage> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
TextField( buildInput(
decoration: InputDecoration( label: _s.path,
labelText: _s.path, hint: '/',
hintText: '/',
),
onSubmitted: (value) => context.pop(value), onSubmitted: (value) => context.pop(value),
), ),
], ],
@@ -179,7 +184,7 @@ class _SFTPPageState extends State<SFTPPage> {
if (_status.files == null) { if (_status.files == null) {
_status.path = AbsolutePath('/'); _status.path = AbsolutePath('/');
listDir(path: '/', client: _client); listDir(path: '/', client: _client);
return centerLoading; return centerSizedLoading;
} else { } else {
return RefreshIndicator( return RefreshIndicator(
child: FadeIn( child: FadeIn(
@@ -373,11 +378,9 @@ class _SFTPPageState extends State<SFTPPage> {
showRoundDialog( showRoundDialog(
context: context, context: context,
title: Text(_s.createFolder), title: Text(_s.createFolder),
child: TextField( child: buildInput(
controller: textController, controller: textController,
decoration: InputDecoration( label: _s.name,
labelText: _s.name,
),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -419,11 +422,9 @@ class _SFTPPageState extends State<SFTPPage> {
showRoundDialog( showRoundDialog(
context: context, context: context,
title: Text(_s.createFile), title: Text(_s.createFile),
child: TextField( child: buildInput(
controller: textController, controller: textController,
decoration: InputDecoration( label: _s.name,
labelText: _s.name,
),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -466,11 +467,9 @@ class _SFTPPageState extends State<SFTPPage> {
showRoundDialog( showRoundDialog(
context: context, context: context,
title: Text(_s.rename), title: Text(_s.rename),
child: TextField( child: buildInput(
controller: textController, controller: textController,
decoration: InputDecoration( label: _s.name,
labelText: _s.name,
),
), ),
actions: [ actions: [
TextButton(onPressed: () => context.pop(), child: Text(_s.cancel)), TextButton(onPressed: () => context.pop(), child: Text(_s.cancel)),

View File

@@ -2,13 +2,13 @@ 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/utils/navigator.dart'; import 'package:toolbox/core/utils/navigator.dart';
import 'package:toolbox/view/widget/input_field.dart';
import '../../../core/utils/ui.dart'; import '../../../core/utils/ui.dart';
import '../../../data/model/server/snippet.dart'; import '../../../data/model/server/snippet.dart';
import '../../../data/provider/snippet.dart'; import '../../../data/provider/snippet.dart';
import '../../../data/res/ui.dart'; import '../../../data/res/ui.dart';
import '../../../locator.dart'; import '../../../locator.dart';
import '../../widget/input_decoration.dart';
class SnippetEditPage extends StatefulWidget { class SnippetEditPage extends StatefulWidget {
const SnippetEditPage({Key? key, this.snippet}) : super(key: key); const SnippetEditPage({Key? key, this.snippet}) : super(key: key);
@@ -60,22 +60,23 @@ class _SnippetEditPageState extends State<SnippetEditPage>
body: ListView( body: ListView(
padding: const EdgeInsets.all(13), padding: const EdgeInsets.all(13),
children: [ children: [
TextField( buildInput(
controller: _nameController, controller: _nameController,
keyboardType: TextInputType.text, type: TextInputType.text,
onSubmitted: (_) => onSubmitted: (_) =>
FocusScope.of(context).requestFocus(_scriptNode), FocusScope.of(context).requestFocus(_scriptNode),
decoration: buildDecoration(_s.name, icon: Icons.info), label: _s.name,
icon: Icons.info,
), ),
TextField( buildInput(
controller: _scriptController, controller: _scriptController,
autocorrect: false, autoCorrect: false,
focusNode: _scriptNode, node: _scriptNode,
minLines: 3, minLines: 3,
maxLines: 10, maxLines: 10,
keyboardType: TextInputType.text, type: TextInputType.text,
enableSuggestions: false, label: _s.snippet,
decoration: buildDecoration(_s.snippet, icon: Icons.code), icon: Icons.code,
), ),
], ],
), ),

View File

@@ -156,7 +156,6 @@ class _SSHPageState extends State<SSHPage> {
child: TerminalView( child: TerminalView(
_terminal, _terminal,
controller: _terminalController, controller: _terminalController,
keyboardType: TextInputType.visiblePassword,
textStyle: _terminalStyle, textStyle: _terminalStyle,
theme: _terminalTheme, theme: _terminalTheme,
deleteDetection: isIOS, deleteDetection: isIOS,

View File

@@ -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,
),
);
}

View File

@@ -1,27 +1,38 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/view/widget/round_rect_card.dart'; import 'package:toolbox/view/widget/round_rect_card.dart';
Widget buildInput( Widget buildInput({
BuildContext context, TextEditingController? controller,
TextEditingController controller, { int maxLines = 1,
int maxLines = 20, int? minLines,
String? hint, String? hint,
String? label,
Function(String)? onSubmitted, Function(String)? onSubmitted,
bool obscureText = false, bool obscureText = false,
IconData? icon, IconData? icon,
TextInputType? type,
FocusNode? node,
bool autoCorrect = true,
}) { }) {
return RoundRectCard( return RoundRectCard(
TextField( Padding(
maxLines: maxLines, padding: const EdgeInsets.symmetric(horizontal: 17),
onSubmitted: onSubmitted, child: TextField(
decoration: InputDecoration( maxLines: maxLines,
hintText: hint, minLines: minLines,
icon: icon != null ? Icon(icon) : null, onSubmitted: onSubmitted,
border: InputBorder.none, keyboardType: type,
contentPadding: const EdgeInsets.symmetric(horizontal: 13, vertical: 7) 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,
), ),
); );
} }

View File

@@ -10,6 +10,7 @@ const buildDataFilePath = 'lib/data/res/build_data.dart';
const apkPath = 'build/app/outputs/flutter-apk/app-release.apk'; const apkPath = 'build/app/outputs/flutter-apk/app-release.apk';
const xcarchivePath = 'build/ios/archive/Runner.xcarchive'; const xcarchivePath = 'build/ios/archive/Runner.xcarchive';
const appleXCConfigPath = 'Runner.xcodeproj/project.pbxproj'; const appleXCConfigPath = 'Runner.xcodeproj/project.pbxproj';
const releaseDirPath = '/Volumes/pm981/flutter_releases';
var regAppleProjectVer = RegExp(r'CURRENT_PROJECT_VERSION = .+;'); var regAppleProjectVer = RegExp(r'CURRENT_PROJECT_VERSION = .+;');
var regAppleMarketVer = RegExp(r'MARKETING_VERSION = .+'); var regAppleMarketVer = RegExp(r'MARKETING_VERSION = .+');
@@ -127,6 +128,7 @@ Future<void> flutterBuild(
if (exitCode == 0) { if (exitCode == 0) {
target = target.replaceFirst('build', build.toString()); target = target.replaceFirst('build', build.toString());
target = '$releaseDirPath/$target';
print('Copying from $source to $target'); print('Copying from $source to $target');
if (isAndroid) { if (isAndroid) {
await File(source).copy(target); await File(source).copy(target);
@@ -146,17 +148,16 @@ Future<void> flutterBuild(
} }
Future<void> flutterBuildIOS() async { Future<void> flutterBuildIOS() async {
await flutterBuild( await flutterBuild(xcarchivePath, '${appName}_ios_build.xcarchive', 'ipa');
xcarchivePath, './release/${appName}_ios_build.xcarchive', 'ipa');
} }
Future<void> flutterBuildMacOS() async { Future<void> flutterBuildMacOS() async {
await flutterBuild( await flutterBuild(
xcarchivePath, './release/${appName}_macos_build.xcarchive', 'macos'); xcarchivePath, '${appName}_macos_build.xcarchive', 'macos');
} }
Future<void> flutterBuildAndroid() async { Future<void> flutterBuildAndroid() async {
await flutterBuild(apkPath, './release/${appName}_build_Arm64.apk', 'apk'); await flutterBuild(apkPath, '${appName}_build_Arm64.apk', 'apk');
await killJava(); await killJava();
} }