From e2a2e8a914118d5c458c31c041a908602d17815f Mon Sep 17 00:00:00 2001 From: zarzet Date: Tue, 14 Jul 2026 17:53:58 +0700 Subject: [PATCH] refactor(library): drop dead pre-pagination filter pipeline in queue tab The DB-backed pagination migration left the old in-widget filter/unification pipeline behind three unused_element ignores; every helper, cache field, and isolate entry point below them was reachable only from that dead root. --- lib/screens/queue_tab.dart | 701 ------------------ lib/screens/queue_tab_helpers.dart | 219 ------ lib/screens/queue_tab_navigation.dart | 36 - .../downloaded_embedded_cover_resolver.dart | 17 - 4 files changed, 973 deletions(-) diff --git a/lib/screens/queue_tab.dart b/lib/screens/queue_tab.dart index a746c96f..06134df7 100644 --- a/lib/screens/queue_tab.dart +++ b/lib/screens/queue_tab.dart @@ -41,7 +41,6 @@ import 'package:spotiflac_android/services/cover_cache_manager.dart'; import 'package:spotiflac_android/screens/library_tracks_folder_screen.dart'; import 'package:spotiflac_android/screens/local_album_screen.dart'; import 'package:spotiflac_android/utils/clickable_metadata.dart'; -import 'package:spotiflac_android/utils/path_match_keys.dart'; import 'package:spotiflac_android/utils/string_utils.dart'; import 'package:spotiflac_android/widgets/download_service_picker.dart'; import 'package:spotiflac_android/widgets/animation_utils.dart'; @@ -139,7 +138,6 @@ class _QueueTabState extends ConsumerState { static const int _libraryPageSize = 300; final _FileExistsListenableCache _fileExistsCache = _FileExistsListenableCache(); - static const int _maxSearchIndexCacheSize = 4000; static const double _libraryGridMinExtent = 92; static const double _libraryGridDefaultExtent = 126; static const double _libraryGridMaxExtent = 190; @@ -186,46 +184,9 @@ class _QueueTabState extends ConsumerState { final FocusNode _searchFocusNode = FocusNode(); String _searchQuery = ''; Timer? _searchDebounce; - List? _historyItemsCache; - List? _localLibraryItemsCache; - _HistoryStats? _historyStatsCache; final Map _completionBridge = {}; final Map _completionBridgeAt = {}; final Set _bridgePrecacheStarted = {}; - final Map _searchIndexCache = {}; - final Map _localSearchIndexCache = {}; - Map> _filteredHistoryCache = const {}; - List? _filterItemsCache; - String _filterQueryCache = ''; - bool _filterRefreshScheduled = false; - bool _isFilteringHistory = false; - int _filterRequestId = 0; - static const int _filterIsolateThreshold = 800; - List? _localFilterItemsCache; - String _localFilterQueryCache = ''; - List _filteredLocalItemsCache = const []; - final Map _unifiedItemsCache = {}; - List? _cachedUnifiedDownloadedSource; - List _cachedUnifiedDownloaded = const []; - List? _cachedUnifiedLocalSource; - List _cachedUnifiedLocal = const []; - List? _cachedDownloadedPathKeysSource; - Set _cachedDownloadedPathKeys = const {}; - final Map> _localPathMatchKeysCache = {}; - List? _cachedLocalSinglesSource; - Map? _cachedLocalSinglesAlbumCountsSource; - List _cachedLocalSingles = const []; - final Map _filterContentDataCache = {}; - List? _filterCacheAllHistoryItems; - _HistoryStats? _filterCacheHistoryStats; - List? _filterCacheLocalLibraryItems; - LibraryCollectionsState? _filterCacheCollectionState; - String _filterCacheSearchQuery = ''; - String? _filterCacheSource; - String? _filterCacheQuality; - String? _filterCacheFormat; - String? _filterCacheMetadata; - String _filterCacheSortMode = 'latest'; String? _filterSource; String? _filterQuality; String? _filterFormat; @@ -318,7 +279,6 @@ class _QueueTabState extends ConsumerState { _searchQuery = normalized; _resetLibraryPaging(); }); - _requestFilterRefresh(); }); } @@ -329,7 +289,6 @@ class _QueueTabState extends ConsumerState { _searchQuery = ''; _resetLibraryPaging(); }); - _requestFilterRefresh(); } int _libraryPageOffsetFor(String filterMode) => @@ -419,8 +378,6 @@ class _QueueTabState extends ConsumerState { void _invalidateLibraryDataCaches() { _queueLibraryCountsCache.clear(); _queueLibraryPageDataCache.clear(); - _unifiedItemsCache.clear(); - _invalidateFilterContentCache(); } void _scheduleBlankLibraryRepair({ @@ -514,379 +471,6 @@ class _QueueTabState extends ConsumerState { return false; } - void _invalidateFilterContentCache() { - _filterContentDataCache.clear(); - _filterCacheAllHistoryItems = null; - _filterCacheHistoryStats = null; - _filterCacheLocalLibraryItems = null; - _filterCacheCollectionState = null; - } - - // ignore: unused_element - void _prepareFilterContentCache({ - required List allHistoryItems, - required _HistoryStats historyStats, - required List localLibraryItems, - required LibraryCollectionsState collectionState, - }) { - final isCacheValid = - identical(_filterCacheAllHistoryItems, allHistoryItems) && - identical(_filterCacheHistoryStats, historyStats) && - identical(_filterCacheLocalLibraryItems, localLibraryItems) && - identical(_filterCacheCollectionState, collectionState) && - _filterCacheSearchQuery == _searchQuery && - _filterCacheSource == _filterSource && - _filterCacheQuality == _filterQuality && - _filterCacheFormat == _filterFormat && - _filterCacheMetadata == _filterMetadata && - _filterCacheSortMode == _sortMode; - - if (isCacheValid) { - return; - } - - _filterContentDataCache.clear(); - _filterCacheAllHistoryItems = allHistoryItems; - _filterCacheHistoryStats = historyStats; - _filterCacheLocalLibraryItems = localLibraryItems; - _filterCacheCollectionState = collectionState; - _filterCacheSearchQuery = _searchQuery; - _filterCacheSource = _filterSource; - _filterCacheQuality = _filterQuality; - _filterCacheFormat = _filterFormat; - _filterCacheMetadata = _filterMetadata; - _filterCacheSortMode = _sortMode; - } - - // ignore: unused_element - void _ensureHistoryCaches( - List items, - List localItems, - _HistoryStats historyStats, - ) { - final historyChanged = !identical(items, _historyItemsCache); - final localChanged = !identical(localItems, _localLibraryItemsCache); - - if (!historyChanged && !localChanged) return; - - _historyItemsCache = items; - _localLibraryItemsCache = localItems; - _historyStatsCache = historyStats; - if (historyChanged) { - _searchIndexCache.clear(); - _cachedUnifiedDownloadedSource = null; - _cachedUnifiedDownloaded = const []; - _cachedDownloadedPathKeysSource = null; - _cachedDownloadedPathKeys = const {}; - } - if (localChanged) { - _localSearchIndexCache.clear(); - _localPathMatchKeysCache.clear(); - _localFilterItemsCache = null; - _localFilterQueryCache = ''; - _filteredLocalItemsCache = const []; - _cachedLocalSinglesSource = null; - _cachedLocalSinglesAlbumCountsSource = null; - _cachedLocalSingles = const []; - _cachedUnifiedLocalSource = null; - _cachedUnifiedLocal = const []; - } - _unifiedItemsCache.clear(); - _invalidateFilterContentCache(); - - if (historyChanged) { - final validPaths = items - .map((item) => _cleanFilePath(item.filePath)) - .where((path) => path.isNotEmpty) - .toSet(); - DownloadedEmbeddedCoverResolver.invalidatePathsNotIn(validPaths); - } - _requestFilterRefresh(); - } - - String _buildSearchKey(DownloadHistoryItem item) { - return '${item.trackName} ${item.artistName} ${item.albumName}' - .toLowerCase(); - } - - String _buildLocalSearchKey(LocalLibraryItem item) { - return '${item.trackName} ${item.artistName} ${item.albumName}' - .toLowerCase(); - } - - String _historySearchKeyForItem(DownloadHistoryItem item) { - final cached = _searchIndexCache[item.id]; - if (cached != null) return cached; - - final searchKey = _buildSearchKey(item); - _searchIndexCache[item.id] = searchKey; - while (_searchIndexCache.length > _maxSearchIndexCacheSize) { - _searchIndexCache.remove(_searchIndexCache.keys.first); - } - return searchKey; - } - - String _localSearchKeyForItem(LocalLibraryItem item) { - final cached = _localSearchIndexCache[item.id]; - if (cached != null) return cached; - - final searchKey = _buildLocalSearchKey(item); - _localSearchIndexCache[item.id] = searchKey; - while (_localSearchIndexCache.length > _maxSearchIndexCacheSize) { - _localSearchIndexCache.remove(_localSearchIndexCache.keys.first); - } - return searchKey; - } - - List _unifiedDownloadedItems( - List items, - ) { - if (identical(items, _cachedUnifiedDownloadedSource)) { - return _cachedUnifiedDownloaded; - } - final unified = items - .map(UnifiedLibraryItem.fromDownloadHistory) - .toList(growable: false); - _cachedUnifiedDownloadedSource = items; - _cachedUnifiedDownloaded = unified; - return unified; - } - - List _unifiedLocalItems(List items) { - if (identical(items, _cachedUnifiedLocalSource)) { - return _cachedUnifiedLocal; - } - final unified = items - .map(UnifiedLibraryItem.fromLocalLibrary) - .toList(growable: false); - _cachedUnifiedLocalSource = items; - _cachedUnifiedLocal = unified; - return unified; - } - - Set _downloadedPathKeys(List historyItems) { - if (identical(historyItems, _cachedDownloadedPathKeysSource)) { - return _cachedDownloadedPathKeys; - } - final keys = {}; - for (final item in historyItems) { - keys.addAll(buildPathMatchKeys(item.filePath)); - } - _cachedDownloadedPathKeysSource = historyItems; - _cachedDownloadedPathKeys = Set.unmodifiable(keys); - return _cachedDownloadedPathKeys; - } - - List _localPathMatchKeys(LocalLibraryItem item) { - final cached = _localPathMatchKeysCache[item.id]; - if (cached != null) return cached; - final keys = buildPathMatchKeys(item.filePath).toList(growable: false); - _localPathMatchKeysCache[item.id] = keys; - return keys; - } - - List _localSingleItems( - List items, - Map localAlbumCounts, - ) { - if (identical(items, _cachedLocalSinglesSource) && - identical(localAlbumCounts, _cachedLocalSinglesAlbumCountsSource)) { - return _cachedLocalSingles; - } - - final singles = items - .where((item) => (localAlbumCounts[item.albumKey] ?? 0) == 1) - .toList(growable: false); - _cachedLocalSinglesSource = items; - _cachedLocalSinglesAlbumCountsSource = localAlbumCounts; - _cachedLocalSingles = singles; - return singles; - } - - List _filterLocalItems( - List items, - String query, - ) { - if (query.isEmpty) return items; - if (identical(items, _localFilterItemsCache) && - query == _localFilterQueryCache) { - return _filteredLocalItemsCache; - } - - final filtered = items - .where((item) { - final searchKey = _localSearchKeyForItem(item); - return searchKey.contains(query); - }) - .toList(growable: false); - - _localFilterItemsCache = items; - _localFilterQueryCache = query; - _filteredLocalItemsCache = filtered; - return filtered; - } - - bool _isFilterCacheValid(List items, String query) { - return identical(items, _filterItemsCache) && query == _filterQueryCache; - } - - void _requestFilterRefresh() { - if (_filterRefreshScheduled) return; - _filterRefreshScheduled = true; - WidgetsBinding.instance.addPostFrameCallback((_) { - _filterRefreshScheduled = false; - if (!mounted) return; - _scheduleHistoryFilterUpdate(); - }); - } - - void _scheduleHistoryFilterUpdate() { - final items = _historyItemsCache; - if (items == null) return; - final query = _searchQuery; - if (_isFilterCacheValid(items, query)) return; - - final albumCounts = - _historyStatsCache?.albumCounts ?? const {}; - if (items.isEmpty) { - setState(() { - _filteredHistoryCache = const {}; - _filterItemsCache = items; - _filterQueryCache = query; - _isFilteringHistory = false; - }); - return; - } - - if (items.length <= _filterIsolateThreshold) { - final filteredAll = _applyHistorySearchFilter(items, query); - final filteredAlbums = _filterHistoryByAlbumCount( - filteredAll, - albumCounts, - 2, - ); - final filteredSingles = _filterHistoryByAlbumCount( - filteredAll, - albumCounts, - 1, - ); - setState(() { - _filteredHistoryCache = { - 'all': filteredAll, - 'albums': filteredAlbums, - 'singles': filteredSingles, - }; - _filterItemsCache = items; - _filterQueryCache = query; - _isFilteringHistory = false; - }); - return; - } - - if (!_isFilteringHistory) { - setState(() => _isFilteringHistory = true); - } - - final requestId = ++_filterRequestId; - final includeSearchKey = query.isNotEmpty; - final entries = List>.generate(items.length, (index) { - final item = items[index]; - final albumKey = - '${item.albumName.toLowerCase()}|${(item.albumArtist ?? item.artistName).toLowerCase()}'; - if (!includeSearchKey) { - return [item.id, albumKey]; - } - final searchKey = _historySearchKeyForItem(item); - return [item.id, albumKey, searchKey]; - }, growable: false); - final payload = { - 'entries': entries, - 'albumCounts': albumCounts, - 'query': query, - }; - - compute(_filterHistoryInIsolate, payload).then((result) { - if (!mounted || requestId != _filterRequestId) return; - final itemsById = {for (final item in items) item.id: item}; - final filtered = >{}; - for (final entry in result.entries) { - filtered[entry.key] = entry.value - .map((id) => itemsById[id]) - .whereType() - .toList(growable: false); - } - setState(() { - _filteredHistoryCache = filtered; - _filterItemsCache = items; - _filterQueryCache = query; - _isFilteringHistory = false; - }); - }); - } - - List _resolveHistoryItems({ - required String filterMode, - required List allHistoryItems, - required Map albumCounts, - }) { - final query = _searchQuery; - if (_isFilterCacheValid(allHistoryItems, query)) { - final cached = _filteredHistoryCache[filterMode]; - if (cached != null) return cached; - } - if (allHistoryItems.isEmpty) return const []; - if (query.isEmpty && filterMode == 'all') return allHistoryItems; - if (allHistoryItems.length <= _filterIsolateThreshold) { - return _filterHistoryItems( - allHistoryItems, - filterMode, - albumCounts, - query, - ); - } - return const []; - } - - List _applyHistorySearchFilter( - List items, - String searchQuery, - ) { - if (searchQuery.isEmpty) return items; - final query = searchQuery; - return items - .where((item) { - final searchKey = _historySearchKeyForItem(item); - return searchKey.contains(query); - }) - .toList(growable: false); - } - - List _filterHistoryByAlbumCount( - List items, - Map albumCounts, - int targetCount, - ) { - return items - .where((item) { - final key = - '${item.albumName.toLowerCase()}|${(item.albumArtist ?? item.artistName).toLowerCase()}'; - final count = albumCounts[key] ?? 0; - return targetCount == 1 ? count == 1 : count >= targetCount; - }) - .toList(growable: false); - } - - bool _shouldShowFilteringIndicator({ - required List allHistoryItems, - required String filterMode, - }) { - if (allHistoryItems.isEmpty) return false; - if (_searchQuery.isEmpty && filterMode == 'all') return false; - if (allHistoryItems.length <= _filterIsolateThreshold) return false; - return !_isFilterCacheValid(allHistoryItems, _searchQuery) || - _isFilteringHistory; - } - void _onFilterPageChanged(int index) { HapticFeedback.selectionClick(); final filterMode = _filterModes[index]; @@ -959,8 +543,6 @@ class _QueueTabState extends ConsumerState { _filterMetadata = null; _sortMode = 'latest'; _resetLibraryPaging(); - _unifiedItemsCache.clear(); - _invalidateFilterContentCache(); }); } @@ -984,173 +566,6 @@ class _QueueTabState extends ConsumerState { return _fileExtLower(item.filePath); } - List _applyAdvancedFilters( - List items, - ) { - List filtered; - if (_activeFilterCount == 0) { - filtered = items; - } else { - filtered = items - .where((item) { - if (_filterSource != null) { - if (_filterSource == 'downloaded' && - item.source != LibraryItemSource.downloaded) { - return false; - } - if (_filterSource == 'local' && - item.source != LibraryItemSource.local) { - return false; - } - } - - if (_filterQuality != null && item.quality != null) { - final quality = item.quality!.toLowerCase(); - switch (_filterQuality) { - case 'hires': - if (!quality.startsWith('24')) return false; - case 'cd': - if (!quality.startsWith('16')) return false; - case 'lossy': - if (quality.startsWith('24') || quality.startsWith('16')) { - return false; - } - } - } else if (_filterQuality != null && item.quality == null) { - if (_filterQuality != 'lossy') return false; - } - - if (_filterFormat != null) { - final ext = _itemFormatLower(item); - if (ext != _filterFormat) return false; - } - - if (!_queueUnifiedItemMatchesMetadataFilter( - item, - _filterMetadata, - )) { - return false; - } - - return true; - }) - .toList(growable: false); - } - - return _applySorting(filtered); - } - - List _applySorting(List items) { - if (_sortMode == 'latest') { - return items; - } - final sorted = List.of(items); - switch (_sortMode) { - case 'oldest': - sorted.sort((a, b) => a.addedAt.compareTo(b.addedAt)); - case 'a-z': - sorted.sort( - (a, b) => - a.trackName.toLowerCase().compareTo(b.trackName.toLowerCase()), - ); - case 'z-a': - sorted.sort( - (a, b) => - b.trackName.toLowerCase().compareTo(a.trackName.toLowerCase()), - ); - case 'artist-asc': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalText( - a.artistName, - b.artistName, - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'artist-desc': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalText( - a.artistName, - b.artistName, - descending: true, - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'album-asc': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalText( - a.albumName, - b.albumName, - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'album-desc': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalText( - a.albumName, - b.albumName, - descending: true, - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'release-oldest': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalDate( - _queueParseReleaseDate(a.releaseDate), - _queueParseReleaseDate(b.releaseDate), - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'release-newest': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalDate( - _queueParseReleaseDate(a.releaseDate), - _queueParseReleaseDate(b.releaseDate), - descending: true, - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'genre-asc': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalText(a.genre, b.genre); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - case 'genre-desc': - sorted.sort((a, b) { - final comparison = _queueCompareOptionalText( - a.genre, - b.genre, - descending: true, - ); - if (comparison != 0) { - return comparison; - } - return _queueCompareOptionalText(a.trackName, b.trackName); - }); - } - return sorted; - } - Set _getAvailableFormats(List items) { final formats = {}; for (final item in items) { @@ -1597,8 +1012,6 @@ class _QueueTabState extends ConsumerState { _filterMetadata = tempMetadata; _sortMode = tempSortMode; _resetLibraryPaging(); - _unifiedItemsCache.clear(); - _invalidateFilterContentCache(); }); Navigator.pop(context); }, @@ -1998,120 +1411,6 @@ class _QueueTabState extends ConsumerState { ); } - List _getUnifiedItems({ - required String filterMode, - required List historyItems, - required List localLibraryItems, - required Map localAlbumCounts, - }) { - if (filterMode == 'albums') return const []; - - final query = _searchQuery; - final cached = _unifiedItemsCache[filterMode]; - if (cached != null && - identical(cached.historyItems, historyItems) && - identical(cached.localItems, localLibraryItems) && - identical(cached.localAlbumCounts, localAlbumCounts) && - cached.query == query) { - return cached.items; - } - - final unifiedDownloaded = _unifiedDownloadedItems(historyItems); - - List localItemsForMerge; - if (filterMode == 'all') { - localItemsForMerge = _filterLocalItems(localLibraryItems, query); - } else { - final localSingles = _localSingleItems( - localLibraryItems, - localAlbumCounts, - ); - localItemsForMerge = _filterLocalItems(localSingles, query); - } - - final unifiedLocal = _unifiedLocalItems(localItemsForMerge); - final downloadedPathKeys = _downloadedPathKeys(historyItems); - - final dedupedUnifiedLocal = []; - for (final item in unifiedLocal) { - final localSource = item.localItem; - final localPathKeys = localSource != null - ? _localPathMatchKeys(localSource) - : buildPathMatchKeys(item.filePath); - final overlapsDownloaded = localPathKeys.any(downloadedPathKeys.contains); - if (!overlapsDownloaded) { - dedupedUnifiedLocal.add(item); - } - } - - final merged = [ - ...unifiedDownloaded, - ...dedupedUnifiedLocal, - ]..sort((a, b) => b.addedAt.compareTo(a.addedAt)); - - _unifiedItemsCache[filterMode] = _UnifiedCacheEntry( - historyItems: historyItems, - localItems: localLibraryItems, - localAlbumCounts: localAlbumCounts, - query: query, - items: merged, - ); - - return merged; - } - - // ignore: unused_element - _FilterContentData _computeFilterContentData({ - required String filterMode, - required List allHistoryItems, - required List<_GroupedAlbum> filteredGroupedAlbums, - required List<_GroupedLocalAlbum> filteredGroupedLocalAlbums, - required Map albumCounts, - required Map localAlbumCounts, - required List localLibraryItems, - required LibraryCollectionsState collectionState, - }) { - final historyItems = _resolveHistoryItems( - filterMode: filterMode, - allHistoryItems: allHistoryItems, - albumCounts: albumCounts, - ); - final showFilteringIndicator = _shouldShowFilteringIndicator( - allHistoryItems: allHistoryItems, - filterMode: filterMode, - ); - - final unifiedItems = _getUnifiedItems( - filterMode: filterMode, - historyItems: historyItems, - localLibraryItems: localLibraryItems, - localAlbumCounts: localAlbumCounts, - ); - final filtered = _applyAdvancedFilters(unifiedItems); - - // Remove tracks that are already in any playlist so they don't appear - // in the main tracks list. When a track is removed from a playlist (or - // the playlist is deleted) it will automatically reappear here because it - // will no longer be in the set. - final filteredUnifiedItems = !collectionState.hasPlaylistTracks - ? filtered - : filtered - .where( - (item) => - !collectionState.isTrackInAnyPlaylist(item.collectionKey), - ) - .toList(growable: false); - - return _FilterContentData( - historyItems: historyItems, - unifiedItems: unifiedItems, - filteredUnifiedItems: filteredUnifiedItems, - filteredGroupedAlbums: filteredGroupedAlbums, - filteredGroupedLocalAlbums: filteredGroupedLocalAlbums, - showFilteringIndicator: showFilteringIndicator, - ); - } - Widget _buildQueueHeaderSliver( BuildContext context, ColorScheme colorScheme, diff --git a/lib/screens/queue_tab_helpers.dart b/lib/screens/queue_tab_helpers.dart index ab20e86f..b67c92fb 100644 --- a/lib/screens/queue_tab_helpers.dart +++ b/lib/screens/queue_tab_helpers.dart @@ -50,20 +50,6 @@ class _GroupedLocalAlbum { int get displayTrackCount => trackCount ?? tracks.length; } -class _HistoryStats { - final Map albumCounts; - final List<_GroupedAlbum> groupedAlbums; - final int albumCount; - final int singleTracks; - - const _HistoryStats({ - required this.albumCounts, - required this.groupedAlbums, - required this.albumCount, - required this.singleTracks, - }); -} - class _FilterContentData { final List historyItems; final List unifiedItems; @@ -366,22 +352,6 @@ final _queueLibraryCountsProvider = return LibraryDatabase.instance.getQueueCounts(request.toDbQuery()); }); -class _UnifiedCacheEntry { - final List historyItems; - final List localItems; - final Map localAlbumCounts; - final String query; - final List items; - - const _UnifiedCacheEntry({ - required this.historyItems, - required this.localItems, - required this.localAlbumCounts, - required this.query, - required this.items, - }); -} - class _QueueItemIdsSnapshot { final List ids; @@ -489,192 +459,3 @@ class _FileExistsListenableCache { _alwaysMissingNotifier.dispose(); } } - -bool _queueHasMetadataValue(String? value) { - return value != null && value.trim().isNotEmpty; -} - -String _queueNormalizedMetadataValue(String? value) { - return value?.trim().toLowerCase() ?? ''; -} - -DateTime? _queueParseReleaseDate(String? value) { - final trimmed = value?.trim() ?? ''; - if (trimmed.isEmpty) { - return null; - } - - final parsed = DateTime.tryParse(trimmed); - if (parsed != null) { - return parsed; - } - - final yearMatch = RegExp(r'(\d{4})').firstMatch(trimmed); - if (yearMatch == null) { - return null; - } - - final year = int.tryParse(yearMatch.group(1)!); - if (year == null || year <= 0) { - return null; - } - return DateTime(year); -} - -bool _queueMatchesMetadataFilter({ - required String? filterMetadata, - required String? artistName, - required String? albumArtist, - required String? releaseDate, - required String? genre, - required int? trackNumber, - required int? discNumber, - required String? isrc, - required String? label, -}) { - if (filterMetadata == null) { - return true; - } - - final hasArtist = _queueHasMetadataValue(artistName); - final hasAlbumArtist = _queueHasMetadataValue(albumArtist); - final hasReleaseDate = _queueParseReleaseDate(releaseDate) != null; - final hasGenre = _queueHasMetadataValue(genre); - final hasTrackNumber = trackNumber != null && trackNumber > 0; - final hasDiscNumber = discNumber != null && discNumber > 0; - final hasLabel = _queueHasMetadataValue(label); - final hasIncorrectIsrc = _queueHasIncorrectIsrcFormat(isrc); - final isComplete = - hasArtist && - hasAlbumArtist && - hasReleaseDate && - hasGenre && - hasTrackNumber && - hasDiscNumber && - hasLabel && - !hasIncorrectIsrc; - - switch (filterMetadata) { - case 'complete': - return isComplete; - case 'missing-any': - return !isComplete; - case 'missing-year': - return !hasReleaseDate; - case 'missing-genre': - return !hasGenre; - case 'missing-album-artist': - return !hasAlbumArtist; - case 'missing-track-number': - return !hasTrackNumber; - case 'missing-disc-number': - return !hasDiscNumber; - case 'missing-artist': - return !hasArtist; - case 'incorrect-isrc-format': - return hasIncorrectIsrc; - case 'missing-label': - return !hasLabel; - default: - return true; - } -} - -bool _queueHasIncorrectIsrcFormat(String? isrc) { - final raw = isrc?.trim() ?? ''; - if (raw.isEmpty) return false; - final normalized = raw.toUpperCase().replaceAll(RegExp(r'[-\s]'), ''); - return !RegExp(r'^[A-Z]{2}[A-Z0-9]{3}\d{7}$').hasMatch(normalized); -} - -bool _queueUnifiedItemMatchesMetadataFilter( - UnifiedLibraryItem item, - String? filterMetadata, -) { - return _queueMatchesMetadataFilter( - filterMetadata: filterMetadata, - artistName: item.artistName, - albumArtist: item.albumArtist, - releaseDate: item.releaseDate, - genre: item.genre, - trackNumber: item.trackNumber, - discNumber: item.discNumber, - isrc: item.isrc, - label: item.label, - ); -} - -int _queueCompareOptionalText( - String? left, - String? right, { - bool descending = false, -}) { - final normalizedLeft = _queueNormalizedMetadataValue(left); - final normalizedRight = _queueNormalizedMetadataValue(right); - final leftEmpty = normalizedLeft.isEmpty; - final rightEmpty = normalizedRight.isEmpty; - - if (leftEmpty && rightEmpty) { - return 0; - } - if (leftEmpty) { - return 1; - } - if (rightEmpty) { - return -1; - } - - final comparison = normalizedLeft.compareTo(normalizedRight); - return descending ? -comparison : comparison; -} - -int _queueCompareOptionalDate( - DateTime? left, - DateTime? right, { - bool descending = false, -}) { - if (left == null && right == null) { - return 0; - } - if (left == null) { - return 1; - } - if (right == null) { - return -1; - } - - final comparison = left.compareTo(right); - return descending ? -comparison : comparison; -} - -Map> _filterHistoryInIsolate(Map payload) { - final entries = (payload['entries'] as List).cast>(); - final albumCounts = Map.from(payload['albumCounts'] as Map); - final query = (payload['query'] as String?) ?? ''; - final hasQuery = query.isNotEmpty; - - final allIds = []; - final albumIds = []; - final singleIds = []; - - for (final entry in entries) { - final id = entry[0] as String; - final albumKey = entry[1] as String; - if (hasQuery) { - final searchKey = entry[2] as String; - if (!searchKey.contains(query)) { - continue; - } - } - - allIds.add(id); - final count = albumCounts[albumKey] ?? 0; - if (count > 1) { - albumIds.add(id); - } else if (count == 1) { - singleIds.add(id); - } - } - - return {'all': allIds, 'albums': albumIds, 'singles': singleIds}; -} diff --git a/lib/screens/queue_tab_navigation.dart b/lib/screens/queue_tab_navigation.dart index dcd56c65..fe2df733 100644 --- a/lib/screens/queue_tab_navigation.dart +++ b/lib/screens/queue_tab_navigation.dart @@ -207,41 +207,6 @@ extension _QueueTabNavigation on _QueueTabState { ).then((_) => _searchFocusNode.unfocus()); } - List _filterHistoryItems( - List items, - String filterMode, - Map albumCounts, [ - String searchQuery = '', - ]) { - var filteredItems = items; - if (searchQuery.isNotEmpty) { - final query = searchQuery; - filteredItems = items.where((item) { - final searchKey = _historySearchKeyForItem(item); - return searchKey.contains(query); - }).toList(); - } - - if (filterMode == 'all') return filteredItems; - - switch (filterMode) { - case 'albums': - return filteredItems.where((item) { - final key = - '${item.albumName.toLowerCase()}|${(item.albumArtist ?? item.artistName).toLowerCase()}'; - return (albumCounts[key] ?? 0) > 1; - }).toList(); - case 'singles': - return filteredItems.where((item) { - final key = - '${item.albumName.toLowerCase()}|${(item.albumArtist ?? item.artistName).toLowerCase()}'; - return (albumCounts[key] ?? 0) == 1; - }).toList(); - default: - return filteredItems; - } - } - void _navigateWithUnfocus(Route route) { _searchFocusNode.unfocus(); Navigator.of(context).push(route).then((_) => _searchFocusNode.unfocus()); @@ -560,5 +525,4 @@ extension _QueueTabNavigation on _QueueTabState { ), ); } - } diff --git a/lib/services/downloaded_embedded_cover_resolver.dart b/lib/services/downloaded_embedded_cover_resolver.dart index 5a598149..9efb5b66 100644 --- a/lib/services/downloaded_embedded_cover_resolver.dart +++ b/lib/services/downloaded_embedded_cover_resolver.dart @@ -112,23 +112,6 @@ class DownloadedEmbeddedCoverResolver { } } - static void invalidatePathsNotIn(Set validCleanPaths) { - if (validCleanPaths.isEmpty) { - final keys = _cache.keys.toList(growable: false); - for (final key in keys) { - invalidate(key); - } - return; - } - - final staleKeys = _cache.keys - .where((path) => !validCleanPaths.contains(path)) - .toList(growable: false); - for (final key in staleKeys) { - invalidate(key); - } - } - static void _touch(String cleanPath, _EmbeddedCoverCacheEntry entry) { _cache ..remove(cleanPath)