mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-11-09 15:33:31 +00:00
only picker overlays can finish a pick, and failed picks say why
- complete-capture-pick ignores any sender that isn't an open picker overlay - when a pick fails for a reason other than cancel, like a window that closed, the hud shows the message in a toast - moving or resizing an area reads a flag on the drag itself instead of react state, so a pointer move that lands before the next render still counts as part of the drag Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f91d1a1288
commit
feb5d0276a
4 files changed
+32
-7
No files matched your search
@@ -1,5 +1,9 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { closeCapturePickerWindows, createCapturePickerWindows } from "../../windows";
|
||||
import {
|
||||
closeCapturePickerWindows,
|
||||
createCapturePickerWindows,
|
||||
isCapturePickerWebContents,
|
||||
} from "../../windows";
|
||||
import { getNativeMacWindowsFrontToBack, stopWindowBoundsCapture } from "../cursor/bounds";
|
||||
import { setSelectedSource } from "../state";
|
||||
import { createAreaSource, createWindowSource, normalizeCapturePick } from "../sourceArea";
|
||||
@@ -115,7 +119,9 @@ export function registerCapturePickerHandlers() {
|
||||
return { success: true, source, record: pick.record };
|
||||
});
|
||||
|
||||
ipcMain.handle("complete-capture-pick", async (_, input: unknown) => {
|
||||
ipcMain.handle("complete-capture-pick", async (event, input: unknown) => {
|
||||
// Only the picker overlays answer a pick.
|
||||
if (!isCapturePickerWebContents(event.sender)) return;
|
||||
if (!input) {
|
||||
finishPick(null);
|
||||
return;
|
||||
|
||||
+6
-1
@@ -3,7 +3,7 @@ import fs from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
import { app, BrowserWindow, ipcMain, type WebContents } from "electron";
|
||||
import {
|
||||
supportsHudCaptureProtection,
|
||||
shouldProtectHudCapture,
|
||||
@@ -1261,6 +1261,11 @@ export function closeCapturePickerWindows(): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether a message came from one of the open picker overlays. */
|
||||
export function isCapturePickerWebContents(contents: WebContents): boolean {
|
||||
return capturePickerWindows.some((win) => !win.isDestroyed() && win.webContents === contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outlines the area being recorded. The outline sits just outside the recorded
|
||||
* rectangle and belongs to Recordly, which recordings exclude, so it never shows
|
||||
|
||||
@@ -25,8 +25,15 @@ type Selection = Target | { kind: "area"; rect: AreaRect };
|
||||
type Drag =
|
||||
| { kind: "press"; startX: number; startY: number }
|
||||
| { kind: "draw"; originX: number; originY: number }
|
||||
| { kind: "move"; startX: number; startY: number; rect: AreaRect }
|
||||
| { kind: "resize"; handle: AreaHandle; startX: number; startY: number; rect: AreaRect };
|
||||
| { kind: "move"; startX: number; startY: number; rect: AreaRect; moved: boolean }
|
||||
| {
|
||||
kind: "resize";
|
||||
handle: AreaHandle;
|
||||
startX: number;
|
||||
startY: number;
|
||||
rect: AreaRect;
|
||||
moved: boolean;
|
||||
};
|
||||
|
||||
const TOOLBAR_HEIGHT = 44;
|
||||
const TOOLBAR_GAP = 12;
|
||||
@@ -190,6 +197,7 @@ export function CapturePicker() {
|
||||
startX: event.clientX,
|
||||
startY: event.clientY,
|
||||
rect: current.rect,
|
||||
moved: false,
|
||||
};
|
||||
} else if (current && rectContains(current.rect, event.clientX, event.clientY)) {
|
||||
dragRef.current = {
|
||||
@@ -197,6 +205,7 @@ export function CapturePicker() {
|
||||
startX: event.clientX,
|
||||
startY: event.clientY,
|
||||
rect: current.rect,
|
||||
moved: false,
|
||||
};
|
||||
} else {
|
||||
dragRef.current = { kind: "press", startX: event.clientX, startY: event.clientY };
|
||||
@@ -245,7 +254,8 @@ export function CapturePicker() {
|
||||
const dx = event.clientX - active.startX;
|
||||
const dy = event.clientY - active.startY;
|
||||
// A click inside a picked window keeps it; only real movement turns it into an area.
|
||||
if (!dragging && Math.hypot(dx, dy) < DRAG_THRESHOLD / 2) return;
|
||||
if (!active.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD / 2) return;
|
||||
active.moved = true;
|
||||
setDragging(true);
|
||||
setSelection({
|
||||
kind: "area",
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { toast } from "@/components/ui/toast";
|
||||
import { useScopedT } from "../../contexts/I18nContext";
|
||||
import { useMicrophoneDevices } from "../../hooks/useMicrophoneDevices";
|
||||
import { useScreenRecorder } from "../../hooks/useScreenRecorder";
|
||||
@@ -188,7 +189,10 @@ function LaunchWindowContent() {
|
||||
|
||||
const handlePickOnScreen = async () => {
|
||||
const result = await window.electronAPI.pickCaptureTarget();
|
||||
if (!result.success) return;
|
||||
if (!result.success) {
|
||||
if (!result.canceled && result.message) toast.error(result.message);
|
||||
return;
|
||||
}
|
||||
if (result.record) {
|
||||
toggleRecording();
|
||||
} else if (result.source) {
|
||||
|
||||
Reference in new issue
Block a user