-
+
|
@@ -67,10 +67,10 @@ If ServerBox app has any bug, please open an [issue](https://github.com/lollipop
|
-
+
|
-
+
|
diff --git a/README_zh.md b/README_zh.md
index a75f158f..b64e67d5 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -48,7 +48,7 @@
-
+
|
@@ -67,10 +67,10 @@
|
-
+
|
-
+
|
diff --git a/imgs/detail.jpg b/imgs/detail.jpg
index 0eb37305..82673614 100644
Binary files a/imgs/detail.jpg and b/imgs/detail.jpg differ
diff --git a/imgs/docker.jpeg b/imgs/docker.jpeg
new file mode 100644
index 00000000..a4028d4f
Binary files /dev/null and b/imgs/docker.jpeg differ
diff --git a/imgs/docker.jpg b/imgs/docker.jpg
deleted file mode 100644
index 63cbe17c..00000000
Binary files a/imgs/docker.jpg and /dev/null differ
diff --git a/imgs/server.jpeg b/imgs/server.jpeg
new file mode 100644
index 00000000..bd570941
Binary files /dev/null and b/imgs/server.jpeg differ
diff --git a/imgs/server.jpg b/imgs/server.jpg
deleted file mode 100644
index b2727886..00000000
Binary files a/imgs/server.jpg and /dev/null differ
diff --git a/imgs/sftp.jpeg b/imgs/sftp.jpeg
new file mode 100644
index 00000000..773d7a82
Binary files /dev/null and b/imgs/sftp.jpeg differ
diff --git a/imgs/sftp.jpg b/imgs/sftp.jpg
deleted file mode 100644
index 340c0113..00000000
Binary files a/imgs/sftp.jpg and /dev/null differ
diff --git a/lib/data/res/color.dart b/lib/data/res/color.dart
index a7af2b1d..c9b1aea0 100644
--- a/lib/data/res/color.dart
+++ b/lib/data/res/color.dart
@@ -8,4 +8,4 @@ Color primaryColor = Color(locator().primaryColor.fetch()!);
final contentColor = DynamicColor(Colors.black87, Colors.white70);
final bgColor = DynamicColor(Colors.white, Colors.black);
-final progressColor = DynamicColor(Colors.grey.shade100, Colors.white10);
+final progressColor = DynamicColor(Colors.black12, Colors.white10);
diff --git a/lib/data/res/ui.dart b/lib/data/res/ui.dart
index ed113833..dde53279 100644
--- a/lib/data/res/ui.dart
+++ b/lib/data/res/ui.dart
@@ -24,6 +24,8 @@ const height13 = SizedBox(height: 13);
const width13 = SizedBox(width: 13);
const width7 = SizedBox(width: 7);
+/// Misc
+
const popMenuChild = Padding(
padding: EdgeInsets.only(left: 7),
child: Icon(
diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart
index 0ae73ba9..2ecc077d 100644
--- a/lib/view/page/convert.dart
+++ b/lib/view/page/convert.dart
@@ -5,7 +5,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../../core/utils/ui.dart';
-import '../../data/res/color.dart';
import '../widget/input_field.dart';
import '../widget/round_rect_card.dart';
@@ -21,7 +20,6 @@ class _ConvertPageState extends State
late TextEditingController _textEditingController;
late TextEditingController _textEditingControllerResult;
late MediaQueryData _media;
- late ThemeData _theme;
late S _s;
int _typeOptionIndex = 0;
@@ -37,7 +35,6 @@ class _ConvertPageState extends State
void didChangeDependencies() {
super.didChangeDependencies();
_media = MediaQuery.of(context);
- _theme = Theme.of(context);
_s = S.of(context)!;
}
@@ -105,10 +102,14 @@ class _ConvertPageState extends State
'URL $encode',
'URL $decode'
];
+ final items = typeOption
+ .map(
+ (e) => PopupMenuItem(value: typeOption.indexOf(e), child: Text(e)),
+ )
+ .toList();
return RoundRectCard(
- ExpansionTile(
- tilePadding: const EdgeInsets.only(left: 7, right: 27),
- childrenPadding: EdgeInsets.zero,
+ ListTile(
+ contentPadding: const EdgeInsets.only(right: 17),
title: Row(
children: [
TextButton(
@@ -133,42 +134,30 @@ class _ConvertPageState extends State
),
trailing: ConstrainedBox(
constraints: BoxConstraints(maxWidth: _media.size.width * 0.35),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- typeOption[_typeOptionIndex],
- textScaleFactor: 1.0,
- textAlign: TextAlign.left,
- style: TextStyle(
- fontSize: 16.0,
- fontWeight: FontWeight.w500,
- color: primaryColor,
- ),
- ),
- Text(
- _s.currentMode,
- textScaleFactor: 1.0,
- textAlign: TextAlign.right,
- style: const TextStyle(fontSize: 9.0, color: Colors.grey),
- )
- ],
- ),
- ),
- children: typeOption
- .map(
- (e) => ListTile(
- title: Text(
- e,
- style: TextStyle(
- color: _theme.textTheme.bodyMedium?.color?.withAlpha(177),
+ child: buildPopuopMenu(
+ items: items,
+ onSelected: (p0) {
+ setState(() {
+ _typeOptionIndex = p0;
+ });
+ },
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Text(
+ typeOption[_typeOptionIndex],
+ textScaleFactor: 1.0,
+ textAlign: TextAlign.right,
+ style: const TextStyle(
+ fontWeight: FontWeight.w500,
+ color: Colors.grey
),
),
- trailing: _buildRadio(typeOption.indexOf(e)),
- ),
- )
- .toList(),
+ ],
+ ),
+ ),
+ ),
),
);
}
@@ -180,18 +169,6 @@ class _ConvertPageState extends State
);
}
- Radio _buildRadio(int index) {
- return Radio(
- value: index,
- groupValue: _typeOptionIndex,
- onChanged: (int? value) {
- setState(() {
- _typeOptionIndex = value ?? 0;
- });
- },
- );
- }
-
@override
bool get wantKeepAlive => true;
}
diff --git a/lib/view/page/docker.dart b/lib/view/page/docker.dart
index 3551b587..5cdb682c 100644
--- a/lib/view/page/docker.dart
+++ b/lib/view/page/docker.dart
@@ -271,6 +271,7 @@ class _DockerManagePageState extends State {
_buildPsItems(),
_buildImages(),
_buildEditHost(),
+ const SizedBox(height: 37),
].map((e) => RoundRectCard(e)).toList(),
);
}
@@ -279,59 +280,64 @@ class _DockerManagePageState extends State {
if (_docker.images == null) {
return const SizedBox();
}
- return ExpansionTile(
- title: Text(_s.imagesList),
- subtitle: Text(
- _s.dockerImagesFmt(_docker.images!.length),
- style: grey,
- ),
- children: _docker.images!
- .map(
- (e) => ListTile(
- title: Text(e.repo),
- subtitle: Text('${e.tag} - ${e.size}'),
- trailing: IconButton(
- icon: const Icon(Icons.delete),
- onPressed: () async {
- showRoundDialog(
- context: context,
- child: Text(_s.sureDelete(e.repo)),
- actions: [
- TextButton(
- onPressed: () => context.pop(),
- child: Text(_s.cancel),
- ),
- TextButton(
- onPressed: () async {
- context.pop();
- final result = await _docker.run(
- 'docker rmi ${e.id} -f',
+ final items = _docker.images!
+ .map(
+ (e) => ListTile(
+ title: Text(e.repo),
+ subtitle: Text('${e.tag} - ${e.size}', style: grey),
+ trailing: IconButton(
+ padding: EdgeInsets.zero,
+ alignment: Alignment.centerRight,
+ icon: const Icon(Icons.delete),
+ onPressed: () async {
+ showRoundDialog(
+ context: context,
+ child: Text(_s.sureDelete(e.repo)),
+ actions: [
+ TextButton(
+ onPressed: () => context.pop(),
+ child: Text(_s.cancel),
+ ),
+ TextButton(
+ onPressed: () async {
+ context.pop();
+ final result = await _docker.run(
+ 'docker rmi ${e.id} -f',
+ );
+ if (result != null) {
+ showSnackBar(
+ context,
+ Text(getErrMsg(result) ?? _s.unknownError),
);
- if (result != null) {
- showSnackBar(
- context,
- Text(getErrMsg(result) ?? _s.unknownError),
- );
- }
- },
- child: Text(
- _s.ok,
- style: const TextStyle(color: Colors.red),
- ),
+ }
+ },
+ child: Text(
+ _s.ok,
+ style: const TextStyle(color: Colors.red),
),
- ],
- );
- },
- ),
+ ),
+ ],
+ );
+ },
),
- )
- .toList(),
+ ),
+ )
+ .toList();
+ items.insert(
+ 0,
+ ListTile(
+ title: Text(_s.imagesList),
+ subtitle: Text(
+ _s.dockerImagesFmt(_docker.images!.length),
+ style: grey,
+ ),
+ ),
);
+ return Column(children: items);
}
Widget _buildLoading() {
if (!_docker.isBusy) return const SizedBox();
- final haveLog = _docker.runLog != null;
return Padding(
padding: const EdgeInsets.all(17),
child: Column(
@@ -339,8 +345,8 @@ class _DockerManagePageState extends State {
const Center(
child: CircularProgressIndicator(),
),
- haveLog ? const SizedBox(height: 17) : const SizedBox(),
- haveLog ? Text(_docker.runLog!) : const SizedBox()
+ const SizedBox(height: 17),
+ Text(_docker.runLog ?? '...'),
],
),
);
@@ -439,18 +445,25 @@ class _DockerManagePageState extends State {
}
Widget _buildPsItems() {
- return ExpansionTile(
- title: Text(_s.containerStatus),
- subtitle: Text(_buildSubtitle(_docker.items!), style: grey),
- children: _docker.items!.map(
- (item) {
- return ListTile(
- title: Text(item.name),
- subtitle: Text('${item.image} - ${item.status}'),
- trailing: _buildMoreBtn(item, _docker.isBusy),
- );
- },
- ).toList(),
+ final items = _docker.items!.map(
+ (item) {
+ return ListTile(
+ title: Text(item.name),
+ subtitle: Text('${item.image} - ${item.status}',
+ style: grey.copyWith(fontSize: 11)),
+ trailing: _buildMoreBtn(item, _docker.isBusy),
+ );
+ },
+ ).toList();
+ items.insert(
+ 0,
+ ListTile(
+ title: Text(_s.containerStatus),
+ subtitle: Text(_buildSubtitle(_docker.items!), style: grey),
+ ),
+ );
+ return Column(
+ children: items,
);
}
diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart
index da21ee85..cbe79338 100644
--- a/lib/view/page/home.dart
+++ b/lib/view/page/home.dart
@@ -185,7 +185,7 @@ class _MyHomePageState extends State
height: MediaQuery.of(context).size.height * 0.07,
),
Padding(
- padding: const EdgeInsets.symmetric(horizontal: 13),
+ padding: const EdgeInsets.symmetric(horizontal: 17),
child: Column(
children: [
ListTile(
@@ -215,24 +215,6 @@ class _MyHomePageState extends State
onTap: () =>
AppRoute(BackupPage(), 'backup page').go(context),
),
- ListTile(
- leading: const Icon(Icons.info),
- title: Text(_s.feedback),
- onTap: () => showRoundDialog(
- context: context,
- child: Text(_s.feedbackOnGithub),
- actions: [
- TextButton(
- onPressed: () => openUrl(issueUrl),
- child: Text(_s.feedback),
- ),
- TextButton(
- onPressed: () => context.pop(),
- child: Text(_s.close),
- )
- ],
- ),
- ),
ListTile(
leading: const Icon(Icons.snippet_folder),
title: Text(_s.snippet),
@@ -241,7 +223,7 @@ class _MyHomePageState extends State
),
ListTile(
leading: const Icon(Icons.text_snippet),
- title: Text(_s.about),
+ title: Text('${_s.about} & ${_s.feedback}'),
onTap: () {
showRoundDialog(
context: context,
@@ -266,6 +248,10 @@ class _MyHomePageState extends State
],
),
actions: [
+ TextButton(
+ onPressed: () => openUrl(issueUrl),
+ child: Text(_s.feedback),
+ ),
TextButton(
onPressed: () => showLicensePage(context: context),
child: Text(_s.license),
diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart
index 52565e95..8ea6cd51 100644
--- a/lib/view/page/server/edit.dart
+++ b/lib/view/page/server/edit.dart
@@ -240,7 +240,6 @@ class _ServerEditPageState extends State with AfterLayoutMixin {
child: Text(_s.cancel),
)
],
- barrierDismiss: false,
);
if (cancel ?? true) {
return;
@@ -250,10 +249,10 @@ class _ServerEditPageState extends State with AfterLayoutMixin {
showSnackBar(context, Text(_s.plzSelectKey));
return;
}
- if (_usernameController.text == '') {
+ if (_usernameController.text.isEmpty) {
_usernameController.text = 'root';
}
- if (_portController.text == '') {
+ if (_portController.text.isEmpty) {
_portController.text = '22';
}
diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart
index c12ba084..2ed524d4 100644
--- a/lib/view/page/setting.dart
+++ b/lib/view/page/setting.dart
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_material_color_picker/flutter_material_color_picker.dart';
import 'package:provider/provider.dart';
+import 'package:toolbox/core/utils/navigator.dart';
import 'package:toolbox/data/model/app/tab.dart';
import '../../core/utils/misc.dart';
@@ -427,6 +428,7 @@ class _SettingPageState extends State {
TextButton(
onPressed: () => setState(() {
_setting.fontPath.delete();
+ context.pop();
_showRestartSnackbar();
}),
child: Text(_s.clear),
@@ -452,6 +454,7 @@ class _SettingPageState extends State {
_setting.fontPath.put(newPath);
}
+ context.pop();
setState(() {});
_showRestartSnackbar();
return;
diff --git a/lib/view/page/sftp/view.dart b/lib/view/page/sftp/view.dart
index 1cbcea6b..3dbe3f35 100644
--- a/lib/view/page/sftp/view.dart
+++ b/lib/view/page/sftp/view.dart
@@ -36,7 +36,6 @@ class _SFTPPageState extends State {
final SftpBrowserStatus _status = SftpBrowserStatus();
final ScrollController _scrollController = ScrollController();
- late MediaQueryData _media;
late S _s;
Server? _si;
@@ -45,7 +44,6 @@ class _SFTPPageState extends State {
@override
void didChangeDependencies() {
super.didChangeDependencies();
- _media = MediaQuery.of(context);
_s = S.of(context)!;
}
@@ -121,43 +119,7 @@ class _SFTPPageState extends State {
)),
icon: const Icon(Icons.add),
),
- IconButton(
- padding: const EdgeInsets.all(0),
- onPressed: () async {
- final p = await showRoundDialog(
- context: context,
- title: Text(_s.goto),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- TextField(
- decoration: InputDecoration(
- labelText: _s.path,
- hintText: '/',
- ),
- onSubmitted: (value) => context.pop(value),
- ),
- ],
- ),
- actions: [
- TextButton(
- onPressed: () => context.pop(),
- child: Text(_s.cancel),
- )
- ],
- );
-
- if (p != null) {
- if (p.isEmpty) {
- showSnackBar(context, Text(_s.fieldMustNotEmpty));
- return;
- }
- _status.path?.update(p);
- listDir(path: p);
- }
- },
- icon: const Icon(Icons.gps_fixed),
- )
+ _buildGotoBtn(),
],
)
],
@@ -165,30 +127,59 @@ class _SFTPPageState extends State {
));
}
- Widget get centerCircleLoading => Center(
- child: Column(
- children: [
- SizedBox(
- height: _media.size.height * 0.4,
- ),
- const CircularProgressIndicator(),
+ Widget _buildGotoBtn() {
+ return IconButton(
+ padding: const EdgeInsets.all(0),
+ onPressed: () async {
+ final p = await showRoundDialog(
+ context: context,
+ title: Text(_s.goto),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ TextField(
+ decoration: InputDecoration(
+ labelText: _s.path,
+ hintText: '/',
+ ),
+ onSubmitted: (value) => context.pop(value),
+ ),
+ ],
+ ),
+ actions: [
+ TextButton(
+ onPressed: () => context.pop(),
+ child: Text(_s.cancel),
+ )
],
- ),
- );
+ );
+
+ if (p != null) {
+ if (p.isEmpty) {
+ showSnackBar(context, Text(_s.fieldMustNotEmpty));
+ return;
+ }
+ _status.path?.update(p);
+ listDir(path: p);
+ }
+ },
+ icon: const Icon(Icons.gps_fixed),
+ );
+ }
Widget _buildFileView() {
if (_client == null || _si?.state != ServerState.connected) {
- return centerCircleLoading;
+ return centerLoading;
}
if (_status.isBusy) {
- return centerCircleLoading;
+ return centerLoading;
}
if (_status.files == null) {
_status.path = AbsolutePath('/');
listDir(path: '/', client: _client);
- return centerCircleLoading;
+ return centerLoading;
} else {
return RefreshIndicator(
child: FadeIn(
diff --git a/lib/view/widget/input_field.dart b/lib/view/widget/input_field.dart
index 279ec932..1a2c15f1 100644
--- a/lib/view/widget/input_field.dart
+++ b/lib/view/widget/input_field.dart
@@ -1,22 +1,27 @@
import 'package:flutter/material.dart';
import 'package:toolbox/view/widget/round_rect_card.dart';
-Widget buildInput(BuildContext context, TextEditingController controller,
- {int maxLines = 20,
- String? hint,
- Function(String)? onSubmitted,
- bool? obscureText}) {
+Widget buildInput(
+ BuildContext context,
+ TextEditingController controller, {
+ int maxLines = 20,
+ String? hint,
+ Function(String)? onSubmitted,
+ bool obscureText = false,
+ IconData? icon,
+}) {
return RoundRectCard(
TextField(
maxLines: maxLines,
onSubmitted: onSubmitted,
decoration: InputDecoration(
- fillColor: Theme.of(context).cardColor,
- hintText: hint,
- filled: true,
- border: InputBorder.none),
+ hintText: hint,
+ icon: icon != null ? Icon(icon) : null,
+ border: InputBorder.none,
+ contentPadding: const EdgeInsets.symmetric(horizontal: 13, vertical: 7)
+ ),
controller: controller,
- obscureText: obscureText ?? false,
+ obscureText: obscureText,
),
);
}
| |