mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-18 11:46:28 -04:00
refactor(build): rename entry modules and remove DESKTOP_ONLY mode (#5476)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
4
.github/copilot-instructions.md
vendored
4
.github/copilot-instructions.md
vendored
@@ -18,7 +18,7 @@ git submodule update --init
|
||||
./gradlew :core:data:allTests
|
||||
|
||||
# Single module tests (Android-only module like :app)
|
||||
./gradlew :app:testFdroidDebugUnitTest
|
||||
./gradlew :androidApp:testFdroidDebugUnitTest
|
||||
|
||||
# Cross-platform compilation check (no tests)
|
||||
./gradlew kmpSmokeCompile
|
||||
@@ -46,7 +46,7 @@ KMP modules have different task names than pure-Android modules. Using the wrong
|
||||
|
||||
## Quick Reference
|
||||
|
||||
- **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/`.
|
||||
- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`androidApp/`, `desktopApp/`) 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.
|
||||
|
||||
@@ -5,7 +5,7 @@ excludeAgent: "code-review"
|
||||
|
||||
# CI Workflow Rules
|
||||
|
||||
- Prefer explicit Gradle task paths (`app:lintFdroidDebug`) over shorthand (`lintDebug`).
|
||||
- Prefer explicit Gradle task paths (`androidApp:lintFdroidDebug`) over shorthand (`lintDebug`).
|
||||
- CI uses `.github/ci-gradle.properties` — don't assume local `gradle.properties` values.
|
||||
- CI passes `-Pci=true` to enable full processor usage via `maxParallelForks`.
|
||||
- Use `fetch-depth: 0` only where needed (spotless ratcheting, version code). Use `fetch-depth: 1` otherwise.
|
||||
|
||||
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
@@ -8,10 +8,10 @@ on:
|
||||
- main
|
||||
paths:
|
||||
# Only rebuild docs when source code changes (Dokka generates from KDoc)
|
||||
- 'app/src/**'
|
||||
- 'androidApp/src/**'
|
||||
- 'core/**/src/**'
|
||||
- 'feature/**/src/**'
|
||||
- 'desktop/src/**'
|
||||
- 'desktopApp/src/**'
|
||||
- 'build-logic/**'
|
||||
- 'build.gradle.kts'
|
||||
- 'settings.gradle.kts'
|
||||
|
||||
10
.github/workflows/pull-request.yml
vendored
10
.github/workflows/pull-request.yml
vendored
@@ -30,9 +30,9 @@ jobs:
|
||||
- '.github/workflows/**'
|
||||
- '.github/actions/**'
|
||||
# Product modules validated by reusable-check
|
||||
- 'app/**'
|
||||
- 'androidApp/**'
|
||||
- 'baselineprofile/**'
|
||||
- 'desktop/**'
|
||||
- 'desktopApp/**'
|
||||
- 'core/**'
|
||||
- 'feature/**'
|
||||
- 'screenshot-tests/**'
|
||||
@@ -95,9 +95,9 @@ jobs:
|
||||
PY
|
||||
|
||||
# 2. VALIDATION & BUILD: Delegate to reusable-check.yml
|
||||
# We disable coverage for PRs to keep feedback fast (< 10 mins).
|
||||
# Desktop compilation is covered by :desktop:test in the shard-app test shard.
|
||||
# Native desktop packaging (createDistributable) only runs in release.yml.
|
||||
# We disable coverage and desktop builds for PRs to keep feedback fast
|
||||
# (< 10 mins). Desktop compilation is already covered by the :desktopApp:test
|
||||
# task in the shard-app test shard.
|
||||
validate-and-build:
|
||||
needs: check-changes
|
||||
if: needs.check-changes.outputs.android == 'true'
|
||||
|
||||
73
.github/workflows/release.yml
vendored
73
.github/workflows/release.yml
vendored
@@ -150,9 +150,9 @@ jobs:
|
||||
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
|
||||
GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
|
||||
run: |
|
||||
rm -f ./app/google-services.json
|
||||
echo $GSERVICES > ./app/google-services.json
|
||||
echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME
|
||||
rm -f ./androidApp/google-services.json
|
||||
echo $GSERVICES > ./androidApp/google-services.json
|
||||
echo $KEYSTORE | base64 -di > ./androidApp/$KEYSTORE_FILENAME
|
||||
echo "$KEYSTORE_PROPERTIES" > ./keystore.properties
|
||||
echo "datadogApplicationId=$DATADOG_APPLICATION_ID" >> ./secrets.properties
|
||||
echo "datadogClientToken=$DATADOG_CLIENT_TOKEN" >> ./secrets.properties
|
||||
@@ -172,14 +172,14 @@ jobs:
|
||||
run: bundle exec fastlane internal
|
||||
|
||||
- name: List outputs
|
||||
run: ls -R app/build/outputs/
|
||||
run: ls -R androidApp/build/outputs/
|
||||
|
||||
- name: Upload Google AAB artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: google-aab
|
||||
path: app/build/outputs/bundle/googleRelease/app-google-release.aab
|
||||
path: androidApp/build/outputs/bundle/googleRelease/androidApp-google-release.aab
|
||||
retention-days: 1
|
||||
|
||||
- name: Upload Google APK artifact
|
||||
@@ -187,20 +187,20 @@ jobs:
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: google-apk
|
||||
path: app/build/outputs/apk/google/release/*.apk
|
||||
path: androidApp/build/outputs/apk/google/release/*.apk
|
||||
retention-days: 1
|
||||
|
||||
- name: Attest Google AAB provenance
|
||||
if: success()
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: app/build/outputs/bundle/googleRelease/app-google-release.aab
|
||||
subject-path: androidApp/build/outputs/bundle/googleRelease/androidApp-google-release.aab
|
||||
|
||||
- name: Attest Google APK provenance
|
||||
if: success()
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: app/build/outputs/apk/google/release/*.apk
|
||||
subject-path: androidApp/build/outputs/apk/google/release/*.apk
|
||||
|
||||
release-fdroid:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -229,7 +229,7 @@ jobs:
|
||||
KEYSTORE_FILENAME: ${{ secrets.KEYSTORE_FILENAME }}
|
||||
KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }}
|
||||
run: |
|
||||
echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME
|
||||
echo $KEYSTORE | base64 -di > ./androidApp/$KEYSTORE_FILENAME
|
||||
echo "$KEYSTORE_PROPERTIES" > ./keystore.properties
|
||||
|
||||
- name: Setup Fastlane
|
||||
@@ -245,21 +245,21 @@ jobs:
|
||||
run: bundle exec fastlane fdroid_build
|
||||
|
||||
- name: List outputs
|
||||
run: ls -R app/build/outputs/
|
||||
run: ls -R androidApp/build/outputs/
|
||||
|
||||
- name: Upload F-Droid APK artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fdroid-apk
|
||||
path: app/build/outputs/apk/fdroid/release/*.apk
|
||||
path: androidApp/build/outputs/apk/fdroid/release/*.apk
|
||||
retention-days: 1
|
||||
|
||||
- name: Attest F-Droid APK provenance
|
||||
if: success()
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: app/build/outputs/apk/fdroid/release/*.apk
|
||||
subject-path: androidApp/build/outputs/apk/fdroid/release/*.apk
|
||||
|
||||
release-desktop:
|
||||
if: ${{ inputs.build_desktop }}
|
||||
@@ -307,13 +307,13 @@ jobs:
|
||||
# `-PaboutLibraries.release=true` as member access on `-PaboutLibraries`,
|
||||
# splitting the token and feeding `.release=true` to Gradle as a task name.
|
||||
run: >
|
||||
./gradlew :desktop:packageReleaseDistributionForCurrentOS
|
||||
${{ contains(runner.os, 'macOS') && ':desktop:packageReleaseUberJarForCurrentOS' || '' }}
|
||||
./gradlew :desktopApp:packageReleaseDistributionForCurrentOS
|
||||
${{ contains(runner.os, 'macOS') && ':desktopApp:packageReleaseUberJarForCurrentOS' || '' }}
|
||||
'-PaboutLibraries.release=true' --no-daemon
|
||||
|
||||
- name: List Desktop Binaries
|
||||
if: runner.os == 'Linux' || runner.os == 'macOS'
|
||||
run: ls -R desktop/build/compose/binaries/main-release
|
||||
run: ls -R desktopApp/build/compose/binaries/main-release
|
||||
|
||||
- name: Upload Desktop Artifacts
|
||||
if: always()
|
||||
@@ -321,13 +321,13 @@ jobs:
|
||||
with:
|
||||
name: desktop-${{ runner.os }}-${{ runner.arch }}
|
||||
path: |
|
||||
desktop/build/compose/binaries/main-release/*/*.dmg
|
||||
desktop/build/compose/binaries/main-release/*/*.msi
|
||||
desktop/build/compose/binaries/main-release/*/*.exe
|
||||
desktop/build/compose/binaries/main-release/*/*.deb
|
||||
desktop/build/compose/binaries/main-release/*/*.rpm
|
||||
desktop/build/compose/binaries/main-release/*/*.AppImage
|
||||
desktop/build/compose/jars/*-release.jar
|
||||
desktopApp/build/compose/binaries/main-release/*/*.dmg
|
||||
desktopApp/build/compose/binaries/main-release/*/*.msi
|
||||
desktopApp/build/compose/binaries/main-release/*/*.exe
|
||||
desktopApp/build/compose/binaries/main-release/*/*.deb
|
||||
desktopApp/build/compose/binaries/main-release/*/*.rpm
|
||||
desktopApp/build/compose/binaries/main-release/*/*.AppImage
|
||||
desktopApp/build/compose/jars/*-release.jar
|
||||
retention-days: 1
|
||||
if-no-files-found: ignore
|
||||
|
||||
@@ -336,13 +336,13 @@ jobs:
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: |
|
||||
desktop/build/compose/binaries/main-release/*/*.dmg
|
||||
desktop/build/compose/binaries/main-release/*/*.msi
|
||||
desktop/build/compose/binaries/main-release/*/*.exe
|
||||
desktop/build/compose/binaries/main-release/*/*.deb
|
||||
desktop/build/compose/binaries/main-release/*/*.rpm
|
||||
desktop/build/compose/binaries/main-release/*/*.AppImage
|
||||
desktop/build/compose/jars/*-release.jar
|
||||
desktopApp/build/compose/binaries/main-release/*/*.dmg
|
||||
desktopApp/build/compose/binaries/main-release/*/*.msi
|
||||
desktopApp/build/compose/binaries/main-release/*/*.exe
|
||||
desktopApp/build/compose/binaries/main-release/*/*.deb
|
||||
desktopApp/build/compose/binaries/main-release/*/*.rpm
|
||||
desktopApp/build/compose/binaries/main-release/*/*.AppImage
|
||||
desktopApp/build/compose/jars/*-release.jar
|
||||
|
||||
create-flatpak-src:
|
||||
if: ${{ inputs.build_flatpak_src }}
|
||||
@@ -370,22 +370,7 @@ jobs:
|
||||
gradle_encryption_key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
|
||||
cache_read_only: 'true'
|
||||
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install ast-grep
|
||||
run: pip install ast-grep-cli
|
||||
|
||||
# Remove Android/iOS targets and other non-desktop bits
|
||||
# that would break the flatpakGradleGenerator
|
||||
- name: Prepare Offline Desktop Build
|
||||
run: ./scripts/desktop-only-prep.sh
|
||||
|
||||
- name: Generate Flatpak Sources
|
||||
env:
|
||||
DESKTOP_ONLY: true
|
||||
run: >
|
||||
./gradlew :build-logic:convention:flatpakGradleGenerator flatpakGradleGenerator
|
||||
--no-configuration-cache --refresh-dependencies --no-parallel
|
||||
|
||||
92
.github/workflows/reusable-check.yml
vendored
92
.github/workflows/reusable-check.yml
vendored
@@ -94,7 +94,7 @@ jobs:
|
||||
|
||||
- name: Lint, Analysis & KMP Smoke Compile
|
||||
if: inputs.run_lint == true
|
||||
run: ./gradlew spotlessCheck detekt app:lintFdroidDebug app:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug core:api:lintDebug kmpSmokeCompile -Pci=true --continue --scan
|
||||
run: ./gradlew spotlessCheck detekt androidApp:lintFdroidDebug androidApp:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug core:api:lintDebug kmpSmokeCompile -Pci=true --continue --scan
|
||||
|
||||
- name: KMP Smoke Compile (lint skipped)
|
||||
if: inputs.run_lint == false
|
||||
@@ -152,13 +152,13 @@ jobs:
|
||||
# See: https://github.com/meshtastic/Meshtastic-Android/issues/3231
|
||||
|
||||
echo "── Step 1: Verify aboutlibraries.json determinism ──"
|
||||
rm -f app/src/main/resources/aboutlibraries.json
|
||||
./gradlew :app:exportLibraryDefinitions -Pci=true --no-configuration-cache
|
||||
cp app/src/main/resources/aboutlibraries.json /tmp/aboutlibraries-run1.json
|
||||
rm -f androidApp/src/main/resources/aboutlibraries.json
|
||||
./gradlew :androidApp:exportLibraryDefinitions -Pci=true --no-configuration-cache
|
||||
cp androidApp/src/main/resources/aboutlibraries.json /tmp/aboutlibraries-run1.json
|
||||
|
||||
rm -f app/src/main/resources/aboutlibraries.json
|
||||
./gradlew :app:exportLibraryDefinitions -Pci=true --no-configuration-cache --rerun-tasks
|
||||
cp app/src/main/resources/aboutlibraries.json /tmp/aboutlibraries-run2.json
|
||||
rm -f androidApp/src/main/resources/aboutlibraries.json
|
||||
./gradlew :androidApp:exportLibraryDefinitions -Pci=true --no-configuration-cache --rerun-tasks
|
||||
cp androidApp/src/main/resources/aboutlibraries.json /tmp/aboutlibraries-run2.json
|
||||
|
||||
if ! diff -q /tmp/aboutlibraries-run1.json /tmp/aboutlibraries-run2.json; then
|
||||
echo "::error::aboutlibraries.json is NOT deterministic across runs!"
|
||||
@@ -168,9 +168,9 @@ jobs:
|
||||
echo "✅ aboutlibraries.json is deterministic"
|
||||
|
||||
echo "── Step 2: Build fdroid release APK ──"
|
||||
./gradlew :app:assembleFdroidRelease -Pci=true -Pmeshtastic.disableAbiSplits=true --no-configuration-cache
|
||||
./gradlew :androidApp:assembleFdroidRelease -Pci=true -Pmeshtastic.disableAbiSplits=true --no-configuration-cache
|
||||
|
||||
APK=$(find app/build/outputs/apk/fdroid/release -name "*.apk" | head -1)
|
||||
APK=$(find androidApp/build/outputs/apk/fdroid/release -name "*.apk" | head -1)
|
||||
if [ -z "$APK" ]; then
|
||||
echo "::error::No fdroid release APK found"
|
||||
exit 1
|
||||
@@ -295,7 +295,7 @@ jobs:
|
||||
# Tests are split into 3 shards that run in parallel:
|
||||
# shard-core: core:* KMP module tests (allTests)
|
||||
# shard-feature: feature:* KMP module tests (allTests)
|
||||
# shard-app: Pure-Android/JVM tests (app, desktop, core:barcode, etc.)
|
||||
# shard-app: Pure-Android/JVM tests (androidApp, desktopApp, core:barcode, etc.)
|
||||
test-shards:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
@@ -359,17 +359,17 @@ jobs:
|
||||
:feature:settings:koverXmlReport
|
||||
- name: shard-app
|
||||
tasks: >-
|
||||
:app:testFdroidDebugUnitTest
|
||||
:app:testGoogleDebugUnitTest
|
||||
:desktop:test
|
||||
:androidApp:testFdroidDebugUnitTest
|
||||
:androidApp:testGoogleDebugUnitTest
|
||||
:desktopApp:test
|
||||
:core:barcode:testFdroidDebugUnitTest
|
||||
:core:barcode:testGoogleDebugUnitTest
|
||||
kover: >-
|
||||
:app:koverXmlReportFdroidDebug
|
||||
:app:koverXmlReportGoogleDebug
|
||||
:androidApp:koverXmlReportFdroidDebug
|
||||
:androidApp:koverXmlReportGoogleDebug
|
||||
:core:barcode:koverXmlReportFdroidDebug
|
||||
:core:barcode:koverXmlReportGoogleDebug
|
||||
:desktop:koverXmlReport
|
||||
:desktopApp:koverXmlReport
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -447,14 +447,14 @@ jobs:
|
||||
cache_read_only: ${{ needs.lint-check.outputs.cache_read_only }}
|
||||
|
||||
- name: Build Android APKs
|
||||
run: ./gradlew app:assembleFdroidDebug app:assembleGoogleDebug -Pci=true --parallel --configuration-cache --continue --scan
|
||||
run: ./gradlew androidApp:assembleFdroidDebug androidApp:assembleGoogleDebug -Pci=true --parallel --configuration-cache --continue --scan
|
||||
|
||||
- name: Upload debug artifact
|
||||
if: ${{ inputs.upload_artifacts }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: app-debug-apks
|
||||
path: app/build/outputs/apk/*/debug/*.apk
|
||||
path: androidApp/build/outputs/apk/*/debug/*.apk
|
||||
retention-days: 7
|
||||
|
||||
- name: Report App Size
|
||||
@@ -463,8 +463,47 @@ jobs:
|
||||
echo "### App Size Report" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Artifact | Size |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| --- | --- |" >> $GITHUB_STEP_SUMMARY
|
||||
find app/build/outputs/apk -name "*.apk" -exec du -h {} + | awk '{print "| " $2 " | " $1 " |"}' >> $GITHUB_STEP_SUMMARY
|
||||
find androidApp/build/outputs/apk -name "*.apk" -exec du -h {} + | awk '{print "| " $2 " | " $1 " |"}' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# ── Desktop Build ───────────────────────────────────────────────────
|
||||
build-desktop:
|
||||
name: Build Desktop Debug (${{ matrix.os }})
|
||||
if: inputs.run_desktop_builds == true
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
contents: read
|
||||
timeout-minutes: 60
|
||||
needs: lint-check
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-24.04, ubuntu-24.04-arm]
|
||||
env:
|
||||
VERSION_CODE: ${{ needs.lint-check.outputs.version_code }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
|
||||
- name: Gradle Setup
|
||||
uses: ./.github/actions/gradle-setup
|
||||
with:
|
||||
gradle_encryption_key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
|
||||
cache_read_only: ${{ needs.lint-check.outputs.cache_read_only }}
|
||||
|
||||
- name: Build Desktop
|
||||
run: ./gradlew :desktopApp:createDistributable -Pci=true --scan
|
||||
|
||||
- name: Upload Desktop artifact
|
||||
if: ${{ inputs.upload_artifacts }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: desktop-app-${{ runner.os }}-${{ runner.arch }}
|
||||
path: desktopApp/build/compose/binaries/main/app/
|
||||
retention-days: 7
|
||||
|
||||
# ── Flatpak Sources ───────────────────────────────────────────────────
|
||||
build-flatpak-src:
|
||||
@@ -494,23 +533,8 @@ jobs:
|
||||
with:
|
||||
gradle_encryption_key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
|
||||
cache_read_only: true
|
||||
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install ast-grep
|
||||
run: pip install ast-grep-cli
|
||||
|
||||
# Remove Android/iOS targets and other non-desktop bits
|
||||
# that would break the flatpakGradleGenerator
|
||||
- name: Prepare Offline Desktop Build
|
||||
run: ./scripts/desktop-only-prep.sh
|
||||
|
||||
- name: Generate Flatpak Sources
|
||||
env:
|
||||
DESKTOP_ONLY: true
|
||||
run: >
|
||||
./gradlew :build-logic:convention:flatpakGradleGenerator flatpakGradleGenerator
|
||||
--no-configuration-cache --refresh-dependencies --no-parallel
|
||||
|
||||
8
.github/workflows/scheduled-updates.yml
vendored
8
.github/workflows/scheduled-updates.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Update firmware releases list
|
||||
id: firmware
|
||||
run: |
|
||||
firmware_file_path="app/src/main/assets/firmware_releases.json"
|
||||
firmware_file_path="androidApp/src/main/assets/firmware_releases.json"
|
||||
temp_firmware_file="/tmp/new_firmware_releases.json"
|
||||
|
||||
echo "Fetching latest firmware releases..."
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
- name: Update hardware list
|
||||
id: hardware
|
||||
run: |
|
||||
hardware_file_path="app/src/main/assets/device_hardware.json"
|
||||
hardware_file_path="androidApp/src/main/assets/device_hardware.json"
|
||||
temp_hardware_file="/tmp/new_device_hardware.json"
|
||||
|
||||
echo "Fetching latest device hardware data..."
|
||||
@@ -172,8 +172,8 @@ jobs:
|
||||
base: 'main'
|
||||
delete-branch: true
|
||||
add-paths: |
|
||||
app/src/main/assets/firmware_releases.json
|
||||
app/src/main/assets/device_hardware.json
|
||||
androidApp/src/main/assets/firmware_releases.json
|
||||
androidApp/src/main/assets/device_hardware.json
|
||||
fastlane/metadata/android/**
|
||||
**/strings.xml
|
||||
**/README.md
|
||||
|
||||
@@ -23,8 +23,8 @@ When reviewing code, meticulously verify the following categories. Flag any devi
|
||||
- [ ] **Compose Multiplatform Resources:** Ensure NO hardcoded strings. Must use `core:resources` (e.g., `stringResource(Res.string.key)` or asynchronous `getStringSuspend(Res.string.key)` for ViewModels/Coroutines). NEVER use blocking `getString()` in a coroutine.
|
||||
- [ ] **String Formatting:** CMP only supports `%N$s` and `%N$d`. Flag any float formats (`%N$.1f`) in Compose string resources; they must be pre-formatted using `NumberFormatter.format()` from `core:common`. Use `MetricFormatter` for metric-specific displays (temperature, voltage, current, percent, humidity, pressure, SNR, RSSI).
|
||||
- [ ] **Centralized Dialogs & Alerts:** Flag inline alert-rendering logic. Mandate the use of `AlertHost(alertManager)` or `SharedDialogs` from `core:ui/commonMain`.
|
||||
- [ ] **Placeholders:** Require `PlaceholderScreen(name)` from `core:ui/commonMain` for unimplemented desktop/JVM features. No inline placeholders in feature modules.
|
||||
- [ ] **Adaptive Layouts:** Verify use of `currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)` to support desktop/tablet breakpoints (≥ 1200dp).
|
||||
- [ ] **Placeholders:** Require `PlaceholderScreen(name)` from `core:ui/commonMain` for unimplemented desktopApp/JVM features. No inline placeholders in feature modules.
|
||||
- [ ] **Adaptive Layouts:** Verify use of `currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)` to support desktopApp/tablet breakpoints (≥ 1200dp).
|
||||
|
||||
### 3. Navigation & State
|
||||
- [ ] **Shared Navigation Graphs:** Feature navigation graphs must be defined as extension functions on `EntryProviderScope<NavKey>` in `commonMain` (e.g., `fun EntryProviderScope<NavKey>.settingsGraph(...)`). Flag any graphs defined in platform-specific source sets.
|
||||
@@ -56,8 +56,8 @@ When reviewing code, meticulously verify the following categories. Flag any devi
|
||||
- [ ] **Robolectric Configuration:** Check that Compose UI tests running via Robolectric on JVM are pinned to `@Config(sdk = [34])` to prevent Java 21 / SDK 35 compatibility issues.
|
||||
|
||||
### 8. ProGuard / R8 Rules
|
||||
- [ ] **New Dependencies:** If a new reflection-heavy dependency is added (DI, serialization, JNI, ServiceLoader), verify keep rules exist in **both** `app/proguard-rules.pro` (R8) and `desktop/proguard-rules.pro` (ProGuard). The two files must stay aligned.
|
||||
- [ ] **Release Smoke-Test:** For dependency or ProGuard rule changes, verify `assembleRelease` and `./gradlew :desktop:runRelease` succeed.
|
||||
- [ ] **New Dependencies:** If a new reflection-heavy dependency is added (DI, serialization, JNI, ServiceLoader), verify keep rules exist in **both** `androidApp/proguard-rules.pro` (R8) and `desktopApp/proguard-rules.pro` (ProGuard). The two files must stay aligned.
|
||||
- [ ] **Release Smoke-Test:** For dependency or ProGuard rule changes, verify `assembleRelease` and `./gradlew :desktopApp:runRelease` succeed.
|
||||
|
||||
## Review Output Guidelines
|
||||
1. **Be Specific & Constructive:** Provide exact file references and code snippets illustrating the required project pattern.
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
Guidelines for building shared UI, adaptive layouts, and handling strings/resources in Meshtastic-Android. The codebase uses Material 3 Adaptive.
|
||||
|
||||
## 1. UI Components & Layouts
|
||||
- **Material 3 / Adaptive:** Use `currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)` to support Large (1200dp) and XL (1600dp) breakpoints. Investigate 3-pane "Power User" scenes using Navigation 3 Scenes and draggable dividers for desktop/tablets.
|
||||
- **Material 3 / Adaptive:** Use `currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)` to support Large (1200dp) and XL (1600dp) breakpoints. Investigate 3-pane "Power User" scenes using Navigation 3 Scenes and draggable dividers for desktopApp/tablets.
|
||||
- **Dialogs & Alerts:** Use centralized components like `AlertHost(alertManager)` from `core:ui/commonMain`. Do NOT trigger alerts inline or duplicate alert logic. Use `SharedDialogs(uiViewModel)` for general popups.
|
||||
- **Placeholders:** Use `PlaceholderScreen(name)` from `core:ui/commonMain` for unimplemented desktop/JVM features.
|
||||
- **Placeholders:** Use `PlaceholderScreen(name)` from `core:ui/commonMain` for unimplemented desktopApp/JVM features.
|
||||
- **Theme Picker:** Use `ThemePickerDialog` from `feature:settings/commonMain`.
|
||||
- **Platform Implementations:** Inject platform-specific behavior (e.g., Map providers) via `CompositionLocal` from the `app` or `desktop` shells. Do not tightly couple Google Maps/osmdroid dependencies to `commonMain`.
|
||||
|
||||
@@ -58,4 +58,4 @@ Choose the right tool for the job:
|
||||
## Reference Anchors
|
||||
- **Shared Strings:** `core/resources/src/commonMain/composeResources/values/strings.xml`
|
||||
- **Platform abstraction contract:** `core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/MapViewProvider.kt`
|
||||
- **Provider wiring:** `app/src/main/kotlin/org/meshtastic/app/MainActivity.kt`
|
||||
- **Provider wiring:** `androidApp/src/main/kotlin/org/meshtastic/app/MainActivity.kt`
|
||||
|
||||
@@ -35,7 +35,7 @@ A step-by-step workflow for implementing a new feature in the Meshtastic-Android
|
||||
```bash
|
||||
./gradlew spotlessCheck spotlessApply detekt assembleDebug test allTests
|
||||
```
|
||||
- If the feature adds a new reflection-heavy dependency, add keep rules to **both** `app/proguard-rules.pro` and `desktop/proguard-rules.pro`, then verify release builds:
|
||||
- If the feature adds a new reflection-heavy dependency, add keep rules to **both** `androidApp/proguard-rules.pro` and `desktopApp/proguard-rules.pro`, then verify release builds:
|
||||
```bash
|
||||
./gradlew assembleFdroidRelease :desktop:runRelease
|
||||
./gradlew assembleFdroidRelease :desktopApp:runRelease
|
||||
```
|
||||
|
||||
@@ -52,10 +52,10 @@ Guidelines on managing Kotlin Multiplatform (KMP) source-sets, expected abstract
|
||||
1. Ensure all new logic compiles against the KMP core (`jvm()`, `iosArm64()`, etc.).
|
||||
2. Do not use platform-specific constructs in `commonMain` or you break the iOS/Desktop builds.
|
||||
3. Test using `kmpSmokeCompile` to verify cross-platform compilation.
|
||||
4. For desktop wiring, copy the pattern in `desktop/src/main/kotlin/org/meshtastic/desktop/di/DesktopKoinModule.kt` and use `NoopStubs.kt` to temporarily mock missing platform implementations.
|
||||
4. For desktop wiring, copy the pattern in `desktopApp/src/main/kotlin/org/meshtastic/desktop/di/DesktopKoinModule.kt` and use `NoopStubs.kt` to temporarily mock missing platform implementations.
|
||||
|
||||
## Reference Anchors
|
||||
- **Shared Okio I/O:** `core/domain/src/commonMain/kotlin/org/meshtastic/core/domain/usecase/settings/ImportProfileUseCase.kt`
|
||||
- **Desktop DI Stubs:** `desktop/src/main/kotlin/org/meshtastic/desktop/stub/NoopStubs.kt`
|
||||
- **Desktop DI Stubs:** `desktopApp/src/main/kotlin/org/meshtastic/desktop/stub/NoopStubs.kt`
|
||||
- **Version Catalog:** `gradle/libs.versions.toml`
|
||||
- **Convention Plugins:** `build-logic/convention/`
|
||||
|
||||
@@ -7,7 +7,7 @@ This skill covers dependency injection (Koin Annotations 4.2.x) and JetBrains Na
|
||||
|
||||
### Guidelines
|
||||
1. **Annotations First:** Use `@Module`, `@ComponentScan`, and `@KoinViewModel` annotations directly in `commonMain` shared modules to encapsulate dependency graphs per feature.
|
||||
2. **App Root Assembly:** Don't assume feature/core `@Module` classes are active automatically. Ensure they are included by the app root module (`@Module(includes = [...])`) in `app/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt` and `desktop/.../DesktopKoinModule.kt`.
|
||||
2. **App Root Assembly:** Don't assume feature/core `@Module` classes are active automatically. Ensure they are included by the app root module (`@Module(includes = [...])`) in `androidApp/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt` and `desktopApp/.../DesktopKoinModule.kt`.
|
||||
3. **No Platform Bleed:** Don't put Android framework dependencies (`Context`, `Activity`, `Application`) into shared `commonMain` business logic. Inject interfaces instead.
|
||||
4. **Resolution:** Resolve app-layer wrappers via `koinViewModel()` or injected bindings within Compose navigation graphs.
|
||||
|
||||
@@ -49,8 +49,8 @@ startKoin<AndroidKoinApp> {
|
||||
- **Custom Backstack Mutation:** Do **not** mutate back navigation with custom stacks disconnected from the app backstack. Mutate `NavBackStack<NavKey>` directly with `add(...)` and `removeLastOrNull()`.
|
||||
|
||||
## Reference Anchors
|
||||
- **App Startup / Koin Bootstrap:** `app/src/main/kotlin/org/meshtastic/app/MeshUtilApplication.kt`
|
||||
- **DI Bootstrap Object:** `app/src/main/kotlin/org/meshtastic/app/di/AndroidKoinApp.kt`
|
||||
- **DI App Wiring:** `app/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt`
|
||||
- **App Startup / Koin Bootstrap:** `androidApp/src/main/kotlin/org/meshtastic/app/MeshUtilApplication.kt`
|
||||
- **DI Bootstrap Object:** `androidApp/src/main/kotlin/org/meshtastic/app/di/AndroidKoinApp.kt`
|
||||
- **DI App Wiring:** `androidApp/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt`
|
||||
- **Shared Routes:** `core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/Routes.kt`
|
||||
- **Desktop Nav Shell:** `desktop/src/main/kotlin/org/meshtastic/desktop/ui/DesktopMainScreen.kt`
|
||||
- **Desktop Nav Shell:** `desktopApp/src/main/kotlin/org/meshtastic/desktop/ui/DesktopMainScreen.kt`
|
||||
|
||||
@@ -11,7 +11,7 @@ Module directory, namespacing conventions, environment setup, and troubleshootin
|
||||
|
||||
| Directory | Description |
|
||||
| :--- | :--- |
|
||||
| `app/` | Main application module. Contains `MainActivity`, Koin DI modules, and app-level logic. Uses package `org.meshtastic.app`. |
|
||||
| `androidApp/` | Main application module. Contains `MainActivity`, Koin DI modules, and app-level logic. Uses package `org.meshtastic.app`. |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.feature`, `meshtastic.kmp.library`, `meshtastic.kmp.jvm.android`, `meshtastic.koin`). |
|
||||
| `config/` | Detekt static analysis rules (`config/detekt/detekt.yml`) and Spotless formatting config (`config/spotless/.editorconfig`). |
|
||||
| `docs/` | Architecture docs and agent playbooks. See `docs/kmp-status.md` and `docs/roadmap.md` for current status. |
|
||||
@@ -38,7 +38,7 @@ Module directory, namespacing conventions, environment setup, and troubleshootin
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`, `firmware`, `wifi-provision`, `widget`). All are KMP except `widget`. Use `meshtastic.kmp.feature` convention plugin. |
|
||||
| `feature/wifi-provision` | KMP WiFi provisioning via BLE (Nymea protocol). Uses `core:ble` Kable abstractions. |
|
||||
| `feature/firmware` | Fully KMP firmware update system: Unified OTA (BLE + WiFi), native Nordic Secure DFU protocol (pure KMP), USB/UF2 updates, and `FirmwareRetriever` with manifest-based resolution. Desktop is a first-class target. |
|
||||
| `desktop/` | Compose Desktop application. Thin host shell relying on feature modules for shared UI. Full Koin DI graph, TCP, Serial/USB, and BLE transports. Versioning via `config.properties` + `GitVersionValueSource`. |
|
||||
| `desktopApp/` | Compose Desktop application. Thin host shell relying on feature modules for shared UI. Full Koin DI graph, TCP, Serial/USB, and BLE transports. Versioning via `config.properties` + `GitVersionValueSource`. |
|
||||
|
||||
## Namespacing
|
||||
- **Standard:** Use the `org.meshtastic.*` namespace for all code.
|
||||
|
||||
@@ -17,7 +17,7 @@ Run in a single invocation for routine changes to ensure code formatting, analys
|
||||
> In KMP modules, the `test` task name is **ambiguous**. Gradle matches both `testAndroid` and
|
||||
> `testAndroidHostTest` and refuses to run either, silently skipping KMP modules.
|
||||
> `allTests` is the `KotlinTestReport` lifecycle task registered by the KMP plugin.
|
||||
> Conversely, `allTests` does **not** cover pure-Android modules (`:app`, `:core:api`, etc.), which is why both `test` and `allTests` are needed.
|
||||
> Conversely, `allTests` does **not** cover pure-Android modules (`:androidApp`, `:core:api`, etc.), which is why both `test` and `allTests` are needed.
|
||||
|
||||
*Note: If testing Compose UI on the JVM (Robolectric) with Java 21, pin tests to `@Config(sdk = [34])` to avoid SDK 35 compatibility crashes.*
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"feature_directory":"specs/20260511-211823-compose-screenshot-testing"}
|
||||
{"feature_directory":"specs/006-kmp-project-structure"}
|
||||
|
||||
@@ -49,5 +49,5 @@ You are an expert Android/KMP engineer. Maintain architectural boundaries, use M
|
||||
<!-- SPECKIT START -->
|
||||
For additional context about technologies to be used, project structure,
|
||||
shell commands, and other important information, read the current plan
|
||||
at `specs/20260511-211823-compose-screenshot-testing/plan.md`
|
||||
at `specs/006-kmp-project-structure/plan.md`
|
||||
<!-- SPECKIT END -->
|
||||
|
||||
@@ -20,7 +20,7 @@ Thank you for your interest in contributing to Meshtastic-Android! We welcome co
|
||||
- Add comments where necessary, especially for complex logic.
|
||||
- Keep methods and classes focused and concise.
|
||||
- **Strings:** Use localised strings via the **Compose Multiplatform Resource** library in `:core:resources`.
|
||||
- Do **not** use the legacy `app/src/main/res/values/strings.xml`.
|
||||
- Do **not** use the legacy `androidApp/src/main/res/values/strings.xml`.
|
||||
- **Definition:** Add strings to `core/resources/src/commonMain/composeResources/values/strings.xml`.
|
||||
- **Usage:**
|
||||
```kotlin
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# `:app`
|
||||
# `:androidApp`
|
||||
|
||||
## Overview
|
||||
The `:app` module is the entry point for the Meshtastic Android application. It orchestrates the various feature modules, manages global state, and provides the main UI shell.
|
||||
The `:androidApp` module is the entry point for the Meshtastic Android application. It orchestrates the various feature modules, manages global state, and provides the main UI shell.
|
||||
|
||||
## Key Components
|
||||
|
||||
@@ -9,7 +9,7 @@ The `:app` module is the entry point for the Meshtastic Android application. It
|
||||
The single Activity of the application. It hosts the shared `MeshtasticNavDisplay` navigation shell and manages the root UI structure (Navigation Bar, Rail, etc.).
|
||||
|
||||
### 2. `MeshService`
|
||||
The core background service that manages long-running communication with the mesh radio. While it is declared in the `:app` manifest for system visibility, its implementation resides in the `:core:service` module. It runs as a **Foreground Service** to ensure reliable communication even when the app is in the background.
|
||||
The core background service that manages long-running communication with the mesh radio. While it is declared in the `:androidApp` manifest for system visibility, its implementation resides in the `:core:service` module. It runs as a **Foreground Service** to ensure reliable communication even when the app is in the background.
|
||||
|
||||
### 3. Koin Application
|
||||
`MeshUtilApplication` is the Koin entry point, providing the global dependency injection container.
|
||||
@@ -24,34 +24,34 @@ The module primarily serves as a "glue" layer, connecting:
|
||||
<!--region graph-->
|
||||
```mermaid
|
||||
graph TB
|
||||
:app[app]:::android-application
|
||||
:app -.-> :core:ble
|
||||
:app -.-> :core:common
|
||||
:app -.-> :core:data
|
||||
:app -.-> :core:database
|
||||
:app -.-> :core:datastore
|
||||
:app -.-> :core:di
|
||||
:app -.-> :core:domain
|
||||
:app -.-> :core:model
|
||||
:app -.-> :core:navigation
|
||||
:app -.-> :core:network
|
||||
:app -.-> :core:nfc
|
||||
:app -.-> :core:prefs
|
||||
:app -.-> :core:proto
|
||||
:app -.-> :core:service
|
||||
:app -.-> :core:resources
|
||||
:app -.-> :core:ui
|
||||
:app -.-> :core:barcode
|
||||
:app -.-> :core:takserver
|
||||
:app -.-> :feature:intro
|
||||
:app -.-> :feature:messaging
|
||||
:app -.-> :feature:connections
|
||||
:app -.-> :feature:map
|
||||
:app -.-> :feature:node
|
||||
:app -.-> :feature:settings
|
||||
:app -.-> :feature:firmware
|
||||
:app -.-> :feature:wifi-provision
|
||||
:app -.-> :feature:widget
|
||||
:androidApp[androidApp]:::android-application
|
||||
:androidApp -.-> :core:ble
|
||||
:androidApp -.-> :core:common
|
||||
:androidApp -.-> :core:data
|
||||
:androidApp -.-> :core:database
|
||||
:androidApp -.-> :core:datastore
|
||||
:androidApp -.-> :core:di
|
||||
:androidApp -.-> :core:domain
|
||||
:androidApp -.-> :core:model
|
||||
:androidApp -.-> :core:navigation
|
||||
:androidApp -.-> :core:network
|
||||
:androidApp -.-> :core:nfc
|
||||
:androidApp -.-> :core:prefs
|
||||
:androidApp -.-> :core:proto
|
||||
:androidApp -.-> :core:service
|
||||
:androidApp -.-> :core:resources
|
||||
:androidApp -.-> :core:ui
|
||||
:androidApp -.-> :core:barcode
|
||||
:androidApp -.-> :core:takserver
|
||||
:androidApp -.-> :feature:intro
|
||||
:androidApp -.-> :feature:messaging
|
||||
:androidApp -.-> :feature:connections
|
||||
:androidApp -.-> :feature:map
|
||||
:androidApp -.-> :feature:node
|
||||
:androidApp -.-> :feature:settings
|
||||
:androidApp -.-> :feature:firmware
|
||||
:androidApp -.-> :feature:wifi-provision
|
||||
:androidApp -.-> :feature:widget
|
||||
|
||||
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;
|
||||
@@ -116,7 +116,7 @@ configure<ApplicationExtension> {
|
||||
}
|
||||
|
||||
// Disable ABI splits for bundle builds or when explicitly requested via Gradle property.
|
||||
// Usage: ./gradlew :app:bundleGoogleRelease -Pmeshtastic.disableAbiSplits=true
|
||||
// Usage: ./gradlew :androidApp:bundleGoogleRelease -Pmeshtastic.disableAbiSplits=true
|
||||
val disableSplits = providers.gradleProperty("meshtastic.disableAbiSplits").map { it.toBoolean() }.getOrElse(false)
|
||||
|
||||
// Enable ABI splits to generate smaller APKs per architecture for F-Droid/IzzyOnDroid
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user