1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-05 20:56:22 +02:00

Compare commits

...

2 Commits

Author SHA1 Message Date
Laurent Cozic
f9bf7550c6 Android release v1.3.1 2020-10-12 18:07:24 +01:00
Laurent Cozic
108ba55939 Upgrading to RN 62 2020-10-12 17:53:18 +01:00
24 changed files with 2103 additions and 2137 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -1 +1,4 @@
*.pbxproj -text *.pbxproj -text
# specific for windows script files
*.bat text eol=crlf

View File

@@ -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")

View File

@@ -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());
}
}
}
}

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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"
} }
} }
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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"`

View File

@@ -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>

View File

@@ -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"

View File

@@ -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

View 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();
}
}

View 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>
);
}
}

View File

@@ -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 => {

View File

@@ -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 };

View File

@@ -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 };

View File

@@ -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);
}; };
} }

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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"
} }
} }

View File

@@ -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');