From 58be9f1d9da641758783cc1ba5d147ed0de3048d Mon Sep 17 00:00:00 2001 From: DelLevin-Home Date: Sat, 20 Jun 2026 16:47:06 +0800 Subject: [PATCH] 1 --- lib/pages/book/book_form_page.dart | 2 +- lib/pages/movies/movie_form_page.dart | 2 +- lib/pages/tag_management_page.dart | 41 +++++++++++++++++++++------ lib/providers/app_provider.dart | 9 ++++-- lib/utils/database_helper.dart | 7 ++++- lib/utils/tag/tag_dao.dart | 12 ++++++-- 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/lib/pages/book/book_form_page.dart b/lib/pages/book/book_form_page.dart index e06d0fb..9056037 100644 --- a/lib/pages/book/book_form_page.dart +++ b/lib/pages/book/book_form_page.dart @@ -263,7 +263,7 @@ class _BookFormPageState extends State { icon: Icons.category_outlined, onTap: () async { final provider = context.read(); - final tags = await provider.getTags('book_genre'); + final tags = await provider.getTags('book_genre', excludeHidden: true); final existingNames = tags.map((t) => t['name'] as String).toList(); if (mounted) { _showMultiValueDialog( diff --git a/lib/pages/movies/movie_form_page.dart b/lib/pages/movies/movie_form_page.dart index 6200936..403de5e 100644 --- a/lib/pages/movies/movie_form_page.dart +++ b/lib/pages/movies/movie_form_page.dart @@ -539,7 +539,7 @@ class _MovieFormPageState extends State { icon: Icons.category_outlined, onTap: () async { final provider = context.read(); - final tags = await provider.getTags('movie_genre'); + final tags = await provider.getTags('movie_genre', excludeHidden: true); final existingNames = tags.map((t) => t['name'] as String).toList(); if (mounted) { _showMultiValueDialog( diff --git a/lib/pages/tag_management_page.dart b/lib/pages/tag_management_page.dart index 27a5b55..35f44bd 100644 --- a/lib/pages/tag_management_page.dart +++ b/lib/pages/tag_management_page.dart @@ -267,20 +267,22 @@ class _TagManagementPageState extends State { final count = _usageCounts[name] ?? 0; final tagId = tag['id'] as String; final isNew = tagId == _newlyAddedTagId; + final isHidden = (tag['is_hidden'] as int?) == 1; return GestureDetector( key: ValueKey(tagId), onTap: () => _showTagMenu(tag), onLongPress: () => _showTagMenu(tag), - child: isNew - ? _NewTagHighlight( - child: _tagChipContent(name, count, colors), - ) - : _tagChipContent(name, count, colors), + child: Opacity( + opacity: isHidden ? 0.4 : 1.0, + child: isNew + ? _NewTagHighlight(child: _tagChipContent(name, count, colors, isHidden: isHidden)) + : _tagChipContent(name, count, colors, isHidden: isHidden), + ), ); } - Widget _tagChipContent(String name, int count, ColorScheme colors) { + Widget _tagChipContent(String name, int count, ColorScheme colors, {bool isHidden = false}) { return Container( padding: const EdgeInsets.only(left: 14, right: 10, top: 8, bottom: 8), decoration: BoxDecoration( @@ -293,7 +295,10 @@ class _TagManagementPageState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Text(name, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: colors.onSurface)), + Text(name, style: TextStyle( + fontSize: 14, fontWeight: FontWeight.w500, color: colors.onSurface, + decoration: isHidden ? TextDecoration.lineThrough : null, + )), if (count > 0) ...[ const SizedBox(width: 6), Container( @@ -341,6 +346,7 @@ class _TagManagementPageState extends State { void _showTagMenu(Map tag) { final colors = Theme.of(context).colorScheme; final name = tag['name'] as String; + final isHidden = (tag['is_hidden'] as int?) == 1; showModalBottomSheet( context: context, @@ -361,9 +367,28 @@ class _TagManagementPageState extends State { width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), decoration: BoxDecoration(color: colors.surfaceContainerHighest, borderRadius: BorderRadius.circular(12)), - child: Text(name, style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: colors.onSurface)), + child: Row( + children: [ + Expanded(child: Text(name, style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: colors.onSurface))), + if (isHidden) Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration(color: colors.outlineVariant, borderRadius: BorderRadius.circular(4)), + child: Text('已隐藏', style: TextStyle(fontSize: 11, color: colors.onSurface.withValues(alpha: 0.5))), + ), + ], + ), ), const SizedBox(height: 16), + _menuAction( + isHidden ? Icons.visibility_outlined : Icons.visibility_off_outlined, + isHidden ? '取消隐藏' : '隐藏', + colors, + () async { + Navigator.pop(ctx); + await context.read().toggleTagHidden(tag['id'] as String); + await _loadTags(_currentType); + }, + ), _menuAction(Icons.edit_outlined, '重命名', colors, () { Navigator.pop(ctx); _showRenameDialog(tag); diff --git a/lib/providers/app_provider.dart b/lib/providers/app_provider.dart index 40c1417..8261f76 100644 --- a/lib/providers/app_provider.dart +++ b/lib/providers/app_provider.dart @@ -653,11 +653,16 @@ class AppProvider extends ChangeNotifier { // ========== 标签管理方法 ========== - Future>> getTags(String type) async { + Future>> getTags(String type, {bool excludeHidden = false}) async { if (_useRemote) { return await ServerDataService.instance.getTags(type.isEmpty ? null : type); } - return await _tagDao.getTagsByType(type); + return await _tagDao.getTagsByType(type, excludeHidden: excludeHidden); + } + + Future toggleTagHidden(String tagId) async { + await _tagDao.toggleHidden(tagId); + notifyListeners(); } Future addTag(String name, String type) async { diff --git a/lib/utils/database_helper.dart b/lib/utils/database_helper.dart index 21adfd0..4280c1f 100644 --- a/lib/utils/database_helper.dart +++ b/lib/utils/database_helper.dart @@ -57,7 +57,7 @@ class DatabaseHelper { return await openDatabase( path, - version: 16, + version: 17, onCreate: _createDB, onUpgrade: _onUpgrade, ); @@ -140,6 +140,9 @@ class DatabaseHelper { await db.execute('ALTER TABLE books ADD COLUMN cover_offset REAL DEFAULT 0'); } } + if (oldVersion < 17) { + await db.execute('ALTER TABLE tags ADD COLUMN is_hidden INTEGER NOT NULL DEFAULT 0'); + } } /// 升级books表到V11(添加ISBN和出版时间字段) @@ -207,6 +210,7 @@ class DatabaseHelper { name TEXT NOT NULL, type TEXT NOT NULL, created_at TEXT NOT NULL, + is_hidden INTEGER NOT NULL DEFAULT 0, UNIQUE(name, type) ) '''); @@ -631,6 +635,7 @@ class DatabaseHelper { name TEXT NOT NULL, type TEXT NOT NULL, created_at TEXT NOT NULL, + is_hidden INTEGER NOT NULL DEFAULT 0, UNIQUE(name, type) ) '''); diff --git a/lib/utils/tag/tag_dao.dart b/lib/utils/tag/tag_dao.dart index 4209d8d..8435fff 100644 --- a/lib/utils/tag/tag_dao.dart +++ b/lib/utils/tag/tag_dao.dart @@ -16,10 +16,12 @@ class TagDao { } /// 获取指定类型的所有标签,按名称排序 - Future>> getTagsByType(String type) => _wrap('getTagsByType', () async { + /// [excludeHidden] 为 true 时,过滤掉隐藏标签 + Future>> getTagsByType(String type, {bool excludeHidden = false}) => _wrap('getTagsByType', () async { final db = await _dbHelper.database; + final where = excludeHidden ? 'type = ? AND is_hidden = 0' : 'type = ?'; return await db.query('tags', - where: 'type = ?', + where: where, whereArgs: [type], orderBy: 'name ASC'); }); @@ -122,6 +124,12 @@ class TagDao { await db.delete('tags', where: 'id = ?', whereArgs: [tagId]); }); + /// 切换标签的隐藏状态 + Future toggleHidden(String tagId) => _wrap('toggleHidden', () async { + final db = await _dbHelper.database; + await db.rawUpdate('UPDATE tags SET is_hidden = 1 - is_hidden WHERE id = ?', [tagId]); + }); + /// 确保标签存在(用于替换操作) Future _ensureTagExists(Transaction txn, String name, String type) async { final existing = await txn.query('tags',