new: server tag

This commit is contained in:
lollipopkit
2023-05-30 22:44:45 +08:00
parent 92ffed6541
commit 472a441c8e
23 changed files with 239 additions and 112 deletions

View File

@@ -108,24 +108,30 @@ abstract class S {
/// **'Thanks to the following people who participated in.'** /// **'Thanks to the following people who participated in.'**
String get aboutThanks; String get aboutThanks;
/// No description provided for @add.
///
/// In en, this message translates to:
/// **'Add'**
String get add;
/// No description provided for @addAServer. /// No description provided for @addAServer.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'add a server'** /// **'add a server'**
String get addAServer; String get addAServer;
/// No description provided for @addOne.
///
/// In en, this message translates to:
/// **'Add one'**
String get addOne;
/// No description provided for @addPrivateKey. /// No description provided for @addPrivateKey.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'Add private key'** /// **'Add private key'**
String get addPrivateKey; String get addPrivateKey;
/// No description provided for @all.
///
/// In en, this message translates to:
/// **'All'**
String get all;
/// No description provided for @alreadyLastDir. /// No description provided for @alreadyLastDir.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View File

@@ -10,14 +10,17 @@ class SDe extends S {
@override @override
String get aboutThanks => 'Vielen Dank an die folgenden Personen, die daran teilgenommen haben.\n'; String get aboutThanks => 'Vielen Dank an die folgenden Personen, die daran teilgenommen haben.\n';
@override
String get add => 'Neu';
@override @override
String get addAServer => 'Server hinzufügen'; String get addAServer => 'Server hinzufügen';
@override @override
String get addOne => 'Hinzufügen'; String get addPrivateKey => 'Private key hinzufügen';
@override @override
String get addPrivateKey => 'Private key hinzufügen'; String get all => 'Alle';
@override @override
String get alreadyLastDir => 'Bereits im letzten Verzeichnis.'; String get alreadyLastDir => 'Bereits im letzten Verzeichnis.';

View File

@@ -10,14 +10,17 @@ class SEn extends S {
@override @override
String get aboutThanks => 'Thanks to the following people who participated in.'; String get aboutThanks => 'Thanks to the following people who participated in.';
@override
String get add => 'Add';
@override @override
String get addAServer => 'add a server'; String get addAServer => 'add a server';
@override @override
String get addOne => 'Add one'; String get addPrivateKey => 'Add private key';
@override @override
String get addPrivateKey => 'Add private key'; String get all => 'All';
@override @override
String get alreadyLastDir => 'Already in last directory.'; String get alreadyLastDir => 'Already in last directory.';

View File

@@ -10,14 +10,17 @@ class SZh extends S {
@override @override
String get aboutThanks => '感谢以下参与的各位。'; String get aboutThanks => '感谢以下参与的各位。';
@override
String get add => '新增';
@override @override
String get addAServer => '添加服务器'; String get addAServer => '添加服务器';
@override @override
String get addOne => '前去新增'; String get addPrivateKey => '添加一个私钥';
@override @override
String get addPrivateKey => '添加一个私钥'; String get all => '所有';
@override @override
String get alreadyLastDir => '已经是最上层目录了'; String get alreadyLastDir => '已经是最上层目录了';
@@ -614,14 +617,17 @@ class SZhTw extends SZh {
@override @override
String get aboutThanks => '感謝以下參與的各位。'; String get aboutThanks => '感謝以下參與的各位。';
@override
String get add => '新增';
@override @override
String get addAServer => '新增服務器'; String get addAServer => '新增服務器';
@override @override
String get addOne => '前去新增'; String get addPrivateKey => '新增一個私鑰';
@override @override
String get addPrivateKey => '新增一個私鑰'; String get all => '所有';
@override @override
String get alreadyLastDir => '已經是最上層目錄了'; String get alreadyLastDir => '已經是最上層目錄了';

View File

@@ -19,4 +19,16 @@ extension StringOrderX on StringOrder {
if (index == -1) return; if (index == -1) return;
this[index] = newId; this[index] = newId;
} }
int index(String id) {
return indexOf(id);
}
void moveById(String oid, String nid, StoreProperty property) {
final index = indexOf(oid);
if (index == -1) return;
final newIndex = indexOf(nid);
if (newIndex == -1) return;
move(index, newIndex, property);
}
} }

View File

@@ -141,7 +141,7 @@ void showSnippetDialog(
context.pop(); context.pop();
AppRoute(const SnippetEditPage(), 'edit snippet').go(context); AppRoute(const SnippetEditPage(), 'edit snippet').go(context);
}, },
child: Text(s.addOne), child: Text(s.add),
) )
], ],
); );

View File

@@ -16,6 +16,8 @@ class ServerPrivateInfo {
late String pwd; late String pwd;
@HiveField(5) @HiveField(5)
String? pubKeyId; String? pubKeyId;
@HiveField(6)
List<String>? tags;
late String id; late String id;
@@ -26,6 +28,7 @@ class ServerPrivateInfo {
required this.user, required this.user,
required this.pwd, required this.pwd,
this.pubKeyId, this.pubKeyId,
this.tags,
}) : id = '$user@$ip:$port'; }) : id = '$user@$ip:$port';
ServerPrivateInfo.fromJson(Map<String, dynamic> json) { ServerPrivateInfo.fromJson(Map<String, dynamic> json) {
@@ -36,6 +39,7 @@ class ServerPrivateInfo {
pwd = json["authorization"].toString(); pwd = json["authorization"].toString();
pubKeyId = json["pubKeyId"]?.toString(); pubKeyId = json["pubKeyId"]?.toString();
id = '$user@$ip:$port'; id = '$user@$ip:$port';
tags = json["tags"]?.cast<String>();
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@@ -46,6 +50,11 @@ class ServerPrivateInfo {
data["user"] = user; data["user"] = user;
data["authorization"] = pwd; data["authorization"] = pwd;
data["pubKeyId"] = pubKeyId; data["pubKeyId"] = pubKeyId;
data["tags"] = tags;
return data; return data;
} }
bool shouldReconnect(ServerPrivateInfo old) {
return id != id || pwd != old.pwd || pubKeyId != old.pubKeyId;
}
} }

View File

@@ -23,13 +23,14 @@ class ServerPrivateInfoAdapter extends TypeAdapter<ServerPrivateInfo> {
user: fields[3] as String, user: fields[3] as String,
pwd: fields[4] as String, pwd: fields[4] as String,
pubKeyId: fields[5] as String?, pubKeyId: fields[5] as String?,
tags: (fields[6] as List?)?.cast<String>(),
); );
} }
@override @override
void write(BinaryWriter writer, ServerPrivateInfo obj) { void write(BinaryWriter writer, ServerPrivateInfo obj) {
writer writer
..writeByte(6) ..writeByte(7)
..writeByte(0) ..writeByte(0)
..write(obj.name) ..write(obj.name)
..writeByte(1) ..writeByte(1)
@@ -41,7 +42,9 @@ class ServerPrivateInfoAdapter extends TypeAdapter<ServerPrivateInfo> {
..writeByte(4) ..writeByte(4)
..write(obj.pwd) ..write(obj.pwd)
..writeByte(5) ..writeByte(5)
..write(obj.pubKeyId); ..write(obj.pubKeyId)
..writeByte(6)
..write(obj.tags);
} }
@override @override

View File

@@ -8,20 +8,16 @@ class Snippet {
late String name; late String name;
@HiveField(1) @HiveField(1)
late String script; late String script;
@HiveField(2) Snippet(this.name, this.script);
List<String>? tags;
Snippet(this.name, this.script, {this.tags});
Snippet.fromJson(Map<String, dynamic> json) { Snippet.fromJson(Map<String, dynamic> json) {
name = json['name'].toString(); name = json['name'].toString();
script = json['script'].toString(); script = json['script'].toString();
tags = json['tags'].cast<String>();
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final data = <String, dynamic>{}; final data = <String, dynamic>{};
data['name'] = name; data['name'] = name;
data['script'] = script; data['script'] = script;
data['tags'] = tags;
return data; return data;
} }
} }

View File

@@ -19,20 +19,17 @@ class SnippetAdapter extends TypeAdapter<Snippet> {
return Snippet( return Snippet(
fields[0] as String, fields[0] as String,
fields[1] as String, fields[1] as String,
tags: (fields[2] as List?)?.cast<String>(),
); );
} }
@override @override
void write(BinaryWriter writer, Snippet obj) { void write(BinaryWriter writer, Snippet obj) {
writer writer
..writeByte(3) ..writeByte(2)
..writeByte(0) ..writeByte(0)
..write(obj.name) ..write(obj.name)
..writeByte(1) ..writeByte(1)
..write(obj.script) ..write(obj.script);
..writeByte(2)
..write(obj.tags);
} }
@override @override

View File

