Exit confirmation
- A dialog in the app's own style now guards every in-game screen. The safe
action is the prominent one, so a stray tap keeps you in the game.
- Eleven screens covered, against both the system back gesture and the close
buttons. The message adapts: a single-device game is lost, a host ends it
for everyone, a client can rejoin.
- The two screens the host also opens from the manager take a flag so that
back there just closes them instead of offering to quit.
Translations
- 21 keys were still holding the English text in Arabic, Basque, Hindi,
Japanese, Korean, Dutch, Polish, Russian, Turkish and both Chinese
variants: 231 strings, covering the whole multi-device flow, permissions
and the mode picker. Nothing failed, the app just showed English.
- The permissions dialog was hardcoded in Spanish; it is localized now.
- Portuguese used Spanish gerunds where pt-PT takes "a + infinitive".
Checked what looked untranslated but is not: Animals and Notes are correct
Catalan, Configuration and Vibration correct French, Version correct German.
Those are whitelisted in the new test rather than silently rewritten.
l10n_cobertura_test guards all of it: no missing or orphan keys, no empty
values, no English left outside the whitelist, and placeholders preserved.
The app crashed on launch with ClassNotFoundException for
es.freetimelab.farolero.game.MainActivity: 374c6ae added the .game suffix to
namespace and applicationId but left the Kotlin source in
es.freetimelab.farolero, so the manifest asked for a class that was never
compiled under that name. Every release built since then died on startup,
including the one already published to internal testing.
Also requests edge-to-edge explicitly now that the app targets 35, rather
than relying on the Flutter default.
Verified on a physical device running Android 16: installs, launches and
stays alive with no crash, and the bottom action buttons sit clear of the
navigation bar.
Play rejected version code 54 for still targeting 34.
From API 35 Android forces edge-to-edge: content is drawn behind the system
bars and it is up to each screen to keep clear of them. Seven screens had no
SafeArea and their bottom action button would have ended up under the
gesture bar, so FondoFarolero gains a respetarBarras flag that insets the
content while the background still paints full bleed. The seventeen screens
that already handle it are untouched.
The navigation bar colour is ignored under edge-to-edge, so its icons are
now forced light to stay visible over the dark background.
Verified on the merged manifest: targetSdkVersion 35, and the release bundle
builds. The visual result has not been checked on a device.
The clue used to be the category name, which is the same for a hundred
words. Each of the 1000 words now carries a single associated trait:
Perro -> Fiel, Cebolla -> Hace llorar, Egipto -> Piramides.
18000 clues across the 18 languages. Files move to version 3; the loader
already reads both formats.
Verification caught 79 clues that contained the word they were meant to
hide and gave it away. Eight were exact matches caused by homonyms that do
not exist in Spanish: Schach and Xake mean both chess and check, and the
same happened with the Arabic 5G and the Chinese Apple and Spam. The other
71 contained the word as a substring, such as Libro -> "Pagine e
segnalibro". All rewritten.
banco_pistas_test guards it: per language it checks 10x100 words, no empty
clue and no clue containing its own word. One-character words are skipped
because any sentence contains them; the Turkish title for the film IT is a
bare "O".
40 keys existed only in app_es.arb and fell back to Spanish everywhere else
(15 of them in English). Most were multi-device screens: hostGame, votar,
clueIs, whoDoYouThinkIsTheImpostor, waitingPlayersSeeWord.
Adds those plus the new keys for impostor awareness, the adjusted impostor
count, the eliminated-player notice and the reconnection screen.
51 keys across the 18 supported languages.
Fixes
- SnapshotPartidaOnline no longer serializes esImpostor unless the game is
over. Every phase change was broadcasting the impostor roles in clear to
all clients.
- The impostor clue travels in its own field and only when the game enables
it. It used to be sent as the category key ("todas" when no category was
picked) and was overwritten by each phase snapshot.
- Eliminated players can no longer vote nor be voted for, on both the client
screen and the host listener.
- Nearby listeners are removed on dispose; votes are no longer dispatched
twice; votacionResultado no longer triggers two navigations.
- _jugadoresHostControlados handed the secret word to the host's own
impostors in the payload.
- Impostor cap unified as maxImpostoresPara(n) for both modes, and the
silent clamp in multi-device now reports the effective number.
- palabraAleatoria uses Random.secure.
Impostors know each other
- ConfigPartida.impostoresSeConocen, on by default. companerosImpostores is
nullable: null means nothing to show, an empty list means "you are the
only impostor".
Reconnection
- IdentidadDispositivo persists a stable device id; the host uses it as the
clientId so a phone that drops and returns is the same client. Falls back
to the endpointId for clients that do not send one.
- Usuario.absorbidoDe records the original owner when the host takes over a
disconnected player, and they are handed back automatically on return.
- New solicitarResync/resync messages: the host replies with the current
phase plus that client's own players, and the client jumps straight to the
running phase.
- Readiness is keyed by clientId instead of endpointId, and a disconnected
client no longer blocks the round.
- The retry gives up after three minutes, only reconnects to the host it
belonged to, and is cancelled correctly while shutting down.
Per-word clue support
- The word bank loader accepts both the old list-of-strings format and the
new one carrying a clue per word, falling back to the category clue.
Not verified on real devices: Nearby reconnection timing still needs two
Android phones.
crearPartida clears the notes, which goes through SharedPreferences, and
ServicioNearby.dispose called notifyListeners after tearing the notifier
down. Both failed on plugin channels that do not exist in the test host.
Suite goes from 25 passing / 8 failing to a green run.
No se puede marcar “vista” sin revelar la palabra antes.
Se puede volver a ver la palabra durante debate/votación/resultado.
Notas online privadas por partida y jugador.
Tests añadidos para notas scoped.
Ajusté roomId en el payload de inicio para que las notas no se mezclen entre partidas.
revert ci: workflow profesional — análisis + bump + build + deploy + notify
Basado en el patrón de javihogar-android:
- PATH global como env (actions/checkout funciona)
- Job análisis separado
- Auto-bump versión patch en cada push a main
- Notify Telegram con estado
- [ci skip] en commit de versión
revert ci: workflow profesional — análisis + bump + build + deploy + notify
Basado en el patrón de javihogar-android:
- PATH global como env (actions/checkout funciona)
- Job análisis separado
- Auto-bump versión patch en cada push a main
- Notify Telegram con estado
- [ci skip] en commit de versión