Skip to content

UI Polish + Fixes Plan (2026-07-03)

Batch of fixes/features on top of the missing-UI work. Ordered; commit per group.

1. Result loot crash (CRITICAL) — ResultScreenView.RenderLoot

MissingComponentException at cg.alpha: GetComponent<CanvasGroup>() ?? AddComponent<...>() — the ?? operator bypasses Unity's fake-null override, returning a missing component. Fix: explicit var cg = GetComponent<CanvasGroup>(); if (cg == null) cg = AddComponent<...>();.

2. Map markers (MapView / MapController / MapMarker)

  • Flat crisp circle — current Circle() fades RGB centre→rim, which reads as a gradient. Make a flat solid disc (uniform colour, hard AA edge) + a thin constant dark outline ring. Shared static sprite → affects minimap AND full map (verify the minimap actually re-renders).
  • Zoomed marker sizeRender uses m.Size * _dotScale (fixed). When zoomed (vp.SpanUV < 1) scale dots up by 1/span (fit-all = 1×, zoom 0.5 = 2×) so they grow with the map.
  • Pulsing markers — add bool Pulse to MapMarker. RebuildMarkers sets it on portals (descent + open exits) and boss enemies (the "portal guard"). MapView.Render applies a time-based sine size pulse to pulsing markers AND always to the player dot (web player blip).

3. Settings vibration toggle disabled marker (UIToggle)

Add [SerializeField] GameObject disabledMark; shown when OFF (mirrors the slider's 0 mark). Wire the vibration row's img_disabled to the vibration UIToggle.

4. Unified player Power (single source of truth)

Lobby / inventory / equipment / in-raid top panels show different Power. Create one helper GearStats-based compute (saved loadout, else starter kit) and route every top-panel Power through it: LobbyController.PlayerPower, InventoryController (equipment + inventory top panels), in-raid HUD (RaidState.PlayerPower is set on spawn from the same source — confirm it matches). Find all .power/Power readouts and unify.

5. UIButton two-step confirm mode (reusable)

Add an opt-in confirm state: - SetConfirm(bool required, float cooldown = -1f) + optional [SerializeField] TMP_Text label. - First click (when required & not awaiting) → label → "Confirm?", become the single global pending-confirm button (entering confirm on ANY button resets the previous one = "different click" resets). cooldown >= 0 auto-resets after that many unscaled seconds; default -1 = no auto-reset. - OnDisable/re-show resets (view reopen). - Second click (awaiting) → reset + fire Clicked. Apply to: - Settings Delete — always confirm → SettingsController wipes the save (ISaveService.Wipe) + reloads. - Item-card Scrap — confirm when the item is better-than-current OR equipped (equipped always confirms). InventoryController/card sets scrapButton.SetConfirm(required) per item.

6. Wire Settings Delete (ITEM 5 dependency)

SettingsView expose DeleteClicked (btn_delete UIButton, confirm-mode) → SettingsController_save.Wipe() + scene reload.

Commit groups

  1. crash fix · 2. map markers (flat circle + zoom size + pulse) · 3. toggle disabled mark ·
  2. UIButton confirm + settings delete · 5. scrap confirm · 6. unified power.