mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
upgrade to react-native 0.69
This commit is contained in:
@@ -72,4 +72,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.170.0
|
||||
^0.176.3
|
||||
|
||||
2
apps/mobile/.gitignore
vendored
2
apps/mobile/.gitignore
vendored
@@ -23,8 +23,10 @@ DerivedData
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
*.hprof
|
||||
ios/.xcode.env.local
|
||||
# Android/IntelliJ
|
||||
#
|
||||
rn-build-deps/
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.7.4
|
||||
2.7.5
|
||||
@@ -1,4 +1,4 @@
|
||||
source 'https://rubygems.org'
|
||||
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
||||
ruby '2.7.4'
|
||||
ruby '2.7.5'
|
||||
gem 'cocoapods', '~> 1.11', '>= 1.11.2'
|
||||
@@ -12,6 +12,7 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
|
||||
@@ -47,7 +48,7 @@
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
|
||||
@@ -53,6 +53,13 @@ public class MainActivity extends ReactActivity {
|
||||
return reactRootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConcurrentRootEnabled() {
|
||||
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
|
||||
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadApp(String appKey) {
|
||||
RNBootSplash.init(getPlainActivity());
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.streetwriters.notesnook;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.RNFetchBlob.RNFetchBlob;
|
||||
import com.dooboolab.RNIap.RNIapModule;
|
||||
import com.facebook.react.PackageList;
|
||||
import com.facebook.react.ReactApplication;
|
||||
@@ -11,21 +9,18 @@ import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
//import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
//import com.facebook.react.modules.systeminfo.AndroidInfoHelpers;
|
||||
import com.facebook.react.TurboReactPackage;
|
||||
import com.facebook.react.module.model.ReactModuleInfo;
|
||||
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.learnium.RNDeviceInfo.RNDeviceModule;
|
||||
import com.oblador.keychain.KeychainPackage;
|
||||
import com.onibenjo.htmltopdf.RNHTMLtoPDFModule;
|
||||
import com.reactnativedocumentpicker.DocumentPickerModule;
|
||||
import com.vinzscam.reactnativefileviewer.RNFileViewerModule;
|
||||
@@ -33,8 +28,7 @@ import com.facebook.react.config.ReactFeatureFlags;
|
||||
import com.streetwriters.notesnook.newarchitecture.MainApplicationReactNativeHost;
|
||||
import cl.json.RNShareModule;
|
||||
import px.tooltips.RNTooltipsModule;
|
||||
import com.facebook.react.bridge.JSIModulePackage; // <- add
|
||||
import com.swmansion.reanimated.ReanimatedJSIModulePackage; // <- add
|
||||
//import io.csie.kudo.reactnative.v8.executor.V8ExecutorFactory;
|
||||
|
||||
public class MainApplication extends MultiDexApplication implements ReactApplication {
|
||||
|
||||
@@ -48,6 +42,15 @@ public class MainApplication extends MultiDexApplication implements ReactApplica
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
|
||||
// return new V8ExecutorFactory(
|
||||
// getApplicationContext(),
|
||||
// getPackageName(),
|
||||
// AndroidInfoHelpers.getFriendlyDeviceName(),
|
||||
// getUseDeveloperSupport());
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
@@ -104,10 +107,6 @@ public class MainApplication extends MultiDexApplication implements ReactApplica
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@Override protected JSIModulePackage getJSIModulePackage() {
|
||||
return new ReanimatedJSIModulePackage(); // <- add
|
||||
}
|
||||
};
|
||||
|
||||
public ReactModuleInfo getModuleInfo(String reactClass, String className) {
|
||||
|
||||
@@ -16,7 +16,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.fabric.ComponentFactory;
|
||||
import com.facebook.react.fabric.CoreComponentsRegistry;
|
||||
import com.facebook.react.fabric.EmptyReactNativeConfig;
|
||||
import com.facebook.react.fabric.FabricJSIModuleProvider;
|
||||
import com.facebook.react.uimanager.ViewManagerRegistry;
|
||||
import com.streetwriters.notesnook.BuildConfig;
|
||||
@@ -24,6 +23,7 @@ import com.streetwriters.notesnook.newarchitecture.components.MainComponentsRegi
|
||||
import com.streetwriters.notesnook.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.facebook.react.fabric.ReactNativeConfig;
|
||||
|
||||
/**
|
||||
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
|
||||
@@ -105,7 +105,7 @@ public class MainApplicationReactNativeHost extends ReactNativeHost {
|
||||
return new FabricJSIModuleProvider(
|
||||
reactApplicationContext,
|
||||
componentFactory,
|
||||
new EmptyReactNativeConfig(),
|
||||
ReactNativeConfig.DEFAULT_CONFIG,
|
||||
viewManagerRegistry);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_PATH := $(THIS_DIR)
|
||||
|
||||
# You can customize the name of your application .so file here.
|
||||
LOCAL_MODULE := rndiffapp_appmodules
|
||||
LOCAL_MODULE := notesnook_appmodules
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
|
||||
@@ -28,8 +28,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libfabricjni \
|
||||
libfbjni \
|
||||
libfolly_futures \
|
||||
libfolly_json \
|
||||
libfolly_runtime \
|
||||
libglog \
|
||||
libjsi \
|
||||
libreact_codegen_rncore \
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowDisablePreview">true</item>
|
||||
<item name="android:editTextBackground">@drawable/edit_text</item>
|
||||
|
||||
<!-- Allow drawing under the system bars background -->
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:fitsSystemWindows">false</item>
|
||||
|
||||
<!-- Set system bars background transparent -->
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
|
||||
<!-- Disable auto contrasted system bars background (on Android 10+) -->
|
||||
<item name="android:enforceStatusBarContrast" tools:targetApi="q">false</item>
|
||||
<item name="android:enforceNavigationBarContrast" tools:targetApi="q">false</item>
|
||||
</style>
|
||||
|
||||
<style name="Share.Window" parent="Theme.AppCompat">
|
||||
<item name="android:windowEnterAnimation">@null</item>
|
||||
<item name="android:windowExitAnimation">@null</item>
|
||||
<item name="android:editTextBackground">@drawable/edit_text</item>
|
||||
</style>
|
||||
|
||||
<!-- BootTheme should inherit from Theme.SplashScreen -->
|
||||
<style name="BootTheme" parent="Theme.SplashScreen">
|
||||
<item name="windowSplashScreenBackground">@color/bootsplash_background</item>
|
||||
<item name="windowSplashScreenAnimatedIcon">@mipmap/bootsplash_logo</item>
|
||||
<item name="postSplashScreenTheme">@style/AppTheme</item>
|
||||
</style>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
|
||||
<style name="AppThemeB" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:backgroundDimEnabled">true</item>
|
||||
<item name="android:editTextBackground">@drawable/edit_text</item>
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -2,15 +2,9 @@
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<!-- Allow drawing under the system bars background -->
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:fitsSystemWindows">false</item>
|
||||
|
||||
<!-- Set status bar background transparent -->
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
|
||||
<!-- Navigation bar will stay translucent on Android < 8.1 -->
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowDisablePreview">true</item>
|
||||
<item name="android:editTextBackground">@drawable/edit_text</item>
|
||||
</style>
|
||||
|
||||
<style name="Share.Window" parent="Theme.AppCompat">
|
||||
|
||||
@@ -6,5 +6,7 @@ include ':app'
|
||||
includeBuild('../node_modules/react-native-gradle-plugin')
|
||||
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
|
||||
include(":ReactAndroid")
|
||||
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
|
||||
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid');
|
||||
include(":ReactAndroid:hermes-engine")
|
||||
project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
|
||||
}
|
||||
|
||||
10
apps/mobile/ios/.xcode.env
Normal file
10
apps/mobile/ios/.xcode.env
Normal file
@@ -0,0 +1,10 @@
|
||||
# This `.xcode.env` file is versioned and is used to source the environment
|
||||
# used when running script phases inside Xcode.
|
||||
# To customize your local environment, you can create an `.xcode.env.local`
|
||||
# file that is not versioned.
|
||||
# NODE_BINARY variable contains the PATH to the node executable.
|
||||
#
|
||||
# Customize the NODE_BINARY variable here.
|
||||
# For example, to use nvm with brew, add the following line
|
||||
# . "$(brew --prefix nvm)/nvm.sh" --no-use
|
||||
export NODE_BINARY=$(command -v node)
|
||||
@@ -1077,7 +1077,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1809;
|
||||
CURRENT_PROJECT_VERSION = 1810;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
@@ -1150,7 +1150,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.8.9;
|
||||
MARKETING_VERSION = 1.8.10;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1179,7 +1179,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Notesnook/Notesnook.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1809;
|
||||
CURRENT_PROJECT_VERSION = 1810;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
@@ -1251,7 +1251,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.8.9;
|
||||
MARKETING_VERSION = 1.8.10;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1409,7 +1409,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1809;
|
||||
CURRENT_PROJECT_VERSION = 1810;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -1420,7 +1420,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.8.9;
|
||||
MARKETING_VERSION = 1.8.10;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1450,7 +1450,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1809;
|
||||
CURRENT_PROJECT_VERSION = 1810;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -1461,7 +1461,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.8.9;
|
||||
MARKETING_VERSION = 1.8.10;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1490,7 +1490,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1809;
|
||||
CURRENT_PROJECT_VERSION = 1810;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -1563,7 +1563,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.8.9;
|
||||
MARKETING_VERSION = 1.8.10;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1593,7 +1593,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1809;
|
||||
CURRENT_PROJECT_VERSION = 1810;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.8.9;
|
||||
MARKETING_VERSION = 1.8.10;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
|
||||
#import <react/config/ReactNativeConfig.h>
|
||||
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
|
||||
|
||||
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
|
||||
RCTTurboModuleManager *_turboModuleManager;
|
||||
@@ -70,8 +71,9 @@ RCTBridge *bridge;
|
||||
shareViewController.view = shareView;
|
||||
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:shareView];
|
||||
} else {
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"Notesnook" initialProperties:nil];
|
||||
NSDictionary *initProps = [self prepareInitialProps];
|
||||
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"Notesnook" , initProps);
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
rootView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
} else {
|
||||
@@ -87,6 +89,25 @@ RCTBridge *bridge;
|
||||
return YES;
|
||||
}
|
||||
|
||||
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
|
||||
///
|
||||
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
|
||||
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
|
||||
- (BOOL)concurrentRootEnabled
|
||||
{
|
||||
// Switch this bool to turn on and off the concurrent root
|
||||
return false;
|
||||
}
|
||||
- (NSDictionary *)prepareInitialProps
|
||||
{
|
||||
NSMutableDictionary *initProps = [NSMutableDictionary new];
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
|
||||
#endif
|
||||
return initProps;
|
||||
}
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
#if DEBUG
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require_relative '../node_modules/react-native/scripts/react_native_pods'
|
||||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||
|
||||
platform :ios, '11.0'
|
||||
platform :ios, '12.4'
|
||||
install! 'cocoapods', :deterministic_uuids => false
|
||||
|
||||
pod 'Base64'
|
||||
|
||||
0
apps/mobile/new.js
Normal file
0
apps/mobile/new.js
Normal file
@@ -1,56 +0,0 @@
|
||||
diff --git a/node_modules/react-native-cli-bump-version/lib/index.js b/node_modules/react-native-cli-bump-version/lib/index.js
|
||||
index a319832..a6710aa 100644
|
||||
--- a/node_modules/react-native-cli-bump-version/lib/index.js
|
||||
+++ b/node_modules/react-native-cli-bump-version/lib/index.js
|
||||
@@ -94,6 +94,14 @@ class BuildGradleManager extends BaseFileManager {
|
||||
return { current, next };
|
||||
}
|
||||
}
|
||||
+
|
||||
+class VersionManager extends BaseFileManager {
|
||||
+
|
||||
+ setVersionCode(code) {
|
||||
+ this.content = `export const APP_VERSION=${code};`;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
class PackageJSONManager {
|
||||
constructor(basePath) {
|
||||
this.content = null;
|
||||
@@ -122,6 +130,8 @@ class PackageJSONManager {
|
||||
};
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
class ProjectFilesManager {
|
||||
constructor(configs) {
|
||||
const { root, pbxprojPath, buildGradlePath } = configs;
|
||||
@@ -129,7 +139,9 @@ class ProjectFilesManager {
|
||||
this.buildGradle = new BuildGradleManager(buildGradlePath);
|
||||
this.pbx = new PBXManager(pbxprojPath);
|
||||
this.packageJSON = new PackageJSONManager(path_1.default.join(root, 'package.json'));
|
||||
+ this.versionManager = new VersionManager(path_1.default.join(root, 'version.js'));
|
||||
}
|
||||
+
|
||||
syncSemver(semverString) {
|
||||
const { skipSemVerFor } = this.configs;
|
||||
if (!skipSemVerFor.includes('ios')) {
|
||||
@@ -151,14 +163,17 @@ class ProjectFilesManager {
|
||||
}
|
||||
if (!skipCodeFor.includes('android')) {
|
||||
const { next: gradleNext, current: gradleCurrent } = this.buildGradle.bumpCode();
|
||||
+ this.versionManager.setVersionCode(gradleNext);
|
||||
console.log(success(`Android build.gradle code: ${gradleCurrent} -> ${gradleNext}`));
|
||||
}
|
||||
+
|
||||
}
|
||||
run() {
|
||||
this.dryRun();
|
||||
this.pbx.write();
|
||||
this.buildGradle.write();
|
||||
this.packageJSON.write();
|
||||
+ this.versionManager.write();
|
||||
}
|
||||
/**
|
||||
* Separated for testing
|
||||
@@ -0,0 +1,22 @@
|
||||
diff --git a/node_modules/react-native-cli-bump-version/react-native.config.js b/node_modules/react-native-cli-bump-version/react-native.config.js
|
||||
index fe5274e..6197368 100644
|
||||
--- a/node_modules/react-native-cli-bump-version/react-native.config.js
|
||||
+++ b/node_modules/react-native-cli-bump-version/react-native.config.js
|
||||
@@ -10,16 +10,14 @@ module.exports = {
|
||||
console.log("My work here is done.");
|
||||
return;
|
||||
}
|
||||
-
|
||||
const appGradlePath = path.join(
|
||||
config.project.android.sourceDir,
|
||||
config.project.android.appName,
|
||||
"build.gradle",
|
||||
);
|
||||
-
|
||||
versioner({
|
||||
root: config.root,
|
||||
- pbxprojPath: config.project.ios.pbxprojPath,
|
||||
+ pbxprojPath: `${config.project.ios.sourceDir}/${config.project.ios.xcodeProject.name.replace(".xcworkspace",".xcodeproj")}/project.pbxproj`,
|
||||
buildGradlePath: appGradlePath,
|
||||
type: args.type,
|
||||
semver: args.semver,
|
||||
421
apps/mobile/patches/react-native-reanimated+2.8.0.patch
Normal file
421
apps/mobile/patches/react-native-reanimated+2.8.0.patch
Normal file
@@ -0,0 +1,421 @@
|
||||
diff --git a/node_modules/react-native-reanimated/android/CMakeLists.txt b/node_modules/react-native-reanimated/android/CMakeLists.txt
|
||||
index e6ff5f2..945b1fb 100644
|
||||
--- a/node_modules/react-native-reanimated/android/CMakeLists.txt
|
||||
+++ b/node_modules/react-native-reanimated/android/CMakeLists.txt
|
||||
@@ -1,3 +1,4 @@
|
||||
+project(Reanimated)
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
|
||||
set (CMAKE_VERBOSE_MAKEFILE ON)
|
||||
@@ -13,6 +14,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
|
||||
|
||||
set (PACKAGE_NAME "reanimated")
|
||||
+set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
|
||||
set (SRC_DIR ${CMAKE_SOURCE_DIR}/src)
|
||||
|
||||
if(${CLIENT_SIDE_BUILD})
|
||||
@@ -119,26 +121,18 @@ find_library(
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
-find_library(
|
||||
- FOLLY_JSON_LIB
|
||||
- folly_json
|
||||
- PATHS ${LIBRN_DIR}
|
||||
- NO_CMAKE_FIND_ROOT_PATH
|
||||
-)
|
||||
find_library(
|
||||
REACT_NATIVE_JNI_LIB
|
||||
reactnativejni
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
-
|
||||
find_library(
|
||||
GLOG_LIB
|
||||
glog
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
-
|
||||
find_library(
|
||||
FBJNI_LIB
|
||||
fbjni
|
||||
@@ -146,6 +140,22 @@ find_library(
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
|
||||
+if(${REACT_NATIVE_TARGET_VERSION} LESS 69)
|
||||
+ find_library(
|
||||
+ FOLLY_LIB
|
||||
+ folly_json
|
||||
+ PATHS ${LIBRN_DIR}
|
||||
+ NO_CMAKE_FIND_ROOT_PATH
|
||||
+ )
|
||||
+else()
|
||||
+ find_library(
|
||||
+ FOLLY_LIB
|
||||
+ folly_runtime
|
||||
+ PATHS ${LIBRN_DIR}
|
||||
+ NO_CMAKE_FIND_ROOT_PATH
|
||||
+ )
|
||||
+endif()
|
||||
+
|
||||
if(${REACT_NATIVE_TARGET_VERSION} LESS 66)
|
||||
set (JSI_LIB "")
|
||||
else()
|
||||
@@ -169,7 +179,7 @@ if(${FOR_HERMES})
|
||||
${HERMES_LIB}
|
||||
${GLOG_LIB}
|
||||
${FBJNI_LIB}
|
||||
- ${FOLLY_JSON_LIB}
|
||||
+ ${FOLLY_LIB}
|
||||
${REACT_NATIVE_JNI_LIB}
|
||||
android
|
||||
)
|
||||
@@ -181,7 +191,7 @@ else()
|
||||
${JSEXECUTOR_LIB}
|
||||
${GLOG_LIB}
|
||||
${FBJNI_LIB}
|
||||
- ${FOLLY_JSON_LIB}
|
||||
+ ${FOLLY_LIB}
|
||||
${REACT_NATIVE_JNI_LIB}
|
||||
android
|
||||
)
|
||||
diff --git a/node_modules/react-native-reanimated/android/build.gradle b/node_modules/react-native-reanimated/android/build.gradle
|
||||
index cc460da..23f491e 100644
|
||||
--- a/node_modules/react-native-reanimated/android/build.gradle
|
||||
+++ b/node_modules/react-native-reanimated/android/build.gradle
|
||||
@@ -1,10 +1,8 @@
|
||||
+import com.android.Version
|
||||
+
|
||||
import java.nio.file.Paths
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
-
|
||||
-import java.util.regex.Matcher
|
||||
-import java.util.regex.Pattern
|
||||
import groovy.json.JsonSlurper
|
||||
-import java.util.zip.ZipFile
|
||||
|
||||
/**
|
||||
* Finds the path of the installed npm package with the given name using Node's
|
||||
@@ -45,18 +43,6 @@ def safeExtGet(prop, fallback) {
|
||||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||
}
|
||||
|
||||
-def getCurrentFlavor() {
|
||||
- String taskRequestName = getGradle().getStartParameter().getTaskRequests().toString()
|
||||
- Pattern pattern = Pattern.compile("(assemble|bundle|install|generate)(\\w*)(Release|Debug)")
|
||||
- Matcher matcher = pattern.matcher(taskRequestName)
|
||||
-
|
||||
- if (matcher.find()) {
|
||||
- return matcher.group(2)
|
||||
- }
|
||||
-
|
||||
- return "NOT-FOUND"
|
||||
-}
|
||||
-
|
||||
def resolveBuildType() {
|
||||
def buildType = System.getenv("CLIENT_SIDE_BUILD")
|
||||
if (buildType != null) {
|
||||
@@ -86,127 +72,6 @@ def resolveReactNativeDirectory() {
|
||||
return file("$projectDir/../../react-native")
|
||||
}
|
||||
|
||||
-abstract class replaceSoTask extends DefaultTask {
|
||||
- public static String appName = ":app"
|
||||
- public static String buildDir = "../../../android/app/build"
|
||||
- public static String fbjniVersion = "0.3.0"
|
||||
-
|
||||
- @TaskAction
|
||||
- def run() {
|
||||
- def libSoDir = new File("${buildDir}/tmp/libSo")
|
||||
- if (!libSoDir.exists()) {
|
||||
- libSoDir.mkdirs()
|
||||
- def fbjniUrl = "https://repo1.maven.org/maven2/com/facebook/fbjni/fbjni/${fbjniVersion}/fbjni-${fbjniVersion}.aar"
|
||||
- def aarFile = new File("${libSoDir.path}/fbjni-${fbjniVersion}.aar")
|
||||
- aarFile.createNewFile()
|
||||
- aarFile.withOutputStream { out ->
|
||||
- def url = new URL(fbjniUrl).openConnection()
|
||||
- out << url.inputStream
|
||||
- }
|
||||
- if (!aarFile.exists()) {
|
||||
- println("Unable to find ${libSoDir.path}/fbjni-${fbjniVersion}.aar")
|
||||
- return
|
||||
- }
|
||||
- def zipFile = new ZipFile(new File("${libSoDir.path}/fbjni-${fbjniVersion}.aar"))
|
||||
- zipFile.entries().each {
|
||||
- def zipIt = it
|
||||
- if (zipIt.name.contains("libfbjni.so")) {
|
||||
- new File("${libSoDir.path}/" + zipIt.name.replace("/libfbjni.so", "")).mkdirs()
|
||||
- new File("${libSoDir.path}/" + zipIt.name).withOutputStream{
|
||||
- it << zipFile.getInputStream(zipIt)
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- for(def abiVersion in ["x86", "x86_64", "armeabi-v7a", "arm64-v8a"]) {
|
||||
- ant.sequential {
|
||||
- copy(
|
||||
- tofile: "${buildDir}/intermediates/merged_native_libs/debug/out/lib/${abiVersion}/libfbjni.so",
|
||||
- file: "${buildDir}/tmp/libSo/jni/${abiVersion}/libfbjni.so",
|
||||
- overwrite: true
|
||||
- )
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-def detectAAR(minor, engine) {
|
||||
- def rnMinorVersionCopy = Integer.parseInt(minor)
|
||||
- def aar = file("react-native-reanimated-${rnMinorVersionCopy}-${engine}.aar")
|
||||
-
|
||||
- if (aar.exists()) {
|
||||
- println "AAR for react-native-reanimated has been found\n$aar"
|
||||
- return aar
|
||||
- } else {
|
||||
- while (!aar.exists() && rnMinorVersionCopy >= 63) {
|
||||
- rnMinorVersionCopy -= 1
|
||||
- aar = file("react-native-reanimated-${rnMinorVersionCopy}-${engine}.aar")
|
||||
- }
|
||||
-
|
||||
- if (rnMinorVersionCopy < 63) {
|
||||
- println "No AAR for react-native-reanimated found. Attempting to build from source."
|
||||
- } else { // aar exists, but was build for lower react-native version
|
||||
- println "\n\n\n"
|
||||
- println "****************************************************************************************"
|
||||
- println "\n\n\n"
|
||||
- println "WARNING reanimated - no version-specific reanimated AAR for react-native version $rnMinorVersion found."
|
||||
- println "Falling back to AAR for react-native version $rnMinorVersionCopy."
|
||||
- println "The react-native JSI interface is not ABI-safe yet, this may result in crashes."
|
||||
- println "Please post a pull request to implement support for react-native version $rnMinorVersion to the reanimated repo."
|
||||
- println "Thanks!"
|
||||
- println "\n\n\n"
|
||||
- println "****************************************************************************************"
|
||||
-
|
||||
- return aar
|
||||
- }
|
||||
- }
|
||||
- return null
|
||||
-}
|
||||
-
|
||||
-def detectJsRuntime() {
|
||||
- def runtimeType = "jsc"
|
||||
- rootProject.getSubprojects().forEach({project ->
|
||||
- if (project.plugins.hasPlugin("com.android.application")) {
|
||||
- if (project.ext.react.enableHermes) {
|
||||
- runtimeType = "hermes"
|
||||
- }
|
||||
- }
|
||||
- })
|
||||
- return runtimeType
|
||||
-}
|
||||
-
|
||||
-def detectReanimatedConfig() {
|
||||
- def buildFromSourceConf = false
|
||||
- rootProject.getSubprojects().forEach({project ->
|
||||
- if (project.plugins.hasPlugin("com.android.application")) {
|
||||
- if (
|
||||
- project.ext.has("reanimated")
|
||||
- && project.ext.reanimated.buildFromSource
|
||||
- ) {
|
||||
- buildFromSourceConf = true
|
||||
- }
|
||||
- }
|
||||
- })
|
||||
- return buildFromSourceConf
|
||||
-}
|
||||
-
|
||||
-def shouldBuildFromSource(aar) {
|
||||
- if (isDeveloperMode()) {
|
||||
- // Example app
|
||||
- return true
|
||||
- }
|
||||
- else if (detectReanimatedConfig()) {
|
||||
- // on user demand
|
||||
- return true
|
||||
- }
|
||||
- else if (aar != null) {
|
||||
- // when binary exist
|
||||
- return false
|
||||
- }
|
||||
- // when binary is not found
|
||||
- return true
|
||||
-}
|
||||
-
|
||||
boolean CLIENT_SIDE_BUILD = resolveBuildType()
|
||||
if (CLIENT_SIDE_BUILD) {
|
||||
configurations.maybeCreate("default")
|
||||
@@ -217,70 +82,6 @@ def reactNativeManifestAsJson = new JsonSlurper().parseText(reactNativeManifest.
|
||||
def reactNativeVersion = reactNativeManifestAsJson.version as String
|
||||
def (major, minor, patch) = reactNativeVersion.tokenize('.')
|
||||
def rnMinorVersion = Integer.parseInt(minor)
|
||||
-def engine = detectJsRuntime()
|
||||
-def aar = detectAAR(minor, engine)
|
||||
-boolean BUILD_FROM_SOURCE = shouldBuildFromSource(aar)
|
||||
-
|
||||
-def getTaskByPath(project, String appName, String secondPart, String flavorString, String lastPart) {
|
||||
- String pathName = "${appName}:${secondPart}${flavorString}${lastPart}"
|
||||
- Task task = project.getTasks().findByPath(pathName)
|
||||
- if (task != null) {
|
||||
- return task
|
||||
- }
|
||||
- pathName = "${appName}:${secondPart}${flavorString.capitalize()}${lastPart}"
|
||||
- return project.getTasks().findByPath(pathName)
|
||||
-}
|
||||
-
|
||||
-if (!BUILD_FROM_SOURCE) {
|
||||
- if (rnMinorVersion < 65) {
|
||||
- tasks.register("replaceSoTaskDebug", replaceSoTask)
|
||||
- tasks.register("replaceSoTaskRelease", replaceSoTask)
|
||||
- Task replaceSoTaskDebug = project.getTasks().findByPath(":react-native-reanimated:replaceSoTaskDebug")
|
||||
- Task replaceSoTaskRelease = project.getTasks().findByPath(":react-native-reanimated:replaceSoTaskRelease")
|
||||
-
|
||||
- if (replaceSoTaskDebug != null && replaceSoTaskRelease != null) {
|
||||
- rootProject.getSubprojects().forEach({project ->
|
||||
- if (project.plugins.hasPlugin("com.android.application") && project.getProperties().get("android")) {
|
||||
- def projectProperties = project.getProperties()
|
||||
- def flavorString = getCurrentFlavor()
|
||||
- def reanimatedConf = projectProperties.get("reanimated")
|
||||
-
|
||||
- if (
|
||||
- flavorString != "NOT-FOUND"
|
||||
- && (!reanimatedConf || (reanimatedConf && !reanimatedConf.get("enablePackagingOptions")))
|
||||
- ) {
|
||||
- replaceSoTask.appName = projectProperties.path
|
||||
- replaceSoTask.buildDir = projectProperties.buildDir
|
||||
- def appName = projectProperties.path
|
||||
-
|
||||
- Task debugNativeLibsTask = getTaskByPath(project, appName, "merge", flavorString, "DebugNativeLibs")
|
||||
- Task debugDebugSymbolsTask = getTaskByPath(project, appName, "strip", flavorString, "DebugDebugSymbols")
|
||||
- Task releaseNativeLibsTask = getTaskByPath(project, appName, "merge", flavorString, "ReleaseNativeLibs")
|
||||
- Task releaseDebugSymbolsTask = getTaskByPath(project, appName, "strip", flavorString, "ReleaseDebugSymbols")
|
||||
- Task debugTask = getTaskByPath(project, appName, "package", flavorString, "Debug")
|
||||
- Task releaseTask = getTaskByPath(project, appName, "package", flavorString, "Release")
|
||||
-
|
||||
- if (
|
||||
- debugNativeLibsTask != null && debugDebugSymbolsTask != null
|
||||
- && releaseNativeLibsTask != null && releaseDebugSymbolsTask != null
|
||||
- && debugTask != null && releaseTask != null
|
||||
- ) {
|
||||
- replaceSoTaskDebug.dependsOn(debugNativeLibsTask, debugDebugSymbolsTask)
|
||||
- debugTask.dependsOn(replaceSoTaskDebug)
|
||||
- replaceSoTaskRelease.dependsOn(releaseNativeLibsTask, releaseDebugSymbolsTask)
|
||||
- releaseTask.dependsOn(replaceSoTaskRelease)
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- })
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- artifacts.add("default", aar)
|
||||
-}
|
||||
-
|
||||
-// end if already loaded aar
|
||||
-if (!BUILD_FROM_SOURCE) return
|
||||
|
||||
def localProps = new Properties()
|
||||
def localPropertiesFile = file("local.properties")
|
||||
@@ -381,8 +182,7 @@ android {
|
||||
"-DBOOST_VERSION=${BOOST_VERSION}",
|
||||
"-DBUILD_DIR=${buildDir}",
|
||||
"-DFOR_HERMES=${FOR_HERMES}",
|
||||
- "-DCLIENT_SIDE_BUILD=${CLIENT_SIDE_BUILD}",
|
||||
- "--clean-first"
|
||||
+ "-DCLIENT_SIDE_BUILD=${CLIENT_SIDE_BUILD}"
|
||||
abiFilters (*reactNativeArchitectures())
|
||||
_stackProtectorFlag ? (cppFlags("-fstack-protector-all")) : null
|
||||
}
|
||||
@@ -407,6 +207,7 @@ android {
|
||||
"**/libfbjni.so",
|
||||
"**/libjsi.so",
|
||||
"**/libfolly_json.so",
|
||||
+ "**/libfolly_runtime.so",
|
||||
"**/libglog.so",
|
||||
"**/libhermes.so",
|
||||
"**/libreactnativejni.so",
|
||||
@@ -435,7 +236,7 @@ task cleanCmakeCache() {
|
||||
}
|
||||
|
||||
task printVersions {
|
||||
- println "Android gradle plugin: ${com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION}"
|
||||
+ println "Android gradle plugin: ${Version.ANDROID_GRADLE_PLUGIN_VERSION}"
|
||||
println "Gradle: ${project.gradle.gradleVersion}"
|
||||
}
|
||||
|
||||
@@ -459,7 +260,12 @@ task createNativeDepsDirectories(dependsOn: applyJavaPatches) {
|
||||
}
|
||||
|
||||
task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) {
|
||||
- src("https://github.com/react-native-community/boost-for-react-native/releases/download/v${BOOST_VERSION.replace("_", ".")}-0/boost_${BOOST_VERSION}.tar.gz")
|
||||
+ def transformedVersion = BOOST_VERSION.replace("_", ".")
|
||||
+ def srcUrl = "https://boostorg.jfrog.io/artifactory/main/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz"
|
||||
+ if (rnMinorVersion < 69) {
|
||||
+ srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/boost_${BOOST_VERSION}.tar.gz"
|
||||
+ }
|
||||
+ src(srcUrl)
|
||||
onlyIfNewer(true)
|
||||
overwrite(false)
|
||||
dest(new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz"))
|
||||
@@ -672,9 +478,29 @@ dependencies {
|
||||
extractHeaders("com.facebook.fbjni:fbjni:" + FBJNI_VERSION + ":headers")
|
||||
extractSO("com.facebook.fbjni:fbjni:" + FBJNI_VERSION)
|
||||
|
||||
- def rnAAR = fileTree("$reactNative/android").matching({ it.include "**/**/*.aar" }).singleFile
|
||||
def jscAAR = fileTree("$reactNative/../jsc-android/dist/org/webkit/android-jsc").matching({ it.include "**/**/*.aar" }).singleFile
|
||||
- extractSO(files(rnAAR, jscAAR))
|
||||
+ extractSO(files(jscAAR))
|
||||
+}
|
||||
+
|
||||
+task unpackReactNativeAAR {
|
||||
+ def buildType = "debug"
|
||||
+ tasks.all({ task ->
|
||||
+ if (task.name == "buildCMakeRelease") {
|
||||
+ buildType = "release"
|
||||
+ }
|
||||
+ })
|
||||
+ def rnAarMatcher = "**/react-native/**/*${buildType}.aar"
|
||||
+ if (rnMinorVersion < 69) {
|
||||
+ rnAarMatcher = "**/**/*.aar"
|
||||
+ }
|
||||
+ def rnAAR = fileTree("$reactNative/android").matching({ it.include rnAarMatcher }).singleFile
|
||||
+ def file = rnAAR.absoluteFile
|
||||
+ def packageName = file.name.tokenize('-')[0]
|
||||
+ copy {
|
||||
+ from zipTree(file)
|
||||
+ into "$reactNative/ReactAndroid/src/main/jni/first-party/$packageName/"
|
||||
+ include "jni/**/*.so"
|
||||
+ }
|
||||
}
|
||||
|
||||
task downloadNdkBuildDependencies {
|
||||
@@ -686,7 +512,7 @@ task downloadNdkBuildDependencies {
|
||||
dependsOn(downloadGlog)
|
||||
}
|
||||
|
||||
-task prepareThirdPartyNdkHeaders(dependsOn:[downloadNdkBuildDependencies, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog]) {
|
||||
+task prepareThirdPartyNdkHeaders(dependsOn:[downloadNdkBuildDependencies, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog, unpackReactNativeAAR]) {
|
||||
}
|
||||
|
||||
def nativeBuildDependsOn(dependsOnTask) {
|
||||
@@ -702,11 +528,17 @@ afterEvaluate {
|
||||
nativeBuildDependsOn(prepareThirdPartyNdkHeaders)
|
||||
nativeBuildDependsOn(extractAARHeaders)
|
||||
nativeBuildDependsOn(extractSOFiles)
|
||||
+
|
||||
+ tasks.forEach({ task ->
|
||||
+ if (task.name.contains("JniLibFolders")) {
|
||||
+ task.dependsOn(packageNdkLibs)
|
||||
+ }
|
||||
+ })
|
||||
}
|
||||
|
||||
if (CLIENT_SIDE_BUILD) {
|
||||
def aarDir = "${buildDir}/outputs"
|
||||
- aar = file("${aarDir}/android-debug.aar")
|
||||
+ def aar = file("${aarDir}/android-debug.aar")
|
||||
if (aar == null) {
|
||||
throw GradleScriptException("AAR build failed. No AAR found in ${aarDir}.")
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
103
apps/mobile/patches/rn-fetch-blob+0.12.0.patch
Normal file
103
apps/mobile/patches/rn-fetch-blob+0.12.0.patch
Normal file
@@ -0,0 +1,103 @@
|
||||
diff --git a/node_modules/rn-fetch-blob/android/build.gradle b/node_modules/rn-fetch-blob/android/build.gradle
|
||||
index a4ca7a4..4fd3cfa 100644
|
||||
--- a/node_modules/rn-fetch-blob/android/build.gradle
|
||||
+++ b/node_modules/rn-fetch-blob/android/build.gradle
|
||||
@@ -41,6 +41,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
|
||||
- //compile 'com.squareup.okhttp3:okhttp:+'
|
||||
+ implementation 'com.squareup.okhttp3:okhttp:3.4.1'
|
||||
+
|
||||
//{RNFetchBlob_PRE_0.28_DEPDENDENCY}
|
||||
}
|
||||
diff --git a/node_modules/rn-fetch-blob/react-native.config.js b/node_modules/rn-fetch-blob/react-native.config.js
|
||||
deleted file mode 100644
|
||||
index 03c61b6..0000000
|
||||
--- a/node_modules/rn-fetch-blob/react-native.config.js
|
||||
+++ /dev/null
|
||||
@@ -1,7 +0,0 @@
|
||||
-module.exports = {
|
||||
- dependency: {
|
||||
- hooks: {
|
||||
- prelink: 'node ./node_modules/rn-fetch-blob/scripts/prelink.js',
|
||||
- },
|
||||
- },
|
||||
-};
|
||||
diff --git a/node_modules/rn-fetch-blob/scripts/prelink.js b/node_modules/rn-fetch-blob/scripts/prelink.js
|
||||
deleted file mode 100644
|
||||
index e2c3ac4..0000000
|
||||
--- a/node_modules/rn-fetch-blob/scripts/prelink.js
|
||||
+++ /dev/null
|
||||
@@ -1,71 +0,0 @@
|
||||
-try {
|
||||
- var fs = require('fs');
|
||||
- var glob = require('glob');
|
||||
- var addAndroidPermissions = process.env.RNFB_ANDROID_PERMISSIONS == 'true';
|
||||
- var MANIFEST_PATH = glob.sync(process.cwd() + '/android/app/src/main/**/AndroidManifest.xml')[0];
|
||||
- var PACKAGE_JSON = process.cwd() + '/package.json';
|
||||
- var package = JSON.parse(fs.readFileSync(PACKAGE_JSON));
|
||||
- var APP_NAME = package.name;
|
||||
- var PACKAGE_GRADLE = process.cwd() + '/node_modules/rn-fetch-blob/android/build.gradle'
|
||||
- var VERSION = checkVersion();
|
||||
-
|
||||
- console.log('RNFetchBlob detected app version => ' + VERSION);
|
||||
-
|
||||
- if(VERSION < 0.28) {
|
||||
- console.log('You project version is '+ VERSION + ' which may not compatible to rn-fetch-blob 7.0+, please consider upgrade your application template to react-native 0.27+.')
|
||||
- // add OkHttp3 dependency fo pre 0.28 project
|
||||
- var main = fs.readFileSync(PACKAGE_GRADLE);
|
||||
- console.log('adding OkHttp3 dependency to pre 0.28 project .. ')
|
||||
- main = String(main).replace('//{RNFetchBlob_PRE_0.28_DEPDENDENCY}', "compile 'com.squareup.okhttp3:okhttp:3.4.1'");
|
||||
- fs.writeFileSync(PACKAGE_GRADLE, main);
|
||||
- console.log('adding OkHttp3 dependency to pre 0.28 project .. ok')
|
||||
- }
|
||||
-
|
||||
- console.log('Add Android permissions => ' + (addAndroidPermissions == "true"))
|
||||
-
|
||||
- if(addAndroidPermissions) {
|
||||
-
|
||||
- // set file access permission for Android < 6.0
|
||||
- fs.readFile(MANIFEST_PATH, function(err, data) {
|
||||
-
|
||||
- if(err)
|
||||
- console.log('failed to locate AndroidManifest.xml file, you may have to add file access permission manually.');
|
||||
- else {
|
||||
-
|
||||
- console.log('RNFetchBlob patching AndroidManifest.xml .. ');
|
||||
- // append fs permission
|
||||
- data = String(data).replace(
|
||||
- '<uses-permission android:name="android.permission.INTERNET" />',
|
||||
- '<uses-permission android:name="android.permission.INTERNET" />\n <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> '
|
||||
- )
|
||||
- // append DOWNLOAD_COMPLETE intent permission
|
||||
- data = String(data).replace(
|
||||
- '<category android:name="android.intent.category.LAUNCHER" />',
|
||||
- '<category android:name="android.intent.category.LAUNCHER" />\n <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>'
|
||||
- )
|
||||
- fs.writeFileSync(MANIFEST_PATH, data);
|
||||
- console.log('RNFetchBlob patching AndroidManifest.xml .. ok');
|
||||
-
|
||||
- }
|
||||
-
|
||||
- })
|
||||
- }
|
||||
- else {
|
||||
- console.log(
|
||||
- '\033[95mrn-fetch-blob \033[97mwill not automatically add Android permissions after \033[92m0.9.4 '+
|
||||
- '\033[97mplease run the following command if you want to add default permissions :\n\n' +
|
||||
- '\033[96m\tRNFB_ANDROID_PERMISSIONS=true react-native link \n')
|
||||
- }
|
||||
-
|
||||
- function checkVersion() {
|
||||
- console.log('RNFetchBlob checking app version ..');
|
||||
- return parseFloat(/\d\.\d+(?=\.)/.exec(package.dependencies['react-native']));
|
||||
- }
|
||||
-
|
||||
-} catch(err) {
|
||||
- console.log(
|
||||
- '\033[95mrn-fetch-blob\033[97m link \033[91mFAILED \033[97m\nCould not automatically link package :'+
|
||||
- err.stack +
|
||||
- 'please follow the instructions to manually link the library : ' +
|
||||
- '\033[4mhttps://github.com/joltup/rn-fetch-blob/wiki/Manually-Link-Package\n')
|
||||
-}
|
||||
@@ -87,21 +87,6 @@ const Launcher = React.memo(
|
||||
const hideSplashScreen = async () => {
|
||||
if (requireIntro.value) await sleep(500);
|
||||
await RNBootSplash.hide({ fade: true });
|
||||
setTimeout(async () => {
|
||||
if (Platform.OS === 'android') {
|
||||
NativeModules.RNBars.setStatusBarStyle(!colors.night ? 'light-content' : 'dark-content');
|
||||
NativeModules.RNBars.setNavigationBarStyle(
|
||||
!colors.night ? 'light-content' : 'dark-content'
|
||||
);
|
||||
await sleep(5);
|
||||
NativeModules.RNBars.setStatusBarStyle(colors.night ? 'light-content' : 'dark-content');
|
||||
NativeModules.RNBars.setNavigationBarStyle(
|
||||
colors.night ? 'light-content' : 'dark-content'
|
||||
);
|
||||
} else {
|
||||
StatusBar.setBarStyle(colors.night ? 'light-content' : 'dark-content');
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -161,6 +146,7 @@ const Launcher = React.memo(
|
||||
};
|
||||
|
||||
const checkAppUpdateAvailable = async () => {
|
||||
return;
|
||||
try {
|
||||
const version = await checkVersion();
|
||||
if (!version.needsUpdate) return false;
|
||||
|
||||
@@ -44,7 +44,7 @@ export const openNote = async (item, isTrash, setSelectedItem) => {
|
||||
history.selectedItemsList = [];
|
||||
}
|
||||
|
||||
if (_note.conflicted) {
|
||||
if (!_note.conflicted) {
|
||||
eSendEvent(eShowMergeDialog, _note);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import KeepAwake from '@sayem314/react-native-keep-awake';
|
||||
import { EV, EVENTS } from 'notes-core/common';
|
||||
import React, { createRef, useEffect, useState } from 'react';
|
||||
import { Modal, Platform, SafeAreaView, Text, View } from 'react-native';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Modal, SafeAreaView, Text, View } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import WebView from 'react-native-webview';
|
||||
import Editor from '../../screens/editor';
|
||||
import { editorController } from '../../screens/editor/tiptap/utils';
|
||||
import { DDS } from '../../services/device-detection';
|
||||
import { eSubscribeEvent, eUnSubscribeEvent, ToastEvent } from '../../services/event-manager';
|
||||
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
||||
import Navigation from '../../services/navigation';
|
||||
import Sync from '../../services/sync';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { dHeight } from '../../utils';
|
||||
import { db } from '../../utils/database';
|
||||
import { eApplyChanges, eShowMergeDialog } from '../../utils/events';
|
||||
import { openLinkInBrowser } from '../../utils/functions';
|
||||
import { normalize, SIZE } from '../../utils/size';
|
||||
import { eOnLoadNote, eShowMergeDialog } from '../../utils/events';
|
||||
import { SIZE } from '../../utils/size';
|
||||
import { timeConverter } from '../../utils/time';
|
||||
import BaseDialog from '../dialog/base-dialog';
|
||||
import DialogButtons from '../dialog/dialog-buttons';
|
||||
@@ -28,128 +26,42 @@ import Paragraph from '../ui/typography/paragraph';
|
||||
|
||||
const sourceUri = '';
|
||||
|
||||
const primaryWebView = createRef();
|
||||
const secondaryWebView = createRef();
|
||||
let note = null;
|
||||
let primaryData = null;
|
||||
let secondaryData = null;
|
||||
|
||||
function onMediaLoaded({ hash, src }) {
|
||||
console.log('on media download complete');
|
||||
let inject = `
|
||||
(function(){
|
||||
const elements = document.querySelectorAll("img[data-hash=${hash}]");
|
||||
if (!elements || !elements.length) return;
|
||||
for (let element of elements) element.setAttribute("src", "${src}");
|
||||
})();`;
|
||||
primaryWebView.current?.injectJavaScript(inject);
|
||||
secondaryWebView.current?.injectJavaScript(inject);
|
||||
}
|
||||
|
||||
const MergeConflicts = () => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [primary, setPrimary] = useState(true);
|
||||
const [secondary, setSecondary] = useState(true);
|
||||
const [keepContentFrom, setKeepContentFrom] = useState(null);
|
||||
const [copyToSave, setCopyToSave] = useState(null);
|
||||
const [disardedContent, setDiscardedContent] = useState(null);
|
||||
const [keep, setKeep] = useState(null);
|
||||
const [copy, setCopy] = useState(null);
|
||||
const [dialogVisible, setDialogVisible] = useState(false);
|
||||
const [loadingAttachments, setLoadingAttachments] = useState(false);
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const onPrimaryWebViewLoad = async () => {
|
||||
let content = await db.content.insertPlaceholders(primaryData, 'placeholder.svg');
|
||||
postMessage(primaryWebView, 'htmldiff', content.data);
|
||||
let theme = { ...colors };
|
||||
theme.factor = normalize(1);
|
||||
|
||||
primaryWebView.current?.injectJavaScript(`
|
||||
(function() {
|
||||
let v = ${JSON.stringify(theme)}
|
||||
if (pageTheme) {
|
||||
pageTheme.colors = v;
|
||||
}
|
||||
|
||||
setTheme();
|
||||
|
||||
})();
|
||||
`);
|
||||
};
|
||||
|
||||
const onSecondaryWebViewLoad = async () => {
|
||||
if (!secondaryData) return;
|
||||
let content = await db.content.insertPlaceholders(secondaryData, 'placeholder.svg');
|
||||
postMessage(secondaryWebView, 'htmldiff', content?.data);
|
||||
let theme = { ...colors };
|
||||
theme.factor = normalize(1);
|
||||
secondaryWebView.current?.injectJavaScript(`
|
||||
(function() {
|
||||
let v = ${JSON.stringify(theme)}
|
||||
if (pageTheme) {
|
||||
pageTheme.colors = v;
|
||||
}
|
||||
setTheme();
|
||||
})();
|
||||
`);
|
||||
};
|
||||
|
||||
function postMessage(webview, type, value = null) {
|
||||
let message = {
|
||||
type: type,
|
||||
value
|
||||
};
|
||||
webview.current?.postMessage(JSON.stringify(message));
|
||||
}
|
||||
|
||||
const _onShouldStartLoadWithRequest = request => {
|
||||
if (request.url.includes('http')) {
|
||||
openLinkInBrowser(request.url, colors)
|
||||
.catch(e =>
|
||||
ToastEvent.show({
|
||||
title: 'Failed to open link',
|
||||
message: e.message,
|
||||
type: 'success',
|
||||
context: 'local'
|
||||
})
|
||||
)
|
||||
.then(r => {
|
||||
console.log('closed');
|
||||
});
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
const content = useRef({});
|
||||
const isKeepingConflicted = !keep?.conflicted;
|
||||
const isKeeping = !!keep;
|
||||
|
||||
const applyChanges = async () => {
|
||||
let content = keepContentFrom === 'primary' ? primaryData : secondaryData;
|
||||
let keepCopy =
|
||||
copyToSave === 'primary' ? primaryData : copyToSave === 'secondary' ? secondaryData : null;
|
||||
|
||||
let _content = keep;
|
||||
let note = db.notes.note(_content.noteId).data;
|
||||
await db.notes.add({
|
||||
id: note.id,
|
||||
conflicted: false,
|
||||
dateEdited: content.dateEdited
|
||||
dateEdited: _content.dateEdited
|
||||
});
|
||||
|
||||
await db.content.add({
|
||||
id: note.contentId,
|
||||
data: content.data,
|
||||
type: content.type,
|
||||
dateResolved: secondaryData.dateModified,
|
||||
data: _content.data,
|
||||
type: _content.type,
|
||||
dateResolved: content.current.conflicted.dateModified,
|
||||
sessionId: Date.now(),
|
||||
conflicted: false
|
||||
});
|
||||
|
||||
if (keepCopy) {
|
||||
if (copy) {
|
||||
await db.notes.add({
|
||||
title: note.title + ' (Copy)',
|
||||
content: {
|
||||
data: keepCopy.data,
|
||||
type: keepCopy.type
|
||||
},
|
||||
id: null
|
||||
data: copy.data,
|
||||
type: copy.type
|
||||
}
|
||||
});
|
||||
}
|
||||
Navigation.queueRoutesForUpdate(
|
||||
@@ -167,89 +79,126 @@ const MergeConflicts = () => {
|
||||
};
|
||||
|
||||
const show = async item => {
|
||||
note = item;
|
||||
let content = await db.content.raw(note.contentId);
|
||||
switch (content.type) {
|
||||
let noteContent = await db.content.raw(item.contentId);
|
||||
switch (noteContent.type) {
|
||||
case 'tiny':
|
||||
primaryData = content;
|
||||
secondaryData = content.conflicted;
|
||||
content.current = { ...noteContent };
|
||||
if (!noteContent.conflicted) {
|
||||
content.current.conflicted = { ...noteContent };
|
||||
}
|
||||
}
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eApplyChanges, applyChanges);
|
||||
eSubscribeEvent(eShowMergeDialog, show);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eApplyChanges, applyChanges);
|
||||
eUnSubscribeEvent(eShowMergeDialog, show);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onPressKeepFromPrimaryWebView = () => {
|
||||
if (keepContentFrom == 'primary') {
|
||||
setKeepContentFrom(null);
|
||||
} else {
|
||||
setKeepContentFrom('primary');
|
||||
}
|
||||
};
|
||||
|
||||
const onPressSaveCopyFromPrimaryWebView = () => {
|
||||
setCopyToSave('primary');
|
||||
setDialogVisible(true);
|
||||
};
|
||||
|
||||
const onPressKeepFromSecondaryWebView = () => {
|
||||
if (keepContentFrom == 'secondary') {
|
||||
setKeepContentFrom(null);
|
||||
} else {
|
||||
setKeepContentFrom('secondary');
|
||||
}
|
||||
};
|
||||
|
||||
const onPressSaveCopyFromSecondaryWebView = () => {
|
||||
setCopyToSave('secondary');
|
||||
setDialogVisible(true);
|
||||
};
|
||||
|
||||
const onPressDiscardFromPrimaryWebView = () => {
|
||||
setDiscardedContent('primary');
|
||||
setDialogVisible(true);
|
||||
};
|
||||
|
||||
const onPressDiscardFromSecondaryWebView = () => {
|
||||
setDiscardedContent('secondary');
|
||||
setDialogVisible(true);
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
db.fs.cancel(primaryData?.noteId);
|
||||
|
||||
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaLoaded);
|
||||
setVisible(false);
|
||||
setPrimary(true);
|
||||
setSecondary(true);
|
||||
setCopyToSave(null);
|
||||
setDiscardedContent(null);
|
||||
setKeepContentFrom(null);
|
||||
setCopy(null);
|
||||
setKeep(null);
|
||||
setDialogVisible(false);
|
||||
primaryData = null;
|
||||
secondaryData = null;
|
||||
note = null;
|
||||
};
|
||||
|
||||
const onLoadImages = async () => {
|
||||
try {
|
||||
setLoadingAttachments(true);
|
||||
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaLoaded);
|
||||
await db.content.downloadMedia(primaryData.data.noteId, primaryData);
|
||||
await db.content.downloadMedia(primaryData.data.noteId, secondaryData);
|
||||
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaLoaded);
|
||||
setLoadingAttachments(false);
|
||||
} catch (e) {
|
||||
setLoadingAttachments(false);
|
||||
eUnSubscribeEvent(EVENTS.mediaAttachmentDownloaded, onMediaLoaded);
|
||||
}
|
||||
const ConfigBar = ({ isDiscarded, keeping, back, isCurrent, contentToKeep }) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 50,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 12,
|
||||
paddingLeft: 6
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{back && <IconButton onPress={close} color={colors.pri} name="arrow-left" />}
|
||||
<Paragraph style={{ flexWrap: 'wrap' }} color={colors.icon} size={SIZE.xs}>
|
||||
<Text style={{ color: isCurrent ? colors.accent : colors.red, fontWeight: 'bold' }}>
|
||||
{isCurrent ? '(This Device)' : '(Incoming)'}
|
||||
</Text>
|
||||
{'\n'}
|
||||
{timeConverter(contentToKeep.dateEdited)}
|
||||
</Paragraph>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end'
|
||||
}}
|
||||
>
|
||||
{isDiscarded ? (
|
||||
<Button
|
||||
onPress={() => {
|
||||
setCopy(contentToKeep);
|
||||
setDialogVisible(true);
|
||||
}}
|
||||
title="Save a copy"
|
||||
type="grayBg"
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
/>
|
||||
) : null}
|
||||
<View style={{ width: 10 }} />
|
||||
{isDiscarded ? (
|
||||
<Button
|
||||
title="Discard"
|
||||
type="accent"
|
||||
accentColor="red"
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
accentText="light"
|
||||
color={colors.errorText}
|
||||
onPress={() => {
|
||||
setDialogVisible(true);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{isDiscarded ? null : (
|
||||
<>
|
||||
<Button
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60,
|
||||
marginLeft: 10
|
||||
}}
|
||||
type="accent"
|
||||
fontSize={SIZE.xs}
|
||||
title={keeping && !isDiscarded ? 'Undo' : 'Keep'}
|
||||
onPress={() => {
|
||||
setKeep(keeping && !isDiscarded ? null : contentToKeep);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return !visible ? null : (
|
||||
@@ -302,103 +251,13 @@ const MergeConflicts = () => {
|
||||
backgroundColor: DDS.isLargeTablet() ? 'rgba(0,0,0,0.3)' : null
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 50,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 12,
|
||||
paddingLeft: 6
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<IconButton onPress={close} color={colors.pri} name="arrow-left" />
|
||||
<Paragraph style={{ flexWrap: 'wrap' }} color={colors.icon} size={SIZE.xs}>
|
||||
<Text style={{ color: colors.accent, fontWeight: 'bold' }}>(This Device)</Text>
|
||||
{'\n'}
|
||||
{timeConverter(primaryData?.dateEdited)}
|
||||
</Paragraph>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end'
|
||||
}}
|
||||
>
|
||||
{keepContentFrom === 'secondary' ? (
|
||||
<Button
|
||||
onPress={onPressSaveCopyFromPrimaryWebView}
|
||||
title="Save a copy"
|
||||
type="grayBg"
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
<ConfigBar
|
||||
back={true}
|
||||
isCurrent={true}
|
||||
isDiscarded={isKeeping && isKeepingConflicted}
|
||||
keeping={isKeeping}
|
||||
contentToKeep={content.current}
|
||||
/>
|
||||
) : null}
|
||||
<View style={{ width: 10 }} />
|
||||
{keepContentFrom === 'secondary' ? (
|
||||
<Button
|
||||
title="Discard"
|
||||
type="accent"
|
||||
accentColor="red"
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
accentText="light"
|
||||
color={colors.errorText}
|
||||
onPress={onPressDiscardFromPrimaryWebView}
|
||||
/>
|
||||
) : null}
|
||||
{keepContentFrom === 'secondary' ? null : (
|
||||
<>
|
||||
<Button
|
||||
type="grayBg"
|
||||
title="Load images"
|
||||
onPress={onLoadImages}
|
||||
height={30}
|
||||
loading={loadingAttachments}
|
||||
fontSize={SIZE.xs}
|
||||
icon="download"
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60,
|
||||
marginLeft: 10
|
||||
}}
|
||||
type="accent"
|
||||
fontSize={SIZE.xs}
|
||||
title={keepContentFrom === 'primary' ? 'Undo' : 'Keep'}
|
||||
onPress={onPressKeepFromPrimaryWebView}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Animated.View
|
||||
style={{
|
||||
@@ -408,129 +267,26 @@ const MergeConflicts = () => {
|
||||
borderBottomColor: colors.nav
|
||||
}}
|
||||
>
|
||||
<WebView
|
||||
onLoad={onPrimaryWebViewLoad}
|
||||
ref={primaryWebView}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onShouldStartLoadWithRequest={_onShouldStartLoadWithRequest}
|
||||
cacheMode="LOAD_DEFAULT"
|
||||
domStorageEnabled={true}
|
||||
scrollEnabled={true}
|
||||
bounces={false}
|
||||
allowFileAccess={true}
|
||||
scalesPageToFit={true}
|
||||
allowingReadAccessToURL={Platform.OS === 'android' ? true : null}
|
||||
allowFileAccessFromFileURLs={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
originWhitelist={['*']}
|
||||
javaScriptEnabled={true}
|
||||
cacheEnabled={true}
|
||||
source={{
|
||||
uri: sourceUri + 'plaineditor.html'
|
||||
<Editor
|
||||
noHeader
|
||||
noToolbar
|
||||
readonly
|
||||
editorId=":conflictPrimary"
|
||||
onLoad={() => {
|
||||
const note = db.notes.note(content.current?.noteId)?.data;
|
||||
if (!note) return;
|
||||
eSendEvent(eOnLoadNote + ':conflictPrimary', { ...note, content: content.current });
|
||||
}}
|
||||
/>
|
||||
</Animated.View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 50,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<Paragraph style={{ flexWrap: 'wrap' }} color={colors.icon} size={SIZE.xs}>
|
||||
<Text style={{ color: 'red', fontWeight: 'bold' }}>(Incoming)</Text>
|
||||
{'\n'}
|
||||
{timeConverter(secondaryData?.dateEdited)}
|
||||
</Paragraph>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end'
|
||||
}}
|
||||
>
|
||||
{keepContentFrom === 'primary' ? (
|
||||
<Button
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60
|
||||
}}
|
||||
type="accent"
|
||||
fontSize={SIZE.xs}
|
||||
onPress={onPressSaveCopyFromSecondaryWebView}
|
||||
title="Save a copy"
|
||||
<ConfigBar
|
||||
back={false}
|
||||
isCurrent={false}
|
||||
isDiscarded={isKeeping && !isKeepingConflicted}
|
||||
keeping={isKeeping}
|
||||
contentToKeep={content.current.conflicted}
|
||||
/>
|
||||
) : null}
|
||||
<View style={{ width: 10 }} />
|
||||
{keepContentFrom === 'primary' ? (
|
||||
<Button
|
||||
title="Discard"
|
||||
type="accent"
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
accentColor="red"
|
||||
accentText="light"
|
||||
onPress={onPressDiscardFromSecondaryWebView}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{keepContentFrom === 'primary' ? null : (
|
||||
<>
|
||||
<Button
|
||||
type="grayBg"
|
||||
title="Load images"
|
||||
height={30}
|
||||
loading={loadingAttachments}
|
||||
fontSize={SIZE.xs}
|
||||
icon="download"
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 60,
|
||||
marginLeft: 10
|
||||
}}
|
||||
type="accent"
|
||||
fontSize={SIZE.xs}
|
||||
title={keepContentFrom === 'secondary' ? 'Undo' : 'Keep'}
|
||||
onPress={onPressKeepFromSecondaryWebView}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Animated.View
|
||||
style={{
|
||||
@@ -539,29 +295,18 @@ const MergeConflicts = () => {
|
||||
borderRadius: 10
|
||||
}}
|
||||
>
|
||||
<WebView
|
||||
onLoad={onSecondaryWebViewLoad}
|
||||
ref={secondaryWebView}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onShouldStartLoadWithRequest={_onShouldStartLoadWithRequest}
|
||||
cacheMode="LOAD_DEFAULT"
|
||||
domStorageEnabled={true}
|
||||
scrollEnabled={true}
|
||||
bounces={false}
|
||||
allowFileAccess={true}
|
||||
scalesPageToFit={true}
|
||||
allowingReadAccessToURL={Platform.OS === 'android' ? true : null}
|
||||
allowFileAccessFromFileURLs={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
originWhitelist={['*']}
|
||||
javaScriptEnabled={true}
|
||||
cacheEnabled={true}
|
||||
source={{
|
||||
uri: sourceUri + 'plaineditor.html'
|
||||
<Editor
|
||||
noHeader
|
||||
noToolbar
|
||||
readonly
|
||||
editorId=":conflictSecondary"
|
||||
onLoad={() => {
|
||||
const note = db.notes.note(content.current?.noteId)?.data;
|
||||
if (!note) return;
|
||||
eSendEvent(eOnLoadNote + ':conflictSecondary', {
|
||||
...note,
|
||||
content: content.current.conflicted
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Animated.View>
|
||||
|
||||
@@ -15,7 +15,7 @@ import Seperator from '../ui/seperator';
|
||||
import Paragraph from '../ui/typography/paragraph';
|
||||
import NotePreview from './preview';
|
||||
|
||||
export default function NoteHistory({ note, ref }) {
|
||||
export default function NoteHistory({ note, fwdRef }) {
|
||||
const [history, setHistory] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
@@ -92,7 +92,7 @@ export default function NoteHistory({ note, ref }) {
|
||||
|
||||
<FlatList
|
||||
onMomentumScrollEnd={() => {
|
||||
ref?.current?.handleChildScrollEnd();
|
||||
fwdRef?.current?.handleChildScrollEnd();
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { Platform, View } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Editor from '../../screens/editor';
|
||||
import EditorOverlay from '../../screens/editor/loading';
|
||||
import { editorController } from '../../screens/editor/tiptap/utils';
|
||||
import { eSendEvent, ToastEvent } from '../../services/event-manager';
|
||||
import Navigation from '../../services/navigation';
|
||||
@@ -8,66 +9,13 @@ import { useEditorStore } from '../../stores/use-editor-store';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { db } from '../../utils/database';
|
||||
import { eCloseProgressDialog, eOnLoadNote } from '../../utils/events';
|
||||
import { openLinkInBrowser } from '../../utils/functions';
|
||||
import { normalize } from '../../utils/size';
|
||||
import DialogHeader from '../dialog/dialog-header';
|
||||
import { Button } from '../ui/button';
|
||||
import Paragraph from '../ui/typography/paragraph';
|
||||
|
||||
const sourceUri = '';
|
||||
|
||||
export default function NotePreview({ session, content }) {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const webviewRef = useRef();
|
||||
|
||||
const onLoad = async () => {
|
||||
let preview = await db.content.insertPlaceholders(content, 'placeholder.svg');
|
||||
|
||||
let theme = { ...colors };
|
||||
theme.factor = normalize(1);
|
||||
|
||||
webviewRef.current?.injectJavaScript(`
|
||||
(function() {
|
||||
let v = ${JSON.stringify(theme)}
|
||||
if (pageTheme) {
|
||||
pageTheme.colors = v;
|
||||
}
|
||||
setTheme()
|
||||
})();
|
||||
`);
|
||||
|
||||
postMessage('htmldiff', preview?.data);
|
||||
};
|
||||
|
||||
function postMessage(type, value = null) {
|
||||
let message = {
|
||||
type: type,
|
||||
value
|
||||
};
|
||||
webviewRef.current?.postMessage(JSON.stringify(message));
|
||||
}
|
||||
|
||||
const _onShouldStartLoadWithRequest = request => {
|
||||
if (request.url.includes('https')) {
|
||||
if (Platform.OS === 'ios' && !request.isTopFrame) return;
|
||||
openLinkInBrowser(request.url, colors)
|
||||
.catch(e =>
|
||||
ToastEvent.show({
|
||||
title: 'Failed to open link',
|
||||
message: e.message,
|
||||
type: 'success',
|
||||
context: 'local'
|
||||
})
|
||||
)
|
||||
.then(r => {
|
||||
console.log('closed');
|
||||
});
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
const editorId = ':noteHistory';
|
||||
|
||||
async function restore() {
|
||||
await db.noteHistory.restore(session.id);
|
||||
@@ -101,35 +49,19 @@ export default function NotePreview({ session, content }) {
|
||||
>
|
||||
<DialogHeader padding={12} title={session.session} />
|
||||
{!session.locked ? (
|
||||
<WebView
|
||||
ref={webviewRef}
|
||||
onShouldStartLoadWithRequest={_onShouldStartLoadWithRequest}
|
||||
onLoad={onLoad}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onError={e => {
|
||||
console.log(e);
|
||||
}}
|
||||
nestedScrollEnabled
|
||||
domStorageEnabled={true}
|
||||
scrollEnabled={true}
|
||||
bounces={false}
|
||||
allowFileAccess={true}
|
||||
scalesPageToFit={true}
|
||||
allowingReadAccessToURL={Platform.OS === 'android' ? true : null}
|
||||
allowFileAccessFromFileURLs={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
originWhitelist={['*']}
|
||||
javaScriptEnabled={true}
|
||||
cacheMode="LOAD_DEFAULT"
|
||||
cacheEnabled={true}
|
||||
source={{
|
||||
uri: sourceUri + 'plaineditor.html'
|
||||
<>
|
||||
<EditorOverlay editorId={editorId} />
|
||||
<Editor
|
||||
noHeader
|
||||
noToolbar
|
||||
readonly
|
||||
editorId={editorId}
|
||||
onLoad={() => {
|
||||
const note = db.notes.note(session.noteId)?.data;
|
||||
eSendEvent(eOnLoadNote + editorId, { ...note, content });
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
|
||||
@@ -30,7 +30,7 @@ export interface TabsRef {
|
||||
setScrollEnabled: () => true;
|
||||
}
|
||||
|
||||
export const NewTabs = forwardRef<TabsRef, TabProps>(
|
||||
export const FluidTabs = forwardRef<TabsRef, TabProps>(
|
||||
(
|
||||
{ children, dimensions, widths, onChangeTab, onScroll, enabled, onDrawerStateChange }: TabProps,
|
||||
ref
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { activateKeepAwake, deactivateKeepAwake } from '@sayem314/react-native-keep-awake';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Platform, View } from 'react-native';
|
||||
import { NavigationBar, StatusBar } from 'react-native-bars';
|
||||
import { Platform, View, StatusBar } from 'react-native';
|
||||
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { notesnook } from '../../e2e/test.ids';
|
||||
import { SideMenu } from '../components/side-menu';
|
||||
import { NewTabs } from '../components/tabs';
|
||||
import { FluidTabs } from '../components/tabs';
|
||||
import { editorState } from '../screens/editor/tiptap/utils';
|
||||
import { EditorWrapper } from '../screens/editor/wrapper';
|
||||
import { DDS } from '../services/device-detection';
|
||||
@@ -255,18 +254,22 @@ export const TabsHolder = React.memo(
|
||||
paddingBottom: Platform.OS === 'android' ? insets?.bottom : 0
|
||||
}}
|
||||
>
|
||||
<StatusBar animated={true} barStyle={colors.night ? 'light-content' : 'dark-content'} />
|
||||
<NavigationBar barStyle={colors.night ? 'light-content' : 'dark-content'} />
|
||||
<StatusBar
|
||||
animated={true}
|
||||
barStyle={colors.night ? 'light-content' : 'dark-content'}
|
||||
translucent={true}
|
||||
backgroundColor="transparent"
|
||||
/>
|
||||
|
||||
{deviceMode && widths[deviceMode] ? (
|
||||
<NewTabs
|
||||
<FluidTabs
|
||||
ref={tabBarRef}
|
||||
dimensions={dimensions}
|
||||
widths={widths[deviceMode]}
|
||||
enabled={deviceMode !== 'tablet'}
|
||||
onScroll={onScroll}
|
||||
onChangeTab={onChangeTab}
|
||||
onDrawerStateChange={state => {}}
|
||||
onDrawerStateChange={state => true}
|
||||
>
|
||||
<View
|
||||
key="1"
|
||||
@@ -309,7 +312,7 @@ export const TabsHolder = React.memo(
|
||||
<NavigationStack />
|
||||
</View>
|
||||
<EditorWrapper key="3" width={widths} dimensions={dimensions} />
|
||||
</NewTabs>
|
||||
</FluidTabs>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Linking, Platform } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
import { notesnook } from '../../../e2e/test.ids';
|
||||
import { useEditor } from './tiptap/use-editor';
|
||||
import { useEditorEvents } from './tiptap/use-editor-events';
|
||||
import { editorController } from './tiptap/utils';
|
||||
|
||||
const sourceUri = '';
|
||||
const source = { uri: sourceUri + 'index.html' };
|
||||
|
||||
const style = {
|
||||
height: '100%',
|
||||
maxHeight: '100%',
|
||||
width: '100%',
|
||||
alignSelf: 'center',
|
||||
backgroundColor: 'transparent'
|
||||
};
|
||||
const onShouldStartLoadWithRequest = request => {
|
||||
Linking.openURL(request.url);
|
||||
return false;
|
||||
};
|
||||
|
||||
const Editor = React.memo(
|
||||
() => {
|
||||
const editor = useEditor();
|
||||
const onMessage = useEditorEvents(editor);
|
||||
editorController.current = editor;
|
||||
|
||||
const onError = () => {
|
||||
editorController.current?.setLoading(true);
|
||||
setTimeout(() => editorController.current?.setLoading(false), 10);
|
||||
};
|
||||
|
||||
return editor.loading ? null : (
|
||||
<WebView
|
||||
testID={notesnook.editor.id}
|
||||
ref={editor.ref}
|
||||
onLoad={editor.onLoad}
|
||||
onRenderProcessGone={onError}
|
||||
onError={onError}
|
||||
injectedJavaScript={`globalThis.sessionId="${editor.sessionId}";`}
|
||||
javaScriptEnabled={true}
|
||||
focusable={true}
|
||||
setSupportMultipleWindows={false}
|
||||
overScrollMode="never"
|
||||
keyboardDisplayRequiresUserAction={false}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
cacheMode="LOAD_DEFAULT"
|
||||
cacheEnabled={true}
|
||||
domStorageEnabled={true}
|
||||
bounces={false}
|
||||
setBuiltInZoomControls={false}
|
||||
setDisplayZoomControls={false}
|
||||
allowFileAccess={true}
|
||||
scalesPageToFit={true}
|
||||
hideKeyboardAccessoryView={true}
|
||||
allowingReadAccessToURL={Platform.OS === 'android' ? true : null}
|
||||
allowFileAccessFromFileURLs={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
originWhitelist={['*']}
|
||||
source={{
|
||||
uri: 'http://localhost:3000'
|
||||
}}
|
||||
style={style}
|
||||
autoManageStatusBarEnabled={false}
|
||||
onMessage={onMessage}
|
||||
/>
|
||||
);
|
||||
},
|
||||
() => true
|
||||
);
|
||||
|
||||
export default Editor;
|
||||
|
||||
// test uri "http://192.168.10.8:3000/index.html"
|
||||
118
apps/mobile/src/screens/editor/index.tsx
Executable file
118
apps/mobile/src/screens/editor/index.tsx
Executable file
@@ -0,0 +1,118 @@
|
||||
import { EV, EVENTS } from 'notes-core/common';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Linking, ViewStyle } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
import { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes';
|
||||
import { notesnook } from '../../../e2e/test.ids';
|
||||
import EditorOverlay from './loading';
|
||||
import { EditorProps } from './tiptap/types';
|
||||
import { useEditor } from './tiptap/use-editor';
|
||||
import { useEditorEvents } from './tiptap/use-editor-events';
|
||||
import { editorController } from './tiptap/utils';
|
||||
|
||||
const sourceUri = '';
|
||||
const source = { uri: sourceUri + 'index.html' };
|
||||
|
||||
const style: ViewStyle = {
|
||||
height: '100%',
|
||||
maxHeight: '100%',
|
||||
width: '100%',
|
||||
alignSelf: 'center',
|
||||
backgroundColor: 'transparent'
|
||||
};
|
||||
const onShouldStartLoadWithRequest = (request: ShouldStartLoadRequest) => {
|
||||
Linking.openURL(request.url);
|
||||
return false;
|
||||
};
|
||||
|
||||
const Editor = React.memo(
|
||||
({ readonly, noToolbar, noHeader, withController, editorId, onLoad }: EditorProps) => {
|
||||
const editor = useEditor(editorId || '', readonly);
|
||||
const onMessage = useEditorEvents(editor, { readonly, noToolbar, noHeader });
|
||||
|
||||
const onMediaDownloaded = ({
|
||||
hash,
|
||||
groupId,
|
||||
src
|
||||
}: {
|
||||
hash: string;
|
||||
groupId: string;
|
||||
src: string;
|
||||
}) => {
|
||||
console.log('onMediaDownoaded', groupId);
|
||||
if (groupId !== editor.note.current?.id) return;
|
||||
editor.commands.updateImage({
|
||||
hash: hash,
|
||||
src: src
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
onLoad && onLoad();
|
||||
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
|
||||
return () => {
|
||||
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (withController) {
|
||||
//@ts-ignore
|
||||
editorController.current = editor;
|
||||
}
|
||||
|
||||
const onError = () => {
|
||||
editor.setLoading(true);
|
||||
setTimeout(() => editor.setLoading(false), 10);
|
||||
};
|
||||
|
||||
return editor.loading ? null : (
|
||||
<>
|
||||
<WebView
|
||||
testID={notesnook.editor.id}
|
||||
ref={editor.ref}
|
||||
onLoad={editor.onLoad}
|
||||
onRenderProcessGone={onError}
|
||||
nestedScrollEnabled
|
||||
onError={onError}
|
||||
injectedJavaScriptBeforeContentLoaded={`
|
||||
globalThis.readonly=${readonly};
|
||||
globalThis.noToolbar=${noToolbar};
|
||||
globalThis.noHeader=${noHeader};
|
||||
`}
|
||||
injectedJavaScript={`
|
||||
globalThis.sessionId="${editor.sessionId}";`}
|
||||
javaScriptEnabled={true}
|
||||
focusable={true}
|
||||
setSupportMultipleWindows={false}
|
||||
overScrollMode="never"
|
||||
keyboardDisplayRequiresUserAction={false}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
cacheMode="LOAD_DEFAULT"
|
||||
cacheEnabled={true}
|
||||
domStorageEnabled={true}
|
||||
bounces={false}
|
||||
setBuiltInZoomControls={false}
|
||||
setDisplayZoomControls={false}
|
||||
allowFileAccess={true}
|
||||
scalesPageToFit={true}
|
||||
hideKeyboardAccessoryView={true}
|
||||
allowFileAccessFromFileURLs={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
originWhitelist={['*']}
|
||||
source={{
|
||||
uri: 'http://localhost:3000'
|
||||
}}
|
||||
style={style}
|
||||
autoManageStatusBarEnabled={false}
|
||||
onMessage={onMessage || undefined}
|
||||
/>
|
||||
<EditorOverlay editorId={editorId || ''} editor={editor} />
|
||||
</>
|
||||
);
|
||||
},
|
||||
() => true
|
||||
);
|
||||
|
||||
export default Editor;
|
||||
|
||||
// test uri "http://192.168.10.8:3000/index.html"
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
||||
import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
|
||||
import { Button } from '../../components/ui/button';
|
||||
import Heading from '../../components/ui/typography/heading';
|
||||
import Paragraph from '../../components/ui/typography/paragraph';
|
||||
@@ -11,47 +11,43 @@ import { SIZE } from '../../utils/size';
|
||||
import { timeConverter } from '../../utils/time';
|
||||
import { editorState } from './tiptap/utils';
|
||||
|
||||
let timer = null;
|
||||
let timerError = null;
|
||||
let timerClosing = null;
|
||||
const EditorOverlay = () => {
|
||||
const EditorOverlay = ({ editorId = '', editor }) => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const [loading, setLoading] = useState(null);
|
||||
const [error, setError] = useState(false);
|
||||
const opacity = useSharedValue(1);
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
opacity: opacity.value
|
||||
};
|
||||
const isDefaultEditor = editorId === '';
|
||||
const timers = useRef({
|
||||
loading: 0,
|
||||
error: 0,
|
||||
closing: 0
|
||||
});
|
||||
|
||||
const clearTimers = () => {
|
||||
clearTimeout(timers.current.loading);
|
||||
clearTimeout(timers.current.error);
|
||||
clearTimeout(timers.current.closing);
|
||||
};
|
||||
|
||||
const load = async _loading => {
|
||||
editorState().overlay = true;
|
||||
clearTimeout(timer);
|
||||
clearTimeout(timerError);
|
||||
clearTimeout(timerClosing);
|
||||
clearTimers();
|
||||
if (_loading) {
|
||||
opacity.value = 1;
|
||||
setLoading(_loading);
|
||||
timerError = setTimeout(() => {
|
||||
timers.current.error = setTimeout(() => {
|
||||
if (_loading) {
|
||||
let _n = _loading;
|
||||
_n.forced = true;
|
||||
eSendEvent(eOnLoadNote, _n);
|
||||
let note = _loading;
|
||||
note.forced = true;
|
||||
eSendEvent(eOnLoadNote + editorId, note);
|
||||
}
|
||||
setError(true);
|
||||
}, 4000);
|
||||
} else {
|
||||
clearTimeout(timer);
|
||||
clearTimeout(timerError);
|
||||
clearTimeout(timerClosing);
|
||||
clearTimers();
|
||||
setError(false);
|
||||
editorState().overlay = false;
|
||||
opacity.value = withTiming(0, { duration: 150 });
|
||||
timerClosing = setTimeout(() => {
|
||||
setLoading(null);
|
||||
}, 150);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -62,11 +58,18 @@ const EditorOverlay = () => {
|
||||
}, [loading]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent('loadingNote', load);
|
||||
eSubscribeEvent('loadingNote' + editorId, load);
|
||||
return () => {
|
||||
eUnSubscribeEvent('loadingNote', load);
|
||||
clearTimers();
|
||||
eUnSubscribeEvent('loadingNote' + editorId, load);
|
||||
};
|
||||
}, [loading]);
|
||||
}, [loading, editorId]);
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
opacity: opacity.value
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
@@ -98,6 +101,7 @@ const EditorOverlay = () => {
|
||||
paddingVertical: 20
|
||||
}}
|
||||
>
|
||||
{isDefaultEditor ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
@@ -118,6 +122,7 @@ const EditorOverlay = () => {
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{loading?.title ? (
|
||||
<Heading
|
||||
@@ -129,7 +134,7 @@ const EditorOverlay = () => {
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
{loading?.dateEdited ? (
|
||||
{loading?.dateEdited && isDefaultEditor ? (
|
||||
<Paragraph
|
||||
textBreakStrategy="balanced"
|
||||
style={{ textAlign: 'center' }}
|
||||
@@ -155,7 +160,8 @@ const EditorOverlay = () => {
|
||||
}}
|
||||
onPress={() => {
|
||||
setError(false);
|
||||
eSendEvent('webviewreset');
|
||||
editor.setLoading(true);
|
||||
setTimeout(() => editor.setLoading(false), 10);
|
||||
}}
|
||||
title="Taking too long? Reload editor"
|
||||
/>
|
||||
|
||||
@@ -4,29 +4,22 @@ import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import WebView from 'react-native-webview';
|
||||
import { db } from '../../../utils/database';
|
||||
import { sleep } from '../../../utils/time';
|
||||
import { Note } from './types';
|
||||
import { Note, Settings } from './types';
|
||||
import { getResponse, randId, textInput } from './utils';
|
||||
import { Attachment, AttachmentProgress } from 'notesnook-editor/dist/extensions/attachment/index';
|
||||
import { ImageAttributes } from 'notesnook-editor/dist/extensions/image/index';
|
||||
import { ToolbarGroupDefinition } from 'notesnook-editor/dist/toolbar/types';
|
||||
import { NoteType } from '../../../utils/types';
|
||||
import { sanitizeFilename } from '../../../utils/sanitizer';
|
||||
|
||||
type Action = { job: string; id: string };
|
||||
|
||||
export type Settings = {
|
||||
readonly: boolean;
|
||||
fullscreen: boolean;
|
||||
deviceMode: string;
|
||||
premium: boolean;
|
||||
tools: ToolbarGroupDefinition[];
|
||||
};
|
||||
|
||||
async function call(webview: RefObject<WebView | undefined>, action?: Action) {
|
||||
if (!webview.current || !action) return;
|
||||
setImmediate(() => webview.current?.injectJavaScript(action.job));
|
||||
let response = await getResponse(action.id);
|
||||
console.log('webview job: ', action.id, response ? response.value : response);
|
||||
if (!response) {
|
||||
console.warn('webview job failed', action.id, action.job);
|
||||
console.warn('webview job failed', action.id);
|
||||
}
|
||||
return response ? response.value : response;
|
||||
}
|
||||
@@ -49,17 +42,17 @@ const fn = (fn: string) => {
|
||||
|
||||
class Commands {
|
||||
ref = createRef<WebView | undefined>();
|
||||
constructor(ref: MutableRefObject<WebView | undefined>) {
|
||||
constructor(ref: RefObject<WebView>) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
async doAsync<T>(job: string) {
|
||||
if (!this.ref) return false;
|
||||
if (!this.ref.current) return false;
|
||||
return call(this.ref, fn(job)) as Promise<T>;
|
||||
}
|
||||
|
||||
focus = async () => {
|
||||
if (!this.ref) return;
|
||||
if (!this.ref.current) return;
|
||||
if (Platform.OS === 'android') {
|
||||
this.ref.current?.requestFocus();
|
||||
setTimeout(async () => {
|
||||
@@ -74,16 +67,20 @@ class Commands {
|
||||
}
|
||||
};
|
||||
|
||||
blur = async () => await this.doAsync(`editor.commands.blur();editorTitle.current?.blur()`);
|
||||
blur = async () =>
|
||||
await this.doAsync(`
|
||||
editor && editor.commands.blur();
|
||||
typeof globalThis.editorTitle !== "undefined" && editorTitle.current && editorTitle.current.blur();
|
||||
`);
|
||||
|
||||
clearContent = async () => {
|
||||
await this.doAsync(
|
||||
`
|
||||
editor.commands.blur();
|
||||
editorTitle.current?.blur();
|
||||
typeof globalThis.editorTitle !== "undefined" && editorTitle.current && editorTitle.current?.blur();
|
||||
editor?.commands.clearContent(false);
|
||||
editorController.setTitle(null);
|
||||
statusBar.current.set({date:"",saved:""});
|
||||
typeof globalThis.statusBar !== "undefined" && statusBar.current.set({date:"",saved:""});
|
||||
`
|
||||
);
|
||||
};
|
||||
@@ -91,7 +88,9 @@ statusBar.current.set({date:"",saved:""});
|
||||
setSessionId = async (id: string | null) => await this.doAsync(`globalThis.sessionId = "${id}"`);
|
||||
|
||||
setStatus = async (date: string | undefined, saved: string) =>
|
||||
await this.doAsync(`statusBar.current.set({date:"${date}",saved:"${saved}"})`);
|
||||
await this.doAsync(
|
||||
`typeof globalThis.statusBar !== "undefined" && statusBar.current.set({date:"${date}",saved:"${saved}"})`
|
||||
);
|
||||
|
||||
setPlaceholder = async (placeholder: string) => {
|
||||
await this.doAsync(`
|
||||
@@ -119,7 +118,7 @@ statusBar.current.set({date:"",saved:""});
|
||||
`);
|
||||
};
|
||||
|
||||
setTags = async (note: Note | null | undefined) => {
|
||||
setTags = async (note: NoteType | null | undefined) => {
|
||||
if (!note) return;
|
||||
let tags = note.tags
|
||||
.map((t: any) =>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEditor } from './use-editor';
|
||||
|
||||
import { ToolbarGroupDefinition } from 'notesnook-editor/dist/toolbar/types';
|
||||
export type useEditorType = ReturnType<typeof useEditor>;
|
||||
|
||||
export type EditorState = {
|
||||
@@ -16,6 +16,25 @@ export type EditorState = {
|
||||
saveCount: 0;
|
||||
};
|
||||
|
||||
export type Settings = {
|
||||
readonly: boolean;
|
||||
fullscreen: boolean;
|
||||
deviceMode: string;
|
||||
premium: boolean;
|
||||
tools: ToolbarGroupDefinition[];
|
||||
noToolbar?: boolean;
|
||||
noHeader?: boolean;
|
||||
};
|
||||
|
||||
export type EditorProps = {
|
||||
readonly: boolean;
|
||||
noToolbar: boolean;
|
||||
noHeader: boolean;
|
||||
withController: boolean;
|
||||
editorId?: string;
|
||||
onLoad?: () => void;
|
||||
};
|
||||
|
||||
export type EditorMessage = {
|
||||
sessionId: string;
|
||||
value: any;
|
||||
|
||||
@@ -13,15 +13,17 @@ import { MMKV } from '../../../utils/database/mmkv';
|
||||
import { eOnLoadNote } from '../../../utils/events';
|
||||
import { tabBarRef } from '../../../utils/global-refs';
|
||||
import { timeConverter } from '../../../utils/time';
|
||||
import { NoteType } from '../../../utils/types';
|
||||
import Commands from './commands';
|
||||
import { AppState, Content, EditorState, Note, SavePayload } from './types';
|
||||
import { defaultState, EditorEvents, isEditorLoaded, makeSessionId, post } from './utils';
|
||||
|
||||
export const useEditor = () => {
|
||||
export const useEditor = (editorId = '', readonly?: boolean) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [sessionId, setSessionId] = useState<string>(makeSessionId());
|
||||
const editorRef = useRef<WebView>();
|
||||
const currentNote = useRef<Note | null>();
|
||||
const sessionIdRef = useRef(sessionId);
|
||||
const editorRef = useRef<WebView>(null);
|
||||
const currentNote = useRef<NoteType | null>();
|
||||
const currentContent = useRef<Content | null>();
|
||||
const timers = useRef<{ [name: string]: NodeJS.Timeout }>({});
|
||||
const commands = useMemo(() => new Commands(editorRef), []);
|
||||
@@ -30,16 +32,21 @@ export const useEditor = () => {
|
||||
const placeholderTip = useRef(TipManager.placeholderTip());
|
||||
const tags = useTagStore(state => state.tags);
|
||||
const insets = useSafeAreaInsets();
|
||||
const isDefaultEditor = editorId === '';
|
||||
|
||||
const postMessage = useCallback(
|
||||
async (type: string, data: any) => await post(editorRef, type, data),
|
||||
[]
|
||||
async (type: string, data: any) => await post(editorRef, sessionIdRef.current, type, data),
|
||||
[sessionIdRef]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
commands.setInsets(insets);
|
||||
commands.setInsets(isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 });
|
||||
}, [insets]);
|
||||
|
||||
useEffect(() => {
|
||||
sessionIdRef.current = sessionId;
|
||||
}, [sessionId]);
|
||||
|
||||
useEffect(() => {
|
||||
commands.setTags(currentNote.current);
|
||||
}, [tags]);
|
||||
@@ -69,11 +76,11 @@ export const useEditor = () => {
|
||||
}, [sessionId, loading]);
|
||||
|
||||
const overlay = (show: boolean, data = { type: 'new' }) => {
|
||||
eSendEvent('loadingNote', show ? currentNote.current || data : false);
|
||||
eSendEvent('loadingNote' + editorId, show ? currentNote.current || data : false);
|
||||
};
|
||||
|
||||
const onReady = useCallback(async () => {
|
||||
if (!(await isEditorLoaded(editorRef))) {
|
||||
if (!(await isEditorLoaded(editorRef, sessionId))) {
|
||||
console.log('reload editor');
|
||||
overlay(true);
|
||||
setLoading(true);
|
||||
@@ -99,7 +106,7 @@ export const useEditor = () => {
|
||||
await commands.clearContent();
|
||||
console.log('reset state: ', resetState);
|
||||
if (resetState) {
|
||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
isDefaultEditor && useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
placeholderTip.current = TipManager.placeholderTip();
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
}
|
||||
@@ -115,9 +122,10 @@ export const useEditor = () => {
|
||||
sessionHistoryId: currentSessionHistoryId
|
||||
}: SavePayload) => {
|
||||
console.log('saving note', id);
|
||||
if (readonly) return;
|
||||
try {
|
||||
if (id && !db.notes?.note(id)) {
|
||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
isDefaultEditor && useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
await reset();
|
||||
return;
|
||||
}
|
||||
@@ -144,11 +152,11 @@ export const useEditor = () => {
|
||||
if (!locked) {
|
||||
id = await db.notes?.add(noteData);
|
||||
if (!note && id) {
|
||||
currentNote.current = db.notes?.note(id).data as Note;
|
||||
currentNote.current = db.notes?.note(id).data as NoteType;
|
||||
state.current?.onNoteCreated && state.current.onNoteCreated(id);
|
||||
}
|
||||
|
||||
if (useEditorStore.getState().currentEditingNote !== id) {
|
||||
if (useEditorStore.getState().currentEditingNote !== id && isDefaultEditor) {
|
||||
setTimeout(() => {
|
||||
id && useEditorStore.getState().setCurrentlyEditingNote(id);
|
||||
});
|
||||
@@ -179,31 +187,25 @@ export const useEditor = () => {
|
||||
[commands, reset]
|
||||
);
|
||||
|
||||
const loadContent = useCallback(async (note: Note) => {
|
||||
const loadContent = useCallback(async (note: NoteType) => {
|
||||
currentNote.current = note;
|
||||
if (note.locked) {
|
||||
if (note.locked || note.content) {
|
||||
currentContent.current = {
|
||||
data: note.content.data,
|
||||
type: note.content.type
|
||||
data: note.content?.data,
|
||||
type: note.content?.type || 'tiny'
|
||||
};
|
||||
} else {
|
||||
let data = await db.content?.raw(note.contentId);
|
||||
if (data) {
|
||||
data = await db.content?.insertPlaceholders(data, 'placeholder.svg');
|
||||
currentContent.current = {
|
||||
data: data.data,
|
||||
type: data.type
|
||||
};
|
||||
}
|
||||
currentContent.current = await db.content?.raw(note.contentId);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const loadNote = useCallback(
|
||||
async (item: Note) => {
|
||||
console.log('loading note', item.type);
|
||||
async (item: NoteType) => {
|
||||
console.log('loading note', item.type, eOnLoadNote + editorId);
|
||||
state.current.currentlyEditing = true;
|
||||
const editorState = useEditorStore.getState();
|
||||
|
||||
//@ts-ignore todo
|
||||
if (item && item.type === 'new') {
|
||||
currentNote.current && (await reset());
|
||||
let nextSessionId = makeSessionId(item);
|
||||
@@ -212,8 +214,9 @@ export const useEditor = () => {
|
||||
await commands.setSessionId(nextSessionId);
|
||||
await commands.focus();
|
||||
} else {
|
||||
//@ts-ignore todo
|
||||
if (!item.forced && currentNote.current?.id === item.id) return;
|
||||
editorState.setCurrentlyEditingNote(item.id);
|
||||
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
|
||||
overlay(true, item);
|
||||
currentNote.current && (await reset(false));
|
||||
await loadContent(item);
|
||||
@@ -242,11 +245,11 @@ export const useEditor = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOnLoadNote, loadNote);
|
||||
eSubscribeEvent(eOnLoadNote + editorId, loadNote);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eOnLoadNote, loadNote);
|
||||
eUnSubscribeEvent(eOnLoadNote + editorId, loadNote);
|
||||
};
|
||||
}, []);
|
||||
}, [editorId]);
|
||||
|
||||
const saveContent = useCallback(
|
||||
({ title, content, type }: { title?: string; content?: string; type: string }) => {
|
||||
@@ -284,13 +287,14 @@ export const useEditor = () => {
|
||||
state.current.ready = true;
|
||||
onReady();
|
||||
postMessage(EditorEvents.theme, useThemeStore.getState().colors);
|
||||
commands.setInsets(isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 });
|
||||
if (currentNote.current) {
|
||||
console.log('force reload note');
|
||||
//@ts-ignore
|
||||
loadNote({ ...currentNote.current, forced: true });
|
||||
} else {
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
commands.setInsets(insets);
|
||||
restoreEditorState();
|
||||
isDefaultEditor && restoreEditorState();
|
||||
}
|
||||
}, [state, currentNote, loadNote]);
|
||||
|
||||
@@ -311,7 +315,9 @@ export const useEditor = () => {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
}
|
||||
setTimeout(() => {
|
||||
console.log('restoring app state here');
|
||||
if (appState.note) {
|
||||
//@ts-ignore
|
||||
loadNote(appState.note);
|
||||
}
|
||||
}, 1);
|
||||
@@ -339,6 +345,7 @@ export const useEditor = () => {
|
||||
setSessionId,
|
||||
note: currentNote,
|
||||
onReady,
|
||||
saveContent
|
||||
saveContent,
|
||||
editorId: editorId
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { BackHandler, InteractionManager, NativeEventSubscription } from 'react-native';
|
||||
import { WebViewMessageEvent } from 'react-native-webview';
|
||||
import { Properties } from '../../../components/properties';
|
||||
import { DDS } from '../../../services/device-detection';
|
||||
import {
|
||||
@@ -29,8 +30,8 @@ import { tabBarRef } from '../../../utils/global-refs';
|
||||
import { NoteType } from '../../../utils/types';
|
||||
import { useDragState } from '../../settings/editor/state';
|
||||
import picker from './picker';
|
||||
import { EditorMessage, useEditorType } from './types';
|
||||
import { editorController, EditorEvents, editorState } from './utils';
|
||||
import { EditorMessage, EditorProps, useEditorType } from './types';
|
||||
import { EditorEvents, editorState } from './utils';
|
||||
|
||||
export const EventTypes = {
|
||||
selection: 'editor-event:selection',
|
||||
@@ -49,7 +50,7 @@ export const EventTypes = {
|
||||
properties: 'editor-event:properties'
|
||||
};
|
||||
|
||||
const publishNote = async () => {
|
||||
const publishNote = async (editor: useEditorType) => {
|
||||
const user = useUserStore.getState().user;
|
||||
if (!user) {
|
||||
ToastEvent.show({
|
||||
@@ -72,7 +73,7 @@ const publishNote = async () => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const currentNote = editorController.current?.note?.current;
|
||||
const currentNote = editor?.note?.current;
|
||||
if (currentNote?.id) {
|
||||
let note = db.notes?.note(currentNote.id)?.data as NoteType;
|
||||
if (note?.locked) {
|
||||
@@ -90,8 +91,8 @@ const publishNote = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const showActionsheet = async () => {
|
||||
const currentNote = editorController.current?.note?.current;
|
||||
const showActionsheet = async (editor: useEditorType) => {
|
||||
const currentNote = editor?.note?.current;
|
||||
if (currentNote?.id) {
|
||||
let note = db.notes?.note(currentNote.id)?.data as NoteType;
|
||||
if (!note) {
|
||||
@@ -112,11 +113,10 @@ const showActionsheet = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
export const useEditorEvents = (editor: useEditorType) => {
|
||||
export const useEditorEvents = (editor: useEditorType, editorProps: Partial<EditorProps>) => {
|
||||
const deviceMode = useSettingStore(state => state.deviceMode);
|
||||
const fullscreen = useSettingStore(state => state.fullscreen);
|
||||
const handleBack = useRef<NativeEventSubscription>();
|
||||
const currentEditingNote = useEditorStore(state => state.currentEditingNote);
|
||||
const readonly = useEditorStore(state => state.readonly);
|
||||
const isPremium = useUserStore(state => state.premium);
|
||||
const tools = useDragState(state => state.data);
|
||||
@@ -129,17 +129,10 @@ export const useEditorEvents = (editor: useEditorType) => {
|
||||
fullscreen: fullscreen,
|
||||
premium: isPremium,
|
||||
readonly: readonly,
|
||||
tools: tools
|
||||
tools: tools,
|
||||
...editorProps
|
||||
});
|
||||
}, [
|
||||
currentEditingNote,
|
||||
fullscreen,
|
||||
isPremium,
|
||||
readonly,
|
||||
editor.sessionId,
|
||||
editor.loading,
|
||||
tools
|
||||
]);
|
||||
}, [fullscreen, isPremium, readonly, editor.sessionId, editor.loading, tools]);
|
||||
|
||||
const onBackPress = useCallback(async () => {
|
||||
const editorHandledBack = await editor.commands.handleBack();
|
||||
@@ -165,7 +158,7 @@ export const useEditorEvents = (editor: useEditorType) => {
|
||||
});
|
||||
setImmediate(() => useEditorStore.getState().setCurrentlyEditingNote(null));
|
||||
editorState().currentlyEditing = false;
|
||||
editorController.current?.reset();
|
||||
editor.reset();
|
||||
}, 1);
|
||||
}, []);
|
||||
|
||||
@@ -217,8 +210,8 @@ export const useEditorEvents = (editor: useEditorType) => {
|
||||
}, [fullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOnLoadNote, onLoadNote);
|
||||
eSubscribeEvent(eClearEditor, onCallClear);
|
||||
eSubscribeEvent(eOnLoadNote + editor.editorId, onLoadNote);
|
||||
eSubscribeEvent(eClearEditor + editor.editorId, onCallClear);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eClearEditor, onCallClear);
|
||||
eUnSubscribeEvent(eOnLoadNote, onLoadNote);
|
||||
@@ -226,8 +219,7 @@ export const useEditorEvents = (editor: useEditorType) => {
|
||||
}, []);
|
||||
|
||||
const onMessage = useCallback(
|
||||
event => {
|
||||
event;
|
||||
(event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
let editorMessage = JSON.parse(data) as EditorMessage;
|
||||
|
||||
@@ -303,10 +295,10 @@ export const useEditorEvents = (editor: useEditorType) => {
|
||||
eSendEvent(eOpenPremiumDialog);
|
||||
break;
|
||||
case EventTypes.monograph:
|
||||
publishNote();
|
||||
publishNote(editor);
|
||||
break;
|
||||
case EventTypes.properties:
|
||||
showActionsheet();
|
||||
showActionsheet(editor);
|
||||
break;
|
||||
case EventTypes.back:
|
||||
onBackPress();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createRef, MutableRefObject } from 'react';
|
||||
import { createRef, RefObject } from 'react';
|
||||
import { TextInput } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
import { eSubscribeEvent, eUnSubscribeEvent } from '../../../services/event-manager';
|
||||
import { NoteType } from '../../../utils/types';
|
||||
import { EditorState, useEditorType } from './types';
|
||||
export const textInput = createRef<TextInput>();
|
||||
export const editorController = createRef<useEditorType>();
|
||||
@@ -32,16 +33,15 @@ export function randId(prefix: string) {
|
||||
.replace('0.', prefix || '');
|
||||
}
|
||||
|
||||
export function makeSessionId(item?: any) {
|
||||
export function makeSessionId(item?: NoteType) {
|
||||
return item?.id ? item.id + randId('_session_') : randId('session_');
|
||||
}
|
||||
|
||||
export async function isEditorLoaded(ref: MutableRefObject<WebView | undefined>) {
|
||||
return await post(ref, EditorEvents.status);
|
||||
export async function isEditorLoaded(ref: RefObject<WebView>, sessionId: string) {
|
||||
return await post(ref, sessionId, EditorEvents.status);
|
||||
}
|
||||
|
||||
export async function post(ref: MutableRefObject<WebView | undefined>, type: string, value = null) {
|
||||
let sessionId = editorController.current?.sessionId;
|
||||
export async function post(ref: RefObject<WebView>, sessionId: string, type: string, value = null) {
|
||||
if (!sessionId) {
|
||||
console.warn('post called without sessionId of type:', type);
|
||||
return;
|
||||
|
||||
@@ -76,8 +76,7 @@ export const EditorWrapper = ({ width }) => {
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
<ProgressBar />
|
||||
<Editor key="editor" />
|
||||
<EditorOverlay key="overlay" />
|
||||
<Editor key="editor" withController={true} />
|
||||
</KeyboardAvoidingView>
|
||||
</SafeAreaView>
|
||||
)}
|
||||
|
||||
@@ -496,7 +496,7 @@ export const useActions = ({ close = () => {}, item }) => {
|
||||
close();
|
||||
await sleep(300);
|
||||
presentSheet({
|
||||
component: ref => <NoteHistory ref={ref} note={item} />
|
||||
component: ref => <NoteHistory fwdRef={ref} note={item} />
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -58,14 +58,6 @@ export const useAppEvents = () => {
|
||||
isReconnecting: false
|
||||
});
|
||||
|
||||
const onMediaDownloaded = ({ hash, groupId, src }) => {
|
||||
if (groupId?.startsWith('monograph')) return;
|
||||
editorController.current?.commands.updateImage({
|
||||
hash: hash,
|
||||
src: src
|
||||
});
|
||||
};
|
||||
|
||||
const onLoadingAttachmentProgress = data => {
|
||||
useAttachmentStore.getState().setLoading(data.total === data.current ? null : data);
|
||||
};
|
||||
@@ -112,7 +104,6 @@ export const useAppEvents = () => {
|
||||
EV.subscribe(EVENTS.userSessionExpired, onSessionExpired);
|
||||
EV.subscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
|
||||
EV.subscribe(EVENTS.userSubscriptionUpdated, onAccountStatusChange);
|
||||
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
|
||||
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachmentProgress);
|
||||
eSubscribeEvent('userLoggedIn', onUserUpdated);
|
||||
|
||||
@@ -123,7 +114,6 @@ export const useAppEvents = () => {
|
||||
EV.unsubscribe(EVENTS.userSessionExpired, onSessionExpired);
|
||||
EV.unsubscribe(EVENTS.userLoggedOut, onLogout);
|
||||
EV.unsubscribe(EVENTS.userEmailConfirmed, onEmailVerified);
|
||||
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
|
||||
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachmentProgress);
|
||||
EV.unsubscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
|
||||
EV.unsubscribe(EVENTS.userSubscriptionUpdated, onAccountStatusChange);
|
||||
|
||||
@@ -64,6 +64,10 @@ export interface NoteType extends Entity<'note'> {
|
||||
contentId?: string;
|
||||
headline?: string;
|
||||
color?: string;
|
||||
content?: {
|
||||
data: string;
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface NotebookType extends Entity<'notebook'> {
|
||||
|
||||
Reference in New Issue
Block a user