diff --git a/docs/IOS_ANDROID_I18N_GAP.md b/docs/IOS_ANDROID_I18N_GAP.md index 641cba3..b5bb9b9 100644 --- a/docs/IOS_ANDROID_I18N_GAP.md +++ b/docs/IOS_ANDROID_I18N_GAP.md @@ -1,59 +1,71 @@ # Gap Android → iOS: allineamento app nativa -Documento operativo per continuare su **Mac** lo sviluppo iOS e rilasciare un’app allineata a quanto già fatto (e rilasciato) su Android. +Documento operativo per continuare su **Mac** lo sviluppo iOS e rilasciare un’app **allineata ad Android `2.0.4-native`**. -**Data:** 24 luglio 2026 -**Riferimento Android rilasciato:** `2.0.4-native` (`versionCode` 25), API `https://www.matchlivetv.it` -**Stato iOS attuale:** marketing `2.0.0`, build `21` — i18n solo parziale +**Aggiornato:** 24 luglio 2026 +**Riferimento Android (produzione / telefono):** `2.0.4-native` (`versionCode` **25**), API `https://www.matchlivetv.it` +**Stato iOS attuale:** marketing `2.0.0`, build `21` — i18n **solo Login parziale** -> **Nota (24 lug 2026):** su Android i18n copre ora anche bottom sheet (es. «Choose team»), dialog, wizard e broadcast — non solo Login/hub. Su iOS resta prioritario allineare almeno hub + sheet equivalenti. +Obiettivo iOS: **stessa copertura lingua** di Android (Login, hub, sheet/dialog, wizard, broadcast) + bump versione. --- ## Contesto -Dopo il rilascio web i18n (IT/EN/FR/DE/ES) e dell’APK Android di produzione, l’app Android ha: +Su Android (rilasciato) la lingua scelta dall’utente vale su **tutta l’app** usabile: -- selettore lingua persistito -- Login + hub Partite localizzati in 5 lingue -- bump versione 2.0.3 / 24 +- Persistenza + apply (`AppLocale` / SharedPreferences `mltv_locale` + recreate) +- Icona **globo** su Login 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 l’infrastruttura lingua esiste (`AppLanguage` + picker), ma **Matches e slogan restano in italiano** e la versione è indietro. +Su iOS esistono già `AppLanguage` + `LanguagePickerView` + Login localizzato, ma **Matches/sheet/wizard/broadcast restano in italiano hardcoded**. Va replicato il lavoro Android in SwiftUI. -API produzione: entrambe le app puntano già a `https://www.matchlivetv.it` di default — **nessun gap di endpoint**. +API produzione: entrambe le app puntano già a `https://www.matchlivetv.it` — **nessun gap di endpoint**. --- -## Stato a confronto +## Stato a confronto (target = Android 2.0.4) -| Area | Android | iOS | -|------|---------|-----| -| Persistenza lingua | SharedPreferences `mltv_locale` + `AppLocale.wrap` + recreate | UserDefaults `mltv.appLanguage` + notification | -| Picker lingua | `LanguagePickerDialog` su Login + Matches | `LanguagePickerView` su Login + Matches | -| Login localizzato | Sì (5 lingue) | Sì (5 lingue via `L10n`) | -| Hub Partite localizzato | Sì (~20 stringhe hub) | **No** — testi IT hardcoded | -| Slogan wordmark | `R.string.app_slogan` | Chiave `app.slogan` in `L10n` **non usata** | -| Catalogo stringhe | `res/values*` (47 chiavi × 5) | Dizionario in `AppLanguage.swift` (~14 chiavi) | -| Logout UI | Icona | Testo «Esci» | -| Versione | `2.0.3-native` / 24 | `2.0.0` / 21 | -| RTMP ingest rewrite | `RtmpIngestUrl.kt` + test | `MediaUrl.swift` (ok in prod; semantica dev leggermente diversa) | -| Wizard / Broadcast | Ancora IT hardcoded | Ancora IT hardcoded (stesso debito) | +| Area | Android 2.0.4 | iOS oggi | Da fare su iOS | +|------|---------------|----------|----------------| +| Persistenza lingua | SharedPreferences + wrap + recreate | UserDefaults + notification | Verificare refresh UI su **tutte** le schermate (non solo Login/Matches root) | +| Picker Login | Icona globo top-right | Testo / picker presente | Allineare a **icona globo** come Android | +| Picker Matches | Icona globo top bar | Presente | OK se già icona; altrimenti allineare | +| Login stringhe | Sì | Sì (`L10n`) | OK | +| Slogan wordmark | `app_slogan` | Chiave `app.slogan` **non usata** | Collegare `L10n.t("app.slogan")` | +| Hub Matches | Sì | Quasi tutto IT fisso | Localizzare con chiavi `matches.*` | +| Sheet/dialog Matches | Sì (`sheet_*`) | IT fisso | Localizzare (priorità: scegli squadra) | +| Status badge partita | `match_status_*` | IT | Localizzare | +| Snackbar hub | `matches_msg_*` | IT | Localizzare | +| Wizard 3 step | Sì (`wizard_*`) | IT | Localizzare | +| Branding / color picker | Sì | IT | Localizzare | +| Broadcast + score dialog | Sì (`broadcast_*`, `score_*`) | IT | Localizzare | +| Catalogo stringhe | `values` + `values-en/fr/de/es` (~230 chiavi) | ~14 chiavi in `AppLanguage.swift` | Espandere `L10n` (o migrare a `Localizable.xcstrings`) | +| Logout UI | Icona | Testo | Icona SF Symbol | +| Versione | `2.0.4-native` / **25** | `2.0.0` / **21** | Bump a **2.0.4** / **25** (o build successiva se 22–25 già usati su TestFlight) | +| RTMP ingest | `RtmpIngestUrl.kt` | `MediaUrl.swift` | OK in prod; allineare solo semantica dev se serve | --- ## File di riferimento -### Android (sorgente “già fatto”) +### Android (sorgente di verità — già fatto) | Ruolo | Path | |-------|------| -| Locale | `native/android/app/src/main/kotlin/.../core/AppLocale.kt` | -| Picker | `native/android/app/src/main/kotlin/.../ui/components/LanguagePickerDialog.kt` | -| Activity | `native/android/app/src/main/kotlin/.../MainActivity.kt` | -| Stringhe IT | `native/android/app/src/main/res/values/strings.xml` | -| Stringhe EN/FR/DE/ES | `native/android/app/src/main/res/values-{en,fr,de,es}/strings.xml` | -| Hub | `.../ui/matches/MatchesScreen.kt`, `MatchSheets.kt` | +| Locale | `native/android/.../core/AppLocale.kt` | +| Picker | `native/android/.../ui/components/LanguagePickerDialog.kt` | +| Activity | `native/android/.../MainActivity.kt` | +| Stringhe | `native/android/app/src/main/res/values/strings.xml` + `values-{en,fr,de,es}/` | | Login | `.../ui/login/LoginScreen.kt` | +| Hub | `.../ui/matches/MatchesScreen.kt` | +| Sheet/dialog | `.../ui/matches/MatchSheets.kt` | +| Wizard | `.../ui/wizard/*.kt` | +| Broadcast | `.../ui/broadcast/*.kt` | | Versione | `native/android/app/build.gradle.kts` | ### iOS (da aggiornare) @@ -63,93 +75,97 @@ API produzione: entrambe le app puntano già a `https://www.matchlivetv.it` di d | Lingua + L10n | `native/ios/MatchLiveTv/Core/AppLanguage.swift` | | Login | `native/ios/MatchLiveTv/UI/Login/LoginScreen.swift` | | Hub | `native/ios/MatchLiveTv/UI/Matches/MatchesScreen.swift` | -| Wordmark | `native/ios/MatchLiveTv/UI/Components/MatchLiveWordmark.swift` (verificare path esatto) | -| Versioni | `native/ios/generate_xcodeproj.py`, `MatchLiveTv.xcodeproj/project.pbxproj`, `Info.plist` | -| Build release | `scripts/build_ios_release.sh` | -| README | `native/ios/README.md` | +| Sheet/dialog Matches | file sheet/alert equivalenti sotto `UI/Matches/` (cercare stringhe IT) | +| Wizard | `UI/Wizard/` (o path equivalente) | +| Broadcast | `UI/Broadcast/` (o path equivalente) | +| Wordmark | `native/ios/MatchLiveTv/UI/Components/MatchLiveWordmark.swift` | +| Versioni | `generate_xcodeproj.py`, `project.pbxproj`, `Info.plist` | +| Build | `scripts/build_ios_release.sh` | --- -## Checklist allineamento iOS (ordine consigliato) +## Piano di lavoro iOS (replicare Android — ordine obbligato) -### 1. Completare stringhe hub (priorità alta) +### Fase A — Infrastruttura stringhe (prima di tutto) -In `AppLanguage.swift` (`L10n.table`), aggiungere chiavi allineate ad Android per **it/en/fr/de/es**. Mapping suggerito: +1. Aprire Android `values/strings.xml` e `values-en|fr|de|es/strings.xml` come catalogo. +2. Portare in `L10n.table` (o meglio `Localizable.xcstrings`) **tutte** le chiavi usate da: + - `matches_*`, `sheet_*`, `match_status_*`, `matches_msg_*` + - `wizard_*`, `wizard_color_hue` + - `broadcast_*`, `score_*` + - `login_*`, `language_*`, `action_*`, `app_slogan`, `common_*` se presenti +3. Convenzione chiavi iOS: `matches.hello` ↔ Android `matches_hello` (punto al posto di `_`). +4. Placeholder: Android `%1$s` → Swift `"Ciao, \(name)"` o `String(format: L10n.t("matches.hello"), name)`. -| Chiave iOS (`L10n`) | Android `strings.xml` | Note | -|---------------------|----------------------|------| -| `matches.hello` | `matches_hello` | formato `"Ciao, %@"` / `"Hi, %@"` | -| `matches.subtitle` | `matches_subtitle` | | -| `matches.schedule` | `matches_schedule` | | -| `matches.new` | `matches_new` | | -| `matches.empty_title` | `matches_empty_title` | | -| `matches.scheduled_title` | `matches_scheduled_title` | | -| `matches.ready_title` | `matches_ready_title` | | -| `matches.empty_hint` | `matches_empty_hint` | | -| `matches.active_team` | `matches_active_team` | `%@` | -| `matches.multi_team_hint` | `matches_multi_team_hint` | | -| `matches.no_other` | `matches_no_other` | | -| `matches.retry` | `matches_retry` | | -| `matches.load_error` | `matches_load_error` | | -| `matches.no_team_title` | `matches_no_team_title` | | -| `matches.no_team_body` | `matches_no_team_body` | | -| `matches.tap_change_team` | `matches_tap_change_team` | | -| `matches.team_for_live` | `matches_team_for_live` | | -| `matches.change` | `matches_change` | | -| `action.save` | `action_save` | se usato in sheet | -| `language.*` | già presenti | | +### Fase B — Login + wordmark (rapido) -Copiare le traduzioni da `values-en|fr|de|es/strings.xml` (testo già validato su Android). +5. Login: icona globo in alto a destra (come Android), non solo testo. +6. `MatchLiveWordmark`: `L10n.t("app.slogan")`. +7. Verificare che al cambio lingua Login si ricrei/rinfreschi (notification già presente). -Poi in `MatchesScreen.swift`: +### Fase C — Hub Matches + sheet/dialog (priorità UX — screenshot «Scegli squadra») -- sostituire ogni `Text("…")` / titolo sezione / empty state / alert con `L10n.t(...)` -- empty “nessuna squadra” → `matches.no_team_title` / `matches.no_team_body` -- assicurarsi che `.id(languageTick)` (o equivalente) ricarichi l’hub al cambio lingua +8. `MatchesScreen.swift`: ogni `Text("…")` hardcoded → `L10n.t(...)`. +9. Sheet/dialog equivalenti a `MatchSheets.kt`: + - scegli squadra → `sheet.choose_team` + - nuova partita / programma / avvia subito + - scegli partita, badge BOZZA/PROGRAMMATA + - riprendi diretta, continua setup + - configura ora?, elimina partita +10. Snackbar/alert hub → `matches.msg_*`. +11. Badge status riga partita → `match.status_*`. +12. Assicurare `.id(languageTick)` (o environment) su root Matches **e** sheet presentati. -### 2. Slogan wordmark (priorità alta) +### Fase D — Wizard -In `MatchLiveWordmark` (o componente equivalente): +13. Localizzare step Partita / Trasmissione / Test rete + branding editor + color hue (`wizard.*`). +14. Errori validazione e CTA AVANTI/INDIETRO/INIZIA. -- usare `L10n.t("app.slogan")` al posto della stringa italiana fissa -- verificare sul Login in EN/FR/DE/ES +### Fase E — Broadcast -### 3. Versione release (priorità media) +15. Overlay controlli, contentDescription, snackbar pausa/ripresa/regia. +16. Dialog termina diretta, set concluso, chiudi set, partita terminata (`broadcast.*`, `score.*`). -Allineare a Android (o policy store equivalente): +### Fase F — Versione e release -- `MARKETING_VERSION` → `2.0.3` (o `2.0.3-native` se accettato da App Store Connect) -- `CURRENT_PROJECT_VERSION` → `24` (o build successiva se 21/22/23 già usati su TestFlight) - -Aggiornare **sia** `generate_xcodeproj.py` **sia** `Info.plist` (`CFBundleShortVersionString` / `CFBundleVersion`) prima di regenerare il progetto. - -### 4. Logout icon (priorità bassa) - -In top bar Matches: SF Symbol tipo `rectangle.portrait.and.arrow.right` + `accessibilityLabel` da `L10n.t("action.logout")`, come icona logout Android. - -### 5. Opzionale — tooling stringhe - -Migrare da dizionario Swift a `Localizable.xcstrings` (o `*.lproj`) per parità con Android `values-*` e revisione traduzioni in Xcode. - -### 6. Fuori scope immediato (stesso debito Android) - -Wizard 3 step, Broadcast overlay, dialoghi set/partita: ancora IT hardcoded su **entrambe** le piattaforme. Non bloccano l’allineamento Login/Matches/i18n di questa release. +17. Bump `MARKETING_VERSION` → `2.0.4`, `CURRENT_PROJECT_VERSION` → `25` (o successivo se conflitto TestFlight). +18. Aggiornare `generate_xcodeproj.py` **e** `Info.plist`, poi `python3 generate_xcodeproj.py`. +19. `./scripts/build_ios_release.sh` (API default già produzione). --- -## Verifica manuale su Mac (pre-release) +## Mapping chiavi — gruppi da copiare da Android + +Sorgente: `native/android/app/src/main/res/values*/strings.xml`. + +| Prefisso Android | Uso | Priorità | +|------------------|-----|----------| +| `language_*`, `login_*`, `app_slogan`, `action_*` | Login / chrome | Alta | +| `matches_*` | Hub | Alta | +| `sheet_*`, `match_status_*`, `matches_msg_*` | Sheet/dialog hub | **Alta** (bug «Scegli squadra» in EN) | +| `wizard_*` | Wizard | Alta (stessa sessione utente dopo hub) | +| `broadcast_*`, `score_*` | Diretta | Alta | +| `streaming_notification_*` | Solo Android FGS | N/A su iOS | + +Non lasciare fuori scope wizard/broadcast: su Android **sono già tradotti**; iOS deve seguirli per parità. + +--- + +## Verifica manuale su Mac (acceptance) 1. `cd native/ios && python3 generate_xcodeproj.py` -2. Build debug su simulatore; login con utenza di produzione (o staging). -3. Cambia lingua Login → English: label + errori + slogan in EN. -4. Entra in Matches: saluto, sezioni, empty state, CTA in EN (non italiano). -5. Kill app e riapri: lingua persistita. -6. Ripeti spot-check FR/DE/ES. -7. Release: dalla root repo - `./scripts/build_ios_release.sh` - (default API già `https://www.matchlivetv.it`; override con `API_BASE_URL=...` se serve). +2. Build simulatore; login produzione. +3. Login: globo → English → label/errori/slogan in EN. +4. Matches: saluto, CTA, empty state in EN. +5. Apri «Change» / scegli squadra: titolo **«Choose team»** (non «Scegli squadra»). +6. Nuova partita / programma / elimina: tutto EN. +7. Wizard 3 step in EN. +8. (Se possibile) overlay diretta: dialog/termina in EN. +9. Kill app → riapri: lingua persistita. +10. Spot-check FR/DE/ES. +11. Release: `./scripts/build_ios_release.sh` -Test automatici (da README iOS): +Test: ```bash cd native/ios @@ -167,20 +183,21 @@ xcodebuild -project MatchLiveTv.xcodeproj -scheme MatchLiveTv \ | | Android | iOS | |--|---------|-----| -| Default | `-PAPI_BASE_URL` / BuildConfig | `API_BASE_URL` in build settings → Info.plist | -| Fallback | `https://www.matchlivetv.it` | idem in `AppConfig` | -| REST | `{base}/api/v1` | idem | -| Cable | `wss://…/cable` | idem | +| 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 per allineare iOS: stesso backend già in produzione con i18n web. +Nessuna modifica server richiesta. --- -## Sintesi priorità +## Sintesi priorità (ordine di esecuzione) -1. **Alta** — Localizzare hub Matches (oggi cambio lingua incompleto). -2. **Alta** — Collegare slogan wordmark a `L10n`. -3. **Media** — Bump versione 2.0.3 / 24. -4. **Bassa** — Icona logout; migrazione a xcstrings; fine-tuning RTMP solo per dev. +1. **A** Catalogo stringhe completo (copiare da Android `values*`) +2. **C** Hub + sheet/dialog (fix «Scegli squadra» in EN) +3. **B** Slogan + globo Login +4. **D** Wizard +5. **E** Broadcast +6. **F** Versione `2.0.4` / `25` + build release -Quando questi punti sono chiusi, l’app iOS è allineata alla release Android `2.0.3-native` per UX lingua e store versioning. +Quando A–F sono chiusi, iOS è allineato ad Android **2.0.4-native** per UX multilingua e versioning store. diff --git a/native/ios/README.md b/native/ios/README.md index 4e276dd..c524865 100644 --- a/native/ios/README.md +++ b/native/ios/README.md @@ -79,7 +79,7 @@ xcodebuild -project MatchLiveTv.xcodeproj -scheme MatchLiveTv \ ## Documentazione correlata -- [`docs/IOS_ANDROID_I18N_GAP.md`](../../docs/IOS_ANDROID_I18N_GAP.md) — gap i18n/versione vs Android (checklist allineamento su Mac) +- [`docs/IOS_ANDROID_I18N_GAP.md`](../../docs/IOS_ANDROID_I18N_GAP.md) — **checklist completa** per allineare iOS ad Android 2.0.4 (hub, sheet, wizard, broadcast, versione) - [`docs/TABELLONI_E_OVERLAY.md`](../../docs/TABELLONI_E_OVERLAY.md) — regolamenti, board, overlay - [`docs/MULTI_SPORT.md`](../../docs/MULTI_SPORT.md) — catalogo sport e engine scoring - [`docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) — infrastruttura e flussi live/HLS