Repository navigation
feat: confirm recordings without a microphone #2047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,11 +26,17 @@ import themePreviewAuto from "~/assets/theme-previews/auto.jpg"; | |
| import themePreviewDark from "~/assets/theme-previews/dark.jpg"; | ||
| import themePreviewLight from "~/assets/theme-previews/light.jpg"; | ||
| import { Input } from "~/routes/editor/ui"; | ||
| import { authStore, generalSettingsStore } from "~/store"; | ||
| import { | ||
| authStore, | ||
| generalSettingsStore, | ||
| recordingStartSafetyStore, | ||
| } from "~/store"; | ||
| import { clientEnv } from "~/utils/env"; | ||
| import { | ||
| deriveGeneralSettings, | ||
| type GeneralSettingsStore, | ||
| RECORDING_START_SAFETY_DEFAULTS, | ||
| type RecordingStartSafetySettings, | ||
| } from "~/utils/general-settings"; | ||
| import { | ||
| type AppTheme, | ||
|
|
@@ -126,11 +132,20 @@ const FREE_INSTANT_MODE_MAX_RESOLUTION = 1280; | |
| const PRO_INSTANT_MODE_MAX_RESOLUTION = 1920; | ||
|
|
||
| export default function GeneralSettings() { | ||
| const [store] = createResource(() => generalSettingsStore.get()); | ||
| const [stores] = createResource(() => | ||
| Promise.all([generalSettingsStore.get(), recordingStartSafetyStore.get()]), | ||
| ); | ||
|
|
||
| return ( | ||
| <Show when={store.state === "ready" && ([store()] as const)}> | ||
| {(store) => <Inner initialStore={store()[0] ?? null} />} | ||
| <Show when={stores()} keyed> | ||
| {(stores) => ( | ||
| <Inner | ||
| initialStore={stores[0] ?? null} | ||
| initialRecordingStartSafety={ | ||
| stores[1] ?? RECORDING_START_SAFETY_DEFAULTS | ||
| } | ||
| /> | ||
| )} | ||
| </Show> | ||
| ); | ||
| } | ||
|
|
@@ -209,10 +224,19 @@ function AppearanceSection(props: { | |
| ); | ||
| } | ||
|
|
||
| function Inner(props: { initialStore: GeneralSettingsStore | null }) { | ||
| function Inner(props: { | ||
| initialStore: GeneralSettingsStore | null; | ||
| initialRecordingStartSafety: RecordingStartSafetySettings; | ||
| }) { | ||
| const [settings, setSettings] = createStore<ExtendedGeneralSettingsStore>( | ||
| deriveGeneralSettings(props.initialStore), | ||
| ); | ||
| const [ | ||
| confirmBeforeRecordingWithoutMicrophone, | ||
| setConfirmBeforeRecordingWithoutMicrophone, | ||
| ] = createSignal( | ||
| props.initialRecordingStartSafety.confirmBeforeRecordingWithoutMicrophone, | ||
| ); | ||
| const auth = authStore.createQuery(); | ||
| const hasCapPro = createMemo(() => { | ||
| const plan = auth.data?.plan; | ||
|
|
@@ -312,6 +336,19 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) { | |
| } | ||
| }; | ||
|
|
||
| const handleRecordingStartSafetyChange = async (value: boolean) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor edge case: if the user toggles this quickly, multiple |
||
| const previousValue = confirmBeforeRecordingWithoutMicrophone(); | ||
| setConfirmBeforeRecordingWithoutMicrophone(value); | ||
| try { | ||
| await recordingStartSafetyStore.set({ | ||
| confirmBeforeRecordingWithoutMicrophone: value, | ||
| }); | ||
| } catch (error) { | ||
| setConfirmBeforeRecordingWithoutMicrophone(previousValue); | ||
| console.error("Failed to update recording start safety", error); | ||
| } | ||
| }; | ||
|
|
||
| const ostype: OsType = type(); | ||
| const excludedWindows = createMemo(() => settings.excludedWindows ?? []); | ||
| const missingDefaultExclusions = createMemo(() => | ||
|
|
@@ -552,6 +589,12 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) { | |
| { text: "10 seconds", value: 10 }, | ||
| ]} | ||
| /> | ||
| <ToggleSettingItem | ||
| label="Confirm before recording without a microphone" | ||
| description="Require confirmation when no microphone is selected or the selected microphone is unavailable." | ||
| value={confirmBeforeRecordingWithoutMicrophone()} | ||
| onChange={handleRecordingStartSafetyChange} | ||
| /> | ||
| <SelectSettingItem | ||
| label="Main window when recording starts" | ||
| description="What happens to the main window once a recording begins." | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor robustness: if the dialog callback never fires (plugin failure, window closes, etc), this await will hang the hotkey task. Consider adding a timeout and treating it as cancel.