Skip to content

feat: revert to multi-activity + wire first-run flow#140

Merged
Lemkinator merged 28 commits into
mainfrom
feat/multi-activity-first-run-flow
Jun 1, 2026
Merged

feat: revert to multi-activity + wire first-run flow#140
Lemkinator merged 28 commits into
mainfrom
feat/multi-activity-first-run-flow

Conversation

@Lemkinator
Copy link
Copy Markdown
Owner

@Lemkinator Lemkinator commented May 31, 2026

Summary

  • Reverts single-activity + Navigation Component migration; restores MainActivity + IconActivity as separate activities
  • Wires common-utils first-run flow: handleFirstRun(...) is the first call in MainActivity.onCreate (before setContentView) — OOBE-only
  • Fixes pre-existing drawer menu ID mismatch (about_app_destcommonutils_about_dest etc.)
  • Adds BuildConfig.FIRST_RUN_SKIPPABLE (false in production, true for nonMinifiedRelease profiling variant); updates BaselineProfileGenerator to pass EXTRA_SKIP_FIRST_RUN so OOBE is never in the profile path

Test Plan

  • ./gradlew build → BUILD SUCCESSFUL (spotless, detekt, lint, Konsist, screenshot tests)
  • ./gradlew :app:assembleNonMinifiedRelease → BUILD SUCCESSFUL
  • Drawer About/AboutMe/Settings items now navigate correctly (menu IDs fixed)

Depends on

🤖 Generated with Claude Code

Architecture & Onboarding

  • Reverts single-activity + Navigation Component to multi-activity (MainActivity + IconActivity).
  • Wires common-utils first-run/OOBE flow: calls handleFirstRun(...) as the first invocation in MainActivity.onCreate (before setContentView) and returns early when onboarding is required.

Configuration & Build

  • Adds BuildConfig.FIRST_RUN_SKIPPABLE (false by default; true for nonMinifiedRelease profiling variant) so benchmark variants can skip OOBE.
  • Updates BaselineProfileGenerator to pass EXTRA_SKIP_FIRST_RUN and perform a navigate-to-icon-and-back step during profile collection.

Fixes & Updates

  • Fixes drawer menu IDs (e.g., about_app_dest → commonutils_about_dest) and updates drawer title to R.string.app_name.
  • Removes Navigation Component/transition imports and refactors drawer handling for the multi-activity flow.
  • Updates lint baseline for Overdraw entries on activity_icon layouts (intentional suppression for OneUI rounded-corner background).
  • Updates CLAUDE.md to document the multi-activity architecture and test/baseline setup.
  • Bumps common-utils to v1.1.1 and mockk to v1.14.11.

Builds: ./gradlew build and :app:assembleNonMinifiedRelease reported successful; drawer navigation verified. Depends on common-utils PR #126.

Lemkinator and others added 10 commits May 28, 2026 20:06
Replace two-activity (MainActivity + IconActivity) pattern with a
single MainActivity hosting MainFragment and IconFragment via the
Navigation Component. IconActivity is renamed to IconFragment and
ported to Fragment lifecycle; MainFragment extracts the app-list UI
from MainActivity. Add Navigation graph (main_navigation.xml) to define
destinations and the icon-detail back-stack. Replace activity_icon
layouts with fragment_icon (portrait + landscape); add fragment_main
layout; update activity_main to host NavHostFragment. Remove
IconActivity from the manifest and delete the now-obsolete
instrumented-test class. Wire local common-utils include-build
substitution for development until the fragment/nav APIs are published.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update IconViewModelTest and MainActivityScreenshotTest for the
renamed/refactored fragment classes. Update BaselineProfileGenerator
to navigate via NavController instead of starting IconActivity directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bump mockk 1.14.9 → 1.14.11 (NewerVersionAvailable). Update lint
baseline to include Overdraw entries for activity_icon.xml layouts
restored during multi-activity revert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ch planning docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

Warning

Review limit reached

@Lemkinator, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 50 minutes and 1 second. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a6df78a-2821-4215-b25b-0a7f2ec813c8

