opt.: no app restart required

This commit is contained in:
lollipopkit
2023-09-21 20:08:54 +08:00
parent cc4a05bf11
commit e928a29353
34 changed files with 498 additions and 620 deletions

View File

@@ -1,9 +1,9 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/ssh_client.dart';
import 'package:toolbox/core/extension/uint8list.dart';
@@ -25,12 +25,10 @@ import 'tag.dart';
class ServerFuncBtnsTopRight extends StatelessWidget {
final ServerPrivateInfo spi;
final S s;
const ServerFuncBtnsTopRight({
super.key,
required this.spi,
required this.s,
});
@override
@@ -45,13 +43,13 @@ class ServerFuncBtnsTopRight extends StatelessWidget {
const SizedBox(
width: 10,
),
Text(e.text(s)),
Text(e.toStr),
],
),
))
.toList(),
padding: const EdgeInsets.symmetric(horizontal: 10),
onSelected: (val) => _onTapMoreBtns(val, spi, context, s),
onSelected: (val) => _onTapMoreBtns(val, spi, context),
);
}
}
@@ -60,12 +58,10 @@ class ServerFuncBtns extends StatelessWidget {
const ServerFuncBtns({
super.key,
required this.spi,
required this.s,
this.iconSize,
});
final ServerPrivateInfo spi;
final S s;
final double? iconSize;
@override
@@ -74,7 +70,7 @@ class ServerFuncBtns extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: ServerTabMenuType.values
.map((e) => IconButton(
onPressed: () => _onTapMoreBtns(e, spi, context, s),
onPressed: () => _onTapMoreBtns(e, spi, context),
padding: EdgeInsets.zero,
tooltip: e.name,
icon: Icon(e.icon, size: iconSize ?? 15),
@@ -88,16 +84,15 @@ void _onTapMoreBtns(
ServerTabMenuType value,
ServerPrivateInfo spi,
BuildContext context,
S s,
) async {
switch (value) {
case ServerTabMenuType.pkg:
_onPkg(context, s, spi);
_onPkg(context, spi);
break;
case ServerTabMenuType.sftp:
AppRoute.sftp(spi: spi).checkGo(
context: context,
check: () => _checkClient(context, spi.id, s.waitConnection),
check: () => _checkClient(context, spi.id),
);
break;
case ServerTabMenuType.snippet:
@@ -114,12 +109,12 @@ void _onTapMoreBtns(
final result = await Providers.server.runSnippets(spi.id, snippets);
if (result != null && result.isNotEmpty) {
context.showRoundDialog(
title: Text(s.result),
title: Text(l10n.result),
child: Text(result),
actions: [
TextButton(
onPressed: () => copy2Clipboard(result),
child: Text(s.copy),
child: Text(l10n.copy),
)
],
);
@@ -128,13 +123,13 @@ void _onTapMoreBtns(
case ServerTabMenuType.docker:
AppRoute.docker(spi: spi).checkGo(
context: context,
check: () => _checkClient(context, spi.id, s.waitConnection),
check: () => _checkClient(context, spi.id),
);
break;
case ServerTabMenuType.process:
AppRoute.process(spi: spi).checkGo(
context: context,
check: () => _checkClient(context, spi.id, s.waitConnection),
check: () => _checkClient(context, spi.id),
);
break;
case ServerTabMenuType.terminal:
@@ -192,19 +187,19 @@ Future<void> _gotoSSH(
}
}
bool _checkClient(BuildContext context, String id, String msg) {
bool _checkClient(BuildContext context, String id) {
final server = Providers.server.servers[id];
if (server == null || server.client == null) {
context.showSnackBar(msg);
context.showSnackBar(l10n.waitConnection);
return false;
}
return true;
}
Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
Future<void> _onPkg(BuildContext context, ServerPrivateInfo spi) async {
final server = spi.findServer;
if (server == null) {
context.showSnackBar(s.noClient);
context.showSnackBar(l10n.noClient);
return;
}
final sys = server.status.sysVer;
@@ -232,13 +227,13 @@ Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
final result = await server.client?.run(listCmd).string;
context.pop();
if (result == null) {
context.showSnackBar(s.noResult);
context.showSnackBar(l10n.noResult);
return;
}
final list = pkg?.updateListRemoveUnused(result.split('\n'));
final upgradeable = list?.map((e) => UpgradePkgInfo(e, pkg)).toList();
if (upgradeable == null || upgradeable.isEmpty) {
context.showSnackBar(s.noUpdateAvailable);
context.showSnackBar(l10n.noUpdateAvailable);
return;
}
final args = upgradeable.map((e) => e.package).join(' ');
@@ -247,14 +242,14 @@ Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
// Confirm upgrade
final gotoUpgrade = await context.showRoundDialog<bool>(
title: Text(s.attention),
title: Text(l10n.attention),
child: SingleChildScrollView(
child: Text('${s.foundNUpdate(upgradeable.length)}\n\n$upgradeCmd'),
child: Text('${l10n.foundNUpdate(upgradeable.length)}\n\n$upgradeCmd'),
),
actions: [
TextButton(
onPressed: () => context.pop(true),
child: Text(s.update),
child: Text(l10n.update),
),
],
);
@@ -263,6 +258,6 @@ Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
AppRoute.ssh(spi: spi, initCmd: upgradeCmd).checkGo(
context: context,
check: () => _checkClient(context, spi.id, s.waitConnection),
check: () => _checkClient(context, spi.id),
);
}

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/input_field.dart';
import 'package:toolbox/view/widget/round_rect_card.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../../data/model/app/tag_pickable.dart';
import '../../data/res/color.dart';
@@ -39,7 +39,6 @@ class TagBtn extends StatelessWidget {
class TagEditor extends StatefulWidget {
final List<String> tags;
final S s;
final void Function(List<String>)? onChanged;
final void Function(String old, String new_)? onRenameTag;
final List<String> allTags;
@@ -47,7 +46,6 @@ class TagEditor extends StatefulWidget {
const TagEditor({
super.key,
required this.tags,
required this.s,
this.onChanged,
this.onRenameTag,
this.allTags = const <String>[],
@@ -78,7 +76,7 @@ class _TagEditorState extends State<TagEditor> {
/// Add vertical divider if suggestions.length > 0
final counts = tags.length + suggestionLen + (suggestionLen == 0 ? 0 : 1);
if (counts == 0) return Text(widget.s.tag);
if (counts == 0) return Text(l10n.tag);
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: _kTagBtnHeight),
child: ListView.builder(
@@ -134,12 +132,12 @@ class _TagEditorState extends State<TagEditor> {
void _showAddTagDialog() {
final textEditingController = TextEditingController();
context.showRoundDialog(
title: Text(widget.s.add),
title: Text(l10n.add),
child: Input(
autoFocus: true,
icon: Icons.tag,
controller: textEditingController,
hint: widget.s.tag,
hint: l10n.tag,
),
actions: [
TextButton(
@@ -149,7 +147,7 @@ class _TagEditorState extends State<TagEditor> {
widget.onChanged?.call(widget.tags);
context.pop();
},
child: Text(widget.s.add),
child: Text(l10n.add),
),
],
);
@@ -158,12 +156,12 @@ class _TagEditorState extends State<TagEditor> {
void _showRenameDialog(String tag) {
final textEditingController = TextEditingController(text: tag);
context.showRoundDialog(
title: Text(widget.s.rename),
title: Text(l10n.rename),
child: Input(
autoFocus: true,
icon: Icons.abc,
controller: textEditingController,
hint: widget.s.tag,
hint: l10n.tag,
),
actions: [
TextButton(
@@ -174,7 +172,7 @@ class _TagEditorState extends State<TagEditor> {
context.pop();
setState(() {});
},
child: Text(widget.s.rename),
child: Text(l10n.rename),
),
],
);
@@ -196,14 +194,12 @@ class TagPicker<T extends TagPickable> extends StatefulWidget {
}
class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
late S _s;
late MediaQueryData _media;
final List<T> _selected = [];
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
_media = MediaQuery.of(context);
}
@@ -211,7 +207,7 @@ class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
Widget build(BuildContext context) {
final children = <Widget>[];
if (widget.tags.isNotEmpty) {
children.add(Text(_s.tag));
children.add(Text(l10n.tag));
children.add(UIs.height13);
children.add(SizedBox(
height: _kTagBtnHeight,
@@ -220,7 +216,7 @@ class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
));
}
if (widget.items.isNotEmpty) {
children.add(Text(_s.all));
children.add(Text(l10n.all));
children.add(UIs.height13);
children.add(SizedBox(
height: _kTagBtnHeight,
@@ -229,15 +225,15 @@ class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
));
}
final child = widget.tags.isEmpty && widget.items.isEmpty
? Text(_s.noOptions)
? Text(l10n.noOptions)
: Column(mainAxisSize: MainAxisSize.min, children: children);
return AlertDialog(
title: Text(_s.choose),
title: Text(l10n.choose),
content: child,
actions: [
TextButton(
onPressed: () => context.pop(_selected),
child: Text(_s.ok),
child: Text(l10n.ok),
),
],
);