mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
03c330ee07
The `Provider` suffix reads as a dependency provider rather than as preview
data, and it collides with the real providers in the codebase — `StringProvider`,
`PickerProvider`, the login feature's `AccountProvider` — so the name says
nothing about which of the two a class is. `PreviewParam` says it.
195 classes are renamed, along with the 185 files named after them, the konsist
rule that enforces the convention, the presentation-class file templates and the
onboarding documentation.
This cannot be split. `Konsist.scopeFromProduction()` scans the whole project, so
flipping the assertion before every class has moved leaves the rule red, and a
rule that accepted either suffix during a transition would be exactly the kind of
compatibility layer this convention change is meant to remove.
Two judgement calls in the rule itself. The `name.endsWith("PreviewProvider")`
exclusion is dropped: its only job was to reject a redundant `Preview` before
`Provider`, and the new suffix already contains it; no class currently ends with
`PreviewProvider`, so removing it changes nothing today. And
`EditableAvatarViewUriProvider` is renamed rather than deleted from the exclusion
list even though no such class exists in this repository, since it presumably
comes from the modules overlaid for the enterprise build.
Nothing keyed off the old suffix: no snapshot filename contains a provider class
name, so no Paparazzi image changes, and the Kover variants match on `*Presenter`,
`*State` and `*ViewKt`, so coverage bounds are unaffected.
122 lines
4.3 KiB
Markdown
122 lines
4.3 KiB
Markdown
# AGENTS.md — Element X Android
|
|
|
|
> **Repo:** `element-hq/element-x-android` — Android Matrix client (Compose UI + `matrix-rust-sdk`).
|
|
|
|
---
|
|
|
|
## Strong Conventions
|
|
|
|
PRs must meet these rules.
|
|
|
|
### Code Style
|
|
|
|
- Style enforced by **Editor config** (`.editorconfig`).
|
|
- Set "Hard wrap at" to 160 chars in Android Studio.
|
|
|
|
### PII & Logging
|
|
|
|
- We use **Timber** for logging. Never use `android.util.Log`.
|
|
- **Never log secrets, passwords, keys, or user content** (e.g. message bodies).
|
|
- Matrix IDs (User IDs, Room IDs, Event IDs) are safe to log.
|
|
|
|
### Strings & Localisation
|
|
|
|
- Default localisation: `en` (en-GB strings), shared with Element X iOS via [Localazy](https://localazy.com/p/element).
|
|
- **Never edit `localazy.xml`** — it is auto-generated and overwritten.
|
|
- New English strings go in **`temporary.xml`**. The core team imports these to Localazy.
|
|
- **Key naming**:
|
|
- Cross-screen verbs: `action_` (e.g., `action_copy`).
|
|
- Common nouns/other: `common_` (e.g., `common_error`).
|
|
- Accessibility: `a11y_`.
|
|
- Screen-specific: `screen_<name>_<key>` (e.g., `screen_onboarding_welcome_title`).
|
|
- Errors: `error_` prefix.
|
|
- Platform-specific: `_ios` or `_android` suffix.
|
|
- Placeholders: Use numbered form `%1$s`, `%2$d`.
|
|
|
|
### Previews
|
|
|
|
- Create previews for **all main states** of a Composable.
|
|
- Use `@PreviewsDayNight` for consistency.
|
|
- Use `PreviewParameterProvider` (e.g., `FooStatePreviewParam`) to provide states.
|
|
- Wrap previews in `ElementPreview { ... }`.
|
|
|
|
---
|
|
|
|
## Pull Request Guidelines
|
|
|
|
- Sentence-style titles (no conventional commits).
|
|
- Exactly one `pr-` label (see `.github/release.yml`).
|
|
- Title = changelog entry — descriptive, no "Fixes #…".
|
|
- Leave description template for the developer. Redirect them to the [contributing etiquette](CONTRIBUTING.md#etiquette).
|
|
- Screenshots/videos for visual changes.
|
|
- 500 additions max — split large changes.
|
|
- Commits need a title and description; no tiny or massive commits.
|
|
- No history rewrites.
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
### Build System
|
|
|
|
Common Gradle tasks:
|
|
- Build: `./gradlew assembleDebug`
|
|
- Unit Tests: `./gradlew test`
|
|
- Lint: `./gradlew lint`
|
|
- Format: `./gradlew ktlintFormat`
|
|
- Update Docs TOC: `./gradlew generateDocsToc`
|
|
|
|
### Gradle Modules
|
|
|
|
Features follow a 3-module structure:
|
|
- `features/foo/api`: Public interfaces and data classes.
|
|
- `features/foo/impl`: Internal implementation, Presenter, and View.
|
|
- `features/foo/test`: Test fakes and utilities.
|
|
|
|
---
|
|
|
|
## Architecture: Appyx + Molecule
|
|
|
|
We use [Appyx](https://bumble-tech.github.io/appyx/) for navigation and [Molecule](https://github.com/cashapp/molecule) for Presenters.
|
|
|
|
### Files Per Screen (`Foo`)
|
|
|
|
| File | Purpose |
|
|
| :--- | :--- |
|
|
| `FooNode.kt` | Appyx Node: Handles navigation and wires the Presenter to the View. |
|
|
| `FooPresenter.kt` | A `@Composable` function that produces `FooState` from `FooEvent`s. |
|
|
| `FooView.kt` | Stateless Composable rendering the UI from `FooState`. |
|
|
| `FooState.kt` | Data class representing the immutable UI state. |
|
|
| `FooEvent.kt` | Sealed interface for UI actions sent to the Presenter. |
|
|
| `FooStatePreviewParam.kt` | Provides sample states for Previews and Screenshot tests. |
|
|
| `FooPresenterTest.kt` | Unit tests for the Presenter logic using Turbine. |
|
|
|
|
---
|
|
|
|
## Dependency Injection (Metro)
|
|
|
|
- We use [Metro](https://zacsweers.github.io/metro/) for DI.
|
|
- Inject via constructor parameters using `@Inject`.
|
|
- Use `@AssistedInject` and `@AssistedFactory` for components requiring runtime arguments (like Navigators or IDs).
|
|
- Use `@ContributesBinding(AppScope::class)` for singleton-like services.
|
|
- Use `@ContributesNode(RoomScope::class)` for Appyx Nodes.
|
|
|
|
---
|
|
|
|
## Compound Design System
|
|
|
|
Always prefer Compound components and tokens from `libraries/compound/` module.
|
|
|
|
- **Colours**: `ElementTheme.colors.textPrimary`, `ElementTheme.colors.bgCanvasDefault`.
|
|
- **Typography**: `ElementTheme.typography.fontBodyMdRegular`.
|
|
- **Icons**: Use `CompoundIcons.IconName()` (e.g., `CompoundIcons.UserProfileSolid()`).
|
|
|
|
---
|
|
|
|
## The Rust SDK Layer
|
|
|
|
We wrap the `matrix-rust-sdk` to isolate the UI from the underlying SDK.
|
|
- Naming: SDK `Room` → `JoinedRoom` or `RoomInfo`.
|
|
- Type Mapping: Map Rust SDK types to Kotlin data classes in the `api` module to avoid leaking `MatrixRustSDK` into the UI.
|
|
- Always follow Kotlin naming conventions (e.g., `userId` instead of `userID`).
|