Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .openhands/memory/2026-11-14.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,107 @@ the `TextAppearance.Caramel` base style + its doc comment. Recovered by restorin
- Note: `git status` counts differ from `diff --stat` because many deletions were staged with
`git rm` (staged) while others were plain `rm` (unstaged) — use `git diff --stat HEAD` for the
true total.

## PR flow for this change (two repos)
- Parent branch `chore/remove-legacy-ui` → PR **ChimeraAnt-DEV/CaramelClient#184** (draft).
- Submodule `sweetloader` branch `chore/remove-in-game-menu` → PR **ChimeraAnt-DEV/SweetLoader#39** (draft).
The submodule remote URL is the OLD name (`preloader-android`) which 301-redirects to `SweetLoader`;
the git credential helper is absent there, so push with
`git -c credential.helper='!f() { echo username=x-access-token; echo password=$GITHUB_TOKEN; }; f' push`.
- **Submodule pin ancestry trap**: the previous pin `fac14a2` is NOT an ancestor of the submodule's
`origin/main` (it lives only on `feat/native-imgui-menu-and-present-frame-effects` + `refs/pull/38`).
No CI gate enforces "pin is on main" — `scripts/check_submodules.sh` only checks (a) no `branch =`
in `.gitmodules`, (b) a 160000 gitlink, (c) checkout == pin. So the parent PR's pin must point at
a commit that is reachable on the submodule's main, which is why the submodule PR exists.
- Commit identity in both repos: `Lynxifyy <297587416+Lynxifyy@users.noreply.github.com>` (matches the
last commit author; avoids GH007). No co-authors, no AI mentions.

## MAJOR DISCOVERY (2026-11-14, later session): the "new UI" the user now wants is the one the deletion removed

The user asked (after the deletion merged) to "use Lynxifyy/CaramelClient-UI-pack as the client's
UI". But `main` **before** the deletion (`6b83ec5`) already *was* a port of that pack:

- `ui/compose/caramel/Caramel{Theme,Controls,Glass,Labels,Util}.kt` = the pack's `theme/Theme.kt` +
`components/*`, value for value (the pack's Compose **Desktop** files are not imported; this is the
Android port). Consumed by `caramel/launch/CaramelLaunchScreen.kt` (631 lines = the pack's
`launcher/Home.kt` screen), hosted by `MainActivity.setupCaramelLaunchScreen()`.
- `sweetloader/src/pl/menu/*` (MenuRender/Theme/Widgets/Host/Jni) = "a screen-level port of the UI
pack's `imgui/src/CaramelMenu.cpp`". Its only consumer was `PresentFrameEffect::OnPresentBoundary`.

Both were deleted by `8a73b8b` (parent PR #184, merged as `cf3c814`) and submodule PR #39 (merged as
`8b69236`). So "use the pack" = **restore that port**, not build new. A plain `git revert 8a73b8b`
restores it and is guaranteed green (the pre-deletion tree passed CI).

**Coverage gap**: only the *launch screen* (Home) + the *in-game menu* were ported. The pack's other
tabs (Mods/Servers/Cosmetics/News/Store) were never ported; those screens were the old View-based
ones (now deleted). The pack's own versions of them carry placeholder data ("Example Network",
"Example Cape", "12,408 playing") which rule 4 (honesty) forbids shipping.

**"Tree background"**: the pack's mod-menu *previews* (`previews/mod_menu/*.png`) show a voxel
tree/forest landscape behind the menu — drawn by `preview/lib.py:game_bg()` as a stand-in for the
game. The real C++ menu draws no trees; it dims the live game (`AddRectFilled(..., IM_COL32(4,9,28,120))`).
So there is nothing tree-shaped to remove in the client — but the backdrop dim could be removed/
made transparent. Needs user confirmation.

