opt.: TagsEditor & Btn

This commit is contained in:
lollipopkit🏳️‍⚧️
2024-07-28 19:05:31 +08:00
parent 432d76f024
commit 8fd4cc1fe1
11 changed files with 44 additions and 90 deletions

View File

@@ -31,7 +31,7 @@ Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/rel
## 🔖 Feature ## 🔖 Feature
- `Status chart` (CPU, Sensors, GPU...), `SSH` Term, `SFTP`, `Docker & Process`... - `Status chart` (CPU, Sensors, GPU...), `SSH` Term, `SFTP`, `Docker & Process`...
- Platform specific: `Bio auth``Msg push``Home widget``watchOS App`... - Platform specific: `Bio auth``Msg push``Home widget``watchOS App`...
- English, 简体中文; Deutsch [@its-tom](https://github.com/its-tom), 繁體中文 [@kalashnikov](https://github.com/kalashnikov), Indonesian [@azkadev](https://github.com/azkadev), Français [@FrancXPT](https://github.com/FrancXPT), Dutch [@QazCetelic](https://github.com/QazCetelic); Español, Русский язык, Português, 日本語 (Generated by GPT) - English, 简体中文; Deutsch [@its-tom](https://github.com/its-tom), 繁體中文 [@kalashnikov](https://github.com/kalashnikov), Indonesian [@azkadev](https://github.com/azkadev), Français [@FrancXPT](https://github.com/FrancXPT), Dutch [@QazCetelic](https://github.com/QazCetelic), Türkçe [@mikropsoft](https://github.com/mikropsoft); Español, Русский язык, Português, 日本語 (Generated by GPT)
## 🏙️ ScreenShots ## 🏙️ ScreenShots

View File

@@ -33,7 +33,7 @@ Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/rel
- 本地化 - 本地化
- English, 简体中文 - English, 简体中文
- Español, Русский язык, Português, 日本語 (Generated by GPT) - Español, Русский язык, Português, 日本語 (Generated by GPT)
- Deutsch (@its-tom) / 繁體中文 (@kalashnikov) / Indonesian (@azkadev) / Français (@FrancXPT) / Dutch (@QazCetelic) - Deutsch [@its-tom](https://github.com/its-tom), 繁體中文 [@kalashnikov](https://github.com/kalashnikov), Indonesian [@azkadev](https://github.com/azkadev), Français [@FrancXPT](https://github.com/FrancXPT), Dutch [@QazCetelic](https://github.com/QazCetelic), Türkçe [@mikropsoft](https://github.com/mikropsoft);
## 🏙️ 截屏 ## 🏙️ 截屏

View File

@@ -26,8 +26,8 @@ class ServerProvider extends ChangeNotifier {
Iterable<Server> get servers => _servers.values; Iterable<Server> get servers => _servers.values;
final List<String> _serverOrder = []; final List<String> _serverOrder = [];
List<String> get serverOrder => _serverOrder; List<String> get serverOrder => _serverOrder;
final _tags = ValueNotifier(<String>[]); final _tags = ValueNotifier(<String>{});
ValueNotifier<List<String>> get tags => _tags; ValueNotifier<Set<String>> get tags => _tags;
Timer? _timer; Timer? _timer;
@@ -85,7 +85,6 @@ class ServerProvider extends ChangeNotifier {
} }
void _updateTags() { void _updateTags() {
_tags.value.clear();
for (final s in _servers.values) { for (final s in _servers.values) {
if (s.spi.tags == null) continue; if (s.spi.tags == null) continue;
for (final t in s.spi.tags!) { for (final t in s.spi.tags!) {
@@ -94,21 +93,7 @@ class ServerProvider extends ChangeNotifier {
} }
} }
} }
_tags.value.sort(); _tags.value = (_tags.value.toList()..sort()).toSet();
_tags.notifyListeners();
}
void renameTag(String old, String new_) {
for (final s in _servers.values) {
if (s.spi.tags == null) continue;
for (var i = 0; i < s.spi.tags!.length; i++) {
if (s.spi.tags![i] == old) {
s.spi.tags![i] = new_;
}
}
Stores.server.update(s.spi, s.spi);
}
_updateTags();
} }
Server genServer(ServerPrivateInfo spi) { Server genServer(ServerPrivateInfo spi) {

View File

@@ -9,8 +9,7 @@ class SnippetProvider extends ChangeNotifier {
late List<Snippet> _snippets; late List<Snippet> _snippets;
List<Snippet> get snippets => _snippets; List<Snippet> get snippets => _snippets;
final _tags = ValueNotifier(<String>[]); final tags = ValueNotifier(<String>{});
ValueNotifier<List<String>> get tags => _tags;
void load() { void load() {
_snippets = Stores.snippet.fetch(); _snippets = Stores.snippet.fetch();
@@ -29,16 +28,14 @@ class SnippetProvider extends ChangeNotifier {
} }
void _updateTags() { void _updateTags() {
_tags.value.clear(); final tags_ = <String>{};
final tags = <String>{};
for (final s in _snippets) { for (final s in _snippets) {
if (s.tags?.isEmpty ?? true) { final t = s.tags;
continue; if (t != null) {
tags_.addAll(t);
} }
tags.addAll(s.tags!);
} }
_tags.value.addAll(tags); tags.value = tags_;
_tags.notifyListeners();
} }
void add(Snippet snippet) { void add(Snippet snippet) {

View File

@@ -48,8 +48,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
final _pveIgnoreCert = ValueNotifier(false); final _pveIgnoreCert = ValueNotifier(false);
final _env = <String, String>{}.vn; final _env = <String, String>{}.vn;
final _customCmds = <String, String>{}.vn; final _customCmds = <String, String>{}.vn;
final _tags = <String>{}.vn;
var _tags = <String>[];
@override @override
void dispose() { void dispose() {
@@ -170,12 +169,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
hint: 'root', hint: 'root',
suggestion: false, suggestion: false,
), ),
TagEditor( TagTile(tags: _tags, allTags: Pros.server.tags.value).cardx,
tags: _tags,
onChanged: (p0) => _tags = p0,
allTags: [...Pros.server.tags.value],
onRenameTag: Pros.server.renameTag,
),
ListTile( ListTile(
title: Text(l10n.autoConnect), title: Text(l10n.autoConnect),
trailing: ListenableBuilder( trailing: ListenableBuilder(
@@ -436,7 +430,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
List<Widget> _buildWOLs() { List<Widget> _buildWOLs() {
return [ return [
const Text('Wake On LAN', style: UIs.text13Grey), const Text('Wake On LAN (beta)', style: UIs.text13Grey),
UIs.height7, UIs.height7,
ListTile( ListTile(
leading: const Icon(BoxIcons.bxs_help_circle), leading: const Icon(BoxIcons.bxs_help_circle),
@@ -455,7 +449,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
controller: _wolIpCtrl, controller: _wolIpCtrl,
type: TextInputType.text, type: TextInputType.text,
label: 'IP ${l10n.addr}', label: 'IP ${l10n.addr}',
icon: Icons.network_cell, icon: ZondIcons.network,
hint: '192.168.1.x', hint: '192.168.1.x',
suggestion: false, suggestion: false,
), ),
@@ -590,7 +584,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
keyId: _keyIdx.value != null keyId: _keyIdx.value != null
? Pros.key.pkis.elementAt(_keyIdx.value!).id ? Pros.key.pkis.elementAt(_keyIdx.value!).id
: null, : null,
tags: _tags, tags: _tags.value.isEmpty ? null : _tags.value.toList(),
alterUrl: _altUrlController.text.selfIfNotNullEmpty, alterUrl: _altUrlController.text.selfIfNotNullEmpty,
autoConnect: _autoConnect.value, autoConnect: _autoConnect.value,
jumpId: _jumpServer.value, jumpId: _jumpServer.value,
@@ -616,7 +610,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
context.showRoundDialog( context.showRoundDialog(
title: l10n.attention, title: l10n.attention,
child: SimpleMarkdown(data: l10n.writeScriptTip), child: SimpleMarkdown(data: l10n.writeScriptTip),
actions: Btns.oks(onTap: () => context.pop(true)), actions: [Btn.ok()],
); );
}, },
child: Row( child: Row(
@@ -648,7 +642,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
} }
/// List in dart is passed by pointer, so you need to copy it here /// List in dart is passed by pointer, so you need to copy it here
_tags.addAll(spi.tags ?? []); _tags.value = spi.tags?.toSet() ?? {};
_altUrlController.text = spi.alterUrl ?? ''; _altUrlController.text = spi.alterUrl ?? '';
_autoConnect.value = spi.autoConnect ?? true; _autoConnect.value = spi.autoConnect ?? true;

View File

@@ -1251,7 +1251,8 @@ class _SettingPageState extends State<SettingPage> {
), ),
onTap: () async { onTap: () async {
final ctrl = TextEditingController(text: val); final ctrl = TextEditingController(text: val);
void onSave(String s) { void onSave() {
final s = ctrl.text.trim();
_setting.sftpEditor.put(s); _setting.sftpEditor.put(s);
context.pop(); context.pop();
} }
@@ -1265,9 +1266,9 @@ class _SettingPageState extends State<SettingPage> {
hint: '\$EDITOR / vim / nano ...', hint: '\$EDITOR / vim / nano ...',
icon: Icons.edit, icon: Icons.edit,
suggestion: false, suggestion: false,
onSubmitted: onSave, onSubmitted: (_) => onSave(),
), ),
actions: Btns.oks(onTap: () => onSave(ctrl.text)), actions: [Btn.ok(onTap: (_) => onSave())],
); );
}, },
); );

View File

@@ -2,10 +2,9 @@ import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:server_box/core/extension/context/locale.dart'; import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/model/server/snippet.dart';
import 'package:server_box/data/res/provider.dart'; import 'package:server_box/data/res/provider.dart';
import '../../../data/model/server/snippet.dart';
class SnippetEditPage extends StatefulWidget { class SnippetEditPage extends StatefulWidget {
const SnippetEditPage({super.key, this.snippet}); const SnippetEditPage({super.key, this.snippet});
@@ -22,7 +21,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final _noteController = TextEditingController(); final _noteController = TextEditingController();
final _scriptNode = FocusNode(); final _scriptNode = FocusNode();
final _autoRunOn = ValueNotifier(<String>[]); final _autoRunOn = ValueNotifier(<String>[]);
final _tags = ValueNotifier(<String>[]); final _tags = <String>{}.vn;
@override @override
void dispose() { void dispose() {
@@ -36,7 +35,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(l10n.edit, style: UIs.text18), title: Text(l10n.edit),
actions: _buildAppBarActions(), actions: _buildAppBarActions(),
), ),
body: _buildBody(), body: _buildBody(),
@@ -45,9 +44,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
} }
List<Widget>? _buildAppBarActions() { List<Widget>? _buildAppBarActions() {
if (widget.snippet == null) { if (widget.snippet == null) return null;
return null;
}
return [ return [
IconButton( IconButton(
onPressed: () { onPressed: () {
@@ -89,7 +86,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final snippet = Snippet( final snippet = Snippet(
name: name, name: name,
script: script, script: script,
tags: _tags.value.isEmpty ? null : _tags.value, tags: _tags.value.isEmpty ? null : _tags.value.toList(),
note: note.isEmpty ? null : note, note: note.isEmpty ? null : note,
autoRunOn: _autoRunOn.value.isEmpty ? null : _autoRunOn.value, autoRunOn: _autoRunOn.value.isEmpty ? null : _autoRunOn.value,
); );
@@ -125,21 +122,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
icon: Icons.note, icon: Icons.note,
suggestion: true, suggestion: true,
), ),
ValBuilder( TagTile(tags: _tags, allTags: Pros.snippet.tags.value).cardx,
listenable: _tags,
builder: (vals) {
return TagEditor(
tags: _tags.value,
onChanged: (p0) => setState(() {
_tags.value = p0;
}),
allTags: [...Pros.snippet.tags.value],
onRenameTag: (old, n) => setState(() {
Pros.snippet.renameTag(old, n);
}),
);
},
),
Input( Input(
controller: _scriptController, controller: _scriptController,
node: _scriptNode, node: _scriptNode,
@@ -167,7 +150,10 @@ class _SnippetEditPageState extends State<SnippetEditPage>
.map((e) => Pros.server.pick(id: e)?.spi.name ?? e) .map((e) => Pros.server.pick(id: e)?.spi.name ?? e)
.join(', '); .join(', ');
return ListTile( return ListTile(
leading: const Icon(Icons.settings_remote, size: 19), leading: const Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(Icons.settings_remote, size: 19),
),
title: Text(l10n.autoRun), title: Text(l10n.autoRun),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
subtitle: subtitle == null subtitle: subtitle == null
@@ -232,7 +218,7 @@ ${l10n.forExample}:
} }
if (snippet.tags != null) { if (snippet.tags != null) {
_tags.value = snippet.tags!; _tags.value = snippet.tags!.toSet();
} }
if (snippet.autoRunOn != null) { if (snippet.autoRunOn != null) {

View File

@@ -100,16 +100,8 @@ class _SnippetListPageState extends State<SnippetListPage> {
maxLines: 3, maxLines: 3,
style: UIs.textGrey, style: UIs.textGrey,
), ),
trailing: Row( trailing: const Icon(Icons.keyboard_arrow_right),
mainAxisSize: MainAxisSize.min, onTap: () => AppRoutes.snippetEdit(snippet: snippet).go(context),
children: [
IconButton(
onPressed: () =>
AppRoutes.snippetEdit(snippet: snippet).go(context),
icon: const Icon(Icons.edit),
),
],
),
), ),
); );
} }

View File

@@ -396,7 +396,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
var newPerm = perm.copyWith(); var newPerm = perm.copyWith();
final ok = await context.showRoundDialog( final ok = await context.showRoundDialog(
child: UnixPermEditor(perm: perm, onChanged: (p) => newPerm = p), child: UnixPermEditor(perm: perm, onChanged: (p) => newPerm = p),
actions: Btns.oks(onTap: () => context.pop(true)), actions: [Btn.ok(onTap: (context) => context.pop(true))],
); );
final permStr = newPerm.perm; final permStr = newPerm.perm;
@@ -752,7 +752,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.showRoundDialog( context.showRoundDialog(
title: l10n.error, title: l10n.error,
child: Text('Unsupport file: ${name.filename}'), child: Text('Unsupport file: ${name.filename}'),
actions: Btns.oks(onTap: () => context.pop()), actions: [Btn.ok()],
); );
return; return;
} }
@@ -760,11 +760,10 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
final confirm = await context.showRoundDialog( final confirm = await context.showRoundDialog(
title: l10n.attention, title: l10n.attention,
child: SimpleMarkdown(data: '```sh\n$cmd\n```'), child: SimpleMarkdown(data: '```sh\n$cmd\n```'),
actions: Btns.okCancels( actions: [
onTapOk: () => context.pop(true), Btn.cancel(onTap: (c) => c.pop(false)),
onTapCancel: () => context.pop(false), Btn.ok(onTap: (c) => c.pop(true), red: true),
red: true, ],
),
); );
if (confirm != true) return; if (confirm != true) return;

View File

@@ -385,8 +385,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "v1.0.90" ref: "v1.0.94"
resolved-ref: "9f17bfce9f6cc9e071c40648bcac8d94e2dee919" resolved-ref: b4e431b7131605fa266be80a016165562b5437eb
url: "https://github.com/lppcg/fl_lib" url: "https://github.com/lppcg/fl_lib"
source: git source: git
version: "0.0.1" version: "0.0.1"

View File

@@ -62,7 +62,7 @@ dependencies:
fl_lib: fl_lib:
git: git:
url: https://github.com/lppcg/fl_lib url: https://github.com/lppcg/fl_lib
ref: v1.0.90 ref: v1.0.94
dependency_overrides: dependency_overrides:
# dartssh2: # dartssh2: