Files
app/.cursor/rules/android.mdc

80 lines
6.6 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: Android/KMP workspace rules (single concise source of truth)
alwaysApply: true
---
# Android / KMP rules
## Project context (quick)
- This is a **messaging app**.
- The Kotlin Multiplatform shared code lives under:
- `app/shared/src/commonMain/kotlin/` (cross-platform logic + Compose UI)
- `app/shared/src/androidMain/kotlin/` (Android-specific implementations)
- `app/shared/src/iosMain/kotlin/` (iOS-specific implementations, when present)
- Android app module: `app/android/`
- Shared UI strings (Compose resources):
- `app/shared/src/commonMain/composeResources/values/strings.xml`
- `app/shared/src/commonMain/composeResources/values-ru/strings.xml`
## Build / validation (required before finishing)
- After changes, run this command (and fix all errors):
- `export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" && ./gradlew :app:shared:compileAndroidMain :app:shared:compileKotlinIosArm64`
- If it fails, investigate and try to fix the issue yourself (dont stop at reporting the failure).
## After Android-affecting changes: build + run on device (Mobile MCP)
If you changed anything under `app:android`, `app:shared` (`commonMain` / `androidMain`), or `utils:shared` that affects Android:
- **Build** debug APK: `./gradlew :app:android:assembleDebug` (artifact: `app/android/build/outputs/apk/debug/android-debug.apk`).
- **Install + launch via Cursor Mobile MCP** (configured name **`Mobile MCP`** in `mcp.json`; in Agent MCP tool calls the server id is often **`user-Mobile MCP`**—use whatever id your session lists for `@mobilenext/mobile-mcp`). **Read each tools schema**, then:
1. **`mobile_list_available_devices`** — pick the target **Android** `device` id(s) (prefer a **physical** device when validating UI; use an emulator when the task needs it or no phone is listed).
2. **`mobile_install_app`** — `device`, `path` = **absolute** path to `android-debug.apk` under the repo (e.g. `<workspace>/app/android/build/outputs/apk/debug/android-debug.apk`).
3. **`mobile_launch_app`** — `device`, `packageName` = **`ru.fromchat.beta`** (debug application id; not `ru.fromchat`).
- Smoke-test the affected flows after launch.
- If **`mobile_install_app`** fails on an **emulator** with insufficient storage, use **“Android emulator storage”** (below), then retry.
- Use raw **`adb install` / `am start`** only if Mobile MCP is unavailable after checking MCP status—say so in the reply.
## Calls (LiveKit / `Call*`, call UI, foreground call service, call audio/video)
Whenever the task touches **calls** (e.g. `CallMediaLayer`, `CallForegroundService`, LiveKit wiring, in-call UI, mic/camera/screen-share for calls):
- **Build** debug: `./gradlew :app:android:assembleDebug`
- **Install + launch with Mobile MCP** on **every Android target** you will use for validation (same three tools as above: **`mobile_list_available_devices`** → **`mobile_install_app`** (`device` + absolute `path` to `android-debug.apk`) → **`mobile_launch_app`** (`device`, `packageName` = **`ru.fromchat.beta`**)). Use the MCP **server id** your environment exposes (e.g. **`user-Mobile MCP`**). Repeat for **each** Android `device` id (emulator **and** phone when both appear in `mobile_list_available_devices`).
- Do **not** treat the task as finished until this has been run on **both** an **emulator** and a **physical device** whenever both are available (start/boot the missing one, list devices again, then install + launch on each). If install fails on the emulator, follow **“Android emulator storage”** below, then retry install + launch. If it still fails after a real cleanup attempt, report what you tried.
- If only one class of device is listed, deploy to every listed Android device and state clearly what was missing.
## Android emulator storage (no approval needed)
When an **Android emulator** hits **`INSTALL_FAILED_INSUFFICIENT_STORAGE`** or otherwise has too little free space for a debug install, you may **do whatever is needed to free space on that emulator only** without asking the user first: uninstall third-party apps (`adb -s <emu> uninstall …`), clear caches (`adb shell pm trim-caches` / `rm` under emulator-owned paths the shell can reach), delete arbitrary files **inside that AVD**, or **wipe the AVD / `emulator -wipe-data`** if that is the fastest fix. Treat the emulator as disposable dev state.
- **Never** use this “anything goes” approach on a **physical device** (only uninstall/clear what the user explicitly asked for, or use normal Mobile MCP flows).
## Never touch Gradle caches
- Do not read, list, search, copy, or modify anything under Gradle cache paths (e.g. `~/.gradle/caches`, `**/.gradle/caches`).
## No magic-string “sanitization” of real data
- Never strip/null/rewrite stored or displayed values by comparing to hard-coded UI/placeholder strings.
- Fix at the source (dont persist placeholders) or use explicit migrations/sentinels—never natural-language matching.
## UI strings (shared module)
- No hardcoded user-visible copy in shared UI. Use Compose Multiplatform resources:
- `app/shared/src/commonMain/composeResources/values/strings.xml` (default)
- `app/shared/src/commonMain/composeResources/values-ru/strings.xml` (Russian)
- Keep keys in sync across both files.
- Exception: Debug API screen (`ru.fromchat.ui.debug`) may hardcode strings.
## Prefer utils package APIs
Prefer `com.pr0gramm3r101.utils` when available (before custom solutions), especially:
- Clipboard: `supportClipboardManagerImpl` / `SupportClipboardManager.setText`
- Strings: `String.toAnnotatedString()`
- Compose: `Modifier.conditional`, `CompositionLocal.invoke()`
## Debug HTTP logging
- Prefer Ktor `HttpClient` for debug/instrumentation HTTP logging.
- Do not use `HttpURLConnection` or raw `OkHttpClient` for debug-only logging.
- Centralize behind `ru.fromchat.debug.DebugLogger`, best-effort only (never crash the app).
## Codebase hygiene
- Prefer **official docs** first for typical Jetpack Compose / Compose Multiplatform patterns; if docs cover it, follow them.
- Avoid breaking iOS via Android-only APIs in `commonMain` (keep platform code in `androidMain` / `iosMain` as needed).
- Do not introduce hardcoded user-visible strings outside the Debug API exception (see “UI strings” above).
## Skills (when to use)
- Use the **Material 3 skill** when implementing or changing Compose UI using Material3 components, theming, tokens, or accessibility.
- Use the **using-computer skill** only when the user asks me to control the computer / click through UI / take screenshots.
- Use **Cursor “create-rule/create-skill/create-hook” skills** only when you explicitly ask to create or modify Cursor rules/skills/hooks.