mirror of https://github.com/laurent22/joplin.git
Mobile: Upgraded React Native to v0.63
commitpull/3936/head2fb6cee901
Merge:4e303be85f
db509955f6
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 16:24:07 2020 +0100 Merge branch 'dev' into rn_63 commit4e303be85f
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 16:14:39 2020 +0100 Clean up commite3a37ec2d6
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 15:57:55 2020 +0100 Use different script for pre-commit and manual start commitbd236648fc
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 15:56:45 2020 +0100 Removed RN eslint config commite7feda41c9
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 15:27:08 2020 +0100 Revert "Disable git hook for now" This reverts commit89263ac742
. commitcfd63fe46f
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 13:02:32 2020 +0100 Ask permission to use geo-location commit66059939a3
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 12:26:20 2020 +0100 Fixed WebView race condition commit1e0d2b7b86
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 11:56:21 2020 +0100 Fixed webview issues commitf537d22d7f
Author: Laurent Cozic <laurent@cozic.net> Date: Fri Oct 16 11:08:29 2020 +0100 Improve resource file watching commiteec32cf70a
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 18:40:13 2020 +0100 Removed cache package dependency and implemented one more suitable for React Native commitefa346fea4
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 14:57:21 2020 +0100 iOS: Added fonts to Info.plist although it was working without it commit572b647bc0
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 14:56:49 2020 +0100 Specify content-type header for OneDrive to prevent network error commitbcedf6c7f0
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 12:45:01 2020 +0100 iOS: Disable long press menu since it is already built-in commit7359dd61d1
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 12:37:40 2020 +0100 Removed unused react-native-device-info commit2d63ab36d3
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 12:35:54 2020 +0100 iOS: Fixed taking a picture commit8e2875a91c
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 12:11:13 2020 +0100 iOS: Restored camera roll functionality commit75f5edf2ad
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 11:40:13 2020 +0100 iOS: Fixed build settings commitb220c98419
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 11:40:03 2020 +0100 iOS: Got images to work with WebKit commitc34b43e841
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 10:24:52 2020 +0100 iOS: Restore more settings commit32997611e6
Author: Laurent Cozic <laurent@cozic.net> Date: Thu Oct 15 10:15:14 2020 +0100 iOS: Added back icons and other properties commitb5811d7f7c
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 23:53:14 2020 +0100 Got iOS build to work commitdc6d7c00e0
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 18:40:06 2020 +0100 Imported old settings in gradle build commitdff59f5603
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 18:20:00 2020 +0100 Restored sharing commit0bdb449e72
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 17:25:40 2020 +0100 Updated NoteBodyViewer commit0c0d228815
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 16:54:42 2020 +0100 Fixed networking commit6ff45ce485
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 13:11:00 2020 +0100 Fixed document picker commitcc889182b6
Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 14 12:56:27 2020 +0100 Added back support for alarms commit040261abfa
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 22:04:49 2020 +0100 Fixed Clipboard and remove image-picker package commit1077ad8f16
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 21:54:52 2020 +0100 Fixed Select Alarm dialog and PoorManIntervals class commit8296676fd5
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 21:32:52 2020 +0100 Fixed icons and warnings commit3b0e3f6f43
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 17:02:59 2020 +0100 Got app to build again commit89263ac742
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 15:41:17 2020 +0100 Disable git hook for now commitd6da162f67
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 15:39:12 2020 +0100 Restored back all RN packages commit7f8ce3732c
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 15:13:12 2020 +0100 Restored base packages commitea59726eb3
Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 13 15:05:17 2020 +0100 Started over from scratch
parent
db509955f6
commit
cb3e1cf1e9
|
@ -64,6 +64,7 @@ CliClient/build/
|
|||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
CliClient/app/LinkSelector.js
|
||||
CliClient/app/services/plugins/PluginRunner.js
|
||||
CliClient/tests/InMemoryCache.js
|
||||
CliClient/tests/models_Setting.js
|
||||
CliClient/tests/services_CommandService.js
|
||||
CliClient/tests/services_InteropService.js
|
||||
|
@ -201,13 +202,21 @@ ReactNativeClient/lib/commands/historyBackward.js
|
|||
ReactNativeClient/lib/commands/historyForward.js
|
||||
ReactNativeClient/lib/commands/synchronize.js
|
||||
ReactNativeClient/lib/components/BackButtonDialogBox.js
|
||||
ReactNativeClient/lib/components/CameraView.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnMessage.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useSource.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/NoteBodyViewer.js
|
||||
ReactNativeClient/lib/components/screens/Note.js
|
||||
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
||||
ReactNativeClient/lib/components/SelectDateTimeDialog.js
|
||||
ReactNativeClient/lib/errorUtils.js
|
||||
ReactNativeClient/lib/eventManager.js
|
||||
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
|
||||
ReactNativeClient/lib/hooks/usePrevious.js
|
||||
ReactNativeClient/lib/hooks/usePropsDebugger.js
|
||||
ReactNativeClient/lib/InMemoryCache.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
|
@ -219,6 +228,7 @@ ReactNativeClient/lib/markdownUtils.js
|
|||
ReactNativeClient/lib/models/Alarm.js
|
||||
ReactNativeClient/lib/models/Setting.js
|
||||
ReactNativeClient/lib/ntpDate.js
|
||||
ReactNativeClient/lib/PoorManIntervals.js
|
||||
ReactNativeClient/lib/reducer.js
|
||||
ReactNativeClient/lib/services/AlarmService.js
|
||||
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
|
||||
|
|
|
@ -58,6 +58,7 @@ plugin_types/
|
|||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
CliClient/app/LinkSelector.js
|
||||
CliClient/app/services/plugins/PluginRunner.js
|
||||
CliClient/tests/InMemoryCache.js
|
||||
CliClient/tests/models_Setting.js
|
||||
CliClient/tests/services_CommandService.js
|
||||
CliClient/tests/services_InteropService.js
|
||||
|
@ -195,13 +196,21 @@ ReactNativeClient/lib/commands/historyBackward.js
|
|||
ReactNativeClient/lib/commands/historyForward.js
|
||||
ReactNativeClient/lib/commands/synchronize.js
|
||||
ReactNativeClient/lib/components/BackButtonDialogBox.js
|
||||
ReactNativeClient/lib/components/CameraView.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnMessage.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useSource.js
|
||||
ReactNativeClient/lib/components/NoteBodyViewer/NoteBodyViewer.js
|
||||
ReactNativeClient/lib/components/screens/Note.js
|
||||
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
||||
ReactNativeClient/lib/components/SelectDateTimeDialog.js
|
||||
ReactNativeClient/lib/errorUtils.js
|
||||
ReactNativeClient/lib/eventManager.js
|
||||
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
|
||||
ReactNativeClient/lib/hooks/usePrevious.js
|
||||
ReactNativeClient/lib/hooks/usePropsDebugger.js
|
||||
ReactNativeClient/lib/InMemoryCache.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
|
@ -213,6 +222,7 @@ ReactNativeClient/lib/markdownUtils.js
|
|||
ReactNativeClient/lib/models/Alarm.js
|
||||
ReactNativeClient/lib/models/Setting.js
|
||||
ReactNativeClient/lib/ntpDate.js
|
||||
ReactNativeClient/lib/PoorManIntervals.js
|
||||
ReactNativeClient/lib/reducer.js
|
||||
ReactNativeClient/lib/services/AlarmService.js
|
||||
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
|
||||
|
|
|
@ -4199,11 +4199,6 @@
|
|||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"scripts": {
|
||||
"test": "gulp buildTests -L && node node_modules/jasmine/bin/jasmine.js --fail-fast=true --config=tests/support/jasmine.json",
|
||||
"test-ci": "gulp buildTests -L && node node_modules/jasmine/bin/jasmine.js --config=tests/support/jasmine.json",
|
||||
"postinstall": "npm run build && patch-package --patch-dir ../patches",
|
||||
"postinstall": "npm run build && patch-package --patch-dir ../patches/shared && patch-package --patch-dir ../patches/node",
|
||||
"build": "gulp build",
|
||||
"start": "gulp build -L && node 'build/main.js' --stack-trace-enabled --log-level debug --env dev"
|
||||
},
|
||||
|
@ -80,7 +80,6 @@
|
|||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mime": "^2.0.3",
|
||||
"moment": "^2.24.0",
|
||||
"multiparty": "^4.2.1",
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import InMemoryCache from 'lib/InMemoryCache';
|
||||
const { time } = require('lib/time-utils.js');
|
||||
|
||||
describe('InMemoryCache', function() {
|
||||
|
||||
it('should get and set values', () => {
|
||||
const cache = new InMemoryCache();
|
||||
|
||||
expect(cache.value('test')).toBe(undefined);
|
||||
expect(cache.value('test', 'default')).toBe('default');
|
||||
|
||||
cache.setValue('test', 'something');
|
||||
expect(cache.value('test')).toBe('something');
|
||||
|
||||
// Check we get the exact same object back (cache should not copy)
|
||||
const someObj = { abcd: '123' };
|
||||
cache.setValue('someObj', someObj);
|
||||
expect(cache.value('someObj')).toBe(someObj);
|
||||
});
|
||||
|
||||
it('should expire values', async () => {
|
||||
const cache = new InMemoryCache();
|
||||
|
||||
// Check that the value is udefined once the cache has expired
|
||||
cache.setValue('test', 'something', 500);
|
||||
expect(cache.value('test')).toBe('something');
|
||||
await time.msleep(510);
|
||||
expect(cache.value('test')).toBe(undefined);
|
||||
|
||||
// Check that the TTL is reset every time setValue is called
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
|
||||
expect(cache.value('test')).toBe('something');
|
||||
});
|
||||
|
||||
it('should delete old records', async () => {
|
||||
const cache = new InMemoryCache(5);
|
||||
|
||||
cache.setValue('1', '1');
|
||||
cache.setValue('2', '2');
|
||||
cache.setValue('3', '3');
|
||||
cache.setValue('4', '4');
|
||||
cache.setValue('5', '5');
|
||||
|
||||
expect(cache.value('1')).toBe('1');
|
||||
|
||||
cache.setValue('6', '6');
|
||||
|
||||
expect(cache.value('1')).toBe(undefined);
|
||||
});
|
||||
|
||||
});
|
|
@ -146,7 +146,7 @@ describe('services_rest_Api', function() {
|
|||
}));
|
||||
|
||||
const noteId = response.id;
|
||||
|
||||
|
||||
{
|
||||
const note = await Note.load(noteId);
|
||||
expect(note.latitude).toBe('48.73207100');
|
||||
|
@ -154,7 +154,7 @@ describe('services_rest_Api', function() {
|
|||
expect(note.altitude).toBe('21.0000');
|
||||
}
|
||||
|
||||
await api.route('PUT', 'notes/' + noteId, null, JSON.stringify({
|
||||
await api.route('PUT', `notes/${noteId}`, null, JSON.stringify({
|
||||
latitude: '49',
|
||||
longitude: '-3',
|
||||
altitude: '22',
|
||||
|
|
|
@ -8061,11 +8061,6 @@
|
|||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.0.4.tgz",
|
||||
"integrity": "sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA=="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"mermaid": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.8.1.tgz",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dist": "node_modules/.bin/electron-builder",
|
||||
"build": "patch-package --patch-dir ../patches && gulp build",
|
||||
"build": "patch-package --patch-dir ../patches/shared && patch-package --patch-dir ../patches/node && gulp build",
|
||||
"postinstall": "npm run build && gulp electronRebuild",
|
||||
"start": "gulp build && electron . --env dev --log-level debug --no-welcome --open-dev-tools"
|
||||
},
|
||||
|
@ -169,7 +169,6 @@
|
|||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mermaid": "^8.8.1",
|
||||
"moment": "^2.22.2",
|
||||
"multiparty": "^4.2.1",
|
||||
|
|
|
@ -21,7 +21,7 @@ node_modules/warning/.*
|
|||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/interface.js
|
||||
node_modules/react-native/flow/
|
||||
|
||||
[options]
|
||||
|
@ -36,9 +36,8 @@ module.file_ext=.ios.js
|
|||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation'
|
||||
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
|
||||
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
|
@ -57,7 +56,6 @@ untyped-type-import=warn
|
|||
nonstrict-import=warn
|
||||
deprecated-type=warn
|
||||
unsafe-getters-setters=warn
|
||||
inexact-spread=warn
|
||||
unnecessary-invariant=warn
|
||||
signature-verification-failure=warn
|
||||
deprecated-utility=error
|
||||
|
@ -72,4 +70,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.105.0
|
||||
^0.122.0
|
||||
|
|
|
@ -20,7 +20,6 @@ DerivedData
|
|||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
|
@ -42,29 +41,19 @@ buck-out/
|
|||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# CocoaPods
|
||||
ios/Pods/
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
# https://docs.fastlane.tools/best-practices/source-control/
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
|
||||
# This is generated:
|
||||
android/build*
|
||||
android/app/build*
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
|
||||
android/.project
|
||||
android/.settings/
|
||||
android/app/.classpath
|
||||
android/app/.project
|
||||
android/app/.settings/
|
||||
android/app/src/debug/res/
|
||||
|
||||
pluginAssets/
|
||||
# CocoaPods
|
||||
/ios/Pods/
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
bracketSpacing: false,
|
||||
jsxBracketSameLine: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
};
|
|
@ -13,7 +13,7 @@ import {
|
|||
Image,
|
||||
} from 'react-native';
|
||||
import { renderFormatButtons } from './renderButtons';
|
||||
import { NoteBodyViewer } from 'lib/components/note-body-viewer.js';
|
||||
import NoteBodyViewer from 'lib/components/NoteBodyViewer/NoteBodyViewer';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonContainer: {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
|
@ -15,9 +15,14 @@ import com.android.build.OutputFile
|
|||
* // the name of the generated asset file containing your JS bundle
|
||||
* bundleAssetName: "index.android.bundle",
|
||||
*
|
||||
* // the entry file for bundle generation
|
||||
* // the entry file for bundle generation. If none specified and
|
||||
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
|
||||
* // default. Can be overridden with ENTRY_FILE environment variable.
|
||||
* entryFile: "index.android.js",
|
||||
*
|
||||
* // https://reactnative.dev/docs/performance#enable-the-ram-format
|
||||
* bundleCommand: "ram-bundle",
|
||||
*
|
||||
* // whether to bundle JS and assets in debug mode
|
||||
* bundleInDebug: false,
|
||||
*
|
||||
|
@ -33,6 +38,13 @@ import com.android.build.OutputFile
|
|||
* // bundleInPaidRelease: true,
|
||||
* // bundleInBeta: true,
|
||||
*
|
||||
* // whether to disable dev mode in custom build variants (by default only disabled in release)
|
||||
* // for example: to disable dev mode in the staging build type (if configured)
|
||||
* devDisabledInStaging: true,
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'devDisabledIn${productFlavor}${buildType}'
|
||||
* // 'devDisabledIn${buildType}'
|
||||
*
|
||||
* // the root of your project, i.e. where "package.json" lives
|
||||
* root: "../../",
|
||||
*
|
||||
|
@ -66,7 +78,6 @@ import com.android.build.OutputFile
|
|||
*/
|
||||
|
||||
project.ext.react = [
|
||||
entryFile: "index.android.js",
|
||||
enableHermes: false, // clean and rebuild if changing
|
||||
]
|
||||
|
||||
|
@ -99,6 +110,7 @@ def enableProguardInReleaseBuilds = false
|
|||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
|
||||
/**
|
||||
* Whether to enable the Hermes VM.
|
||||
*
|
||||
|
@ -111,18 +123,13 @@ def enableHermes = project.ext.react.get("enableHermes", false);
|
|||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
// To fix this error:
|
||||
// > java.io.UncheckedIOException: java.io.IOException: Execution of compression failed. java.lang.OutOfMemoryError
|
||||
// https://stackoverflow.com/q/57284812/561309
|
||||
dexOptions { javaMaxHeapSize "4g" }
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "net.cozic.joplin"
|
||||
defaultConfig {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097583
|
||||
|
@ -130,18 +137,23 @@ android {
|
|||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
|
||||
// https://github.com/react-native-community/react-native-camera/issues/2138
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
|
||||
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
|
||||
multiDexEnabled true
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('debug.keystore')
|
||||
storePassword 'android'
|
||||
keyAlias 'androiddebugkey'
|
||||
|
@ -156,57 +168,54 @@ android {
|
|||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
release {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://facebook.github.io/react-native/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// https://developer.android.com/studio/build/configure-apk-splits.html
|
||||
release {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.debug
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// https://developer.android.com/studio/build/configure-apk-splits.html
|
||||
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.webkit:android-jsc:r241213"
|
||||
compile project(':react-native-push-notification')
|
||||
// implementation (project(':react-native-camera')) {
|
||||
// // This is required because com.google.firebase requires v16.0.x of com.google.android.gms
|
||||
// // while react-native-camera requires v15.x, which results in broken dependencies with
|
||||
// // this error message:
|
||||
// //
|
||||
// // The library com.google.android.gms:play-services-base is being requested by various other libraries at [[15.0.1,15.0.1]], but resolves to 16.0.1
|
||||
// //
|
||||
// // For the record: found solution by removing all Firebase stuff here and running "gradlew.bat :app:dependencies"
|
||||
// // That shows that react-native-camera was the one requiring v15.0.1.
|
||||
// exclude group: "com.google.android.gms"
|
||||
// }
|
||||
implementation project(':react-native-file-viewer')
|
||||
implementation project(':react-native-securerandom')
|
||||
implementation project(':react-native-fs')
|
||||
implementation project(':react-native-image-picker')
|
||||
implementation project(':react-native-vector-icons')
|
||||
implementation project(':react-native-fs')
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "com.android.support:appcompat-v7:28.0.0"
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||
}
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
}
|
||||
|
||||
if (enableHermes) {
|
||||
def hermesPath = "../../node_modules/hermes-engine/android/";
|
||||
|
@ -216,44 +225,16 @@ dependencies {
|
|||
implementation jscFlavor
|
||||
}
|
||||
|
||||
implementation project(':react-native-sqlite-storage')
|
||||
implementation project(':rn-fetch-blob')
|
||||
implementation project(':react-native-document-picker')
|
||||
implementation project(':react-native-image-resizer')
|
||||
// implementation project(':react-native-share-extension')
|
||||
implementation project(':react-native-version-info')
|
||||
implementation project(':react-native-camera')
|
||||
implementation "com.facebook.react:react-native:+"
|
||||
implementation project(':react-native-quick-actions')
|
||||
|
||||
// implementation "com.google.android.gms:play-services-base:16.0.1" // For Firebase
|
||||
// implementation 'me.leolin:ShortcutBadger:1.1.21@aar' // For Firebase - this line if you wish to use badge on Android
|
||||
|
||||
// To fix the error below, which happened after adding react-native-camera.
|
||||
// Doesn't make any sense since rn-camera neither defines v26 nor 27 but
|
||||
// v25.0.2 in build.gradle, but anyway now it works ¯\_(ツ)_/¯
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Fatal error
|
||||
// { Error: Command failed: ./gradlew assembleRelease -PbuildDir=build --console plain
|
||||
//
|
||||
// FAILURE: Build failed with an exception.
|
||||
//
|
||||
// * What went wrong:
|
||||
// Execution failed for task ':app:preReleaseBuild'.
|
||||
// > Android dependency 'com.android.support:support-v4' has different version for the compile (26.1.0) and runtime (27.1.1) classpath. You should manually set the same version via DependencyResolution
|
||||
// --------------------------------------------------------------------------------------
|
||||
// https://github.com/react-native-community/react-native-camera/issues/1532#issuecomment-386434771
|
||||
compile ("com.android.support:support-v4:26.0.1") {
|
||||
force = true //<-- force dependency resolution to 26.0.1 in my case
|
||||
}
|
||||
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
|
||||
implementation 'com.android.support:multidex:2.0.1'
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
// puts all compile dependencies into folder libs for BUCK to use
|
||||
task copyDownloadableDepsToLibs(type: Copy) {
|
||||
from configurations.compile
|
||||
into 'libs'
|
||||
from configurations.compile
|
||||
into 'libs'
|
||||
}
|
||||
|
||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
"""Helper definitions to glob .aar and .jar targets"""
|
||||
|
||||
def create_aar_targets(aarfiles):
|
||||
for aarfile in aarfiles:
|
||||
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
|
||||
lib_deps.append(":" + name)
|
||||
android_prebuilt_aar(
|
||||
name = name,
|
||||
aar = aarfile,
|
||||
)
|
||||
|
||||
def create_jar_targets(jarfiles):
|
||||
for jarfile in jarfiles:
|
||||
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
|
||||
lib_deps.append(":" + name)
|
||||
prebuilt_jar(
|
||||
name = name,
|
||||
binary_jar = jarfile,
|
||||
)
|
Binary file not shown.
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
*/
|
||||
package net.cozic.joplin;
|
||||
|
||||
import android.content.Context;
|
||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
||||
import com.facebook.flipper.android.utils.FlipperUtils;
|
||||
import com.facebook.flipper.core.FlipperClient;
|
||||
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
|
||||
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.network.NetworkingModule;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class ReactNativeFlipper {
|
||||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
|
||||
if (FlipperUtils.shouldEnableFlipper(context)) {
|
||||
final FlipperClient client = AndroidFlipperClient.getInstance(context);
|
||||
|
||||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
|
||||
client.addPlugin(new ReactFlipperPlugin());
|
||||
client.addPlugin(new DatabasesFlipperPlugin(context));
|
||||
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
|
||||
client.addPlugin(CrashReporterPlugin.getInstance());
|
||||
|
||||
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
|
||||
NetworkingModule.setCustomClientBuilder(
|
||||
new NetworkingModule.CustomClientBuilder() {
|
||||
@Override
|
||||
public void apply(OkHttpClient.Builder builder) {
|
||||
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
|
||||
}
|
||||
});
|
||||
client.addPlugin(networkFlipperPlugin);
|
||||
client.start();
|
||||
|
||||
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
|
||||
// Hence we run if after all native modules have been initialized
|
||||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
||||
if (reactContext == null) {
|
||||
reactInstanceManager.addReactInstanceEventListener(
|
||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
||||
@Override
|
||||
public void onReactContextInitialized(ReactContext reactContext) {
|
||||
reactInstanceManager.removeReactInstanceEventListener(this);
|
||||
reactContext.runOnNativeModulesQueueThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
client.addPlugin(new FrescoFlipperPlugin());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
client.addPlugin(new FrescoFlipperPlugin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +1,89 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto"
|
||||
package="net.cozic.joplin"
|
||||
android:versionCode="2"
|
||||
android:versionName="0.8.0">
|
||||
package="net.cozic.joplin">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove"/>
|
||||
|
||||
<!-- ============================= -->
|
||||
<!-- START RN-push-notitication -->
|
||||
<!-- ============================= -->
|
||||
<!-- RN-NOTIFICATION -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
|
||||
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<!-- ============================= -->
|
||||
<!-- END RN-push-notitication -->
|
||||
<!-- ============================= -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<!-- /RN-NOTIFICATION -->
|
||||
|
||||
<!-- Make these features optional to enable Chromebooks -->
|
||||
<!-- Make these features optional to enable Chromebooks -->
|
||||
<!-- https://github.com/laurent22/joplin/issues/37 -->
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="26" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:theme="@style/AppTheme"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:allowBackup="false"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:hardwareAccelerated="true"
|
||||
android:largeHeap="true"
|
||||
>
|
||||
|
||||
<!-- ============================= -->
|
||||
<!-- START RN-push-notitication -->
|
||||
<!-- ============================= -->
|
||||
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_name" android:value="@string/default_notification_channel_id"/>
|
||||
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_description" android:value="Allow displaying a notification for Joplin's alarms"/>
|
||||
<meta-data android:name="com.dieam.reactnativepushnotification.notification_color" android:resource="@android:color/white"/>
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<!-- RN-NOTIFICATION -->
|
||||
<receiver
|
||||
android:name="com.google.android.gms.gcm.GcmReceiver"
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.c2dm.permission.SEND" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
<category android:name="${applicationId}" />
|
||||
</intent-filter>
|
||||
android:name="com.emekalites.react.alarm.notification.AlarmReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="ACTION_DISMISS" />
|
||||
<action android:name="ACTION_SNOOZE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
|
||||
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
|
||||
<receiver
|
||||
android:name="com.emekalites.react.alarm.notification.AlarmDismissReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
<receiver
|
||||
android:name="com.emekalites.react.alarm.notification.AlarmBootReceiver"
|
||||
android:directBootAware="true"
|
||||
android:enabled="false"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- /RN-NOTIFICATION -->
|
||||
|
||||
<service
|
||||
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerServiceGcm"
|
||||
android:exported="false" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<!-- ============================= -->
|
||||
<!-- END RN-push-notitication -->
|
||||
<!-- ============================= -->
|
||||
|
||||
<!--
|
||||
2018-12-16: Changed android:launchMode from "singleInstance" to "singleTop" for Firebase notification
|
||||
Previously singleInstance was necessary to prevent multiple instance of the RN app from running at the same time, but maybe no longer needed.
|
||||
|
||||
2020-10-06: Changed back again to "singleInstance" and notifications still seem to work. Changing to singleInstance
|
||||
to try to fix this bug: https://discourse.joplinapp.org/t/joplin-android-app-looses-nextcloud-sync-settings/10997/6
|
||||
Users would lose their settings, and it's possibly due to multiple instances of the app running at the same time, perhaps
|
||||
due to sharing with the app. When checking the log, it would show "saving settings", then the app startup message, and after the app
|
||||
has started, it would show "setting saved". So basically the app, or one instance of it, has started while settings were being saved
|
||||
|
||||
2020-10-08: Changed back again to "singleTop" as it has worked so far. The multiple instance bug was "fixed" in a different way
|
||||
See ReactNativeClient/root.js for more info about the bug.
|
||||
2018-12-16: Changed android:launchMode from "singleInstance" to "singleTop" for Firebase notification
|
||||
Previously singleInstance was necessary to prevent multiple instance of the RN app from running at the same time, but maybe no longer needed.
|
||||
|
||||
2020-10-06: Changed back again to "singleInstance" and notifications still seem to work. Changing to singleInstance
|
||||
to try to fix this bug: https://discourse.joplinapp.org/t/joplin-android-app-looses-nextcloud-sync-settings/10997/6
|
||||
Users would lose their settings, and it's possibly due to multiple instances of the app running at the same time, perhaps
|
||||
due to sharing with the app. When checking the log, it would show "saving settings", then the app startup message, and after the app
|
||||
has started, it would show "setting saved". So basically the app, or one instance of it, has started while settings were being saved
|
||||
|
||||
2020-10-08: Changed back again to "singleTop" as it has worked so far. The multiple instance bug was "fixed" in a different way
|
||||
See ReactNativeClient/root.js for more info about the bug.
|
||||
-->
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:launchMode="singleTop">
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
||||
android:launchMode="singleTop"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
|
||||
<!-- SHARE EXTENSION -->
|
||||
<activity
|
||||
android:noHistory="true"
|
||||
android:name=".share.ShareActivity"
|
||||
|
@ -124,6 +102,8 @@
|
|||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<!-- /SHARE EXTENSION -->
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
|
@ -12,4 +12,4 @@ public class MainActivity extends ReactActivity {
|
|||
protected String getMainComponentName() {
|
||||
return "Joplin";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,24 +3,28 @@ package net.cozic.joplin;
|
|||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.database.CursorWindow;
|
||||
import android.os.Build;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import androidx.multidex.MultiDex;
|
||||
import com.facebook.react.PackageList;
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import net.cozic.joplin.share.SharePackage;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import net.cozic.joplin.share.SharePackage;
|
||||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(this);
|
||||
}
|
||||
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
new ReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
|
@ -29,6 +33,7 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
packages.add(new SharePackage());
|
||||
|
@ -41,23 +46,16 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
// Enable debugging with the WebView we use to display notes
|
||||
// Changes are made as recommended by folks at `react-native-webview`
|
||||
// https://github.com/react-native-community/react-native-webview/blob/master/docs/Debugging.md
|
||||
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
}
|
||||
|
||||
// To try to fix the error "Row too big to fit into CursorWindow"
|
||||
// To try to fix the error "Row too big to fit into CursorWindow"
|
||||
// https://github.com/andpor/react-native-sqlite-storage/issues/364#issuecomment-526423153
|
||||
// https://github.com/laurent22/joplin/issues/1767#issuecomment-515617991
|
||||
try {
|
||||
|
@ -66,25 +64,31 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
field.set(null, 50 * 1024 * 1024); //the 102400 is the new size added
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
|
||||
}
|
||||
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads Flipper in React Native templates.
|
||||
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
|
||||
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
*
|
||||
* @param context
|
||||
* @param reactInstanceManager
|
||||
*/
|
||||
private static void initializeFlipper(Context context) {
|
||||
private static void initializeFlipper(
|
||||
Context context, ReactInstanceManager reactInstanceManager) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
try {
|
||||
/*
|
||||
We use reflection here to pick up the class that initializes Flipper,
|
||||
since Flipper library is not available in release mode
|
||||
*/
|
||||
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
|
||||
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
|
||||
Class<?> aClass = Class.forName("net.cozic.joplin.ReactNativeFlipper");
|
||||
aClass
|
||||
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
||||
.invoke(null, context, reactInstanceManager);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
|
@ -96,4 +100,4 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
<resources>
|
||||
<color name="white">#FFF</color>
|
||||
</resources>
|
|
@ -2,18 +2,17 @@
|
|||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "28.0.3"
|
||||
buildToolsVersion = "29.0.2"
|
||||
minSdkVersion = 16
|
||||
compileSdkVersion = 28
|
||||
targetSdkVersion = 28
|
||||
compileSdkVersion = 29
|
||||
targetSdkVersion = 29
|
||||
}
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:3.4.2")
|
||||
|
||||
classpath("com.android.tools.build:gradle:3.5.3")
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
@ -22,10 +21,6 @@ buildscript {
|
|||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url("$rootDir/../node_modules/react-native/android")
|
||||
|
@ -34,22 +29,9 @@ allprojects {
|
|||
// Android JSC is installed from npm
|
||||
url("$rootDir/../node_modules/jsc-android/dist")
|
||||
}
|
||||
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'https://jitpack.io' }
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Maybe remove this (forgot why it was needed - probably to make some module work)
|
||||
|
||||
subprojects {
|
||||
afterEvaluate {project ->
|
||||
if (project.hasProperty("android")) {
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# Required for react-native-webview
|
||||
# https://github.com/react-native-community/react-native-webview/blob/master/docs/Getting-Started.md
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
|
||||
# To fix this error:
|
||||
# > java.io.UncheckedIOException: java.io.IOException: Execution of compression failed. java.lang.OutOfMemoryError
|
||||
# https://stackoverflow.com/q/57284812/561309
|
||||
org.gradle.jvmargs=-Xmx4608m
|
||||
# Version of flipper SDK to use with React Native
|
||||
FLIPPER_VERSION=0.54.0
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -125,8 +125,8 @@ if $darwin; then
|
|||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
@ -154,19 +154,19 @@ if $cygwin ; then
|
|||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
@ -175,14 +175,9 @@ save () {
|
|||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem http://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
|
@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
|||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
rootProject.name = 'Joplin'
|
||||
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||
include ':react-native-fs'
|
||||
project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
|
||||
|
||||
include ':app'
|
||||
|
||||
|
||||
|
||||
//include ':app', ':react-native-share-extension'
|
||||
//project(':react-native-share-extension').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-share-extension/android')
|
||||
|
||||
include ':react-native-push-notification'
|
||||
project(':react-native-push-notification').projectDir = file('../node_modules/react-native-push-notification/android')
|
||||
|
||||
include ':react-native-camera'
|
||||
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
|
|
@ -1,29 +1,4 @@
|
|||
{
|
||||
"name": "Joplin",
|
||||
"displayName": "Joplin",
|
||||
"expo": {
|
||||
"name": "Joplin",
|
||||
"description": "Joplin for Android",
|
||||
"slug": "Joplin",
|
||||
"privacy": "public",
|
||||
"sdkVersion": "18.0.0",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#cccccc",
|
||||
"icon": "./assets/icons/app-icon.png",
|
||||
"notification": {
|
||||
"icon": "./assets/icons/notification-icon.png",
|
||||
"color": "#000000"
|
||||
},
|
||||
"loading": {
|
||||
"icon": "./assets/icons/loading-icon.png",
|
||||
"hideExponentText": false
|
||||
},
|
||||
"packagerOpts": {
|
||||
"assetExts": ["ttf"]
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
}
|
||||
}
|
||||
"displayName": "Joplin"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
const gulp = require('gulp');
|
||||
const utils = require('../Tools/gulp/utils');
|
||||
|
||||
const tasks = {
|
||||
encodeAssets: {
|
||||
fn: require('./tools/encodeAssets'),
|
||||
},
|
||||
buildReactNativeInjectedJs: {
|
||||
fn: require('./tools/buildReactNativeInjectedJs'),
|
||||
},
|
||||
podInstall: {
|
||||
fn: require('./tools/podInstall'),
|
||||
},
|
||||
};
|
||||
|
||||
utils.registerGulpTasks(gulp, tasks);
|
||||
|
||||
gulp.task('build', gulp.series(
|
||||
'buildReactNativeInjectedJs',
|
||||
'encodeAssets',
|
||||
'podInstall'
|
||||
));
|
|
@ -1,3 +0,0 @@
|
|||
const { main } = require('./main.js');
|
||||
|
||||
main();
|
|
@ -1,3 +0,0 @@
|
|||
const { main } = require('./main.js');
|
||||
|
||||
main();
|
|
@ -1,3 +1,44 @@
|
|||
const { main } = require('./main.js');
|
||||
// Note about the application structure:
|
||||
// - The user interface and its state is managed by React/Redux.
|
||||
// - Persistent storage to SQLite and Web API is handled outside of React/Redux using regular JavaScript (no middleware, no thunk, etc.).
|
||||
// - Communication from React to SQLite is done by calling model methods (note.save, etc.)
|
||||
// - Communication from SQLite to Redux is done via dispatcher.
|
||||
|
||||
main();
|
||||
// So there's basically still a one way flux: React => SQLite => Redux => React
|
||||
|
||||
import { LogBox, AppRegistry } from 'react-native';
|
||||
const { Root } = require('./root.js');
|
||||
|
||||
// Seems JavaScript developers love adding warnings everywhere, even when these warnings can't be fixed
|
||||
// or don't really matter. Because we want important warnings to actually be fixed, we disable
|
||||
// all the useless ones, that way we aren't flooded by them when the app starts, and when there's
|
||||
// one we know it should be fixed (or added here).
|
||||
LogBox.ignoreLogs([
|
||||
// Happens for example in react-native-side-menu, but the package is discontinued
|
||||
// and we should just switch to a different one (or do it without a package).
|
||||
'Animated: `useNativeDriver` was not specified. This is a required option and must be explicitly set to `true` or `false`',
|
||||
|
||||
// What's the point of printing warnings for non-user code. Of all the things that
|
||||
// are broken and unreliable in React Native, require cycles are just a minor annoyance
|
||||
// which shouldn't forever print warnings.
|
||||
// To make it more fun, they don't normalise paths so forward slashes and backward slashes
|
||||
// need to be handled to support Windows.
|
||||
'Require cycle: node_modules/react-native-',
|
||||
'Require cycle: node_modules\\react-native-',
|
||||
'Require cycle: node_modules/rn-fetch-blob',
|
||||
'Require cycle: node_modules\\rn-fetch-blob',
|
||||
'Require cycle: node_modules/aws-sdk',
|
||||
'Require cycle: node_modules\\aws-sdk',
|
||||
|
||||
// It's being updated over time and we don't need to see these warnings all the time
|
||||
'Warning: componentWillReceiveProps has been renamed',
|
||||
'Warning: componentWillUpdate has been renamed',
|
||||
'Warning: componentWillMount has been renamed',
|
||||
|
||||
// Triggered by react-native-webview. Happens on slow devices when loading the note viewer.
|
||||
// Apparently it can be safely ignored:
|
||||
// https://github.com/react-native-webview/react-native-webview/issues/124
|
||||
'Did not receive response to shouldStartLoad in time, defaulting to YES',
|
||||
]);
|
||||
|
||||
AppRegistry.registerComponent('Joplin', () => Root);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
@ -22,6 +22,19 @@
|
|||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
|
@ -36,19 +49,5 @@
|
|||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
|
|
@ -8,36 +8,37 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
9E1B958F73B0E37D15AA9B24 /* libPods-Joplin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DDE6F1BE6285C68A2DA17BE9 /* libPods-Joplin.a */; };
|
||||
AE6BB3A2FDA34D01864A721A /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 381C047F2739439CB3E6452A /* libRNVectorIcons.a */; };
|
||||
ED297163215061F000B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED297162215061F000B7C4FE /* JavaScriptCore.framework */; };
|
||||
ED2971652150620600B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED2971642150620600B7C4FE /* JavaScriptCore.framework */; };
|
||||
F3D0BB525E6C490294D73075 /* libRNSecureRandom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */; };
|
||||
FBF57CE2F0F448FA9A8985E2 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EB8BCAEA9AA41CAAE460443 /* libsqlite3.0.tbd */; };
|
||||
46E31F54C547C341F605BB66 /* libPods-Joplin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A5E1CD825FABD6C4E704EA54 /* libPods-Joplin.a */; };
|
||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
|
||||
0EB8BCAEA9AA41CAAE460443 /* libsqlite3.0.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
|
||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* JoplinTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JoplinTests.m; sourceTree = "<group>"; };
|
||||
09056573D4C040FBD5FEB93A /* Pods-Joplin-JoplinTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-JoplinTests.debug.xcconfig"; path = "Target Support Files/Pods-Joplin-JoplinTests/Pods-Joplin-JoplinTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* Joplin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Joplin.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Joplin/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Joplin/AppDelegate.m; sourceTree = "<group>"; };
|
||||
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Joplin/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Joplin/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Joplin/main.m; sourceTree = "<group>"; };
|
||||
22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSecureRandom.a; sourceTree = "<group>"; };
|
||||
381C047F2739439CB3E6452A /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
|
||||
4DA7F7A61FC1196F00353191 /* Joplin.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Joplin.entitlements; path = Joplin/Joplin.entitlements; sourceTree = "<group>"; };
|
||||
6CFFC13990302AAE61F81DB1 /* Pods-Joplin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin.release.xcconfig"; path = "Target Support Files/Pods-Joplin/Pods-Joplin.release.xcconfig"; sourceTree = "<group>"; };
|
||||
756FF6C78FB548317DAD12C0 /* Pods-Joplin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin.debug.xcconfig"; path = "Target Support Files/Pods-Joplin/Pods-Joplin.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
DDE6F1BE6285C68A2DA17BE9 /* libPods-Joplin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Joplin.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
14868D674CC065C7BF1C9944 /* Pods-Joplin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin.release.xcconfig"; path = "Target Support Files/Pods-Joplin/Pods-Joplin.release.xcconfig"; sourceTree = "<group>"; };
|
||||
245A6EBAE2E874DB706B16DB /* Pods-Joplin-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-tvOS.release.xcconfig"; path = "Target Support Files/Pods-Joplin-tvOS/Pods-Joplin-tvOS.release.xcconfig"; sourceTree = "<group>"; };
|
||||
258F823D616BE3D6A52BC900 /* libPods-Joplin-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Joplin-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2C91CD1424C7137D07789148 /* Pods-Joplin-JoplinTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-JoplinTests.release.xcconfig"; path = "Target Support Files/Pods-Joplin-JoplinTests/Pods-Joplin-JoplinTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
2DA44D9A347489A29B995F73 /* Pods-Joplin-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Joplin-tvOSTests/Pods-Joplin-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
37DBC181C4AD99CBE0D07EEB /* Pods-Joplin-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-Joplin-tvOSTests/Pods-Joplin-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
505CB61090817F4453631957 /* Pods-Joplin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin.debug.xcconfig"; path = "Target Support Files/Pods-Joplin/Pods-Joplin.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = Joplin/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
A3FEB746EE7F1B0FF28528E1 /* Pods-Joplin-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Joplin-tvOS/Pods-Joplin-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A5E1CD825FABD6C4E704EA54 /* libPods-Joplin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Joplin.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B61798F36B3BC123BF8EA4D9 /* libPods-Joplin-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Joplin-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
|
||||
F5E37D05726A4A08B2EE323A /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFetchBlob.a; sourceTree = "<group>"; };
|
||||
F69B873C692CE22F1C4C9264 /* libPods-Joplin-JoplinTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Joplin-JoplinTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -45,68 +46,55 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
ED297163215061F000B7C4FE /* JavaScriptCore.framework in Frameworks */,
|
||||
ED2971652150620600B7C4FE /* JavaScriptCore.framework in Frameworks */,
|
||||
FBF57CE2F0F448FA9A8985E2 /* libsqlite3.0.tbd in Frameworks */,
|
||||
AE6BB3A2FDA34D01864A721A /* libRNVectorIcons.a in Frameworks */,
|
||||
F3D0BB525E6C490294D73075 /* libRNSecureRandom.a in Frameworks */,
|
||||
9E1B958F73B0E37D15AA9B24 /* libPods-Joplin.a in Frameworks */,
|
||||
46E31F54C547C341F605BB66 /* libPods-Joplin.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
04FA5E9085024E3A9DAF0E03 /* Frameworks */ = {
|
||||
00E356EF1AD99517003FC87E /* JoplinTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
|
||||
0EB8BCAEA9AA41CAAE460443 /* libsqlite3.0.tbd */,
|
||||
DDE6F1BE6285C68A2DA17BE9 /* libPods-Joplin.a */,
|
||||
00E356F21AD99517003FC87E /* JoplinTests.m */,
|
||||
00E356F01AD99517003FC87E /* Supporting Files */,
|
||||
);
|
||||
name = Frameworks;
|
||||
path = JoplinTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
00E356F01AD99517003FC87E /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
00E356F11AD99517003FC87E /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13B07FAE1A68108700A75B9A /* Joplin */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4DA7F7A61FC1196F00353191 /* Joplin.entitlements */,
|
||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */,
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
|
||||
13B07FB71A68108700A75B9A /* main.m */,
|
||||
);
|
||||
name = Joplin;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4D2A85911FBCE3950028537D /* Recovered References */ = {
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F5E37D05726A4A08B2EE323A /* libRNFetchBlob.a */,
|
||||
381C047F2739439CB3E6452A /* libRNVectorIcons.a */,
|
||||
22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */,
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
|
||||
B61798F36B3BC123BF8EA4D9 /* libPods-Joplin-tvOS.a */,
|
||||
258F823D616BE3D6A52BC900 /* libPods-Joplin-tvOSTests.a */,
|
||||
A5E1CD825FABD6C4E704EA54 /* libPods-Joplin.a */,
|
||||
F69B873C692CE22F1C4C9264 /* libPods-Joplin-JoplinTests.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F0B55ADB94AB5BB22C598AC /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
756FF6C78FB548317DAD12C0 /* Pods-Joplin.debug.xcconfig */,
|
||||
6CFFC13990302AAE61F81DB1 /* Pods-Joplin.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7FDFE2A137C24ED08645158D /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Resources;
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
|
@ -121,11 +109,10 @@
|
|||
children = (
|
||||
13B07FAE1A68108700A75B9A /* Joplin */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
00E356EF1AD99517003FC87E /* JoplinTests */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
04FA5E9085024E3A9DAF0E03 /* Frameworks */,
|
||||
7FDFE2A137C24ED08645158D /* Resources */,
|
||||
4D2A85911FBCE3950028537D /* Recovered References */,
|
||||
5F0B55ADB94AB5BB22C598AC /* Pods */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
9CDB1D9DB6483D893504BFCB /* Pods */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
|
@ -140,6 +127,21 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9CDB1D9DB6483D893504BFCB /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
505CB61090817F4453631957 /* Pods-Joplin.debug.xcconfig */,
|
||||
14868D674CC065C7BF1C9944 /* Pods-Joplin.release.xcconfig */,
|
||||
09056573D4C040FBD5FEB93A /* Pods-Joplin-JoplinTests.debug.xcconfig */,
|
||||
2C91CD1424C7137D07789148 /* Pods-Joplin-JoplinTests.release.xcconfig */,
|
||||
A3FEB746EE7F1B0FF28528E1 /* Pods-Joplin-tvOS.debug.xcconfig */,
|
||||
245A6EBAE2E874DB706B16DB /* Pods-Joplin-tvOS.release.xcconfig */,
|
||||
2DA44D9A347489A29B995F73 /* Pods-Joplin-tvOSTests.debug.xcconfig */,
|
||||
37DBC181C4AD99CBE0D07EEB /* Pods-Joplin-tvOSTests.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -147,19 +149,20 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Joplin" */;
|
||||
buildPhases = (
|
||||
071815849A41B8B427FC87DC /* [CP] Check Pods Manifest.lock */,
|
||||
335ACF4DE85695BEBB18D8A3 /* [CP] Check Pods Manifest.lock */,
|
||||
FD10A7F022414F080027D42C /* Start Packager */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
B4AFEC44AA65E5E06375BA82 /* [CP] Copy Pods Resources */,
|
||||
CBC8354E4CF5CF4E15F2FCDE /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Joplin;
|
||||
productName = "Hello World";
|
||||
productName = Joplin;
|
||||
productReference = 13B07F961A680F5B00A75B9A /* Joplin.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
|
@ -169,29 +172,20 @@
|
|||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 610;
|
||||
LastUpgradeCheck = 1130;
|
||||
ORGANIZATIONNAME = joplinapp.org;
|
||||
TargetAttributes = {
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
DevelopmentTeam = A9BXAFS6CT;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.Push = {
|
||||
enabled = 1;
|
||||
};
|
||||
com.apple.iCloud = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
LastSwiftMigration = 1120;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Joplin" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
|
@ -210,8 +204,8 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -232,7 +226,7 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=/usr/local/opt/node@12/bin/node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
};
|
||||
071815849A41B8B427FC87DC /* [CP] Check Pods Manifest.lock */ = {
|
||||
335ACF4DE85695BEBB18D8A3 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
|
@ -254,7 +248,7 @@
|
|||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B4AFEC44AA65E5E06375BA82 /* [CP] Copy Pods Resources */ = {
|
||||
CBC8354E4CF5CF4E15F2FCDE /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
|
@ -277,6 +271,7 @@
|
|||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
|
@ -296,12 +291,32 @@
|
|||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Joplin/Pods-Joplin-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FD10A7F022414F080027D42C /* Start Packager */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Start Packager";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
@ -316,47 +331,19 @@
|
|||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
13B07FB21A68108700A75B9A /* Base */,
|
||||
);
|
||||
name = LaunchScreen.xib;
|
||||
path = Joplin;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 756FF6C78FB548317DAD12C0 /* Pods-Joplin.debug.xcconfig */;
|
||||
baseConfigurationReference = 505CB61090817F4453631957 /* Pods-Joplin.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)..",
|
||||
ode_modules,
|
||||
"eact-native-image-pickerios",
|
||||
"$(SRCROOT)..",
|
||||
ode_modules,
|
||||
"eact-native-securerandomios",
|
||||
"$(SRCROOT)..",
|
||||
ode_modules,
|
||||
"eact-native-file-viewerios",
|
||||
);
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MARKETING_VERSION = 10.3.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
|
@ -365,8 +352,8 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin;
|
||||
PRODUCT_NAME = Joplin;
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
|
@ -374,25 +361,15 @@
|
|||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 6CFFC13990302AAE61F81DB1 /* Pods-Joplin.release.xcconfig */;
|
||||
baseConfigurationReference = 14868D674CC065C7BF1C9944 /* Pods-Joplin.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 55;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)..\node_modules\neact-native-image-pickerios",
|
||||
"$(SRCROOT)..\node_modules\neact-native-securerandomios",
|
||||
"$(SRCROOT)..\node_modules\neact-native-file-viewerios",
|
||||
);
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MARKETING_VERSION = 10.3.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
|
@ -401,8 +378,7 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin;
|
||||
PRODUCT_NAME = Joplin;
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
|
@ -412,24 +388,37 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
|
@ -442,7 +431,13 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -453,17 +448,28 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
|
@ -471,13 +477,20 @@
|
|||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOSTests.xctest"
|
||||
BlueprintName = "Joplin-tvOSTests"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -1,25 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
|
||||
BuildableName = "libReact.a"
|
||||
BlueprintName = "React"
|
||||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
|
@ -34,12 +20,16 @@
|
|||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "NO"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
|
@ -47,34 +37,13 @@
|
|||
BlueprintName = "JoplinTests"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Joplin.app"
|
||||
BlueprintName = "Joplin"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -91,8 +60,6 @@
|
|||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
</Workspace>
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <React/RCTBridgeDelegate.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <UserNotifications/UNUserNotificationCenter.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
|
|
|
@ -1,32 +1,82 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "RNQuickActionManager.h"
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
#ifdef FB_SONARKIT_ENABLED
|
||||
#import <FlipperKit/FlipperClient.h>
|
||||
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
|
||||
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
|
||||
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
|
||||
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
|
||||
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
|
||||
#import "RNQuickActionManager.h"
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <RNCPushNotificationIOS.h>
|
||||
|
||||
static void InitializeFlipper(UIApplication *application) {
|
||||
FlipperClient *client = [FlipperClient sharedClient];
|
||||
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
|
||||
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
|
||||
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
|
||||
[client addPlugin:[FlipperKitReactPlugin new]];
|
||||
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
|
||||
[client start];
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
// ===================================================
|
||||
// BEGIN react-native-quick-actions
|
||||
// ===================================================
|
||||
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler {
|
||||
[RNQuickActionManager onQuickActionPress:shortcutItem completionHandler:completionHandler];
|
||||
}
|
||||
// ===================================================
|
||||
// END react-native-quick-actions
|
||||
// ===================================================
|
||||
|
||||
|
||||
|
||||
|
||||
// ===================================================
|
||||
// BEGIN react-native-push-notification-ios
|
||||
// ===================================================
|
||||
|
||||
// IOS 10+ Required for localNotification event
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
||||
didReceiveNotificationResponse:(UNNotificationResponse *)response
|
||||
withCompletionHandler:(void (^)(void))completionHandler
|
||||
{
|
||||
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
|
||||
completionHandler();
|
||||
}
|
||||
// IOS 4-10 Required for the localNotification event.
|
||||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
|
||||
{
|
||||
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
|
||||
}
|
||||
|
||||
// ===================================================
|
||||
// END react-native-push-notification-ios
|
||||
// ===================================================
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
#ifdef FB_SONARKIT_ENABLED
|
||||
InitializeFlipper(application);
|
||||
#endif
|
||||
|
||||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"Joplin"
|
||||
initialProperties:nil];
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"Joplin"
|
||||
initialProperties:nil];
|
||||
|
||||
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
|
||||
|
||||
|
@ -35,49 +85,15 @@
|
|||
rootViewController.view = rootView;
|
||||
self.window.rootViewController = rootViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
// BEGIN react-native-push-notification-ios
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
center.delegate = self;
|
||||
// END react-native-push-notification-ios
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =====================================================
|
||||
// For @react-native-community/push-notification-ios
|
||||
// =====================================================
|
||||
|
||||
// Required to register for notifications
|
||||
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
|
||||
{
|
||||
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
|
||||
}
|
||||
// Required for the register event.
|
||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||
{
|
||||
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
|
||||
}
|
||||
// Required for the notification event. You must call the completion handler after handling the remote notification.
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
||||
{
|
||||
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||
}
|
||||
// Required for the registrationError event.
|
||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
|
||||
{
|
||||
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
|
||||
}
|
||||
// Required for the localNotification event.
|
||||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
|
||||
{
|
||||
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// /For @react-native-community/push-notification-ios
|
||||
// =====================================================
|
||||
|
||||
|
||||
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
#if DEBUG
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Joplin" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
|
@ -47,6 +47,8 @@
|
|||
<string>To add geo-location information to a note. Can be disabled in app.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>To allow attaching images to a note</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>The images will be displayed on your notes.</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
@ -72,5 +74,24 @@
|
|||
<string>Light</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>AntDesign.ttf</string>
|
||||
<string>Entypo.ttf</string>
|
||||
<string>EvilIcons.ttf</string>
|
||||
<string>Feather.ttf</string>
|
||||
<string>FontAwesome.ttf</string>
|
||||
<string>FontAwesome5_Brands.ttf</string>
|
||||
<string>FontAwesome5_Regular.ttf</string>
|
||||
<string>FontAwesome5_Solid.ttf</string>
|
||||
<string>Foundation.ttf</string>
|
||||
<string>Ionicons.ttf</string>
|
||||
<string>MaterialIcons.ttf</string>
|
||||
<string>MaterialCommunityIcons.ttf</string>
|
||||
<string>SimpleLineIcons.ttf</string>
|
||||
<string>Octicons.ttf</string>
|
||||
<string>Zocial.ttf</string>
|
||||
<string>Fontisto.ttf</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.$(CFBundleIdentifier)</string>
|
||||
</array>
|
||||
<key>com.apple.developer.icloud-services</key>
|
||||
<array>
|
||||
<string>CloudDocuments</string>
|
||||
</array>
|
||||
<key>com.apple.developer.ubiquity-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.$(CFBundleIdentifier)</string>
|
||||
</array>
|
||||
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
||||
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
|
||||
<rect key="frame" x="0.0" y="647" width="375" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Joplin" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
|
||||
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
|
||||
<rect key="frame" x="0.0" y="626" width="375" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
|
||||
<constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/>
|
||||
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
|
||||
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="SfN-ll-jLj"/>
|
||||
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
|
||||
<constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/>
|
||||
<constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/>
|
||||
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
|
||||
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="52.173913043478265" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
|
@ -1,12 +1,3 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,65 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
#define TIMEOUT_SECONDS 600
|
||||
#define TEXT_TO_LOOK_FOR @"Welcome to React"
|
||||
|
||||
@interface JoplinTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation JoplinTests
|
||||
|
||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
|
||||
{
|
||||
if (test(view)) {
|
||||
return YES;
|
||||
}
|
||||
for (UIView *subview in [view subviews]) {
|
||||
if ([self findSubviewInView:subview matching:test]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)testRendersWelcomeScreen
|
||||
{
|
||||
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
BOOL foundElement = NO;
|
||||
|
||||
__block NSString *redboxError = nil;
|
||||
#ifdef DEBUG
|
||||
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
|
||||
if (level >= RCTLogLevelError) {
|
||||
redboxError = message;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
|
||||
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
RCTSetLogFunction(RCTDefaultLogFunction);
|
||||
#endif
|
||||
|
||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
|
||||
@end
|
|
@ -1,43 +1,23 @@
|
|||
platform :ios, '9.0'
|
||||
require_relative '../node_modules/react-native/scripts/react_native_pods'
|
||||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||
target 'Joplin' do
|
||||
# Pods for Joplin
|
||||
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
|
||||
pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
|
||||
pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
|
||||
pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
|
||||
pod 'React', :path => '../node_modules/react-native/'
|
||||
pod 'React-Core', :path => '../node_modules/react-native/'
|
||||
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
|
||||
pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
|
||||
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
|
||||
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
|
||||
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
|
||||
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
|
||||
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
|
||||
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
|
||||
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
|
||||
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
|
||||
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
|
||||
pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
|
||||
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
|
||||
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
|
||||
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
|
||||
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
|
||||
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
|
||||
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
|
||||
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
|
||||
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
|
||||
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
|
||||
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
|
||||
pod 'rn-fetch-blob', :path => '../node_modules/rn-fetch-blob'
|
||||
use_native_modules!
|
||||
end
|
||||
|
||||
# target 'Joplin-tvOS' do
|
||||
# # Pods for Joplin-tvOS
|
||||
# target 'Joplin-tvOSTests' do
|
||||
# inherit! :search_paths
|
||||
# # Pods for testing
|
||||
# end
|
||||
# end
|
||||
# Note: it was 13.4 to get @react-native-community/datetimepicker to work
|
||||
# but it's probably not necessary actually. Just needed to upgrade XCode.
|
||||
platform :ios, '10.0'
|
||||
|
||||
target 'Joplin' do
|
||||
config = use_native_modules!
|
||||
|
||||
use_react_native!(:path => config["reactNativePath"])
|
||||
|
||||
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
|
||||
|
||||
# Enables Flipper.
|
||||
#
|
||||
# Note that if you have use_frameworks! enabled, Flipper will not work and
|
||||
# you should disable these next few lines.
|
||||
use_flipper!
|
||||
post_install do |installer|
|
||||
flipper_post_install(installer)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,273 +1,380 @@
|
|||
PODS:
|
||||
- boost-for-react-native (1.63.0)
|
||||
- CocoaAsyncSocket (7.6.4)
|
||||
- CocoaLibEvent (1.0.0)
|
||||
- DoubleConversion (1.1.6)
|
||||
- FBLazyVector (0.61.5)
|
||||
- FBReactNativeSpec (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- RCTRequired (= 0.61.5)
|
||||
- RCTTypeSafety (= 0.61.5)
|
||||
- React-Core (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5)
|
||||
- Folly (2018.10.22.00):
|
||||
- FBLazyVector (0.63.3)
|
||||
- FBReactNativeSpec (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTRequired (= 0.63.3)
|
||||
- RCTTypeSafety (= 0.63.3)
|
||||
- React-Core (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- Flipper (0.54.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- Flipper-RSocket (~> 1.1)
|
||||
- Flipper-DoubleConversion (1.1.7)
|
||||
- Flipper-Folly (2.3.0):
|
||||
- boost-for-react-native
|
||||
- CocoaLibEvent (~> 1.0)
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Glog
|
||||
- OpenSSL-Universal (= 1.0.2.20)
|
||||
- Flipper-Glog (0.3.6)
|
||||
- Flipper-PeerTalk (0.0.4)
|
||||
- Flipper-RSocket (1.1.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- FlipperKit (0.54.0):
|
||||
- FlipperKit/Core (= 0.54.0)
|
||||
- FlipperKit/Core (0.54.0):
|
||||
- Flipper (~> 0.54.0)
|
||||
- FlipperKit/CppBridge
|
||||
- FlipperKit/FBCxxFollyDynamicConvert
|
||||
- FlipperKit/FBDefines
|
||||
- FlipperKit/FKPortForwarding
|
||||
- FlipperKit/CppBridge (0.54.0):
|
||||
- Flipper (~> 0.54.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (0.54.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- FlipperKit/FBDefines (0.54.0)
|
||||
- FlipperKit/FKPortForwarding (0.54.0):
|
||||
- CocoaAsyncSocket (~> 7.6)
|
||||
- Flipper-PeerTalk (~> 0.0.4)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (0.54.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (0.54.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable
|
||||
- YogaKit (~> 1.18)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (0.54.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (0.54.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitReactPlugin (0.54.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/SKIOSNetworkPlugin (0.54.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitNetworkPlugin
|
||||
- Folly (2020.01.13.00):
|
||||
- boost-for-react-native
|
||||
- DoubleConversion
|
||||
- Folly/Default (= 2018.10.22.00)
|
||||
- Folly/Default (= 2020.01.13.00)
|
||||
- glog
|
||||
- Folly/Default (2018.10.22.00):
|
||||
- Folly/Default (2020.01.13.00):
|
||||
- boost-for-react-native
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- RCTRequired (0.61.5)
|
||||
- RCTTypeSafety (0.61.5):
|
||||
- FBLazyVector (= 0.61.5)
|
||||
- Folly (= 2018.10.22.00)
|
||||
- RCTRequired (= 0.61.5)
|
||||
- React-Core (= 0.61.5)
|
||||
- React (0.61.5):
|
||||
- React-Core (= 0.61.5)
|
||||
- React-Core/DevSupport (= 0.61.5)
|
||||
- React-Core/RCTWebSocket (= 0.61.5)
|
||||
- React-RCTActionSheet (= 0.61.5)
|
||||
- React-RCTAnimation (= 0.61.5)
|
||||
- React-RCTBlob (= 0.61.5)
|
||||
- React-RCTImage (= 0.61.5)
|
||||
- React-RCTLinking (= 0.61.5)
|
||||
- React-RCTNetwork (= 0.61.5)
|
||||
- React-RCTSettings (= 0.61.5)
|
||||
- React-RCTText (= 0.61.5)
|
||||
- React-RCTVibration (= 0.61.5)
|
||||
- React-Core (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- OpenSSL-Universal (1.0.2.20):
|
||||
- OpenSSL-Universal/Static (= 1.0.2.20)
|
||||
- OpenSSL-Universal/Static (1.0.2.20)
|
||||
- RCTRequired (0.63.3)
|
||||
- RCTTypeSafety (0.63.3):
|
||||
- FBLazyVector (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTRequired (= 0.63.3)
|
||||
- React-Core (= 0.63.3)
|
||||
- React (0.63.3):
|
||||
- React-Core (= 0.63.3)
|
||||
- React-Core/DevSupport (= 0.63.3)
|
||||
- React-Core/RCTWebSocket (= 0.63.3)
|
||||
- React-RCTActionSheet (= 0.63.3)
|
||||
- React-RCTAnimation (= 0.63.3)
|
||||
- React-RCTBlob (= 0.63.3)
|
||||
- React-RCTImage (= 0.63.3)
|
||||
- React-RCTLinking (= 0.63.3)
|
||||
- React-RCTNetwork (= 0.63.3)
|
||||
- React-RCTSettings (= 0.63.3)
|
||||
- React-RCTText (= 0.63.3)
|
||||
- React-RCTVibration (= 0.63.3)
|
||||
- React-callinvoker (0.63.3)
|
||||
- React-Core (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default (= 0.61.5)
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-Core/Default (= 0.63.3)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/CoreModulesHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/Default (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/Default (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/DevSupport (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default (= 0.61.5)
|
||||
- React-Core/RCTWebSocket (= 0.61.5)
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-jsinspector (= 0.61.5)
|
||||
- React-Core/Default (= 0.63.3)
|
||||
- React-Core/RCTWebSocket (= 0.63.3)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- React-jsinspector (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTActionSheetHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTAnimationHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTBlobHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTImageHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTLinkingHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTNetworkHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTSettingsHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTTextHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTVibrationHeaders (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.61.5):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- React-Core/RCTWebSocket (0.63.3):
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-Core/Default (= 0.61.5)
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsiexecutor (= 0.61.5)
|
||||
- React-Core/Default (= 0.63.3)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsiexecutor (= 0.63.3)
|
||||
- Yoga
|
||||
- React-CoreModules (0.61.5):
|
||||
- FBReactNativeSpec (= 0.61.5)
|
||||
- Folly (= 2018.10.22.00)
|
||||
- RCTTypeSafety (= 0.61.5)
|
||||
- React-Core/CoreModulesHeaders (= 0.61.5)
|
||||
- React-RCTImage (= 0.61.5)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5)
|
||||
- React-cxxreact (0.61.5):
|
||||
- React-CoreModules (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTTypeSafety (= 0.63.3)
|
||||
- React-Core/CoreModulesHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-RCTImage (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-cxxreact (0.63.3):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-jsinspector (= 0.61.5)
|
||||
- React-jsi (0.61.5):
|
||||
- React-callinvoker (= 0.63.3)
|
||||
- React-jsinspector (= 0.63.3)
|
||||
- React-jsi (0.63.3):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-jsi/Default (= 0.61.5)
|
||||
- React-jsi/Default (0.61.5):
|
||||
- React-jsi/Default (= 0.63.3)
|
||||
- React-jsi/Default (0.63.3):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-jsiexecutor (0.61.5):
|
||||
- React-jsiexecutor (0.63.3):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-jsinspector (0.61.5)
|
||||
- react-native-camera (2.10.2):
|
||||
- React
|
||||
- react-native-camera/RCT (= 2.10.2)
|
||||
- react-native-camera/RN (= 2.10.2)
|
||||
- react-native-camera/RCT (2.10.2):
|
||||
- React
|
||||
- react-native-camera/RN (2.10.2):
|
||||
- React
|
||||
- react-native-document-picker (2.3.0):
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-jsinspector (0.63.3)
|
||||
- react-native-alarm-notification (1.7.1):
|
||||
- React
|
||||
- react-native-camera (3.40.0):
|
||||
- React-Core
|
||||
- react-native-camera/RCT (= 3.40.0)
|
||||
- react-native-camera/RN (= 3.40.0)
|
||||
- react-native-camera/RCT (3.40.0):
|
||||
- React-Core
|
||||
- react-native-camera/RN (3.40.0):
|
||||
- React-Core
|
||||
- react-native-document-picker (4.0.0):
|
||||
- React-Core
|
||||
- react-native-geolocation (2.0.2):
|
||||
- React
|
||||
- react-native-image-picker (0.14.3):
|
||||
- react-native-image-picker (2.3.4):
|
||||
- React-Core
|
||||
- react-native-image-resizer (1.3.0):
|
||||
- React-Core
|
||||
- react-native-slider (3.0.3):
|
||||
- React
|
||||
- react-native-image-resizer (1.0.0):
|
||||
- react-native-sqlite-storage (5.0.0):
|
||||
- React
|
||||
- react-native-slider (2.0.8):
|
||||
- React
|
||||
- react-native-sqlite-storage (4.1.0):
|
||||
- React
|
||||
- react-native-version-info (1.0.1):
|
||||
- React
|
||||
- react-native-webview (5.12.0):
|
||||
- React
|
||||
- React-RCTActionSheet (0.61.5):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.61.5)
|
||||
- React-RCTAnimation (0.61.5):
|
||||
- React-Core/RCTAnimationHeaders (= 0.61.5)
|
||||
- React-RCTBlob (0.61.5):
|
||||
- React-Core/RCTBlobHeaders (= 0.61.5)
|
||||
- React-Core/RCTWebSocket (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- React-RCTNetwork (= 0.61.5)
|
||||
- React-RCTImage (0.61.5):
|
||||
- React-Core/RCTImageHeaders (= 0.61.5)
|
||||
- React-RCTNetwork (= 0.61.5)
|
||||
- React-RCTLinking (0.61.5):
|
||||
- React-Core/RCTLinkingHeaders (= 0.61.5)
|
||||
- React-RCTNetwork (0.61.5):
|
||||
- React-Core/RCTNetworkHeaders (= 0.61.5)
|
||||
- React-RCTSettings (0.61.5):
|
||||
- React-Core/RCTSettingsHeaders (= 0.61.5)
|
||||
- React-RCTText (0.61.5):
|
||||
- React-Core/RCTTextHeaders (= 0.61.5)
|
||||
- React-RCTVibration (0.61.5):
|
||||
- React-Core/RCTVibrationHeaders (= 0.61.5)
|
||||
- ReactCommon/jscallinvoker (0.61.5):
|
||||
- react-native-version-info (1.1.0):
|
||||
- React-Core
|
||||
- react-native-webview (10.9.2):
|
||||
- React-Core
|
||||
- React-RCTActionSheet (0.63.3):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.63.3)
|
||||
- React-RCTAnimation (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTTypeSafety (= 0.63.3)
|
||||
- React-Core/RCTAnimationHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-RCTBlob (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- React-Core/RCTBlobHeaders (= 0.63.3)
|
||||
- React-Core/RCTWebSocket (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-RCTNetwork (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-RCTImage (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTTypeSafety (= 0.63.3)
|
||||
- React-Core/RCTImageHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- React-RCTNetwork (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-RCTLinking (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- React-Core/RCTLinkingHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-RCTNetwork (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTTypeSafety (= 0.63.3)
|
||||
- React-Core/RCTNetworkHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-RCTSettings (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- RCTTypeSafety (= 0.63.3)
|
||||
- React-Core/RCTSettingsHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- React-RCTText (0.63.3):
|
||||
- React-Core/RCTTextHeaders (= 0.63.3)
|
||||
- React-RCTVibration (0.63.3):
|
||||
- FBReactNativeSpec (= 0.63.3)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- React-Core/RCTVibrationHeaders (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (= 0.63.3)
|
||||
- ReactCommon/turbomodule/core (0.63.3):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- Folly (= 2020.01.13.00)
|
||||
- glog
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- ReactCommon/turbomodule/core (0.61.5):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core (= 0.61.5)
|
||||
- React-cxxreact (= 0.61.5)
|
||||
- React-jsi (= 0.61.5)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5)
|
||||
- React-callinvoker (= 0.63.3)
|
||||
- React-Core (= 0.63.3)
|
||||
- React-cxxreact (= 0.63.3)
|
||||
- React-jsi (= 0.63.3)
|
||||
- rn-fetch-blob (0.12.0):
|
||||
- React-Core
|
||||
- RNCPushNotificationIOS (1.0.5):
|
||||
- React
|
||||
- RNDeviceInfo (5.5.1):
|
||||
- React
|
||||
- RNFileViewer (1.0.1):
|
||||
- React
|
||||
- RNFS (2.11.17):
|
||||
- RNCClipboard (1.5.0):
|
||||
- React-Core
|
||||
- RNCPushNotificationIOS (1.6.0):
|
||||
- React-Core
|
||||
- RNDateTimePicker (3.0.3):
|
||||
- React-Core
|
||||
- RNFileViewer (2.1.4):
|
||||
- React-Core
|
||||
- RNFS (2.16.6):
|
||||
- React
|
||||
- RNQuickAction (0.3.13):
|
||||
- React
|
||||
- RNSecureRandom (1.0.0-rc.0):
|
||||
- React
|
||||
- RNVectorIcons (6.6.0):
|
||||
- RNShare (4.0.2):
|
||||
- React-Core
|
||||
- RNVectorIcons (7.1.0):
|
||||
- React
|
||||
- Yoga (1.14.0)
|
||||
- YogaKit (1.18.1):
|
||||
- Yoga (~> 1.14)
|
||||
|
||||
DEPENDENCIES:
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
|
||||
- Flipper (~> 0.54.0)
|
||||
- Flipper-DoubleConversion (= 1.1.7)
|
||||
- Flipper-Folly (~> 2.2)
|
||||
- Flipper-Glog (= 0.3.6)
|
||||
- Flipper-PeerTalk (~> 0.0.4)
|
||||
- Flipper-RSocket (~> 1.1)
|
||||
- FlipperKit (~> 0.54.0)
|
||||
- FlipperKit/Core (~> 0.54.0)
|
||||
- FlipperKit/CppBridge (~> 0.54.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0)
|
||||
- FlipperKit/FBDefines (~> 0.54.0)
|
||||
- FlipperKit/FKPortForwarding (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitReactPlugin (~> 0.54.0)
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0)
|
||||
- FlipperKit/SKIOSNetworkPlugin (~> 0.54.0)
|
||||
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
||||
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
|
||||
- React (from `../node_modules/react-native/`)
|
||||
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
|
||||
- React-Core (from `../node_modules/react-native/`)
|
||||
- React-Core/DevSupport (from `../node_modules/react-native/`)
|
||||
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
|
||||
|
@ -276,6 +383,7 @@ DEPENDENCIES:
|
|||
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
|
||||
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- react-native-alarm-notification (from `../node_modules/react-native-alarm-notification`)
|
||||
- react-native-camera (from `../node_modules/react-native-camera`)
|
||||
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
|
||||
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
|
||||
|
@ -294,21 +402,33 @@ DEPENDENCIES:
|
|||
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
|
||||
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
|
||||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||
- ReactCommon/jscallinvoker (from `../node_modules/react-native/ReactCommon`)
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
|
||||
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
|
||||
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
|
||||
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
|
||||
- RNFileViewer (from `../node_modules/react-native-file-viewer/ios`)
|
||||
- "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)"
|
||||
- RNFileViewer (from `../node_modules/react-native-file-viewer`)
|
||||
- RNFS (from `../node_modules/react-native-fs`)
|
||||
- RNQuickAction (from `../node_modules/react-native-quick-actions`)
|
||||
- RNSecureRandom (from `../node_modules/react-native-securerandom`)
|
||||
- RNShare (from `../node_modules/react-native-share`)
|
||||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- boost-for-react-native
|
||||
- CocoaAsyncSocket
|
||||
- CocoaLibEvent
|
||||
- Flipper
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Folly
|
||||
- Flipper-Glog
|
||||
- Flipper-PeerTalk
|
||||
- Flipper-RSocket
|
||||
- FlipperKit
|
||||
- OpenSSL-Universal
|
||||
- YogaKit
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
DoubleConversion:
|
||||
|
@ -327,6 +447,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native/Libraries/TypeSafety"
|
||||
React:
|
||||
:path: "../node_modules/react-native/"
|
||||
React-callinvoker:
|
||||
:path: "../node_modules/react-native/ReactCommon/callinvoker"
|
||||
React-Core:
|
||||
:path: "../node_modules/react-native/"
|
||||
React-CoreModules:
|
||||
|
@ -339,6 +461,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
|
||||
React-jsinspector:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsinspector"
|
||||
react-native-alarm-notification:
|
||||
:path: "../node_modules/react-native-alarm-notification"
|
||||
react-native-camera:
|
||||
:path: "../node_modules/react-native-camera"
|
||||
react-native-document-picker:
|
||||
|
@ -379,18 +503,22 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native/ReactCommon"
|
||||
rn-fetch-blob:
|
||||
:path: "../node_modules/rn-fetch-blob"
|
||||
RNCClipboard:
|
||||
:path: "../node_modules/@react-native-community/clipboard"
|
||||
RNCPushNotificationIOS:
|
||||
:path: "../node_modules/@react-native-community/push-notification-ios"
|
||||
RNDeviceInfo:
|
||||
:path: "../node_modules/react-native-device-info"
|
||||
RNDateTimePicker:
|
||||
:path: "../node_modules/@react-native-community/datetimepicker"
|
||||
RNFileViewer:
|
||||
:path: "../node_modules/react-native-file-viewer/ios"
|
||||
:path: "../node_modules/react-native-file-viewer"
|
||||
RNFS:
|
||||
:path: "../node_modules/react-native-fs"
|
||||
RNQuickAction:
|
||||
:path: "../node_modules/react-native-quick-actions"
|
||||
RNSecureRandom:
|
||||
:path: "../node_modules/react-native-securerandom"
|
||||
RNShare:
|
||||
:path: "../node_modules/react-native-share"
|
||||
RNVectorIcons:
|
||||
:path: "../node_modules/react-native-vector-icons"
|
||||
Yoga:
|
||||
|
@ -398,49 +526,64 @@ EXTERNAL SOURCES:
|
|||
|
||||
SPEC CHECKSUMS:
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
|
||||
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
|
||||
DoubleConversion: cde416483dac037923206447da6e1454df403714
|
||||
FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f
|
||||
FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d
|
||||
FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f
|
||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||
Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a
|
||||
Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
|
||||
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
|
||||
Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
|
||||
FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
||||
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
||||
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
||||
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
||||
React-Core: 688b451f7d616cc1134ac95295b593d1b5158a04
|
||||
React-CoreModules: d04f8494c1a328b69ec11db9d1137d667f916dcb
|
||||
React-cxxreact: d0f7bcafa196ae410e5300736b424455e7fb7ba7
|
||||
React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7
|
||||
React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386
|
||||
React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0
|
||||
react-native-camera: ea85f74cf2e501d2a91a3da7092ecdac082f18df
|
||||
react-native-document-picker: 8508bfda34be6c24a2cbecbe515b15108658c183
|
||||
OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd
|
||||
RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047
|
||||
RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab
|
||||
React: f36e90f3ceb976546e97df3403e37d226f79d0e3
|
||||
React-callinvoker: 18874f621eb96625df7a24a7dc8d6e07391affcd
|
||||
React-Core: ac3d816b8e3493970153f4aaf0cff18af0bb95e6
|
||||
React-CoreModules: 4016d3a4e518bcfc4f5a51252b5a05692ca6f0e1
|
||||
React-cxxreact: ffc9129013b87cb36cf3f30a86695a3c397b0f99
|
||||
React-jsi: df07aa95b39c5be3e41199921509bfa929ed2b9d
|
||||
React-jsiexecutor: b56c03e61c0dd5f5801255f2160a815f4a53d451
|
||||
React-jsinspector: 8e68ffbfe23880d3ee9bafa8be2777f60b25cbe2
|
||||
react-native-alarm-notification: 8f2adb4521bf7ca867278d4c236553e154dbbbc6
|
||||
react-native-camera: 5c1fbfecf63b802b8ca4a71c60d30a71550fb348
|
||||
react-native-document-picker: b3e78a8f7fef98b5cb069f20fc35797d55e68e28
|
||||
react-native-geolocation: cbd9d6bd06bac411eed2671810f454d4908484a8
|
||||
react-native-image-picker: 3693786b3d5958c8f71deed66ec068b323565e0d
|
||||
react-native-image-resizer: aa1600566fd336a044daf9273dcec5033c1d41ca
|
||||
react-native-slider: b2f361499888302147205f17f6fffa921a7bda70
|
||||
react-native-sqlite-storage: bb10beb2407e5fc21f3f1bcd86bacbfd6edcc818
|
||||
react-native-version-info: daadd78b8fc93cf2764cb5aa52ec995961b62201
|
||||
react-native-webview: 26d8993b090ca5d59eb9a9466dcb8291baa3223e
|
||||
React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76
|
||||
React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360
|
||||
React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72
|
||||
React-RCTImage: 6b8e8df449eb7c814c99a92d6b52de6fe39dea4e
|
||||
React-RCTLinking: 121bb231c7503cf9094f4d8461b96a130fabf4a5
|
||||
React-RCTNetwork: fb353640aafcee84ca8b78957297bd395f065c9a
|
||||
React-RCTSettings: 8db258ea2a5efee381fcf7a6d5044e2f8b68b640
|
||||
React-RCTText: 9ccc88273e9a3aacff5094d2175a605efa854dbe
|
||||
React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
|
||||
ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
|
||||
react-native-image-picker: 32d1ad2c0024ca36161ae0d5c2117e2d6c441f11
|
||||
react-native-image-resizer: b53bf95ad880100e20262687e41f76fdbc9df255
|
||||
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
|
||||
react-native-sqlite-storage: ce71689c5a73b79390a1ab213555ae80979a5dc7
|
||||
react-native-version-info: 64f0f0bf3da6316298f9cd6085d50ba3a992d0c7
|
||||
react-native-webview: c51f73be304c61d359ec3e7c5e4e8f2c977fd360
|
||||
React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa
|
||||
React-RCTAnimation: 1befece0b5183c22ae01b966f5583f42e69a83c2
|
||||
React-RCTBlob: 0b284339cbe4b15705a05e2313a51c6d8b51fa40
|
||||
React-RCTImage: d1756599ebd4dc2cb19d1682fe67c6b976658387
|
||||
React-RCTLinking: 9af0a51c6d6a4dd1674daadafffc6d03033a6d18
|
||||
React-RCTNetwork: 332c83929cc5eae0b3bbca4add1d668e1fc18bda
|
||||
React-RCTSettings: d6953772cfd55f2c68ad72b7ef29efc7ec49f773
|
||||
React-RCTText: 65a6de06a7389098ce24340d1d3556015c38f746
|
||||
React-RCTVibration: 8e9fb25724a0805107fc1acc9075e26f814df454
|
||||
ReactCommon: 4167844018c9ed375cc01a843e9ee564399e53c3
|
||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||
RNCPushNotificationIOS: 30ed75aa2981a4ee00b8a2c46599ff18a9c7fcf6
|
||||
RNDeviceInfo: 6812ed7e578d4344bf4e77102f014b5adf0b5c28
|
||||
RNFileViewer: 5047ecf40477339723cc08abd55b5ebcefcef4b5
|
||||
RNFS: 416676c3a9ae404454bade10e3d78147c7c33a40
|
||||
RNCClipboard: 8f9f12fabf3c06e976f19f87a62c89e28dfedfca
|
||||
RNCPushNotificationIOS: 20c4403b2ef8732297ea81e22f66c41bed7aaedf
|
||||
RNDateTimePicker: e9fcd5ecdc0c5b018871e0d178d6040dca11973c
|
||||
RNFileViewer: 83cc066ad795b1f986791d03b56fe0ee14b6a69f
|
||||
RNFS: 2bd9eb49dc82fa9676382f0585b992c424cd59df
|
||||
RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93
|
||||
RNSecureRandom: 1f19ad1492f7ed416b8fc79e92216a1f73f13a4c
|
||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||
Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b
|
||||
RNShare: 7a7277f3c313652422d9de072ac50714dff5e8a4
|
||||
RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59
|
||||
Yoga: 7d13633d129fd179e01b8953d38d47be90db185a
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: c8797581a23c0ae9c6a4f471c2b19dda3644a8b2
|
||||
PODFILE CHECKSUM: a0d1ca4e385ef46f9103f02206ebf612107dd508
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
|
|
@ -698,6 +698,7 @@ export default class BaseApplication {
|
|||
initArgs = Object.assign(initArgs, extraFlags);
|
||||
|
||||
this.logger_.addTarget(TargetType.File, { path: `${profileDir}/log.txt` });
|
||||
// this.logger_.addTarget(TargetType.Console, { level: Logger.LEVEL_DEBUG });
|
||||
this.logger_.setLevel(initArgs.logLevel);
|
||||
|
||||
reg.setLogger(this.logger_);
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// There are plenty of packages for in-memory caching but each have their
|
||||
// own gotchas and often have extra complexity which makes it work in one
|
||||
// platform but not in another (for example, the use of long timeouts would
|
||||
// be fine in Node but not in React Native).
|
||||
//
|
||||
// So this class implements a simple in-memory cache with support for TTL.
|
||||
// Checking for expired keys is a bit inefficient since it doesn't rely on
|
||||
// timers, so it's checking every time a value is set or retrieved. But it
|
||||
// should be fine in most cases, as long as the class is not used at a massive
|
||||
// scale.
|
||||
|
||||
interface Record {
|
||||
value: any,
|
||||
expiredTime: number,
|
||||
}
|
||||
|
||||
interface Records {
|
||||
[key:string]: Record;
|
||||
}
|
||||
|
||||
interface ExpirableKeys {
|
||||
[key:string]: boolean,
|
||||
}
|
||||
|
||||
export default class Cache {
|
||||
|
||||
private maxRecords_:number;
|
||||
private records_:Records = {};
|
||||
private expirableKeys_:ExpirableKeys = {};
|
||||
private recordKeyHistory_:string[] = [];
|
||||
|
||||
constructor(maxRecords:number = 50) {
|
||||
this.maxRecords_ = maxRecords;
|
||||
}
|
||||
|
||||
private checkExpiredRecords() {
|
||||
const now = Date.now();
|
||||
|
||||
for (const key in this.expirableKeys_) {
|
||||
if (!this.records_[key]) {
|
||||
delete this.expirableKeys_[key];
|
||||
} else {
|
||||
if (this.records_[key].expiredTime <= now) {
|
||||
delete this.records_[key];
|
||||
delete this.expirableKeys_[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (this.recordKeyHistory_.length > this.maxRecords_) {
|
||||
const key = this.recordKeyHistory_[0];
|
||||
delete this.records_[key];
|
||||
delete this.expirableKeys_[key];
|
||||
this.recordKeyHistory_.splice(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public value(key:string, defaultValue:any = undefined):any {
|
||||
this.checkExpiredRecords();
|
||||
if (key in this.records_) return this.records_[key].value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public setValue(key:string, value:any, ttl:number = 0) {
|
||||
this.checkExpiredRecords();
|
||||
|
||||
this.records_[key] = {
|
||||
value: value,
|
||||
expiredTime: ttl ? Date.now() + ttl : 0,
|
||||
};
|
||||
|
||||
const idx = this.recordKeyHistory_.indexOf(key);
|
||||
if (idx >= 0) this.recordKeyHistory_.splice(idx, 1);
|
||||
this.recordKeyHistory_.push(key);
|
||||
|
||||
if (ttl) {
|
||||
this.expirableKeys_[key] = true;
|
||||
} else {
|
||||
delete this.expirableKeys_[key];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
// On mobile all the setTimeout and setInterval should go through this class
|
||||
// as it will either use the native timeout/interval for short intervals or
|
||||
// the custom one for long intervals.
|
||||
|
||||
// For custom intervals, they are triggered
|
||||
// whenever the update() function is called, and in mobile it's called for
|
||||
// example on the Redux action middleware or when the app gets focus.
|
||||
|
||||
const { time } = require('lib/time-utils.js');
|
||||
|
||||
type IntervalId = number;
|
||||
|
||||
interface Interval {
|
||||
id: IntervalId,
|
||||
callback: Function,
|
||||
interval: number,
|
||||
lastIntervalTime: number,
|
||||
isTimeout: boolean,
|
||||
}
|
||||
|
||||
interface Intervals {
|
||||
[key: number]: Interval;
|
||||
}
|
||||
|
||||
export default class PoorManIntervals {
|
||||
|
||||
private static maxNativeTimerDuration_ = 10 * 1000;
|
||||
private static lastUpdateTime_:number = 0;
|
||||
private static intervalId_:IntervalId = 0;
|
||||
private static intervals_:Intervals = {};
|
||||
|
||||
public static setInterval(callback:Function, interval:number):IntervalId {
|
||||
if (interval <= this.maxNativeTimerDuration_) return setInterval(callback, interval);
|
||||
|
||||
this.intervalId_++;
|
||||
const id = this.intervalId_;
|
||||
|
||||
this.intervals_[id] = {
|
||||
id: id,
|
||||
callback: callback,
|
||||
interval: interval,
|
||||
lastIntervalTime: time.unixMs(),
|
||||
isTimeout: false,
|
||||
};
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public static setTimeout(callback:Function, interval:number):IntervalId {
|
||||
if (interval <= this.maxNativeTimerDuration_) return setTimeout(callback, interval);
|
||||
|
||||
this.intervalId_++;
|
||||
const id = this.intervalId_;
|
||||
|
||||
this.intervals_[id] = {
|
||||
id: id,
|
||||
callback: callback,
|
||||
interval: interval,
|
||||
lastIntervalTime: time.unixMs(),
|
||||
isTimeout: true,
|
||||
};
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public static clearInterval(id:IntervalId) {
|
||||
const r = this.intervals_[id];
|
||||
if (!r) {
|
||||
clearInterval(id);
|
||||
} else {
|
||||
delete this.intervals_[id];
|
||||
}
|
||||
}
|
||||
|
||||
public static clearTimeout(id:IntervalId) {
|
||||
const r = this.intervals_[id];
|
||||
if (!r) {
|
||||
clearTimeout(id);
|
||||
} else {
|
||||
delete this.intervals_[id];
|
||||
}
|
||||
}
|
||||
|
||||
public static update() {
|
||||
// Don't update more than once a second
|
||||
if (this.lastUpdateTime_ + 1000 > time.unixMs()) return;
|
||||
|
||||
for (const id in this.intervals_) {
|
||||
const interval = this.intervals_[id];
|
||||
const now = time.unixMs();
|
||||
if (now - interval.lastIntervalTime >= interval.interval) {
|
||||
interval.lastIntervalTime = now;
|
||||
interval.callback();
|
||||
if (interval.isTimeout) {
|
||||
this.clearTimeout(interval.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.lastUpdateTime_ = time.unixMs();
|
||||
}
|
||||
}
|
|
@ -335,8 +335,9 @@ class WebDavApi {
|
|||
// </d:propfind>'
|
||||
|
||||
async exec(method, path = '', body = null, headers = null, options = null) {
|
||||
if (headers === null) headers = {};
|
||||
if (options === null) options = {};
|
||||
headers = Object.assign({}, headers);
|
||||
options = Object.assign({}, options);
|
||||
|
||||
if (!options.responseFormat) options.responseFormat = 'json';
|
||||
if (!options.target) options.target = 'string';
|
||||
|
||||
|
@ -344,6 +345,13 @@ class WebDavApi {
|
|||
|
||||
if (authToken) headers['Authorization'] = `Basic ${authToken}`;
|
||||
|
||||
// That should not be needed, but it is required for React Native 0.63+
|
||||
// https://github.com/facebook/react-native/issues/30176
|
||||
if (!headers['Content-Type']) {
|
||||
if (method === 'PROPFIND') headers['Content-Type'] = 'text/xml';
|
||||
if (method === 'PUT') headers['Content-Type'] = 'text/plain';
|
||||
}
|
||||
|
||||
// On iOS, the network lib appends a If-None-Match header to PROPFIND calls, which is kind of correct because
|
||||
// the call is idempotent and thus could be cached. According to RFC-7232 though only GET and HEAD should have
|
||||
// this header for caching purposes. It makes no mention of PROPFIND.
|
||||
|
@ -365,7 +373,6 @@ class WebDavApi {
|
|||
|
||||
if (shim.httpAgent(url)) fetchOptions.agent = shim.httpAgent(url);
|
||||
|
||||
|
||||
let response = null;
|
||||
|
||||
// console.info('WebDAV Call', `${method} ${url}`, headers, options);
|
||||
|
|
|
@ -3,7 +3,7 @@ const { Platform, PermissionsAndroid } = require('react-native');
|
|||
type rationale = {
|
||||
title: string,
|
||||
message: string,
|
||||
buttonPositive: string,
|
||||
buttonPositive?: string,
|
||||
buttonNegative?: string
|
||||
buttonNeutral?: string
|
||||
}
|
||||
|
@ -15,5 +15,5 @@ export default async (permissions: string, rationale?: rationale) => {
|
|||
if (result !== PermissionsAndroid.RESULTS.GRANTED) {
|
||||
result = await PermissionsAndroid.request(permissions, rationale);
|
||||
}
|
||||
return result === PermissionsAndroid.RESULTS.GRANTED;
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { RNCamera } from 'react-native-camera';
|
||||
const { RNCamera } = require('react-native-camera');
|
||||
const React = require('react');
|
||||
const Component = React.Component;
|
||||
const { connect } = require('react-redux');
|
||||
|
@ -31,7 +31,7 @@ class CameraView extends Component {
|
|||
this.onLayout = this.onLayout.bind(this);
|
||||
}
|
||||
|
||||
onLayout(event) {
|
||||
onLayout(event:any) {
|
||||
this.setState({
|
||||
screenWidth: event.nativeEvent.layout.width,
|
||||
screenHeight: event.nativeEvent.layout.height,
|
||||
|
@ -70,23 +70,26 @@ class CameraView extends Component {
|
|||
fixOrientation: true,
|
||||
});
|
||||
|
||||
this.setState({ snapping: false });
|
||||
|
||||
if (this.props.onPhoto) this.props.onPhoto(result);
|
||||
|
||||
this.setState({ snapping: false });
|
||||
}
|
||||
|
||||
async onCameraReady() {
|
||||
const ratios = await this.camera.getSupportedRatiosAsync();
|
||||
this.setState({ ratios: ratios });
|
||||
if (this.supportsRatios()) {
|
||||
const ratios = await this.camera.getSupportedRatiosAsync();
|
||||
this.setState({ ratios: ratios });
|
||||
}
|
||||
}
|
||||
|
||||
renderButton(onPress, iconName, style) {
|
||||
renderButton(onPress:Function, iconNameOrIcon:any, style:any) {
|
||||
let icon = null;
|
||||
|
||||
if (typeof iconName === 'string') {
|
||||
if (typeof iconNameOrIcon === 'string') {
|
||||
icon = (
|
||||
<Icon
|
||||
name={iconName}
|
||||
name={iconNameOrIcon}
|
||||
style={{
|
||||
fontSize: 40,
|
||||
color: 'black',
|
||||
|
@ -94,7 +97,7 @@ class CameraView extends Component {
|
|||
/>
|
||||
);
|
||||
} else {
|
||||
icon = iconName;
|
||||
icon = iconNameOrIcon;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -106,11 +109,11 @@ class CameraView extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
fitRectIntoBounds(rect, bounds) {
|
||||
fitRectIntoBounds(rect:any, bounds:any) {
|
||||
const rectRatio = rect.width / rect.height;
|
||||
const boundsRatio = bounds.width / bounds.height;
|
||||
|
||||
const newDimensions = {};
|
||||
const newDimensions:any = {};
|
||||
|
||||
// Rect is more landscape than bounds - fit to width
|
||||
if (rectRatio > boundsRatio) {
|
||||
|
@ -124,7 +127,7 @@ class CameraView extends Component {
|
|||
return newDimensions;
|
||||
}
|
||||
|
||||
cameraRect(ratio) {
|
||||
cameraRect(ratio:string) {
|
||||
// To keep the calculations simpler, it's assumed that the phone is in
|
||||
// portrait orientation. Then at the end we swap the values if needed.
|
||||
const splitted = ratio.split(':');
|
||||
|
@ -146,16 +149,21 @@ class CameraView extends Component {
|
|||
return output;
|
||||
}
|
||||
|
||||
supportsRatios() {
|
||||
return shim.mobilePlatform() === 'android';
|
||||
}
|
||||
|
||||
render() {
|
||||
const photoIcon = this.state.snapping ? 'md-checkmark' : 'md-camera';
|
||||
|
||||
const displayRatios = shim.mobilePlatform() === 'android' && this.state.ratios.length > 1;
|
||||
const displayRatios = this.supportsRatios() && this.state.ratios.length > 1;
|
||||
|
||||
const reverseCameraButton = this.renderButton(this.reverse_onPress, 'md-reverse-camera', { flex: 1, flexDirection: 'row', justifyContent: 'flex-start', marginLeft: 20 });
|
||||
const reverseCameraButton = this.renderButton(this.reverse_onPress, 'md-camera-reverse', { flex: 1, flexDirection: 'row', justifyContent: 'flex-start', marginLeft: 20 });
|
||||
const ratioButton = !displayRatios ? <View style={{ flex: 1 }}/> : this.renderButton(this.ratio_onPress, <Text style={{ fontWeight: 'bold', fontSize: 20 }}>{Setting.value('camera.ratio')}</Text>, { flex: 1, flexDirection: 'row', justifyContent: 'flex-end', marginRight: 20 });
|
||||
|
||||
let cameraRatio = '4:3';
|
||||
const cameraProps = {};
|
||||
const cameraProps:any = {};
|
||||
|
||||
if (displayRatios) {
|
||||
cameraProps.ratio = this.props.cameraRatio;
|
||||
cameraRatio = this.props.cameraRatio;
|
||||
|
@ -170,7 +178,7 @@ class CameraView extends Component {
|
|||
<View style={{ position: 'absolute', backgroundColor: '#000000', width: '100%', height: '100%' }}/>
|
||||
<RNCamera
|
||||
style={Object.assign({ position: 'absolute' }, cameraRect)}
|
||||
ref={ref => {
|
||||
ref={(ref:any) => {
|
||||
this.camera = ref;
|
||||
}}
|
||||
type={this.props.cameraType}
|
||||
|
@ -223,7 +231,7 @@ class CameraView extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state:any) => {
|
||||
return {
|
||||
cameraRatio: state.settings['camera.ratio'],
|
||||
cameraType: state.settings['camera.type'],
|
||||
|
@ -231,4 +239,4 @@ const mapStateToProps = state => {
|
|||
};
|
||||
|
||||
|
||||
module.exports = connect(mapStateToProps)(CameraView);
|
||||
export default connect(mapStateToProps)(CameraView);
|
|
@ -0,0 +1,111 @@
|
|||
import { useRef, useMemo, useCallback } from 'react';
|
||||
|
||||
import Setting from 'lib/models/Setting';
|
||||
import useSource from './hooks/useSource';
|
||||
import useOnMessage from './hooks/useOnMessage';
|
||||
import useOnResourceLongPress from './hooks/useOnResourceLongPress';
|
||||
|
||||
const React = require('react');
|
||||
const { View } = require('react-native');
|
||||
const { WebView } = require('react-native-webview');
|
||||
const { themeStyle } = require('lib/components/global-style.js');
|
||||
const BackButtonDialogBox = require('lib/components/BackButtonDialogBox').default;
|
||||
const { reg } = require('lib/registry.js');
|
||||
|
||||
interface Props {
|
||||
themeId: number,
|
||||
style: any,
|
||||
noteBody: string,
|
||||
noteMarkupLanguage: number,
|
||||
highlightedKeywords: string[],
|
||||
noteResources: any,
|
||||
paddingBottom: number,
|
||||
noteHash: string,
|
||||
onJoplinLinkClick: Function,
|
||||
onCheckboxChange?: Function,
|
||||
onMarkForDownload?: Function,
|
||||
onLoadEnd?: Function,
|
||||
}
|
||||
|
||||
export default function NoteBodyViewer(props:Props) {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
const webViewStyle:any = useMemo(() => {
|
||||
return { backgroundColor: theme.backgroundColor };
|
||||
}, [theme.backgroundColor]);
|
||||
|
||||
const dialogBoxRef = useRef(null);
|
||||
|
||||
const { source, injectedJs } = useSource(
|
||||
props.noteBody,
|
||||
props.noteMarkupLanguage,
|
||||
props.themeId,
|
||||
props.highlightedKeywords,
|
||||
props.noteResources,
|
||||
props.paddingBottom,
|
||||
props.noteHash
|
||||
);
|
||||
|
||||
const onResourceLongPress = useOnResourceLongPress(
|
||||
props.onJoplinLinkClick,
|
||||
dialogBoxRef
|
||||
);
|
||||
|
||||
const onMessage = useOnMessage(
|
||||
props.onCheckboxChange,
|
||||
props.noteBody,
|
||||
props.onMarkForDownload,
|
||||
props.onJoplinLinkClick,
|
||||
onResourceLongPress
|
||||
);
|
||||
|
||||
const onLoadEnd = useCallback(() => {
|
||||
if (props.onLoadEnd) props.onLoadEnd();
|
||||
}, [props.onLoadEnd]);
|
||||
|
||||
function onError() {
|
||||
reg.logger().error('WebView error');
|
||||
}
|
||||
|
||||
// On iOS scalesPageToFit work like this:
|
||||
//
|
||||
// Find the widest image, resize it *and everything else* by x% so that
|
||||
// the image fits within the viewport. The problem is that it means if there's
|
||||
// a large image, everything is going to be scaled to a very small size, making
|
||||
// the text unreadable.
|
||||
//
|
||||
// On Android:
|
||||
//
|
||||
// Find the widest elements and scale them (and them only) to fit within the viewport
|
||||
// It means it's going to scale large images, but the text will remain at the normal
|
||||
// size.
|
||||
//
|
||||
// That means we can use scalesPageToFix on Android but not on iOS.
|
||||
// The weird thing is that on iOS, scalesPageToFix=false along with a CSS
|
||||
// rule "img { max-width: 100% }", works like scalesPageToFix=true on Android.
|
||||
// So we use scalesPageToFix=false on iOS along with that CSS rule.
|
||||
//
|
||||
// 2020-10-15: As we've now fully switched to WebKit for iOS (useWebKit=true) and
|
||||
// since the WebView package went through many versions it's possible that
|
||||
// the above no longer applies.
|
||||
|
||||
return (
|
||||
<View style={props.style}>
|
||||
<WebView
|
||||
theme={theme}
|
||||
useWebKit={true}
|
||||
allowingReadAccessToURL={`file://${Setting.value('resourceDir')}`}
|
||||
style={webViewStyle}
|
||||
source={source}
|
||||
injectedJavaScript={injectedJs.join('\n')}
|
||||
originWhitelist={['file://*', './*', 'http://*', 'https://*']}
|
||||
mixedContentMode="always"
|
||||
allowFileAccess={true}
|
||||
onLoadEnd={onLoadEnd}
|
||||
onError={onError}
|
||||
onMessage={onMessage}
|
||||
/>
|
||||
<BackButtonDialogBox ref={dialogBoxRef}/>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { useCallback } from 'react';
|
||||
const shared = require('lib/components/shared/note-screen-shared');
|
||||
|
||||
export default function useOnMessage(onCheckboxChange:Function, noteBody:string, onMarkForDownload:Function, onJoplinLinkClick:Function, onResourceLongPress:Function) {
|
||||
return useCallback((event:any) => {
|
||||
// Since RN 58 (or 59) messages are now escaped twice???
|
||||
const msg = unescape(unescape(event.nativeEvent.data));
|
||||
|
||||
console.info('Got IPC message: ', msg);
|
||||
|
||||
if (msg.indexOf('checkboxclick:') === 0) {
|
||||
const newBody = shared.toggleCheckbox(msg, noteBody);
|
||||
if (onCheckboxChange) onCheckboxChange(newBody);
|
||||
} else if (msg.indexOf('markForDownload:') === 0) {
|
||||
const splittedMsg = msg.split(':');
|
||||
const resourceId = splittedMsg[1];
|
||||
if (onMarkForDownload) onMarkForDownload({ resourceId: resourceId });
|
||||
} else if (msg.startsWith('longclick:')) {
|
||||
onResourceLongPress(msg);
|
||||
} else if (msg.startsWith('joplin:')) {
|
||||
onJoplinLinkClick(msg);
|
||||
} else if (msg.startsWith('error:')) {
|
||||
console.error(`Webview injected script error: ${msg}`);
|
||||
}
|
||||
}, [onCheckboxChange, noteBody, onMarkForDownload, onJoplinLinkClick, onResourceLongPress]);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import { useCallback } from 'react';
|
||||
import Setting from 'lib/models/Setting';
|
||||
import shim from 'lib/shim';
|
||||
|
||||
const { ToastAndroid } = require('react-native');
|
||||
const { _ } = require('lib/locale.js');
|
||||
const { reg } = require('lib/registry.js');
|
||||
const { dialogs } = require('lib/dialogs.js');
|
||||
const Resource = require('lib/models/Resource.js');
|
||||
const Share = require('react-native-share').default;
|
||||
|
||||
export default function useOnResourceLongPress(onJoplinLinkClick:Function, dialogBoxRef:any) {
|
||||
return useCallback(async (msg:string) => {
|
||||
try {
|
||||
const resourceId = msg.split(':')[1];
|
||||
const resource = await Resource.load(resourceId);
|
||||
const name = resource.title ? resource.title : resource.file_name;
|
||||
|
||||
const action = await dialogs.pop({ dialogbox: dialogBoxRef.current }, name, [
|
||||
{ text: _('Open'), id: 'open' },
|
||||
{ text: _('Share'), id: 'share' },
|
||||
]);
|
||||
|
||||
if (action === 'open') {
|
||||
onJoplinLinkClick(`joplin://${resourceId}`);
|
||||
} else if (action === 'share') {
|
||||
const filename = resource.file_name ?
|
||||
`${resource.file_name}.${resource.file_extension}` :
|
||||
resource.title;
|
||||
const targetPath = `${Setting.value('resourceDir')}/${filename}`;
|
||||
|
||||
await shim.fsDriver().copy(Resource.fullPath(resource), targetPath);
|
||||
|
||||
await Share.open({
|
||||
type: resource.mime,
|
||||
filename: resource.title,
|
||||
url: `file://${targetPath}`,
|
||||
failOnCancel: false,
|
||||
});
|
||||
|
||||
await shim.fsDriver().remove(targetPath);
|
||||
}
|
||||
} catch (e) {
|
||||
reg.logger().error('Could not handle link long press', e);
|
||||
ToastAndroid.show('An error occurred, check log for details', ToastAndroid.SHORT);
|
||||
}
|
||||
}, [onJoplinLinkClick]);
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
import { useEffect, useState, useMemo } from 'react';
|
||||
import shim from 'lib/shim';
|
||||
import Setting from 'lib/models/Setting';
|
||||
const { themeStyle } = require('lib/components/global-style.js');
|
||||
const markupLanguageUtils = require('lib/markupLanguageUtils');
|
||||
const { assetsToHeaders } = require('lib/joplin-renderer');
|
||||
|
||||
interface Source {
|
||||
uri: string,
|
||||
baseUrl: string,
|
||||
}
|
||||
|
||||
interface UseSourceResult {
|
||||
source: Source,
|
||||
injectedJs: string[],
|
||||
}
|
||||
|
||||
let markupToHtml_:any = null;
|
||||
|
||||
function markupToHtml() {
|
||||
if (markupToHtml_) return markupToHtml_;
|
||||
markupToHtml_ = markupLanguageUtils.newMarkupToHtml();
|
||||
return markupToHtml_;
|
||||
}
|
||||
|
||||
export default function useSource(noteBody:string, noteMarkupLanguage:number, themeId:number, highlightedKeywords:string[], noteResources:any, paddingBottom:number, noteHash:string):UseSourceResult {
|
||||
const [source, setSource] = useState<Source>(undefined);
|
||||
const [injectedJs, setInjectedJs] = useState<string[]>([]);
|
||||
const [resourceLoadedTime, setResourceLoadedTime] = useState(0);
|
||||
const [isFirstRender, setIsFirstRender] = useState(true);
|
||||
|
||||
const rendererTheme = useMemo(() => {
|
||||
return {
|
||||
bodyPaddingTop: '.8em', // Extra top padding on the rendered MD so it doesn't touch the border
|
||||
bodyPaddingBottom: paddingBottom, // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text)
|
||||
...themeStyle(themeId),
|
||||
};
|
||||
}, [themeId, paddingBottom]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
async function renderNote() {
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
const bodyToRender = noteBody || '';
|
||||
|
||||
const mdOptions = {
|
||||
onResourceLoaded: () => {
|
||||
setResourceLoadedTime(Date.now());
|
||||
},
|
||||
highlightedKeywords: highlightedKeywords,
|
||||
resources: noteResources,
|
||||
codeTheme: theme.codeThemeCss,
|
||||
postMessageSyntax: 'window.joplinPostMessage_',
|
||||
enableLongPress: shim.mobilePlatform() === 'android', // On iOS, there's already a built-on open/share menu
|
||||
longPressDelay: 500, // TODO use system value
|
||||
};
|
||||
|
||||
// Whenever a resource state changes, for example when it goes from "not downloaded" to "downloaded", the "noteResources"
|
||||
// props changes, thus triggering a render. The **content** of this noteResources array however is not changed because
|
||||
// it doesn't contain info about the resource download state. Because of that, if we were to use the markupToHtml() cache
|
||||
// it wouldn't re-render at all. We don't need this cache in any way because this hook is only triggered when we know
|
||||
// something has changed.
|
||||
markupToHtml().clearCache(noteMarkupLanguage);
|
||||
|
||||
const result = await markupToHtml().render(
|
||||
noteMarkupLanguage,
|
||||
bodyToRender,
|
||||
rendererTheme,
|
||||
mdOptions
|
||||
);
|
||||
|
||||
if (cancelled) return;
|
||||
|
||||
let html = result.html;
|
||||
|
||||
const resourceDownloadMode = Setting.value('sync.resourceDownloadMode');
|
||||
|
||||
const js = [];
|
||||
js.push('try {');
|
||||
js.push(shim.injectedJs('webviewLib'));
|
||||
// Note that this postMessage function accepts two arguments, for compatibility with the desktop version, but
|
||||
// the ReactNativeWebView actually supports only one, so the second arg is ignored (and currently not needed for the mobile app).
|
||||
js.push('window.joplinPostMessage_ = (msg, args) => { return window.ReactNativeWebView.postMessage(msg); };');
|
||||
js.push('webviewLib.initialize({ postMessage: msg => { return window.ReactNativeWebView.postMessage(msg); } });');
|
||||
js.push(`
|
||||
const readyStateCheckInterval = setInterval(function() {
|
||||
if (document.readyState === "complete") {
|
||||
clearInterval(readyStateCheckInterval);
|
||||
if ("${resourceDownloadMode}" === "manual") webviewLib.setupResourceManualDownload();
|
||||
const hash = "${noteHash}";
|
||||
// Gives it a bit of time before scrolling to the anchor
|
||||
// so that images are loaded.
|
||||
if (hash) {
|
||||
setTimeout(() => {
|
||||
const e = document.getElementById(hash);
|
||||
if (!e) {
|
||||
console.warn('Cannot find hash', hash);
|
||||
return;
|
||||
}
|
||||
e.scrollIntoView();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
`);
|
||||
js.push('} catch (e) {');
|
||||
js.push(' window.ReactNativeWebView.postMessage("error:" + e.message + ": " + JSON.stringify(e))');
|
||||
js.push(' true;');
|
||||
js.push('}');
|
||||
js.push('true;');
|
||||
|
||||
html =
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
${assetsToHeaders(result.pluginAssets, { asHtml: true })}
|
||||
</head>
|
||||
<body>
|
||||
${html}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const tempFile = `${Setting.value('resourceDir')}/NoteBodyViewer.html`;
|
||||
await shim.fsDriver().writeFile(tempFile, html, 'utf8');
|
||||
|
||||
if (cancelled) return;
|
||||
|
||||
// Now that we are sending back a file instead of an HTML string, we're always sending back the
|
||||
// same file. So we add a cache busting query parameter to it, to make sure that the WebView re-renders.
|
||||
//
|
||||
// `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir.
|
||||
setSource({
|
||||
uri: `file://${tempFile}?r=${Math.round(Math.random() * 100000000)}`,
|
||||
baseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||
});
|
||||
|
||||
setInjectedJs(js);
|
||||
}
|
||||
|
||||
// When mounted, we need to render the webview in two stages;
|
||||
// - First without any source, so that all webview props are setup properly
|
||||
// - Secondly with the source to actually render the note
|
||||
// This is necessary to prevent a race condition that could cause an ERR_ACCESS_DENIED error
|
||||
// https://github.com/react-native-webview/react-native-webview/issues/656#issuecomment-551312436
|
||||
|
||||
if (isFirstRender) {
|
||||
setIsFirstRender(false);
|
||||
setSource(undefined);
|
||||
setInjectedJs([]);
|
||||
} else {
|
||||
renderNote();
|
||||
}
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [resourceLoadedTime, noteBody, noteMarkupLanguage, themeId, rendererTheme, highlightedKeywords, noteResources, noteHash, isFirstRender]);
|
||||
|
||||
return { source, injectedJs };
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
import * as React from 'react';
|
||||
import { View, Button, Text } from 'react-native';
|
||||
import { themeStyle } from 'lib/theme';
|
||||
import { _ } from 'lib/locale';
|
||||
|
||||
const PopupDialog = require('react-native-popup-dialog').default;
|
||||
const { DialogTitle, DialogButton } = require('react-native-popup-dialog');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const DateTimePickerModal = require('react-native-modal-datetime-picker').default;
|
||||
|
||||
export default class SelectDateTimeDialog extends React.PureComponent<any, any> {
|
||||
|
||||
private dialog_:any = null;
|
||||
private shown_:boolean = false;
|
||||
|
||||
constructor(props:any) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
date: null,
|
||||
mode: 'date',
|
||||
showPicker: false,
|
||||
};
|
||||
|
||||
this.onReject = this.onReject.bind(this);
|
||||
this.onPickerConfirm = this.onPickerConfirm.bind(this);
|
||||
this.onPickerCancel = this.onPickerCancel.bind(this);
|
||||
this.onSetDate = this.onSetDate.bind(this);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps:any) {
|
||||
if (newProps.date != this.state.date) {
|
||||
this.setState({ date: newProps.date });
|
||||
}
|
||||
|
||||
if ('shown' in newProps && newProps.shown != this.shown_) {
|
||||
this.show(newProps.shown);
|
||||
}
|
||||
}
|
||||
|
||||
show(doShow:boolean = true) {
|
||||
if (doShow) {
|
||||
this.dialog_.show();
|
||||
} else {
|
||||
this.dialog_.dismiss();
|
||||
}
|
||||
|
||||
this.shown_ = doShow;
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.show(false);
|
||||
}
|
||||
|
||||
onAccept() {
|
||||
if (this.props.onAccept) this.props.onAccept(this.state.date);
|
||||
}
|
||||
|
||||
onReject() {
|
||||
if (this.props.onReject) this.props.onReject();
|
||||
}
|
||||
|
||||
onClear() {
|
||||
if (this.props.onAccept) this.props.onAccept(null);
|
||||
}
|
||||
|
||||
onPickerConfirm(selectedDate:Date) {
|
||||
this.setState({ date: selectedDate, showPicker: false });
|
||||
}
|
||||
|
||||
onPickerCancel() {
|
||||
this.setState({ showPicker: false });
|
||||
}
|
||||
|
||||
onSetDate() {
|
||||
this.setState({ showPicker: true });
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
if (!this.shown_) return <View/>;
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, margin: 20, alignItems: 'center' }}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{ this.state.date && <Text style={{ ...theme.normalText, marginRight: 10 }}>{time.formatDateToLocal(this.state.date)}</Text> }
|
||||
<Button title="Set date" onPress={this.onSetDate} />
|
||||
</View>
|
||||
<DateTimePickerModal
|
||||
date={this.state.date ? this.state.date : new Date()}
|
||||
is24Hour={time.use24HourFormat()}
|
||||
isVisible={this.state.showPicker}
|
||||
mode="datetime"
|
||||
onConfirm={this.onPickerConfirm}
|
||||
onCancel={this.onPickerCancel}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const clearAlarmText = _('Clear alarm'); // For unknown reasons, this particular string doesn't get translated if it's directly in the text property below
|
||||
|
||||
const popupActions = [
|
||||
<DialogButton text={_('Save alarm')} align="center" onPress={() => this.onAccept()} key="saveButton" />,
|
||||
<DialogButton text={clearAlarmText} align="center" onPress={() => this.onClear()} key="clearButton" />,
|
||||
<DialogButton text={_('Cancel')} align="center" onPress={() => this.onReject()} key="cancelButton" />,
|
||||
];
|
||||
|
||||
return (
|
||||
<PopupDialog
|
||||
ref={(dialog:any) => { this.dialog_ = dialog; }}
|
||||
dialogTitle={<DialogTitle title={_('Set alarm')} />}
|
||||
actions={popupActions}
|
||||
dismissOnTouchOutside={false}
|
||||
width={0.9}
|
||||
height={350}
|
||||
>
|
||||
{this.renderContent()}
|
||||
</PopupDialog>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,9 @@ class ActionButtonComponent extends React.Component {
|
|||
this.state = {
|
||||
buttonIndex: 0,
|
||||
};
|
||||
|
||||
this.renderIconMultiStates = this.renderIconMultiStates.bind(this);
|
||||
this.renderIcon = this.renderIcon.bind(this);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps) {
|
||||
|
@ -55,6 +58,16 @@ class ActionButtonComponent extends React.Component {
|
|||
this.newNoteNavigate(this.props.parentFolderId, false);
|
||||
}
|
||||
|
||||
renderIconMultiStates() {
|
||||
const button = this.props.buttons[this.state.buttonIndex];
|
||||
return <Icon name={button.icon} style={styles.actionButtonIcon} />;
|
||||
}
|
||||
|
||||
renderIcon() {
|
||||
const mainButton = this.props.mainButton ? this.props.mainButton : {};
|
||||
return mainButton.icon ? <Icon name={mainButton.icon} style={styles.actionButtonIcon} /> : <Icon name="md-add" style={styles.actionButtonIcon} />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const buttons = this.props.buttons ? this.props.buttons : [];
|
||||
|
||||
|
@ -96,17 +109,13 @@ class ActionButtonComponent extends React.Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
const mainButton = this.props.mainButton ? this.props.mainButton : {};
|
||||
const mainIcon = mainButton.icon ? <Icon name={mainButton.icon} style={styles.actionButtonIcon} /> : <Icon name="md-add" style={styles.actionButtonIcon} />;
|
||||
|
||||
if (this.props.multiStates) {
|
||||
if (!this.props.buttons || !this.props.buttons.length) throw new Error('Multi-state button requires at least one state');
|
||||
if (this.state.buttonIndex < 0 || this.state.buttonIndex >= this.props.buttons.length) throw new Error(`Button index out of bounds: ${this.state.buttonIndex}/${this.props.buttons.length}`);
|
||||
const button = this.props.buttons[this.state.buttonIndex];
|
||||
const mainIcon = <Icon name={button.icon} style={styles.actionButtonIcon} />;
|
||||
return (
|
||||
<ReactNativeActionButton
|
||||
icon={mainIcon}
|
||||
renderIcon={this.renderIconMultiStates}
|
||||
buttonColor="rgba(231,76,60,1)"
|
||||
onPress={() => {
|
||||
button.onPress();
|
||||
|
@ -115,7 +124,7 @@ class ActionButtonComponent extends React.Component {
|
|||
);
|
||||
} else {
|
||||
return (
|
||||
<ReactNativeActionButton textStyle={styles.itemText} icon={mainIcon} buttonColor="rgba(231,76,60,1)" onPress={function() {}}>
|
||||
<ReactNativeActionButton textStyle={styles.itemText} renderIcon={this.renderIcon} buttonColor="rgba(231,76,60,1)" onPress={function() {}}>
|
||||
{buttonComps}
|
||||
</ReactNativeActionButton>
|
||||
);
|
||||
|
|
|
@ -1,322 +0,0 @@
|
|||
import Async from 'react-async';
|
||||
|
||||
const React = require('react');
|
||||
const Component = React.Component;
|
||||
const { Platform, View, Text, ToastAndroid } = require('react-native');
|
||||
const { WebView } = require('react-native-webview');
|
||||
const { themeStyle } = require('lib/components/global-style.js');
|
||||
const Setting = require('lib/models/Setting').default;
|
||||
const { _ } = require('lib/locale.js');
|
||||
const { reg } = require('lib/registry.js');
|
||||
const shim = require('lib/shim').default;
|
||||
const { assetsToHeaders } = require('lib/joplin-renderer');
|
||||
const shared = require('lib/components/shared/note-screen-shared.js');
|
||||
const markupLanguageUtils = require('lib/markupLanguageUtils');
|
||||
const { dialogs } = require('lib/dialogs.js');
|
||||
const BackButtonDialogBox = require('lib/components/BackButtonDialogBox').default;
|
||||
const Resource = require('lib/models/Resource.js');
|
||||
const Share = require('react-native-share').default;
|
||||
|
||||
class NoteBodyViewer extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
resources: {},
|
||||
webViewLoaded: false,
|
||||
bodyHtml: '',
|
||||
};
|
||||
|
||||
this.forceUpdate_ = false;
|
||||
|
||||
this.isMounted_ = false;
|
||||
|
||||
this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml();
|
||||
|
||||
this.reloadNote = this.reloadNote.bind(this);
|
||||
this.watchFn = this.watchFn.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.isMounted_ = true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.markupToHtml_ = null;
|
||||
this.isMounted_ = false;
|
||||
}
|
||||
|
||||
async reloadNote() {
|
||||
this.forceUpdate_ = false;
|
||||
|
||||
const note = this.props.note;
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const bodyToRender = note ? note.body : '';
|
||||
|
||||
const mdOptions = {
|
||||
onResourceLoaded: () => {
|
||||
if (this.resourceLoadedTimeoutId_) {
|
||||
shim.clearTimeout(this.resourceLoadedTimeoutId_);
|
||||
this.resourceLoadedTimeoutId_ = null;
|
||||
}
|
||||
|
||||
this.resourceLoadedTimeoutId_ = shim.setTimeout(() => {
|
||||
this.resourceLoadedTimeoutId_ = null;
|
||||
this.forceUpdate();
|
||||
}, 100);
|
||||
},
|
||||
highlightedKeywords: this.props.highlightedKeywords,
|
||||
resources: this.props.noteResources,
|
||||
codeTheme: theme.codeThemeCss,
|
||||
postMessageSyntax: 'window.joplinPostMessage_',
|
||||
enableLongPress: shim.isReactNative(),
|
||||
longPressDelay: 500, // TODO use system value
|
||||
};
|
||||
|
||||
const result = await this.markupToHtml_.render(
|
||||
note.markup_language,
|
||||
bodyToRender,
|
||||
{
|
||||
bodyPaddingTop: '.8em', // Extra top padding on the rendered MD so it doesn't touch the border
|
||||
bodyPaddingBottom: this.props.paddingBottom, // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text)
|
||||
...this.props.webViewStyle,
|
||||
},
|
||||
mdOptions
|
||||
);
|
||||
let html = result.html;
|
||||
|
||||
const resourceDownloadMode = Setting.value('sync.resourceDownloadMode');
|
||||
|
||||
const injectedJs = [];
|
||||
injectedJs.push(shim.injectedJs('webviewLib'));
|
||||
// Note that this postMessage function accepts two arguments, for compatibility with the desktop version, but
|
||||
// the ReactNativeWebView actually supports only one, so the second arg is ignored (and currently not needed for the mobile app).
|
||||
injectedJs.push('window.joplinPostMessage_ = (msg, args) => { return window.ReactNativeWebView.postMessage(msg); };');
|
||||
injectedJs.push('webviewLib.initialize({ postMessage: msg => { return window.ReactNativeWebView.postMessage(msg); } });');
|
||||
injectedJs.push(`
|
||||
const readyStateCheckInterval = shim.setInterval(function() {
|
||||
if (document.readyState === "complete") {
|
||||
shim.clearInterval(readyStateCheckInterval);
|
||||
if ("${resourceDownloadMode}" === "manual") webviewLib.setupResourceManualDownload();
|
||||
|
||||
const hash = "${this.props.noteHash}";
|
||||
// Gives it a bit of time before scrolling to the anchor
|
||||
// so that images are loaded.
|
||||
if (hash) {
|
||||
shim.setTimeout(() => {
|
||||
const e = document.getElementById(hash);
|
||||
if (!e) {
|
||||
console.warn('Cannot find hash', hash);
|
||||
return;
|
||||
}
|
||||
e.scrollIntoView();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
`);
|
||||
|
||||
html =
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
${assetsToHeaders(result.pluginAssets, { asHtml: true })}
|
||||
</head>
|
||||
<body>
|
||||
${html}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// On iOS scalesPageToFit work like this:
|
||||
//
|
||||
// Find the widest image, resize it *and everything else* by x% so that
|
||||
// the image fits within the viewport. The problem is that it means if there's
|
||||
// a large image, everything is going to be scaled to a very small size, making
|
||||
// the text unreadable.
|
||||
//
|
||||
// On Android:
|
||||
//
|
||||
// Find the widest elements and scale them (and them only) to fit within the viewport
|
||||
// It means it's going to scale large images, but the text will remain at the normal
|
||||
// size.
|
||||
//
|
||||
// That means we can use scalesPageToFix on Android but not on iOS.
|
||||
// The weird thing is that on iOS, scalesPageToFix=false along with a CSS
|
||||
// rule "img { max-width: 100% }", works like scalesPageToFix=true on Android.
|
||||
// So we use scalesPageToFix=false on iOS along with that CSS rule.
|
||||
|
||||
// `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir.
|
||||
return {
|
||||
source: {
|
||||
html: html,
|
||||
baseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||
},
|
||||
injectedJs: injectedJs,
|
||||
};
|
||||
}
|
||||
|
||||
onLoadEnd() {
|
||||
shim.setTimeout(() => {
|
||||
if (this.props.onLoadEnd) this.props.onLoadEnd();
|
||||
}, 100);
|
||||
|
||||
if (this.state.webViewLoaded) return;
|
||||
|
||||
// Need to display after a delay to avoid a white flash before
|
||||
// the content is displayed.
|
||||
shim.setTimeout(() => {
|
||||
if (!this.isMounted_) return;
|
||||
this.setState({ webViewLoaded: true });
|
||||
}, 100);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const safeGetNoteProp = (props, propName) => {
|
||||
if (!props) return null;
|
||||
if (!props.note) return null;
|
||||
return props.note[propName];
|
||||
};
|
||||
|
||||
// To address https://github.com/laurent22/joplin/issues/433
|
||||
// If a checkbox in a note is ticked, the body changes, which normally would trigger a re-render
|
||||
// of this component, which has the unfortunate side effect of making the view scroll back to the top.
|
||||
// This re-rendering however is uncessary since the component is already visually updated via JS.
|
||||
// So here, if the note has not changed, we prevent the component from updating.
|
||||
// This fixes the above issue. A drawback of this is if the note is updated via sync, this change
|
||||
// will not be displayed immediately.
|
||||
const currentNoteId = safeGetNoteProp(this.props, 'id');
|
||||
const nextNoteId = safeGetNoteProp(nextProps, 'id');
|
||||
|
||||
if (currentNoteId !== nextNoteId || nextState.webViewLoaded !== this.state.webViewLoaded) return true;
|
||||
|
||||
// If the length of the body has changed, then it's something other than a checkbox that has changed,
|
||||
// for example a resource that has been attached to the note while in View mode. In that case, update.
|
||||
return (`${safeGetNoteProp(this.props, 'body')}`).length !== (`${safeGetNoteProp(nextProps, 'body')}`).length;
|
||||
}
|
||||
|
||||
rebuildMd() {
|
||||
this.forceUpdate_ = true;
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
watchFn() {
|
||||
// react-async will not fetch the data again after the first render
|
||||
// so we use this watchFn function to force it to reload in certain
|
||||
// cases. It is used in particular when re-rendering the note when
|
||||
// a resource has been downloaded in auto mode.
|
||||
return this.forceUpdate_;
|
||||
}
|
||||
|
||||
async onResourceLongPress(msg) {
|
||||
try {
|
||||
const resourceId = msg.split(':')[1];
|
||||
const resource = await Resource.load(resourceId);
|
||||
const name = resource.title ? resource.title : resource.file_name;
|
||||
|
||||
const action = await dialogs.pop(this, name, [
|
||||
{ text: _('Open'), id: 'open' },
|
||||
{ text: _('Share'), id: 'share' },
|
||||
]);
|
||||
|
||||
if (action === 'open') {
|
||||
this.props.onJoplinLinkClick(`joplin://${resourceId}`);
|
||||
} else if (action === 'share') {
|
||||
const filename = resource.file_name ?
|
||||
`${resource.file_name}.${resource.file_extension}` :
|
||||
resource.title;
|
||||
const targetPath = `${Setting.value('resourceDir')}/${filename}`;
|
||||
|
||||
await shim.fsDriver().copy(Resource.fullPath(resource), targetPath);
|
||||
|
||||
await Share.open({
|
||||
type: resource.mime,
|
||||
filename: resource.title,
|
||||
url: `file://${targetPath}`,
|
||||
failOnCancel: false,
|
||||
});
|
||||
|
||||
await shim.fsDriver().remove(targetPath);
|
||||
}
|
||||
} catch (e) {
|
||||
reg.logger().error('Could not handle link long press', e);
|
||||
ToastAndroid.show('An error occurred, check log for details', ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
// Note: useWebKit={false} is needed to go around this bug:
|
||||
// https://github.com/react-native-community/react-native-webview/issues/376
|
||||
// However, if we add the <meta> tag as described there, it is no longer necessary and WebKit can be used!
|
||||
// https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-501991406
|
||||
//
|
||||
// However, on iOS, due to the bug below, we cannot use WebKit:
|
||||
// https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-503754654
|
||||
|
||||
|
||||
const webViewStyle = { backgroundColor: this.props.webViewStyle.backgroundColor };
|
||||
// On iOS, the onLoadEnd() event is never fired so always
|
||||
// display the webview (don't do the little trick
|
||||
// to avoid the white flash).
|
||||
if (Platform.OS !== 'ios') {
|
||||
webViewStyle.opacity = this.state.webViewLoaded ? 1 : 0.01;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={this.props.style}>
|
||||
<Async promiseFn={this.reloadNote} watchFn={this.watchFn}>
|
||||
{({ data, error, isPending }) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return <Text>{error.message}</Text>;
|
||||
}
|
||||
|
||||
if (isPending) return null;
|
||||
|
||||
return (
|
||||
<WebView
|
||||
useWebKit={Platform.OS !== 'ios'}
|
||||
style={webViewStyle}
|
||||
source={data.source}
|
||||
injectedJavaScript={data.injectedJs.join('\n')}
|
||||
originWhitelist={['file://*', './*', 'http://*', 'https://*']}
|
||||
mixedContentMode="always"
|
||||
allowFileAccess={true}
|
||||
onLoadEnd={() => this.onLoadEnd()}
|
||||
onError={() => reg.logger().error('WebView error')}
|
||||
onMessage={event => {
|
||||
// Since RN 58 (or 59) messages are now escaped twice???
|
||||
let msg = unescape(unescape(event.nativeEvent.data));
|
||||
|
||||
console.info('Got IPC message: ', msg);
|
||||
|
||||
if (msg.indexOf('checkboxclick:') === 0) {
|
||||
const newBody = shared.toggleCheckbox(msg, this.props.note.body);
|
||||
if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody);
|
||||
} else if (msg.indexOf('markForDownload:') === 0) {
|
||||
msg = msg.split(':');
|
||||
const resourceId = msg[1];
|
||||
if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId });
|
||||
} else if (msg.startsWith('longclick:')) {
|
||||
this.onResourceLongPress(msg);
|
||||
} else if (msg.startsWith('joplin:')) {
|
||||
this.props.onJoplinLinkClick(msg);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</Async>
|
||||
<BackButtonDialogBox
|
||||
ref={dialogbox => {
|
||||
this.dialogbox = dialogbox;
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { NoteBodyViewer };
|
|
@ -264,7 +264,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||
|
||||
const renderUndoButton = () => {
|
||||
return renderTopButton({
|
||||
iconName: 'md-undo',
|
||||
iconName: 'arrow-undo-circle-sharp',
|
||||
onPress: this.props.onUndoButtonPress,
|
||||
visible: this.props.showUndoButton,
|
||||
disabled: this.props.undoButtonDisabled,
|
||||
|
@ -273,7 +273,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||
|
||||
const renderRedoButton = () => {
|
||||
return renderTopButton({
|
||||
iconName: 'md-redo',
|
||||
iconName: 'arrow-redo-circle-sharp',
|
||||
onPress: this.props.onRedoButtonPress,
|
||||
visible: this.props.showRedoButton,
|
||||
});
|
||||
|
@ -323,7 +323,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||
return (
|
||||
<TouchableOpacity onPress={onPress}>
|
||||
<View style={styles.iconButton}>
|
||||
<Icon name="md-funnel" style={styles.topIcon} />
|
||||
<Icon name="filter-outline" style={styles.topIcon} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
@ -481,7 +481,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||
!menuOptionComponents.length || !showContextMenuButton ? null : (
|
||||
<Menu onSelect={value => this.menu_select(value)} style={this.styles().contextMenu}>
|
||||
<MenuTrigger style={contextMenuStyle}>
|
||||
<Icon name="md-more" style={this.styles().contextMenuTrigger} />
|
||||
<Icon name="md-ellipsis-vertical" style={this.styles().contextMenuTrigger} />
|
||||
</MenuTrigger>
|
||||
<MenuOptions>
|
||||
<ScrollView style={{ maxHeight: windowHeight }}>{menuOptionComponents}</ScrollView>
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
import FileViewer from 'react-native-file-viewer';
|
||||
import AsyncActionQueue from '../../AsyncActionQueue';
|
||||
import UndoRedoService from 'lib/services/UndoRedoService';
|
||||
import uuid from 'lib/uuid';
|
||||
import Setting from 'lib/models/Setting';
|
||||
import shim from 'lib/shim';
|
||||
import NoteBodyViewer from 'lib/components/NoteBodyViewer/NoteBodyViewer';
|
||||
import checkPermissions from 'lib/checkPermissions';
|
||||
|
||||
const FileViewer = require('react-native-file-viewer').default;
|
||||
const React = require('react');
|
||||
const { Platform, Clipboard, Keyboard, View, TextInput, StyleSheet, Linking, Image, Share } = require('react-native');
|
||||
const { Platform, Keyboard, View, TextInput, StyleSheet, Linking, Image, Share, PermissionsAndroid } = require('react-native');
|
||||
const { connect } = require('react-redux');
|
||||
const uuid = require('lib/uuid').default;
|
||||
const { MarkdownEditor } = require('../../../MarkdownEditor/index.js');
|
||||
const RNFS = require('react-native-fs');
|
||||
const Note = require('lib/models/Note.js');
|
||||
const UndoRedoService = require('lib/services/UndoRedoService.js').default;
|
||||
const BaseItem = require('lib/models/BaseItem.js');
|
||||
const Setting = require('lib/models/Setting').default;
|
||||
const Resource = require('lib/models/Resource.js');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const Clipboard = require('@react-native-community/clipboard').default;
|
||||
const md5 = require('md5');
|
||||
const { BackButtonService } = require('lib/services/back-button.js');
|
||||
const NavService = require('lib/services/NavService.js');
|
||||
|
@ -26,24 +30,24 @@ const { time } = require('lib/time-utils.js');
|
|||
const { Checkbox } = require('lib/components/checkbox.js');
|
||||
const { _ } = require('lib/locale');
|
||||
const { reg } = require('lib/registry.js');
|
||||
const shim = require('lib/shim').default;
|
||||
const ResourceFetcher = require('lib/services/ResourceFetcher');
|
||||
const { BaseScreenComponent } = require('lib/components/base-screen.js');
|
||||
const { themeStyle, editorFont } = require('lib/components/global-style.js');
|
||||
const { dialogs } = require('lib/dialogs.js');
|
||||
const DialogBox = require('react-native-dialogbox').default;
|
||||
const { NoteBodyViewer } = require('lib/components/note-body-viewer.js');
|
||||
const { DocumentPicker, DocumentPickerUtil } = require('react-native-document-picker');
|
||||
const DocumentPicker = require('react-native-document-picker').default;
|
||||
const ImageResizer = require('react-native-image-resizer').default;
|
||||
const shared = require('lib/components/shared/note-screen-shared.js');
|
||||
const ImagePicker = require('react-native-image-picker');
|
||||
const { SelectDateTimeDialog } = require('lib/components/select-date-time-dialog.js');
|
||||
const ImagePicker = require('react-native-image-picker').default;
|
||||
const SelectDateTimeDialog = require('lib/components/SelectDateTimeDialog').default;
|
||||
const ShareExtension = require('lib/ShareExtension.js').default;
|
||||
const CameraView = require('lib/components/CameraView');
|
||||
const CameraView = require('lib/components/CameraView').default;
|
||||
const urlUtils = require('lib/urlUtils');
|
||||
|
||||
const emptyArray:any[] = [];
|
||||
|
||||
class NoteScreenComponent extends BaseScreenComponent {
|
||||
static navigationOptions() {
|
||||
static navigationOptions():any {
|
||||
return { header: null };
|
||||
}
|
||||
|
||||
|
@ -151,7 +155,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.setState({ noteTagDialogShown: false });
|
||||
};
|
||||
|
||||
this.onJoplinLinkClick_ = async msg => {
|
||||
this.onJoplinLinkClick_ = async (msg:string) => {
|
||||
try {
|
||||
if (msg.indexOf('joplin://') === 0) {
|
||||
const resourceUrlInfo = urlUtils.parseResourceUrl(msg);
|
||||
|
@ -194,7 +198,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
}
|
||||
};
|
||||
|
||||
this.refreshResource = async (resource, noteBody = null) => {
|
||||
this.refreshResource = async (resource:any, noteBody:string = null) => {
|
||||
if (noteBody === null && this.state.note && this.state.note.body) noteBody = this.state.note.body;
|
||||
if (noteBody === null) return;
|
||||
|
||||
|
@ -202,9 +206,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
if (resourceIds.indexOf(resource.id) >= 0) {
|
||||
shared.clearResourceCache();
|
||||
const attachedResources = await shared.attachedResources(noteBody);
|
||||
this.setState({ noteResources: attachedResources }, () => {
|
||||
if (this.refs.noteBodyViewer) this.refs.noteBodyViewer.rebuildMd();
|
||||
});
|
||||
this.setState({ noteResources: attachedResources });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -230,6 +232,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.screenHeader_undoButtonPress = this.screenHeader_undoButtonPress.bind(this);
|
||||
this.screenHeader_redoButtonPress = this.screenHeader_redoButtonPress.bind(this);
|
||||
this.body_selectionChange = this.body_selectionChange.bind(this);
|
||||
this.onBodyViewerLoadEnd = this.onBodyViewerLoadEnd.bind(this);
|
||||
this.onBodyViewerCheckboxChange = this.onBodyViewerCheckboxChange.bind(this);
|
||||
}
|
||||
|
||||
undoRedoService_stackChange() {
|
||||
|
@ -239,11 +243,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
} });
|
||||
}
|
||||
|
||||
async undoRedo(type) {
|
||||
async undoRedo(type:string) {
|
||||
const undoState = await this.undoRedoService_[type](this.undoState());
|
||||
if (!undoState) return;
|
||||
|
||||
this.setState((state) => {
|
||||
this.setState((state:any) => {
|
||||
const newNote = Object.assign({}, state.note);
|
||||
newNote.body = undoState.body;
|
||||
return {
|
||||
|
@ -270,7 +274,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.styles_ = {};
|
||||
|
||||
// TODO: Clean up these style names and nesting
|
||||
const styles = {
|
||||
const styles:any = {
|
||||
screen: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
|
@ -299,12 +303,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
},
|
||||
noteBodyViewerPreview: {
|
||||
borderTopColor: theme.dividerColor,
|
||||
borderTopWidth: 1,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
checkbox: {
|
||||
color: theme.color,
|
||||
paddingRight: 10,
|
||||
|
@ -318,6 +316,14 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
},
|
||||
};
|
||||
|
||||
styles.noteBodyViewerPreview = {
|
||||
...styles.noteBodyViewer,
|
||||
borderTopColor: theme.dividerColor,
|
||||
borderTopWidth: 1,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
borderBottomWidth: 1,
|
||||
};
|
||||
|
||||
styles.titleContainer = {
|
||||
flex: 0,
|
||||
flexDirection: 'row',
|
||||
|
@ -353,12 +359,29 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
return shared.isModified(this);
|
||||
}
|
||||
|
||||
undoState(noteBody = null) {
|
||||
undoState(noteBody:string = null) {
|
||||
return {
|
||||
body: noteBody === null ? this.state.note.body : noteBody,
|
||||
};
|
||||
}
|
||||
|
||||
async requestGeoLocationPermissions() {
|
||||
if (!Setting.value('trackLocation')) return;
|
||||
|
||||
const response = await checkPermissions(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, {
|
||||
message: _('In order to associate a geo-location with the note, the app needs your permission to access your location.\n\nYou may turn off this option at any time in the Configuration screen.'),
|
||||
title: _('Permission needed'),
|
||||
});
|
||||
|
||||
// If the user simply pressed "Deny", we don't automatically switch it off because they might accept
|
||||
// once we show the rationale again on second try. If they press "Never again" however we switch it off.
|
||||
// https://github.com/zoontek/react-native-permissions/issues/385#issuecomment-563132396
|
||||
if (response === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
|
||||
reg.logger().info('Geo-location tracking has been automatically disabled');
|
||||
Setting.setValue('trackLocation', false);
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
BackButtonService.addHandler(this.backHandler);
|
||||
NavService.addHandler(this.navHandler);
|
||||
|
@ -375,13 +398,18 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
const resourceIds = await Note.linkedResourceIds(this.state.note.body);
|
||||
await ResourceFetcher.instance().markForDownload(resourceIds);
|
||||
}
|
||||
|
||||
// Although it is async, we don't wait for the answer so that if permission
|
||||
// has already been granted, it doesn't slow down opening the note. If it hasn't
|
||||
// been granted, the popup will open anyway.
|
||||
this.requestGeoLocationPermissions();
|
||||
}
|
||||
|
||||
onMarkForDownload(event) {
|
||||
onMarkForDownload(event:any) {
|
||||
ResourceFetcher.instance().markForDownload(event.resourceId);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps:any) {
|
||||
if (this.doFocusUpdate_) {
|
||||
this.doFocusUpdate_ = false;
|
||||
this.focusUpdate();
|
||||
|
@ -412,13 +440,13 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
if (this.undoRedoService_) this.undoRedoService_.off('stackChange', this.undoRedoService_stackChange);
|
||||
}
|
||||
|
||||
title_changeText(text) {
|
||||
title_changeText(text:string) {
|
||||
shared.noteComponent_change(this, 'title', text);
|
||||
this.setState({ newAndNoTitleChangeNoteId: null });
|
||||
this.scheduleSave();
|
||||
}
|
||||
|
||||
body_changeText(text) {
|
||||
body_changeText(text:string) {
|
||||
if (!this.undoRedoService_.canUndo) {
|
||||
this.undoRedoService_.push(this.undoState());
|
||||
} else {
|
||||
|
@ -428,7 +456,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.scheduleSave();
|
||||
}
|
||||
|
||||
body_selectionChange(event) {
|
||||
body_selectionChange(event:any) {
|
||||
this.selection = event.nativeEvent.selection;
|
||||
}
|
||||
|
||||
|
@ -438,7 +466,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
};
|
||||
}
|
||||
|
||||
saveActionQueue(noteId) {
|
||||
saveActionQueue(noteId:string) {
|
||||
if (!this.saveActionQueues_[noteId]) {
|
||||
this.saveActionQueues_[noteId] = new AsyncActionQueue(500);
|
||||
}
|
||||
|
@ -449,13 +477,13 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.saveActionQueue(this.state.note.id).push(this.makeSaveAction());
|
||||
}
|
||||
|
||||
async saveNoteButton_press(folderId = null) {
|
||||
async saveNoteButton_press(folderId:string = null) {
|
||||
await shared.saveNoteButton_press(this, folderId);
|
||||
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
|
||||
async saveOneProperty(name, value) {
|
||||
async saveOneProperty(name:string, value:any) {
|
||||
await shared.saveOneProperty(this, name, value);
|
||||
}
|
||||
|
||||
|
@ -478,47 +506,45 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
}
|
||||
|
||||
async pickDocument() {
|
||||
return new Promise((resolve) => {
|
||||
DocumentPicker.show({ filetype: [DocumentPickerUtil.allFiles()] }, (error, res) => {
|
||||
if (error) {
|
||||
// Also returns an error if the user doesn't pick a file
|
||||
// so just resolve with null.
|
||||
console.info('pickDocument error:', error);
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
try {
|
||||
const result = await DocumentPicker.pick();
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (DocumentPicker.isCancel(error)) {
|
||||
console.info('pickDocument: user has cancelled');
|
||||
return null;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async imageDimensions(uri) {
|
||||
async imageDimensions(uri:string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Image.getSize(
|
||||
uri,
|
||||
(width, height) => {
|
||||
(width:number, height:number) => {
|
||||
resolve({ width: width, height: height });
|
||||
},
|
||||
error => {
|
||||
(error:any) => {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
showImagePicker(options) {
|
||||
showImagePicker(options:any) {
|
||||
return new Promise((resolve) => {
|
||||
ImagePicker.launchImageLibrary(options, response => {
|
||||
ImagePicker.launchImageLibrary(options, (response:any) => {
|
||||
resolve(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async resizeImage(localFilePath, targetPath, mimeType) {
|
||||
async resizeImage(localFilePath:string, targetPath:string, mimeType:string) {
|
||||
const maxSize = Resource.IMAGE_MAX_DIMENSION;
|
||||
|
||||
const dimensions = await this.imageDimensions(localFilePath);
|
||||
const dimensions:any = await this.imageDimensions(localFilePath);
|
||||
|
||||
reg.logger().info('Original dimensions ', dimensions);
|
||||
|
||||
|
@ -564,9 +590,9 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
return true;
|
||||
}
|
||||
|
||||
async attachFile(pickerResponse, fileType) {
|
||||
async attachFile(pickerResponse:any, fileType:string) {
|
||||
if (!pickerResponse) {
|
||||
reg.logger().warn('Got no response from picker');
|
||||
// User has cancelled
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -674,7 +700,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.setState({ showCamera: true });
|
||||
}
|
||||
|
||||
cameraView_onPhoto(data) {
|
||||
cameraView_onPhoto(data:any) {
|
||||
this.attachFile(
|
||||
{
|
||||
uri: data.uri,
|
||||
|
@ -724,7 +750,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
this.setState({ alarmDialogShown: true });
|
||||
}
|
||||
|
||||
async onAlarmDialogAccept(date) {
|
||||
async onAlarmDialogAccept(date:Date) {
|
||||
const newNote = Object.assign({}, this.state.note);
|
||||
newNote.todo_due = date ? date.getTime() : 0;
|
||||
|
||||
|
@ -811,17 +837,35 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
|
||||
// The file attachement modules only work in Android >= 5 (Version 21)
|
||||
// https://github.com/react-community/react-native-image-picker/issues/606
|
||||
|
||||
// As of 2020-10-13, support for attaching images from the gallery is removed
|
||||
// as the package react-native-image-picker has permission issues. It's still
|
||||
// possible to attach files, which has often a similar UI, with thumbnails for
|
||||
// images so normally it should be enough.
|
||||
let canAttachPicture = true;
|
||||
if (Platform.OS === 'android' && Platform.Version < 21) canAttachPicture = false;
|
||||
if (canAttachPicture) {
|
||||
output.push({
|
||||
title: _('Attach...'),
|
||||
onPress: async () => {
|
||||
const buttonId = await dialogs.pop(this, _('Choose an option'), [{ text: _('Take photo'), id: 'takePhoto' }, { text: _('Attach photo'), id: 'attachPhoto' }, { text: _('Attach any file'), id: 'attachFile' }]);
|
||||
const buttons = [];
|
||||
|
||||
// On iOS, it will show "local files", which means certain files saved from the browser
|
||||
// and the iCloud files, but it doesn't include photos and images from the CameraRoll
|
||||
//
|
||||
// On Android, it will depend on the phone, but usually it will allow browing all files and photos.
|
||||
buttons.push({ text: _('Attach file'), id: 'attachFile' });
|
||||
|
||||
// Disabled on Android because it doesn't work due to permission issues, but enabled on iOS
|
||||
// because that's only way to browse photos from the camera roll.
|
||||
if (Platform.OS === 'ios') buttons.push({ text: _('Attach photo'), id: 'attachPhoto' });
|
||||
buttons.push({ text: _('Take photo'), id: 'takePhoto' });
|
||||
|
||||
const buttonId = await dialogs.pop(this, _('Choose an option'), buttons);
|
||||
|
||||
if (buttonId === 'takePhoto') this.takePhoto_onPress();
|
||||
if (buttonId === 'attachPhoto') this.attachPhoto_onPress();
|
||||
if (buttonId === 'attachFile') this.attachFile_onPress();
|
||||
if (buttonId === 'attachPhoto') this.attachPhoto_onPress();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -882,11 +926,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
return output;
|
||||
}
|
||||
|
||||
async todoCheckbox_change(checked) {
|
||||
async todoCheckbox_change(checked:boolean) {
|
||||
await this.saveOneProperty('todo_completed', checked ? time.unixMs() : 0);
|
||||
}
|
||||
|
||||
titleTextInput_contentSizeChange(event) {
|
||||
titleTextInput_contentSizeChange(event:any) {
|
||||
if (!this.enableMultilineTitle_) return;
|
||||
|
||||
const height = event.nativeEvent.contentSize.height;
|
||||
|
@ -920,7 +964,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
}
|
||||
}
|
||||
|
||||
async folderPickerOptions_valueChanged(itemValue) {
|
||||
async folderPickerOptions_valueChanged(itemValue:any) {
|
||||
const note = this.state.note;
|
||||
const isProvisionalNote = this.props.provisionalNoteIds.includes(note.id);
|
||||
|
||||
|
@ -954,6 +998,19 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
return this.folderPickerOptions_;
|
||||
}
|
||||
|
||||
onBodyViewerLoadEnd() {
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 1 });
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 0 });
|
||||
}, 50);
|
||||
}, 5);
|
||||
}
|
||||
|
||||
onBodyViewerCheckboxChange(newBody:string) {
|
||||
this.saveOneProperty('body', newBody);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
|
@ -971,65 +1028,39 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
return <CameraView themeId={this.props.themeId} style={{ flex: 1 }} onPhoto={this.cameraView_onPhoto} onCancel={this.cameraView_onCancel} />;
|
||||
}
|
||||
|
||||
// Currently keyword highlighting is supported only when FTS is available.
|
||||
const keywords = this.props.searchQuery && !!this.props.ftsEnabled ? this.props.highlightedWords : emptyArray;
|
||||
|
||||
let bodyComponent = null;
|
||||
if (this.state.mode == 'view' && !this.useBetaEditor()) {
|
||||
const onCheckboxChange = newBody => {
|
||||
this.saveOneProperty('body', newBody);
|
||||
};
|
||||
|
||||
// Currently keyword highlighting is supported only when FTS is available.
|
||||
let keywords = [];
|
||||
if (this.props.searchQuery && !!this.props.ftsEnabled) {
|
||||
keywords = this.props.highlightedWords;
|
||||
}
|
||||
|
||||
// Note: as of 2018-12-29 it's important not to display the viewer if the note body is empty,
|
||||
// to avoid the HACK_webviewLoadingState related bug.
|
||||
bodyComponent =
|
||||
!note || !note.body.trim() ? null : (
|
||||
<NoteBodyViewer
|
||||
onJoplinLinkClick={this.onJoplinLinkClick_}
|
||||
ref="noteBodyViewer"
|
||||
style={this.styles().noteBodyViewer}
|
||||
webViewStyle={theme}
|
||||
// Extra bottom padding to make it possible to scroll past the
|
||||
// action button (so that it doesn't overlap the text)
|
||||
paddingBottom="150"
|
||||
note={note}
|
||||
paddingBottom={150}
|
||||
noteBody={note.body}
|
||||
noteMarkupLanguage={note.markup_language}
|
||||
noteResources={this.state.noteResources}
|
||||
highlightedKeywords={keywords}
|
||||
themeId={this.props.themeId}
|
||||
noteHash={this.props.noteHash}
|
||||
onCheckboxChange={newBody => {
|
||||
onCheckboxChange(newBody);
|
||||
}}
|
||||
onCheckboxChange={this.onBodyViewerCheckboxChange}
|
||||
onMarkForDownload={this.onMarkForDownload}
|
||||
onLoadEnd={() => {
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 1 });
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 0 });
|
||||
}, 50);
|
||||
}, 5);
|
||||
}}
|
||||
onLoadEnd={this.onBodyViewerLoadEnd}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// autoFocus={fieldToFocus === 'body'}
|
||||
|
||||
// Currently keyword highlighting is supported only when FTS is available.
|
||||
let keywords = [];
|
||||
if (this.props.searchQuery && !!this.props.ftsEnabled) {
|
||||
keywords = this.props.highlightedWords;
|
||||
}
|
||||
|
||||
const onCheckboxChange = newBody => {
|
||||
this.saveOneProperty('body', newBody);
|
||||
};
|
||||
|
||||
bodyComponent = this.useBetaEditor()
|
||||
// Note: blurOnSubmit is necessary to get multiline to work.
|
||||
// See https://github.com/facebook/react-native/issues/12717#issuecomment-327001997
|
||||
//
|
||||
// 2020-10-16: As of React Native 0.63, the Markdown Editor no longer crashes in Android, however the
|
||||
// cursor is still too unreliable to be usable, so we disable it in Android.
|
||||
? <MarkdownEditor
|
||||
ref={this.markdownEditorRef} // For focusing the Markdown editor
|
||||
editorFont={editorFont(this.props.editorFont)}
|
||||
|
@ -1038,7 +1069,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
value={note.body}
|
||||
borderColor={this.styles().markdownButtons.borderColor}
|
||||
markdownButtonsColor={this.styles().markdownButtons.color}
|
||||
saveText={text => this.body_changeText(text)}
|
||||
saveText={(text:string) => this.body_changeText(text)}
|
||||
blurOnSubmit={false}
|
||||
selectionColor={theme.textSelectionColor}
|
||||
keyboardAppearance={theme.keyboardAppearance}
|
||||
|
@ -1046,29 +1077,18 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
placeholderTextColor={theme.colorFaded}
|
||||
noteBodyViewer={{
|
||||
onJoplinLinkClick: this.onJoplinLinkClick_,
|
||||
ref: 'noteBodyViewer',
|
||||
style: {
|
||||
...this.styles().noteBodyViewer,
|
||||
...this.styles().noteBodyViewerPreview,
|
||||
},
|
||||
style: this.styles().noteBodyViewerPreview,
|
||||
paddingBottom: 0,
|
||||
webViewStyle: theme,
|
||||
note: note,
|
||||
noteBody: note.body,
|
||||
noteMarkupLanguage: note.markup_language,
|
||||
noteResources: this.state.noteResources,
|
||||
highlightedKeywords: keywords,
|
||||
themeId: this.props.themeId,
|
||||
noteHash: this.props.noteHash,
|
||||
onCheckboxChange: newBody => {
|
||||
onCheckboxChange(newBody);
|
||||
},
|
||||
onCheckboxChange: this.onBodyViewerCheckboxChange,
|
||||
onMarkForDownload: this.onMarkForDownload,
|
||||
onLoadEnd: () => {
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 1 });
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 0 });
|
||||
}, 50);
|
||||
}, 5);
|
||||
},
|
||||
onLoadEnd: this.onBodyViewerLoadEnd,
|
||||
}}
|
||||
|
||||
/>
|
||||
|
@ -1095,7 +1115,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
ref="noteBodyTextField"
|
||||
multiline={true}
|
||||
value={note.body}
|
||||
onChangeText={(text) => this.body_changeText(text)}
|
||||
onChangeText={(text:string) => this.body_changeText(text)}
|
||||
onSelectionChange={this.body_selectionChange}
|
||||
blurOnSubmit={false}
|
||||
selectionColor={theme.textSelectionColor}
|
||||
|
@ -1178,10 +1198,10 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
{bodyComponent}
|
||||
{!this.useBetaEditor() && actionButtonComp}
|
||||
|
||||
<SelectDateTimeDialog shown={this.state.alarmDialogShown} date={dueDate} onAccept={this.onAlarmDialogAccept} onReject={this.onAlarmDialogReject} />
|
||||
<SelectDateTimeDialog themeId={this.props.themeId} shown={this.state.alarmDialogShown} date={dueDate} onAccept={this.onAlarmDialogAccept} onReject={this.onAlarmDialogReject} />
|
||||
|
||||
<DialogBox
|
||||
ref={dialogbox => {
|
||||
ref={(dialogbox:any) => {
|
||||
this.dialogbox = dialogbox;
|
||||
}}
|
||||
/>
|
||||
|
@ -1191,7 +1211,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
}
|
||||
}
|
||||
|
||||
const NoteScreen = connect(state => {
|
||||
const NoteScreen = connect((state:any) => {
|
||||
return {
|
||||
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||
noteHash: state.selectedNoteHash,
|
||||
|
@ -1209,4 +1229,4 @@ const NoteScreen = connect(state => {
|
|||
};
|
||||
})(NoteScreenComponent);
|
||||
|
||||
module.exports = { NoteScreen };
|
||||
export default NoteScreen;
|
|
@ -100,8 +100,8 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
|||
const exportPath = this.state.profileExportPath;
|
||||
const resourcePath = `${exportPath}/resources`;
|
||||
try {
|
||||
const hasPermissions = await checkPermissions(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
|
||||
if (!hasPermissions) {
|
||||
const response = await checkPermissions(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
|
||||
if (response !== PermissionsAndroid.RESULTS.GRANTED) {
|
||||
throw new Error('Permission denied');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import PopupDialog, { DialogTitle, DialogButton } from 'react-native-popup-dialog';
|
||||
import DatePicker from 'react-native-datepicker';
|
||||
import moment from 'moment';
|
||||
import { _ } from 'lib/locale.js';
|
||||
const { time } = require('lib/time-utils.js');
|
||||
|
||||
class SelectDateTimeDialog extends React.PureComponent {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.dialog_ = null;
|
||||
this.shown_ = false;
|
||||
this.state = { date: null };
|
||||
|
||||
this.onReject = this.onReject.bind(this);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps) {
|
||||
if (newProps.date != this.state.date) {
|
||||
this.setState({ date: newProps.date });
|
||||
}
|
||||
|
||||
if ('shown' in newProps && newProps.shown != this.shown_) {
|
||||
this.show(newProps.shown);
|
||||
}
|
||||
}
|
||||
|
||||
show(doShow = true) {
|
||||
if (doShow) {
|
||||
this.dialog_.show();
|
||||
} else {
|
||||
this.dialog_.dismiss();
|
||||
}
|
||||
|
||||
this.shown_ = doShow;
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.show(false);
|
||||
}
|
||||
|
||||
dateTimeFormat() {
|
||||
return time.dateTimeFormat();
|
||||
}
|
||||
|
||||
stringToDate(s) {
|
||||
return moment(s, this.dateTimeFormat()).toDate();
|
||||
}
|
||||
|
||||
onAccept() {
|
||||
if (this.props.onAccept) this.props.onAccept(this.state.date);
|
||||
}
|
||||
|
||||
onReject() {
|
||||
if (this.props.onReject) this.props.onReject();
|
||||
}
|
||||
|
||||
onClear() {
|
||||
if (this.props.onAccept) this.props.onAccept(null);
|
||||
}
|
||||
|
||||
render() {
|
||||
const clearAlarmText = _('Clear alarm'); // For unknown reasons, this particular string doesn't get translated if it's directly in the text property below
|
||||
|
||||
const popupActions = [
|
||||
<DialogButton text={_('Save alarm')} align="center" onPress={() => this.onAccept()} key="saveButton" />,
|
||||
<DialogButton text={clearAlarmText} align="center" onPress={() => this.onClear()} key="clearButton" />,
|
||||
<DialogButton text={_('Cancel')} align="center" onPress={() => this.onReject()} key="cancelButton" />,
|
||||
];
|
||||
|
||||
return (
|
||||
<PopupDialog
|
||||
ref={(dialog) => { this.dialog_ = dialog; }}
|
||||
dialogTitle={<DialogTitle title={_('Set alarm')} />}
|
||||
actions={popupActions}
|
||||
dismissOnTouchOutside={false}
|
||||
width={0.9}
|
||||
height={350}
|
||||
>
|
||||
<View style={{ flex: 1, margin: 20, alignItems: 'center' }}>
|
||||
<DatePicker
|
||||
date={this.state.date}
|
||||
mode="datetime"
|
||||
placeholder={_('Select date')}
|
||||
format={this.dateTimeFormat()}
|
||||
confirmBtnText={_('Confirm')}
|
||||
cancelBtnText={_('Cancel')}
|
||||
onDateChange={(date) => { this.setState({ date: this.stringToDate(date) }); }}
|
||||
style={{ width: 300 }}
|
||||
customStyles={{
|
||||
btnConfirm: {
|
||||
paddingVertical: 0,
|
||||
},
|
||||
btnCancel: {
|
||||
paddingVertical: 0,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</PopupDialog>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { SelectDateTimeDialog };
|
|
@ -237,7 +237,7 @@ class SideMenuContentComponent extends Component {
|
|||
|
||||
let iconWrapper = null;
|
||||
|
||||
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'md-arrow-dropdown' : 'md-arrow-dropup';
|
||||
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'md-arrow-down' : 'md-arrow-up';
|
||||
const iconComp = <Icon name={iconName} style={this.styles().folderIcon} />;
|
||||
|
||||
iconWrapper = !hasChildren ? null : (
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
// Use this to show which props have been changed within a component.
|
||||
//
|
||||
// Usage: usePropsDebugger(props);
|
||||
|
||||
import useEffectDebugger from './useEffectDebugger';
|
||||
|
||||
export default function usePropsDebugger(effectHook:any, props:any) {
|
||||
export default function usePropsDebugger(props:any) {
|
||||
const dependencies:any[] = [];
|
||||
const dependencyNames:string[] = [];
|
||||
|
||||
|
@ -9,5 +13,5 @@ export default function usePropsDebugger(effectHook:any, props:any) {
|
|||
dependencyNames.push(k);
|
||||
}
|
||||
|
||||
useEffectDebugger(effectHook, dependencies, dependencyNames);
|
||||
useEffectDebugger(() => {}, dependencies, dependencyNames);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,20 @@ const utils = require('./utils');
|
|||
const noteStyle = require('./noteStyle');
|
||||
const Setting = require('lib/models/Setting').default;
|
||||
const { themeStyle } = require('lib/theme');
|
||||
const memoryCache = require('memory-cache');
|
||||
const InMemoryCache = require('lib/InMemoryCache').default;
|
||||
const md5 = require('md5');
|
||||
|
||||
// Renderered notes can potentially be quite large (for example
|
||||
// when they come from the clipper) so keep the cache size
|
||||
// relatively small.
|
||||
const inMemoryCache = new InMemoryCache(10);
|
||||
|
||||
class HtmlToHtml {
|
||||
constructor(options) {
|
||||
if (!options) options = {};
|
||||
this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null;
|
||||
this.ResourceModel_ = options.ResourceModel;
|
||||
this.cache_ = new memoryCache.Cache();
|
||||
this.cache_ = inMemoryCache;
|
||||
this.fsDriver_ = {
|
||||
writeFile: (/* path, content, encoding = 'base64'*/) => { throw new Error('writeFile not set'); },
|
||||
exists: (/* path*/) => { throw new Error('exists not set'); },
|
||||
|
@ -55,7 +60,7 @@ class HtmlToHtml {
|
|||
}, options);
|
||||
|
||||
const cacheKey = md5(escape(markup));
|
||||
let html = this.cache_.get(cacheKey);
|
||||
let html = this.cache_.value(cacheKey);
|
||||
|
||||
if (!html) {
|
||||
html = htmlUtils.sanitizeHtml(markup);
|
||||
|
@ -80,7 +85,7 @@ class HtmlToHtml {
|
|||
});
|
||||
}
|
||||
|
||||
this.cache_.put(cacheKey, html, 1000 * 60 * 10);
|
||||
this.cache_.setValue(cacheKey, html, 1000 * 60 * 10);
|
||||
|
||||
if (options.bodyOnly) {
|
||||
return {
|
||||
|
|
|
@ -63,6 +63,11 @@ class MarkupToHtml {
|
|||
return output;
|
||||
}
|
||||
|
||||
clearCache(markupLanguage) {
|
||||
const r = this.renderer(markupLanguage);
|
||||
if (r.clearCache) r.clearCache();
|
||||
}
|
||||
|
||||
async render(markupLanguage, markup, theme, options) {
|
||||
return this.renderer(markupLanguage).render(markup, theme, options);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const MarkdownIt = require('markdown-it');
|
|||
const md5 = require('md5');
|
||||
const noteStyle = require('./noteStyle');
|
||||
const { fileExtension } = require('./pathUtils');
|
||||
const memoryCache = require('memory-cache');
|
||||
const InMemoryCache = require('lib/InMemoryCache').default;
|
||||
|
||||
// /!\/!\ Note: the order of rules is important!! /!\/!\
|
||||
const rules = {
|
||||
|
@ -44,6 +44,9 @@ function slugify(s) {
|
|||
return nodeSlug(s);
|
||||
}
|
||||
|
||||
// Share across all instances of MdToHtml
|
||||
const inMemoryCache = new InMemoryCache(20);
|
||||
|
||||
class MdToHtml {
|
||||
constructor(options = null) {
|
||||
if (!options) options = {};
|
||||
|
@ -57,7 +60,7 @@ class MdToHtml {
|
|||
this.cachedHighlightedCode_ = {};
|
||||
this.ResourceModel_ = options.ResourceModel;
|
||||
this.pluginOptions_ = options.pluginOptions ? options.pluginOptions : {};
|
||||
this.contextCache_ = new memoryCache.Cache();
|
||||
this.contextCache_ = inMemoryCache;
|
||||
|
||||
this.tempDir_ = options.tempDir;
|
||||
this.fsDriver_ = {
|
||||
|
@ -175,7 +178,11 @@ class MdToHtml {
|
|||
return html.substring(3, html.length - 5);
|
||||
}
|
||||
|
||||
// "style" here is really the theme, as returned by themeStyle()
|
||||
clearCache() {
|
||||
this.cachedOutputs_ = {};
|
||||
}
|
||||
|
||||
// "theme" is the theme as returned by themeStyle()
|
||||
async render(body, theme = null, options = null) {
|
||||
options = Object.assign({}, {
|
||||
// In bodyOnly mode, the rendered Markdown is returned without the wrapper DIV
|
||||
|
|
|
@ -16,7 +16,7 @@ function installRule(markdownIt:any, mdOptions:any, ruleOptions:any, context:any
|
|||
}
|
||||
|
||||
const cacheKey = md5(escape(token.content));
|
||||
let sanitizedContent = context.cache.get(cacheKey);
|
||||
let sanitizedContent = context.cache.value(cacheKey);
|
||||
|
||||
// For html_inline, the content is only a fragment of HTML, as it will be rendered, but
|
||||
// it's not necessarily valid HTML. For example this HTML:
|
||||
|
@ -37,7 +37,7 @@ function installRule(markdownIt:any, mdOptions:any, ruleOptions:any, context:any
|
|||
|
||||
token.content = sanitizedContent;
|
||||
|
||||
context.cache.put(cacheKey, sanitizedContent, 1000 * 60 * 60);
|
||||
context.cache.setValue(cacheKey, sanitizedContent, 1000 * 60 * 60);
|
||||
walkHtmlTokens(token.children);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -855,11 +855,6 @@
|
|||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"mermaid": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.8.1.tgz",
|
||||
|
@ -972,9 +967,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"slug": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/slug/-/slug-3.3.5.tgz",
|
||||
"integrity": "sha512-d/9yTbJDtSIhJThaNRP/U5uxwCl0mWIlV42JmKSfvg8t7DiVt69G8rAWTc0FWhaQOier0fiNAWVs7ctvVhK1RA=="
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/slug/-/slug-3.5.1.tgz",
|
||||
"integrity": "sha512-ei0JnJzg8HKhLunZy+vpNlILRRradfaAQ+p2YEI4b4r8yX/5TlFi1JSwcYQCg7INZxdTC43BT68rHMkRxzn7Xg=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mermaid": "^8.8.1",
|
||||
"slug": "^3.5.0"
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const BaseModel = require('lib/BaseModel.js');
|
|||
const Note = require('lib/models/Note.js');
|
||||
|
||||
export interface Notification {
|
||||
id: string,
|
||||
id: number,
|
||||
noteId: string,
|
||||
date: Date,
|
||||
title: string,
|
||||
|
|
|
@ -100,6 +100,9 @@ class OneDriveApi {
|
|||
const r = await shim.fetch(this.tokenBaseUrl(), {
|
||||
method: 'POST',
|
||||
body: body,
|
||||
headers: {
|
||||
['Content-Type']: 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
|
||||
if (!r.ok) {
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
const { time } = require('lib/time-utils.js');
|
||||
|
||||
class PoorManIntervals {
|
||||
static setInterval(callback, interval) {
|
||||
PoorManIntervals.intervalId_++;
|
||||
|
||||
PoorManIntervals.intervals_.push({
|
||||
id: PoorManIntervals.intervalId_,
|
||||
callback: callback,
|
||||
interval: interval,
|
||||
lastIntervalTime: time.unixMs(),
|
||||
});
|
||||
|
||||
return PoorManIntervals.intervalId_;
|
||||
}
|
||||
|
||||
static setTimeout(callback, interval) {
|
||||
PoorManIntervals.intervalId_++;
|
||||
|
||||
PoorManIntervals.intervals_.push({
|
||||
id: PoorManIntervals.intervalId_,
|
||||
callback: callback,
|
||||
interval: interval,
|
||||
lastIntervalTime: time.unixMs(),
|
||||
oneOff: true,
|
||||
});
|
||||
|
||||
return PoorManIntervals.intervalId_;
|
||||
}
|
||||
|
||||
static intervalById(id) {
|
||||
for (let i = 0; i < PoorManIntervals.intervals_.length; i++) {
|
||||
if (PoorManIntervals.intervals_[i].id == id) return PoorManIntervals.intervals_[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static clearInterval(id) {
|
||||
for (let i = 0; i < PoorManIntervals.intervals_.length; i++) {
|
||||
if (PoorManIntervals.intervals_[i].id == id) {
|
||||
PoorManIntervals.intervals_.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static update() {
|
||||
// Don't update more than once a second
|
||||
if (PoorManIntervals.lastUpdateTime_ + 1000 > time.unixMs()) return;
|
||||
|
||||
for (let i = 0; i < PoorManIntervals.intervals_.length; i++) {
|
||||
const interval = PoorManIntervals.intervals_[i];
|
||||
const now = time.unixMs();
|
||||
if (now - interval.lastIntervalTime >= interval.interval) {
|
||||
interval.lastIntervalTime = now;
|
||||
interval.callback();
|
||||
if (interval.oneOff) {
|
||||
this.clearInterval(interval.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PoorManIntervals.lastUpdateTime_ = time.unixMs();
|
||||
}
|
||||
}
|
||||
|
||||
PoorManIntervals.lastUpdateTime_ = 0;
|
||||
PoorManIntervals.intervalId_ = 0;
|
||||
PoorManIntervals.intervals_ = [];
|
||||
|
||||
module.exports = { PoorManIntervals };
|
|
@ -1,48 +1,67 @@
|
|||
import Logger from 'lib/Logger';
|
||||
import { Notification } from 'lib/models/Alarm';
|
||||
|
||||
const PushNotification = require('react-native-push-notification');
|
||||
const ReactNativeAN = require('react-native-alarm-notification').default;
|
||||
|
||||
export default class AlarmServiceDriver {
|
||||
|
||||
private PushNotification_:any = null;
|
||||
private logger_:Logger;
|
||||
|
||||
PushNotificationHandler_() {
|
||||
if (!this.PushNotification_) {
|
||||
PushNotification.configure({
|
||||
// (required) Called when a remote or local notification is opened or received
|
||||
onNotification: function(notification:any) {
|
||||
console.info('Notification was opened: ', notification);
|
||||
// process the notification
|
||||
},
|
||||
popInitialNotification: true,
|
||||
requestPermissions: true,
|
||||
});
|
||||
|
||||
this.PushNotification_ = PushNotification;
|
||||
}
|
||||
|
||||
return this.PushNotification_;
|
||||
constructor(logger:Logger) {
|
||||
this.logger_ = logger;
|
||||
}
|
||||
|
||||
hasPersistentNotifications() {
|
||||
public hasPersistentNotifications() {
|
||||
return true;
|
||||
}
|
||||
|
||||
notificationIsSet() {
|
||||
public notificationIsSet() {
|
||||
throw new Error('Available only for non-persistent alarms');
|
||||
}
|
||||
|
||||
async clearNotification(id:any) {
|
||||
return this.PushNotificationHandler_().cancelLocalNotifications({ id: `${id}` });
|
||||
public async clearNotification(id:number) {
|
||||
const alarm = await this.alarmByJoplinNotificationId(id);
|
||||
if (!alarm) return;
|
||||
|
||||
this.logger_.info('AlarmServiceDriver: Deleting alarm:', alarm);
|
||||
|
||||
await ReactNativeAN.deleteAlarm(alarm.id);
|
||||
}
|
||||
|
||||
async scheduleNotification(notification:Notification) {
|
||||
const config = {
|
||||
id: `${notification.id}`,
|
||||
message: notification.title,
|
||||
date: notification.date,
|
||||
// Returns -1 if could not be found
|
||||
private alarmJoplinAlarmId(alarm:any):number {
|
||||
if (!alarm.data) return -1;
|
||||
const m = alarm.data.match(/joplinNotificationId==>(\d+)/);
|
||||
return m ? Number(m[1]) : -1;
|
||||
}
|
||||
|
||||
private async alarmByJoplinNotificationId(joplinNotificationId:number) {
|
||||
const alarms:any[] = await ReactNativeAN.getScheduledAlarms();
|
||||
for (const alarm of alarms) {
|
||||
const id = this.alarmJoplinAlarmId(alarm);
|
||||
if (id === joplinNotificationId) return alarm;
|
||||
}
|
||||
|
||||
this.logger_.warn('AlarmServiceDriver: Could not find alarm that matches Joplin notification ID. It could be because it has already been triggered:', joplinNotificationId);
|
||||
return null;
|
||||
}
|
||||
|
||||
public async scheduleNotification(notification:Notification) {
|
||||
const alarmNotifData = {
|
||||
title: notification.title,
|
||||
message: notification.body ? notification.body : '-', // Required
|
||||
channel: 'net.cozic.joplin.notification',
|
||||
small_icon: 'ic_launcher',
|
||||
color: 'white',
|
||||
data: { joplinNotificationId: `${notification.id}` },
|
||||
};
|
||||
|
||||
this.PushNotificationHandler_().localNotificationSchedule(config);
|
||||
// ReactNativeAN expects a string as a date and it seems this utility
|
||||
// function converts it to the right format.
|
||||
const fireDate = ReactNativeAN.parseDate(notification.date);
|
||||
|
||||
const alarm = await ReactNativeAN.scheduleAlarm({ ...alarmNotifData, fire_date: fireDate });
|
||||
|
||||
this.logger_.info('AlarmServiceDriver: Created new alarm:', alarm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import { Notification } from 'lib/models/Alarm';
|
||||
import Logger from 'lib/Logger';
|
||||
const PushNotificationIOS = require('@react-native-community/push-notification-ios').default;
|
||||
|
||||
export default class AlarmServiceDriver {
|
||||
|
||||
private hasPermission_:boolean = null;
|
||||
private inAppNotificationHandler_:any = null;
|
||||
private logger_:Logger;
|
||||
|
||||
constructor() {
|
||||
constructor(logger:Logger) {
|
||||
this.logger_ = logger;
|
||||
PushNotificationIOS.addEventListener('localNotification', (instance:any) => {
|
||||
if (!this.inAppNotificationHandler_) return;
|
||||
|
||||
if (!instance || !instance._data || !instance._data.id) {
|
||||
console.warn('PushNotificationIOS.addEventListener: Did not receive a proper notification instance');
|
||||
this.logger_.warn('PushNotificationIOS.addEventListener: Did not receive a proper notification instance');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -57,7 +60,7 @@ export default class AlarmServiceDriver {
|
|||
return this.hasPermissions(newPerm);
|
||||
}
|
||||
|
||||
async clearNotification(id:any) {
|
||||
async clearNotification(id:number) {
|
||||
PushNotificationIOS.cancelLocalNotifications({ id: `${id}` });
|
||||
}
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ export default class AlarmServiceDriverNode {
|
|||
return false;
|
||||
}
|
||||
|
||||
notificationIsSet(id:string) {
|
||||
notificationIsSet(id:number) {
|
||||
return id in this.notifications_;
|
||||
}
|
||||
|
||||
async clearNotification(id:string) {
|
||||
async clearNotification(id:number) {
|
||||
if (!this.notificationIsSet(id)) return;
|
||||
shim.clearTimeout(this.notifications_[id].timeoutId);
|
||||
delete this.notifications_[id];
|
||||
|
|
|
@ -14,6 +14,7 @@ interface WatchedItem {
|
|||
lastResourceUpdatedTime: number,
|
||||
path:string,
|
||||
asyncSaveQueue: AsyncActionQueue,
|
||||
size: number,
|
||||
}
|
||||
|
||||
interface WatchedItems {
|
||||
|
@ -111,7 +112,12 @@ export default class ResourceEditWatcher {
|
|||
const stat = await shim.fsDriver().stat(path);
|
||||
const editedFileUpdatedTime = stat.mtime.getTime();
|
||||
|
||||
if (watchedItem.lastFileUpdatedTime === editedFileUpdatedTime) {
|
||||
// To check if the item has really changed we look at the updated time and size, which
|
||||
// in most cases is sufficient. It could be a problem if the editing tool is making a change
|
||||
// that neither changes the timestamp nor the file size. The alternative would be to compare
|
||||
// the files byte for byte but that could be slow and the file might have changed again by
|
||||
// the time we finished comparing.
|
||||
if (watchedItem.lastFileUpdatedTime === editedFileUpdatedTime && watchedItem.size === stat.size) {
|
||||
// chokidar is buggy and emits "change" events even when nothing has changed
|
||||
// so double-check the modified time and skip processing if there's no change.
|
||||
// In particular it emits two such events just after the file has been copied
|
||||
|
@ -121,13 +127,14 @@ export default class ResourceEditWatcher {
|
|||
// handle and once in the "raw" event handler, due to a bug in chokidar. So having
|
||||
// this check means we don't unecessarily save the resource twice when the file is
|
||||
// modified by the user.
|
||||
this.logger().debug(`ResourceEditWatcher: No timestamp change - skip: ${resourceId}`);
|
||||
this.logger().debug(`ResourceEditWatcher: No timestamp and file size change - skip: ${resourceId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger().debug(`ResourceEditWatcher: Queuing save action: ${resourceId}`);
|
||||
watchedItem.asyncSaveQueue.push(makeSaveAction(resourceId, path));
|
||||
watchedItem.lastFileUpdatedTime = editedFileUpdatedTime;
|
||||
watchedItem.size = stat.size;
|
||||
};
|
||||
|
||||
if (!this.watcher_) {
|
||||
|
@ -185,6 +192,7 @@ export default class ResourceEditWatcher {
|
|||
lastResourceUpdatedTime: 0,
|
||||
asyncSaveQueue: new AsyncActionQueue(1000),
|
||||
path: '',
|
||||
size: -1,
|
||||
};
|
||||
|
||||
this.watchedItems_[resourceId] = watchedItem;
|
||||
|
@ -200,6 +208,7 @@ export default class ResourceEditWatcher {
|
|||
watchedItem.path = editFilePath;
|
||||
watchedItem.lastFileUpdatedTime = stat.mtime.getTime();
|
||||
watchedItem.lastResourceUpdatedTime = resource.updated_time;
|
||||
watchedItem.size = stat.size;
|
||||
|
||||
this.watch(editFilePath);
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ const { PermissionsAndroid } = require('react-native');
|
|||
export default async (sharedData: SharedData, folderId: string, dispatch: Function) => {
|
||||
|
||||
if (!!sharedData.resources && sharedData.resources.length > 0) {
|
||||
const hasPermissions = await checkPermissions(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
|
||||
const response = await checkPermissions(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
|
||||
|
||||
if (!hasPermissions) {
|
||||
if (response !== PermissionsAndroid.RESULTS.GRANTED) {
|
||||
ToastAndroid.show('Cannot receive shared data - permission denied', ToastAndroid.SHORT);
|
||||
ShareExtension.close();
|
||||
return;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const shim = require('lib/shim').default;
|
||||
const { GeolocationReact } = require('lib/geolocation-react.js');
|
||||
const { PoorManIntervals } = require('lib/poor-man-intervals.js');
|
||||
const PoorManIntervals = require('lib/PoorManIntervals').default;
|
||||
const RNFetchBlob = require('rn-fetch-blob').default;
|
||||
const { generateSecureRandom } = require('react-native-securerandom');
|
||||
const FsDriverRN = require('lib/fs-driver-rn.js').FsDriverRN;
|
||||
|
@ -18,8 +18,6 @@ const injectedJs = {
|
|||
|
||||
function shimInit() {
|
||||
shim.Geolocation = GeolocationReact;
|
||||
shim.setInterval = PoorManIntervals.setInterval;
|
||||
shim.clearInterval = PoorManIntervals.clearInterval;
|
||||
shim.sjclModule = require('lib/vendor/sjcl-rn.js');
|
||||
|
||||
shim.fsDriver = () => {
|
||||
|
@ -46,6 +44,13 @@ function shimInit() {
|
|||
if (!validatedUrl) throw new Error(`Not a valid URL: ${url}`);
|
||||
|
||||
return shim.fetchWithRetry(() => {
|
||||
// If the request has a body and it's not a GET call, and it doesn't have a Content-Type header
|
||||
// we display a warning, because it could trigger a "Network request failed" error.
|
||||
// https://github.com/facebook/react-native/issues/30176
|
||||
if (options?.body && options?.method && options.method !== 'GET' && !options?.headers?.['Content-Type']) {
|
||||
console.warn('Done a non-GET fetch call without a Content-Type header. It may make the request fail.', url, options);
|
||||
}
|
||||
|
||||
return fetch(validatedUrl, options);
|
||||
}, options);
|
||||
};
|
||||
|
@ -199,19 +204,19 @@ function shimInit() {
|
|||
};
|
||||
|
||||
shim.setTimeout = (fn, interval) => {
|
||||
return setTimeout(fn, interval);
|
||||
return PoorManIntervals.setTimeout(fn, interval);
|
||||
};
|
||||
|
||||
shim.setInterval = (fn, interval) => {
|
||||
return setInterval(fn, interval);
|
||||
return PoorManIntervals.setInterval(fn, interval);
|
||||
};
|
||||
|
||||
shim.clearTimeout = (id) => {
|
||||
return clearTimeout(id);
|
||||
return PoorManIntervals.clearTimeout(id);
|
||||
};
|
||||
|
||||
shim.clearInterval = (id) => {
|
||||
return clearInterval(id);
|
||||
return PoorManIntervals.clearInterval(id);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,14 @@ class Time {
|
|||
this.timeFormat_ = v;
|
||||
}
|
||||
|
||||
use24HourFormat() {
|
||||
return this.timeFormat() ? this.timeFormat().includes('HH') : true;
|
||||
}
|
||||
|
||||
formatDateToLocal(date, format = null) {
|
||||
return this.formatMsToLocal(date.getTime(), format);
|
||||
}
|
||||
|
||||
dateTimeFormat() {
|
||||
return `${this.dateFormat()} ${this.timeFormat()}`;
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
// Note about the application structure:
|
||||
// - The user interface and its state is managed by React/Redux.
|
||||
// - Persistent storage to SQLite and Web API is handled outside of React/Redux using regular JavaScript (no middleware, no thunk, etc.).
|
||||
// - Communication from React to SQLite is done by calling model methods (note.save, etc.)
|
||||
// - Communication from SQLite to Redux is done via dispatcher.
|
||||
|
||||
// So there's basically still a one way flux: React => SQLite => Redux => React
|
||||
|
||||
// console.disableYellowBox = true
|
||||
|
||||
import { YellowBox, AppRegistry } from 'react-native';
|
||||
YellowBox.ignoreWarnings([
|
||||
'Require cycle: node_modules/react-native-',
|
||||
'Require cycle: node_modules/rn-fetch-blob',
|
||||
'Warning: componentWillReceiveProps has been renamed',
|
||||
'Warning: componentWillUpdate has been renamed',
|
||||
'Warning: componentWillMount has been renamed',
|
||||
]);
|
||||
const { Root } = require('./root.js');
|
||||
|
||||
// Disable buggy Fast Refresh
|
||||
// NOTE: not working - can make the app go into an infinite crash/restart loop
|
||||
// if (__DEV__) {
|
||||
// const { DevSettings } = NativeModules;
|
||||
// DevSettings.setHotLoadingEnabled(false);
|
||||
// DevSettings.setLiveReloadEnabled(false);
|
||||
// }
|
||||
|
||||
function main() {
|
||||
AppRegistry.registerComponent('Joplin', () => Root);
|
||||
console.ignoredYellowBox = ['Remote debugger'];
|
||||
// Note: The final part of the initialization process is in
|
||||
// AppComponent.componentDidMount(), when the application is ready.
|
||||
}
|
||||
|
||||
module.exports = { main };
|
|
@ -4,6 +4,7 @@
|
|||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
transformer: {
|
||||
getTransformOptions: async () => ({
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,18 +5,16 @@
|
|||
"version": "0.8.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start --reset-cache",
|
||||
"start-ios": "react-native run-ios",
|
||||
"start-android": "react-native run-android",
|
||||
"postinstall": "patch-package --patch-dir ../patches && jetify && npm run build",
|
||||
"start": "react-native start --reset-cache",
|
||||
"build": "gulp build",
|
||||
"log-ios": "react-native-log-ios \"Joplin\"",
|
||||
"log-android": "adb logcat *:S ReactNative:V ReactNativeJS:V"
|
||||
"postinstall": "patch-package --patch-dir ../patches/shared && jetify && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-community/clipboard": "^1.5.0",
|
||||
"@react-native-community/datetimepicker": "^3.0.3",
|
||||
"@react-native-community/geolocation": "^2.0.2",
|
||||
"@react-native-community/push-notification-ios": "^1.0.5",
|
||||
"@react-native-community/slider": "^2.0.8",
|
||||
"@react-native-community/push-notification-ios": "^1.6.0",
|
||||
"@react-native-community/slider": "^3.0.3",
|
||||
"async-mutex": "^0.1.3",
|
||||
"aws-sdk": "^2.588.0",
|
||||
"base-64": "^0.1.0",
|
||||
|
@ -48,7 +46,6 @@
|
|||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mermaid": "^8.8.1",
|
||||
"moment": "^2.24.0",
|
||||
"nanoid": "^3.1.12",
|
||||
|
@ -56,33 +53,30 @@
|
|||
"punycode": "^2.1.1",
|
||||
"query-string": "4.3.4",
|
||||
"re-reselect": "^4.0.0",
|
||||
"react": "16.9.0",
|
||||
"react": "16.13.1",
|
||||
"react-async": "^10.0.0",
|
||||
"react-native": "0.61.5",
|
||||
"react-native-action-button": "^2.6.9",
|
||||
"react-native-camera": "^2.10.2",
|
||||
"react-native-datepicker": "^1.6.0",
|
||||
"react-native-device-info": "^5.5.1",
|
||||
"react-native": "0.63.3",
|
||||
"react-native-action-button": "^2.8.5",
|
||||
"react-native-alarm-notification": "^1.7.1",
|
||||
"react-native-camera": "^3.40.0",
|
||||
"react-native-dialogbox": "^0.6.10",
|
||||
"react-native-document-picker": "^2.3.0",
|
||||
"react-native-document-picker": "^4.0.0",
|
||||
"react-native-dropdownalert": "^3.1.2",
|
||||
"react-native-file-viewer": "^1.0.15",
|
||||
"react-native-fs": "^2.11.17",
|
||||
"react-native-image-picker": "^0.26.7",
|
||||
"react-native-image-resizer": "^1.0.0",
|
||||
"react-native-log-ios": "^1.5.0",
|
||||
"react-native-material-dropdown": "^0.5.2",
|
||||
"react-native-popup-dialog": "^0.9.35",
|
||||
"react-native-file-viewer": "^2.1.4",
|
||||
"react-native-fs": "^2.16.6",
|
||||
"react-native-image-picker": "^2.3.4",
|
||||
"react-native-image-resizer": "^1.3.0",
|
||||
"react-native-modal-datetime-picker": "^9.0.0",
|
||||
"react-native-popup-dialog": "^0.9.41",
|
||||
"react-native-popup-menu": "^0.10.0",
|
||||
"react-native-push-notification": "git+https://github.com/laurent22/react-native-push-notification.git",
|
||||
"react-native-quick-actions": "^0.3.13",
|
||||
"react-native-securerandom": "^1.0.0-rc.0",
|
||||
"react-native-share": "^3.3.3",
|
||||
"react-native-share": "^4.0.2",
|
||||
"react-native-side-menu": "^1.1.3",
|
||||
"react-native-sqlite-storage": "^4.1.0",
|
||||
"react-native-vector-icons": "^6.6.0",
|
||||
"react-native-version-info": "^1.0.1",
|
||||
"react-native-webview": "^5.12.0",
|
||||
"react-native-sqlite-storage": "^5.0.0",
|
||||
"react-native-vector-icons": "^7.1.0",
|
||||
"react-native-version-info": "^1.1.0",
|
||||
"react-native-webview": "^10.9.2",
|
||||
"react-redux": "5.0.7",
|
||||
"redux": "4.0.0",
|
||||
"reselect": "^4.0.0",
|
||||
|
@ -100,15 +94,14 @@
|
|||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.2",
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"app-module-path": "^2.2.0",
|
||||
"execa": "^4.0.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"gulp": "^4.0.2",
|
||||
"jetifier": "^1.6.5",
|
||||
"metro-react-native-babel-preset": "^0.54.1",
|
||||
"patch-package": "^6.2.2",
|
||||
"react-test-renderer": "^16.8.3"
|
||||
"metro-react-native-babel-preset": "^0.63.0",
|
||||
"patch-package": "^6.2.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
module.exports = `LyoKCkF0b20gT25lIERhcmsgV2l0aCBzdXBwb3J0IGZvciBSZWFzb25NTCBieSBHaWRpIE1vcnJpcywgYmFzZWQgb2ZmIHdvcmsgYnkgRGFuaWVsIEdhbWFnZQoKT3JpZ2luYWwgT25lIERhcmsgU3ludGF4IHRoZW1lIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2F0b20vb25lLWRhcmstc3ludGF4CgoqLwouaGxqcyB7CiAgZGlzcGxheTogYmxvY2s7CiAgb3ZlcmZsb3cteDogYXV0bzsKICBwYWRkaW5nOiAwLjVlbTsKICBjb2xvcjogI2FiYjJiZjsKICBiYWNrZ3JvdW5kOiAjMjgyYzM0Owp9Ci5obGpzLWtleXdvcmQsIC5obGpzLW9wZXJhdG9yIHsKICBjb2xvcjogI0Y5MjY3MjsKfQouaGxqcy1wYXR0ZXJuLW1hdGNoIHsKICBjb2xvcjogI0Y5MjY3MjsKfQouaGxqcy1wYXR0ZXJuLW1hdGNoIC5obGpzLWNvbnN0cnVjdG9yIHsKICBjb2xvcjogIzYxYWVlZTsKfQouaGxqcy1mdW5jdGlvbiB7CiAgY29sb3I6ICM2MWFlZWU7Cn0KLmhsanMtZnVuY3Rpb24gLmhsanMtcGFyYW1zIHsKICBjb2xvcjogI0E2RTIyRTsKfQouaGxqcy1mdW5jdGlvbiAuaGxqcy1wYXJhbXMgLmhsanMtdHlwaW5nIHsKICBjb2xvcjogI0ZEOTcxRjsKfQouaGxqcy1tb2R1bGUtYWNjZXNzIC5obGpzLW1vZHVsZSB7CiAgY29sb3I6ICM3ZTU3YzI7Cn0KLmhsanMtY29uc3RydWN0b3IgewogIGNvbG9yOiAjZTJiOTNkOwp9Ci5obGpzLWNvbnN0cnVjdG9yIC5obGpzLXN0cmluZyB7CiAgY29sb3I6ICM5Q0NDNjU7Cn0KLmhsanMtY29tbWVudCwgLmhsanMtcXVvdGUgewogIGNvbG9yOiAjYjE4ZWIxOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQouaGxqcy1kb2N0YWcsIC5obGpzLWZvcm11bGEgewogIGNvbG9yOiAjYzY3OGRkOwp9Ci5obGpzLXNlY3Rpb24sIC5obGpzLW5hbWUsIC5obGpzLXNlbGVjdG9yLXRhZywgLmhsanMtZGVsZXRpb24sIC5obGpzLXN1YnN0IHsKICBjb2xvcjogI2UwNmM3NTsKfQouaGxqcy1saXRlcmFsIHsKICBjb2xvcjogIzU2YjZjMjsKfQouaGxqcy1zdHJpbmcsIC5obGpzLXJlZ2V4cCwgLmhsanMtYWRkaXRpb24sIC5obGpzLWF0dHJpYnV0ZSwgLmhsanMtbWV0YS1zdHJpbmcgewogIGNvbG9yOiAjOThjMzc5Owp9Ci5obGpzLWJ1aWx0X2luLCAuaGxqcy1jbGFzcyAuaGxqcy10aXRsZSB7CiAgY29sb3I6ICNlNmMwN2I7Cn0KLmhsanMtYXR0ciwgLmhsanMtdmFyaWFibGUsIC5obGpzLXRlbXBsYXRlLXZhcmlhYmxlLCAuaGxqcy10eXBlLCAuaGxqcy1zZWxlY3Rvci1jbGFzcywgLmhsanMtc2VsZWN0b3ItYXR0ciwgLmhsanMtc2VsZWN0b3ItcHNldWRvLCAuaGxqcy1udW1iZXIgewogIGNvbG9yOiAjZDE5YTY2Owp9Ci5obGpzLXN5bWJvbCwgLmhsanMtYnVsbGV0LCAuaGxqcy1saW5rLCAuaGxqcy1tZXRhLCAuaGxqcy1zZWxlY3Rvci1pZCwgLmhsanMtdGl0bGUgewogIGNvbG9yOiAjNjFhZWVlOwp9Ci5obGpzLWVtcGhhc2lzIHsKICBmb250LXN0eWxlOiBpdGFsaWM7Cn0KLmhsanMtc3Ryb25nIHsKICBmb250LXdlaWdodDogYm9sZDsKfQouaGxqcy1saW5rIHsKICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsKfQo=`;
|
|
@ -0,0 +1 @@
|
|||
module.exports = `LyoKCkF0b20gT25lIExpZ2h0IGJ5IERhbmllbCBHYW1hZ2UKT3JpZ2luYWwgT25lIExpZ2h0IFN5bnRheCB0aGVtZSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9hdG9tL29uZS1saWdodC1zeW50YXgKCmJhc2U6ICAgICNmYWZhZmEKbW9uby0xOiAgIzM4M2E0Mgptb25vLTI6ICAjNjg2Yjc3Cm1vbm8tMzogICNhMGExYTcKaHVlLTE6ICAgIzAxODRiYgpodWUtMjogICAjNDA3OGYyCmh1ZS0zOiAgICNhNjI2YTQKaHVlLTQ6ICAgIzUwYTE0ZgpodWUtNTogICAjZTQ1NjQ5Cmh1ZS01LTI6ICNjOTEyNDMKaHVlLTY6ICAgIzk4NjgwMQpodWUtNi0yOiAjYzE4NDAxCgoqLwoKLmhsanMgewogIGRpc3BsYXk6IGJsb2NrOwogIG92ZXJmbG93LXg6IGF1dG87CiAgcGFkZGluZzogMC41ZW07CiAgY29sb3I6ICMzODNhNDI7CiAgYmFja2dyb3VuZDogI2ZhZmFmYTsKfQoKLmhsanMtY29tbWVudCwKLmhsanMtcXVvdGUgewogIGNvbG9yOiAjYTBhMWE3OwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQoKLmhsanMtZG9jdGFnLAouaGxqcy1rZXl3b3JkLAouaGxqcy1mb3JtdWxhIHsKICBjb2xvcjogI2E2MjZhNDsKfQoKLmhsanMtc2VjdGlvbiwKLmhsanMtbmFtZSwKLmhsanMtc2VsZWN0b3ItdGFnLAouaGxqcy1kZWxldGlvbiwKLmhsanMtc3Vic3QgewogIGNvbG9yOiAjZTQ1NjQ5Owp9CgouaGxqcy1saXRlcmFsIHsKICBjb2xvcjogIzAxODRiYjsKfQoKLmhsanMtc3RyaW5nLAouaGxqcy1yZWdleHAsCi5obGpzLWFkZGl0aW9uLAouaGxqcy1hdHRyaWJ1dGUsCi5obGpzLW1ldGEtc3RyaW5nIHsKICBjb2xvcjogIzUwYTE0ZjsKfQoKLmhsanMtYnVpbHRfaW4sCi5obGpzLWNsYXNzIC5obGpzLXRpdGxlIHsKICBjb2xvcjogI2MxODQwMTsKfQoKLmhsanMtYXR0ciwKLmhsanMtdmFyaWFibGUsCi5obGpzLXRlbXBsYXRlLXZhcmlhYmxlLAouaGxqcy10eXBlLAouaGxqcy1zZWxlY3Rvci1jbGFzcywKLmhsanMtc2VsZWN0b3ItYXR0ciwKLmhsanMtc2VsZWN0b3ItcHNldWRvLAouaGxqcy1udW1iZXIgewogIGNvbG9yOiAjOTg2ODAxOwp9CgouaGxqcy1zeW1ib2wsCi5obGpzLWJ1bGxldCwKLmhsanMtbGluaywKLmhsanMtbWV0YSwKLmhsanMtc2VsZWN0b3ItaWQsCi5obGpzLXRpdGxlIHsKICBjb2xvcjogIzQwNzhmMjsKfQoKLmhsanMtZW1waGFzaXMgewogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQoKLmhsanMtc3Ryb25nIHsKICBmb250LXdlaWdodDogYm9sZDsKfQoKLmhsanMtbGluayB7CiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7Cn0K`;
|
|
@ -0,0 +1,29 @@
|
|||
module.exports = {
|
||||
hash:"0f24ccb2b0c004ee83a88554e1d7bf62", files: {
|
||||
'highlight.js/atom-one-dark-reasonable.css': { data: require('./highlight.js/atom-one-dark-reasonable.css.base64.js'), mime: 'text/css', encoding: 'base64' },
|
||||
'highlight.js/atom-one-light.css': { data: require('./highlight.js/atom-one-light.css.base64.js'), mime: 'text/css', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_AMS-Regular.woff2': { data: require('./katex/fonts/KaTeX_AMS-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Caligraphic-Bold.woff2': { data: require('./katex/fonts/KaTeX_Caligraphic-Bold.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Caligraphic-Regular.woff2': { data: require('./katex/fonts/KaTeX_Caligraphic-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Fraktur-Bold.woff2': { data: require('./katex/fonts/KaTeX_Fraktur-Bold.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Fraktur-Regular.woff2': { data: require('./katex/fonts/KaTeX_Fraktur-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Main-Bold.woff2': { data: require('./katex/fonts/KaTeX_Main-Bold.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Main-BoldItalic.woff2': { data: require('./katex/fonts/KaTeX_Main-BoldItalic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Main-Italic.woff2': { data: require('./katex/fonts/KaTeX_Main-Italic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Main-Regular.woff2': { data: require('./katex/fonts/KaTeX_Main-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Math-BoldItalic.woff2': { data: require('./katex/fonts/KaTeX_Math-BoldItalic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Math-Italic.woff2': { data: require('./katex/fonts/KaTeX_Math-Italic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_SansSerif-Bold.woff2': { data: require('./katex/fonts/KaTeX_SansSerif-Bold.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_SansSerif-Italic.woff2': { data: require('./katex/fonts/KaTeX_SansSerif-Italic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_SansSerif-Regular.woff2': { data: require('./katex/fonts/KaTeX_SansSerif-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Script-Regular.woff2': { data: require('./katex/fonts/KaTeX_Script-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Size1-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size1-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Size2-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size2-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Size3-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size3-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Size4-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size4-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_Typewriter-Regular.woff2': { data: require('./katex/fonts/KaTeX_Typewriter-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'katex/katex.css': { data: require('./katex/katex.css.base64.js'), mime: 'text/css', encoding: 'base64' },
|
||||
'mermaid/mermaid.min.js': { data: require('./mermaid/mermaid.min.js.base64.js'), mime: 'application/javascript', encoding: 'base64' },
|
||||
'mermaid/mermaid_render.js': { data: require('./mermaid/mermaid_render.js.base64.js'), mime: 'application/javascript', encoding: 'base64' },
|
||||
}
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue