Files
MatchLiveTv/docs/IOS_ANDROID_I18N_GAP.md

153 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Gap Android → iOS: allineamento app nativa
Documento operativo per continuare su **Mac** lo sviluppo iOS e rilasciare unapp **allineata ad Android**.
**Aggiornato:** 12 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)
**Nuovo (branch `feature/stream-audio-mute`):** mute microfono in diretta. Codice iOS già nel branch; verifica su Mac in [`IOS_STREAM_AUDIO_MUTE.md`](IOS_STREAM_AUDIO_MUTE.md).
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 dallutente vale su **tutta** lapp usabile:
- Persistenza + apply live (`AppLocale` / SharedPreferences `mltv_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` → iOS `matches.hello` (ogni `_``.`)
- Placeholder: `%1$s` / `%1$d``%1$@` / `%1$d` con `L10n.t("key", args...)`
- Catalogo generato da `values*/strings.xml` (escluse `streaming_notification_*`, solo Android FGS)
---
## Verifica manuale su Mac (acceptance)
1. `cd native/ios && python3 generate_xcodeproj.py`
2. Build simulatore; login produzione.
3. Login: globo → English → label/errori/slogan in EN.
4. **Loggato:** cambio lingua da Matches → resti su Matches, testi EN (niente ritorno al Login).
5. Matches: saluto, CTA, empty state in EN.
6. Apri «Change» / scegli squadra: titolo **«Choose team»** (non «Scegli squadra»).
7. Nuova partita → Avvia ora → wizard si apre **senza crash**; step in EN.
8. Wizard 3 step in EN; logo picker funziona.
9. (Se possibile) overlay diretta: dialog/termina in EN.
10. Kill app → riapri: lingua persistita **e** sessione resta se token valido.
11. Spot-check FR/DE/ES.
12. Release: `./scripts/build_ios_release.sh`
```bash
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 AF 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.