@@ -23,7 +23,10 @@ typedef ServersMap = Map<String, Server>;
class ServerProvider extends BusyProvider { class ServerProvider extends BusyProvider {
final ServersMap _servers = {}; final ServersMap _servers = {};
ServersMap get servers => _servers; ServersMap get servers => _servers;
final StringOrder serverOrder = []; final StringOrder _serverOrder = [];
StringOrder get serverOrder => _serverOrder;
final List<String> _tags = [];
List<String> get tags => _tags;
final _limiter = TryLimiter(); final _limiter = TryLimiter();
@@ -42,23 +45,38 @@ class ServerProvider extends BusyProvider {
} }
final serverOrder_ = _settingStore.serverOrder.fetch(); final serverOrder_ = _settingStore.serverOrder.fetch();
if (serverOrder_ != null) { if (serverOrder_ != null) {
serverOrder.addAll(serverOrder_.toSet()); _serverOrder.addAll(serverOrder_.toSet());
if (serverOrder.length != infos.length) { if (_serverOrder.length != infos.length) {
final missed = infos final missed = infos
.where( .where(
(e) => !serverOrder.contains(e.id), (e) => !_serverOrder.contains(e.id),
) )
.map((e) => e.id); .map((e) => e.id);
serverOrder.addAll(missed); _serverOrder.addAll(missed);
} }
} else { } else {
serverOrder.addAll(_servers.keys); _serverOrder.addAll(_servers.keys);
} }
_settingStore.serverOrder.put(serverOrder); _settingStore.serverOrder.put(_serverOrder);
_updateTags();
setBusyState(false); setBusyState(false);
notifyListeners(); notifyListeners();
} }
void _updateTags() {
_tags.clear();
for (final s in _servers.values) {
if (s.spi.tags == null) continue;
for (final t in s.spi.tags!) {
if (!_tags.contains(t)) {
_tags.add(t);
}
}
}
_tags.sort();
notifyListeners();
}
Server genServer(ServerPrivateInfo spi) { Server genServer(ServerPrivateInfo spi) {
return Server(spi, initStatus, null, ServerState.disconnected); return Server(spi, initStatus, null, ServerState.disconnected);
} }
@@ -81,8 +99,7 @@ class ServerProvider extends BusyProvider {
} }
Future<void> startAutoRefresh() async { Future<void> startAutoRefresh() async {
final duration = final duration = _settingStore.serverStatusUpdateInterval.fetch()!;
locator<SettingStore>().serverStatusUpdateInterval.fetch()!;
if (duration == 0) return; if (duration == 0) return;
stopAutoRefresh(); stopAutoRefresh();
_timer = Timer.periodic(Duration(seconds: duration), (_) async { _timer = Timer.periodic(Duration(seconds: duration), (_) async {
@@ -126,15 +143,17 @@ class ServerProvider extends BusyProvider {
_servers[spi.id] = genServer(spi); _servers[spi.id] = genServer(spi);
notifyListeners(); notifyListeners();
_serverStore.put(spi); _serverStore.put(spi);
serverOrder.add(spi.id); _serverOrder.add(spi.id);
_settingStore.serverOrder.put(serverOrder); _settingStore.serverOrder.put(_serverOrder);
_updateTags();
refreshData(spi: spi); refreshData(spi: spi);
} }
void delServer(String id) { void delServer(String id) {
_servers.remove(id); _servers.remove(id);
serverOrder.remove(id); _serverOrder.remove(id);
_settingStore.serverOrder.put(serverOrder); _settingStore.serverOrder.put(_serverOrder);
_updateTags();
notifyListeners(); notifyListeners();
_serverStore.delete(id); _serverStore.delete(id);
} }
@@ -143,13 +162,27 @@ class ServerProvider extends BusyProvider {
ServerPrivateInfo old, ServerPrivateInfo old,
ServerPrivateInfo newSpi, ServerPrivateInfo newSpi,
) async { ) async {
_servers.remove(old.id); if (old != newSpi) {
_serverStore.update(old, newSpi); _serverStore.update(old, newSpi);
_servers[newSpi.id] = genServer(newSpi); _servers[old.id]?.spi = newSpi;
if (newSpi.id != old.id) {
_servers[newSpi.id] = _servers[old.id]!;
_servers[newSpi.id]?.spi = newSpi;
_servers.remove(old.id);
_serverOrder.update(old.id, newSpi.id);
_settingStore.serverOrder.put(_serverOrder);
}
// Only reconnect if neccessary
if (newSpi.shouldReconnect(old)) {
_servers[newSpi.id]?.client = await genClient(newSpi); _servers[newSpi.id]?.client = await genClient(newSpi);
serverOrder.update(old.id, newSpi.id); refreshData(spi: newSpi);
_settingStore.serverOrder.put(serverOrder); }
await refreshData(spi: newSpi);
// Only update if [spi.tags] changed
_updateTags();
}
} }
Future<void> _getData(ServerPrivateInfo spi) async { Future<void> _getData(ServerPrivateInfo spi) async {

View File

@@ -2,9 +2,10 @@
"@@locale": "de", "@@locale": "de",
"about": "Über", "about": "Über",
"aboutThanks": "Vielen Dank an die folgenden Personen, die daran teilgenommen haben.\n", "aboutThanks": "Vielen Dank an die folgenden Personen, die daran teilgenommen haben.\n",
"add": "Neu",
"addAServer": "Server hinzufügen", "addAServer": "Server hinzufügen",
"addOne": "Hinzufügen",
"addPrivateKey": "Private key hinzufügen", "addPrivateKey": "Private key hinzufügen",
"all": "Alle",
"alreadyLastDir": "Bereits im letzten Verzeichnis.", "alreadyLastDir": "Bereits im letzten Verzeichnis.",
"appPrimaryColor": "Farbschema", "appPrimaryColor": "Farbschema",
"attention": "Achtung", "attention": "Achtung",

View File

@@ -2,9 +2,10 @@
"@@locale": "en", "@@locale": "en",
"about": "About", "about": "About",
"aboutThanks": "Thanks to the following people who participated in.", "aboutThanks": "Thanks to the following people who participated in.",
"add": "Add",
"addAServer": "add a server", "addAServer": "add a server",
"addOne": "Add one",
"addPrivateKey": "Add private key", "addPrivateKey": "Add private key",
"all": "All",
"alreadyLastDir": "Already in last directory.", "alreadyLastDir": "Already in last directory.",
"appPrimaryColor": "App primary color", "appPrimaryColor": "App primary color",
"attention": "Attention", "attention": "Attention",

View File

@@ -2,9 +2,10 @@
"@@locale": "zh", "@@locale": "zh",
"about": "关于", "about": "关于",
"aboutThanks": "感谢以下参与的各位。", "aboutThanks": "感谢以下参与的各位。",
"add": "新增",
"addAServer": "添加服务器", "addAServer": "添加服务器",
"addOne": "前去新增",
"addPrivateKey": "添加一个私钥", "addPrivateKey": "添加一个私钥",
"all": "所有",
"alreadyLastDir": "已经是最上层目录了", "alreadyLastDir": "已经是最上层目录了",
"appPrimaryColor": "App主要色", "appPrimaryColor": "App主要色",
"attention": "注意", "attention": "注意",

View File

@@ -2,9 +2,10 @@
"@@locale": "zh_TW", "@@locale": "zh_TW",
"about": "關於", "about": "關於",
"aboutThanks": "感謝以下參與的各位。", "aboutThanks": "感謝以下參與的各位。",
"add": "新增",
"addAServer": "新增服務器", "addAServer": "新增服務器",
"addOne": "前去新增",
"addPrivateKey": "新增一個私鑰", "addPrivateKey": "新增一個私鑰",
"all": "所有",
"alreadyLastDir": "已經是最上層目錄了", "alreadyLastDir": "已經是最上層目錄了",
"appPrimaryColor": "主要色調", "appPrimaryColor": "主要色調",
"attention": "注意", "attention": "注意",

View File

@@ -69,7 +69,6 @@ class _ConvertPageState extends State<ConvertPage>
} }
}, },
tooltip: _s.convert, tooltip: _s.convert,
heroTag: 'convert fab',
child: const Icon(Icons.send), child: const Icon(Icons.send),
), ),
); );

