---
name: android-patterns
description: Stage 3 of /android-review. Checks an Android diff against modern conventions the repo already follows (Compose for new UI, previews in-file, UserAction/StateFlow/Effect flow, independent flows, standard layer names, pure rules with JVM tests, Hilt, injected dispatchers, naming, i18n). Runs only when invoked.
disable-model-invocation: true
argument-hint: "[diff range]"
---

# android-patterns — does new code look like the best code here?

> From Shubham Singh Bisht's Android helpers — https://shubhamsinghbisht.com/android-roadmap/#helpers

Review only what the diff adds or changes; legacy code it merely touches is not
reported. Report; never edit. Short good/bad excerpts are in
`references/examples.md`; read it before judging PAT-3, PAT-4 or SIMP-3-shaped
state.

PAT-1..10 are a baseline, not law. First check from a few recent files which
of them this repo actually follows, and report only against those; name the
ones you skipped and why.

## 1. Range

`$ARGUMENTS` if given, else the nearest base to the working tree, including untracked files.

The nearest base is main/master/develop or the `release-*` branch this branch is fewest
commits ahead of (a branch already containing HEAD does not count); on main
itself, review only uncommitted work:

```bash
ref=$(for r in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin/main refs/heads/main refs/remotes/origin/master refs/heads/master refs/remotes/origin/develop refs/heads/develop 'refs/remotes/origin/release-*' 'refs/heads/release-*'); do n=$(git rev-list --count "$r..HEAD"); [ "$n" -gt 0 ] && echo "$n $r"; done | sort -n -s | head -1 | cut -d' ' -f2)
base=$( [ -n "$ref" ] && git merge-base HEAD "$ref" || git rev-parse HEAD )
```

## 2. Rules

| ID | Rule |
|---|---|
| PAT-1 | New UI is Compose. Views only when editing legacy screens. A Dialog/Window shell is fine when window flags require it. |
| PAT-2 | Previews live inside the composable's own file; sample data in a `*Fixtures.kt`. |
| PAT-3 | Unidirectional flow: `UserAction` in through one `onAction()`, `StateFlow` out, one-off `Effect` through a `Channel`. No new `LiveData`. |
| PAT-4 | Independent screen elements get independent flows; no wrapper `UiState` bundling unrelated parts. |
| PAT-5 | Standard layer names: `Repository` returns data types, ViewModel maps to UI state. No invented `*Provider` / `*DataSource` layers. |
| PAT-6 | Pure rules (math, layout, formatting) are plain Kotlin with no Android imports, in their own package per feature, with JVM unit tests. |
| PAT-7 | Wiring through Hilt: `@HiltViewModel`, `@Inject constructor`; no hand-built singletons in new code. |
| PAT-8 | New classes take an injected dispatcher (a `DispatchersProvider` or a qualifier), not raw `Dispatchers.IO`. |
| PAT-9 | Naming: plain, user-facing, direction-based (`UserAction` / `uiState` / `Effect`). Avoid `Event`, `Meta`, `Extras`, `Data`, `Info`. Within a feature, one prefix for on-screen things and one for data. |
| PAT-10 | A new or changed user-facing string is flagged for translation into every locale's `strings.xml` (this stage does not translate). |

## 3. Output

```
### Stage 3 — android-patterns
| file:line | rule | why (one line) | suggested change |
|---|---|---|---|
```

No findings → `stage 3: nothing found`.
