# 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. ### Step 107 - Read-on-visible + cross-device unread sync - Implemented read acknowledgement from actual visible messages in `ChatScreen`: - tracks visible `LazyColumn` rows and sends read up to max visible incoming message id. - unread now drops as messages appear on screen while scrolling. - Improved cross-device sync (web <-> android): - `message_read` realtime event now parses `user_id` and `last_read_message_id`. - on `message_read`, Android refreshes chat snapshot from backend to keep unread counters aligned across devices. ### Step 108 - Strict read boundary by visible incoming only - Removed fallback read-pointer advancement in `ChatViewModel.acknowledgeLatestMessages(...)` that previously moved `lastReadMessageId` by latest loaded message id. - Read pointer is now advanced only via `onVisibleIncomingMessageId(...)` from visible incoming rows in `ChatScreen`. - This prevents read acknowledgements from overshooting beyond what user actually saw during refresh/recompose scenarios. ### Step 109 - Telegram-like Settings/Profile visual refresh - Redesigned `SettingsScreen` to Telegram-inspired dark card layout: - profile header card with avatar/name/email/username, - grouped settings rows with material icons, - appearance controls (Light/Dark/System), - quick security/help sections and preserved logout/back actions. - Redesigned `ProfileScreen` to Telegram-inspired structure: - gradient hero header with centered avatar, status, and action buttons, - primary profile info card, - tab-like section (`Posts/Archived/Gifts`) with placeholder content, - inline edit card (name/username/bio/avatar URL) with existing save/upload behavior preserved.