Skip to content

Incremental Jetpack Compose adoption #21138

@criticalAY

Description

@criticalAY

Jetpack Compose for AnkiDroid incrementally, starting with a new shared :ui-compose module that houses the theme bridge and reusable UI components. Existing Views/Fragments stay; new screens and migrated leaf screens render in Compose hosted inside the current Fragment shells via ComposeView.

FYI: At I/O 2026 Google formally moved Android UI to "Compose First":

  • Android Views, Fragments, RecyclerView, ViewPager, and android.widget are in maintenance mode critical bug fixes only, no new features (source).
  • All new Android Studio UI tooling targets Compose (Layout Editor / Navigation Editor are frozen).
  • Compose BOM 2026.04.01 (Compose 1.11) ships Grid, FlexBox, Style API, faster SlotTable runtime (release notes).
  • The official guidance is interop-first incremental adoption via AndroidView / ComposeView (interop docs).

What its worth, AnkiDroid is well-positioned: AGP 9, Kotlin 2.3, minSdk 24, no Hilt/Dagger lock-in, view binding already enabled, small custom-View footprint.

Proposed approach

Phase 0 Foundations

  • Enable Compose in :AnkiDroid build (compose BOM, kotlin-compose plugin, buildFeatures.compose = true)
  • Create :ui-compose module (theme + shared components)
  • Document conventions in docs/development/compose.md

Phase 1: Pilot leaf screens (separate PRs, one per screen)

Low-risk, no shared state, prove the patterns:

  • AboutFragment (static content)
  • LoadingDialogFragment, AsyncDialogFragment (dialogs)
  • PageFragment (WebView + toolbar- proves AndroidView interop) ,etc

Phase 2: Mid-complexity

  • Settings sub-screens (will need a strategy for custom Preference subclasses)
  • Info / help screens

Phase 3: Lists

  • Card Browser, Deck Picker- LazyColumn / LazyVerticalGrid

Phase 4: Stateful surfaces

  • Reviewer, Note Editor, last, when patterns are well-established

New module: :ui-compose

AnkiDroid already has a :common / :common:android pattern, but a Compose-specific module deserves its own root-level name because its purpose is UI building blocks, not "common utilities." I'd propose:

ui-compose Module Implementation Tasks

  • Build Setup

    • build.gradle: Apply kotlin-compose, set compose=true
    • src/main/AndroidManifest.xml: Add baseline manifest
  • Theme (theme/)

    • AnkiTheme.kt: MaterialTheme wrapper
    • ThemeBridge.kt: Styleable & attribute reading helpers
    • res/values/compose_theme_attrs.xml: The <declare-styleable>
  • Core Components (components/)

    • AnkiTopAppBar.kt: Unified toolbar style
    • AnkiAlertDialog.kt: AppCompat dialog convention wrapper
    • AnkiButton.kt: Text/filled buttons matching ?colorAccent
  • Text Utilities (text/)

    • HtmlText.kt: AnnotatedString.fromHtml + custom link styles
  • Previews & Testing

    • preview/AnkiPreviews.kt: @Preview helpers and theme variants
    • src/test/: Screenshot baselines for isolated components

:common semantically means "non-UI shared code." Putting UI components there is misleading. :ui-compose is unambiguous and matches Now in Android's core/designsystem convention.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions