Skip to content

fix(desktop): restore last confirmed capture area when reopening selector#1872

Open
ManthanNimodiya wants to merge 3 commits into
CapSoftware:mainfrom
ManthanNimodiya:fix/capture-area-restore-last-selection
Open

fix(desktop): restore last confirmed capture area when reopening selector#1872
ManthanNimodiya wants to merge 3 commits into
CapSoftware:mainfrom
ManthanNimodiya:fix/capture-area-restore-last-selection

Conversation

@ManthanNimodiya
Copy link
Copy Markdown
Contributor

@ManthanNimodiya ManthanNimodiya commented May 26, 2026

Problem

When a user had previously selected a capture area and reopened the area selector, it always started blank, forcing them to redraw their selection every time.
This was reported by multiple users in the community.

The root cause was in target-select-overlay.tsx: initialAreaBounds (which seeds the Cropper's starting position) was always initialized to undefined, even when an existing area target was already set.

Solution

Added an effectiveInitialBounds memo that falls back to the current captureTarget area bounds when no explicit initialAreaBounds is set.
Both initialCrop and shouldShowSelectionHint now use this memo, so:

  • Opening the selector with a previously confirmed area pre-loads those bounds
  • The "draw a selection" hint is suppressed when bounds are available
  • Re-entering area mode within the same session also restores correctly

Also fixed capture-area.tsx (the alternate area selection flow) with the same pattern, activeScreenId now handles both "display" and "area" capture target variants.

Test Plan

  • Confirm a capture area → reopen selector → previous selection is pre-loaded ✓
  • Adjust the pre-loaded area → close → reopen → shows updated bounds ✓
  • Switch to display mode and back to area mode within same session → bounds restored ✓
  • First-time use (no previous area) → blank selector with draw hint ✓

Greptile Summary

This PR restores previously confirmed capture-area bounds when the selector is reopened, fixing a reported UX regression. The fix addresses both selection flows independently: target-select-overlay.tsx gets an effectiveInitialBounds memo that falls back to options.captureTarget.bounds (guarded by target.screen === params.displayId for multi-display safety), and capture-area.tsx gets a screenId derived from both "display" and "area" variants so that a prior area confirmation no longer silently breaks subsequent saves and pre-loads.

  • target-select-overlay.tsx: new effectiveInitialBounds memo correctly short-circuits to stored captureTarget bounds; drives both shouldShowSelectionHint and initialCrop.
  • capture-area.tsx: activeScreenId now returns target.screen for the "area" variant; a "frozen on first non-null" pattern prevents stale async Tauri-store updates from overwriting the resolved screen ID. Minor gap: initialCrop doesn't fall back to rawOptions.captureTarget.bounds, so the first open of capture-area.tsx after an overlay-confirmed area still starts blank.

Confidence Score: 4/5

Safe to merge; the fix is scoped to UI initialisation logic and cannot cause data loss or corrupt the saved capture target.

The overlay fix is solid and well-guarded. The capture-area.tsx fix correctly unblocks the previously broken area variant path, but the initialCrop accessor still reads only from state.lastSelectedBounds and doesn't fall back to rawOptions.captureTarget.bounds, leaving a small parity gap with the overlay flow. The redundant reactive dependency in the frozen-signal effect is harmless but worth cleaning up.

apps/desktop/src/routes/capture-area.tsx — the initialCrop fallback logic and the screenId guard effect.

Important Files Changed

Filename Overview
apps/desktop/src/routes/capture-area.tsx Adds activeScreenId memo to handle both display and area variants, and a frozen screenId signal to prevent stale async Tauri-store resets; correctly threads screenId through hasStoredSelection, handleConfirm, reset, and initialCrop. Minor: screenId() is read as a reactive dep inside the guard effect (benign extra run), and initialCrop doesn't fall back to rawOptions.captureTarget.bounds for the area variant, leaving a gap when the area was last confirmed via the overlay flow.
apps/desktop/src/routes/target-select-overlay.tsx Adds effectiveInitialBounds memo that falls back to options.captureTarget.bounds when initialAreaBounds is unset and the current display matches; correctly guards on target.screen === params.displayId for multi-display safety; updates both shouldShowSelectionHint and initialCrop to use the new memo. Logic looks correct.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/desktop/src/routes/capture-area.tsx:95-98
**Effect reads `screenId()` as a reactive dependency**

`screenId()` is accessed inside the effect body, so SolidJS tracks it as a dependency. When `setScreenId(id)` fires, the effect re-runs: `activeScreenId()` is still the same `id`, `!screenId()` is now `false`, so nothing happens — it's benign but causes an extra scheduling cycle. Using `untrack(screenId)` inside the condition removes the unnecessary dependency and matches the intent of "only set once."

```suggestion
	createEffect(() => {
		const id = activeScreenId();
		if (id && !untrack(screenId)) setScreenId(id);
	});
```

### Issue 2 of 2
apps/desktop/src/routes/capture-area.tsx:313-321
**`initialCrop` doesn't fall back to `rawOptions.captureTarget.bounds` for the area variant**

`state.lastSelectedBounds` is only populated by `capture-area.tsx`'s own `handleConfirm`. If the user previously confirmed an area through `target-select-overlay.tsx` (which writes only to `options.captureTarget`), `state.lastSelectedBounds` will have no entry for that screen, and `initialCrop` returns `CROP_ZERO`. The overlay's `effectiveInitialBounds` memo handles this by falling back to `options.captureTarget.bounds` when variant is `"area"` — the same pattern could be applied here to keep both flows consistent.

Reviews (1): Last reviewed commit: "fix(desktop): restore last confirmed cap..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

@superagent-security superagent-security Bot added contributor:verified Contributor passed trust analysis. pr:verified PR passed security analysis. labels May 26, 2026
Comment thread apps/desktop/src/routes/capture-area.tsx
Comment thread apps/desktop/src/routes/capture-area.tsx
@ManthanNimodiya
Copy link
Copy Markdown
Contributor Author

@richiemcilroy, have a look when you get chance and lmk for any changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor:verified Contributor passed trust analysis. pr:verified PR passed security analysis.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant