Skip to content

techdebt: app module disables non-transitive R classes due to one unqualified :core resource reference #292

Description

@grunt-claude-bot

Summary

android.nonTransitiveRClass=false in the root gradle.properties (line 28) disables non-transitive R classes for the app module, while modules/private-general-purpose/gradle.properties explicitly enables it (true) for the :core/:iap/general-purpose-app composite build. This inconsistency was introduced incidentally in #141 ("feat(export-transactions): implement in-app purchase") — the line was added with no explanation in the commit message, PR description, or review comments, as a side effect of that PR standing up the :core module and moving several shared resources into it.

Non-transitive R classes are AGP's default since 8.0 and Android Studio's default since Bumblebee — they shrink generated R classes, prevent resource-reference duplication across modules, and improve Gradle compilation avoidance (a module's Java/Kotlin compile task no longer needs to re-run just because a dependency's resources changed). Leaving it off for app forfeits those build-time wins project-wide.

Why it can't just be flipped today

app's compilation actually depends on the transitive resolution it disables. Specifically:

app/src/main/java/com/brainwallet/tools/adapter/TransactionListAdapter.java:181

convertView.arrowIcon.setImageResource(received ? R.drawable.arrow_down_bold_circle : R.drawable.arrow_up_bold_circle);

combined with the unqualified import com.brainwallet.R; at line 27. Both arrow_down_bold_circle and arrow_up_bold_circle were moved out of app/src/main/res/drawable and into modules/private-general-purpose/core/src/main/res/drawable in #141, but this call site was never updated to reference :core's own R class. It only compiles today because app's R class transitively inherits :core's drawable table.

This is the only call site in app that actually breaks under non-transitive R classes — I checked every resource :core contributes (5 drawables, 8 fonts, 9 colors) against what app/src/main/res also declares:

Resource In :core? Duplicated in app? Breaks if flipped?
drawable/arrow_back_24px core-only, unreferenced from app code — no
drawable/arrow_down_bold_circle ✅ yes
drawable/arrow_up_bold_circle ✅ yes
drawable/brainwallet_logotype_color no — resolves locally
drawable/brainwallet_logotype_white no — resolves locally
font/ibm_plex_sans_* (all 8) ✅ (all 8) no — resolves locally
color/white, cheddar, midnight, grape, chili, pesto no — resolves locally
color/lavender core-only, unreferenced from app code — no
color/border core-only, unreferenced from app code — no

Two smells here

  1. The immediate blocker: TransactionListAdapter.java:181 relies on implicit cross-module resource resolution instead of explicitly importing :core's R class.
  2. A milder duplication smell: brainwallet_logotype_color/brainwallet_logotype_white, all 8 ibm_plex_sans_* fonts, and 6 of the 9 core colors (white, cheddar, midnight, grape, chili, pesto) are declared identically by name in both app/src/main/res and :core/src/main/res. Each module's copy currently shadows the other depending on resolution order — exactly the kind of duplicate-resource risk non-transitive R classes is designed to surface. Worth auditing whether these duplicates can be deleted from app now that :core is expected to be the shared source of these assets.

Proposed fix

  1. Update TransactionListAdapter.java to reference :core's R class explicitly for the two arrow drawables, e.g.:
    com.grunt.brainwallet.core.R.drawable.arrow_down_bold_circle
    com.grunt.brainwallet.core.R.drawable.arrow_up_bold_circle
  2. Decide whether to delete the duplicate drawables/fonts/colors from app/src/main/res in favor of :core's copies (or vice versa) — pick one source of truth.
  3. Flip android.nonTransitiveRClass=true in root gradle.properties, matching modules/private-general-purpose/gradle.properties.
  4. Full rebuild + ./gradlew testBrainwalletDebugUnitTest to confirm nothing else was silently relying on transitive resolution outside the code paths grepped here.

References

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions