#29 opt. for material 3

This commit is contained in:
lollipopkit
2023-05-07 16:34:21 +08:00
parent 5afa543ba5
commit 29ea43a10f
18 changed files with 178 additions and 202 deletions

View File

@@ -48,7 +48,7 @@ If ServerBox app has any bug, please open an [issue](https://github.com/lollipop
<table>
<tr>
<td>
<img width="200px" src="imgs/server.jpg">
<img width="200px" src="imgs/server.jpeg">
</td>
<td>
<img width="200px" src="imgs/detail.jpg">
@@ -67,10 +67,10 @@ If ServerBox app has any bug, please open an [issue](https://github.com/lollipop
<img width="200px" src="imgs/ping.png">
</td>
<td>
<img width="200px" src="imgs/sftp.jpg">
<img width="200px" src="imgs/sftp.jpeg">
</td>
<td>
<img width="200px" src="imgs/docker.jpg">
<img width="200px" src="imgs/docker.jpeg">
</td>
<td>
<img width="200px" src="imgs/convert.png">

View File

@@ -48,7 +48,7 @@
<table>
<tr>
<td>
<img width="200px" src="imgs/server.jpg">
<img width="200px" src="imgs/server.jpeg">
</td>
<td>
<img width="200px" src="imgs/detail.jpg">
@@ -67,10 +67,10 @@
<img width="200px" src="imgs/ping.png">
</td>
<td>
<img width="200px" src="imgs/sftp.jpg">
<img width="200px" src="imgs/sftp.jpeg">
</td>
<td>
<img width="200px" src="imgs/docker.jpg">
<img width="200px" src="imgs/docker.jpeg">
</td>
<td>
<img width="200px" src="imgs/convert.png">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 297 KiB

BIN
imgs/docker.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

BIN
imgs/server.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 KiB

BIN
imgs/sftp.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

View File

@@ -8,4 +8,4 @@ Color primaryColor = Color(locator<SettingStore>().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);

View File

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

View File

@@ -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<ConvertPage>
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<ConvertPage>
void didChangeDependencies() {
super.didChangeDependencies();
_media = MediaQuery.of(context);
_theme = Theme.of(context);
_s = S.of(context)!;
}
@@ -105,10 +102,14 @@ class _ConvertPageState extends State<ConvertPage>
'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<ConvertPage>
),
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<int>(
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<ConvertPage>
);
}
Radio _buildRadio(int index) {
return Radio<int>(
value: index,
groupValue: _typeOptionIndex,
onChanged: (int? value) {
setState(() {
_typeOptionIndex = value ?? 0;
});
},
);
}
@override
bool get wantKeepAlive => true;
}

View File

@@ -271,6 +271,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
_buildPsItems(),
_buildImages(),
_buildEditHost(),
const SizedBox(height: 37),
].map((e) => RoundRectCard(e)).toList(),
);
}
@@ -279,59 +280,64 @@ class _DockerManagePageState extends State<DockerManagePage> {
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<DockerManagePage> {
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<DockerManagePage> {
}
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,
);
}

View File

@@ -185,7 +185,7 @@ class _MyHomePageState extends State<MyHomePage>
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<MyHomePage>
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<MyHomePage>
),
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<MyHomePage>
],
),
actions: [
TextButton(
onPressed: () => openUrl(issueUrl),
child: Text(_s.feedback),
),
TextButton(
onPressed: () => showLicensePage(context: context),
child: Text(_s.license),

View File

@@ -240,7 +240,6 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
child: Text(_s.cancel),
)
],
barrierDismiss: false,
);
if (cancel ?? true) {
return;
@@ -250,10 +249,10 @@ class _ServerEditPageState extends State<ServerEditPage> 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';
}

View File

@@ -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<SettingPage> {
TextButton(
onPressed: () => setState(() {
_setting.fontPath.delete();
context.pop();
_showRestartSnackbar();
}),
child: Text(_s.clear),
@@ -452,6 +454,7 @@ class _SettingPageState extends State<SettingPage> {
_setting.fontPath.put(newPath);
}
context.pop();
setState(() {});
_showRestartSnackbar();
return;

View File

@@ -36,7 +36,6 @@ class _SFTPPageState extends State<SFTPPage> {
final SftpBrowserStatus _status = SftpBrowserStatus();
final ScrollController _scrollController = ScrollController();
late MediaQueryData _media;
late S _s;
Server? _si;
@@ -45,7 +44,6 @@ class _SFTPPageState extends State<SFTPPage> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
_media = MediaQuery.of(context);
_s = S.of(context)!;
}
@@ -121,43 +119,7 @@ class _SFTPPageState extends State<SFTPPage> {
)),
icon: const Icon(Icons.add),
),
IconButton(
padding: const EdgeInsets.all(0),
onPressed: () async {
final p = await showRoundDialog<String?>(
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<SFTPPage> {
));
}
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<String?>(
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(

View File

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