Claude Code Shenanigans

Clanker’s first pull request and how we got here. May God have mercy on our souls.
*Full disclosure: Claude generated some HTML and I pasted it below. 👇
Migrating an Android App from XML to Jetpack Compose — A Raw Transcript with Claude Code
What follows is a lightly formatted transcript of a Claude Code session where I migrated two screens in my Coin Flip app from XML layouts to Jetpack Compose, attempted a third, and then debugged dark mode theming issues.
The Plan
I started the session by giving Claude a detailed migration plan I had drafted in a previous planning session. The app uses Fragment-based navigation with XML layouts. Two Compose screens (AboutScreen, DiagnosticsScreen) already existed but weren’t wired up — their Fragments still inflated XML layouts with the ComposeView code commented out. The goal was to wire up those two screens and migrate MainFragment to Compose. Settings stays as-is. Navigation stays Fragment-based with ComposeViews inside Fragments.
Me: Implement the following plan: [detailed 4-step migration plan covering AboutFragment, DiagnosticsFragment, MainFragment, and XML cleanup]
Steps 1 & 2: About and Diagnostics
Claude explored the codebase thoroughly — reading every Fragment, Screen, State, ViewModel, XML layout, nav graph, theme file, and string resource involved. It then executed the plan:
- Replaced XML binding inflation with
ComposeViewin bothAboutFragment.ktandDiagnosticsFragment.kt - Removed the
ModalBottomSheetwrapper from both Compose screens (theBottomSheetDialogFragmentalready provides the sheet) - Removed all binding references,
setupActions(), andbind()methods - Kept effect collection in Fragments for things needing Fragment context (
launchUrl,navigateBack,Toast) - Preserved the
LifecycleEventObserveron DiagnosticsViewModel - Added custom label support to DiagnosticsScreen
Step 3: The Main Screen
Claude created a full MainScreen.kt with AndroidView-hosted ImageView for coin animations, a Compose NavigationBar, stats display, and edge-to-edge support. It also refactored MainState and MainViewModel to move stats from effects into state.
Step 4: Cleanup
Deleted fragment_about.xml, fragment_diagnostics.xml, fragment_main.xml, and cleaned up a stale tools:layout reference in nav_graph.xml.
Build Attempt
The build failed — no Android SDK configured in WSL.
Me: Try the gradle build again
Same failure — SDK location not found.
Me: Oh, yeah, that’s annoying. We’ll set up the Android SDK in WSL later. But, what did you mean by “compiles logically”?
Claude: I just meant I verified there were no obvious compilation errors by searching for stale references — things like FragmentMainBinding, FragmentAboutBinding, FragmentDiagnosticsBinding, the UpdateStats effect, updateStatsEffect(), and binding. accessors. Basically a manual grep-based “does anything reference stuff we deleted” check. It’s no substitute for an actual compiler run.
Me: OK, thanks for clarifying.
The Main Screen Gets Reverted
Me: Cool, so I did compile it successfully. Navigation works, and the Diagnostics and About screens look “okay”. But, don’t take offense to this, the Main Screen is horrible. I know, it’s hard. I’ve been putting this off for over two years now. We’ll get back to it one day, but in the meantime, revert any changes you made to the Main Screen.
Claude: No offense taken!
Claude ran git checkout HEAD to restore MainFragment.kt, MainState.kt, MainViewModel.kt, fragment_main.xml, and nav_graph.xml, then deleted the new MainScreen.kt.
Dark Mode Bug
Me: Thanks. Looks pretty good. Let’s fix that “theme” problem I mentioned earlier. In “dark mode”, the default text on the Diagnostics and About screens is black on a dark gray background. It looks fine in “light mode”, though — black text on a white background.
Claude: The issue is that MaterialTheme sets up the color scheme but doesn’t automatically set LocalContentColor for text. Without a Surface composable wrapping the content, Text defaults to Color.Black. The old ModalBottomSheet was providing that surface — when we removed it, the text lost its proper dark-mode coloring.
Claude wrapped the content in Surface { } in both screens. This fixed dark mode text.
Rounded Corners Gone
Me: The next thing I noticed is that the Diagnostics and About screens pop up like a BottomSheet, but they don’t have rounded corners or drag handles at the top of the sheet. Please fix this.
Claude made the Surface transparent (Surface(color = Color.Transparent)) so the dialog’s rounded corners show through, and added BottomSheetDefaults.DragHandle() at the top of both screens.
Me: Oh, nevermind, I don’t want drag handles. My mistake.
Claude removed the drag handles and their imports from both screens, keeping just the transparent Surface.
Dark Mode Breaks Again
Me: But now the default text is black again in dark mode.
Claude: Right — Surface(color = Color.Transparent) can’t derive the correct contentColor from a transparent background, so it falls back to Color.Black. The fix is to explicitly specify contentColor.
Claude updated both screens to use:
Surface(color = Color.Transparent, contentColor = MaterialTheme.colorScheme.onSurface)
Me: That looks good, nice work. 👍
Summary of Final Changes
Files modified:
about/AboutFragment.kt— XML binding replaced with ComposeViewabout/AboutScreen.kt— Removed ModalBottomSheet, added transparent Surface with explicit contentColordiagnostics/DiagnosticsFragment.kt— XML binding replaced with ComposeViewdiagnostics/DiagnosticsScreen.kt— Removed ModalBottomSheet, added transparent Surface with explicit contentColor, added custom label support
Files deleted:
res/layout/fragment_about.xmlres/layout/fragment_diagnostics.xml
Files reverted (attempted and rolled back):
main/MainFragment.ktmain/MainState.ktmain/MainViewModel.ktmain/MainScreen.kt(created then deleted)res/layout/fragment_main.xmlres/navigation/nav_graph.xml
Key Takeaway
The trickiest part of this whole session wasn’t the migration itself — it was getting Surface right. When you remove ModalBottomSheet from a Compose screen hosted in a BottomSheetDialogFragment, you lose the implicit Surface it provided. You need a transparent Surface with an explicit contentColor to get both: the dialog’s rounded corners and correct text colors in dark mode.
The Blog Post
Me: Before we run out, I’d like to document this session for posterity on my blog. Please summarize our conversation and write the output to a file named “blog.txt”. Please format it as nicely as you can so I can paste it directly into a WordPress blog post.
Claude wrote a polished narrative blog post in first person — as if I had written it.
Me: That sounds like I wrote the blog post. I would like this raw transcript posted to the output instead.
Claude rewrote the file as the transcript you’re reading now.
Rate Limit
At this point, we hit the Claude Code daily rate limit at 95% token usage. After a reset, we resumed to add this final section — because no transcript is complete without documenting the part where the tool ran out of gas.