push notifications
This commit is contained in:
53
.claude/agent-memory/android-bug-hunter/MEMORY.md
Normal file
53
.claude/agent-memory/android-bug-hunter/MEMORY.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Android Bug Hunter — Project Memory
|
||||
|
||||
## Recurring Patterns Found
|
||||
|
||||
### NotificationHelper: runBlocking on Service Thread
|
||||
`NotificationHelper.show()` calls `runBlocking` three times (notificationsEnabled, mutedRooms, roomNameCache).
|
||||
This blocks the `PushService` callback thread. Fix: pass pre-collected values in or make `show()` a suspend fun.
|
||||
See: `push/NotificationHelper.kt`
|
||||
|
||||
### FluffytrixPushService: Leaking CoroutineScope
|
||||
`FluffytrixPushService` creates its own `CoroutineScope(SupervisorJob() + Dispatchers.IO)` but never cancels
|
||||
it when the service is destroyed. Coroutines launched from `onNewEndpoint`/`onUnregistered` can outlive the
|
||||
service. Fix: cancel scope in `onDestroy()`.
|
||||
|
||||
### PushRegistrationManager: OkHttp response body not closed
|
||||
`registerPusher()` stores `response.body?.string()` (which auto-closes), but the `execute()` call itself is
|
||||
never inside a `use {}` block — if `body?.string()` throws, the response is not closed.
|
||||
Fix: wrap in `response.use { ... }`.
|
||||
|
||||
### build.gradle.kts: API key in plain BuildConfig
|
||||
`TENOR_API_KEY` hardcoded in `buildConfigField` — visible in plaintext in the APK's BuildConfig class.
|
||||
|
||||
### MainViewModel: `onUpdate` listener launches on `Dispatchers.Default` inside `viewModelScope`
|
||||
The timeline listener's `onUpdate` callback launches a coroutine with `viewModelScope.launch(Dispatchers.Default)`.
|
||||
If the ViewModel is cleared mid-flight the scope is cancelled but the `onUpdate` lambda (captured by the
|
||||
SDK via JNI) can still fire and attempt `launch` on a cancelled scope — harmless but noisy.
|
||||
|
||||
### MainViewModel: `CoroutineScope` inside `loadTimeline` shared across closures
|
||||
A `Mutex` local to `loadTimeline` is captured by the `TimelineListener` lambda. When `loadTimeline` is called
|
||||
again for a new room, the old listener still holds the old mutex — correct, but produces confusing parallelism.
|
||||
|
||||
### MainViewModel: `sendGif` creates a new OkHttpClient per call
|
||||
A brand-new `OkHttpClient()` is constructed inside `sendGif` on every invocation. Should reuse a shared
|
||||
client (like the one in `PushRegistrationManager`).
|
||||
|
||||
### SettingsScreen: new OkHttpClient per API-key test
|
||||
A new `OkHttpClient()` is created on every "Save" button press inside `SettingsScreen`. Leaks the connection
|
||||
pool after the composable is disposed.
|
||||
|
||||
### DeepLinkState: global singleton StateFlow — never clears on logout
|
||||
`DeepLinkState` is a process-level `object`. After logout/re-login the stale `pendingRoomId` can navigate
|
||||
the new session to the old room.
|
||||
|
||||
### PreferencesManager: `notificationsEnabled` default logic is inverted-looking
|
||||
`prefs[KEY_NOTIFICATIONS_ENABLED] != false` — treats missing key as `true` (desired), but any corruption
|
||||
storing a non-boolean type would also return `true`. Low risk but worth noting.
|
||||
|
||||
## Key File Paths
|
||||
- Push infra: `app/src/main/java/com/example/fluffytrix/push/`
|
||||
- ViewModel: `app/src/main/java/com/example/fluffytrix/ui/screens/main/MainViewModel.kt`
|
||||
- Settings UI: `app/src/main/java/com/example/fluffytrix/ui/screens/settings/SettingsScreen.kt`
|
||||
- DI: `app/src/main/java/com/example/fluffytrix/di/AppModule.kt`
|
||||
- Prefs: `app/src/main/java/com/example/fluffytrix/data/local/PreferencesManager.kt`
|
||||
Reference in New Issue
Block a user