📥 Commits

Reviewing files that changed from the base of the PR and between 46b46e6 and 4b98587.

📒 Files selected for processing (1)
  • gradle/libs.versions.toml
📝 Walkthrough

Walkthrough

Adds a build-time flag to skip first-run onboarding for benchmark variants, gates MainActivity startup on onboardIfNeeded, extends baseline profile generation to pass the skip extra and navigate UI, refactors drawer menu handling, and updates docs, lint baselines, and dependency versions.

Changes

Onboarding Skip Control and Baseline Profile

Layer / File(s) Summary
Onboarding control infrastructure
app/build.gradle.kts, app/src/main/java/de/lemke/geticon/ui/MainActivity.kt, app/src/androidTest/java/de/lemke/geticon/TestApp.kt, CLAUDE.md
Define BuildConfig.FIRST_RUN_SKIPPABLE (false by default, true for nonMinifiedRelease), import and call onboardIfNeeded early in MainActivity.onCreate with early return when onboarding runs, update TestApp comment and CLAUDE.md architecture notes.
Baseline Profile with app navigation
baselineprofile/src/main/java/de/lemke/geticon/baselineprofile/BaselineProfileGenerator.kt
Add shared constants and UIAutomator imports; configure rule.collect (stable/max iterations, include startup profile), start activity with EXTRA_SKIP_ONBOARDING, and add navigateToIconAndBack() helper to simulate picker selection, wait for icon screen, and return.
Navigation drawer menu handler updates
app/src/main/java/de/lemke/geticon/ui/MainActivity.kt
Remove unused transition/View imports and adjust CommonUtils imports; refactor initDrawer to use commonutils_* destination IDs, expand when branches for APK extraction, About/About Me/Settings (via transformToActivity), LeakCanary, and set drawer title to R.string.app_name.
Documentation, lint baselines, and dependency updates
CLAUDE.md, app/lint-baseline.xml, gradle/libs.versions.toml
Document existing unit/screenshot and instrumented tests; add Overdraw lint baseline entries for activity_icon layouts and update UnusedResources locations; bump common-utils to 1.1.1 and mockk to 1.14.11.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

"🐰 I nudged the first run flag to sleep,
Benchmarks tiptoe past onboarding's keep,
ProfileGen hops, clicks, then hops back home,
Drawer labels twirl beneath the chrome,
Lint and deps sigh softly — all set to leap."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: reverting to multi-activity architecture and wiring the first-run flow, which aligns with the substantial refactoring shown across MainActivity, IconActivity, BaselineProfileGenerator, and build configuration.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/multi-activity-first-run-flow

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 and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the first-run flow using common-utils, updates the baseline profile generator to skip the first-run chain, deletes the IconActivityTest file, and temporarily includes the local common-utils build in settings. Feedback highlights critical issues: passing an empty Intent to startActivityAndWait will fail to launch the app, unconditionally including the sibling build path in settings.gradle.kts will break CI/CD environments, and using findViewById with menu item IDs in MainActivity can lead to null pointer exceptions.

Comment thread settings.gradle.kts Outdated
Comment thread app/src/main/java/de/lemke/geticon/ui/MainActivity.kt Outdated
Lemkinator and others added 5 commits May 31, 2026 18:27
… benchmark

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
handleFirstRun → onboardIfNeeded
EXTRA_SKIP_FIRST_RUN → EXTRA_SKIP_ONBOARDING

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Restore IconActivityTest.kt deleted by single-activity migration
- Replace (findViewByid ?: binding.navigationView) with findViewByid<View>:
  the ?: caused Kotlin to infer T=DrawerNavigationView, inserting a
  checkcast that failed at runtime; IDs exist in R.id so no fallback needed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Lemkinator
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces changes to support skipping the onboarding flow during baseline profile generation, updates the mockk dependency, and refactors navigation and onboarding logic in MainActivity. Feedback on the changes includes a recommendation to safely handle potential null values from findViewById when handling navigation clicks to prevent crashes, and a suggestion to remove a redundant non-null assertion operator (!!) in the Gradle build configuration.

