Files
Messenger/android/CHANGELOG.md
Codex d54eb400c7
Some checks failed
Android CI / android (push) Has started running
Android Release / release (push) Has been cancelled
CI / test (push) Has been cancelled
android: fix unread ack to use latest visible message
2026-03-09 23:25:20 +03:00

709 lines
44 KiB
Markdown
Raw 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.
# Android Changelog
## 2026-03-08
### Step 1 - Build and app wiring
- Added Android project plugin configuration for Hilt and Kotlin serialization.
- Added dependency repositories and explicit app module include in settings.
- Added app dependencies for Retrofit/OkHttp, DataStore, coroutines, Hilt, and unit testing.
- Enabled INTERNET permission and registered MessengerApplication in manifest.
- Added MessengerApplication with HiltAndroidApp.
### Step 2 - Network/data core + DI
- Fixed DTO/Auth API serialization annotations and endpoint declarations for `/api/v1/auth/login`, `/api/v1/auth/refresh`, `/api/v1/auth/me`.
- Implemented DataStore-based token persistence with a corrected `getTokens()` read path.
- Added auth network stack: bearer interceptor, 401 authenticator with refresh flow and retry guard.
- Added clean-layer contracts and implementations: `domain/common`, `domain/auth`, `data/auth/repository`.
- Wired dependencies with Hilt modules for DataStore, OkHttp/Retrofit, and repository bindings.
### Step 3 - Minimal auth UI and navigation
- Replaced Phase 0 placeholder UI with Compose auth flow (`AuthViewModel` + login screen).
- Added loading/error states for login and startup session restore.
- Added navigation graph: `AuthGraph (login)` to placeholder `Chats` screen after successful auth.
- Implemented automatic session restore on app start using stored tokens.
### Step 4 - Unit tests
- Added `DataStoreTokenRepositoryTest` for token save/read and clear behavior.
- Added `NetworkAuthRepositoryTest` for login success path and 401 -> `InvalidCredentials` error mapping.
### Step 5 - Chat Room models and persistence core
- Added domain chat model (`ChatItem`) for chat list rendering concerns.
- Added Room entities: `chats`, `users_short` with sort-friendly indices.
- Added `ChatDao` with `observeChats()`, `upsertChats()`, and transactional `clearAndReplaceChats()`.
- Added `MessengerDatabase` and Hilt database wiring (`DatabaseModule`).
### Step 6 - Chat API and repository sync
- Added chat REST API client for `/api/v1/chats` and `/api/v1/chats/{chat_id}`.
- Added chat DTOs and remote/local mappers (`ChatReadDto -> ChatEntity/UserShortEntity -> ChatItem`).
- Implemented `NetworkChatRepository` with cache-first flow strategy (Room first, then server sync).
- Added chat domain contracts/use-cases (`ChatRepository`, observe/refresh use-cases).
- Wired chat API/repository via Hilt modules.
### Step 7 - Realtime manager and chat list updates
- Added a unified realtime manager abstraction and WebSocket implementation for `/api/v1/realtime/ws?token=...`.
- Implemented auto-reconnect with exponential backoff and max cap.
- Added realtime event parser for `receive_message`, `message_updated`, `message_deleted`, `chat_updated`, `chat_deleted`, `user_online`, `user_offline`.
- Added use-case level realtime event handling that updates Room and triggers repository refreshes when needed.
- Wired realtime manager into DI.
### Step 8 - Chat list UI and navigation
- Added Chat List screen with tabs (`All` / `Archived`), local search filter, pull-to-refresh, and state handling (loading/empty/error).
- Added chat row rendering for unread badge, mention badge (`@`), pinned/muted marks, and message preview by media type.
- Added private chat presence display (`online` / `last seen recently` fallback).
- Connected Chat List to ViewModel/use-cases with no business logic inside composables.
- Added chat click navigation to placeholder `ChatScreen(chatId)`.
### Step 9 - Tests and checklist updates
- Added unit test for chat cache-first sync strategy (`NetworkChatRepositoryTest`).
- Added unit test for realtime event parsing (`RealtimeEventParserTest`).
- Added DAO test (`ChatDaoTest`) using in-memory Room + Robolectric.
- Updated Android checklist status in `docs/android-checklist.md`.
### Step 10 - Build stabilization fixes
- Switched Android API base URL to `https://chat.daemonlord.ru/`.
- Added cleartext traffic flag in manifest for local/dev compatibility.
- Fixed Hilt dependency cycle by separating refresh `AuthApiService` with a dedicated qualifier.
- Added `CoroutineDispatcher` DI provider and qualifier for repositories.
- Fixed Material3 experimental API opt-in and removed deprecated `StateFlow.distinctUntilChanged()` usage.
### Step 11 - Sprint A / 1) Message Room + models
- Added message domain model (`MessageItem`) for chat screen rendering.
- Added Room entities `messages` and `message_attachments` with chat-history indexes.
- Added `MessageDao` with observe/pagination/upsert/delete APIs.
- Updated `MessengerDatabase` schema to include message tables and DAO.
- Added Hilt DI provider for `MessageDao`.
### Step 12 - Sprint A / 2) Message API + repository
- Added message REST API client for history/send/edit/delete endpoints.
- Added message DTOs and mappers (`MessageReadDto -> MessageEntity -> MessageItem`).
- Added `MessageRepository` contracts/use-cases for observe/sync/pagination/send/edit/delete.
- Implemented `NetworkMessageRepository` with cache-first observation and optimistic text send.
- Wired message API and repository into Hilt modules.
### Step 13 - Sprint A / 3) Message realtime integration
- Extended realtime event model/parser with message-focused events (`message_delivered`, `message_read`, `typing_start`, `typing_stop`) and richer message payload mapping.
- Updated unified realtime handler to write `receive_message`, `message_updated`, `message_deleted` into `messages` Room state.
- Added delivery/read status updates in Room for message status events.
- Kept chat list sync updates in the same manager/use-case pipeline for consistency.
### Step 14 - Sprint A / 4) Message UI core
- Replaced chat placeholder with a real message screen route + ViewModel.
- Added message list rendering with Telegram-like bubble alignment and status hints.
- Added input composer with send flow, reply/edit modes, and inline action cancellation.
- Added long-press actions (`reply`, `edit`, `delete`) for baseline message operations.
- Added manual "load older" pagination trigger and chat back navigation integration.
### Step 15 - Sprint A / 5) Message tests and docs
- Added unit tests for `NetworkMessageRepository` sync/send flows.
- Added DAO test for message scoped replace behavior in Room.
- Expanded realtime parser tests with rich `receive_message` mapping coverage.
- Updated `docs/android-checklist.md` for completed message-core items.
### Step 16 - Sprint B / 1-2) Media data layer + chat integration
- Added media API/DTO layer for upload URL and attachment creation.
- Added `MediaRepository` + `UploadAndAttachMediaUseCase` and network implementation with presigned PUT upload.
- Extended `MessageRepository` with media send flow (`sendMediaMessage`) and optimistic local update behavior.
- Wired media API/repository through Hilt modules.
- Integrated file picking and media sending into Android `ChatScreen`/`ChatViewModel` with upload state handling.
### Step 17 - Sprint B / media tests
- Added `NetworkMediaRepositoryTest` for successful upload+attach flow.
- Added error-path coverage for failed presigned upload handling.
## 2026-03-09
### Step 18 - Sprint P0 / 1) Message core completion
- Extended message API/data contracts with `messages/status`, `forward`, and reaction endpoints.
- Added message domain support for forwarded message metadata and attachment waveform payload.
- Implemented repository operations for delivery/read acknowledgements, forward, and reactions.
- Updated Chat ViewModel/UI with forward flow, reaction toggle, and edit/delete-for-all edge-case guards.
- Added automatic delivered/read acknowledgement for latest incoming message in active chat.
- Fixed outgoing message detection by resolving current user id from JWT `sub` claim.
### Step 19 - Sprint P0 / 2) Media UX after send
- Added media endpoint mapping for chat attachments (`GET /api/v1/media/chats/{chat_id}/attachments`).
- Extended Room message observation to include attachment relations via `MessageLocalModel`.
- Synced and persisted message attachments during message refresh/pagination and after media send.
- Extended message domain model with attachment list payload.
- Added message attachment rendering in Chat UI: inline image preview, minimal image viewer overlay, and basic audio play/pause control.
### Step 20 - Sprint P0 / 3) Roles/permissions baseline
- Extended chat data/domain models with `my_role` and added `observeChatById` stream in Room/repository.
- Added `ObserveChatUseCase` to expose per-chat permission state to message screen.
- Implemented channel send restrictions in `ChatViewModel`: sending/attach disabled for `member` role in `channel` chats.
- Added composer-level restriction hint in Chat UI to explain blocked actions.
### Step 21 - Sprint P0 / 4) Invite join flow (minimum)
- Added chat API contracts for invite actions: `POST /api/v1/chats/{chat_id}/invite-link` and `POST /api/v1/chats/join-by-invite`.
- Added domain model/use-cases for invite-link creation and join-by-invite.
- Extended chat repository with invite operations and local chat upsert on successful join.
- Added minimal Chat List UI flow for join-by-invite token input with loading/error handling and auto-open of joined chat.
### Step 22 - Sprint P0 / 5) Realtime stability and reconcile
- Added heartbeat in WebSocket manager (`ping` interval + `pong` timeout detection) with forced reconnect on stale link.
- Improved socket lifecycle hygiene by cancelling heartbeat on close/failure/disconnect paths.
- Added `connect` event mapping and centralized reconcile trigger in realtime handler.
- On realtime reconnect, chat repository now refreshes `all` and `archived` snapshots to reduce stale state after transient disconnects.
### Step 23 - Sprint P0 / 6) Auth hardening foundation
- Extended auth API/repository contracts with sessions management endpoints:
- `GET /api/v1/auth/sessions`
- `DELETE /api/v1/auth/sessions/{jti}`
- `DELETE /api/v1/auth/sessions`
- Added domain model and use-cases for listing/revoking sessions.
- Added unit coverage for session DTO -> domain mapping in `NetworkAuthRepositoryTest`.
### Step 24 - Sprint P0 / 7) Quality pass
- Added realtime parser unit coverage for `connect` event mapping.
- Extended message DAO tests with attachment relation verification.
- Added Android smoke and baseline document (`docs/android-smoke.md`) with test matrix and performance targets.
- Updated Android checklist quality section with initial performance baseline completion.
### Step 25 - UI safe insets fix
- Enabled edge-to-edge mode in `MainActivity` via `enableEdgeToEdge()`.
- Added safe area insets handling (`WindowInsets.safeDrawing`) for login, chat list, session-check and chat screens.
- Added bottom composer protection in chat screen with `navigationBarsPadding()` and `imePadding()`.
- Fixed UI overlap with status bar and navigation bar on modern Android devices.
### Step 26 - Core base / bulk forward foundation
- Added message API/data contracts for bulk forward (`POST /api/v1/messages/{message_id}/forward-bulk`).
- Extended `MessageRepository` with `forwardMessageBulk(...)`.
- Implemented bulk-forward flow in `NetworkMessageRepository` with Room/chat last-message updates.
- Added `ForwardMessageBulkUseCase` for future multi-select message actions.
- Updated message repository unit test fakes to cover new API surface.
### Step 27 - Core base / message action state machine
- Added reusable `MessageActionState` reducer with explicit selection modes (`NONE`, `SINGLE`, `MULTI`).
- Added action-intent contract for message operations (reply/edit/forward/delete/reaction/clear).
- Integrated `ChatViewModel` with reducer-backed selection logic while preserving current UI behavior.
- Added base ViewModel handlers for entering/toggling multi-select mode (`onEnterMultiSelect`, `onToggleMessageMultiSelection`, `onClearSelection`).
- Added unit tests for reducer transitions and available intents (`MessageActionStateTest`).
### Step 28 - Core base / Android multi-forward execution
- Switched chat forward state from single-message payload to `forwardingMessageIds` set.
- Extended `ChatViewModel` forward flow: multi-select now forwards multiple source messages in one action.
- Wired `ForwardMessageBulkUseCase` for multi-message forwarding (sequential safe execution with error short-circuit).
- Updated chat action bar and forward sheet labels for multi-selection count.
### Step 29 - Core base / multi-select delete execution
- Fixed multi-select delete behavior in `ChatViewModel`: `Delete` now applies to all selected messages, not only focused one.
- Added explicit guard for `Delete for all` in multi-select mode (single-message only).
### Step 30 - Core base / reply-forward preview data foundation
- Extended message DTO/Room/domain models with optional preview metadata:
- `replyPreviewText`, `replyPreviewSenderName`
- `forwardedFromDisplayName`
- sender profile fields from API payload (`senderDisplayName`, `senderUsername`, `senderAvatarUrl`)
- Added Room self-relation in `MessageLocalModel` to resolve reply preview fallback from referenced message.
- Updated message mappers and repository/realtime temporary entity creation for new model fields.
- Bumped Room schema version to `7`.
### Step 31 - Chat UI / reply-forward bubble blocks
- Added inline forwarded header rendering in message bubbles with display-name fallback.
- Added inline reply preview block in message bubbles (author + snippet) based on new preview fields/fallbacks.
- Updated Telegram UI batch-2 checklist items for reply-preview and forwarded header.
### Step 32 - Chat UI / pinned message bar
- Added `pinned_message_id` support in chat DTO/local/domain models and DAO selects.
- Extended `ChatViewModel` state with pinned message id + resolved pinned message object.
- Rendered pinned message bar under chat app bar with hide action.
- Updated Telegram UI batch-2 checklist item for pinned message block.
### Step 33 - Chat UI / top app bar restructuring
- Extended chat UI state with resolved chat header fields (`chatTitle`, `chatSubtitle`, `chatAvatarUrl`).
- Updated chat top app bar layout to Telegram-like structure: back, avatar, title, status, call action, menu action.
- Kept load-more behavior accessible via menu placeholder action button.
- Updated Telegram UI batch-2 checklist item for chat top app bar.
### Step 34 - Chat UI / composer restyling
- Reworked chat composer into rounded Telegram-like container with emoji slot, text input, attach button, and send/voice state button.
- Preserved send/upload state guards and existing insets handling (`navigationBarsPadding` + `imePadding`).
- Updated Telegram UI batch-2 checklist composer-related items.
### Step 35 - Chat UI / multi-select bars and overlays
- Split message selection UX into dedicated top selection bar (count/close/delete/edit/reactions) and bottom action bar (reply/forward).
- Enhanced selected bubble visual state with explicit selected marker text.
- Updated Telegram UI batch-2 checklist items for multi-select mode.
### Step 36 - Chat list / advanced states baseline
- Added chat-list local type filters (`All`, `People`, `Groups`, `Channels`) with new `ChatListFilter` UI state.
- Added archive statistics stream in `ChatListViewModel` and special archive top-row entry in `All` tab.
- Extended list preview formatting with media-type markers and retained unread/mention/pinned indicators.
- Updated Telegram UI checklists for chat-list advanced states (batch 2 and batch 3).
### Step 37 - Chat UI / wallpaper-aware readability
- Added gradient wallpaper-like chat background layer in `ChatScreen`.
- Kept pinned/composer/action surfaces on semi-transparent containers to preserve readability over wallpaper.
- Updated Telegram UI checklist items for wallpaper and overlay readability.
### Step 38 - Quality/docs / mapper fallback coverage
- Added `MessageMappersTest` to verify reply preview fallback resolution from Room self-relation (`reply_to_message_id`).
- Updated Android master checklist for completed chat list tabs/filters coverage.
### Step 39 - Android scope / remove calls UI
- Removed chat top-bar `Call` action from Android `ChatScreen`.
- Updated Android UI checklist wording to reflect chat header without calls support.
### Step 40 - Invite deep link flow (app links)
- Added Android App Links intent filter for `https://chat.daemonlord.ru/join...`.
- Added invite token extraction from incoming intents (`query token` and `/join/{token}` path formats).
- Wired deep link token into `MessengerNavHost -> ChatListRoute -> ChatListViewModel` auto-join flow.
- Removed manual `Invite token` input row from chat list screen.
### Step 41 - Chat UI / long-press action menu
- Added long-press message action card in `ChatScreen` with quick reactions.
- Added context actions from long-press: reply, edit, forward, delete, select, close.
- Added placeholder disabled pin action in the menu to keep action set consistent with Telegram-like flow.
- Updated Telegram UI batch-2 checklist items for long-press reactions and context menu.
### Step 42 - Chat list / row and FAB parity pass
- Updated chat list rows with avatar rendering, trailing message time, and richer right-side metadata layout.
- Kept unread/mention/pinned/muted indicators while aligning row structure closer to Telegram list pattern.
- Added floating compose FAB placeholder at bottom-right in chat list screen.
- Updated Telegram UI batch-2 checklist chat-list parity items.
### Step 43 - Chat list / floating bottom navigation shell
- Added floating rounded bottom navigation container on chat list screen.
- Added active tab visual state (Chats selected) with pill styling.
- Updated Telegram UI checklists for bottom-nav shell parity (batch 1 and batch 2).
### Step 44 - Chat UI / bubble density pass
- Updated message bubble shapes for incoming/outgoing messages to denser rounded Telegram-like contours.
- Kept bottom-right time + delivery state rendering in bubble footer after time formatting update.
- Updated Telegram UI batch-2 checklist item for message bubble parity.
### Step 45 - Chat UI / media bubble improvements
- Added richer video attachment card rendering in message bubbles.
- Added file-list style attachment rows (icon + filename + type/size metadata).
- Upgraded non-voice audio attachment player with play/pause, progress bar, and current/total duration labels.
- Updated Telegram UI batch-2 checklist media-bubble items.
### Step 46 - Media viewer / header and gallery navigation
- Upgraded chat image viewer to use global image gallery state (`index / total`) instead of a single URL.
- Added fullscreen viewer header with close, index, share placeholder, and delete placeholder actions.
- Added image navigation controls (`Prev`/`Next`) for gallery traversal.
- Updated Telegram UI batch-2 checklist for fullscreen media header support.
### Step 47 - Notifications foundation (FCM + channels + deep links)
- Added Firebase Messaging dependency and Android manifest wiring for `POST_NOTIFICATIONS`.
- Added notification channels (`messages`, `mentions`, `system`) with startup initialization in `MessengerApplication`.
- Added push service (`MessengerFirebaseMessagingService`) + payload parser + notification dispatcher.
- Added notification tap deep-link handling to open target chat from `MainActivity` via nav host.
- Added runtime notification permission request flow (Android 13+) in `MessengerNavHost`.
- Added parser unit test (`PushPayloadParserTest`).
### Step 48 - Foreground local notifications from realtime
- Added `ActiveChatTracker` to suppress local notifications for currently opened chat.
- Wired realtime receive-message handling to trigger local notification via `NotificationDispatcher` when chat is not active.
- Added chat title lookup helper in `ChatDao` for notification titles.
- Added explicit realtime stop in `ChatViewModel.onCleared()` to avoid stale collectors.
### Step 49 - Mention override for muted chats
- Extended realtime receive-message model/parsing with `isMention` flag support.
- Added muted-chat guard in realtime notification flow: muted chats stay silent unless message is a mention.
- Routed mention notifications to mentions channel/priority via `NotificationDispatcher`.
- Added parser unit test for mention-flag mapping.
### Step 50 - Notification settings storage (DataStore)
- Added domain notification settings models/repository contracts (global + per-chat override).
- Added `DataStoreNotificationSettingsRepository` with persistence for global flags and per-chat override mode.
- Added `ShouldShowMessageNotificationUseCase` and wired realtime notifications through it.
- Added unit tests for DataStore notification settings repository and notification visibility use case.
### Step 51 - Logout with full local cleanup
- Added `LogoutUseCase` with centralized sign-out flow: disconnect realtime, clear active chat, clear auth session, and clear local cached data.
- Added `SessionCleanupRepository` + `DefaultSessionCleanupRepository` to wipe Room tables and clear per-chat notification overrides.
- Added logout action in chat list UI and wired it to `AuthViewModel`, with automatic navigation back to login via auth state.
- Added unit tests for logout use case orchestration and notification override cleanup.
### Step 52 - Settings/Profile shell and logout relocation
- Added dedicated `Settings` and `Profile` routes/screens with mobile-safe insets and placeholder content.
- Removed direct logout action from chat list and moved logout action to `Settings`.
- Wired bottom navigation pills in chats to open `Settings` and `Profile`.
### Step 53 - Secure token storage (Keystore-backed)
- Added `EncryptedPrefsTokenRepository` backed by `EncryptedSharedPreferences` and Android `MasterKey` (Keystore).
- Switched DI token binding from DataStore token repository to encrypted shared preferences repository.
- Kept DataStore for non-token app settings and renamed preferences file to `messenger_preferences.preferences_pb`.
### Step 54 - Message interactions: tap menu vs long-press select
- Updated chat message gesture behavior to match Telegram pattern:
- tap opens contextual message menu with reactions/actions,
- long-press enters multi-select mode directly.
- Hid single-selection action bars while contextual menu is visible to avoid mixed UX states.
- Improved multi-select visual affordance with per-message selection indicator circles.
### Step 55 - Chat multi-select action cleanup
- Removed duplicate forward action in multi-select mode (`Forward selected`), leaving a single clear forward action button.
### Step 56 - Unified API error handling
- Added shared API error mapper (`ApiErrorMapper`) with mode-aware mapping (`DEFAULT`, `LOGIN`).
- Switched auth/chat/message/media repositories to a single `Throwable -> AppError` mapping source.
- Kept login-specific invalid-credentials mapping while standardizing unauthorized/server/network handling for other API calls.
### Step 57 - Offline-first message history reading
- Added paged local history reading path by introducing configurable message observe limit (`observeMessages(chatId, limit)`).
- Updated chat screen loading strategy to expand local Room-backed history first when loading older messages.
- Added network-failure fallback in message sync/load-more: if network is unavailable but local cache exists, chat remains readable without blocking error.
### Step 58 - Keep authenticated session when offline at app start
- Updated auth restore flow in `AuthViewModel`: network errors during session restore no longer force logout when local tokens exist.
- App now opens authenticated flow in offline mode instead of redirecting to login.
### Step 59 - Deferred message action queue (send/edit/delete)
- Added Room-backed pending action queue (`pending_message_actions`) for message operations that fail due to network issues.
- Implemented enqueue + optimistic behavior for `sendText`, `editMessage`, and `deleteMessage` on network failures.
- Added automatic pending-action flush on chat sync/load-more and before new message operations.
- Kept non-network server failures as immediate errors (no queueing), while allowing offline continuation.
### Step 60 - Media cache foundation (Coil + Exo cache)
- Added global Coil image loader cache policy in `MessengerApplication` (memory + disk cache).
- Added Media3 `SimpleCache` singleton module for media stream/file caching foundation.
- Added Media3/Coil core dependencies and configured cache sizes for mobile usage.
### Step 61 - Compose UI tests baseline
- Added instrumented Compose UI tests for login and chat list states.
- Added Android test dependencies for Compose test runner (`ui-test-junit4`) and test infra.
- Covered key visual states: auth error rendering, chat list loading state, and empty state.
### Step 62 - Android CI pipeline
- Added dedicated Android CI workflow for `main` branch and PRs.
- CI now runs Android build, unit tests, lint, and androidTest assemble.
- Added optional detekt execution step (auto-skipped when detekt task is not configured).
### Step 63 - Integration tests for auth/chat/realtime
- Kept repository-level integration coverage for auth/chat data flows (MockWebServer + in-memory storage).
- Added `RealtimePipelineIntegrationTest` to validate realtime event handling pipeline (`receive_message` -> Room state update).
- Consolidated quality checklist integration test coverage for auth/chat/realtime.
### Step 64 - Android release workflow
- Added dedicated release workflow (`.github/workflows/android-release.yml`) for `main` branch pushes.
- Adapted version extraction for Kotlin DSL (`android/app/build.gradle.kts`) and guarded release by existing git tag.
- Wired release build, git tag push, and Gitea release publication with APK artifact upload.
### Step 65 - Account and media parity foundation (checklist 1-15)
- Introduced `:core:common` module and moved base `AppError`/`AppResult` contracts out of `:app`.
- Added structured app logging (`Timber`) and crash reporting baseline (`Firebase Crashlytics`) with app startup wiring.
- Added API version header interceptor + build-time feature flags and DI provider.
- Added account network layer for auth/account management:
- verify email, password reset request/reset,
- sessions list + revoke one/all,
- 2FA setup/enable/disable + recovery status/regenerate,
- profile/privacy update and blocked users management.
- Added deep-link aware auth routes for `/verify-email` and `/reset-password`.
- Reworked Settings/Profile screens from placeholders to editable account management screens.
- Added avatar upload with center square crop (`1:1`) before upload.
- Upgraded message attachment rendering with in-bubble multi-image gallery and unified attachment context actions (open/copy/close).
### Step 66 - Voice recording controls + global audio focus
- Added microphone permission (`RECORD_AUDIO`) and in-chat voice recording flow based on press-and-hold gesture.
- Implemented Telegram-like gesture controls for voice button:
- hold to record,
- slide up to lock recording,
- slide left to cancel recording.
- Added minimum voice length validation (`>= 1s`) before sending.
- Integrated voice message sending via existing media upload path (`audio/mp4` attachment).
- Added process-wide audio focus coordinator to enforce single active audio source:
- attachment player pauses when another source starts,
- recording requests focus and stops competing playback.
### Step 67 - Group/channel management baseline in Chat List
- Extended chat API/repository layer with management operations:
- create group/channel,
- discover + join/leave chats,
- invite link create/regenerate,
- members/bans listing and admin actions (add/remove/ban/unban/promote/demote).
- Added domain models for discover/member/ban items and repository mappings.
- Added in-app management panel in `ChatListScreen` (FAB toggle) for:
- creating group/channel,
- joining discovered chats,
- loading chat members/bans by chat id,
- executing admin/member visibility actions from one place.
### Step 68 - Search, inline jump, theme toggle, accessibility pass
- Added global search baseline in chat list:
- users search (`/users/search`),
- messages search (`/messages/search`),
- chat discovery integration (`/chats/discover`).
- Added inline search in chat screen with jump navigation (prev/next) and automatic scroll to matched message.
- Added highlighted message state for active inline search result.
- Added theme switching controls in settings (Light/Dark/System) via `AppCompatDelegate`.
- Added accessibility refinements for key surfaces and controls:
- explicit content descriptions for avatars and tab-like controls,
- voice record button semantic label for TalkBack.
### Step 69 - Bugfix pass: voice recording, theme apply, profile avatar UX
- Fixed voice recording start on Android by switching `VoiceRecorder` to compatible `MediaRecorder()` initialization.
- Fixed microphone permission flow: record action now triggers runtime permission request reliably and auto-starts recording after grant.
- Fixed theme switching application by introducing app-level `MessengerTheme` and switching app manifest base theme to DayNight.
- Fixed profile screen usability after avatar upload:
- enabled vertical scrolling with safe insets/navigation padding,
- constrained avatar preview to a centered circular area instead of full-screen takeover.
### Step 70 - Chat interaction consistency: gestures + sheets/dialogs
- Reworked single-message actions to open in `ModalBottomSheet` (tap action menu) instead of inline action bars.
- Reworked forward target chooser to `ModalBottomSheet` for consistent overlay behavior across chat actions.
- Added destructive action confirmation via `AlertDialog` before delete actions.
- Reduced gesture conflicts by removing attachment-level long-press handlers that collided with message selection gestures.
- Improved voice hold gesture reliability by handling consumed pointer down events (`requireUnconsumed = false`).
### Step 71 - Voice playback waveform/speed + circle video playback
- Added voice-focused audio playback mode with waveform rendering in message bubbles.
- Added playback speed switch for voice messages (`1.0x -> 1.5x -> 2.0x`).
- Added view-only circle video renderer for `video_note` messages with looped playback.
- Kept regular audio/video attachment rendering for non-voice/non-circle media unchanged.
### Step 72 - Adaptive layout baseline (phone/tablet) + voice release fix
- Added tablet-aware max-width layout constraints across major screens (login, verify/reset auth, chats list, chat, profile, settings).
- Kept phone layout unchanged while centering content and limiting line width on larger displays.
- Fixed voice hold-to-send gesture reliability by removing pointer-input restarts during active recording, so release consistently triggers send path.
### Step 73 - Voice message send/playback bugfixes
- Fixed voice media type mapping in message repository: recorded files with `voice_*.m4a` are now sent as message type `voice` (not generic `audio`).
- Fixed audio replay behavior: when playback reaches the end, next play restarts from `0:00`.
- Improved duration display in audio/voice player by adding metadata fallback when `MediaPlayer` duration is not immediately available.
### Step 74 - UI references consolidation (Batch 4)
- Added full Telegram reference mapping checklist (`docs/android-ui-batch-4-checklist.md`) with screenshot-by-screenshot description.
- Added explicit icon policy: no emoji icons in production UI components, Material Icons/vector icons only.
- Updated UI checklist index with Batch 4 entry.
### Step 75 - Material Icons migration (Batch 1 start)
- Replaced symbol/emoji-based UI controls in chat surfaces with Material Icons:
- chat header/menu/search controls (`more`, `up/down`),
- image viewer actions (`close`, `forward`, `delete`),
- multi-select markers (`radio checked/unchecked`, `selected` check),
- attachment/media markers (`movie`, `attach file`).
- Replaced chat list management FAB glyph toggle (`+`/`×`) with Material `Add`/`Close` icons.
- Added `androidx.compose.material:material-icons-extended` dependency for consistent icon usage.
### Step 76 - Shared main tabs shell with scroll-aware visibility
- Moved `Chats / Contacts / Settings / Profile` bottom panel to a shared navigation shell (`AppNavGraph`) so it behaves as global page navigation.
- Added dedicated `Contacts` page route and wired it into main tabs.
- Removed local duplicated bottom panel from chat list screen.
- Implemented scroll-direction behavior for all 4 main pages:
- hide panel on downward scroll,
- show panel on upward scroll / at top.
### Step 77 - Main tabs bar UX/layout fix
- Replaced custom pill-row main bar with compact `NavigationBar` inside rounded container for stable 4-tab layout on small screens.
- Added bottom content paddings for `Chats/Contacts/Settings/Profile` pages so content is not obscured by the floating main bar.
- Raised chats management FAB offset to avoid overlap with the global bottom bar.
### Step 78 - Telegram-like bottom tabs visual tuning
- Tuned shared main bar visual style to better match Telegram references:
- rounded floating container with subtle elevation,
- unified selected/unselected item colors,
- stable 4-item navigation with icons + labels.
- Kept scroll-hide/show behavior and page-level navigation unchanged.
### Step 79 - Main pages app bars + safe-area pass
- Added top app bars for all 4 main pages (`Chats`, `Contacts`, `Settings`, `Profile`) to make them feel like proper standalone sections.
- Moved chats management toggle action into chats app bar.
- Kept safe-area handling and bottom insets consistent with shared floating tabs bar to avoid overlap.
### Step 80 - Top bar offset consistency fix
- Unified top bar alignment across `Chats`, `Contacts`, `Settings`, and `Profile`:
- removed extra outer paddings that shifted headers down/right on some pages,
- separated content padding from top app bar container.
- Result: consistent title baseline and horizontal alignment between main pages.
### Step 81 - Chats bottom gap fix when tabs bar hidden
- Fixed blank gap at the bottom of chats list when global tabs bar auto-hides on scroll.
- Chats screen bottom padding is now dynamic and applied only while tabs bar is visible.
### Step 82 - Chats list header closer to Telegram reference
- Removed `Archived` top tab from chats list UI.
- Added search action in top app bar and unified single search field with leading search icon.
- Kept archive as dedicated row inside chats list; opening archive now happens from that row and back navigation appears in app bar while archive is active.
### Step 83 - Chats header realtime connection status
- Added realtime connection state stream (`Disconnected/Connecting/Reconnecting/Connected`) to `RealtimeManager`.
- Wired websocket lifecycle into that state in `WsRealtimeManager`.
- Bound chats top bar title to realtime state:
- shows `Connecting...` while reconnect/initial connect is in progress,
- shows regular page title once connected.
### Step 84 - Chats list preview icon policy cleanup
- Updated chat last-message preview text to remove emoji prefixes.
- Switched media-type preview prefixes to plain text labels (`Photo`, `Video`, `Voice`, etc.) to match Material-icons-only UI policy.
### Step 85 - Unread counter fix for active/read chats
- Added `ChatDao.markChatRead(chatId)` to clear `unread_count` and `unread_mentions_count` in Room.
- Applied optimistic local unread reset on `markMessageRead(...)` in message repository.
- Fixed realtime unread logic: incoming messages in currently active chat no longer increment unread badge.
### Step 86 - Chats list visual pass toward Telegram reference
- Updated chats list row density: tighter vertical rhythm, larger avatar, stronger title hierarchy, cleaner secondary text.
- Restyled archive as dedicated list row with leading archive icon avatar, subtitle, and unread badge.
- Kept search in top app bar action and changed search field default to collapsed (opens via search icon).
- Returned message-type emoji markers in chat previews:
- `🖼` photo, `🎤` voice, `🎵` audio, `🎥` video, `⭕` circle video, `🔗` links.
### Step 87 - Chats list micro-typography and time formatting
- Refined chat row typography hierarchy to be closer to Telegram density:
- title/body/presence font scale aligned and single-line ellipsis for long values.
- Tightened unread/mention badge sizing and spacing for compact right-side metadata.
- Updated trailing time formatter:
- today: `HH:mm`,
- this week: localized short weekday,
- older: `dd.MM.yy`.
### Step 88 - Chats list interaction states (menu/select/search)
- Added default overflow menu (`⋮`) state in chats header with Telegram-like quick actions UI.
- Added long-press multi-select mode for chat rows with:
- top selection bar (`count`, action icons),
- dedicated overflow menu for selected chats.
- Added dedicated search-mode state in chats screen:
- search field + section chips (`Chats/Channels/Apps/Posts`),
- horizontal recent avatars strip,
- list filtered by active query.
### Step 89 - Chats actions wiring + duplicate menu fix
- Removed duplicated overflow action in chats top bar (single `⋮` remains in default mode).
- Wired selection actions to behavior:
- delete selected -> leave selected chats,
- archive selected -> switch to archived section,
- non-implemented bulk actions now show explicit user feedback.
- Wired default menu actions:
- create group/channel -> open management panel,
- saved -> open saved chat if present,
- unsupported items show clear feedback instead of silent no-op.
### Step 90 - Fullscreen chats search redesign (Telegram-like)
- Reworked chats search mode into a fullscreen flow:
- top rounded search field with inline clear button,
- horizontal category chips (`Chats`, `Channels`, `Apps`, `Posts`),
- dedicated recent avatars row for the active category.
- Added search-mode content states:
- empty query -> `Recent` list block (history-style chat rows),
- non-empty query -> local matches + `Global search` and `Messages` sections.
- Kept search action in chats top bar; while search mode is active, app bar switches to back-navigation + empty title (content drives the page).
### Step 91 - Search history/recent persistence + clear action
- Added `ChatSearchRepository` abstraction and `DataStoreChatSearchRepository` implementation.
- Persisted chats search metadata in `DataStore`:
- recent opened chats list,
- search history list (bounded).
- Wired chats fullscreen search to persisted data:
- green recent avatars strip now reads saved recent chats,
- red `Recent` list now reads saved history with fallback.
- Connected `Очистить` action to real history cleanup in `DataStore`.
- On opening a chat from search results/messages/history, the chat is now stored in recent/history.
### Step 92 - Search filter leak fix on exit
- Fixed chats search state leak: leaving fullscreen search now resets local/global query.
- Main chats list no longer stays filtered by previous search input after returning from search mode.
### Step 93 - Fullscreen search UX polish
- Added system back-handler for search mode with safe query reset.
- Improved fullscreen search result sections:
- `Показать больше / Свернуть` toggle for global users,
- `Показать больше / Свернуть` toggle for message results.
- Added explicit empty-state text when local/global/message search sections all have no results.
### Step 94 - Pinned-only drag markers in selection mode
- Updated chats multi-select row UI: drag markers are now shown only for pinned chats.
- Non-pinned chats no longer render reorder marker in selection mode.
### Step 95 - Selection badge on avatar (Telegram-like)
- Added explicit selection indicator directly on chat avatars in multi-select mode:
- selected chat -> colored circle with check icon,
- unselected chat -> empty outlined circle.
- This matches the reference behavior and makes selected rows easier to scan.
### Step 96 - Selection menu labels and behavior polish
- Updated multi-select top actions/menu to be closer to Telegram reference in wording.
- Added dynamic `Закрепить/Открепить` label in selection overflow based on selected chats pinned state.
- Kept non-supported actions explicit with user feedback (Toast), avoiding silent no-op behavior.
### Step 97 - Chats popup/select actions wired to backend API
- Extended Android chat data layer with missing parity endpoints:
- `archive/unarchive`
- `pin-chat/unpin-chat`
- `clear`
- `delete (for_all=false)`
- `chat notifications get/update`
- Added repository methods and `ViewModel` actions for those operations.
- Replaced chats multi-select UI stubs with real API calls:
- mute/unmute selected chats,
- archive/unarchive selected chats,
- pin/unpin selected chats,
- clear selected chats,
- delete selected chats for current user.
### Step 98 - Realtime sync fix for pin/archive updates
- Improved `chat_updated` handling in realtime flow:
- now refreshes both active and archived chats lists to sync user-scoped flags (`pinned`, `archived`) immediately.
- Added parser fallback for realtime chat events to support payloads with either `chat_id` or `id`.
### Step 99 - Saved chat API parity
- Added Android support for `GET /api/v1/chats/saved`.
- Wired chats overflow `Saved` action to real backend request (instead of local title heuristic).
- Saved chat is now upserted into local Room cache and opened via normal navigation flow.
### Step 100 - Android image compression before upload
- Added pre-upload image compression in Android media pipeline (`NetworkMediaRepository`).
- For non-GIF images:
- decode + resize with max side `1920`,
- re-encode as `image/jpeg` with quality `82`,
- keep original bytes if compression does not reduce payload size.
- Upload request and attachment metadata now use actual prepared payload (`fileName`, `fileType`, `fileSize`), matching web behavior.
### Step 101 - Chat title/profile API parity
- Added Android API integration for:
- `PATCH /api/v1/chats/{chat_id}/title`
- `PATCH /api/v1/chats/{chat_id}/profile`
- Extended `ChatRepository`/`NetworkChatRepository` with `updateChatTitle(...)` and `updateChatProfile(...)`.
- Wired these actions into the existing Chat Management panel:
- edit selected chat title,
- edit selected chat profile fields (title/description).
### Step 102 - Global search + message thread parity
- Added Android data-layer integration for unified backend global search:
- `GET /api/v1/search`
- new `SearchRepository` + `SearchApiService` returning `users/chats/messages`.
- Switched chats fullscreen search flow to use unified backend search instead of composed per-domain calls.
- Extended message data layer with:
- `GET /api/v1/messages/{message_id}/thread`
- `MessageRepository.getMessageThread(...)` for thread/replies usage in upcoming UI steps.
### Step 103 - Contacts API parity + real Contacts screen
- Added Android integration for contacts endpoints:
- `GET /api/v1/users/contacts`
- `POST /api/v1/users/{user_id}/contacts`
- `POST /api/v1/users/contacts/by-email`
- `DELETE /api/v1/users/{user_id}/contacts`
- Extended `AccountRepository` + `NetworkAccountRepository` with contacts methods.
- Replaced placeholder Contacts screen with real stateful flow (`ContactsViewModel`):
- load contacts from backend,
- user search + add contact,
- add contact by email,
- remove contact,
- loading/refresh/error/info states.
### Step 104 - Push token sync (Android + backend)
- Added backend push token lifecycle API and storage:
- `POST /api/v1/notifications/push-token`
- `DELETE /api/v1/notifications/push-token`
- new table `push_device_tokens` (+ Alembic migration `0027_push_device_tokens`).
- Added Android push token sync manager:
- registers FCM token on app start and after auth refresh/login,
- updates backend token on `FirebaseMessagingService.onNewToken`,
- unregisters token on logout.
- Added backend FCM delivery in Celery notification tasks:
- sends to registered user device tokens,
- auto-removes invalid/unregistered tokens,
- safe fallback logs when Firebase is not configured.
### Step 105 - Web Firebase push registration
- Added web-side Firebase Messaging bootstrap (env-driven, no hardcoded secrets):
- fetch web push token and register in backend via `/notifications/push-token`,
- unregister token on logout,
- handle foreground push payload via existing notification service worker.
- Added required env keys to `web/.env.example` and backend Firebase env keys to root `.env.example`.
### Step 106 - Unread counter stabilization in Chat screen
- Fixed read acknowledgement strategy in `ChatViewModel`:
- read status is now acknowledged by the latest visible message id in chat (not only latest incoming),
- delivery status still uses latest incoming message.
- This removes cases where unread badge reappears after chat list refresh because the previous read ack used an outdated incoming id.