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
- `Status chart` (CPU, Sensors, GPU...), `SSH` Term, `SFTP`, `Docker & Process`...
- 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

View File

@@ -33,7 +33,7 @@ Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/rel
- 本地化
- English, 简体中文
- 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;
final List<String> _serverOrder = [];
List<String> get serverOrder => _serverOrder;
final _tags = ValueNotifier(<String>[]);
ValueNotifier<List<String>> get tags => _tags;
final _tags = ValueNotifier(<String>{});
ValueNotifier<Set<String>> get tags => _tags;
Timer? _timer;
@@ -85,7 +85,6 @@ class ServerProvider extends ChangeNotifier {
}
void _updateTags() {
_tags.value.clear();
for (final s in _servers.values) {
if (s.spi.tags == null) continue;
for (final t in s.spi.tags!) {
@@ -94,21 +93,7 @@ class ServerProvider extends ChangeNotifier {
}
}
}
_tags.value.sort();
_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();
_tags.value = (_tags.value.toList()..sort()).toSet();
}
Server genServer(ServerPrivateInfo spi) {

View File

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

View File

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

View File

@@ -1251,7 +1251,8 @@ class _SettingPageState extends State<SettingPage> {
),
onTap: () async {
final ctrl = TextEditingController(text: val);
void onSave(String s) {
void onSave() {
final s = ctrl.text.trim();
_setting.sftpEditor.put(s);
context.pop();
}
@@ -1265,9 +1266,9 @@ class _SettingPageState extends State<SettingPage> {
hint: '\$EDITOR / vim / nano ...',
icon: Icons.edit,
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_markdown/flutter_markdown.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 '../../../data/model/server/snippet.dart';
class SnippetEditPage extends StatefulWidget {
const SnippetEditPage({super.key, this.snippet});
@@ -22,7 +21,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final _noteController = TextEditingController();
final _scriptNode = FocusNode();
final _autoRunOn = ValueNotifier(<String>[]);
final _tags = ValueNotifier(<String>[]);
final _tags = <String>{}.vn;
@override
void dispose() {
@@ -36,7 +35,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: Text(l10n.edit, style: UIs.text18),
title: Text(l10n.edit),
actions: _buildAppBarActions(),
),
body: _buildBody(),
@@ -45,9 +44,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
}
List<Widget>? _buildAppBarActions() {
if (widget.snippet == null) {
return null;
}
if (widget.snippet == null) return null;
return [
IconButton(
onPressed: () {
@@ -89,7 +86,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final snippet = Snippet(
name: name,
script: script,
tags: _tags.value.isEmpty ? null : _tags.value,
tags: _tags.value.isEmpty ? null : _tags.value.toList(),
note: note.isEmpty ? null : note,
autoRunOn: _autoRunOn.value.isEmpty ? null : _autoRunOn.value,
);
@@ -125,21 +122,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
icon: Icons.note,
suggestion: true,
),
ValBuilder(
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);
}),
);
},
),
TagTile(tags: _tags, allTags: Pros.snippet.tags.value).cardx,
Input(
controller: _scriptController,
node: _scriptNode,
@@ -167,7 +150,10 @@ class _SnippetEditPageState extends State<SnippetEditPage>
.map((e) => Pros.server.pick(id: e)?.spi.name ?? e)
.join(', ');
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),
trailing: const Icon(Icons.keyboard_arrow_right),
subtitle: subtitle == null
@@ -232,7 +218,7 @@ ${l10n.forExample}:
}
if (snippet.tags != null) {
_tags.value = snippet.tags!;
_tags.value = snippet.tags!.toSet();
}
if (snippet.autoRunOn != null) {

View File

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

View File

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

View File

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

View File

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