View File

@@ -76,7 +76,6 @@ class _PingPageState extends State<PingPage>
), ),
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
heroTag: 'ping fab',
onPressed: () { onPressed: () {
try { try {
doPing(); doPing();

View File

@@ -14,6 +14,7 @@ import '../../../data/provider/server.dart';
import '../../../data/res/ui.dart'; import '../../../data/res/ui.dart';
import '../../../data/store/private_key.dart'; import '../../../data/store/private_key.dart';
import '../../../locator.dart'; import '../../../locator.dart';
import '../../widget/tag.dart';
import '../private_key/edit.dart'; import '../private_key/edit.dart';
class ServerEditPage extends StatefulWidget { class ServerEditPage extends StatefulWidget {
@@ -43,6 +44,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
bool usePublicKey = false; bool usePublicKey = false;
int? _pubKeyIndex; int? _pubKeyIndex;
PrivateKeyInfo? _keyInfo; PrivateKeyInfo? _keyInfo;
List<String> _tags = [];
@override @override
void initState() { void initState() {
@@ -143,6 +145,13 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
icon: Icons.account_box, icon: Icons.account_box,
hint: 'root', hint: 'root',
), ),
TagEditor(
tags: _tags,
onChanged: (p0) => setState(() {
_tags = p0;
}),
s: _s,
),
width7, width7,
Row( Row(
children: [ children: [
@@ -262,6 +271,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
user: _usernameController.text, user: _usernameController.text,
pwd: authorization, pwd: authorization,
pubKeyId: usePublicKey ? _keyInfo!.id : null, pubKeyId: usePublicKey ? _keyInfo!.id : null,
tags: _tags,
); );
if (widget.spi == null) { if (widget.spi == null) {
@@ -300,6 +310,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
} else { } else {
usePublicKey = true; usePublicKey = true;
} }
if (widget.spi?.tags != null) {
_tags = widget.spi!.tags!;
}
setState(() {}); setState(() {});
} }
} }

View File

@@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/core/extension/navigator.dart';
import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/extension/order.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
import 'package:toolbox/view/widget/fade_in.dart';
import '../../../core/route.dart'; import '../../../core/route.dart';
import '../../../core/utils/ui.dart'; import '../../../core/utils/ui.dart';
@@ -45,6 +46,8 @@ class _ServerPageState extends State<ServerPage>
late SettingStore _settingStore; late SettingStore _settingStore;
late S _s; late S _s;
String? _tag;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -71,18 +74,65 @@ class _ServerPageState extends State<ServerPage>
'Add server info page', 'Add server info page',
).go(context), ).go(context),
tooltip: _s.addAServer, tooltip: _s.addAServer,
heroTag: 'server page fab',
child: const Icon(Icons.add), child: const Icon(Icons.add),
), ),
); );
} }
Widget _buildTagsSwitcher(ServerProvider pro) {
if (pro.tags.isEmpty) return placeholder;
final items = <String?>[null, ...pro.tags];
return Container(
height: 37,
width: _media.size.width,
alignment: Alignment.center,
color: Colors.transparent,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => _buildTagItem(items[index]),
itemCount: items.length,
),
);
}
Widget _buildTagItem(String? tag) {
return Padding(
padding: const EdgeInsets.only(left: 4, right: 5, bottom: 9),
child: GestureDetector(
onTap: () {
setState(() {
_tag = tag;
});
},
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(20.0)),
color: primaryColor.withAlpha(20),
),
padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 2.7),
child: Center(
child: Text(
tag == null ? _s.all : '#$tag',
style: TextStyle(
color: _tag == tag ? null : _theme.disabledColor,
fontSize: 15,
fontWeight: FontWeight.w500,
),
),
)),
),
);
}
Widget _buildBody() { Widget _buildBody() {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async => onRefresh: () async =>
await _serverProvider.refreshData(onlyFailed: true), await _serverProvider.refreshData(onlyFailed: true),
child: Consumer<ServerProvider>( child: Consumer<ServerProvider>(
builder: (_, pro, __) { builder: (_, pro, __) {
if (!pro.tags.contains(_tag)) {
_tag = null;
}
if (pro.serverOrder.isEmpty) { if (pro.serverOrder.isEmpty) {
return Center( return Center(
child: Text( child: Text(
@@ -91,21 +141,29 @@ class _ServerPageState extends State<ServerPage>
), ),
); );
} }
return ReorderableListView( final filtered = pro.serverOrder
.where((e) => pro.servers.containsKey(e))
.where((e) =>
_tag == null ||
(pro.servers[e]?.spi.tags?.contains(_tag) ?? false))
.toList();
return FadeIn(
key: ValueKey(_tag),
child: ReorderableListView(
header: _buildTagsSwitcher(pro),
padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), padding: const EdgeInsets.fromLTRB(7, 10, 7, 7),
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
onReorder: (oldIndex, newIndex) => setState(() { onReorder: (oldIndex, newIndex) => setState(() {
pro.serverOrder.move( pro.serverOrder.moveById(
oldIndex, filtered[oldIndex],
newIndex, filtered[newIndex],
_settingStore.serverOrder, _settingStore.serverOrder,
); );
}), }),
children: pro.serverOrder children: filtered
.where((e) => pro.servers.containsKey(e))
.map((e) => _buildEachServerCard(pro.servers[e])) .map((e) => _buildEachServerCard(pro.servers[e]))
.toList(), .toList(),
); ));
}, },
), ),
); );

