This commit is contained in:
lollipopkit
2023-08-20 23:30:44 +08:00
parent e643378249
commit 8111a83703
9 changed files with 182 additions and 183 deletions

View File

@@ -99,7 +99,6 @@ class _ServerDetailPageState extends State<ServerDetailPage>
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 13, left: 13,
right: 13, right: 13,
top: 13,
bottom: _media.padding.bottom + 77, bottom: _media.padding.bottom + 77,
), ),
itemCount: buildFuncs ? _cardsOrder.length + 1 : _cardsOrder.length, itemCount: buildFuncs ? _cardsOrder.length + 1 : _cardsOrder.length,

View File

@@ -16,7 +16,7 @@ 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/custom_appbar.dart'; import '../../widget/custom_appbar.dart';
import '../../widget/tag/editor.dart'; import '../../widget/tag/btn.dart';
import '../private_key/edit.dart'; import '../private_key/edit.dart';
class ServerEditPage extends StatefulWidget { class ServerEditPage extends StatefulWidget {

View File

@@ -127,7 +127,7 @@ class _ServerPageState extends State<ServerPage>
Widget _buildBodySmall({ Widget _buildBodySmall({
required ServerProvider provider, required ServerProvider provider,
required List<String> filtered, required List<String> filtered,
EdgeInsets? padding = const EdgeInsets.fromLTRB(7, 10, 7, 7), EdgeInsets? padding = const EdgeInsets.fromLTRB(7, 0, 7, 7),
bool buildTags = true, bool buildTags = true,
}) { }) {
final count = buildTags ? filtered.length + 2 : filtered.length + 1; final count = buildTags ? filtered.length + 2 : filtered.length + 1;
@@ -164,7 +164,7 @@ class _ServerPageState extends State<ServerPage>
child: _buildBodySmall( child: _buildBodySmall(
provider: pro, provider: pro,
filtered: left, filtered: left,
padding: const EdgeInsets.fromLTRB(7, 10, 0, 7), padding: const EdgeInsets.fromLTRB(7, 0, 0, 7),
buildTags: false, buildTags: false,
), ),
), ),
@@ -172,7 +172,7 @@ class _ServerPageState extends State<ServerPage>
child: _buildBodySmall( child: _buildBodySmall(
provider: pro, provider: pro,
filtered: right, filtered: right,
padding: const EdgeInsets.fromLTRB(0, 10, 7, 7), padding: const EdgeInsets.fromLTRB(0, 0, 7, 7),
buildTags: false, buildTags: false,
), ),
), ),

View File

@@ -10,7 +10,7 @@ import '../../../data/provider/snippet.dart';
import '../../../data/res/ui.dart'; import '../../../data/res/ui.dart';
import '../../../locator.dart'; import '../../../locator.dart';
import '../../widget/custom_appbar.dart'; import '../../widget/custom_appbar.dart';
import '../../widget/tag/editor.dart'; import '../../widget/tag/btn.dart';
class SnippetEditPage extends StatefulWidget { class SnippetEditPage extends StatefulWidget {
const SnippetEditPage({Key? key, this.snippet}) : super(key: key); const SnippetEditPage({Key? key, this.snippet}) : super(key: key);

View File

@@ -1,5 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/navigator.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 '../../../core/utils/ui.dart';
import '../../../data/res/color.dart'; import '../../../data/res/color.dart';
class TagBtn extends StatelessWidget { class TagBtn extends StatelessWidget {
@@ -16,28 +22,174 @@ class TagBtn extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return _wrap(
padding: const EdgeInsets.only(left: 4, right: 5, bottom: 9), Text(
child: ClipRRect( content,
borderRadius: const BorderRadius.all(Radius.circular(20.0)), textAlign: TextAlign.center,
child: Material( style: TextStyle(
color: primaryColor.withAlpha(20), color: isEnable ? null : Colors.grey,
child: InkWell( fontSize: 13,
onTap: onTap,
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 11, vertical: 2.7),
child: Text(
content,
style: TextStyle(
color: isEnable ? null : Colors.grey,
fontSize: 13,
),
),
),
),
), ),
), ),
onTap: onTap,
); );
} }
} }
class TagEditor extends StatelessWidget {
final List<String> tags;
final S s;
final void Function(List<String>)? onChanged;
final void Function(String old, String new_)? onRenameTag;
final List<String>? tagSuggestions;
const TagEditor({
super.key,
required this.tags,
required this.s,
this.onChanged,
this.onRenameTag,
this.tagSuggestions,
});
@override
Widget build(BuildContext context) {
return RoundRectCard(ListTile(
leading: const Icon(Icons.tag),
title: _buildTags(context, tags),
trailing: InkWell(
child: const Icon(Icons.add),
onTap: () {
_showTagDialog(context, tags, onChanged);
},
),
));
}
Widget _buildTags(BuildContext context, List<String> tags) {
tagSuggestions?.removeWhere((element) => tags.contains(element));
final suggestionLen = tagSuggestions?.length ?? 0;
final counts = tags.length + suggestionLen + (suggestionLen == 0 ? 0 : 1);
if (counts == 0) return Text(s.tag);
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 27),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
if (index < tags.length) {
return _buildTagItem(context, tags[index], false);
} else if (index > tags.length) {
return _buildTagItem(
context,
tagSuggestions![index - tags.length - 1],
true,
);
}
return const VerticalDivider();
},
itemCount: counts,
),
);
}
Widget _buildTagItem(BuildContext context, String tag, bool isAdd) {
return _wrap(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'#$tag',
textAlign: TextAlign.center,
style: textSize13,
),
const SizedBox(width: 4.0),
Icon(
isAdd ? Icons.add_circle : Icons.cancel,
size: 13.7,
),
],
),
onTap: () {
if (isAdd) {
tags.add(tag);
} else {
tags.remove(tag);
}
onChanged?.call(tags);
},
onLongPress: () => _showRenameDialog(context, tag),
);
}
void _showTagDialog(
BuildContext context,
List<String> tags,
void Function(List<String>)? onChanged,
) {
final textEditingController = TextEditingController();
showRoundDialog(
context: context,
title: Text(s.add),
child: Input(
controller: textEditingController,
hint: s.tag,
),
actions: [
TextButton(
onPressed: () {
final tag = textEditingController.text;
tags.add(tag.trim());
onChanged?.call(tags);
Navigator.pop(context);
},
child: Text(s.add),
),
],
);
}
void _showRenameDialog(BuildContext context, String tag) {
final textEditingController = TextEditingController(text: tag);
showRoundDialog(
context: context,
title: Text(s.rename),
child: Input(
controller: textEditingController,
hint: s.tag,
),
actions: [
TextButton(
onPressed: () {
final newTag = textEditingController.text.trim();
if (newTag.isEmpty) return;
onRenameTag?.call(tag, newTag);
context.pop();
},
child: Text(s.rename),
),
],
);
}
}
Widget _wrap(Widget child, {void Function()? onTap,
void Function()? onLongPress,}) {
return Padding(
padding: const EdgeInsets.all(3),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(20.0)),
child: Material(
color: primaryColor.withAlpha(20),
child: InkWell(
onTap: onTap,
onLongPress: onLongPress,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 9.7, vertical: 1.7),
child: child,
),
),
),
),
);
}

