Skip to content

feat: hide watch-related UI entirely when no watch has ever been paired - #25

Open
PonceGL wants to merge 1 commit into
feature/wear-performance-settingsfrom
feature/wear-ui-pairing-gate
Open

feat: hide watch-related UI entirely when no watch has ever been paired#25
PonceGL wants to merge 1 commit into
feature/wear-performance-settingsfrom
feature/wear-ui-pairing-gate

Conversation

@PonceGL

@PonceGL PonceGL commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Qué resuelve

Los tres puntos de entrada de "enviar/gestionar reloj" en el teléfono (menú "Enviar a reloj" de una playlist, botón de enviar canción en SongInfoBottomSheet, y la nueva categoría "Reloj" en Ajustes) se mostraban siempre, sin importar si el usuario alguna vez emparejó un Wear OS. El caso "emparejado pero desconectado ahora mismo" ya estaba bien resuelto (visible, deshabilitado, mensaje "no conectado") — lo que faltaba era la otra mitad: nunca emparejado → ocultar del todo.

Mecanismo

CapabilityClient.FILTER_ALL (nodos que alguna vez anunciaron la capacidad, alcanzables o no) en vez de FILTER_REACHABLE (solo ahora mismo). Nueva WearPhoneTransferSender.refreshWatchPairingState(), mismo molde que isPixelPlayWatchAvailable() ya existente, actualizando un nuevo PhoneWatchTransferStateStore.isAnyWatchPaired (default false — más seguro ocultar de más que de menos para quien nunca emparejó nada).

Se refresca en tres puntos: arranque de la app (mismo patrón que resumePersistedBatchIfNeeded), dentro de refreshWatchAvailability() en ambos ViewModels (gratis, sin nuevos call sites), y un LaunchedEffect(Unit) nuevo en PlaylistDetailScreen/Ajustes para que el flag ya esté resuelto antes de decidir si mostrar el menú, no solo después de tocarlo.

Tests

3 casos nuevos en PhoneWatchTransferStateStoreTest (default false, independiente de reachableWatchNodeIds). Arreglé el mock de PlaylistViewModelTest que necesitaba un stub para la llamada nueva. refreshWatchPairingState() en sí no tiene test unitario — misma limitación que isPixelPlayWatchAvailable() al lado (llamada estática a GMS, sin agente de mockeo inline).

Verifiqué :app:assembleRelease (R8 + shrinkResources) limpio.

Pendiente de hardware: confirmar en un teléfono sin reloj emparejado que las tres opciones no aparecen, que aparecen al emparejar uno, y que se quedan visibles (con el comportamiento "no conectado" ya existente) al apagar el reloj sin desemparejarlo.

Three watch-related entry points on the phone — the "Send to Watch"
playlist menu item, SongInfoBottomSheet's per-song send button, and the
new "Watch" Settings category — used to always show, even for someone
who's never paired a Wear OS device. The existing reachability check
(CapabilityClient FILTER_REACHABLE) already correctly shows these as
disabled/"not connected" for a paired-but-currently-unreachable watch;
what was missing was a distinct signal for "has the user ever paired a
watch with PixelPlay installed at all", to hide the UI entirely in that
case instead of showing a permanently-broken option.

Added WearPhoneTransferSender.refreshWatchPairingState(), same shape as
the existing isPixelPlayWatchAvailable() but using CapabilityClient's
FILTER_ALL (every node that's ever advertised the capability, reachable
or not) instead of FILTER_REACHABLE. Stored in
PhoneWatchTransferStateStore.isAnyWatchPaired, the same shared singleton
that already holds reachableWatchNodeIds — same pattern, distinct
concept, defaults to false (safer to hide for someone who's never paired
anything than to flash the UI on before the first check resolves).

Refreshed at three points: app startup (PixelPlayApplication, same
dagger.Lazy + best-effort try/catch shape as resumePersistedBatchIfNeeded),
inside the existing refreshWatchAvailability() in both PlaylistViewModel
and SongInfoBottomSheetViewModel (fires wherever reachability already
gets refreshed, no new call sites needed there), and a new
LaunchedEffect(Unit) on PlaylistDetailScreen's composition and on the
Settings hub — needed so the flag is resolved before the user opens a
menu/list that needs to gate on it, not only after they tap something
that was already conditionally hidden.

Left untouched: the send-to-watch confirmation dialog's existing
"not connected" messaging for a paired-but-unreachable watch — already
correct, not this change's concern.

Test coverage: 3 new PhoneWatchTransferStateStore cases (default false,
flips independently of reachableWatchNodeIds). Fixed
PlaylistViewModelTest's mock, which needed a stub for the new call.
refreshWatchPairingState() itself isn't unit tested — same static-GMS-call
constraint as isPixelPlayWatchAvailable() next to it, already undtested
for the same reason.

Verified :app still builds clean in release (R8 + shrinkResources).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant