You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-26 22:41:17 +02:00
Merge branch 'release-3.4' into dev
This commit is contained in:
@@ -417,8 +417,10 @@ class Application extends BaseApplication {
|
|||||||
if (argv.length) {
|
if (argv.length) {
|
||||||
this.gui_ = this.dummyGui();
|
this.gui_ = this.dummyGui();
|
||||||
|
|
||||||
|
const initialFolder = await Folder.load(Setting.value('activeFolderId'));
|
||||||
|
await this.switchCurrentFolder(initialFolder);
|
||||||
await this.applySettingsSideEffects();
|
await this.applySettingsSideEffects();
|
||||||
await this.refreshCurrentFolder();
|
|
||||||
try {
|
try {
|
||||||
await this.execCommand(argv);
|
await this.execCommand(argv);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -54,6 +54,14 @@ const Camera = (props: Props, ref: ForwardedRef<CameraRef>) => {
|
|||||||
logger.error(message);
|
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) => {
|
useAsyncEffect(async (event) => {
|
||||||
// iOS issue workaround: Since upgrading to Expo SDK 52, closing and reopening the camera on iOS
|
// 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,
|
// never emits onCameraReady. As a workaround, call .resumePreview and wait for it to resolve,
|
||||||
@@ -63,16 +71,16 @@ const Camera = (props: Props, ref: ForwardedRef<CameraRef>) => {
|
|||||||
// Instead, wait for the preview to start using resumePreview:
|
// Instead, wait for the preview to start using resumePreview:
|
||||||
await camera.resumePreview();
|
await camera.resumePreview();
|
||||||
if (event.cancelled) return;
|
if (event.cancelled) return;
|
||||||
props.onCameraReady();
|
onCameraReady();
|
||||||
}
|
}
|
||||||
}, [camera, props.onCameraReady]);
|
}, [camera, onCameraReady]);
|
||||||
|
|
||||||
return hasPermission?.granted ? <CameraView
|
return hasPermission?.granted ? <CameraView
|
||||||
ref={setCamera}
|
ref={setCamera}
|
||||||
style={props.style}
|
style={props.style}
|
||||||
facing={props.cameraType === CameraDirection.Front ? 'front' : 'back'}
|
facing={props.cameraType === CameraDirection.Front ? 'front' : 'back'}
|
||||||
ratio={props.ratio as CameraRatio}
|
ratio={props.ratio as CameraRatio}
|
||||||
onCameraReady={Platform.OS === 'android' ? props.onCameraReady : undefined}
|
onCameraReady={onCameraReady}
|
||||||
onMountError={onMountError}
|
onMountError={onMountError}
|
||||||
animateShutter={false}
|
animateShutter={false}
|
||||||
barcodeScannerSettings={barcodeScannerSettings}
|
barcodeScannerSettings={barcodeScannerSettings}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
|||||||
// A small border above the header: Covers the part of the shadow that would otherwise
|
// A small border above the header: Covers the part of the shadow that would otherwise
|
||||||
// be shown above the header on Android.
|
// be shown above the header on Android.
|
||||||
aboveHeader: {
|
aboveHeader: {
|
||||||
backgroundColor: '#323640',
|
backgroundColor: theme.backgroundColor2,
|
||||||
paddingBottom: 6,
|
paddingBottom: 6,
|
||||||
marginTop: -6,
|
marginTop: -6,
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import Resource from '@joplin/lib/models/Resource';
|
|||||||
import { ResourceInfos } from '@joplin/renderer/types';
|
import { ResourceInfos } from '@joplin/renderer/types';
|
||||||
import useContentScripts from './utils/useContentScripts';
|
import useContentScripts from './utils/useContentScripts';
|
||||||
import uuid from '@joplin/lib/uuid';
|
import uuid from '@joplin/lib/uuid';
|
||||||
|
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
|
||||||
|
|
||||||
const logger = Logger.create('renderer/useWebViewSetup');
|
const logger = Logger.create('renderer/useWebViewSetup');
|
||||||
|
|
||||||
@@ -149,6 +150,8 @@ const useWebViewSetup = (props: Props): SetUpResult<RendererControl> => {
|
|||||||
void messenger.remoteApi.renderer.setExtraContentScriptsAndRerender(contentScripts);
|
void messenger.remoteApi.renderer.setExtraContentScriptsAndRerender(contentScripts);
|
||||||
}, [messenger, contentScripts]);
|
}, [messenger, contentScripts]);
|
||||||
|
|
||||||
|
const onRerenderRequestRef = useRef(()=>{});
|
||||||
|
|
||||||
const rendererControl = useMemo((): RendererControl => {
|
const rendererControl = useMemo((): RendererControl => {
|
||||||
const renderer = messenger.remoteApi.renderer;
|
const renderer = messenger.remoteApi.renderer;
|
||||||
|
|
||||||
@@ -201,6 +204,7 @@ const useWebViewSetup = (props: Props): SetUpResult<RendererControl> => {
|
|||||||
const key = `${pluginId}.${settingKey}`;
|
const key = `${pluginId}.${settingKey}`;
|
||||||
if (!pluginSettingKeysRef.current.has(key)) {
|
if (!pluginSettingKeysRef.current.has(key)) {
|
||||||
pluginSettingKeysRef.current.add(key);
|
pluginSettingKeysRef.current.add(key);
|
||||||
|
onRerenderRequestRef.current();
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -234,16 +238,21 @@ const useWebViewSetup = (props: Props): SetUpResult<RendererControl> => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
rerenderToBody: async (markup, options, cancelEvent) => {
|
rerenderToBody: async (markup, options, cancelEvent) => {
|
||||||
const { getSettings, getSettingsChanged } = await prepareRenderer(options);
|
const { getSettings } = await prepareRenderer(options);
|
||||||
if (cancelEvent?.cancelled) return null;
|
if (cancelEvent?.cancelled) return null;
|
||||||
|
|
||||||
const output = await renderer.rerenderToBody(markup, getSettings());
|
const render = async () => {
|
||||||
if (cancelEvent?.cancelled) return null;
|
if (cancelEvent?.cancelled) return;
|
||||||
|
|
||||||
if (getSettingsChanged()) {
|
await renderer.rerenderToBody(markup, getSettings());
|
||||||
return await renderer.rerenderToBody(markup, getSettings());
|
};
|
||||||
}
|
|
||||||
return output;
|
const queue = new AsyncActionQueue();
|
||||||
|
onRerenderRequestRef.current = async () => {
|
||||||
|
queue.push(render);
|
||||||
|
};
|
||||||
|
|
||||||
|
return await render();
|
||||||
},
|
},
|
||||||
render: async (markup, options) => {
|
render: async (markup, options) => {
|
||||||
const { getSettings, getSettingsChanged } = await prepareRenderer(options);
|
const { getSettings, getSettingsChanged } = await prepareRenderer(options);
|
||||||
|
|||||||
@@ -522,6 +522,13 @@ describe('models/Setting', () => {
|
|||||||
expect(Setting.value('revisionService.ttlDays')).toBe(1);
|
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 () => {
|
test('should adjust settings to avoid conflicts', async () => {
|
||||||
const testSettingId = 'plugin-plugin.calebjohn.rich-markdown.inlineImages';
|
const testSettingId = 'plugin-plugin.calebjohn.rich-markdown.inlineImages';
|
||||||
await Setting.registerSetting(testSettingId, {
|
await Setting.registerSetting(testSettingId, {
|
||||||
|
|||||||
@@ -808,15 +808,20 @@ class Setting extends BaseModel {
|
|||||||
this.scheduleChangeEvent();
|
this.scheduleChangeEvent();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setValueInternalIfExists = <Key extends string> (key: Key, value: SettingValueType<Key>) => {
|
||||||
|
if (!this.keyExists(key)) return;
|
||||||
|
setValueInternal(key, value);
|
||||||
|
};
|
||||||
|
|
||||||
setValueInternal(key, value);
|
setValueInternal(key, value);
|
||||||
|
|
||||||
// Prevent conflicts. Use setValueInternal to avoid infinite recursion in the case
|
// Prevent conflicts. Use setValueInternal to avoid infinite recursion in the case
|
||||||
// where conflictingSettings has invalid data.
|
// where conflictingSettings has invalid data.
|
||||||
for (const conflict of conflictingSettings) {
|
for (const conflict of conflictingSettings) {
|
||||||
if (conflict.key1 === key && conflict.value1 === value) {
|
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) {
|
} else if (conflict.key2 === key && conflict.value2 === value) {
|
||||||
setValueInternal(conflict.key1, conflict.alternate1);
|
setValueInternalIfExists(conflict.key1, conflict.alternate1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user