View File

@@ -1,154 +0,0 @@
import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/navigator.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 '../../../core/utils/ui.dart';
import '../../../data/res/color.dart';
class TagEditor extends StatelessWidget {
final List<String> tags;
final S s;
final void Function(List<String>)? onChanged;
final void Function(String old, String new_)? onRenameTag;
final List<String>? tagSuggestions;
const TagEditor({
super.key,
required this.tags,
required this.s,
this.onChanged,
this.onRenameTag,
this.tagSuggestions,
});
@override
Widget build(BuildContext context) {
return RoundRectCard(ListTile(
leading: const Icon(Icons.tag),
title: _buildTags(context, tags),
trailing: InkWell(
child: const Icon(Icons.add),
onTap: () {
_showTagDialog(context, tags, onChanged);
},
),
));
}
Widget _buildTags(BuildContext context, List<String> tags) {
tagSuggestions?.removeWhere((element) => tags.contains(element));
final suggestionLen = tagSuggestions?.length ?? 0;
final counts = tags.length + suggestionLen + (suggestionLen == 0 ? 0 : 1);
if (counts == 0) return Text(s.tag);
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 27),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
if (index < tags.length) {
return _buildTagItem(context, tags[index], false);
} else if (index > tags.length) {
return _buildTagItem(
context,
tagSuggestions![index - tags.length - 1],
true,
);
}
return const VerticalDivider();
},
itemCount: counts,
),
);
}
Widget _buildTagItem(BuildContext context, String tag, bool isAdd) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: InkWell(
onTap: () {
if (isAdd) {
tags.add(tag);
} else {
tags.remove(tag);
}
onChanged?.call(tags);
},
onLongPress: () => _showRenameDialog(context, tag),
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(20.0)),
color: primaryColor,
),
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'#$tag',
style: const TextStyle(color: Colors.white),
),
const SizedBox(width: 4.0),
Icon(
isAdd ? Icons.add_circle : Icons.cancel,
size: 14.0,
color: Colors.white,
),
],
),
),
),
);
}
void _showTagDialog(
BuildContext context,
List<String> tags,
void Function(List<String>)? onChanged,
) {
final textEditingController = TextEditingController();
showRoundDialog(
context: context,
title: Text(s.add),
child: Input(
controller: textEditingController,
hint: s.tag,
),
actions: [
TextButton(
onPressed: () {
final tag = textEditingController.text;
tags.add(tag.trim());
onChanged?.call(tags);
Navigator.pop(context);
},
child: Text(s.add),
),
],
);
}
void _showRenameDialog(BuildContext context, String tag) {
final textEditingController = TextEditingController(text: tag);
showRoundDialog(
context: context,
title: Text(s.rename),
child: Input(
controller: textEditingController,
hint: s.tag,
),
actions: [
TextButton(
onPressed: () {
final newTag = textEditingController.text.trim();
if (newTag.isEmpty) return;
onRenameTag?.call(tag, newTag);
context.pop();
},
child: Text(s.rename),
),
],
);
}
}

View File

@@ -2,7 +2,8 @@ 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/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/tag/btn.dart';
import 'btn.dart';
class TagPicker<T> extends StatefulWidget { class TagPicker<T> extends StatefulWidget {
final List<T> items; final List<T> items;

View File

@@ -23,7 +23,7 @@ class TagSwitcher extends StatelessWidget {
if (tags.isEmpty) return placeholder; if (tags.isEmpty) return placeholder;
final items = <String?>[null, ...tags]; final items = <String?>[null, ...tags];
return Container( return Container(
height: 37, height: 31,
width: width, width: width,
alignment: Alignment.center, alignment: Alignment.center,
color: Colors.transparent, color: Colors.transparent,

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/view/widget/tag/btn.dart';
import 'btn.dart';
class TagView extends StatelessWidget { class TagView extends StatelessWidget {
final void Function(String?) onTap; final void Function(String?) onTap;