View File

@@ -217,7 +217,7 @@ class _SFTPPageState extends State<SFTPPage> {
_onItemPress(context, file, true); _onItemPress(context, file, true);
} }
}, },
onLongPress: () => _onItemPress(context, file, false), onLongPress: () => _onItemPress(context, file, !isDir),
); );
}, },
), ),

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/core/extension/navigator.dart';
import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/input_field.dart';
import 'package:toolbox/view/widget/tag.dart';
import '../../../core/utils/ui.dart'; import '../../../core/utils/ui.dart';
import '../../../data/model/server/snippet.dart'; import '../../../data/model/server/snippet.dart';
@@ -29,8 +28,6 @@ class _SnippetEditPageState extends State<SnippetEditPage>
late SnippetProvider _provider; late SnippetProvider _provider;
late S _s; late S _s;
var _tags = <String>[];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -76,7 +73,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
showSnackBar(context, Text(_s.fieldMustNotEmpty)); showSnackBar(context, Text(_s.fieldMustNotEmpty));
return; return;
} }
final snippet = Snippet(name, script, tags: _tags); final snippet = Snippet(name, script);
if (widget.snippet != null) { if (widget.snippet != null) {
_provider.update(widget.snippet!, snippet); _provider.update(widget.snippet!, snippet);
} else { } else {
@@ -107,13 +104,6 @@ class _SnippetEditPageState extends State<SnippetEditPage>
label: _s.snippet, label: _s.snippet,
icon: Icons.code, icon: Icons.code,
), ),
TagEditor(
tags: widget.snippet?.tags ?? [],
onChanged: (p0) => setState(() {
_tags = p0;
}),
s: _s.tag,
)
], ],
); );
} }
@@ -123,7 +113,6 @@ class _SnippetEditPageState extends State<SnippetEditPage>
if (widget.snippet != null) { if (widget.snippet != null) {
_nameController.text = widget.snippet!.name; _nameController.text = widget.snippet!.name;
_scriptController.text = widget.snippet!.script; _scriptController.text = widget.snippet!.script;
_tags = widget.snippet!.tags ?? [];
} }
} }
} }

