mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-16 02:34:57 -04:00
docs: Update specs and governance for Android M3 accessibility (#5392)
This commit is contained in:
124
.github/copilot-instructions.md
vendored
124
.github/copilot-instructions.md
vendored
@@ -1,5 +1,7 @@
|
||||
# Meshtastic Android — Copilot Instructions
|
||||
|
||||
> **Full rules**: `AGENTS.md` is the source of truth. This file is a compact quick-reference for build commands and task naming. For architecture, conventions, and workflow details, consult `AGENTS.md` and the `.skills/` playbooks listed at the bottom.
|
||||
|
||||
## Build, Test & Lint
|
||||
|
||||
**Requires:** JDK 21, `ANDROID_HOME` set, proto submodule initialized.
|
||||
@@ -42,118 +44,20 @@ KMP modules have different task names than pure-Android modules. Using the wrong
|
||||
- ❌ `:feature:connections:testDebugUnitTest` — ambiguous in KMP modules. Use `:feature:connections:allTests`.
|
||||
- ❌ `:feature:connections:compileFdroidDebugKotlin` — wrong for KMP. Use `:feature:connections:compileKotlinJvm` or `kmpSmokeCompile`.
|
||||
|
||||
## Architecture
|
||||
## Quick Reference
|
||||
|
||||
**Kotlin Multiplatform** project targeting Android, Desktop (JVM), and iOS. Business logic lives in `commonMain`; platform shells (`app/`, `desktop/`) wire DI and host UI.
|
||||
- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`app/`, `desktop/`) wire DI and host UI. See `AGENTS.md` and `.skills/kmp-architecture/`.
|
||||
- **Flavors**: `fdroid` (OSS) / `google` (Maps + DataDog). Only one installable at a time (different signing keys).
|
||||
- **Verify before push**: Run `./gradlew spotlessApply detekt assembleDebug test allTests`, then confirm CI with `gh pr checks <PR>`.
|
||||
- **Strings**: `stringResource(Res.string.key)` — run `python3 scripts/sort-strings.py` after adding strings.
|
||||
- **Icons**: `MeshtasticIcons` (from `core/ui/icon/`), not `material.icons.Icons`.
|
||||
- **Error handling**: `safeCatching {}` (not `runCatching {}`) in coroutine code.
|
||||
- **Dispatchers**: `org.meshtastic.core.common.util.ioDispatcher`, not `Dispatchers.IO`.
|
||||
- **Navigation**: `MeshtasticNavDisplay` + `NavigationBackHandler` (not Android `BackHandler`).
|
||||
- **Protos**: `core/proto/` is a read-only git submodule. Never modify proto files.
|
||||
- **Branches**: Must start with `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`, `test/`, `deps/`, or a numeric spec prefix. Always branch off `origin/main`.
|
||||
|
||||
### Module layers
|
||||
|
||||
| Layer | Modules | Role |
|
||||
|-------|---------|------|
|
||||
| Host | `app`, `desktop` | Platform shell, Koin root, theme |
|
||||
| Feature | `feature/*` | Self-contained screens (KMP, `meshtastic.kmp.feature` plugin) |
|
||||
| Core | `core/*` | Shared logic, data, networking, UI components |
|
||||
|
||||
### Key technologies
|
||||
|
||||
- **UI:** Compose Multiplatform + Material 3 Adaptive
|
||||
- **Navigation:** JetBrains Navigation 3 (`@Serializable sealed interface` routes in `core:navigation`)
|
||||
- **DI:** Koin 4.2+ with K2 Compiler Plugin (`@Module`, `@KoinViewModel`, `startKoin<AndroidKoinApp>`)
|
||||
- **Networking:** Ktor (no OkHttp)
|
||||
- **BLE:** Kable (via `core:ble`)
|
||||
- **Database:** Room KMP
|
||||
- **I/O:** Okio
|
||||
- **Build:** Gradle Kotlin DSL with convention plugins in `build-logic/`
|
||||
- **Flavors:** `fdroid` (OSS) / `google` (Maps + DataDog)
|
||||
|
||||
### Navigation pattern
|
||||
|
||||
Feature navigation graphs are extension functions on `EntryProviderScope<NavKey>` in `commonMain`. The host shell renders via `MeshtasticNavDisplay`. Use `NavigationBackHandler` (not Android's `BackHandler`).
|
||||
|
||||
## Key Conventions
|
||||
|
||||
### Source-set boundaries
|
||||
|
||||
- **`commonMain`** — All business logic, ViewModels, UI. No `java.*` or `android.*` imports.
|
||||
- **`androidMain`** — Android framework integration only. No business logic.
|
||||
- **`jvmMain` / `jvmAndroidMain`** — Shared JVM code (Android + Desktop).
|
||||
- Platform capabilities: prefer interface + DI over `expect`/`actual`.
|
||||
|
||||
### Strings & formatting
|
||||
|
||||
- All strings in `core/resources/src/commonMain/composeResources/values/strings.xml`
|
||||
- Use `stringResource(Res.string.key)` — never hardcoded strings.
|
||||
- CMP only supports `%N$s` (string) and `%N$d` (int) — pre-format floats with `NumberFormatter.format()`.
|
||||
- Run `python3 scripts/sort-strings.py` after adding strings.
|
||||
|
||||
### Error handling
|
||||
|
||||
- Use `safeCatching {}` (from `core:common`) instead of `runCatching {}` in suspend/coroutine code — `runCatching` swallows `CancellationException`.
|
||||
|
||||
### Dispatchers
|
||||
|
||||
- Use `org.meshtastic.core.common.util.ioDispatcher` — never `Dispatchers.IO` directly.
|
||||
- Inject `CoroutineDispatchers` from `core:di`.
|
||||
|
||||
### Build-logic
|
||||
|
||||
- Convention plugins: `meshtastic.kmp.feature`, `meshtastic.kmp.library`, `meshtastic.kmp.jvm.android`, `meshtastic.koin`
|
||||
- Use `libs.library("alias-name")` string-based lookups (not type-safe accessors) in convention plugins.
|
||||
- Prefer lazy Gradle configuration (`configureEach`, `withPlugin`, provider APIs).
|
||||
|
||||
### Icons
|
||||
|
||||
- Use `MeshtasticIcons` (from `core/ui/icon/`) instead of `material.icons.Icons`.
|
||||
|
||||
### Protos
|
||||
|
||||
- `core/proto/` is a **read-only git submodule** from `meshtastic/protobufs`. Never modify proto files.
|
||||
|
||||
### Design standards
|
||||
|
||||
- All UI must conform to the [Meshtastic Client Design Standards](https://raw.githubusercontent.com/meshtastic/design/refs/heads/master/standards/meshtastic_design_standards_latest.md).
|
||||
- Review new screens/significant UI changes against the standards before merge.
|
||||
|
||||
### Branch naming
|
||||
|
||||
Branches must start with: `bugfix/`, `enhancement/`, `dependencies/`, or `repo/`.
|
||||
|
||||
### Branching workflow
|
||||
|
||||
- `origin` = `meshtastic/Meshtastic-Android` (upstream, source of truth). Personal forks are typically behind.
|
||||
- Always create branches off fetched upstream: `git fetch origin && git checkout -b <name> origin/main`
|
||||
- Never branch from a personal fork's `main` — it may be stale.
|
||||
|
||||
### Push workflow (verify-then-push)
|
||||
|
||||
**Before push:**
|
||||
```bash
|
||||
./gradlew spotlessApply detekt assembleDebug test allTests # or targeted module tasks
|
||||
```
|
||||
Only push when the above passes locally.
|
||||
|
||||
**After push:**
|
||||
```bash
|
||||
gh pr checks <PR_NUMBER> # or: gh run list --branch <branch> --limit 3
|
||||
```
|
||||
Report CI status only after fetching actual results. Never say "CI should be green now" — check and confirm.
|
||||
|
||||
### Scope discipline
|
||||
|
||||
When a working branch grows beyond ~5 logical commits or starts spanning unrelated concerns, proactively propose:
|
||||
1. A fresh branch off `origin/main`
|
||||
2. Cherry-pick only the high-impact, low-blast-radius changes
|
||||
3. Defer tangential work to follow-up PRs
|
||||
|
||||
Don't pile unrelated changes onto an existing branch. Squash fixup commits before pushing.
|
||||
|
||||
### Multi-flavor device installs
|
||||
|
||||
Two app flavors exist: `com.geeksville.mesh` (fdroid) and `com.geeksville.mesh.google` (google). Only one can be installed at a time (different signing keys). When switching flavors on a device:
|
||||
- Uninstall the other flavor first, or the install will fail silently.
|
||||
- Be aware that uninstalling loses onboarding state, permissions, and bonded-device data. Ask before uninstalling if the user has an active session.
|
||||
|
||||
## Deeper guidance
|
||||
## Deeper Guidance
|
||||
|
||||
Consult `.skills/` for detailed playbooks:
|
||||
- `.skills/project-overview/` — Full codebase map and bootstrap
|
||||
|
||||
Reference in New Issue
Block a user