Skip to content

feat: drop the frozen icon library, proven by not changing a single golden - #52

Merged
GeiserX merged 1 commit into
mainfrom
feat/icons-off-the-frozen-library
Aug 6, 2026
Merged

feat: drop the frozen icon library, proven by not changing a single golden#52
GeiserX merged 1 commit into
mainfrom
feat/icons-off-the-frozen-library

Conversation

@GeiserX

@GeiserX GeiserX commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Closes CashPilot-android-vxb. This is what the golden gate in #51 was built for.

Why

androidx.compose.material:material-icons-extended is frozen at 1.7.8. Google stopped publishing it, and material3 1.4.0 stopped depending on material-icons-core transitively — so it was resolving only because the Compose BOM still happened to pin it. One day a BOM stops, and the build breaks with a missing version, not a deprecation warning.

The argument that this is safe

Not one golden changed.

app/src/test/screenshots/ was recorded from the ImageVectors, before this migration. All 16 still match — byte for byte — rendered from the drawables. git diff --stat on that directory is empty.

That is the entire case, and it is why the goldens were built first.

What changed

  • 16 vector drawables in res/drawable/, converted from the same upstream Material Icons SVGs the Compose artifact is generated from.
  • 30 call sites move from Icons.Default.X to painterResource(R.drawable.ic_x).
  • The dependency is removed from build.gradle.kts and the version catalog.

Two things that would otherwise have been lost quietly

  • ArrowBack was Icons.AutoMirrored, so ic_arrow_back.xml carries android:autoMirrored="true". No golden could have caught dropping this — they all render LTR. It needed noticing by reading, not by testing.
  • The converter refuses a filled non-path shape rather than approximating it, because a converter that quietly does its best defeats the gate it feeds. query_stats hit that and was inspected: its <rect> is fill="none", the transparent bounding box. So unfilled shapes of any kind are skipped and only filled ones raise — and both directions have a control.

Controls

Control Result
Point ic_settings at the close glyph verifyRoborazziDebug FAILS
A filled <rect> alongside a real path converter refuses: unsupported FILLED shape <rect>
A transparent <rect> alongside a real path converts correctly
A stray Icons. reference does not compile — stronger than the test that also guards it

One control passed, so it is filed rather than hidden

An orphaned drawable is not caught by anything that fails. Lint's UnusedResources detects it, but only as a warning:

ic_unused_thing.xml:1: Warning: The resource R.drawable.ic_unused_thing appears to be unused [UnusedResources]

Two pre-existing unused strings (earnings_shared_detail, earnings_no_reading) share that gap and look like an unwired feature — the more interesting half. Raising the severity can't be done here without resolving those first, so it's its own bead rather than scope creep in a PR whose job is sixteen substitutions that change nothing.

Summary by CodeRabbit

  • UI Improvements

    • Updated dashboard, settings, and setup screens with consistent built-in icons.
    • Added icons for navigation, notifications, status indicators, warnings, settings, visibility, and connectivity.
    • Improved support for mirrored back-arrow display.
  • Quality

    • Added automated coverage checks to ensure all app icons are used consistently.
    • Removed the previous icon package after migrating to drawable-based icons.

…olden

material-icons-extended is frozen at 1.7.8. Google stopped publishing it
and material3 1.4.0 stopped depending on material-icons-core
transitively, so it was resolving only because the Compose BOM still
happened to pin it -- a dependency that would one day break with a
missing version rather than a deprecation warning.

The 16 icons the app draws are now vector drawables in res/drawable/,
converted from the same upstream Material Icons SVGs the Compose artifact
is generated from. 30 call sites move from Icons.Default.X to
painterResource(R.drawable.ic_x), and the dependency is gone.

NOT ONE GOLDEN CHANGED. app/src/test/screenshots/ was recorded from the
ImageVectors before this migration and every one of the 16 still matches,
byte for byte, rendered from the drawables. That is the entire argument
that this is safe, and it is why the goldens were built first.

Details that would otherwise have been lost quietly:

* ArrowBack was Icons.AutoMirrored, so ic_arrow_back.xml carries
  android:autoMirrored="true". No golden could have caught dropping it --
  they all render LTR.
* The converter REFUSES a filled non-path shape rather than
  approximating it, because a converter that quietly does its best would
  defeat the gate it feeds. query_stats hit that and was inspected: its
  <rect> is fill="none", the transparent bounding box, so unfilled shapes
  of any kind are skipped and only FILLED ones raise. Both directions are
  controlled.

Controls, all failing as required: pointing ic_settings at the close
glyph fails verifyRoborazziDebug; a filled <rect> is refused by the
converter; a stray Icons. reference no longer even compiles, which is
stronger than the test that also guards it.

One control PASSED, so it is filed rather than hidden: an orphaned
drawable is caught by lint's UnusedResources but only as a WARNING, so
nothing fails. Two pre-existing unused strings share that gap. Raising
the severity cannot be done in this PR without first resolving those, so
it is its own bead.

Closes CashPilot-android-vxb
@GeiserX

GeiserX commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 079b936e-5c57-45aa-bbcf-06e80c0280dc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The app replaces Compose Material icons with 16 vector drawable resources. Dashboard, settings, and setup screens use drawable painters. The extended Material Icons dependency is removed. Golden tests now validate drawable coverage and reject remaining Material icon references.

Changes

Icon migration

