mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-10-31 16:22:49 +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.
4.3 KiB
4.3 KiB
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. - 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:
_iosor_androidsuffix. - Placeholders: Use numbered form
%1$s,%2$d.
- Cross-screen verbs:
Previews
- Create previews for all main states of a Composable.
- Use
@PreviewsDayNightfor 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.
- 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 for navigation and 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 FooEvents. |
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 for DI.
- Inject via constructor parameters using
@Inject. - Use
@AssistedInjectand@AssistedFactoryfor 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→JoinedRoomorRoomInfo. - Type Mapping: Map Rust SDK types to Kotlin data classes in the
apimodule to avoid leakingMatrixRustSDKinto the UI. - Always follow Kotlin naming conventions (e.g.,
userIdinstead ofuserID).