mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-15 23:50:38 +02:00
fix: distinguish preparing from downloading in native worker progress
Prevent premature 'downloading' status before actual byte transfer starts, and cache async provider values to avoid UI flicker during queue library reloads. Progress pipeline: - StartItemProgress now initializes with 'preparing' status instead of 'downloading' - SetItemProgress ignores synthetic pre-download progress updates while status is still 'preparing' (no byte data yet) - DownloadService reads backend status field and propagates preparing/ downloading/finalizing to native worker item snapshot - Dart progress stream maps 'preparing' to DownloadStatus.downloading with progress 0.0 (indeterminate spinner) Queue tab: - Add _queueLibraryCountsCache and _queueLibraryPageDataCache to retain last successful data during FutureProvider refetches - Prevents empty-state flash when loadedIndexVersion bumps trigger provider invalidation - Caches trimmed to max 24 entries via FIFO eviction
This commit is contained in:
@@ -2099,7 +2099,8 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
final progressFromBackend =
|
||||
(itemProgress['progress'] as num?)?.toDouble() ?? 0.0;
|
||||
final hasRealProgress =
|
||||
bytesReceived > 0 || bytesTotal > 0 || progressFromBackend > 0;
|
||||
status != 'preparing' &&
|
||||
(bytesReceived > 0 || bytesTotal > 0 || progressFromBackend > 0);
|
||||
|
||||
if (status == 'finalizing') {
|
||||
progressUpdates[itemId] = const _ProgressUpdate(
|
||||
@@ -2112,7 +2113,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status == 'preparing' && !hasRealProgress) {
|
||||
if (status == 'preparing') {
|
||||
progressUpdates[itemId] = const _ProgressUpdate(
|
||||
status: DownloadStatus.downloading,
|
||||
progress: 0.0,
|
||||
@@ -2264,10 +2265,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
|
||||
final progressPercent =
|
||||
(selectedProgress['progress'] as num?)?.toDouble() ?? 0.0;
|
||||
final hasRealProgress =
|
||||
bytesReceived > 0 || bytesTotal > 0 || progressPercent > 0;
|
||||
|
||||
if (backendStatus == 'preparing' && !hasRealProgress) {
|
||||
if (backendStatus == 'preparing') {
|
||||
notifProgress = 0;
|
||||
notifTotal = 0;
|
||||
} else if (bytesTotal <= 0) {
|
||||
@@ -5400,6 +5398,11 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status == 'preparing') {
|
||||
updateItemStatus(itemId, DownloadStatus.downloading, progress: 0.0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status == 'downloading') {
|
||||
updateItemStatus(
|
||||
itemId,
|
||||
|
||||
+63
-15
@@ -150,6 +150,10 @@ class _QueueTabState extends ConsumerState<QueueTab> {
|
||||
double? _libraryGridScaleStartExtent;
|
||||
int _libraryPageLimit = _libraryPageSize;
|
||||
bool _libraryPageLoadScheduled = false;
|
||||
final Map<_QueueLibraryCountsRequest, QueueLibraryCounts>
|
||||
_queueLibraryCountsCache = {};
|
||||
final Map<_QueueLibraryPageRequest, _QueueLibraryPageData>
|
||||
_queueLibraryPageDataCache = {};
|
||||
|
||||
double _effectiveTextScale() {
|
||||
final textScale = MediaQuery.textScalerOf(context).scale(1.0);
|
||||
@@ -249,6 +253,55 @@ class _QueueTabState extends ConsumerState<QueueTab> {
|
||||
});
|
||||
}
|
||||
|
||||
QueueLibraryCounts _resolveQueueLibraryCounts(
|
||||
AsyncValue<QueueLibraryCounts> value,
|
||||
_QueueLibraryCountsRequest request,
|
||||
) {
|
||||
return value.maybeWhen(
|
||||
data: (counts) {
|
||||
_queueLibraryCountsCache[request] = counts;
|
||||
_trimQueueLibraryCaches();
|
||||
return counts;
|
||||
},
|
||||
orElse: () =>
|
||||
_queueLibraryCountsCache[request] ??
|
||||
const QueueLibraryCounts(
|
||||
allTrackCount: 0,
|
||||
albumCount: 0,
|
||||
singleTrackCount: 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_QueueLibraryPageData _resolveQueueLibraryPageData(
|
||||
AsyncValue<_QueueLibraryPageData>? value,
|
||||
_QueueLibraryPageRequest request,
|
||||
) {
|
||||
if (value == null) {
|
||||
return _queueLibraryPageDataCache[request] ??
|
||||
const _QueueLibraryPageData();
|
||||
}
|
||||
return value.maybeWhen(
|
||||
data: (data) {
|
||||
_queueLibraryPageDataCache[request] = data;
|
||||
_trimQueueLibraryCaches();
|
||||
return data;
|
||||
},
|
||||
orElse: () =>
|
||||
_queueLibraryPageDataCache[request] ?? const _QueueLibraryPageData(),
|
||||
);
|
||||
}
|
||||
|
||||
void _trimQueueLibraryCaches() {
|
||||
const maxEntries = 24;
|
||||
while (_queueLibraryCountsCache.length > maxEntries) {
|
||||
_queueLibraryCountsCache.remove(_queueLibraryCountsCache.keys.first);
|
||||
}
|
||||
while (_queueLibraryPageDataCache.length > maxEntries) {
|
||||
_queueLibraryPageDataCache.remove(_queueLibraryPageDataCache.keys.first);
|
||||
}
|
||||
}
|
||||
|
||||
bool _handleLibraryScrollNotification({
|
||||
required ScrollNotification notification,
|
||||
required String filterMode,
|
||||
@@ -2455,14 +2508,7 @@ class _QueueTabState extends ConsumerState<QueueTab> {
|
||||
localLibraryEnabled: localLibraryEnabled,
|
||||
);
|
||||
final countsValue = ref.watch(_queueLibraryCountsProvider(countsRequest));
|
||||
final queueCounts = countsValue.maybeWhen(
|
||||
data: (counts) => counts,
|
||||
orElse: () => const QueueLibraryCounts(
|
||||
allTrackCount: 0,
|
||||
albumCount: 0,
|
||||
singleTrackCount: 0,
|
||||
),
|
||||
);
|
||||
final queueCounts = _resolveQueueLibraryCounts(countsValue, countsRequest);
|
||||
|
||||
_QueueLibraryPageRequest pageRequest(String filterMode) =>
|
||||
_QueueLibraryPageRequest(
|
||||
@@ -2477,17 +2523,19 @@ class _QueueTabState extends ConsumerState<QueueTab> {
|
||||
localLibraryEnabled: localLibraryEnabled,
|
||||
);
|
||||
|
||||
final pageRequests = <String, _QueueLibraryPageRequest>{
|
||||
for (final mode in _filterModes) mode: pageRequest(mode),
|
||||
};
|
||||
final pageValues = <String, AsyncValue<_QueueLibraryPageData>>{
|
||||
for (final mode in _filterModes)
|
||||
mode: ref.watch(_queueLibraryPageProvider(pageRequest(mode))),
|
||||
for (final entry in pageRequests.entries)
|
||||
entry.key: ref.watch(_queueLibraryPageProvider(entry.value)),
|
||||
};
|
||||
|
||||
_QueueLibraryPageData pageData(String filterMode) =>
|
||||
pageValues[filterMode]?.maybeWhen(
|
||||
data: (data) => data,
|
||||
orElse: () => const _QueueLibraryPageData(),
|
||||
) ??
|
||||
const _QueueLibraryPageData();
|
||||
_resolveQueueLibraryPageData(
|
||||
pageValues[filterMode],
|
||||
pageRequests[filterMode]!,
|
||||
);
|
||||
|
||||
_FilterContentData getFilterData(String filterMode) {
|
||||
return pageData(filterMode).toFilterContentData(
|
||||
|
||||
Reference in New Issue
Block a user