Layer / File(s) Summary
Drawable icon resources
app/src/main/res/drawable/ic_*.xml
Added vector drawable resources for arrows, status icons, alerts, navigation, and screen actions.
Screen icon integration
app/src/main/java/com/cashpilot/android/ui/screen/DashboardScreen.kt, app/src/main/java/com/cashpilot/android/ui/screen/SettingsScreen.kt, app/src/main/java/com/cashpilot/android/ui/screen/SetupScreen.kt
Replaced Material icon usage with painterResource. Updated SetupCard to accept Painter.
Dependency and golden-test cleanup
app/build.gradle.kts, gradle/libs.versions.toml, app/src/test/java/com/cashpilot/android/IconGoldenTest.kt
Removed the extended icons dependency. Updated documentation, drawable coverage checks, rendering, and checks for remaining Icons.* references.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies removal of the icon library and confirms that golden screenshots remain unchanged.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/icons-off-the-frozen-library

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/test/java/com/cashpilot/android/IconGoldenTest.kt`:
- Around line 173-177: Update the offenders regex in IconGoldenTest so it
rejects any Icons reference, including Icons.AutoMirrored.* and all Compose icon
themes, instead of enumerating only Filled, Outlined, and Default. Keep the
existing source scan and assertion behavior unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e46a41ec-5bf1-4859-9f79-def1b2dbb71e

📥 Commits

Reviewing files that changed from the base of the PR and between 0cfabac and 1b99da0.

📒 Files selected for processing (22)
  • app/build.gradle.kts
  • app/src/main/java/com/cashpilot/android/ui/screen/DashboardScreen.kt
  • app/src/main/java/com/cashpilot/android/ui/screen/SettingsScreen.kt
  • app/src/main/java/com/cashpilot/android/ui/screen/SetupScreen.kt
  • app/src/main/res/drawable/ic_arrow_back.xml
  • app/src/main/res/drawable/ic_arrow_downward.xml
  • app/src/main/res/drawable/ic_arrow_upward.xml
  • app/src/main/res/drawable/ic_battery_alert.xml
  • app/src/main/res/drawable/ic_check_circle.xml
  • app/src/main/res/drawable/ic_chevron_right.xml
  • app/src/main/res/drawable/ic_circle.xml
  • app/src/main/res/drawable/ic_close.xml
  • app/src/main/res/drawable/ic_cloud.xml
  • app/src/main/res/drawable/ic_cloud_off.xml
  • app/src/main/res/drawable/ic_language.xml
  • app/src/main/res/drawable/ic_notifications.xml
  • app/src/main/res/drawable/ic_query_stats.xml
  • app/src/main/res/drawable/ic_settings.xml
  • app/src/main/res/drawable/ic_visibility_off.xml
  • app/src/main/res/drawable/ic_warning.xml
  • app/src/test/java/com/cashpilot/android/IconGoldenTest.kt
  • gradle/libs.versions.toml
💤 Files with no reviewable changes (1)
  • app/build.gradle.kts

Comment on lines +173 to +177
val offenders = Regex("""Icons\.(?:AutoMirrored\.)?(?:Filled|Outlined|Default)\.""")
.findAll(sourceText())
.map { it.value }
.toSet()
assert(offenders.isEmpty()) { "the app still draws Material Icons: $offenders" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import re

pattern = re.compile(r"\bIcons\.")
samples = [
    "Icons.Rounded.Settings",
    "Icons.Sharp.Warning",
    "Icons.TwoTone.Cloud",
    "Icons.AutoMirrored.Rounded.ArrowBack",
]
missing = [sample for sample in samples if not pattern.search(sample)]
if missing:
    raise SystemExit(f"pattern misses: {missing}")
PY

if rg -nP '\bIcons\.' app/src/main/java --glob '*.kt'; then
  echo "Material Icons references remain" >&2
  exit 1
fi

Repository: GeiserX/CashPilot-android

Length of output: 163


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Target file lines 150-185:\n'
sed -n '150,185p' app/src/test/java/com/cashpilot/android/IconGoldenTest.kt

printf '\nCurrent material icon usages in app sources:\n'
rg -n 'Icons\.|AutoMirrored|Rounded|Sharp|TwoTone' app/src/main --glob '*.kt' || true

printf '\nCurrent test references to material icons guard:\n'
rg -n 'Icons\.(?:AutoMirrored\.)?(?:Filled|Outlined|Default)|sourceText|offenders' app/src/test/java/com/cashpilot/android/IconGoldenTest.kt --glob '*.kt' || true

Repository: GeiserX/CashPilot-android

Length of output: 2407


Expand the Material Icons guard.

Use a single Icons reference check instead of enumerating Filled, Outlined, and Default. This also covers valid Compose themes such as Rounded, Sharp, and TwoTone, including Icons.AutoMirrored.*.

Proposed fixed pattern
-        val offenders = Regex("""Icons\.(?:AutoMirrored\.)?(?:Filled|Outlined|Default)\.""")
+        val offenders = Regex("""\bIcons\.""")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val offenders = Regex("""Icons\.(?:AutoMirrored\.)?(?:Filled|Outlined|Default)\.""")
.findAll(sourceText())
.map { it.value }
.toSet()
assert(offenders.isEmpty()) { "the app still draws Material Icons: $offenders" }
val offenders = Regex("""\bIcons\.""")
.findAll(sourceText())
.map { it.value }
.toSet()
assert(offenders.isEmpty()) { "the app still draws Material Icons: $offenders" }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/test/java/com/cashpilot/android/IconGoldenTest.kt` around lines 173 -
177, Update the offenders regex in IconGoldenTest so it rejects any Icons
reference, including Icons.AutoMirrored.* and all Compose icon themes, instead
of enumerating only Filled, Outlined, and Default. Keep the existing source scan
and assertion behavior unchanged.

@GeiserX
GeiserX merged commit d4e90f2 into main Aug 6, 2026
3 checks passed
@GeiserX
GeiserX deleted the feat/icons-off-the-frozen-library branch August 6, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant