You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-08 23:07:32 +02:00
Compare commits
39 Commits
android-v2
...
binary-sig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57195ef715 | ||
|
|
531f2d7f78 | ||
|
|
3db882d940 | ||
|
|
b824ff5457 | ||
|
|
3669a1b5d6 | ||
|
|
b93f9aaf01 | ||
|
|
8679290206 | ||
|
|
4acec5c6c7 | ||
|
|
f1b03453a4 | ||
|
|
7972dd5556 | ||
|
|
ed58ed91fd | ||
|
|
a0fd942a1c | ||
|
|
4842500f0a | ||
|
|
84c7f28ec5 | ||
|
|
f3eea43d24 | ||
|
|
8babaddbcb | ||
|
|
13cdaabb17 | ||
|
|
a94aa21088 | ||
|
|
6116bed4e3 | ||
|
|
fabd0b4dda | ||
|
|
6b72f86e7b | ||
|
|
02cf546124 | ||
|
|
eecb012d64 | ||
|
|
0b3919fd62 | ||
|
|
897fd0f727 | ||
|
|
9edb402b18 | ||
|
|
36ae58ffe1 | ||
|
|
5ef8b86957 | ||
|
|
c7228cfcd6 | ||
|
|
7a791dbf98 | ||
|
|
a543588527 | ||
|
|
998ad142a6 | ||
|
|
b6a53f96f7 | ||
|
|
841a9c6e09 | ||
|
|
d25c078ef0 | ||
|
|
ff69ac17be | ||
|
|
b44945b3a0 | ||
|
|
2584224026 | ||
|
|
46136871bf |
@@ -405,6 +405,7 @@ packages/app-mobile/components/SideMenu.js
|
||||
packages/app-mobile/components/TextInput.js
|
||||
packages/app-mobile/components/app-nav.js
|
||||
packages/app-mobile/components/biometrics/BiometricPopup.js
|
||||
packages/app-mobile/components/biometrics/biometricAuthenticate.js
|
||||
packages/app-mobile/components/biometrics/sensorInfo.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/getResponsiveValue.test.js
|
||||
|
||||
3
.github/scripts/run_ci.sh
vendored
3
.github/scripts/run_ci.sh
vendored
@@ -180,9 +180,6 @@ cd "$ROOT_DIR/packages/app-desktop"
|
||||
|
||||
if [[ $GIT_TAG_NAME = v* ]]; then
|
||||
echo "Step: Building and publishing desktop application..."
|
||||
# cd "$ROOT_DIR/packages/tools"
|
||||
# node bundleDefaultPlugins.js
|
||||
cd "$ROOT_DIR/packages/app-desktop"
|
||||
USE_HARD_LINKS=false yarn run dist
|
||||
elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
|
||||
echo "Step: Building Docker Image..."
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -392,6 +392,7 @@ packages/app-mobile/components/SideMenu.js
|
||||
packages/app-mobile/components/TextInput.js
|
||||
packages/app-mobile/components/app-nav.js
|
||||
packages/app-mobile/components/biometrics/BiometricPopup.js
|
||||
packages/app-mobile/components/biometrics/biometricAuthenticate.js
|
||||
packages/app-mobile/components/biometrics/sensorInfo.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/getResponsiveValue.test.js
|
||||
|
||||
30
.yarn/patches/rn-fetch-blob-npm-0.12.0-cf02e3c544.patch
Normal file
30
.yarn/patches/rn-fetch-blob-npm-0.12.0-cf02e3c544.patch
Normal file
@@ -0,0 +1,30 @@
|
||||
diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
|
||||
index a8abd71833879201e3438b2fa51d712a311c4551..ffe9c2c6dfa5c703ba76b65d94d5dd6784102c19 100644
|
||||
--- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
|
||||
+++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
|
||||
@@ -591,7 +591,7 @@ public class RNFetchBlobReq extends BroadcastReceiver implements Runnable {
|
||||
// ignored.printStackTrace();
|
||||
}
|
||||
|
||||
- RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;
|
||||
+ RNFetchBlobFileResp rnFetchBlobFileResp = new RNFetchBlobFileResp(responseBody);
|
||||
|
||||
if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){
|
||||
callback.invoke("Download interrupted.", null);
|
||||
diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
|
||||
index 2470eef612308c15a89dfea5a1f16937469be29f..965f8becc195965907699182c764ec9e51811450 100644
|
||||
--- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
|
||||
+++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
|
||||
@@ -35,6 +35,12 @@ public class RNFetchBlobFileResp extends ResponseBody {
|
||||
FileOutputStream ofStream;
|
||||
boolean isEndMarkerReceived;
|
||||
|
||||
+ // ref: https://github.com/joltup/rn-fetch-blob/issues/490#issuecomment-990899440
|
||||
+ public RNFetchBlobFileResp(ResponseBody body) {
|
||||
+ super();
|
||||
+ this.originalBody = body;
|
||||
+ }
|
||||
+
|
||||
public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseBody body, String path, boolean overwrite) throws IOException {
|
||||
super();
|
||||
this.rctContext = ctx;
|
||||
@@ -95,6 +95,7 @@
|
||||
},
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"resolutions": {
|
||||
"react-native-camera@4.2.1": "patch:react-native-camera@npm%3A4.2.1#./.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch"
|
||||
"react-native-camera@4.2.1": "patch:react-native-camera@npm%3A4.2.1#./.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch",
|
||||
"rn-fetch-blob@0.12.0": "patch:rn-fetch-blob@npm%3A0.12.0#./.yarn/patches/rn-fetch-blob-npm-0.12.0-cf02e3c544.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dist": "yarn run electronRebuild && npx electron-builder",
|
||||
"dist": "yarn run bundleDefaultPlugins && yarn run electronRebuild && npx electron-builder",
|
||||
"bundleDefaultPlugins": "cd ../tools && node bundleDefaultPlugins.js",
|
||||
"build": "gulp build",
|
||||
"postinstall": "yarn run build",
|
||||
"electronBuilder": "gulp electronBuilder",
|
||||
@@ -90,7 +91,11 @@
|
||||
"CFBundleURLName": "org.joplinapp.x-callback-url"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"binaries": [
|
||||
"Contents/Resources/build/defaultPlugins/io.github.jackgruber.backup/7zip-bin/mac/arm64/7za",
|
||||
"Contents/Resources/build/defaultPlugins/io.github.jackgruber.backup/7zip-bin/mac/x64/7za"
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"icon": "../../Assets/LinuxIcons",
|
||||
@@ -107,6 +112,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/laurent22/joplin#readme",
|
||||
"devDependencies": {
|
||||
"@electron/notarize": "1.2.3",
|
||||
"@electron/rebuild": "3.2.10",
|
||||
"@joplin/tools": "~2.11",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@types/jest": "29.2.6",
|
||||
@@ -115,9 +122,7 @@
|
||||
"@types/react-redux": "7.1.25",
|
||||
"@types/styled-components": "5.1.26",
|
||||
"electron": "19.1.4",
|
||||
"electron-builder": "23.6.0",
|
||||
"electron-notarize": "1.2.2",
|
||||
"electron-rebuild": "3.2.9",
|
||||
"electron-builder": "24.1.2",
|
||||
"glob": "8.1.0",
|
||||
"gulp": "4.0.2",
|
||||
"jest": "29.4.3",
|
||||
@@ -176,4 +181,4 @@
|
||||
"taboverride": "4.0.3",
|
||||
"tinymce": "5.10.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const electron_notarize = require('electron-notarize');
|
||||
const electron_notarize = require('@electron/notarize');
|
||||
const execCommand = require('./execCommand');
|
||||
|
||||
function isDesktopAppTag(tagName) {
|
||||
|
||||
@@ -150,8 +150,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097686
|
||||
versionName "2.11.1"
|
||||
versionCode 2097687
|
||||
versionName "2.11.2"
|
||||
// ndk {
|
||||
// abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
// }
|
||||
|
||||
@@ -3,62 +3,57 @@
|
||||
*/
|
||||
|
||||
|
||||
import { EditorSettings } from '../types';
|
||||
import { initCodeMirror } from './CodeMirror';
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { forceParsing } from '@codemirror/language';
|
||||
import loadLangauges from './testUtil/loadLanguages';
|
||||
|
||||
// Randomly fails on:
|
||||
//
|
||||
// > 42 | expect(headerLineContent.textContent).toBe(headerLineText);
|
||||
//
|
||||
import { expect, describe, it } from '@jest/globals';
|
||||
|
||||
|
||||
const createEditorSettings = (themeId: number) => {
|
||||
const themeData = themeStyle(themeId);
|
||||
const editorSettings: EditorSettings = {
|
||||
katexEnabled: true,
|
||||
spellcheckEnabled: true,
|
||||
themeId,
|
||||
themeData,
|
||||
};
|
||||
|
||||
return editorSettings;
|
||||
};
|
||||
|
||||
describe('CodeMirror', () => {
|
||||
it('should succeed', async () => {
|
||||
expect(1).toBe(1);
|
||||
// This checks for a regression -- occasionally, when updating packages,
|
||||
// syntax highlighting in the CodeMirror editor stops working. This is usually
|
||||
// fixed by
|
||||
// 1. removing all `@codemirror/` and `@lezer/` dependencies from yarn.lock,
|
||||
// 2. upgrading all CodeMirror packages to the latest versions in package.json, and
|
||||
// 3. re-running `yarn install`.
|
||||
//
|
||||
// See https://github.com/laurent22/joplin/issues/7253
|
||||
it('should give headings a different style', async () => {
|
||||
const headerLineText = '# Testing...';
|
||||
const initialText = `${headerLineText}\nThis is a test.`;
|
||||
const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
|
||||
|
||||
await loadLangauges();
|
||||
const editor = initCodeMirror(document.body, initialText, editorSettings);
|
||||
|
||||
// Force the generation of the syntax tree now.
|
||||
forceParsing(editor.editor);
|
||||
|
||||
// CodeMirror nests the tag that styles the header within .cm-headerLine:
|
||||
// <div class='cm-headerLine'><span class='someclass'>Testing...</span></div>
|
||||
const headerLineContent = document.body.querySelector('.cm-headerLine > span')!;
|
||||
|
||||
|
||||
expect(headerLineContent.textContent).toBe(headerLineText);
|
||||
|
||||
const style = getComputedStyle(headerLineContent);
|
||||
expect(style.borderBottom).not.toBe('');
|
||||
expect(style.fontSize).toBe('1.6em');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// import { EditorSettings } from '../types';
|
||||
// import { initCodeMirror } from './CodeMirror';
|
||||
// import { themeStyle } from '@joplin/lib/theme';
|
||||
// import Setting from '@joplin/lib/models/Setting';
|
||||
// import { forceParsing } from '@codemirror/language';
|
||||
// import loadLangauges from './testUtil/loadLanguages';
|
||||
|
||||
|
||||
// const createEditorSettings = (themeId: number) => {
|
||||
// const themeData = themeStyle(themeId);
|
||||
// const editorSettings: EditorSettings = {
|
||||
// katexEnabled: true,
|
||||
// spellcheckEnabled: true,
|
||||
// themeId,
|
||||
// themeData,
|
||||
// };
|
||||
|
||||
// return editorSettings;
|
||||
// };
|
||||
|
||||
// describe('CodeMirror', () => {
|
||||
// it('should give headings a different style', async () => {
|
||||
// const headerLineText = '# Testing...';
|
||||
// const initialText = `${headerLineText}\nThis is a test.`;
|
||||
// const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
|
||||
|
||||
// await loadLangauges();
|
||||
// const editor = initCodeMirror(document.body, initialText, editorSettings);
|
||||
|
||||
// // Force the generation of the syntax tree now.
|
||||
// forceParsing(editor.editor);
|
||||
|
||||
// // CodeMirror nests the tag that styles the header within .cm-headerLine:
|
||||
// // <div class='cm-headerLine'><span class='someclass'>Testing...</span></div>
|
||||
// const headerLineContent = document.body.querySelector('.cm-headerLine > span')!;
|
||||
|
||||
|
||||
// expect(headerLineContent.textContent).toBe(headerLineText);
|
||||
|
||||
// const style = getComputedStyle(headerLineContent);
|
||||
// expect(style.borderBottom).not.toBe('');
|
||||
// expect(style.fontSize).toBe('1.6em');
|
||||
// });
|
||||
// });
|
||||
|
||||
@@ -2,10 +2,10 @@ const React = require('react');
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { View, Dimensions, Alert, Button } from 'react-native';
|
||||
import FingerprintScanner from 'react-native-fingerprint-scanner';
|
||||
import { SensorInfo } from './sensorInfo';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import biometricAuthenticate from './biometricAuthenticate';
|
||||
|
||||
const logger = Logger.create('BiometricPopup');
|
||||
|
||||
@@ -21,7 +21,7 @@ export default (props: Props) => {
|
||||
// doesn't work properly, we disable it. We only want the user to enable the
|
||||
// feature after they've read the description in the config screen.
|
||||
const [initialPromptDone, setInitialPromptDone] = useState(true); // useState(Setting.value('security.biometricsInitialPromptDone'));
|
||||
const [display, setDisplay] = useState(!!props.sensorInfo.supportedSensors && (props.sensorInfo.enabled || !initialPromptDone));
|
||||
const [display, setDisplay] = useState(props.sensorInfo.enabled || !initialPromptDone);
|
||||
const [tryBiometricsCheck, setTryBiometricsCheck] = useState(initialPromptDone);
|
||||
|
||||
logger.info('Render start');
|
||||
@@ -37,18 +37,14 @@ export default (props: Props) => {
|
||||
logger.info('biometricsCheck: start');
|
||||
|
||||
try {
|
||||
logger.info('biometricsCheck: authenticate...');
|
||||
await FingerprintScanner.authenticate({ description: _('Verify your identity') });
|
||||
logger.info('biometricsCheck: authenticate done');
|
||||
setTryBiometricsCheck(false);
|
||||
await biometricAuthenticate();
|
||||
setDisplay(false);
|
||||
} catch (error) {
|
||||
Alert.alert(_('Could not verify your identify'), error.message);
|
||||
setTryBiometricsCheck(false);
|
||||
} finally {
|
||||
FingerprintScanner.release();
|
||||
Alert.alert(error.message);
|
||||
}
|
||||
|
||||
setTryBiometricsCheck(false);
|
||||
|
||||
logger.info('biometricsCheck: end');
|
||||
};
|
||||
|
||||
@@ -97,7 +93,7 @@ export default (props: Props) => {
|
||||
},
|
||||
]
|
||||
);
|
||||
}, [initialPromptDone, props.sensorInfo.supportedSensors, display, props.dispatch]);
|
||||
}, [initialPromptDone, display, props.dispatch]);
|
||||
|
||||
const windowSize = useMemo(() => {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import FingerprintScanner, { Errors } from 'react-native-fingerprint-scanner';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
||||
const logger = Logger.create('biometricAuthenticate');
|
||||
|
||||
export default async () => {
|
||||
try {
|
||||
logger.info('Authenticate...');
|
||||
await FingerprintScanner.authenticate({ description: _('Verify your identity') });
|
||||
logger.info('Authenticate done');
|
||||
} catch (error) {
|
||||
const errorName = (error as Errors).name;
|
||||
|
||||
let errorMessage = error.message;
|
||||
if (errorName === 'FingerprintScannerNotEnrolled' || errorName === 'FingerprintScannerNotAvailable') {
|
||||
errorMessage = _('Biometric unlock is not setup on the device. Please set it up in order to unlock Joplin. If the device is on lockout, consider switching it off and on to reset biometrics scanning.');
|
||||
}
|
||||
|
||||
error.message = _('Could not verify your identify: %s', errorMessage);
|
||||
|
||||
logger.warn(error);
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
FingerprintScanner.release();
|
||||
}
|
||||
};
|
||||
@@ -30,6 +30,18 @@ export default async (): Promise<SensorInfo> => {
|
||||
|
||||
try {
|
||||
logger.info('Getting isSensorAvailable...');
|
||||
|
||||
// Note: If `isSensorAvailable()` doesn't return anything, it seems we
|
||||
// could assume that biometrics are not setup on the device, and thus we
|
||||
// can unlock the app. However that's not always correct - on some
|
||||
// devices (eg Galaxy S22), `isSensorAvailable()` will return nothing if
|
||||
// the device is on lockout - i.e. if the user gave the wrong
|
||||
// fingerprint multiple times.
|
||||
//
|
||||
// So we definitely can't unlock the app in that case, and it means
|
||||
// `isSensorAvailable()` is pretty much useless. Instead we ask for
|
||||
// fingerprint when the user turns on the feature and at that point we
|
||||
// know if the device supports biometrics or not.
|
||||
const result = await FingerprintScanner.isSensorAvailable();
|
||||
logger.info('isSensorAvailable result', result);
|
||||
supportedSensors = result;
|
||||
|
||||
@@ -23,6 +23,7 @@ const { themeStyle } = require('../global-style.js');
|
||||
const shared = require('@joplin/lib/components/shared/config-shared.js');
|
||||
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
|
||||
import { openDocumentTree } from '@joplin/react-native-saf-x';
|
||||
import biometricAuthenticate from '../biometrics/biometricAuthenticate';
|
||||
|
||||
class ConfigScreenComponent extends BaseScreenComponent {
|
||||
public static navigationOptions(): any {
|
||||
@@ -463,7 +464,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
<Text key="label" style={this.styles().switchSettingText}>
|
||||
{label}
|
||||
</Text>
|
||||
<Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={(value: any) => updateSettingValue(key, value)} />
|
||||
<Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={(value: any) => void updateSettingValue(key, value)} />
|
||||
</View>
|
||||
{descriptionComp}
|
||||
</View>
|
||||
@@ -474,13 +475,39 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
return !hasDescription ? this.styles().settingContainer : this.styles().settingContainerNoBottomBorder;
|
||||
}
|
||||
|
||||
private async handleSetting(key: string, value: any): Promise<boolean> {
|
||||
// When the user tries to enable biometrics unlock, we ask for the
|
||||
// fingerprint or Face ID, and if it's correct we save immediately. If
|
||||
// it's not, we don't turn on the setting.
|
||||
if (key === 'security.biometricsEnabled' && !!value) {
|
||||
try {
|
||||
await biometricAuthenticate();
|
||||
shared.updateSettingValue(this, key, value);
|
||||
await this.saveButton_press();
|
||||
} catch (error) {
|
||||
shared.updateSettingValue(this, key, false);
|
||||
Alert.alert(error.message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key === 'security.biometricsEnabled' && !value) {
|
||||
shared.updateSettingValue(this, key, value);
|
||||
await this.saveButton_press();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public settingToComponent(key: string, value: any) {
|
||||
const themeId = this.props.themeId;
|
||||
const theme = themeStyle(themeId);
|
||||
const output: any = null;
|
||||
|
||||
const updateSettingValue = (key: string, value: any) => {
|
||||
return shared.updateSettingValue(this, key, value);
|
||||
const updateSettingValue = async (key: string, value: any) => {
|
||||
const handled = await this.handleSetting(key, value);
|
||||
if (!handled) shared.updateSettingValue(this, key, value);
|
||||
};
|
||||
|
||||
const md = Setting.settingMetadata(key);
|
||||
@@ -517,7 +544,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
fontSize: theme.fontSize,
|
||||
}}
|
||||
onValueChange={(itemValue: string) => {
|
||||
updateSettingValue(key, itemValue);
|
||||
void updateSettingValue(key, itemValue);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@@ -553,7 +580,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
</Text>
|
||||
<View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', flex: 1 }}>
|
||||
<Text style={this.styles().sliderUnits}>{unitLabel}</Text>
|
||||
<Slider key="control" style={{ flex: 1 }} step={md.step} minimumValue={minimum} maximumValue={maximum} value={value} onValueChange={value => updateSettingValue(key, value)} />
|
||||
<Slider key="control" style={{ flex: 1 }} step={md.step} minimumValue={minimum} maximumValue={maximum} value={value} onValueChange={value => void updateSettingValue(key, value)} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -577,7 +604,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
<Text key="label" style={this.styles().settingText}>
|
||||
{md.label()}
|
||||
</Text>
|
||||
<TextInput autoCorrect={false} autoComplete="off" selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} autoCapitalize="none" key="control" style={this.styles().settingControl} value={value} onChangeText={(value: any) => updateSettingValue(key, value)} secureTextEntry={!!md.secure} />
|
||||
<TextInput autoCorrect={false} autoComplete="off" selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} autoCapitalize="none" key="control" style={this.styles().settingControl} value={value} onChangeText={(value: any) => void updateSettingValue(key, value)} secureTextEntry={!!md.secure} />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -328,7 +328,7 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-image-resizer (1.4.5):
|
||||
- React-Core
|
||||
- react-native-netinfo (9.3.7):
|
||||
- react-native-netinfo (9.3.8):
|
||||
- React-Core
|
||||
- react-native-rsa-native (2.0.5):
|
||||
- React
|
||||
@@ -722,7 +722,7 @@ SPEC CHECKSUMS:
|
||||
react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a
|
||||
react-native-image-picker: ec9b713e248760bfa0f879f0715391de4651a7cb
|
||||
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
|
||||
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
|
||||
react-native-netinfo: fbc23bc2fe217155d85f2f7e0644b1654df8029b
|
||||
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
|
||||
react-native-saf-x: 9bd5238d3b43d76bbec64aa82c173ac20a4bce9f
|
||||
react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/datetimepicker": "6.7.5",
|
||||
"@react-native-community/geolocation": "2.1.0",
|
||||
"@react-native-community/netinfo": "9.3.7",
|
||||
"@react-native-community/netinfo": "9.3.8",
|
||||
"@react-native-community/push-notification-ios": "1.10.1",
|
||||
"@react-native-community/slider": "4.4.2",
|
||||
"assert-browserify": "2.0.0",
|
||||
@@ -54,7 +54,7 @@
|
||||
"react-native-image-picker": "5.3.1",
|
||||
"react-native-image-resizer": "1.4.5",
|
||||
"react-native-modal-datetime-picker": "14.0.1",
|
||||
"react-native-paper": "5.4.1",
|
||||
"react-native-paper": "5.5.2",
|
||||
"react-native-popup-menu": "0.16.1",
|
||||
"react-native-quick-actions": "0.3.13",
|
||||
"react-native-rsa-native": "2.0.5",
|
||||
@@ -79,19 +79,19 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.16.0",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"@codemirror/commands": "6.1.2",
|
||||
"@codemirror/commands": "6.2.2",
|
||||
"@codemirror/lang-cpp": "6.0.2",
|
||||
"@codemirror/lang-html": "6.4.0",
|
||||
"@codemirror/lang-html": "6.4.3",
|
||||
"@codemirror/lang-java": "6.0.1",
|
||||
"@codemirror/lang-javascript": "6.1.1",
|
||||
"@codemirror/lang-markdown": "6.0.5",
|
||||
"@codemirror/lang-javascript": "6.1.5",
|
||||
"@codemirror/lang-markdown": "6.1.0",
|
||||
"@codemirror/lang-php": "6.0.1",
|
||||
"@codemirror/lang-rust": "6.0.1",
|
||||
"@codemirror/language": "6.3.2",
|
||||
"@codemirror/legacy-modes": "6.3.1",
|
||||
"@codemirror/search": "6.2.3",
|
||||
"@codemirror/state": "6.1.4",
|
||||
"@codemirror/view": "6.7.1",
|
||||
"@codemirror/language": "6.6.0",
|
||||
"@codemirror/legacy-modes": "6.3.2",
|
||||
"@codemirror/search": "6.3.0",
|
||||
"@codemirror/state": "6.2.0",
|
||||
"@codemirror/view": "6.9.3",
|
||||
"@joplin/tools": "~2.11",
|
||||
"@lezer/highlight": "1.1.4",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
|
||||
@@ -501,7 +501,7 @@ async function initialize(dispatch: Function) {
|
||||
if (Setting.value('env') === 'prod') {
|
||||
await db.open({ name: getDatabaseName(currentProfile, isSubProfile) });
|
||||
} else {
|
||||
await db.open({ name: getDatabaseName(currentProfile, isSubProfile, '-1') });
|
||||
await db.open({ name: getDatabaseName(currentProfile, isSubProfile, '-3') });
|
||||
|
||||
// await db.clearForTesting();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "2.4.2",
|
||||
"slugify": "1.6.5",
|
||||
"slugify": "1.6.6",
|
||||
"yeoman-generator": "5.8.0",
|
||||
"yosay": "2.0.2"
|
||||
},
|
||||
|
||||
@@ -110,6 +110,8 @@ export default class ReportService {
|
||||
let syncedCount = 0;
|
||||
for (let i = 0; i < BaseItem.syncItemDefinitions_.length; i++) {
|
||||
const d = BaseItem.syncItemDefinitions_[i];
|
||||
// ref: https://github.com/laurent22/joplin/issues/7940#issuecomment-1473709148
|
||||
if (d.className === 'MasterKey') continue;
|
||||
const ItemClass = BaseItem.getClass(d.className);
|
||||
const o = {
|
||||
total: await ItemClass.count(),
|
||||
|
||||
@@ -41,7 +41,7 @@ async function downloadFile(url: string, outputPath: string) {
|
||||
|
||||
export async function extractPlugins(currentDir: string, defaultPluginDir: string, downloadedPluginsNames: PluginIdAndName): Promise<void> {
|
||||
for (const pluginId of Object.keys(downloadedPluginsNames)) {
|
||||
await execCommand(`tar xzf ${currentDir}/${downloadedPluginsNames[pluginId]}`, { quiet: true });
|
||||
await execCommand(`tar xzf ${currentDir}/${downloadedPluginsNames[pluginId]}`, { quiet: true, splitCommandOptions: { handleEscape: false } });
|
||||
await move(`package/publish/${pluginId}.jpl`, `${defaultPluginDir}/${pluginId}/plugin.jpl`, { overwrite: true });
|
||||
await move(`package/publish/${pluginId}.json`, `${defaultPluginDir}/${pluginId}/manifest.json`, { overwrite: true });
|
||||
await remove(`${downloadedPluginsNames[pluginId]}`);
|
||||
@@ -73,6 +73,20 @@ export const downloadPlugins = async (localPluginsVersions: PluginAndVersion, de
|
||||
return downloadedPluginsNames;
|
||||
};
|
||||
|
||||
// Mac app signing/notarizing fails if the binaries are inside an archive (plugin.jpl)
|
||||
// Contents of plugin.jpl are unzipped just for Mac so that binary signing passes through
|
||||
// ref: https://github.com/laurent22/joplin/pull/8048, https://github.com/laurent22/joplin/pull/8040
|
||||
const extractMacPlugins = async (defaultPluginDir: string, downloadedPluginsNames: PluginIdAndName) => {
|
||||
if (process.platform !== 'darwin') return;
|
||||
|
||||
for (const pluginId in downloadedPluginsNames) {
|
||||
const pluginDirectory = `${defaultPluginDir}/${pluginId}`;
|
||||
const archivePath = `${pluginDirectory}/plugin.jpl`;
|
||||
await execCommand(`tar xzf ${archivePath} --directory ${pluginDirectory}`, { quiet: true, splitCommandOptions: { handleEscape: false } });
|
||||
await remove(archivePath);
|
||||
}
|
||||
};
|
||||
|
||||
async function start(): Promise<void> {
|
||||
const defaultPluginDir = join(__dirname, '..', '..', 'packages', 'app-desktop', 'build', 'defaultPlugins');
|
||||
const defaultPluginsInfo = getDefaultPluginsInfo();
|
||||
@@ -84,6 +98,7 @@ async function start(): Promise<void> {
|
||||
const localPluginsVersions = await localPluginsVersion(defaultPluginDir, defaultPluginsInfo);
|
||||
const downloadedPluginNames: PluginIdAndName = await downloadPlugins(localPluginsVersions, defaultPluginsInfo, manifests);
|
||||
await extractPlugins(__dirname, defaultPluginDir, downloadedPluginNames);
|
||||
await extractMacPlugins(defaultPluginDir, downloadedPluginNames);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as execa from 'execa';
|
||||
import commandToString from './commandToString';
|
||||
import splitCommandString from './splitCommandString';
|
||||
import splitCommandString, { SplitCommandOptions } from './splitCommandString';
|
||||
import { stdout } from 'process';
|
||||
|
||||
interface ExecCommandOptions {
|
||||
@@ -8,6 +8,7 @@ interface ExecCommandOptions {
|
||||
showStdout?: boolean;
|
||||
showStderr?: boolean;
|
||||
quiet?: boolean;
|
||||
splitCommandOptions?: SplitCommandOptions | null;
|
||||
}
|
||||
|
||||
export default async (command: string | string[], options: ExecCommandOptions | null = null): Promise<string> => {
|
||||
@@ -33,7 +34,7 @@ export default async (command: string | string[], options: ExecCommandOptions |
|
||||
}
|
||||
}
|
||||
|
||||
const args: string[] = typeof command === 'string' ? splitCommandString(command) : command as string[];
|
||||
const args: string[] = typeof command === 'string' ? splitCommandString(command, options.splitCommandOptions || null) : command as string[];
|
||||
const executableName = args[0];
|
||||
args.splice(0, 1);
|
||||
const promise = execa(executableName, args);
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
export default (command: string, options: any = null) => {
|
||||
export interface SplitCommandOptions {
|
||||
handleEscape?: boolean;
|
||||
}
|
||||
|
||||
export default (command: string, options: SplitCommandOptions | null = null) => {
|
||||
options = options || {};
|
||||
if (!('handleEscape' in options)) {
|
||||
options.handleEscape = true;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Joplin Android app changelog
|
||||
|
||||
## [android-v2.11.2](https://github.com/laurent22/joplin/releases/tag/android-v2.11.2) (Pre-release) - 2023-04-09T12:04:06Z
|
||||
|
||||
- Improved: Resolve #8022: Editor syntax highlighting was broken (#8023) (#8022 by Henry Heino)
|
||||
- Improved: Updated packages @react-native-community/netinfo (v9.3.8)
|
||||
- Fixed: Removed `MasterKey` from Sync Status report (#8026) (#7940 by Arun Kumar)
|
||||
- Security: Prevent bypassing fingerprint lock on certain devices (6b72f86)
|
||||
|
||||
## [android-v2.11.1](https://github.com/laurent22/joplin/releases/tag/android-v2.11.1) (Pre-release) - 2023-04-08T08:49:19Z
|
||||
|
||||
- New: Add log info for biometrics feature (efdbaeb)
|
||||
|
||||
@@ -431,6 +431,22 @@
|
||||
"created_at": "2023-04-07T10:04:51Z",
|
||||
"repoId": 79162682,
|
||||
"pullRequestNo": 8029
|
||||
},
|
||||
{
|
||||
"name": "tbjers",
|
||||
"id": 1117052,
|
||||
"comment_id": 1501316440,
|
||||
"created_at": "2023-04-10T02:33:42Z",
|
||||
"repoId": 79162682,
|
||||
"pullRequestNo": 8036
|
||||
},
|
||||
{
|
||||
"name": "simonla",
|
||||
"id": 14934570,
|
||||
"comment_id": 1503950257,
|
||||
"created_at": "2023-04-11T19:02:23Z",
|
||||
"repoId": 79162682,
|
||||
"pullRequestNo": 8042
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -741,7 +741,7 @@ The following commands are available in [command-line mode](#command-line-mode):
|
||||
|
||||
# License
|
||||
|
||||
Copyright (c) 2016-2021 Laurent Cozic
|
||||
Copyright (c) 2016-2023 Laurent Cozic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
"config:base"
|
||||
],
|
||||
"major": {
|
||||
"stabilityDays": 30,
|
||||
"stabilityDays": 80,
|
||||
},
|
||||
"minor": {
|
||||
"stabilityDays": 20,
|
||||
"stabilityDays": 40,
|
||||
},
|
||||
"patch": {
|
||||
"stabilityDays": 10,
|
||||
"stabilityDays": 20,
|
||||
},
|
||||
"prConcurrentLimit": 5,
|
||||
"prHourlyLimit": 0,
|
||||
@@ -38,6 +38,7 @@
|
||||
"@codemirror/search",
|
||||
"@codemirror/state",
|
||||
"@codemirror/view",
|
||||
"@lezer/highlight",
|
||||
"@fortawesome/fontawesome-svg-core",
|
||||
"@fortawesome/free-solid-svg-icons",
|
||||
"@svgr/webpack",
|
||||
|
||||
Reference in New Issue
Block a user