#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.
///
/// In en, this message translates to:
/// **'unknown'**
/// **'Unknown'**
String get unknown;
/// No description provided for @unknownError.

View File

@@ -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';

View File

@@ -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";

View File

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

View File

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

View File

@@ -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,

View File

@@ -89,7 +89,7 @@ class _ConvertPageState extends State<ConvertPage>
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<ConvertPage>
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<ConvertPage>
Widget _buildResult() {
return SizedBox(
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: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<DockerManagePage> {
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<DockerManagePage> {
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<DockerManagePage> {
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(
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<DockerManagePage> {
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) {

View File

@@ -191,8 +191,10 @@ class _MyHomePageState extends State<MyHomePage>
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<MyHomePage>
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),

View File

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

View File

@@ -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<PkgManagePage>
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(

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/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<PrivateKeyEditPage>
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<PrivateKeyEditPage>
},
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

View File

@@ -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<ServerEditPage> 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<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) {
_keyInfo ??= locator<PrivateKeyStore>().get(widget.spi!.pubKeyId!);
Widget _buildKeyAuth() {
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;
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<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 (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<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,
style: grey,
),
contentPadding: const EdgeInsets.only(left: 17, right: 11),
trailing: buildSwitch(context, _setting.showDistLogo),
);
}
@@ -382,8 +383,10 @@ class _SettingPageState extends State<SettingPage> {
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!);

View File

@@ -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<SFTPPage> {
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<SFTPPage> {
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<SFTPPage> {
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<SFTPPage> {
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<SFTPPage> {
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<SFTPPage> {
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)),

View File

@@ -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<SnippetEditPage>
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,
),
],
),

View File

@@ -156,7 +156,6 @@ class _SSHPageState extends State<SSHPage> {
child: TerminalView(
_terminal,
controller: _terminalController,
keyboardType: TextInputType.visiblePassword,
textStyle: _terminalStyle,
theme: _terminalTheme,
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: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,
),
);
}

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 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<void> 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<void> flutterBuild(
}
Future<void> flutterBuildIOS() async {
await flutterBuild(
xcarchivePath, './release/${appName}_ios_build.xcarchive', 'ipa');
await flutterBuild(xcarchivePath, '${appName}_ios_build.xcarchive', 'ipa');
}
Future<void> flutterBuildMacOS() async {
await flutterBuild(
xcarchivePath, './release/${appName}_macos_build.xcarchive', 'macos');
xcarchivePath, '${appName}_macos_build.xcarchive', 'macos');
}
Future<void> flutterBuildAndroid() async {
await flutterBuild(apkPath, './release/${appName}_build_Arm64.apk', 'apk');
await flutterBuild(apkPath, '${appName}_build_Arm64.apk', 'apk');
await killJava();
}