mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-24 06:40:37 -04:00
163 lines
6.1 KiB
Markdown
163 lines
6.1 KiB
Markdown
# `:feature:docs`
|
|
|
|
## Overview
|
|
|
|
The `:feature:docs` module is an **in-app documentation browser** with Compose Multiplatform UI. It bundles the Meshtastic user guide and developer guide as Compose resources at build time, provides full-text keyword search, Crowdin-backed multilingual content, optional ML Kit runtime translation (Google Play flavor), and a "Chirpy" AI Q&A assistant (Gemini Nano on Google Play; keyword fallback on F-Droid / Desktop / iOS).
|
|
|
|
**Targets:** Android · JVM (Desktop) · iOS (via `meshtastic.kmp.feature` convention plugin)
|
|
|
|
## Key Responsibilities
|
|
|
|
- Bundle `docs/en/user/**/*.md` and `docs/en/developer/**/*.md` as Compose resources at build time
|
|
- Sync Crowdin-translated locales into `composeResources/files/{locale}/docs/`
|
|
- Keyword search (TF-IDF style) across the full doc bundle
|
|
- Locale-aware content loading with Crowdin → ML Kit fallback chain
|
|
- Adaptive list/detail layout (single pane on phones, split pane on tablets/desktop)
|
|
- Chirpy AI assistant: streaming Q&A against in-app docs via Gemini Nano or keyword fallback
|
|
|
|
## Source Structure
|
|
|
|
```
|
|
src/commonMain/kotlin/org/meshtastic/feature/docs/
|
|
├── ai/
|
|
│ ├── AIDocAssistant.kt ← interface (Gemini Nano / keyword fallback)
|
|
│ ├── ChirpySessionHolder.kt
|
|
│ └── KeywordFallbackAssistant.kt
|
|
├── data/
|
|
│ ├── DocBundleLoader.kt ← interface + DefaultDocBundleLoader
|
|
│ └── KeywordSearchEngine.kt ← TF-IDF keyword search
|
|
├── model/
|
|
│ └── DocModels.kt ← DocSection, DocPage, DocBundle, DocSearchResult, ...
|
|
├── navigation/
|
|
│ └── DocsNavigation.kt ← docsEntries(), ChirpyUiState, rememberChirpyState()
|
|
├── translation/
|
|
│ ├── DocTranslationService.kt ← ML Kit (Google) or no-op (fdroid/desktop/iOS)
|
|
│ ├── DocTranslationCache.kt
|
|
│ ├── MarkdownTranslationSegmenter.kt
|
|
│ └── NoOpDocTranslator.kt
|
|
└── ui/
|
|
├── DocsBrowserScreen.kt ← list pane
|
|
├── DocsPageRouteScreen.kt ← detail pane
|
|
├── DocsSearchBar.kt
|
|
├── ChirpyAssistantSheet.kt ← AI assistant bottom sheet
|
|
├── ComposeResourceImageTransformer.kt
|
|
├── DocPageIconResolver.kt
|
|
└── DocsPreviews.kt
|
|
```
|
|
|
|
## Key Types
|
|
|
|
### `DocSection` (sealed interface)
|
|
|
|
```kotlin
|
|
sealed interface DocSection {
|
|
data object UserGuide : DocSection
|
|
data object DeveloperGuide : DocSection
|
|
}
|
|
```
|
|
|
|
### `DocPage`
|
|
|
|
```kotlin
|
|
data class DocPage(
|
|
val id: String,
|
|
val title: String,
|
|
val section: DocSection,
|
|
val navOrder: Int,
|
|
val resourcePath: String,
|
|
val keywords: List<String>,
|
|
val charCount: Int,
|
|
)
|
|
```
|
|
|
|
### `AIDocAssistant` (interface)
|
|
|
|
```kotlin
|
|
interface AIDocAssistant {
|
|
suspend fun isSupported(): Boolean
|
|
suspend fun answer(question: String, currentPageId: String? = null): AIDocAssistantResult
|
|
fun answerStream(question: String, currentPageId: String? = null): Flow<AIDocAssistantResult>
|
|
fun resetSession()
|
|
}
|
|
```
|
|
|
|
`AIDocAssistantResult` is a sealed interface: `Partial`, `Success`, `Fallback`, `Error`.
|
|
|
|
Platform bindings:
|
|
- **Google flavor**: Gemini Nano via on-device ML
|
|
- **F-Droid / Desktop / iOS**: `KeywordFallbackAssistant` (keyword search + summarisation, no network)
|
|
|
|
### `ChirpyMessage`
|
|
|
|
```kotlin
|
|
@Serializable
|
|
data class ChirpyMessage(
|
|
val id: String,
|
|
val role: ChirpyRole, // USER | ASSISTANT | SYSTEM
|
|
val text: String,
|
|
val sources: List<SourceRef>,
|
|
)
|
|
```
|
|
|
|
## Gradle Tasks
|
|
|
|
Two custom tasks keep bundled docs in sync:
|
|
|
|
| Task | Description |
|
|
|---|---|
|
|
| `syncDocsToComposeResources` | Copies `docs/en/user/**/*.md`, `docs/en/developer/**/*.md`, and `docs/screenshots/**/*.png` into `src/commonMain/composeResources/files/docs/`. Runs automatically before resource generation. |
|
|
| `syncTranslatedDocsToComposeResources` | Copies Crowdin-translated locales from `docs/{locale}/user/**/*.md` into `src/commonMain/composeResources/files/{locale}/docs/` using CMP qualifier format (e.g. `pt-rBR`). |
|
|
|
|
These tasks run automatically — no manual invocation is required during normal development.
|
|
|
|
## Navigation
|
|
|
|
Routes (registered under the Settings nav graph):
|
|
|
|
| Route | Description |
|
|
|---|---|
|
|
| `SettingsRoute.HelpDocs` | Doc browser list pane |
|
|
| `SettingsRoute.HelpDocPage` | Individual doc page detail pane |
|
|
|
|
The `docsEntries()` extension uses Material3 adaptive `ListDetailSceneStrategy` to automatically provide a split-pane layout on large screens.
|
|
|
|
## Dependency Graph
|
|
|
|
```
|
|
feature:docs
|
|
├── core:common, core:navigation, core:resources, core:ui, core:di
|
|
├── coil (image loading in Markdown)
|
|
├── markdown-renderer-m3 (Compose Markdown rendering)
|
|
├── compose.material3.adaptive, compose.material3.adaptive.navigation3
|
|
└── kotlinx.collections.immutable
|
|
```
|
|
|
|
## Dependency Graph
|
|
|
|
<!--region graph-->
|
|
```mermaid
|
|
graph TB
|
|
:feature:docs[docs]:::kmp-feature
|
|
:feature:docs -.-> :core:common
|
|
:feature:docs -.-> :core:navigation
|
|
:feature:docs -.-> :core:resources
|
|
:feature:docs -.-> :core:ui
|
|
:feature:docs -.-> :core:di
|
|
:feature:docs -.-> :core:testing
|
|
|
|
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef compose-desktop-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef kmp-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef kmp-library-compose fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
|
|
|
|
```
|
|
<!--endregion-->
|