You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-09-05 20:56:22 +02:00
Compare commits
2 Commits
android-v3
...
android-v1
Author | SHA1 | Date | |
---|---|---|---|
|
f9bf7550c6 | ||
|
108ba55939 |
@@ -200,6 +200,7 @@ ReactNativeClient/lib/commands/historyBackward.js
|
|||||||
ReactNativeClient/lib/commands/historyForward.js
|
ReactNativeClient/lib/commands/historyForward.js
|
||||||
ReactNativeClient/lib/commands/synchronize.js
|
ReactNativeClient/lib/commands/synchronize.js
|
||||||
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
||||||
|
ReactNativeClient/lib/components/SelectDateTimeDialog.js
|
||||||
ReactNativeClient/lib/errorUtils.js
|
ReactNativeClient/lib/errorUtils.js
|
||||||
ReactNativeClient/lib/eventManager.js
|
ReactNativeClient/lib/eventManager.js
|
||||||
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||||
@@ -217,6 +218,7 @@ ReactNativeClient/lib/markdownUtils.js
|
|||||||
ReactNativeClient/lib/models/Alarm.js
|
ReactNativeClient/lib/models/Alarm.js
|
||||||
ReactNativeClient/lib/models/Setting.js
|
ReactNativeClient/lib/models/Setting.js
|
||||||
ReactNativeClient/lib/ntpDate.js
|
ReactNativeClient/lib/ntpDate.js
|
||||||
|
ReactNativeClient/lib/PoorManIntervals.js
|
||||||
ReactNativeClient/lib/reducer.js
|
ReactNativeClient/lib/reducer.js
|
||||||
ReactNativeClient/lib/services/AlarmService.js
|
ReactNativeClient/lib/services/AlarmService.js
|
||||||
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
|
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -194,6 +194,7 @@ ReactNativeClient/lib/commands/historyBackward.js
|
|||||||
ReactNativeClient/lib/commands/historyForward.js
|
ReactNativeClient/lib/commands/historyForward.js
|
||||||
ReactNativeClient/lib/commands/synchronize.js
|
ReactNativeClient/lib/commands/synchronize.js
|
||||||
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
||||||
|
ReactNativeClient/lib/components/SelectDateTimeDialog.js
|
||||||
ReactNativeClient/lib/errorUtils.js
|
ReactNativeClient/lib/errorUtils.js
|
||||||
ReactNativeClient/lib/eventManager.js
|
ReactNativeClient/lib/eventManager.js
|
||||||
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||||
@@ -211,6 +212,7 @@ ReactNativeClient/lib/markdownUtils.js
|
|||||||
ReactNativeClient/lib/models/Alarm.js
|
ReactNativeClient/lib/models/Alarm.js
|
||||||
ReactNativeClient/lib/models/Setting.js
|
ReactNativeClient/lib/models/Setting.js
|
||||||
ReactNativeClient/lib/ntpDate.js
|
ReactNativeClient/lib/ntpDate.js
|
||||||
|
ReactNativeClient/lib/PoorManIntervals.js
|
||||||
ReactNativeClient/lib/reducer.js
|
ReactNativeClient/lib/reducer.js
|
||||||
ReactNativeClient/lib/services/AlarmService.js
|
ReactNativeClient/lib/services/AlarmService.js
|
||||||
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
|
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
|
||||||
|
3
ReactNativeClient/.gitattributes
vendored
3
ReactNativeClient/.gitattributes
vendored
@@ -1 +1,4 @@
|
|||||||
*.pbxproj -text
|
*.pbxproj -text
|
||||||
|
|
||||||
|
# specific for windows script files
|
||||||
|
*.bat text eol=crlf
|
||||||
|
@@ -15,7 +15,9 @@ import com.android.build.OutputFile
|
|||||||
* // the name of the generated asset file containing your JS bundle
|
* // the name of the generated asset file containing your JS bundle
|
||||||
* bundleAssetName: "index.android.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",
|
* entryFile: "index.android.js",
|
||||||
*
|
*
|
||||||
* // whether to bundle JS and assets in debug mode
|
* // whether to bundle JS and assets in debug mode
|
||||||
@@ -66,7 +68,6 @@ import com.android.build.OutputFile
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
project.ext.react = [
|
project.ext.react = [
|
||||||
entryFile: "index.android.js",
|
|
||||||
enableHermes: false, // clean and rebuild if changing
|
enableHermes: false, // clean and rebuild if changing
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -125,12 +126,13 @@ android {
|
|||||||
applicationId "net.cozic.joplin"
|
applicationId "net.cozic.joplin"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 2097583
|
versionCode 2097584
|
||||||
versionName "1.3.0"
|
versionName "1.3.1"
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||||
}
|
}
|
||||||
missingDimensionStrategy 'react-native-camera', 'general'
|
missingDimensionStrategy 'react-native-camera', 'general'
|
||||||
|
multiDexEnabled true
|
||||||
}
|
}
|
||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
@@ -168,6 +170,14 @@ android {
|
|||||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
pickFirst "lib/armeabi-v7a/libc++_shared.so"
|
||||||
|
pickFirst "lib/arm64-v8a/libc++_shared.so"
|
||||||
|
pickFirst "lib/x86/libc++_shared.so"
|
||||||
|
pickFirst "lib/x86_64/libc++_shared.so"
|
||||||
|
}
|
||||||
|
|
||||||
// applicationVariants are e.g. debug, release
|
// applicationVariants are e.g. debug, release
|
||||||
applicationVariants.all { variant ->
|
applicationVariants.all { variant ->
|
||||||
variant.outputs.each { output ->
|
variant.outputs.each { output ->
|
||||||
@@ -206,8 +216,20 @@ dependencies {
|
|||||||
implementation project(':react-native-fs')
|
implementation project(':react-native-fs')
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
implementation "com.android.support:appcompat-v7:28.0.0"
|
implementation "com.android.support:appcompat-v7:28.0.0"
|
||||||
|
//noinspection GradleDynamicVersion
|
||||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
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'
|
||||||
|
}
|
||||||
|
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
||||||
|
exclude group:'com.facebook.flipper'
|
||||||
|
}
|
||||||
|
|
||||||
if (enableHermes) {
|
if (enableHermes) {
|
||||||
def hermesPath = "../../node_modules/hermes-engine/android/";
|
def hermesPath = "../../node_modules/hermes-engine/android/";
|
||||||
debugImplementation files(hermesPath + "hermes-debug.aar")
|
debugImplementation files(hermesPath + "hermes-debug.aar")
|
||||||
|
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -96,7 +96,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@@ -8,6 +8,7 @@ import android.webkit.WebView;
|
|||||||
|
|
||||||
import com.facebook.react.PackageList;
|
import com.facebook.react.PackageList;
|
||||||
import com.facebook.react.ReactApplication;
|
import com.facebook.react.ReactApplication;
|
||||||
|
import com.facebook.react.ReactInstanceManager;
|
||||||
import com.facebook.react.ReactNativeHost;
|
import com.facebook.react.ReactNativeHost;
|
||||||
import com.facebook.react.ReactPackage;
|
import com.facebook.react.ReactPackage;
|
||||||
import com.facebook.soloader.SoLoader;
|
import com.facebook.soloader.SoLoader;
|
||||||
@@ -69,22 +70,27 @@ public class MainApplication extends Application implements ReactApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SoLoader.init(this, /* native exopackage */ false);
|
SoLoader.init(this, /* native exopackage */ false);
|
||||||
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
|
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 context
|
||||||
|
* @param reactInstanceManager
|
||||||
*/
|
*/
|
||||||
private static void initializeFlipper(Context context) {
|
private static void initializeFlipper(
|
||||||
|
Context context, ReactInstanceManager reactInstanceManager) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
We use reflection here to pick up the class that initializes Flipper,
|
We use reflection here to pick up the class that initializes Flipper,
|
||||||
since Flipper library is not available in release mode
|
since Flipper library is not available in release mode
|
||||||
*/
|
*/
|
||||||
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
|
Class<?> aClass = Class.forName("com.rndiffapp.ReactNativeFlipper");
|
||||||
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
|
aClass
|
||||||
|
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
||||||
|
.invoke(null, context, reactInstanceManager);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
|
@@ -2,17 +2,18 @@
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
buildToolsVersion = "28.0.3"
|
buildToolsVersion = "29.0.2"
|
||||||
minSdkVersion = 16
|
minSdkVersion = 16
|
||||||
compileSdkVersion = 28
|
compileSdkVersion = 29
|
||||||
targetSdkVersion = 28
|
targetSdkVersion = 29
|
||||||
|
kotlinVersion = "1.3.72"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:3.4.2")
|
classpath("com.android.tools.build:gradle:3.5.2")
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
@@ -36,7 +37,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://www.jitpack.io' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +47,8 @@ subprojects {
|
|||||||
afterEvaluate {project ->
|
afterEvaluate {project ->
|
||||||
if (project.hasProperty("android")) {
|
if (project.hasProperty("android")) {
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 29
|
||||||
buildToolsVersion "28.0.3"
|
buildToolsVersion "29.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,10 +17,14 @@
|
|||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
# org.gradle.parallel=true
|
# org.gradle.parallel=true
|
||||||
|
|
||||||
# Required for react-native-webview
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
# https://github.com/react-native-community/react-native-webview/blob/master/docs/Getting-Started.md
|
# 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
|
android.useAndroidX=true
|
||||||
|
# Automatically convert third-party libraries to use AndroidX
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
# Version of flipper SDK to use with React Native
|
||||||
|
FLIPPER_VERSION=0.33.1
|
||||||
|
|
||||||
# To fix this error:
|
# To fix this error:
|
||||||
# > java.io.UncheckedIOException: java.io.IOException: Execution of compression failed. java.lang.OutOfMemoryError
|
# > java.io.UncheckedIOException: java.io.IOException: Execution of compression failed. java.lang.OutOfMemoryError
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
6
ReactNativeClient/android/gradlew
vendored
6
ReactNativeClient/android/gradlew
vendored
@@ -7,7 +7,7 @@
|
|||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# 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
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
# 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\""
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if $cygwin ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
@@ -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 <React/RCTBridgeDelegate.h>
|
#import <React/RCTBridgeDelegate.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@@ -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 "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "RNQuickActionManager.h"
|
#import "RNQuickActionManager.h"
|
||||||
|
|
||||||
@@ -15,6 +6,25 @@
|
|||||||
#import <React/RCTRootView.h>
|
#import <React/RCTRootView.h>
|
||||||
#import <RNCPushNotificationIOS.h>
|
#import <RNCPushNotificationIOS.h>
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#import <FlipperKit/FlipperClient.h>
|
||||||
|
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
|
||||||
|
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
|
||||||
|
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
|
||||||
|
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
|
||||||
|
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.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
|
@implementation AppDelegate
|
||||||
|
|
||||||
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler {
|
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler {
|
||||||
@@ -23,6 +33,10 @@
|
|||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
InitializeFlipper(application);
|
||||||
|
#endif
|
||||||
|
|
||||||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
||||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||||
moduleName:@"Joplin"
|
moduleName:@"Joplin"
|
||||||
|
@@ -1,5 +1,47 @@
|
|||||||
platform :ios, '9.0'
|
platform :ios, '9.0'
|
||||||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||||
|
|
||||||
|
def add_flipper_pods!(versions = {})
|
||||||
|
versions['Flipper'] ||= '~> 0.33.1'
|
||||||
|
versions['DoubleConversion'] ||= '1.1.7'
|
||||||
|
versions['Flipper-Folly'] ||= '~> 2.1'
|
||||||
|
versions['Flipper-Glog'] ||= '0.3.6'
|
||||||
|
versions['Flipper-PeerTalk'] ||= '~> 0.0.4'
|
||||||
|
versions['Flipper-RSocket'] ||= '~> 1.0'
|
||||||
|
pod 'FlipperKit', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FlipperKitUserDefaultsPlugin', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FlipperKitReactPlugin', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
# List all transitive dependencies for FlipperKit pods
|
||||||
|
# to avoid them being linked in Release builds
|
||||||
|
pod 'Flipper', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'Flipper-DoubleConversion', versions['DoubleConversion'], :configuration => 'Debug'
|
||||||
|
pod 'Flipper-Folly', versions['Flipper-Folly'], :configuration => 'Debug'
|
||||||
|
pod 'Flipper-Glog', versions['Flipper-Glog'], :configuration => 'Debug'
|
||||||
|
pod 'Flipper-PeerTalk', versions['Flipper-PeerTalk'], :configuration => 'Debug'
|
||||||
|
pod 'Flipper-RSocket', versions['Flipper-RSocket'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/Core', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/CppBridge', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FBCxxFollyDynamicConvert', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FBDefines', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FKPortForwarding', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configuration => 'Debug'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Post Install processing for Flipper
|
||||||
|
def flipper_post_install(installer)
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
if target.name == 'YogaKit'
|
||||||
|
target.build_configurations.each do |config|
|
||||||
|
config.build_settings['SWIFT_VERSION'] = '4.1'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
target 'Joplin' do
|
target 'Joplin' do
|
||||||
# Pods for Joplin
|
# Pods for Joplin
|
||||||
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
|
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
|
||||||
@@ -24,20 +66,22 @@ target 'Joplin' do
|
|||||||
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
|
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
|
||||||
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
|
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
|
||||||
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
|
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
|
||||||
|
pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon"
|
||||||
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
|
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
|
||||||
pod 'ReactCommon/turbomodule/core', :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 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true
|
||||||
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
|
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 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
|
||||||
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
|
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
|
||||||
pod 'rn-fetch-blob', :path => '../node_modules/rn-fetch-blob'
|
pod 'rn-fetch-blob', :path => '../node_modules/rn-fetch-blob'
|
||||||
use_native_modules!
|
use_native_modules!
|
||||||
end
|
|
||||||
|
|
||||||
# target 'Joplin-tvOS' do
|
# Enables Flipper.
|
||||||
# # Pods for Joplin-tvOS
|
#
|
||||||
# target 'Joplin-tvOSTests' do
|
# Note that if you have use_frameworks! enabled, Flipper will not work and
|
||||||
# inherit! :search_paths
|
# you should disable these next few lines.
|
||||||
# # Pods for testing
|
add_flipper_pods!
|
||||||
# end
|
post_install do |installer|
|
||||||
# end
|
flipper_post_install(installer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
94
ReactNativeClient/lib/PoorManIntervals.ts
Normal file
94
ReactNativeClient/lib/PoorManIntervals.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
125
ReactNativeClient/lib/components/SelectDateTimeDialog.tsx
Normal file
125
ReactNativeClient/lib/components/SelectDateTimeDialog.tsx
Normal file
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -2,7 +2,8 @@ import FileViewer from 'react-native-file-viewer';
|
|||||||
import AsyncActionQueue from '../../AsyncActionQueue';
|
import AsyncActionQueue from '../../AsyncActionQueue';
|
||||||
|
|
||||||
const React = require('react');
|
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 } = require('react-native');
|
||||||
|
const Clipboard = require('@react-native-community/clipboard').default;
|
||||||
const { connect } = require('react-redux');
|
const { connect } = require('react-redux');
|
||||||
const uuid = require('lib/uuid').default;
|
const uuid = require('lib/uuid').default;
|
||||||
const { MarkdownEditor } = require('../../../MarkdownEditor/index.js');
|
const { MarkdownEditor } = require('../../../MarkdownEditor/index.js');
|
||||||
@@ -36,8 +37,8 @@ const { NoteBodyViewer } = require('lib/components/note-body-viewer.js');
|
|||||||
const { DocumentPicker, DocumentPickerUtil } = require('react-native-document-picker');
|
const { DocumentPicker, DocumentPickerUtil } = require('react-native-document-picker');
|
||||||
const ImageResizer = require('react-native-image-resizer').default;
|
const ImageResizer = require('react-native-image-resizer').default;
|
||||||
const shared = require('lib/components/shared/note-screen-shared.js');
|
const shared = require('lib/components/shared/note-screen-shared.js');
|
||||||
const ImagePicker = require('react-native-image-picker');
|
// const ImagePicker = require('react-native-image-picker');
|
||||||
const { SelectDateTimeDialog } = require('lib/components/select-date-time-dialog.js');
|
const SelectDateTimeDialog = require('lib/components/SelectDateTimeDialog').default;
|
||||||
const ShareExtension = require('lib/ShareExtension.js').default;
|
const ShareExtension = require('lib/ShareExtension.js').default;
|
||||||
const CameraView = require('lib/components/CameraView');
|
const CameraView = require('lib/components/CameraView');
|
||||||
const urlUtils = require('lib/urlUtils');
|
const urlUtils = require('lib/urlUtils');
|
||||||
@@ -507,13 +508,13 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showImagePicker(options) {
|
// showImagePicker(options) {
|
||||||
return new Promise((resolve) => {
|
// return new Promise((resolve) => {
|
||||||
ImagePicker.launchImageLibrary(options, response => {
|
// ImagePicker.launchImageLibrary(options, response => {
|
||||||
resolve(response);
|
// resolve(response);
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
async resizeImage(localFilePath, targetPath, mimeType) {
|
async resizeImage(localFilePath, targetPath, mimeType) {
|
||||||
const maxSize = Resource.IMAGE_MAX_DIMENSION;
|
const maxSize = Resource.IMAGE_MAX_DIMENSION;
|
||||||
@@ -665,10 +666,10 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
this.scheduleSave();
|
this.scheduleSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
async attachPhoto_onPress() {
|
// async attachPhoto_onPress() {
|
||||||
const response = await this.showImagePicker({ mediaType: 'photo', noData: true });
|
// const response = await this.showImagePicker({ mediaType: 'photo', noData: true });
|
||||||
await this.attachFile(response, 'image');
|
// await this.attachFile(response, 'image');
|
||||||
}
|
// }
|
||||||
|
|
||||||
takePhoto_onPress() {
|
takePhoto_onPress() {
|
||||||
this.setState({ showCamera: true });
|
this.setState({ showCamera: true });
|
||||||
@@ -817,10 +818,14 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
output.push({
|
output.push({
|
||||||
title: _('Attach...'),
|
title: _('Attach...'),
|
||||||
onPress: async () => {
|
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 buttonId = await dialogs.pop(this, _('Choose an option'), [
|
||||||
|
{ text: _('Attach file'), id: 'attachFile' },
|
||||||
|
{ text: _('Take photo'), id: 'takePhoto' },
|
||||||
|
// { text: _('Attach photo'), id: 'attachPhoto' },
|
||||||
|
]);
|
||||||
|
|
||||||
if (buttonId === 'takePhoto') this.takePhoto_onPress();
|
if (buttonId === 'takePhoto') this.takePhoto_onPress();
|
||||||
if (buttonId === 'attachPhoto') this.attachPhoto_onPress();
|
// if (buttonId === 'attachPhoto') this.attachPhoto_onPress();
|
||||||
if (buttonId === 'attachFile') this.attachFile_onPress();
|
if (buttonId === 'attachFile') this.attachFile_onPress();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1178,7 +1183,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
{bodyComponent}
|
{bodyComponent}
|
||||||
{!this.useBetaEditor() && actionButtonComp}
|
{!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
|
<DialogBox
|
||||||
ref={dialogbox => {
|
ref={dialogbox => {
|
||||||
|
@@ -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 };
|
|
@@ -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,6 +1,6 @@
|
|||||||
const shim = require('lib/shim').default;
|
const shim = require('lib/shim').default;
|
||||||
const { GeolocationReact } = require('lib/geolocation-react.js');
|
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 RNFetchBlob = require('rn-fetch-blob').default;
|
||||||
const { generateSecureRandom } = require('react-native-securerandom');
|
const { generateSecureRandom } = require('react-native-securerandom');
|
||||||
const FsDriverRN = require('lib/fs-driver-rn.js').FsDriverRN;
|
const FsDriverRN = require('lib/fs-driver-rn.js').FsDriverRN;
|
||||||
@@ -18,8 +18,6 @@ const injectedJs = {
|
|||||||
|
|
||||||
function shimInit() {
|
function shimInit() {
|
||||||
shim.Geolocation = GeolocationReact;
|
shim.Geolocation = GeolocationReact;
|
||||||
shim.setInterval = PoorManIntervals.setInterval;
|
|
||||||
shim.clearInterval = PoorManIntervals.clearInterval;
|
|
||||||
shim.sjclModule = require('lib/vendor/sjcl-rn.js');
|
shim.sjclModule = require('lib/vendor/sjcl-rn.js');
|
||||||
|
|
||||||
shim.fsDriver = () => {
|
shim.fsDriver = () => {
|
||||||
@@ -199,19 +197,19 @@ function shimInit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
shim.setTimeout = (fn, interval) => {
|
shim.setTimeout = (fn, interval) => {
|
||||||
return setTimeout(fn, interval);
|
return PoorManIntervals.setTimeout(fn, interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
shim.setInterval = (fn, interval) => {
|
shim.setInterval = (fn, interval) => {
|
||||||
return setInterval(fn, interval);
|
return PoorManIntervals.setInterval(fn, interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
shim.clearTimeout = (id) => {
|
shim.clearTimeout = (id) => {
|
||||||
return clearTimeout(id);
|
return PoorManIntervals.clearTimeout(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
shim.clearInterval = (id) => {
|
shim.clearInterval = (id) => {
|
||||||
return clearInterval(id);
|
return PoorManIntervals.clearInterval(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,10 @@ class Time {
|
|||||||
this.timeFormat_ = v;
|
this.timeFormat_ = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use24HourFormat() {
|
||||||
|
return this.timeFormat() ? this.timeFormat().includes('HH') : true;
|
||||||
|
}
|
||||||
|
|
||||||
dateTimeFormat() {
|
dateTimeFormat() {
|
||||||
return `${this.dateFormat()} ${this.timeFormat()}`;
|
return `${this.dateFormat()} ${this.timeFormat()}`;
|
||||||
}
|
}
|
||||||
@@ -79,6 +83,10 @@ class Time {
|
|||||||
return moment.unix(ms / 1000).format('HH:mm:ss');
|
return moment.unix(ms / 1000).format('HH:mm:ss');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formatDateToLocal(date, format = null) {
|
||||||
|
return this.formatMsToLocal(date.getTime(), format);
|
||||||
|
}
|
||||||
|
|
||||||
formatMsToLocal(ms, format = null) {
|
formatMsToLocal(ms, format = null) {
|
||||||
if (format === null) format = this.dateTimeFormat();
|
if (format === null) format = this.dateTimeFormat();
|
||||||
return moment(ms).format(format);
|
return moment(ms).format(format);
|
||||||
|
3513
ReactNativeClient/package-lock.json
generated
3513
ReactNativeClient/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,8 @@
|
|||||||
"log-android": "adb logcat *:S ReactNative:V ReactNativeJS:V"
|
"log-android": "adb logcat *:S ReactNative:V ReactNativeJS:V"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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/geolocation": "^2.0.2",
|
||||||
"@react-native-community/push-notification-ios": "^1.0.5",
|
"@react-native-community/push-notification-ios": "^1.0.5",
|
||||||
"@react-native-community/slider": "^2.0.8",
|
"@react-native-community/slider": "^2.0.8",
|
||||||
@@ -56,9 +58,9 @@
|
|||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
"query-string": "4.3.4",
|
"query-string": "4.3.4",
|
||||||
"re-reselect": "^4.0.0",
|
"re-reselect": "^4.0.0",
|
||||||
"react": "16.9.0",
|
"react": "16.11.0",
|
||||||
"react-async": "^10.0.0",
|
"react-async": "^10.0.0",
|
||||||
"react-native": "0.61.5",
|
"react-native": "0.62.2",
|
||||||
"react-native-action-button": "^2.6.9",
|
"react-native-action-button": "^2.6.9",
|
||||||
"react-native-camera": "^2.10.2",
|
"react-native-camera": "^2.10.2",
|
||||||
"react-native-datepicker": "^1.6.0",
|
"react-native-datepicker": "^1.6.0",
|
||||||
@@ -72,6 +74,7 @@
|
|||||||
"react-native-image-resizer": "^1.0.0",
|
"react-native-image-resizer": "^1.0.0",
|
||||||
"react-native-log-ios": "^1.5.0",
|
"react-native-log-ios": "^1.5.0",
|
||||||
"react-native-material-dropdown": "^0.5.2",
|
"react-native-material-dropdown": "^0.5.2",
|
||||||
|
"react-native-modal-datetime-picker": "^9.0.0",
|
||||||
"react-native-popup-dialog": "^0.9.35",
|
"react-native-popup-dialog": "^0.9.35",
|
||||||
"react-native-popup-menu": "^0.10.0",
|
"react-native-popup-menu": "^0.10.0",
|
||||||
"react-native-push-notification": "git+https://github.com/laurent22/react-native-push-notification.git",
|
"react-native-push-notification": "git+https://github.com/laurent22/react-native-push-notification.git",
|
||||||
@@ -106,8 +109,8 @@
|
|||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"jetifier": "^1.6.5",
|
"jetifier": "^1.6.5",
|
||||||
"metro-react-native-babel-preset": "^0.54.1",
|
"metro-react-native-babel-preset": "^0.58.0",
|
||||||
"patch-package": "^6.2.2",
|
"patch-package": "^6.2.2",
|
||||||
"react-test-renderer": "^16.8.3"
|
"react-test-renderer": "^16.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,7 @@ const { DatabaseDriverReactNative } = require('lib/database-driver-react-native'
|
|||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
const { setLocale, closestSupportedLocale, defaultLocale } = require('lib/locale');
|
const { setLocale, closestSupportedLocale, defaultLocale } = require('lib/locale');
|
||||||
const RNFetchBlob = require('rn-fetch-blob').default;
|
const RNFetchBlob = require('rn-fetch-blob').default;
|
||||||
const { PoorManIntervals } = require('lib/poor-man-intervals.js');
|
const PoorManIntervals = require('lib/PoorManIntervals').default;
|
||||||
const reducer = require('lib/reducer').default;
|
const reducer = require('lib/reducer').default;
|
||||||
const { defaultState } = require('lib/reducer');
|
const { defaultState } = require('lib/reducer');
|
||||||
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
||||||
|
Reference in New Issue
Block a user