- Replace useRef with useState for prefsHydrated to prevent race condition
- Wrap localStorage.getItem in try/catch in loadUserPreferences
- Validate aspectRatio against known valid values
- Include 'good' in exportQuality validation, 'mp4' in exportFormat validation
Load saved preferences (padding, aspect ratio, export quality, export format)
on mount and auto-save whenever these settings change. Uses the existing
userPreferences.ts utility with a ref guard to prevent overwriting saved prefs
with defaults before the initial load completes.
Add a top-level publish config in electron-builder.json5 pointing to
GitHub Releases. This embeds the update information URL in the AppImage
header, enabling tools like AppImageUpdate, AppImageLauncher, and
AppManager to perform delta updates instead of full re-downloads.
Also update the Linux build workflow to upload the generated .zsync file
alongside the .AppImage artifact.
Fixes#219
Expand the arrow key guard to also skip elements with
role="separator" (PanelResizeHandle), role="slider", and
role="spinbutton" so keyboard panel resizing is not intercepted.
- Read currentTime directly from the video element instead of the React
ref so rapid arrow key presses each advance by exactly one frame
- Add JSDoc docstrings to frameStep.ts exports
- Add HTMLSelectElement and contentEditable to the arrow key input guard
to prevent intercepting native keyboard behavior on form controls
- Add i18nKey field to FixedShortcut interface and wire up i18n lookups
in ShortcutsConfigDialog and KeyboardShortcutsHelp so fixed shortcut
labels are properly localized
Contains the zoom region configuration used in the PR demo video:
two auto-follow zoom regions and one manual zoom region.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- LaunchWindow: render sr-only <select> when webcamExpanded but
cameraDevices.length === 0 (loading/error/empty), so keyboard users
always have a focusable element even in no-camera states
- useCameraDevices.test: add error-branch test asserting error message,
empty devices array and isLoading=false when enumerateDevices rejects
- useCameraDevices: remove getUserMedia label probe to avoid conflict with
useScreenRecorder acquiring the real stream; use enumerateDevices only and
fall back to 'Camera <id>' for unlabeled devices; gate effect on enabled flag
- LaunchWindow: fix selectedCameraLabel to reflect loading/error/empty states
in the collapsed view (was always showing 'Default Camera')
- LaunchWindow: unify webcam <select> to a single always-mounted element
(sr-only when unavailable); mirrors the mic selector pattern
- useCameraDevices.test.ts: re-seed mockGetUserMedia in beforeEach after
vi.resetAllMocks(); update permission test to assert fallback label behavior
- LaunchWindow: expose isLoading/error from useCameraDevices; show
'Searching...' only while enumeration is in flight, 'Camera unavailable'
on error, 'No camera found' when list is empty (fixes perpetual loading state)
- LaunchWindow: keep <select> always mounted (sr-only when collapsed) and
expand panel on focus as well as hover; fixes keyboard inaccessibility for
both mic and webcam selectors
- i18n: add webcam.noneFound and webcam.unavailable to en/es/zh-CN locales