Chat notifications (production-ready)
- ChatDeeplinkService: resolves client chat ID from incoming push/WS payloads using the (senderId, chatId) matrix and switches selectedDeviceProvider when the payload references a different watch (multi-device deeplink)
- IncomingChatResolver in domain layer with full unit coverage of the 4-case matrix
- ChatContext provider (sealed: outsideChat / list / conversation) wired into ChatListScreen and ChatConversationScreen via initState/dispose to enable WhatsApp-style suppression
- notifications_init refactor: foreground CHAT_MESSAGE notifications are suppressed on chat list and matching conversation; tap navigation goes through ChatDeeplinkService
- ChatSyncService.subscribeToReconnect: reconciles from REST when the WebSocket comes back from a disconnect (recovers messages missed in background)
- 5s message-id dedup window in the WS listener (mitigates server-side duplicate chat-message-received events)
- Reconcile from remote on conversation mount (covers cached controller from background)
- AppBar refresh button + inverted pull-to-refresh in the conversation (overscroll either edge of the reverse list)
WS event parser fix
- chat-message-received normalises to chat_message_received; parser now accepts both that and chat_message so the conversation reactively refreshes when a watch sends a message
Chat application layer
- Split the conversation controller into services: chat_send_service, chat_sync_service, chat_participants_service, chat_permission_flow_service, chat_media_cleanup_service
- chat_conversation_config centralises page size, polling interval, dedup window
- chat_bubble_shell extracted; input bar split into smaller widgets
- emoji picker sheet + emoji blocking input formatter + watch_emoji_catalog
- Multipart upload header race fixed via synchronized.Lock around the shared Dio instance
Videocall (carryover from earlier work in this branch)
- Application services: incoming, outgoing, session
- Domain entities: VideocallIncomingArgs, VideocallRoom, VideocallUserId, parseDeviceIdFromRoom helper
- Views split: idle, incoming, active call, group call
- Widgets: picture_in_picture_video, remote_or_fallback_video, video_call_header
- videocall_config centralises timeouts, ringing duration, battery threshold
- Incoming via push (channel mode) with full-screen notification + ringtone
- Hangup-on-remote-left moved to controller; redirect on participant update documented
- treezor_token_interceptor: distinguish session expiry from operation-denied 401s
Localization & misc
- New keys for chat conversation, refresh, errors across en/es/de/fr/it/pt
- Location map: dispose ref-after-unmount fix; route history layer cleanup
- Legacy device view model: position update event handling
- AndroidManifest: notification channel + permissions for incoming-call full-screen intent
- Skip login when SDK client is already logged in (early return with isSdkReady)
- Set isSdkReady immediately when login() returns true instead of waiting for async callback
- Add ref.mounted check after userInfo future to prevent state updates on disposed provider
- Logout VideocallClient on session clear to prevent stale SDK sessions
- Use getActiveCallItem() in onCallItemUpdate for fresh call state (matches JC demo app)
- Wire VIDEO_CALL_REQUEST/CANCEL/REFUSE/ROOM_COUNT commands via CommandsRepository
- Add VideocallChatType enum (single/multi) with chatType stored in state
- Implement auto-login to Juphoon SDK using sanitized email + user UUID
- Add runtime camera/microphone permissions before call start
- Add RetryInterceptor for transient TLS/socket errors in Dio
- Migrate VideocallItem to Freezed with isTalking extension
- Implement startGroupCall/leaveGroupCall using ChannelService with participant grid
- Add PopScope to intercept back navigation during active calls
- Redesign idle screen with device option cards and group call button
- Redesign active call UI with video overlay, PiP local view, and new controls layout
- Clean up SDK wrapper: remove unused streams, merge destroy+dispose into shutdown
- Add i18n keys for videocall UI across 6 locales
- Replace setState with FutureBuilder in VideoViewWidget
- Remove comments from datasource impl
- Replace GetIt.I with ref.read(provider) in controllers
- Fix state comparison using isTalking getter
- Add hangUp/stopAudio/stopCamera cleanup on dispose
- Remove duplicate SafeArea from IncomingCallOverlay
- Add missedCall error event to enum
- Replace Colors.white70 with theme colorScheme
- Move VIDEOCALL_INTEGRATION.md to apps/mobile_app/docs/
- Gitignore config JSON files with app keys
- Add 28 i18n keys in 6 locales for all videocall strings
- Map error events to specific i18n messages
- Rename ViewModel → Controller, ViewState → State with @riverpod codegen
- Move state/ → providers/ folder for consistency
- Add post-init device configuration (camera, speaker, maxCallNum, mediaConfig)
- Use MediaConfig.generateByMode based on device capabilities.system (rtos/android)
- Add CallParam.ticket for smartwatch wake-up protocol
- Start audio/camera before call, stop on hangup
- Granular video management based on uploadVideoStreamSelf/Other flags
- Build watch userId from device.imei (w_ prefix)
- Add imei field to DeviceEntity
- Add system field to DeviceCapabilitiesEntity with isRtos/isAndroid helpers
Merges videocall stash, resolves conflicts with installed_apps routes,
and refactors UI to match current legacy patterns:
- Replace themePortProvider with context.sfColors and Theme.of(context)
- Replace showTopSnackbar with feedback dialogs
- Replace hardcoded colors with theme-aware colorScheme
- Wrap test login button in kDebugMode
- Rename error enum values to be more descriptive
Add LegacyLoadingIndicator widget using a transparent GIF animation
for all full-page loading states across legacy modules. Also fix
HealthController crash by deferring provider mutation during build.