fix: offline download — wait for completion, suppress transient errors

createPack() resolves when the pack is registered, not when tiles are
done downloading. Wrapping in a Promise that resolves only on
status.state === 'complete' keeps the progress modal visible and the
'Download complete' alert fires only when the pack is actually ready.

Transient tile errors ('stream was reset: CANCEL') are silently ignored
in the error listener — MapLibre retries them internally and they do not
indicate a failed download. The onError callback is removed from the
public API since it was causing spurious alerts mid-download.
This commit is contained in:
Davide Scaini
2026-06-04 01:06:39 +02:00
parent ccfc60934a
commit 86397e0980
2 changed files with 30 additions and 19 deletions
-1
View File
@@ -110,7 +110,6 @@ export function RecordingScreen() {
dlName.trim(),
expanded,
(pct, _tiles, sizeBytes) => { setDlProgress(pct); setDlSize(sizeBytes); },
(msg) => Alert.alert('Download error', msg),
);
setDlVisible(false);
setDlProgress(null);
+30 -18
View File
@@ -22,31 +22,43 @@ export interface OfflineRegion {
// ── Download ──────────────────────────────────────────────────────────────────
export async function downloadRegion(
/**
* Download a region and return a Promise that resolves only when the pack
* reaches state 'complete'. Transient tile-fetch errors (e.g. "stream was
* reset: CANCEL") are silently ignored — MapLibre retries them internally
* and they do not indicate a failed download.
*/
export function downloadRegion(
name: string,
bounds: LngLatBounds,
onProgress: (pct: number, tilesDown: number, sizeBytes: number) => void,
onError: (msg: string) => void,
): Promise<string> {
OfflineManager.setProgressEventThrottle(500);
const pack = await OfflineManager.createPack(
{
mapStyle: OFFLINE_STYLE_URL,
bounds,
minZoom: MIN_ZOOM,
maxZoom: MAX_ZOOM,
metadata: { name, createdAt: new Date().toISOString() },
},
(_pack, status: OfflinePackStatus) => {
onProgress(status.percentage, status.completedTileCount, status.completedTileSize);
},
(_pack, error) => {
onError(error.message);
},
);
return new Promise((resolve, reject) => {
let packId: string;
return pack.id;
OfflineManager.createPack(
{
mapStyle: OFFLINE_STYLE_URL,
bounds,
minZoom: MIN_ZOOM,
maxZoom: MAX_ZOOM,
metadata: { name, createdAt: new Date().toISOString() },
},
(pack, status: OfflinePackStatus) => {
packId = pack.id;
onProgress(status.percentage, status.completedTileCount, status.completedTileSize);
if (status.state === 'complete') {
resolve(packId);
}
},
(_pack, _error) => {
// Transient tile-level errors — MapLibre retries these automatically.
// Do not reject: the overall download is still in progress.
},
).catch(reject); // only rejects on createPack failure (e.g. bad style URL)
});
}
// ── List ──────────────────────────────────────────────────────────────────────