Bump marketing/build a 2.0.10/31, copy EN forgot password e checklist password policy. Co-authored-by: Cursor <cursoragent@cursor.com>
6.8 KiB
Gap Android → iOS: allineamento app nativa
Documento operativo per continuare su Mac lo sviluppo iOS e rilasciare un’app allineata ad Android.
Aggiornato: 8 agosto 2026
Riferimento Android (produzione / telefono / Play): 2.0.10-native (versionCode 31), API https://www.matchlivetv.it
Stato iOS attuale: marketing 2.0.10, build 31 — i18n allineato (Login, hub, sheet/dialog, wizard, broadcast, account/forgot)
Obiettivo iOS: stessa copertura lingua di Android (Login, hub, sheet/dialog, wizard, broadcast, account) + bump versione, senza i bug di sessione/crash già risolti su Android.
Contesto
Su Android (rilasciato) la lingua scelta dall’utente vale su tutta l’app usabile:
- Persistenza + apply live (
AppLocale/ SharedPreferencesmltv_locale+ProvideAppLocale) - Icona globo su Login (TopAppBar) e Matches
- Hub Partite localizzato
- Bottom sheet e dialog Matches (es. «Choose team», nuova partita, programma, elimina, riprendi)
- Wizard 3 step + branding colori
- Broadcast overlay, snackbar, dialog fine set/partita
- ~230+ chiavi × 5 lingue in
res/values*
Su iOS: AppLanguage + L10n (~225 chiavi × 5 lingue) + LanguagePickerView; Login/Matches/Wizard/Broadcast usano L10n.t(...). Refresh UI via NotificationCenter + .id(languageTick) senza reset sessione/nav.
API produzione: entrambe le app puntano già a https://www.matchlivetv.it — nessun gap di endpoint.
Lezioni Android 2.0.5 (obbligatorie su iOS)
Queste sono regressioni/bug già visti su Android; non ripeterli su iOS.
| Problema | Sintomo | Fix Android (da replicare in spirito) | Stato iOS |
|---|---|---|---|
| Recreate Activity al cambio lingua | Torna al Login / perde nav | Niente recreate obbligatorio: aggiorna UI via stato lingua + refresh stringhe | OK — languageTick / notification |
| Context “nudo” per le stringhe | Crash wizard: picker foto | Mantieni Activity come host | OK — SwiftUI host invariato |
| Globe sotto lo scroll del form Login | Tap ignorato | Globe in toolbar/top bar | OK — globo in top bar Login |
| Splash che richiede rete per restare loggato | Dopo cambio lingua → Login se API lenta | Se token locale presente → resta autenticato | OK — validateOrRefresh restituisce sessione locale su errore rete |
Stato a confronto (target = Android 2.0.5)
| Area | Android 2.0.5 | iOS oggi | Da fare su iOS |
|---|---|---|---|
| Persistenza lingua | SharedPreferences + ProvideAppLocale |
UserDefaults + notification | Fatto |
| Picker Login | Icona globo in TopAppBar | Icona globo top bar | Fatto |
| Picker Matches | Icona globo top bar | Icona globo + logout icon | Fatto |
| Login stringhe | Sì | Sì (L10n) |
Fatto |
| Slogan wordmark | app_slogan |
L10n.t("app.slogan") |
Fatto |
| Hub Matches | Sì | matches.* |
Fatto |
| Sheet/dialog Matches | Sì (sheet_*) |
sheet.* |
Fatto |
| Status badge partita | match_status_* |
match.status.* |
Fatto |
| Snackbar hub | matches_msg_* |
matches.msg.* |
Fatto |
| Wizard 3 step | Sì (wizard_*) |
wizard.* |
Fatto |
| Branding / color picker | Sì | wizard.branding.* / wizard.color.hue |
Fatto |
| Broadcast + score dialog | Sì | broadcast.* / score.* |
Fatto |
| Catalogo stringhe | values* (~230) |
AppLanguage.swift L10n (~225, no FGS) |
Fatto |
| Logout UI | Icona | Icona SF Symbol | Fatto |
| Versione | 2.0.10-native / 31 |
2.0.10 / 31 |
Fatto |
| RTMP ingest | RtmpIngestUrl.kt |
MediaUrl.swift |
OK |
Residui fuori scope Android (opzionali)
Nessuno per messaggi utente: tutte le stringhe UI/errori/termiche/API/overlay usano L10n.
Permission dialog di sistema localizzati via Resources/{it,en,fr,de,es}.lproj/InfoPlist.strings.
Brand fissi lasciati intenzionalmente invariati: MATCH / LIVE / TV, Match Live TV, YouTube Live.
File di riferimento
Android (sorgente di verità)
| Ruolo | Path |
|---|---|
| Locale + ProvideAppLocale | native/android/.../core/AppLocale.kt |
| Stringhe | native/android/app/src/main/res/values/strings.xml + values-{en,fr,de,es}/ |
| UI | Login / Matches / MatchSheets / Wizard / Broadcast |
iOS (allineato)
| Ruolo | Path |
|---|---|
| Lingua + L10n | native/ios/MatchLiveTv/Core/AppLanguage.swift |
| Login | native/ios/MatchLiveTv/UI/Login/LoginScreen.swift |
| Hub + sheet | native/ios/MatchLiveTv/UI/Matches/MatchesScreen.swift |
| Status badge | native/ios/MatchLiveTv/Domain/MatchHubFilter.swift (MatchPresentation) |
| Wizard | native/ios/MatchLiveTv/UI/Wizard/*.swift |
| Broadcast | native/ios/MatchLiveTv/UI/Broadcast/*.swift |
| Wordmark | native/ios/MatchLiveTv/UI/Components/MatchLiveWordmark.swift |
| Versioni | generate_xcodeproj.py, Info.plist, project.pbxproj |
Convenzione chiavi
- Android
matches_hello→ iOSmatches.hello(ogni_→.) - Placeholder:
%1$s/%1$d→%1$@/%1$dconL10n.t("key", args...) - Catalogo generato da
values*/strings.xml(esclusestreaming_notification_*, solo Android FGS)
Verifica manuale su Mac (acceptance)
cd native/ios && python3 generate_xcodeproj.py- Build simulatore; login produzione.
- Login: globo → English → label/errori/slogan in EN.
- Loggato: cambio lingua da Matches → resti su Matches, testi EN (niente ritorno al Login).
- Matches: saluto, CTA, empty state in EN.
- Apri «Change» / scegli squadra: titolo «Choose team» (non «Scegli squadra»).
- Nuova partita → Avvia ora → wizard si apre senza crash; step in EN.
- Wizard 3 step in EN; logo picker funziona.
- (Se possibile) overlay diretta: dialog/termina in EN.
- Kill app → riapri: lingua persistita e sessione resta se token valido.
- Spot-check FR/DE/ES.
- Release:
./scripts/build_ios_release.sh
cd native/ios
python3 generate_xcodeproj.py
xcodebuild -project MatchLiveTv.xcodeproj -scheme MatchLiveTv \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath build/DerivedData \
ONLY_ACTIVE_ARCH=YES ARCHS=arm64 EXCLUDED_ARCHS=x86_64 \
build
Note API / produzione
| Android | iOS | |
|---|---|---|
| Default | BuildConfig / -PAPI_BASE_URL |
API_BASE_URL → Info.plist |
| Fallback | https://www.matchlivetv.it |
idem |
| REST / Cable | /api/v1, wss://…/cable |
idem |
Nessuna modifica server richiesta.
Versione store target: 2.0.10 / build 31 (parità con Android 2.0.10-native / versionCode 31).
Sintesi
Fasi A–F del piano originale sono chiuse. Tutti i messaggi utente (UI, errori API/RTMP, termica, overlay, permission system) passano da L10n / InfoPlist.strings in IT/EN/FR/DE/ES.