feat(downloads): detect lost SAF grant and offer folder re-selection

A persisted SAF tree grant can die silently (folder deleted or renamed,
SD card removed, app data reset, system revocation). Downloads then fail
with no recovery path beyond digging through Settings.

- Add isSafTreeAccessible bridge method: the grant must still be in the
  system's persisted permission list and the tree writable
- Show a warning banner in Files & Folders when the saved SAF folder is
  no longer accessible, with an inline re-select action
- In the download error dialog, replace Retry with a Re-select folder
  action when the failure is a lost folder grant (Android SAF or iOS
  bookmark); a successful re-pick retries the item automatically
- Share the folder-access error messages as constants so the UI can
  match on them reliably
This commit is contained in:
zarzet
2026-07-10 10:12:16 +07:00
parent 53824b7ac2
commit 927fc8abac
22 changed files with 389 additions and 24 deletions
+12 -4
View File
@@ -30,6 +30,16 @@ export 'package:spotiflac_android/services/history_database.dart'
final _log = AppLogger('DownloadQueue');
final _historyLog = AppLogger('DownloadHistory');
/// Set on queued items when the persisted Android SAF grant fails validation.
/// The queue UI matches on this to offer re-selecting the download folder.
const String safPermissionLostErrorMessage =
'SAF permission invalid or revoked. Please reconfigure download location in Settings.';
/// Set on queued items when the iOS download folder bookmark can no longer be
/// opened. The queue UI matches on this to offer re-selecting the folder.
const String downloadFolderAccessLostErrorMessage =
'Download folder access lost. Please re-select your download folder in Settings.';
final _invalidFolderChars = RegExp(r'[<>:"/\\|?*]');
final _trimDotsAndSpacesRegex = RegExp(r'^[. ]+|[. ]+$');
final _trimUnderscoresAndSpacesRegex = RegExp(r'^[_ ]+|[_ ]+$');
@@ -7114,8 +7124,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
updateItemStatus(
item.id,
DownloadStatus.failed,
error:
'SAF permission invalid or revoked. Please reconfigure download location in Settings.',
error: safPermissionLostErrorMessage,
);
}
}
@@ -7146,8 +7155,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
updateItemStatus(
item.id,
DownloadStatus.failed,
error:
'Download folder access lost. Please re-select your download folder in Settings.',
error: downloadFolderAccessLostErrorMessage,
);
}
}