feat: colored tag categories division like e621/gelbooru/rule34 and fix search for tags with parentheses
Build and Release / Build Windows x64 (push) Has been cancelled
Build and Release / Build Windows x64 (push) Has been cancelled
This commit is contained in:
@@ -567,7 +567,7 @@ class _TagInputSearchBarState extends State<TagInputSearchBar> {
|
||||
final draft = _controller.text.trim().toLowerCase();
|
||||
if (draft.isEmpty) return '';
|
||||
final raw = draft.split(RegExp(r'\s+')).last;
|
||||
return raw.replaceAll(RegExp(r'^[\(\)]+|[\(\)]+$'), '').trim();
|
||||
return raw.trim();
|
||||
}
|
||||
|
||||
bool get _isEditing => _focusNode.hasFocus || _localDirty;
|
||||
|
||||
@@ -1,36 +1,142 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../backend/models/tag_suggestion.dart';
|
||||
|
||||
class TagChip extends StatelessWidget {
|
||||
const TagChip({
|
||||
required this.tag,
|
||||
this.category,
|
||||
this.group,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String tag;
|
||||
final TagCategory? category;
|
||||
final String? group;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onLongPress;
|
||||
|
||||
TagCategory get _resolvedCategory {
|
||||
if (category != null) return category!;
|
||||
final g = (group ?? '').toLowerCase();
|
||||
return switch (g) {
|
||||
'artist' => TagCategory.artist,
|
||||
'character' => TagCategory.character,
|
||||
'copyright' => TagCategory.copyright,
|
||||
'species' => TagCategory.species,
|
||||
'meta' => TagCategory.meta,
|
||||
'general' => TagCategory.general,
|
||||
_ => tagCategoryFromString(g),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final chip = ActionChip(
|
||||
onPressed: onTap,
|
||||
label: Text(tag),
|
||||
labelStyle: TextStyle(
|
||||
color: scheme.onSecondaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final cat = _resolvedCategory;
|
||||
|
||||
final (Color baseColor, Color textColor) = _colorsForCategory(cat, scheme, isDark);
|
||||
|
||||
final chipWidget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: baseColor.withValues(alpha: isDark ? 0.18 : 0.12),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: baseColor.withValues(alpha: isDark ? 0.45 : 0.32),
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 6,
|
||||
height: 6,
|
||||
margin: const EdgeInsets.only(right: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: baseColor,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: baseColor.withValues(alpha: 0.6),
|
||||
blurRadius: 4,
|
||||
spreadRadius: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 13,
|
||||
letterSpacing: -0.1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: scheme.secondaryContainer.withValues(alpha: 0.62),
|
||||
side: BorderSide(color: scheme.outlineVariant.withValues(alpha: 0.65)),
|
||||
visualDensity: VisualDensity.compact,
|
||||
);
|
||||
if (onLongPress == null) return chip;
|
||||
|
||||
if (onLongPress == null) return chipWidget;
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onLongPress: onLongPress,
|
||||
child: chip,
|
||||
child: chipWidget,
|
||||
);
|
||||
}
|
||||
|
||||
static (Color, Color) _colorsForCategory(
|
||||
TagCategory cat,
|
||||
ColorScheme scheme,
|
||||
bool isDark,
|
||||
) {
|
||||
return switch (cat) {
|
||||
TagCategory.artist => (
|
||||
const Color(0xFFFF4757), // e621 / Gelbooru red/coral
|
||||
isDark ? const Color(0xFFFF6B81) : const Color(0xFFD63031),
|
||||
),
|
||||
TagCategory.character => (
|
||||
const Color(0xFF2ED573), // Vibrant character green
|
||||
isDark ? const Color(0xFF7BED9F) : const Color(0xFF10AC84),
|
||||
),
|
||||
TagCategory.copyright => (
|
||||
const Color(0xFFA55EEA), // Classic anime series purple
|
||||
isDark ? const Color(0xFFD980FA) : const Color(0xFF8854D0),
|
||||
),
|
||||
TagCategory.species => (
|
||||
const Color(0xFFFFA502), // e621 species amber/orange
|
||||
isDark ? const Color(0xFFFFC048) : const Color(0xFFE67E22),
|
||||
),
|
||||
TagCategory.meta => (
|
||||
const Color(0xFF1E90FF), // Meta / format cyan / ice blue
|
||||
isDark ? const Color(0xFF70A1FF) : const Color(0xFF0984E3),
|
||||
),
|
||||
TagCategory.general || TagCategory.unknown => (
|
||||
isDark ? scheme.primary : scheme.primary,
|
||||
isDark ? scheme.onSurface : scheme.onSurface,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user