diff --git a/apps/desktop/src-tauri/capabilities/default.json b/apps/desktop/src-tauri/capabilities/default.json
index ffad27e2..0dd6e469 100644
--- a/apps/desktop/src-tauri/capabilities/default.json
+++ b/apps/desktop/src-tauri/capabilities/default.json
@@ -17,6 +17,7 @@
"core:window:allow-set-focus",
"core:window:allow-start-dragging",
"core:window:allow-set-position",
+ "core:webview:default",
"core:webview:allow-create-webview-window",
"core:app:allow-version",
"shell:default",
diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs
index 79581574..c5dad46f 100644
--- a/apps/desktop/src-tauri/src/lib.rs
+++ b/apps/desktop/src-tauri/src/lib.rs
@@ -2232,6 +2232,12 @@ async fn reset_microphone_permissions(app: AppHandle) -> Result<(), ()> {
Ok(())
}
+#[tauri::command]
+#[specta::specta]
+async fn is_camera_window_open(app: AppHandle) -> bool {
+ CapWindow::Camera { ws_port: 0 }.get(&app).is_some()
+}
+
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub async fn run() {
let specta_builder = tauri_specta::Builder::new()
@@ -2286,7 +2292,8 @@ pub async fn run() {
set_general_settings,
delete_auth_open_signin,
reset_camera_permissions,
- reset_microphone_permissions
+ reset_microphone_permissions,
+ is_camera_window_open
])
.events(tauri_specta::collect_events![
RecordingOptionsChanged,
diff --git a/apps/desktop/src/routes/(window-chrome)/index.tsx b/apps/desktop/src/routes/(window-chrome)/index.tsx
index a41452ad..a1d31348 100644
--- a/apps/desktop/src/routes/(window-chrome)/index.tsx
+++ b/apps/desktop/src/routes/(window-chrome)/index.tsx
@@ -4,7 +4,6 @@ import { createEventListener } from "@solid-primitives/event-listener";
import { cache, createAsync, redirect, useNavigate } from "@solidjs/router";
import { createMutation, createQuery } from "@tanstack/solid-query";
import { getVersion } from "@tauri-apps/api/app";
-import { Window } from "@tauri-apps/api/window";
import { cx } from "cva";
import {
Show,
@@ -47,7 +46,7 @@ export const route = {
};
export default function () {
- const options = createOptionsQuery();
+ const { options, setOptions } = createOptionsQuery();
const windows = createQuery(() => listWindows);
const videoDevices = createVideoDevicesQuery();
const audioDevices = createQuery(() => listAudioDevices);
@@ -87,7 +86,6 @@ export default function () {
}
});
- // important for sign in redirect, trust me
createAsync(() => getAuth());
createUpdateCheck();
@@ -179,12 +177,25 @@ export default function () {
if (!item || !options.data) return;
- commands.setRecordingOptions({
+ setOptions({
...options.data,
audioInputName: item.name !== "No Audio" ? item.name : null,
});
};
+ onMount(async () => {
+ if (options.data?.cameraLabel && options.data.cameraLabel !== "No Camera") {
+ const cameraWindowActive = await commands.isCameraWindowOpen();
+
+ if (!cameraWindowActive) {
+ console.log("cameraWindow not found");
+ setOptions({
+ ...options.data,
+ });
+ }
+ }
+ });
+
return (
@@ -247,7 +258,7 @@ export default function () {
value={selectedWindow() ?? null}
onChange={(d: CaptureWindow | null) => {
if (!d || !options.data) return;
- commands.setRecordingOptions({
+ setOptions({
...options.data,
captureTarget: { variant: "window", ...d },
});
@@ -265,7 +276,7 @@ export default function () {
return;
}
if (s === "screen") {
- commands.setRecordingOptions({
+ setOptions({
...options.data,
captureTarget: { variant: "screen" },
});
@@ -330,12 +341,12 @@ export default function () {
if (!options.data) return;
if (!item || !item.isCamera) {
- await commands.setRecordingOptions({
+ await setOptions({
...options.data,
cameraLabel: null,
});
} else {
- await commands.setRecordingOptions({
+ await setOptions({
...options.data,
cameraLabel: item.name,
});
@@ -401,7 +412,7 @@ export default function () {
return requestPermission("camera");
}
if (!options.data?.cameraLabel) return;
- commands.setRecordingOptions({
+ setOptions({
...options.data,
cameraLabel: null,
});
@@ -492,14 +503,14 @@ export default function () {
if (permissions?.data?.microphone !== "granted") {
await requestPermission("microphone");
if (permissions?.data?.microphone === "granted") {
- commands.setRecordingOptions({
+ setOptions({
...options.data!,
audioInputName: audioDevice().name,
});
}
} else {
if (!options.data?.audioInputName) return;
- commands.setRecordingOptions({
+ setOptions({
...options.data,
audioInputName: null,
});
diff --git a/apps/desktop/src/routes/(window-chrome)/update.tsx b/apps/desktop/src/routes/(window-chrome)/update.tsx
index 7f26f140..c5e90ca3 100644
--- a/apps/desktop/src/routes/(window-chrome)/update.tsx
+++ b/apps/desktop/src/routes/(window-chrome)/update.tsx
@@ -59,12 +59,13 @@ export default function () {
}>
- Update has been installed. Restart Cap to finish updating.
-
-
-
+
+
+ Update has been installed. Restart Cap to finish updating.
+
+
+
+
({
@@ -133,7 +132,7 @@ export default function () {
{
- commands.setRecordingOptions({
+ setOptions({
...options(),
cameraLabel: null,
});
diff --git a/apps/desktop/src/utils/queries.ts b/apps/desktop/src/utils/queries.ts
index b6d9ec1f..2c5f48fa 100644
--- a/apps/desktop/src/utils/queries.ts
+++ b/apps/desktop/src/utils/queries.ts
@@ -1,10 +1,10 @@
import { createQuery, queryOptions } from "@tanstack/solid-query";
-import { createTimer } from "@solid-primitives/timer";
-import { commands } from "./tauri";
+import { commands, RecordingOptions } from "./tauri";
import { createQueryInvalidate } from "./events";
import { createStore, reconcile } from "solid-js/store";
-import { createMemo } from "solid-js";
+import { createEffect, createMemo } from "solid-js";
+import { makePersisted } from "@solid-primitives/storage";
export const listWindows = queryOptions({
queryKey: ["capture", "windows"] as const,
@@ -64,15 +64,48 @@ export const getPermissions = queryOptions({
refetchInterval: 1000,
});
+type PartialRecordingOptions = Omit;
export function createOptionsQuery() {
- const options = createQuery(() => getOptions);
+ const KEY = "recordingOptionsQuery";
+ const localState = localStorage.getItem(KEY);
+ const [state, setState, _init] = makePersisted(
+ createStore(
+ localState
+ ? JSON.parse(localState)
+ : {
+ cameraLabel: null,
+ audioInputName: null,
+ }
+ )
+ );
+
+ const setOptions = (newOptions: RecordingOptions) => {
+ commands.setRecordingOptions(newOptions);
+ const { captureTarget: _, ...partialOptions } = newOptions;
+ setState(partialOptions);
+ };
+
+ createEffect(() => {
+ localStorage.setItem(KEY, JSON.stringify(state));
+ });
+
+ const options = createQuery(() => ({
+ ...getOptions,
+ select: (data) => {
+ if (data && state) {
+ return { ...data, ...state };
+ }
+ },
+ }));
+
createQueryInvalidate(options, "recordingOptionsChanged");
- return options;
+ return { options, setOptions };
}
export function createCurrentRecordingQuery() {
const currentRecording = createQuery(() => getCurrentRecording);
+
createQueryInvalidate(currentRecording, "currentRecordingChanged");
return currentRecording;
diff --git a/apps/desktop/src/utils/tauri.ts b/apps/desktop/src/utils/tauri.ts
index 49b0fab3..f02b8f20 100644
--- a/apps/desktop/src/utils/tauri.ts
+++ b/apps/desktop/src/utils/tauri.ts
@@ -307,6 +307,9 @@ async resetMicrophonePermissions() : Promise> {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
+},
+async isCameraWindowOpen() : Promise {
+ return await TAURI_INVOKE("is_camera_window_open");
}
}