fix: robust first-launch auto-preload (mobile bible/download)
- OfflineManager.preload accepts bibleTranslations: 'all' and resolves translation ids internally from versions.json (single source), removing the fragile settings-side fetch that could throw and abort the whole download on mobile first launch - Decouple trigger from '#settings/autopreload' route param via one-shot requestAutoPreload()/consumeAutoPreload() flag - Auto-expand + tick Bible variant checkboxes for UI consistency - Offer modal sets the flag and navigates to plain '#settings'
This commit is contained in:
1 parent
142b95d226
commit
623c56a96f
3 files changed
+41
-13
No files matched your search
@@ -20,7 +20,7 @@ import { diagLog } from './diag-log';
|
|||||||
export interface PreloadOptions {
|
export interface PreloadOptions {
|
||||||
languages: string[];
|
languages: string[];
|
||||||
types: ('calendar' | 'bible')[];
|
types: ('calendar' | 'bible')[];
|
||||||
bibleTranslations?: string[];
|
bibleTranslations?: string[] | 'all';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PreloadProgress {
|
export interface PreloadProgress {
|
||||||
@@ -89,12 +89,36 @@ function getFallbackCalendarFiles(lang: string): string[] {
|
|||||||
|
|
||||||
export class OfflineManager {
|
export class OfflineManager {
|
||||||
private static _progress: PreloadProgress | null = null;
|
private static _progress: PreloadProgress | null = null;
|
||||||
|
private static _autoPreloadRequested = false;
|
||||||
|
|
||||||
|
/** Request an automatic "preload everything" once the Settings view opens. */
|
||||||
|
static requestAutoPreload() {
|
||||||
|
OfflineManager._autoPreloadRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Consume (one-shot) the automatic preload request. */
|
||||||
|
static consumeAutoPreload(): boolean {
|
||||||
|
const v = OfflineManager._autoPreloadRequested;
|
||||||
|
OfflineManager._autoPreloadRequested = false;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
/** Get size string for a Bible translation. */
|
/** Get size string for a Bible translation. */
|
||||||
static getBibleSize(translationPath: string): string {
|
static getBibleSize(translationPath: string): string {
|
||||||
return BIBLE_SIZES[translationPath] || '?';
|
return BIBLE_SIZES[translationPath] || '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolve every Bible translation id from versions.json (single source). */
|
||||||
|
static async getAllBibleTranslationIds(): Promise<string[]> {
|
||||||
|
try {
|
||||||
|
const resp = await fetch('/data/bible/versions.json');
|
||||||
|
const versions = await resp.json() as any[];
|
||||||
|
return versions.map((v: any) => v.id);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Discover all book files for a Bible translation from versions.json. */
|
/** Discover all book files for a Bible translation from versions.json. */
|
||||||
static async getBibleFiles(translationPath: string): Promise<string[]> {
|
static async getBibleFiles(translationPath: string): Promise<string[]> {
|
||||||
const files: string[] = [];
|
const files: string[] = [];
|
||||||
@@ -140,7 +164,10 @@ export class OfflineManager {
|
|||||||
const uniqueFiles = [...new Set(filesToFetch)];
|
const uniqueFiles = [...new Set(filesToFetch)];
|
||||||
|
|
||||||
// Add Bible translation files
|
// Add Bible translation files
|
||||||
for (const trans of options.bibleTranslations || []) {
|
const bibleTranslations = options.bibleTranslations === 'all'
|
||||||
|
? await OfflineManager.getAllBibleTranslationIds()
|
||||||
|
: (options.bibleTranslations || []);
|
||||||
|
for (const trans of bibleTranslations) {
|
||||||
const bibleFiles = await OfflineManager.getBibleFiles(trans);
|
const bibleFiles = await OfflineManager.getBibleFiles(trans);
|
||||||
for (const f of bibleFiles) {
|
for (const f of bibleFiles) {
|
||||||
if (!uniqueFiles.includes(f)) uniqueFiles.push(f);
|
if (!uniqueFiles.includes(f)) uniqueFiles.push(f);
|
||||||
@@ -162,7 +189,7 @@ export class OfflineManager {
|
|||||||
diagLog('preload-start', {
|
diagLog('preload-start', {
|
||||||
langs: options.languages.join(','),
|
langs: options.languages.join(','),
|
||||||
types: options.types.join(','),
|
types: options.types.join(','),
|
||||||
bibles: (options.bibleTranslations || []).length,
|
bibles: bibleTranslations.length,
|
||||||
total: progress.total,
|
total: progress.total,
|
||||||
manifest: m !== null,
|
manifest: m !== null,
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-1
@@ -12,6 +12,7 @@ import { loadSettings, type Settings } from './settings-view';
|
|||||||
import { getTranslations, type LanguageCode } from '../core/i18n';
|
import { getTranslations, type LanguageCode } from '../core/i18n';
|
||||||
import { DataCache } from '../core/data-cache';
|
import { DataCache } from '../core/data-cache';
|
||||||
import { diagLog } from '../core/diag-log';
|
import { diagLog } from '../core/diag-log';
|
||||||
|
import { OfflineManager } from '../core/offline-manager';
|
||||||
import { markEverInstalled, hasEverInstalledMarker } from '../core/pwa-install';
|
import { markEverInstalled, hasEverInstalledMarker } from '../core/pwa-install';
|
||||||
|
|
||||||
type View = 'calendar' | 'bible' | 'prayer' | 'akathists' | 'parimii' | 'horologion' | 'sbornik' | 'paraclete' | 'irmologion' | 'menaion' | 'triodion' | 'lives' | 'settings';
|
type View = 'calendar' | 'bible' | 'prayer' | 'akathists' | 'parimii' | 'horologion' | 'sbornik' | 'paraclete' | 'irmologion' | 'menaion' | 'triodion' | 'lives' | 'settings';
|
||||||
@@ -201,7 +202,8 @@ export class App {
|
|||||||
|
|
||||||
document.getElementById('offline-offer-all')?.addEventListener('click', () => {
|
document.getElementById('offline-offer-all')?.addEventListener('click', () => {
|
||||||
overlay.remove();
|
overlay.remove();
|
||||||
window.location.hash = '#settings/autopreload';
|
OfflineManager.requestAutoPreload();
|
||||||
|
window.location.hash = '#settings';
|
||||||
});
|
});
|
||||||
document.getElementById('offline-offer-choose')?.addEventListener('click', () => {
|
document.getElementById('offline-offer-choose')?.addEventListener('click', () => {
|
||||||
overlay.remove();
|
overlay.remove();
|
||||||
|
|||||||
@@ -672,7 +672,7 @@ export class SettingsView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auto-preload everything if triggered from first-launch offer
|
// Auto-preload everything if triggered from first-launch offer
|
||||||
if (this.action === 'autopreload') {
|
if (OfflineManager.consumeAutoPreload() || this.action === 'autopreload') {
|
||||||
document.querySelectorAll('.offline-lang').forEach(el => (el as HTMLInputElement).checked = true);
|
document.querySelectorAll('.offline-lang').forEach(el => (el as HTMLInputElement).checked = true);
|
||||||
document.querySelectorAll('.offline-type').forEach(el => (el as HTMLInputElement).checked = true);
|
document.querySelectorAll('.offline-type').forEach(el => (el as HTMLInputElement).checked = true);
|
||||||
const progressDiv = document.getElementById('offline-progress');
|
const progressDiv = document.getElementById('offline-progress');
|
||||||
@@ -680,20 +680,19 @@ export class SettingsView {
|
|||||||
const progressText = document.getElementById('offline-progress-text');
|
const progressText = document.getElementById('offline-progress-text');
|
||||||
if (progressDiv) progressDiv.classList.remove('hidden');
|
if (progressDiv) progressDiv.classList.remove('hidden');
|
||||||
|
|
||||||
|
// Reveal + select all Bible variants for UI consistency
|
||||||
|
document.getElementById('bible-row')?.dispatchEvent(new Event('click'));
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelectorAll('.bible-trans').forEach(el => (el as HTMLInputElement).checked = true);
|
||||||
|
}, 300);
|
||||||
|
|
||||||
const selectedLangs = LANGUAGES.map(l => l.code);
|
const selectedLangs = LANGUAGES.map(l => l.code);
|
||||||
const selectedTypes: ('calendar' | 'bible')[] = ['calendar', 'bible'];
|
const selectedTypes: ('calendar' | 'bible')[] = ['calendar', 'bible'];
|
||||||
|
|
||||||
let bibleTrans: string[] = [];
|
|
||||||
try {
|
|
||||||
const resp = await fetch('/data/bible/versions.json');
|
|
||||||
const versions = await resp.json();
|
|
||||||
bibleTrans = versions.map((v: any) => v.id);
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
OfflineManager.preload({
|
OfflineManager.preload({
|
||||||
languages: selectedLangs,
|
languages: selectedLangs,
|
||||||
types: selectedTypes,
|
types: selectedTypes,
|
||||||
bibleTranslations: bibleTrans,
|
bibleTranslations: 'all',
|
||||||
}).then((prog) => {
|
}).then((prog) => {
|
||||||
if (progressBar) progressBar.style.width = '100%';
|
if (progressBar) progressBar.style.width = '100%';
|
||||||
if (progressText) {
|
if (progressText) {
|
||||||
|
|||||||
Reference in new issue
Block a user