**Restore is entangled**: `MainActivity` (2244 lines, the pack launch screen's host) references ~30
legacy UI classes (MsftLoginActivity, SetupWizardActivity, VoiceChatActivity, CustomAlertDialog,
LoadingDialog, DynamicAnim, LaunchIntro, ActivityMainBinding, …). So restoring the pack UI alone is
NOT a clean subset — a full revert brings the legacy View UI back too.

## Outcome (later same day): ported the pack, PRs opened

Did NOT revert `8a73b8b` — that would have brought the whole legacy View UI back. Instead ported the
pack's Compose launcher as new code and restored the native menu on a fresh branch off current `main`.

- **Launcher**: `MainActivity` (Java) hosts one `ComposeView`; `CaramelLauncherHost` is the Java-facing
seam (activity supplies `Actions`, Kotlin supplies the frame). Pack ported under
`ui/compose/caramel/` — frame, glass title bar, 56dp sidebar rail, all six tabs (Home/Mods/Servers/
Cosmetics/News/Store). The pack's `Versions`/`ExampleMods`/`ExampleServers` were **dropped**:
`CaramelLauncherState` defaults every list empty and the activity fills it from `VersionManager`,
`MsftAccountStore`, `ModManager`, so empty screens draw empty states (honesty rule). Store tab says
"coming soon".
- **Native menu**: restored `src/pl/menu/*` + vendored `third_party/imgui` 1.91.5 + `NOTICE` on a
**fresh submodule branch off `origin/main`** (`feat/restore-pack-menu`), not off the old removal
commit — the removal PR #39 had already merged (`8b69236`), so the working tree delta vs `origin/main`
was pure additions (verified: `git diff --stat 3fda389 origin/main` is empty, so the old HEAD tree ==
origin/main tree). Removed the full-screen dim scrim; `MenuHost::Frame` skips the whole ImGui frame
while closed. Java bridge `InGameMenuController` + `PreloaderMenu` restored to their **original paths**
(the preloader dir holds files declaring `org.chimeramc.client.preloader` — path != package, that is
the convention).
- **Two hygiene gates caught real bugs** the local build was silent on: `NoEmojiInUiTextTest` (a `★`
in a `FilterChip` label) and `Api28CompatTest` (`String.isBlank` = API 33 → used `q.trim().isEmpty()`).
Also restored `ModUnavailableReasonResourcesTest` (deleted with the menu; pins the four
`mod_unavailable_reason*` strings and that `MenuRender.cpp` draws `m.unavailableReason`, not a raw id).
- **Verified**: `:app:testDebugUnitTest` 3167/0, `:app:assembleDebug` green incl NDK (`libsweetloader.so`
exports `Java_..._PreloaderMenu_*`), `:app:lintDebug`, `check_ui_hygiene.py`, `validate_release_content.py`,
`check_submodules.sh`, `verify_berryapi_abi.py` clean; `sweetloader/tests/cosmetics/run_tests.sh` green.
- **PRs**: ChimeraAnt-DEV/SweetLoader#40 (`feat/restore-pack-menu`) and ChimeraAnt-DEV/CaramelClient#185
(`feat/port-caramel-ui-pack`, gitlink → 4ff2e63). Both marked ready (GraphQL
`markPullRequestReadyForReview`) and **both CI green** (SweetLoader 4 gates; CaramelClient `build`
success, `instrumented-smoke` skipped). The submodule remote URL redirects: canonical repo is
`ChimeraAnt-DEV/SweetLoader`, not `.../preloader-android` (301).

## Follow-up: finished the launcher port (PR #186)

PR #185 merged, but the port had two real holes that only showed once it was on `main`:
`SplashActivity` (the sole `LAUNCHER` entry) was still the placeholder stub — it drew nothing and
started nothing, so the app could not leave the splash; and the account/screenshots/instance-settings
surfaces had no host behind them. Fixed on `feat/caramel-ui-splash-modals` (commit 39006e4, PR #186):

- `SplashActivity` warms `VersionManager.initializeAsync` then navigates; a `MainThread.Scope`
`postDelayed` backstop (4s) guarantees the handover even if the store stalls. Compose screen via
`CaramelSplashHost`; window bg is the pack navy so no white flash.
- `CaramelModals` / `CaramelModalParts` = account menu, account settings, add-account (device-code),
screenshots grid, friends, add friend, instance settings, launcher settings — all wired to real
`MainActivity` actions.
- `ThreadOwnershipTest` failures were exactly the two things that test exists to catch: the old
`new Handler(Looper.getMainLooper())` in `SplashActivity` and a `new Thread(...)` in `MainActivity`.
Both now go through `MainThread.scope()` / `AppExecutors.run(...)`.
- **New lint error `UnsafeImplicitIntentLaunch`** from the port's `ACTION_VIEW` folder/screenshot
opens. Repo convention is one audited suppression helper (`UrlOpener` for https); added
`util/LocalFileOpener` (folder + image) which also switches `Uri.fromFile` → `FileProvider` content
uri (a `file:` uri is not readable by another app since API 24, so the old form opened a chooser
that then failed). `:app:lintDebug` green again.

Verified: `:app:testDebugUnitTest` 3167/0, `:app:assembleDebug`, `:app:lintDebug`, `check_ui_hygiene.py`,
`verify_berryapi_abi.py`, `check_submodules.sh`, `validate_release_content.py` all clean.
26 changes: 19 additions & 7 deletions .openhands/memory/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@ Index only. Detail and session notes live in the daily logs (`YYYY-MM-DD.md`).

The repo was called **GlowberryClient** before; the package is `org.chimeramc.client` either way.

### UI skeleton state (2026-11-14: the whole legacy UI was deleted for a new one)
The launcher UI + the in-game Mod Menu UI were removed in one sweep, keeping every system. Do not
re-add the old UI; a new one is being dropped in. See the 2026-11-14 daily log for the full list.
### UI skeleton state (2026-11-14: legacy UI deleted, then the pack UI ported back)
The launcher UI + the in-game Mod Menu UI were removed in one sweep, keeping every system; the
Caramel UI pack was then ported back in on top of current `main` (PR #185 + SweetLoader #40). **Do
not re-add the old View-based UI** — the pack port is the way forward. The port **did not** restore
the pack's demo data (`Versions`/`ExampleMods`/`ExampleServers`): `CaramelLauncherState` defaults
every list empty and `MainActivity` fills it from `VersionManager`/`MsftAccountStore`/`ModManager`,
so empty screens draw empty states (honesty rule). See the 2026-11-14 daily log for the full list.
- **`ui.activities` files live under `launcher/ui/activities/`** (dir ≠ package for the whole
`launcher/ui` tree — package decls are `org.chimeramc.client.ui.*`). Operate on FILES, not dirs.
- 7 placeholder Activities remain (`BaseActivity` + `MainActivity`/`SplashActivity`/`LibraryActivity`/
`SettingsActivity`/`ModsFullscreenActivity`/`CrashActivity`); they draw nothing but are manifest
targets. `MainActivity.setTextMinecraftVersion()` and `LibraryActivity.EXTRA_INITIAL_TAB`/`TAB_*`
are kept no-op API other code still calls. Layouts 94→20; the kept 20 are the game-host/HUD ones.
- **The in-game menu was 3 layers, all cut**: native ImGui (`sweetloader/src/pl/menu/` + vendored
`third_party/imgui/`, consumed only by `PresentFrameEffect.cpp`), the Java bridge
(`PreloaderMenu`/`InGameMenuController`), and the launcher overlay widgets (`MoreButtonsEditor`,
`VoicePanel`/`VoiceUiKit`, `CosmeticsPanel`). `DebugMenuOverlay` is the F3 overlay MOD — keep it.
- **The in-game menu was 3 layers, all cut, then the native one restored** (SweetLoader #40): native
ImGui (`sweetloader/src/pl/menu/` + vendored `third_party/imgui/`, consumed only by
`PresentFrameEffect.cpp`), the Java bridge (`PreloaderMenu`/`InGameMenuController`), and the
launcher overlay widgets (`MoreButtonsEditor`, `VoicePanel`/`VoiceUiKit`, `CosmeticsPanel`, still
cut). `DebugMenuOverlay` is the F3 overlay MOD — keep it. The menu is drawn from the present hook
**with no full-screen dim scrim**, and the host skips the whole ImGui frame while the menu is closed.
- **Kept (a new UI will reuse them)**: `UiTokens`, `Widget.Caramel.Card*`, `TextAppearance.Caramel.*`,
`GlowDimens`, generic `bg_*`/`ic_*` drawables, `PersonalizationManager`, all `core.*` systems.
Removed only the dead legacy chrome (`splash_bg_*`, `launch_bg_*`, dock/nav drawables + styles).
Expand All @@ -38,6 +44,9 @@ re-add the old UI; a new one is being dropped in. See the 2026-11-14 daily log f
unmerged, and then a clean checkout depends on that branch surviving. `scripts/check_submodules.sh`
gates it. Check with `git -C <sub> merge-base --is-ancestor <pin> origin/main`, and note a pin can
be *behind main by one* while still looking "on a branch" (`git log --oneline <pin>..origin/main`).
`scripts/check_submodules.sh` does **not** check ancestry (only that no `branch =` floats and the
checkout equals the pin), so a `feat/*` tip pin passes it — PR #185 pins `4ff2e63` on
`feat/restore-pack-menu`, which must merge (SweetLoader #40) before/with it.
- **`.universe` and `.singularity` are the only mod formats** (`.AntEgg`/`.chimerapack`/`.levipack`
are gone). Rust workspace `sweetloader/rust/`: `universe-core/-jni`
(manifest/archive/signature/loadorder/permission/config/report/runtime/fault/version/patterns),
Expand Down Expand Up @@ -169,4 +178,7 @@ re-add the old UI; a new one is being dropped in. See the 2026-11-14 daily log f
baseline, which *shrinks* when a `findViewById` is replaced by a ViewBinding read).
- **`NoSilentCatchTest`**: a `catch` that discards the throwable fails. Use
`AppLog.warnOnce(tag, key, message, e)`, even for an expected `UnsatisfiedLinkError` fail-closed path.
- **`NoEmojiInUiTextTest` / `NoEmojiTest`**: no emoji/glyph codepoints in client UI strings (a `★` in
a Compose `FilterChip` label fails it). **`Api28CompatTest`**: shipped sources must not call an API
newer than 28 — `String.isBlank` (33) is the usual slip, use `s.trim().isEmpty()`.
- Baseline format note: the baseline files live under **`scripts/hygiene/`**, not `scripts/`.
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
android:name="org.chimeramc.client.ui.activities.SplashActivity"
android:exported="true"
android:screenOrientation="sensorLandscape"
android:theme="@style/LauncherTheme"
android:configChanges="fontScale|density|smallestScreenSize|screenSize|uiMode|screenLayout|orientation|navigation|keyboardHidden|keyboard|touchscreen|locale|mnc|mcc"
tools:ignore="DiscouragedApi">
<intent-filter>
Expand All @@ -93,7 +94,7 @@
android:name="org.chimeramc.client.ui.activities.MainActivity"
android:exported="true"
android:screenOrientation="sensorLandscape"
android:theme="@style/MainActivityTheme"
android:theme="@style/LauncherTheme"
android:configChanges="fontScale|density|smallestScreenSize|screenSize|uiMode|screenLayout|orientation|navigation|keyboardHidden|keyboard|touchscreen|locale|mnc|mcc"
tools:ignore="DiscouragedApi">

Expand Down
Loading
Loading