View File

@@ -1,5 +0,0 @@
// import 'package:flutter/material.dart';
// class SnippetGroupOrderPage extends StatelessWidget {
// final
// }

View File

@@ -1,16 +1,22 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/input_field.dart';
import 'package:toolbox/view/widget/round_rect_card.dart'; import 'package:toolbox/view/widget/round_rect_card.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../../core/utils/ui.dart';
import '../../data/res/color.dart'; import '../../data/res/color.dart';
class TagEditor extends StatelessWidget { class TagEditor extends StatelessWidget {
final List<String> tags; final List<String> tags;
final String s; final S s;
final void Function(List<String>)? onChanged; final void Function(List<String>)? onChanged;
const TagEditor( const TagEditor({
{super.key, required this.tags, this.onChanged, required this.s}); super.key,
required this.tags,
this.onChanged,
required this.s,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -38,7 +44,7 @@ class TagEditor extends StatelessWidget {
List<String> tags, List<String> tags,
Function(String) onTagDelete, Function(String) onTagDelete,
) { ) {
if (tags.isEmpty) return Text(s); if (tags.isEmpty) return Text(s.tag);
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: Row(
@@ -88,14 +94,12 @@ class TagEditor extends StatelessWidget {
void Function(List<String>)? onChanged, void Function(List<String>)? onChanged,
) { ) {
final textEditingController = TextEditingController(); final textEditingController = TextEditingController();
showDialog( showRoundDialog(
context: context, context: context,
builder: (context) { title: Text(s.add),
return AlertDialog( child: Input(
title: const Text('Add Tag'),
content: Input(
controller: textEditingController, controller: textEditingController,
hint: 'Tag', hint: s.tag,
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -105,11 +109,9 @@ class TagEditor extends StatelessWidget {
onChanged?.call(tags); onChanged?.call(tags);
Navigator.pop(context); Navigator.pop(context);
}, },
child: const Text('Add'), child: Text(s.add),
), ),
], ],
); );
},
);
} }
} }