diff --git a/src/app/constants.ts b/src/app/constants.ts index 69ee5315..d0f27e2b 100644 --- a/src/app/constants.ts +++ b/src/app/constants.ts @@ -43,11 +43,13 @@ export const DEFAULT_SETTINGS = { ultraFast: true, audioDevicesToRecord: [] as string[], seperateAudioTracks: false, - hardwareEncoding: false + hardwareEncoding: false, + regionToRecord: { x: 0, y: 0, width: 0, height: 0 } }, key: { startStopRecording: "F9", startStopRecordingRegion: "F10", + startStopRecordingSavedRegion: "Shift+F10", addBookmark: "F2" } } as Settings; diff --git a/src/common/Icon.tsx b/src/common/Icon.tsx index 77dd1a18..717fe683 100644 --- a/src/common/Icon.tsx +++ b/src/common/Icon.tsx @@ -40,7 +40,8 @@ export type Icons = | "bookmark" | "film" | "camera" - | "trash"; + | "trash" + | "move"; export type IconDirection = "up" | "down" | "left" | "right"; @@ -460,6 +461,20 @@ function getIcon(name: Icons): { viewBox: string; el: JSX.Element } { ) }; + case "move": + return { + viewBox: "0 0 512 512", + el: ( + + ) + }; default: return { viewBox: "0 -10 1000 1000", diff --git a/src/common/RegionSelect.tsx b/src/common/RegionSelect.tsx index 39e992b5..b5a25e17 100644 --- a/src/common/RegionSelect.tsx +++ b/src/common/RegionSelect.tsx @@ -1,5 +1,6 @@ import { ipcRenderer } from "electron"; import { useEffect, useRef } from "react"; +import { type CustomRegion } from "@/libs/recorder/argumentBuilder"; export default function RegionSelect() { const dRef = useRef(null); @@ -97,7 +98,7 @@ export default function RegionSelect() { console.log("stopDraw"); isDrawing = false; const br = regionDiv.getBoundingClientRect(); - ipcRenderer.send("region-selected", { x: br.x, y: br.y, width: br.width, height: br.height }); + ipcRenderer.send("region-selected", { x: br.x, y: br.y, width: br.width, height: br.height } as CustomRegion); } catch (err) { ipcRenderer.send("region-select-cancelled", "stopDraw failed", err); } diff --git a/src/common/TextBox.tsx b/src/common/TextBox.tsx index fde341a7..bcb16444 100644 --- a/src/common/TextBox.tsx +++ b/src/common/TextBox.tsx @@ -1,7 +1,7 @@ import useDebouncer from "@/hooks/useDebouncer"; import { logger } from "@/libs/logger"; import { ipcRenderer } from "electron"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import Icon, { type Icons } from "./Icon"; import { type CommonComponentProps } from "./types"; @@ -41,6 +41,10 @@ export default function TextBox(props: TextBoxProps) { const { doDebounce } = useDebouncer(debounce); const [curVal, setCurVal] = useState(value); + useEffect(() => { + setCurVal(value); + }, [value]); + // newVal param set as string becuase we get input value // from onBlur event (e.target.value), which returns as only string. // So no point having union type to include numbers as well. diff --git a/src/libs/recorder/index.ts b/src/libs/recorder/index.ts index c0fe9beb..fe890320 100644 --- a/src/libs/recorder/index.ts +++ b/src/libs/recorder/index.ts @@ -17,6 +17,23 @@ ipcRenderer.on("startStopRecordingRegion-pressed", async () => { await Recorder.auto(b); }); +ipcRenderer.on("startStopRecordingSavedRegion-pressed", async () => { + const r = store.getState().settings.recording.regionToRecord; + // A width and height at the very least is required. + if (!r.width || !r.height) { + logger.error("Recorder", "Cant record saved region", "a width and height must be set"); + Notifications.popup({ + id: "CANT-RECORD-SR", + title: "Can't Record Saved Region!", + message: "A width and or height has not been provided in settings!", + showCancel: true + }).catch((err) => logger.error("Recorder", "Failed to show CANT-RECORD-SR popup", err)); + return; + } + logger.info("Recorder", "Saved Region", r); + await Recorder.auto(r); +}); + ipcRenderer.on("addBookmark-pressed", async () => { if (store.getState().recorder.recordingStatus !== 1) { console.log("can't add bookmark when not recording"); diff --git a/src/settings/keybind/KeyBindings.tsx b/src/settings/keybind/KeyBindings.tsx index 6e2eb16d..64438af0 100644 --- a/src/settings/keybind/KeyBindings.tsx +++ b/src/settings/keybind/KeyBindings.tsx @@ -1,7 +1,12 @@ import { type RootState } from "@/app/store"; import { useDispatch, useSelector } from "react-redux"; import NamedContainer from "../../common/NamedContainer"; -import { setAddBookmark, setStartStopRecording, setStartStopRecordingRegion } from "../settingsSlice"; +import { + setAddBookmark, + setStartStopRecording, + setStartStopRecordingRegion, + setStartStopRecordingSavedRegion +} from "../settingsSlice"; import KeyBindButton from "./KeyBindButton"; export default function KeyBindings() { @@ -19,7 +24,7 @@ export default function KeyBindings() { }} /> - + + + { + dispatch(setStartStopRecordingSavedRegion(newBind)); + }} + /> + store.settings.recording); @@ -51,6 +55,15 @@ export default function Recording() { .catch((err) => logger.error("Recording", "Failed to get audio devices!", err)); }, []); + async function dragRegionToRecord() { + try { + const b = await ipcRenderer.invoke("select-region-win"); + dispatch(setRegionToRecord({ x: b.x, y: b.y, width: b.width, height: b.height })); + } catch (err) { + logger.error("Settings/Recording", "Failed to drag new region", err); + } + } + return ( <> @@ -69,6 +82,50 @@ export default function Recording() { /> + +
+ X + { + dispatch(setRegionToRecord({ x: s })); + }} + /> + Y + { + dispatch(setRegionToRecord({ y: s })); + }} + /> + W + { + dispatch(setRegionToRecord({ width: s })); + }} + /> + H + { + dispatch(setRegionToRecord({ height: s })); + }} + /> + +
+
+ ) { state.recording.hardwareEncoding = action.payload; }, + setRegionToRecord(state, action: PayloadAction<{ x?: number; y?: number; width?: number; height?: number }>) { + if (typeof action.payload.x === "number") state.recording.regionToRecord.x = action.payload.x; + if (typeof action.payload.y === "number") state.recording.regionToRecord.y = action.payload.y; + if (typeof action.payload.width === "number") state.recording.regionToRecord.width = action.payload.width; + if (typeof action.payload.height === "number") state.recording.regionToRecord.height = action.payload.height; + }, // // Key Binding Settings @@ -95,6 +101,9 @@ const settingsSlice = createSlice({ setStartStopRecordingRegion(state, action: PayloadAction) { state.key.startStopRecordingRegion = action.payload; }, + setStartStopRecordingSavedRegion(state, action: PayloadAction) { + state.key.startStopRecordingSavedRegion = action.payload; + }, setAddBookmark(state, action: PayloadAction) { state.key.addBookmark = action.payload; } @@ -124,9 +133,11 @@ export const { removeAudioDevicesToRecord, setSeperateAudioTracks, setHardwareEncoding, + setRegionToRecord, setStartStopRecording, setStartStopRecordingRegion, + setStartStopRecordingSavedRegion, setAddBookmark } = settingsSlice.actions; diff --git a/src/settings/types.ts b/src/settings/types.ts index ef783218..0e760019 100644 --- a/src/settings/types.ts +++ b/src/settings/types.ts @@ -69,11 +69,22 @@ export interface RecordingSettings { * If we should offload encoding to GPU. */ hardwareEncoding: boolean; + + /** + * Saved custom region of screen to record. + * If a user only records a certain space of + * their screen always, this will help by saving that region. + */ + regionToRecord: { x: number; y: number; width: number; height: number }; } export interface KeyBindingSettings { startStopRecording: string; startStopRecordingRegion: string; + /** + * Start/stop recording the `regionToRecord` setting if set. + */ + startStopRecordingSavedRegion: string; addBookmark: string; }