Comment thread app/src/main/java/de/lemke/geticon/ui/MainActivity.kt
Comment thread app/build.gradle.kts
@Lemkinator
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the onboarding flow by integrating onboardIfNeeded from common-utils v1.1.0, replacing the previous OOBE setup. It introduces a FIRST_RUN_SKIPPABLE build configuration to allow baseline profile benchmarks to bypass onboarding, and enhances the baseline profile generator to navigate to the icon screen and back. Additionally, it updates dependency versions and refactors the navigation drawer menu item IDs in MainActivity. Feedback is provided regarding a potential NullPointerException when using findViewById on menu item IDs within the navigation drawer, suggesting a safe fallback helper to prevent crashes if the views are recycled or not yet laid out.

Comment thread app/src/main/java/de/lemke/geticon/ui/MainActivity.kt
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
app/lint-baseline.xml (1)

15-35: ⚡ Quick win

Verify the Overdraw suppression is intentional.

These baseline entries suppress Overdraw warnings for activity_icon.xml layouts where the root element paints ?roundedCornerColor while the theme also paints a background. Overdraw can impact rendering performance, though modern devices handle it well.

Please confirm:

  • Is the background on the root element necessary for visual design (e.g., rounded corners)?
  • Can the theme background be disabled for this activity to eliminate the overdraw?

If the background is required, the suppression is acceptable. Otherwise, consider removing one of the redundant backgrounds.

💡 Potential fix if theme background is not needed

If the roundedCornerColor is sufficient, you could apply a transparent theme background for IconActivity:

<style name="Theme.GetIcon.IconActivity" parent="CommonUtils.AppTheme">
    <item name="android:windowBackground">`@android`:color/transparent</item>
</style>

Then reference it in AndroidManifest.xml for IconActivity.

🤖 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/lint-baseline.xml` around lines 15 - 35, The lint baseline is suppressing
Overdraw for the root background in the layouts activity_icon.xml (root uses
android:background="?roundedCornerColor" and inferred theme
`@style/CommonUtils.AppTheme`); verify whether the root background is required for
the rounded-corner visual, and if not remove the root android:background from
src/main/res/layout/activity_icon.xml and
src/main/res/layout-land/activity_icon.xml to eliminate redundant theme
background, otherwise create/apply an activity-specific theme (e.g.,
Theme.GetIcon.IconActivity derived from CommonUtils.AppTheme) that sets
android:windowBackground to transparent and assign it to IconActivity in the
manifest so the theme background doesn't double-paint.
🤖 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/main/java/de/lemke/geticon/ui/MainActivity.kt`:
- Around line 80-83: The call to prepareActivityTransformationFrom() is executed
before the onboarding early-return, causing UI/transform setup even when
onboardIfNeeded(...) returns null; move prepareActivityTransformationFrom() so
it runs after the onboarding gate (i.e., after the
onboardIfNeeded(BuildConfig.VERSION_CODE, BuildConfig.VERSION_NAME, ...) ?:
return check inside MainActivity.onCreate()), keeping installSplashScreen() and
super.onCreate(savedInstanceState) in place as needed; update the onCreate()
sequence to call prepareActivityTransformationFrom() only after onboardIfNeeded
allows continuation.

In
`@baselineprofile/src/main/java/de/lemke/geticon/baselineprofile/BaselineProfileGenerator.kt`:
- Around line 52-60: In navigateToIconAndBack(), the UIAutomator finds are
treated as optional so the benchmark can continue silently when selectors fail;
replace the safe calls with explicit null checks (e.g., use requireNotNull or
throw IllegalStateException) for the result of
device.wait(Until.findObject(By.res(PACKAGE_NAME, "appPicker")), TIMEOUT_MS) and
for the subsequent findObject(By.clazz("android.widget.TextView")) (referenced
as appItem) and also for the final
device.wait(Until.findObject(By.res(PACKAGE_NAME, "icon")), TIMEOUT_MS); if any
are null, fail fast with a clear error message mentioning the missing selector
(appPicker/TextView/icon) so the benchmark stops instead of proceeding silently.

In `@CLAUDE.md`:
- Around line 18-20: Update the stale sentence in CLAUDE.md that reads "No
instrumented tests yet." to reflect that instrumented tests now exist; mention
the new instrumentation files such as TestApp
(app/src/androidTest/java/de/lemke/geticon/TestApp.kt) and the baseline-profile
generator test path so the README accurately documents current instrumented-test
coverage (replace or remove the outdated line and add a brief note pointing to
those instrumentation locations).

---

Nitpick comments:
In `@app/lint-baseline.xml`:
- Around line 15-35: The lint baseline is suppressing Overdraw for the root
background in the layouts activity_icon.xml (root uses
android:background="?roundedCornerColor" and inferred theme
`@style/CommonUtils.AppTheme`); verify whether the root background is required for
the rounded-corner visual, and if not remove the root android:background from
src/main/res/layout/activity_icon.xml and
src/main/res/layout-land/activity_icon.xml to eliminate redundant theme
background, otherwise create/apply an activity-specific theme (e.g.,
Theme.GetIcon.IconActivity derived from CommonUtils.AppTheme) that sets
android:windowBackground to transparent and assign it to IconActivity in the
manifest so the theme background doesn't double-paint.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b8bbfb5-4163-452a-a859-94881c92c668

📥 Commits

Reviewing files that changed from the base of the PR and between 8d0ea55 and 6f2ace6.

📒 Files selected for processing (7)
  • CLAUDE.md
  • app/build.gradle.kts
  • app/lint-baseline.xml
  • app/src/androidTest/java/de/lemke/geticon/TestApp.kt
  • app/src/main/java/de/lemke/geticon/ui/MainActivity.kt
  • baselineprofile/src/main/java/de/lemke/geticon/baselineprofile/BaselineProfileGenerator.kt
  • gradle/libs.versions.toml

Comment thread app/src/main/java/de/lemke/geticon/ui/MainActivity.kt Outdated
Comment thread CLAUDE.md Outdated
@Lemkinator
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the onboarding flow to use the new onboardIfNeeded utility from common-utils (which was upgraded to version 1.1.1). It introduces a FIRST_RUN_SKIPPABLE build config field to allow baseline profile benchmarks to bypass the onboarding flow using a new EXTRA_SKIP_ONBOARDING intent extra. Additionally, it refactors navigation logic in MainActivity, updates documentation in CLAUDE.md, and refines the baseline profile generator to navigate to the icon screen and back. I have no feedback to provide as there are no review comments.

Was called before super.onCreate() and before the onboardIfNeeded early
return — running unnecessarily on every first-run redirect and violating
the library's own kdoc ("after super.onCreate").
@Lemkinator
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the onboarding flow by integrating onboardIfNeeded from common-utils (which was upgraded to version 1.1.1), allowing benchmarks to skip the first-run chain via a new FIRST_RUN_SKIPPABLE build configuration. It also enhances the baseline profile generator to navigate through the app picker and icon screens, updates documentation, and cleans up MainActivity navigation logic. Feedback on these changes includes removing a redundant double-bang (!!) operator in the Gradle build file and resolving a potential UI Automator race condition in the baseline profile generator by waiting for descendants to be laid out.

Comment thread app/build.gradle.kts
@Lemkinator
Copy link
Copy Markdown
Owner Author

🤖 Claude Code · Won't fix (re: CodeRabbitAI at lint-baseline.xml:15-35) — suppression is intentional. Removing android:background="?roundedCornerColor" from the ToolbarLayout root causes a transparent background on the icon screen. The attribute is required for OneUI's rounded-corner design. Overdraw suppression is correct.

Avoids a race condition where the container appears before list items
are bound, causing findObject(TextView) to return null immediately.
@Lemkinator Lemkinator merged commit f411a4a into main Jun 1, 2026
8 checks passed
@Lemkinator Lemkinator deleted the feat/multi-activity-first-run-flow branch June 1, 2026 18:43
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