3.5 KiB
App Module
Single Activity architecture. MainActivity is the sole entry point.
Navigation
LibreChatNavHost (in this module) is the Android-specific entry point. It wraps the shared module's LibreChatNavHost via a content lambda, adding:
- Deep link handling (
librechat://conversation/{conversationId}) - Share intent routing (navigates to NewChat if not already on a chat screen)
- Tablet layout branching based on
WindowSizeClass
The shared module owns the core navigation: Navigator, NavHostViewModel, MainNavDisplay, PhoneLayout, sidebar/drawer composables, and all feature entry providers. See shared/CLAUDE.md for details.
Layout Modes
- Phone: Delegates to shared
PhoneLayout—ModalNavigationDrawersidebar-first pattern. - Tablet (600dp+ width): Uses
TabletLayout(Android-only, in this module) — persistent side panel with swipe gesture andBackHandler.
Feature modules provide entries via EntryProviderScope<NavKey> extensions (e.g., authEntries(), chatEntries()). Navigation is driven by onNavigate: (NavKey) -> Unit and onBack: () -> Unit lambdas — feature modules never receive NavBackStack directly.
Android-Only Files in This Module
LibreChatNavHost.kt— Thin wrapper adding deep links, share intents, and tablet/phone branchingTabletLayout.kt— Persistent sidebar withBackHandler,android.net.Uri, and custom swipe gesture
Top-Level Destinations
Top-level routes: NewChat (Chat), Conversations, AgentMarketplace (Agents), Files, SettingsTabbed (Settings).
Conversations are integrated into the drawer body. Agents, Files, and Settings are accessible via drawer footer links. All routes are registered in the shared MainNavDisplay entry provider.
Auth & Session
NavHostViewModel(in shared) observes auth state viaisLoggedInflow- Start destination is
NewChatif logged in,ServerUrlotherwise sessionExpiredflow triggers nav to auth flow with full back stack clear- Drawer gestures are hidden during auth flow
Deep Linking
- Scheme:
librechat://conversation/{conversationId} - Handled in
MainActivity.handleDeepLink()and forwarded to this module'sLibreChatNavHost onNewIntenthandles deep links when app is already running
Connectivity
ConnectivityObserverinjected intoMainActivity- Offline banner animates in/out at top of screen when connection is lost
Dependencies
This module depends on :shared, all :core:*, and all :feature:* modules.
It applies convention plugins: librechat.mobile.application, librechat.mobile.compose, librechat.mobile.koin.
Server Banners
NavHostViewModel(shared) fetches banners fromBannerRepositoryon init, filters expired viadisplayFrom/displayTowithInstant.parse()- Dismissed banner IDs tracked in-memory via
dismissedBannerIds: StateFlow<Set<String>>(session-scoped, not persisted) BannerDisplaycomposable shown at top of content in bothPhoneLayout(shared) andTabletLayout(app)- Banner types: "info" (blue), "warning" (amber), "error" (red) — defaults to "info" if type is null
- Gotcha:
displayFrom/displayToare ISO 8601 strings parsed withInstant.parse()— wrap inrunCatchingsince the format from the server is not guaranteed
Preset Navigation
PresetManagerroute registered inSettingsNavigation.ktPresetManagerScreenaccessible from Settings → Chat section- Navigation wired through shared
MainNavDisplayentry provider, accessible from both phone and tablet layouts