fix: gamepad focus, systems update sync, SD card storage, wizard loop
Gamepad focus on dialogs
- Move pushLayer() from postFrameCallback to initState() in UpdateDialog,
SystemsUpdateDialog and new RestartRequiredDialog so the nav layer is
registered before any child widget's postFrameCallback can override it
during app startup (race condition on first launch) - Replace inline AlertDialog restart-required flow with RestartRequiredDialog
StatefulWidget (gamepad A support, consistent visual style) - Fix app-resume focus regression: _reactivateGamepadNavigation() was calling
_gamepadNav.activate() directly, bypassing the GamepadNavigationManager
stack and activating the games-list nav even when a dialog was on top.
Now calls GamepadNavigationManager.reactivate() which activates the actual
top-of-stack layer. Also removed Windows-only guard so reactivate() fires
on all platforms on app resume.
Systems update
- Fix JsonConfigService.loadAndSyncSystems() always syncing from bundled
assets, ignoring downloaded cache files. Now prefers cached versions for
existing systems and also loads new systems only present in cache. - Add getCacheDir() public method to SystemsUpdateService.
- Show Syncing systems database... status in progress bar during
loadAndSyncSystems() step after download completes. New i18n key
systemsUpdateSyncing added to all 11 locale files. - Fix _fetchManifest() hitting stale CDN cache on raw.githubusercontent.com
(Fastly): add timestamp query parameter + Cache-Control/Pragma no-cache
headers to force fresh fetch on every startup check.
SD card user data location and setup wizard loop
- getUserDataPath() now falls back to default path instead of creating an
empty directory when the custom path is inaccessible (SD not mounted,
MANAGE_EXTERNAL_STORAGE not yet granted on boot, etc.), preventing a fresh
empty DB from being opened and triggering the wizard. - Add resolveAndroidUserDataPath() to UserDataLocationService which converts
the SAF URI to the real filesystem path honoring the user's chosen folder,
consistent with how ROM folders are accessed via MANAGE_EXTERNAL_STORAGE. - Add setup_completed_prefs SharedPreferences flag written on wizard completion
and on successful data migration. _checkInitialSetup() checks this flag first
before touching SQLite so the setup wizard is never shown again even if the
DB path is temporarily inaccessible on boot. Existing users get the flag
backfilled automatically on first successful load.