diff --git a/packages/app-cli/app/app.ts b/packages/app-cli/app/app.ts index e2ffcebea3..dec5be771e 100644 --- a/packages/app-cli/app/app.ts +++ b/packages/app-cli/app/app.ts @@ -417,8 +417,10 @@ class Application extends BaseApplication { if (argv.length) { this.gui_ = this.dummyGui(); + const initialFolder = await Folder.load(Setting.value('activeFolderId')); + await this.switchCurrentFolder(initialFolder); await this.applySettingsSideEffects(); - await this.refreshCurrentFolder(); + try { await this.execCommand(argv); } catch (error) { diff --git a/packages/app-mobile/components/CameraView/Camera/index.tsx b/packages/app-mobile/components/CameraView/Camera/index.tsx index 2cd0d6b3f1..f3ef426349 100644 --- a/packages/app-mobile/components/CameraView/Camera/index.tsx +++ b/packages/app-mobile/components/CameraView/Camera/index.tsx @@ -54,6 +54,14 @@ const Camera = (props: Props, ref: ForwardedRef) => { logger.error(message); }, []); + const isReadyRef = useRef(false); + const onCameraReady = useCallback(() => { + if (isReadyRef.current) return; // Already emitted + + isReadyRef.current = true; + props.onCameraReady(); + }, [props.onCameraReady]); + useAsyncEffect(async (event) => { // iOS issue workaround: Since upgrading to Expo SDK 52, closing and reopening the camera on iOS // never emits onCameraReady. As a workaround, call .resumePreview and wait for it to resolve, @@ -63,16 +71,16 @@ const Camera = (props: Props, ref: ForwardedRef) => { // Instead, wait for the preview to start using resumePreview: await camera.resumePreview(); if (event.cancelled) return; - props.onCameraReady(); + onCameraReady(); } - }, [camera, props.onCameraReady]); + }, [camera, onCameraReady]); return hasPermission?.granted ? => { void messenger.remoteApi.renderer.setExtraContentScriptsAndRerender(contentScripts); }, [messenger, contentScripts]); + const onRerenderRequestRef = useRef(()=>{}); + const rendererControl = useMemo((): RendererControl => { const renderer = messenger.remoteApi.renderer; @@ -201,6 +204,7 @@ const useWebViewSetup = (props: Props): SetUpResult => { const key = `${pluginId}.${settingKey}`; if (!pluginSettingKeysRef.current.has(key)) { pluginSettingKeysRef.current.add(key); + onRerenderRequestRef.current(); settingsChanged = true; } }, @@ -234,16 +238,21 @@ const useWebViewSetup = (props: Props): SetUpResult => { return { rerenderToBody: async (markup, options, cancelEvent) => { - const { getSettings, getSettingsChanged } = await prepareRenderer(options); + const { getSettings } = await prepareRenderer(options); if (cancelEvent?.cancelled) return null; - const output = await renderer.rerenderToBody(markup, getSettings()); - if (cancelEvent?.cancelled) return null; + const render = async () => { + if (cancelEvent?.cancelled) return; - if (getSettingsChanged()) { - return await renderer.rerenderToBody(markup, getSettings()); - } - return output; + await renderer.rerenderToBody(markup, getSettings()); + }; + + const queue = new AsyncActionQueue(); + onRerenderRequestRef.current = async () => { + queue.push(render); + }; + + return await render(); }, render: async (markup, options) => { const { getSettings, getSettingsChanged } = await prepareRenderer(options); diff --git a/packages/lib/models/Setting.test.ts b/packages/lib/models/Setting.test.ts index 32c51cc0c2..e6aa9f03ab 100644 --- a/packages/lib/models/Setting.test.ts +++ b/packages/lib/models/Setting.test.ts @@ -522,6 +522,13 @@ describe('models/Setting', () => { expect(Setting.value('revisionService.ttlDays')).toBe(1); }); + test('should not fail to save settings that can conflict with uninstalled plugin settings', async () => { + Setting.setValue('editor.imageRendering', true); + expect(Setting.value('editor.imageRendering')).toBe(true); + Setting.setValue('editor.imageRendering', false); + expect(Setting.value('editor.imageRendering')).toBe(false); + }); + test('should adjust settings to avoid conflicts', async () => { const testSettingId = 'plugin-plugin.calebjohn.rich-markdown.inlineImages'; await Setting.registerSetting(testSettingId, { diff --git a/packages/lib/models/Setting.ts b/packages/lib/models/Setting.ts index 2ad2d0691d..df2a39e87a 100644 --- a/packages/lib/models/Setting.ts +++ b/packages/lib/models/Setting.ts @@ -808,15 +808,20 @@ class Setting extends BaseModel { this.scheduleChangeEvent(); }; + const setValueInternalIfExists = (key: Key, value: SettingValueType) => { + if (!this.keyExists(key)) return; + setValueInternal(key, value); + }; + setValueInternal(key, value); // Prevent conflicts. Use setValueInternal to avoid infinite recursion in the case // where conflictingSettings has invalid data. for (const conflict of conflictingSettings) { if (conflict.key1 === key && conflict.value1 === value) { - setValueInternal(conflict.key2, conflict.alternate2); + setValueInternalIfExists(conflict.key2, conflict.alternate2); } else if (conflict.key2 === key && conflict.value2 === value) { - setValueInternal(conflict.key1, conflict.alternate1); + setValueInternalIfExists(conflict.key1, conflict.alternate1); } } }