mirror of
https://github.com/standardnotes/mobile.git
synced 2026-04-19 13:49:03 -04:00
@@ -102,8 +102,8 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
|
||||
versionCode 3000050
|
||||
versionName "3.0.5"
|
||||
versionCode 3000060
|
||||
versionName "3.0.6"
|
||||
|
||||
multiDexEnabled true
|
||||
|
||||
@@ -159,6 +159,8 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':@react-native-community_async-storage')
|
||||
compile project(':react-native-webview')
|
||||
compile project(':react-native-file-viewer')
|
||||
compile project(':react-native-fs')
|
||||
compile project(':react-native-gesture-handler')
|
||||
|
||||
@@ -9,6 +9,8 @@ import android.support.annotation.Nullable;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.reactnativecommunity.asyncstorage.AsyncStoragePackage;
|
||||
import com.reactnativecommunity.webview.RNCWebViewPackage;
|
||||
import com.vinzscam.reactnativefileviewer.RNFileViewerPackage;
|
||||
import com.rnfs.RNFSPackage;
|
||||
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
|
||||
@@ -45,18 +47,20 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new RNFileViewerPackage(),
|
||||
new RNFSPackage(),
|
||||
new RNGestureHandlerPackage(),
|
||||
BugsnagReactNative.getPackage(),
|
||||
new KeychainPackage(),
|
||||
new VectorIconsPackage(),
|
||||
new RCTAesPackage(),
|
||||
new RNMail(),
|
||||
new ReactNativeFingerprintScannerPackage(),
|
||||
new SNTextViewPackage(),
|
||||
new FlagSecurePackage()
|
||||
new MainReactPackage(),
|
||||
new AsyncStoragePackage(),
|
||||
new RNCWebViewPackage(),
|
||||
new RNFileViewerPackage(),
|
||||
new RNFSPackage(),
|
||||
new RNGestureHandlerPackage(),
|
||||
BugsnagReactNative.getPackage(),
|
||||
new KeychainPackage(),
|
||||
new VectorIconsPackage(),
|
||||
new RCTAesPackage(),
|
||||
new RNMail(),
|
||||
new ReactNativeFingerprintScannerPackage(),
|
||||
new SNTextViewPackage(),
|
||||
new FlagSecurePackage()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,10 +81,6 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
|
||||
// Set AsyncStorage size, default is 6mb
|
||||
long size = 50L * 1024L * 1024L; // 50 MB
|
||||
com.facebook.react.modules.storage.ReactDatabaseSupplier.getInstance(getApplicationContext()).setMaximumSize(size);
|
||||
|
||||
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
|
||||
@@ -17,4 +17,6 @@
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
android.useDeprecatedNdk=true
|
||||
|
||||
AsyncStorage_db_size_in_MB=50
|
||||
#android.enableAapt2=false
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
rootProject.name = 'StandardNotes'
|
||||
include ':@react-native-community_async-storage'
|
||||
project(':@react-native-community_async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android')
|
||||
include ':react-native-webview'
|
||||
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
|
||||
include ':react-native-file-viewer'
|
||||
project(':react-native-file-viewer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-file-viewer/android')
|
||||
include ':react-native-fs'
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
|
||||
@@ -38,6 +37,7 @@
|
||||
300BF5D7132F46BCAB353149 /* libRNGestureHandler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04047F33889C425483EB8244 /* libRNGestureHandler.a */; };
|
||||
3B66E39D04514331AF08A4D1 /* FontAwesome5_Solid.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 074A7613CE8C41BAB3C4193E /* FontAwesome5_Solid.ttf */; };
|
||||
40F325481D4F4F04AC15D0A9 /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 48127930FB1344778C168838 /* libRNVectorIcons.a */; };
|
||||
4C4C0C80E5254E16BA086A86 /* libRNCWebView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4449457EB3FC4387810027F1 /* libRNCWebView.a */; };
|
||||
5A8928DC2824482A99763067 /* FontAwesome5_Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EF2E9E34ADA441EDB4CE8370 /* FontAwesome5_Regular.ttf */; };
|
||||
5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
|
||||
6C1915C4DE9040A9BB17CFBB /* libRNStoreReview.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADB6F6B9BC7144FCB2C08D40 /* libRNStoreReview.a */; };
|
||||
@@ -58,6 +58,7 @@
|
||||
CDB58A211F6C51A4009EF868 /* libReactNativeFingerprintScanner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB58A0F1F6C5174009EF868 /* libReactNativeFingerprintScanner.a */; };
|
||||
CDB58A221F6C5235009EF868 /* libRCTAes.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB58A091F6C516B009EF868 /* libRCTAes.a */; };
|
||||
F0D84FDB75374348BC0017C2 /* libBugsnagReactNative.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFD3F9197A5F41C0904D7E60 /* libBugsnagReactNative.a */; };
|
||||
7A0B269BD1714EA79E486BAE /* libRNCAsyncStorage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1009A2994551440E819E2CE6 /* libRNCAsyncStorage.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -327,6 +328,13 @@
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RNStoreReview;
|
||||
};
|
||||
CD5AEDE322825CB8002439FB /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = EC178A0479CE4154896293C3 /* RNCWebView.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RNCWebView;
|
||||
};
|
||||
CD885F771F70228400B91C20 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 737AF67874434967865855D8 /* BugsnagReactNative.xcodeproj */;
|
||||
@@ -484,6 +492,7 @@
|
||||
2D02E4901E0B4A5D006451C7 /* StandardNotes-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "StandardNotes-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2FAF1266E8404686B7F36870 /* RNFS.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFS.xcodeproj; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = "<group>"; };
|
||||
37A42F4068AE42DD8D2DF182 /* libRNFileViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFileViewer.a; sourceTree = "<group>"; };
|
||||
4449457EB3FC4387810027F1 /* libRNCWebView.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCWebView.a; sourceTree = "<group>"; };
|
||||
48127930FB1344778C168838 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
|
||||
54ED130E749A46A3B15B27F2 /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
|
||||
59DCF8530F2945FFAA0300FD /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = "<group>"; };
|
||||
@@ -511,8 +520,11 @@
|
||||
CDCF33ADCFE845D588CC4E66 /* libRNKeychain.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNKeychain.a; sourceTree = "<group>"; };
|
||||
CEB6B877AE784055A8E294A8 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
||||
D38724A93AC141D6B51D1356 /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
|
||||
EC178A0479CE4154896293C3 /* RNCWebView.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNCWebView.xcodeproj; path = "../node_modules/react-native-webview/ios/RNCWebView.xcodeproj"; sourceTree = "<group>"; };
|
||||
EF2E9E34ADA441EDB4CE8370 /* FontAwesome5_Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Regular.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf"; sourceTree = "<group>"; };
|
||||
EFD3F9197A5F41C0904D7E60 /* libBugsnagReactNative.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBugsnagReactNative.a; sourceTree = "<group>"; };
|
||||
FF655164AD874250A8F6E20E /* RNCAsyncStorage.xcodeproj */ = {isa = PBXFileReference; name = "RNCAsyncStorage.xcodeproj"; path = "../node_modules/@react-native-community/async-storage/ios/RNCAsyncStorage.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
||||
1009A2994551440E819E2CE6 /* libRNCAsyncStorage.a */ = {isa = PBXFileReference; name = "libRNCAsyncStorage.a"; path = "libRNCAsyncStorage.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -554,6 +566,8 @@
|
||||
300BF5D7132F46BCAB353149 /* libRNGestureHandler.a in Frameworks */,
|
||||
0A7C7EB08AA3465C8E686821 /* libRNFS.a in Frameworks */,
|
||||
9E1F5D0FE7C441D685DAEEAA /* libRNFileViewer.a in Frameworks */,
|
||||
4C4C0C80E5254E16BA086A86 /* libRNCWebView.a in Frameworks */,
|
||||
7A0B269BD1714EA79E486BAE /* libRNCAsyncStorage.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -769,6 +783,8 @@
|
||||
19A39FBB53A3465B81022E02 /* RNGestureHandler.xcodeproj */,
|
||||
2FAF1266E8404686B7F36870 /* RNFS.xcodeproj */,
|
||||
645E3D9167344C3E81B7223C /* RNFileViewer.xcodeproj */,
|
||||
EC178A0479CE4154896293C3 /* RNCWebView.xcodeproj */,
|
||||
FF655164AD874250A8F6E20E /* RNCAsyncStorage.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -842,6 +858,14 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD5AEDE022825CB8002439FB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD5AEDE422825CB8002439FB /* libRNCWebView.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD885F741F70228400B91C20 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -902,6 +926,7 @@
|
||||
04047F33889C425483EB8244 /* libRNGestureHandler.a */,
|
||||
CEB6B877AE784055A8E294A8 /* libRNFS.a */,
|
||||
37A42F4068AE42DD8D2DF182 /* libRNFileViewer.a */,
|
||||
4449457EB3FC4387810027F1 /* libRNCWebView.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
@@ -1127,6 +1152,10 @@
|
||||
ProductGroup = CDB58A0B1F6C5174009EF868 /* Products */;
|
||||
ProjectRef = CDB58A0A1F6C5174009EF868 /* ReactNativeFingerprintScanner.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = CD5AEDE022825CB8002439FB /* Products */;
|
||||
ProjectRef = EC178A0479CE4154896293C3 /* RNCWebView.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = CDEBDDB721E044BD00333D77 /* Products */;
|
||||
ProjectRef = 645E3D9167344C3E81B7223C /* RNFileViewer.xcodeproj */;
|
||||
@@ -1423,6 +1452,13 @@
|
||||
remoteRef = CD4D91841F7BE11800080678 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
CD5AEDE422825CB8002439FB /* libRNCWebView.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRNCWebView.a;
|
||||
remoteRef = CD5AEDE322825CB8002439FB /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
CD885F781F70228400B91C20 /* libBugsnagReactNative.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@@ -1696,6 +1732,8 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-file-viewer/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-webview/ios",
|
||||
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
|
||||
);
|
||||
INFOPLIST_FILE = StandardNotesTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1704,11 +1742,6 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1734,6 +1767,8 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-file-viewer/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-webview/ios",
|
||||
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
|
||||
);
|
||||
INFOPLIST_FILE = StandardNotesTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1742,11 +1777,6 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1776,6 +1806,8 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-file-viewer/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-webview/ios",
|
||||
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
|
||||
);
|
||||
INFOPLIST_FILE = StandardNotes/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1811,6 +1843,8 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-file-viewer/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-webview/ios",
|
||||
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
|
||||
);
|
||||
INFOPLIST_FILE = StandardNotes/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1849,6 +1883,8 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-file-viewer/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-webview/ios",
|
||||
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
|
||||
);
|
||||
INFOPLIST_FILE = "StandardNotes-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1856,11 +1892,6 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1895,6 +1926,8 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-file-viewer/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-webview/ios",
|
||||
"$(SRCROOT)/../node_modules/@react-native-community/async-storage/ios",
|
||||
);
|
||||
INFOPLIST_FILE = "StandardNotes-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1902,11 +1935,6 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1937,11 +1965,6 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.StandardNotes-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1968,11 +1991,6 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.StandardNotes-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -67,11 +67,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.5</string>
|
||||
<string>3.0.6</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5</string>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D2A28121D9B038B00D4039D"
|
||||
BuildableName = "libReact.a"
|
||||
BlueprintName = "React-tvOS"
|
||||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "StandardNotes-tvOS.app"
|
||||
BlueprintName = "StandardNotes-tvOS"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "StandardNotes-tvOSTests.xctest"
|
||||
BlueprintName = "StandardNotes-tvOSTests"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "StandardNotes-tvOSTests.xctest"
|
||||
BlueprintName = "StandardNotes-tvOSTests"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "StandardNotes-tvOS.app"
|
||||
BlueprintName = "StandardNotes-tvOS"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "StandardNotes-tvOS.app"
|
||||
BlueprintName = "StandardNotes-tvOS"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "StandardNotes-tvOS.app"
|
||||
BlueprintName = "StandardNotes-tvOS"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
|
||||
BuildableName = "libReact.a"
|
||||
BlueprintName = "React"
|
||||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "sn_react.app"
|
||||
BlueprintName = "StandardNotes"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "StandardNotesTests.xctest"
|
||||
BlueprintName = "StandardNotesTests"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "StandardNotesTests.xctest"
|
||||
BlueprintName = "StandardNotesTests"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "sn_react.app"
|
||||
BlueprintName = "StandardNotes"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "sn_react.app"
|
||||
BlueprintName = "StandardNotes"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "sn_react.app"
|
||||
BlueprintName = "StandardNotes"
|
||||
ReferencedContainer = "container:StandardNotes.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
@end
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import "RCCManager.h"
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
NSURL *jsCodeLocation;
|
||||
|
||||
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
|
||||
|
||||
// RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
||||
// moduleName:@"sn_react"
|
||||
// initialProperties:nil
|
||||
// launchOptions:launchOptions];
|
||||
// rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
[[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions];
|
||||
|
||||
// self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
// UIViewController *rootViewController = [UIViewController new];
|
||||
// rootViewController.view = rootView;
|
||||
// self.window.rootViewController = rootViewController;
|
||||
// [self.window makeKeyAndVisible];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G23a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>S. Notes</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>Entypo.ttf</string>
|
||||
<string>EvilIcons.ttf</string>
|
||||
<string>FontAwesome.ttf</string>
|
||||
<string>Foundation.ttf</string>
|
||||
<string>Ionicons.ttf</string>
|
||||
<string>MaterialCommunityIcons.ttf</string>
|
||||
<string>MaterialIcons.ttf</string>
|
||||
<string>Octicons.ttf</string>
|
||||
<string>SimpleLineIcons.ttf</string>
|
||||
<string>Zocial.ttf</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)org.reactjs.native.example.sn-react</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
#define TIMEOUT_SECONDS 600
|
||||
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
|
||||
|
||||
@interface sn_reactTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation sn_reactTests
|
||||
|
||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
|
||||
{
|
||||
if (test(view)) {
|
||||
return YES;
|
||||
}
|
||||
for (UIView *subview in [view subviews]) {
|
||||
if ([self findSubviewInView:subview matching:test]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)testRendersWelcomeScreen
|
||||
{
|
||||
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
BOOL foundElement = NO;
|
||||
|
||||
__block NSString *redboxError = nil;
|
||||
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
|
||||
if (level >= RCTLogLevelError) {
|
||||
redboxError = message;
|
||||
}
|
||||
});
|
||||
|
||||
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
|
||||
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
RCTSetLogFunction(RCTDefaultLogFunction);
|
||||
|
||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "StandardNotes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.6",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -2375,6 +2375,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@react-native-community/async-storage": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.4.0.tgz",
|
||||
"integrity": "sha512-Aksg16keqrxaluFRZwmo8O8ppP9TFylyCEwBElmxeZ+a6DQAvyMn5nS3n+lgSpkYsrwU2ZGVjDluhkjtBrkEqQ=="
|
||||
},
|
||||
"@react-navigation/core": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-3.0.2.tgz",
|
||||
@@ -10634,6 +10639,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-webview": {
|
||||
"version": "5.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-5.8.1.tgz",
|
||||
"integrity": "sha512-b6pSvmjoiWtcz6YspggW02X+BRXJWuquHwkh37BRx1NMW1iwMZA31SnFQvTpPzWYYIb9WF/mRsy2nGtt9C6NIg==",
|
||||
"requires": {
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"invariant": "2.2.4"
|
||||
}
|
||||
},
|
||||
"react-navigation": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/react-navigation/-/react-navigation-3.0.9.tgz",
|
||||
@@ -11543,11 +11557,6 @@
|
||||
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
|
||||
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
|
||||
},
|
||||
"sn-models": {
|
||||
"version": "0.1.14",
|
||||
"resolved": "https://registry.npmjs.org/sn-models/-/sn-models-0.1.14.tgz",
|
||||
"integrity": "sha512-p5Tp18sKP68saA4EkdAeYo+X3dNdmGwgqPKL0Bi0Y6lv2SO0LiHPbcBxKcsQjrikE8ePUviJVeckRfMgR5QbYA=="
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||
@@ -11645,6 +11654,11 @@
|
||||
"kind-of": "3.2.2"
|
||||
}
|
||||
},
|
||||
"snjs": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/snjs/-/snjs-0.2.0.tgz",
|
||||
"integrity": "sha512-wkvycOiFKnEewyFDlfN5k+zu3ppvzCdE9YQPR82dWMqwxZK3qCx8RuBGr2p0M4bjyqrPXyVwVrJHbE60kGVRug=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
@@ -11746,9 +11760,9 @@
|
||||
"integrity": "sha1-ATl5IuX2Ls8whFUiyVxP4dJefU4="
|
||||
},
|
||||
"standard-file-js": {
|
||||
"version": "0.3.56",
|
||||
"resolved": "https://registry.npmjs.org/standard-file-js/-/standard-file-js-0.3.56.tgz",
|
||||
"integrity": "sha512-I/iOm53skG+4NsbKdzmGSra6fEj9Qm0xirhUAToaLyXpbWkuQMu+md6SMEJO8Bg9cFmjUhAk1xtxVr3+IPf/eA=="
|
||||
"version": "0.3.58",
|
||||
"resolved": "https://registry.npmjs.org/standard-file-js/-/standard-file-js-0.3.58.tgz",
|
||||
"integrity": "sha512-xkoC+lDK12WPL2+ckD2Ki8WfTsy8TphvwqLS9OASuY06MHdVh9qGGooYvewjXSQkSQTBDrs7f+0mzEX0Rn2AZw=="
|
||||
},
|
||||
"static-extend": {
|
||||
"version": "0.1.2",
|
||||
|
||||
12
package.json
12
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "StandardNotes",
|
||||
"version": "3.0.5",
|
||||
"versionIOS": "3.0.5",
|
||||
"versionAndroid": "3.0.5",
|
||||
"version": "3.0.6",
|
||||
"versionIOS": "3.0.6",
|
||||
"versionAndroid": "3.0.6",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -12,6 +12,7 @@
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-community/async-storage": "1.4.0",
|
||||
"base-64": "^0.1.0",
|
||||
"bugsnag-react-native": "^2.12.6",
|
||||
"immutable": "^3.8.1",
|
||||
@@ -25,11 +26,12 @@
|
||||
"react-native-keychain": "^1.2.1",
|
||||
"react-native-store-review": "^0.1.3",
|
||||
"react-native-vector-icons": "6.1.0",
|
||||
"react-native-webview": "5.8.1",
|
||||
"react-navigation": "^3.0.9",
|
||||
"react-navigation-header-buttons": "^2.1.1",
|
||||
"regenerator": "^0.13.3",
|
||||
"sn-models": "0.1.14",
|
||||
"standard-file-js": "0.3.56"
|
||||
"snjs": "0.2.0",
|
||||
"standard-file-js": "0.3.58"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "^23.6.0",
|
||||
|
||||
@@ -45,10 +45,12 @@ import {
|
||||
SNNote,
|
||||
SNTag,
|
||||
SNTheme,
|
||||
SNComponent
|
||||
} from 'sn-models';
|
||||
SNComponent,
|
||||
SNComponentManager
|
||||
} from 'snjs';
|
||||
|
||||
global.SNNote = SNNote;
|
||||
global.SNTag = SNTag;
|
||||
global.SNTheme = SNTheme;
|
||||
global.SNComponent = SNComponent;
|
||||
global.SNComponentManager = SNComponentManager;
|
||||
|
||||
@@ -1,412 +1,71 @@
|
||||
/* This domain will be used to save context item client data */
|
||||
let ClientDataDomain = "org.standardnotes.sn.components";
|
||||
import ModelManager from "@SFJS/modelManager";
|
||||
import Sync from "@SFJS/syncManager";
|
||||
import AlertManager from "@SFJS/alertManager";
|
||||
import { Platform } from 'react-native';
|
||||
import StyleKit from "@Style/StyleKit"
|
||||
|
||||
import { Platform, Alert } from 'react-native';
|
||||
|
||||
import StyleKit from '@Style/StyleKit'
|
||||
import ModelManager from './sfjs/modelManager'
|
||||
import Sync from './sfjs/syncManager'
|
||||
import SF from "./sfjs/sfjs"
|
||||
import ApplicationState from "@Lib/ApplicationState"
|
||||
|
||||
export default class ComponentManager {
|
||||
export default class ComponentManager extends SNComponentManager {
|
||||
|
||||
static instance = null;
|
||||
|
||||
static get() {
|
||||
if (this.instance == null) {
|
||||
this.instance = new ComponentManager();
|
||||
this.instance = new ComponentManager({
|
||||
modelManager: ModelManager.get(),
|
||||
syncManager: Sync.get(),
|
||||
alertManager: AlertManager.get(),
|
||||
environment: "mobile",
|
||||
platform: Platform.OS
|
||||
});
|
||||
}
|
||||
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.streamObservers = [];
|
||||
this.contextStreamObservers = [];
|
||||
this.activeComponents = [];
|
||||
|
||||
// this.loggingEnabled = true;
|
||||
|
||||
this.handlers = [];
|
||||
|
||||
StyleKit.get().addThemeChangeObserver(() => {
|
||||
this.postActiveThemesToAllComponents();
|
||||
});
|
||||
|
||||
ModelManager.get().addItemSyncObserver("component-manager", "*", (allItems, validItems, deletedItems, source) => {
|
||||
|
||||
/* If the source of these new or updated items is from a Component itself saving items, we don't need to notify
|
||||
components again of the same item. Regarding notifying other components than the issuing component, other mapping sources
|
||||
will take care of that, like ModelManager.MappingSourceRemoteSaved
|
||||
*/
|
||||
if(source == SFModelManager.MappingSourceComponentRetrieved) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(let observer of this.contextStreamObservers) {
|
||||
for(let handler of this.handlers) {
|
||||
if(!handler.areas.includes(observer.component.area) && !handler.areas.includes("*")) {
|
||||
continue;
|
||||
}
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(observer.component);
|
||||
if(itemInContext) {
|
||||
var matchingItem = _.find(allItems, {uuid: itemInContext.uuid});
|
||||
if(matchingItem) {
|
||||
this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
constructor({modelManager, syncManager, desktopManager, nativeExtManager,
|
||||
alertManager, $uiRunner, platform, environment}) {
|
||||
super({modelManager, syncManager, desktopManager, nativeExtManager,
|
||||
alertManager, $uiRunner, platform, environment});
|
||||
}
|
||||
|
||||
contextItemDidChangeInArea(area) {
|
||||
for(let handler of this.handlers) {
|
||||
if(handler.areas.includes(area) === false && !handler.areas.includes("*")) {
|
||||
continue;
|
||||
}
|
||||
var observers = this.contextStreamObservers.filter(function(observer){
|
||||
return observer.component.area === area;
|
||||
})
|
||||
/*
|
||||
Overrides
|
||||
*/
|
||||
|
||||
for(let observer of observers) {
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(observer.component);
|
||||
this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsonForItem(item, component, source) {
|
||||
var params = {uuid: item.uuid, content_type: item.content_type, created_at: item.created_at, updated_at: item.updated_at, deleted: item.deleted};
|
||||
params.content = item.createContentJSONFromProperties();
|
||||
params.clientData = item.getDomainDataItem(component.getClientDataKey(), ClientDataDomain) || {};
|
||||
|
||||
/* This means the this function is being triggered through a remote Saving response, which should not update
|
||||
actual local content values. The reason is, Save responses may be delayed, and a user may have changed some values
|
||||
in between the Save was initiated, and the time it completes. So we only want to update actual content values (and not just metadata)
|
||||
when its another source, like ModelManager.MappingSourceRemoteRetrieved.
|
||||
|
||||
3/7/18: Add MappingSourceLocalSaved as well to handle fully offline saving. github.com/standardnotes/forum/issues/169
|
||||
*/
|
||||
if(source && (source == SFModelManager.MappingSourceRemoteSaved || source == SFModelManager.MappingSourceLocalSaved)) {
|
||||
params.isMetadataUpdate = true;
|
||||
}
|
||||
this.removePrivatePropertiesFromResponseItems([params], component);
|
||||
return params;
|
||||
}
|
||||
|
||||
sendItemsInReply(component, items, message, source) {
|
||||
if(this.loggingEnabled) {console.log("Web|componentManager|sendItemsInReply", component.name, items, message)};
|
||||
var response = {items: {}};
|
||||
var mapped = items.map(function(item) {
|
||||
return this.jsonForItem(item, component, source);
|
||||
}.bind(this));
|
||||
|
||||
response.items = mapped;
|
||||
this.replyToMessage(component, message, response);
|
||||
}
|
||||
|
||||
sendContextItemInReply(component, item, originalMessage, source) {
|
||||
if(this.loggingEnabled) {console.log("Web|componentManager|sendContextItemInReply", component.name, item, originalMessage)};
|
||||
var response = {item: this.jsonForItem(item, component, source)};
|
||||
this.replyToMessage(component, originalMessage, response);
|
||||
}
|
||||
|
||||
replyToMessage(component, originalMessage, replyData) {
|
||||
var reply = {
|
||||
action: "reply",
|
||||
original: originalMessage,
|
||||
data: replyData
|
||||
}
|
||||
|
||||
this.sendMessageToComponent(component, reply);
|
||||
}
|
||||
|
||||
sendMessageToComponent(component, message) {
|
||||
let permissibleActionsWhileHidden = ["component-registered", "themes"];
|
||||
if(component.hidden && !permissibleActionsWhileHidden.includes(message.action)) {
|
||||
if(this.loggingEnabled) {
|
||||
console.log("Component disabled for current item, not sending any messages.", component.name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.loggingEnabled) {
|
||||
console.log("Web|sendMessageToComponent", component.name, JSON.stringify(message));
|
||||
}
|
||||
component.window.postMessage(JSON.stringify(message));
|
||||
}
|
||||
|
||||
get components() {
|
||||
return ModelManager.get().allItemsMatchingTypes(["SN|Component", "SN|Theme"]);
|
||||
}
|
||||
|
||||
componentsForArea(area) {
|
||||
return this.components.filter(function(component){
|
||||
return component.area === area;
|
||||
})
|
||||
}
|
||||
|
||||
urlForComponent(component) {
|
||||
var localReplacement = ApplicationState.isIOS ? "localhost" : "10.0.2.2";
|
||||
var url = component.hosted_url || component.url;
|
||||
if(url) {
|
||||
url = url.replace("localhost", localReplacement).replace("sn.local", localReplacement);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
componentForUrl(url) {
|
||||
return this.components.filter(function(component){
|
||||
return component.url === url || component.hosted_url === url;
|
||||
})[0];
|
||||
}
|
||||
|
||||
componentForSessionKey(key) {
|
||||
return _.find(this.components, {sessionKey: key});
|
||||
}
|
||||
|
||||
isReadOnlyMessage(message) {
|
||||
let writeActions = ["save-items", "delete-items", "create-item"]
|
||||
// Ensure the message action is not one of the writeActions
|
||||
return !writeActions.includes(message.action);
|
||||
}
|
||||
|
||||
handleMessage(component, message) {
|
||||
|
||||
if(!component) {
|
||||
if(this.loggingEnabled) {
|
||||
console.log("Component not defined, returning");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Actions that won't succeeed with readonly mode
|
||||
let readwriteActions = [
|
||||
"save-items",
|
||||
"associate-item",
|
||||
"deassociate-item",
|
||||
"create-item",
|
||||
"create-items",
|
||||
"delete-items",
|
||||
"set-component-data"
|
||||
];
|
||||
|
||||
if(component.readonly && readwriteActions.includes(message.action)) {
|
||||
Alert.alert('Extended Expired', `The extension ${component.name} is trying to save, but it is in a locked state and cannot accept changes.`);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Mobile only handles a subset of possible messages.
|
||||
Possible Messages:
|
||||
set-component-data
|
||||
stream-context-item
|
||||
save-items
|
||||
*/
|
||||
|
||||
if(message.action === "stream-context-item") {
|
||||
this.handleStreamContextItemMessage(component, message);
|
||||
} else if(message.action === "set-component-data") {
|
||||
this.handleSetComponentDataMessage(component, message);
|
||||
} else if(message.action === "save-items") {
|
||||
this.handleSaveItemsMessage(component, message);
|
||||
}
|
||||
|
||||
// Notify observers
|
||||
for(let handler of this.handlers) {
|
||||
if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
|
||||
setTimeout(function () {
|
||||
handler.actionHandler && handler.actionHandler(component, message.action, message.data);
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removePrivatePropertiesFromResponseItems(responseItems, component, options = {}) {
|
||||
// Don't allow component to overwrite these properties.
|
||||
var privateProperties = ["autoupdateDisabled", "permissions", "active"];
|
||||
if(options) {
|
||||
if(options.includeUrls) { privateProperties = privateProperties.concat(["url", "hosted_url", "local_url"])}
|
||||
}
|
||||
for(var responseItem of responseItems) {
|
||||
// Do not pass in actual items here, otherwise that would be destructive.
|
||||
// Instead, generic JS/JSON objects should be passed.
|
||||
for(var prop of privateProperties) {
|
||||
delete responseItem.content[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleStreamContextItemMessage(component, message) {
|
||||
|
||||
if(!_.find(this.contextStreamObservers, {identifier: component.uuid})) {
|
||||
// for pushing laster as changes come in
|
||||
this.contextStreamObservers.push({
|
||||
identifier: component.uuid,
|
||||
component: component,
|
||||
originalMessage: message
|
||||
})
|
||||
}
|
||||
|
||||
// push immediately now
|
||||
for(let handler of this.handlersForArea(component.area)) {
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(component);
|
||||
this.sendContextItemInReply(component, itemInContext, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isItemWithinComponentContextJurisdiction(item, component) {
|
||||
for(let handler of this.handlersForArea(component.area)) {
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(component);
|
||||
if(itemInContext && itemInContext.uuid == item.uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
handlersForArea(area) {
|
||||
return this.handlers.filter((candidate) => {return candidate.areas.includes(area)});
|
||||
}
|
||||
|
||||
handleSaveItemsMessage(component, message) {
|
||||
var responseItems = message.data.items;
|
||||
|
||||
// Ensure you're just trying to save the context item
|
||||
if(!(responseItems.length == 1 && this.isItemWithinComponentContextJurisdiction(responseItems[0], component))) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.removePrivatePropertiesFromResponseItems(responseItems, component, {includeUrls: true});
|
||||
|
||||
/*
|
||||
We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
|
||||
this would update them server side via sync, but would never make its way back to the UI.
|
||||
*/
|
||||
var localItems = ModelManager.get().mapResponseItemsToLocalModels(responseItems, SFModelManager.MappingSourceComponentRetrieved);
|
||||
|
||||
for(var item of localItems) {
|
||||
var responseItem = _.find(responseItems, {uuid: item.uuid});
|
||||
_.merge(item.content, responseItem.content);
|
||||
if(responseItem.clientData) {
|
||||
item.setDomainDataItem(component.url || component.uuid, responseItem.clientData, ClientDataDomain);
|
||||
}
|
||||
item.setDirty(true);
|
||||
}
|
||||
|
||||
Sync.get().sync().then((response) => {
|
||||
// Allow handlers to be notified when a save begins and ends, to update the UI
|
||||
var saveMessage = Object.assign({}, message);
|
||||
saveMessage.action = (response && response.error) ? "save-error" : "save-success";
|
||||
this.replyToMessage(component, message, {error: response && response.error})
|
||||
this.handleMessage(component, saveMessage);
|
||||
});
|
||||
}
|
||||
|
||||
handleSetComponentDataMessage(component, message) {
|
||||
component.componentData = message.data.componentData;
|
||||
component.setDirty(true);
|
||||
Sync.get().sync();
|
||||
}
|
||||
|
||||
registerHandler(handler) {
|
||||
this.handlers.push(handler);
|
||||
}
|
||||
|
||||
deregisterHandler(identifier) {
|
||||
var handler = _.find(this.handlers, {identifier: identifier});
|
||||
this.handlers.splice(this.handlers.indexOf(handler), 1);
|
||||
}
|
||||
|
||||
// Called by other views when the iframe is ready
|
||||
async registerComponentWindow(component, componentWindow) {
|
||||
if(!component) { console.error("component is null");}
|
||||
if(!componentWindow) { console.error("componentWindow is null");}
|
||||
|
||||
if(component.window === componentWindow) {
|
||||
if(this.loggingEnabled) {
|
||||
console.log("Web|componentManager", "attempting to re-register same component window.")
|
||||
}
|
||||
}
|
||||
|
||||
if(this.loggingEnabled) {
|
||||
console.log("Web|componentManager|registerComponentWindow");
|
||||
}
|
||||
|
||||
component.window = componentWindow;
|
||||
component.sessionKey = await SF.get().crypto.generateUUID();
|
||||
|
||||
this.sendMessageToComponent(component, {
|
||||
action: "component-registered",
|
||||
sessionKey: component.sessionKey,
|
||||
componentData: component.componentData,
|
||||
data: {
|
||||
uuid: component.uuid,
|
||||
environment: "mobile",
|
||||
platform: Platform.OS,
|
||||
activeThemeUrls: [this.getActiveThemeUrl()]
|
||||
}
|
||||
});
|
||||
|
||||
// Some editors may not yet accept initial activeThemeUrls in component-registerd event
|
||||
this.postActiveThemeToComponent(component);
|
||||
}
|
||||
|
||||
deactivateComponent(component, dontSync = false) {
|
||||
component.active = false;
|
||||
component.sessionKey = null;
|
||||
|
||||
this.streamObservers = this.streamObservers.filter(function(o){
|
||||
return o.component !== component;
|
||||
})
|
||||
|
||||
this.contextStreamObservers = this.contextStreamObservers.filter(function(o){
|
||||
return o.component !== component;
|
||||
})
|
||||
}
|
||||
|
||||
getActiveThemeUrl() {
|
||||
urlsForActiveThemes() {
|
||||
let theme = StyleKit.get().activeTheme;
|
||||
if(theme.content.isSystemTheme) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(theme) {
|
||||
let url = this.urlForComponent(theme);
|
||||
return url;
|
||||
return [url];
|
||||
}
|
||||
}
|
||||
|
||||
postActiveThemeToComponent(component) {
|
||||
let url = this.getActiveThemeUrl();
|
||||
if(!url) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
@param {object} dialog: {permissions, String, component, callback}
|
||||
*/
|
||||
|
||||
var data = { themes: [url] }
|
||||
|
||||
this.sendMessageToComponent(component, {action: "themes", data: data})
|
||||
presentPermissionsDialog(dialog) {
|
||||
let text = `${dialog.component.name} would like to interact with your ${dialog.permissionsString}`;
|
||||
this.alertManager.confirm({
|
||||
title: "Grant Permissions",
|
||||
text: text,
|
||||
confirmButtonText: "Continue",
|
||||
cancelButtonText: "Cancel",
|
||||
onConfirm: () => {dialog.callback(true)},
|
||||
onCancel: () => {dialog.callback(false)},
|
||||
})
|
||||
}
|
||||
|
||||
postActiveThemesToAllComponents() {
|
||||
for(var component of this.components) {
|
||||
// Skip over components that are themes themselves,
|
||||
// or components that are not active, or components that don't have a window
|
||||
// On desktop/web, we check if component.active is true as well below, but on mobile,
|
||||
// .active isn't set
|
||||
if(component.isTheme() || !component.window) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.postActiveThemeToComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Custom functions, not overrides
|
||||
*/
|
||||
|
||||
getEditors() {
|
||||
return this.componentsForArea("editor-editor");
|
||||
@@ -416,23 +75,6 @@ export default class ComponentManager {
|
||||
return this.getEditors().filter((e) => {return e.content.isMobileDefault})[0];
|
||||
}
|
||||
|
||||
editorForNote(note) {
|
||||
let editors = ModelManager.get().validItemsForContentType("SN|Component").filter(function(component){
|
||||
return component.area == "editor-editor";
|
||||
})
|
||||
|
||||
for(var editor of editors) {
|
||||
if(editor.isExplicitlyEnabledForItem(note)) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
// No editor found for note. Use default editor, if note does not prefer system editor
|
||||
if(!note.content.mobilePrefersPlainEditor) {
|
||||
return this.getDefaultEditor();
|
||||
}
|
||||
}
|
||||
|
||||
setEditorAsMobileDefault(editor, isDefault) {
|
||||
if(isDefault) {
|
||||
// Remove current default
|
||||
@@ -443,7 +85,7 @@ export default class ComponentManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Could be null if plain editor
|
||||
// Could be null if plain editor
|
||||
if(editor) {
|
||||
editor.content.isMobileDefault = isDefault;
|
||||
editor.setDirty(true);
|
||||
|
||||
@@ -2,7 +2,7 @@ import {Platform} from 'react-native';
|
||||
import * as StoreReview from 'react-native-store-review';
|
||||
import Storage from "./sfjs/storageManager";
|
||||
|
||||
let NumRunsBeforeAskingForReview = [18, 65, 120]
|
||||
let NumRunsBeforeAskingForReview = [18, 45, 105]
|
||||
|
||||
export default class ReviewManager {
|
||||
|
||||
|
||||
@@ -12,6 +12,19 @@ export default class AlertManager extends SFAlertManager {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
async alert({title, text, closeButtonText = "OK", onClose} = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// On iOS, confirm should go first. On Android, cancel should go first.
|
||||
let buttons = [
|
||||
{text: closeButtonText, onPress: () => {
|
||||
resolve();
|
||||
onClose && onClose();
|
||||
}},
|
||||
];
|
||||
Alert.alert(title, text, buttons, { cancelable: true })
|
||||
})
|
||||
}
|
||||
|
||||
async confirm({title, text, confirmButtonText = "OK", cancelButtonText = "Cancel", onConfirm, onCancel} = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// On iOS, confirm should go first. On Android, cancel should go first.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Storage from "./storageManager"
|
||||
import "../../models/extend/item.js";
|
||||
import { SFPredicate, SFPrivileges } from "standard-file-js";
|
||||
import { SNMfa, SNServerExtension, SNExtension, SNEditor } from 'sn-models';
|
||||
import { SNMfa, SNServerExtension, SNExtension, SNEditor } from 'snjs';
|
||||
|
||||
SFModelManager.ContentTypeClassMapping = {
|
||||
"Note" : SNNote,
|
||||
@@ -251,4 +251,25 @@ export default class ModelManager extends SFModelManager {
|
||||
|
||||
return {notes: notes, tags: tags};
|
||||
}
|
||||
|
||||
/*
|
||||
Misc
|
||||
*/
|
||||
|
||||
humanReadableDisplayForContentType(contentType) {
|
||||
return {
|
||||
"Note" : "note",
|
||||
"Tag" : "tag",
|
||||
"SN|SmartTag": "smart tag",
|
||||
"Extension" : "action-based extension",
|
||||
"SN|Component" : "component",
|
||||
"SN|Editor" : "editor",
|
||||
"SN|Theme" : "theme",
|
||||
"SF|Extension" : "server extension",
|
||||
"SF|MFA" : "two-factor authentication setting",
|
||||
"SN|FileSafe|Credentials": "FileSafe credential",
|
||||
"SN|FileSafe|FileMetadata": "FileSafe file",
|
||||
"SN|FileSafe|Integration": "FileSafe integration"
|
||||
}[contentType];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,9 @@ export default class PrivilegesManager extends SFPrivilegesManager {
|
||||
let credentials = await this.netCredentialsForAction(action);
|
||||
let sources = [];
|
||||
for(var credential of credentials) {
|
||||
sources = sources.concat(sourcesForCredential(credential));
|
||||
sources = sources.concat(sourcesForCredential(credential)).sort((a, b) => {
|
||||
return a.sort - b.sort;
|
||||
})
|
||||
}
|
||||
|
||||
return sources;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { AsyncStorage } from 'react-native';
|
||||
import { Platform } from 'react-native';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import AlertManager from './alertManager';
|
||||
|
||||
export default class Storage extends SFStorageManager {
|
||||
|
||||
@@ -12,6 +14,12 @@ export default class Storage extends SFStorageManager {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.isAndroid = Platform.OS == 'android';
|
||||
this.platformString = this.isAndroid ? "Android" : "iOS";
|
||||
}
|
||||
|
||||
async getItem(key) {
|
||||
try {
|
||||
return AsyncStorage.getItem(key);
|
||||
@@ -59,25 +67,109 @@ export default class Storage extends SFStorageManager {
|
||||
|
||||
// Models
|
||||
|
||||
async getAllModels() {
|
||||
var items = [];
|
||||
var keys = await AsyncStorage.getAllKeys();
|
||||
|
||||
var stores = await AsyncStorage.multiGet(keys);
|
||||
stores.map((result, i, store) => {
|
||||
// get at each store's key/value so you can work with it
|
||||
let key = store[i][0];
|
||||
if(key.includes("Item-")) {
|
||||
async getAllModels() {
|
||||
const itemsFromStores = (stores) => {
|
||||
let items = [];
|
||||
stores.map((result, i, store) => {
|
||||
let key = store[i][0];
|
||||
let value = store[i][1];
|
||||
if(value) {
|
||||
items.push(JSON.parse(value));
|
||||
}
|
||||
})
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/*
|
||||
As of react-native-asyncstorage 1.4.0:
|
||||
|
||||
If Android has items saved that are over ~1MB, then:
|
||||
|
||||
let stores = await AsyncStorage.multiGet(keys);
|
||||
items = items.concat(itemsFromStores(stores));
|
||||
|
||||
will fail silently and no items will load.
|
||||
|
||||
let item = await AsyncStorage.getItem(key);
|
||||
items.push(JSON.parse(item));
|
||||
|
||||
will fail with an exception 'Cursor Window: Window is full'.
|
||||
But actually if you wrap it in a try catch, then it will throw an exception correctly.
|
||||
So that's what we're using now on Android.
|
||||
|
||||
let item = itemsFromStores(await AsyncStorage.multiGet([key]))[0];
|
||||
items.push(item);
|
||||
|
||||
will succeed completely.
|
||||
|
||||
Issue created here: https://github.com/react-native-community/react-native-async-storage/issues/105
|
||||
|
||||
So what we'll do for now is if Android, use multiGet with just 1 key each time.
|
||||
We need to determine why multiGet([key]) works, but getItem(key) doesn't.
|
||||
|
||||
It looks like the reason getItem fails while multiGet doesn't is because getItem
|
||||
correctly returns the exception. However, even when there is an exception, getItem
|
||||
internally still retrieves the item value. So the value and exception are both present,
|
||||
but only the exception is sent.
|
||||
|
||||
Whereas with multiGet, exceptions aren't reported at all, so the value is sent up.
|
||||
When multiGet gets patched to reports errors, I suspect this loophole will no longer work.
|
||||
|
||||
However, getItem's `callback` param can be used instead of the promise, which will return both a value and an exception,
|
||||
and we can choose which one we want to handle.
|
||||
|
||||
multiGet also currently totally fails if even 1 key fails:
|
||||
https://github.com/react-native-community/react-native-async-storage/issues/106
|
||||
*/
|
||||
|
||||
let keys = await this.getAllModelKeys();
|
||||
let items = [];
|
||||
let failedItemIds = [];
|
||||
if(this.isAndroid) {
|
||||
for(let key of keys) {
|
||||
try {
|
||||
let item = await AsyncStorage.getItem(key);
|
||||
if(item) {
|
||||
items.push(JSON.parse(item));
|
||||
}
|
||||
} catch (e) {
|
||||
let id = key.replace("Item-", "");
|
||||
failedItemIds.push(id);
|
||||
console.log("Error getting item", key, e);
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
try {
|
||||
let stores = await AsyncStorage.multiGet(keys);
|
||||
items = items.concat(itemsFromStores(stores));
|
||||
} catch(e) {
|
||||
console.log("Error getting items", keys, e);
|
||||
}
|
||||
}
|
||||
|
||||
if(failedItemIds.length > 0) {
|
||||
this.showLoadFailForItemIds(failedItemIds);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
showLoadFailForItemIds(failedItemIds) {
|
||||
let text = `The following items could not be loaded. This may happen if you are in low-memory conditions, or if the note is very large in size. For compatibility with ${this.platformString}, we recommend breaking up large notes into smaller chunks using the desktop or web app.\n\nItems:\n`
|
||||
let index = 0;
|
||||
text += failedItemIds.map((id) => {
|
||||
let result = id;
|
||||
if(index != failedItemIds.length - 1) {
|
||||
result += "\n";
|
||||
}
|
||||
index++;
|
||||
return result;
|
||||
})
|
||||
AlertManager.get().alert({title: "Unable to load item", text: text})
|
||||
}
|
||||
|
||||
keyForItem(item) {
|
||||
return "Item-" + item.uuid;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,16 @@ SFItem.prototype.updateFromJSON = function(json) {
|
||||
}
|
||||
}
|
||||
|
||||
const original_dateToLocalizedString = SFItem.prototype.dateToLocalizedString;
|
||||
SFItem.prototype.dateToLocalizedString = function(date) {
|
||||
return moment(date).format('llll');
|
||||
}
|
||||
|
||||
SFItem.prototype.updatedAtTimestamp = function() {
|
||||
// date is a moment date
|
||||
// in the base class we do date.getTime(), but that doesn't work with moment dates.
|
||||
return this.updated_at.valueOf();
|
||||
}
|
||||
|
||||
// Define these getters
|
||||
|
||||
Object.defineProperty(SFItem.prototype, "key", {
|
||||
|
||||
@@ -77,6 +77,7 @@ export default class Authenticate extends Abstract {
|
||||
}
|
||||
|
||||
submitPressed() {
|
||||
// If we just pressed submit on the only pending source left, disable submit button
|
||||
if(this.pendingSources.length == 1) {
|
||||
this.setState({submitDisabled: true});
|
||||
}
|
||||
@@ -114,13 +115,11 @@ export default class Authenticate extends Abstract {
|
||||
}
|
||||
|
||||
async beginAuthenticationForSource(source) {
|
||||
if(ApplicationState.get().getMostRecentState() == ApplicationState.LosingFocus) {
|
||||
// Authentication modal may be displayed on lose focus just before the app is closing.
|
||||
// In this state however, we don't want to begin auth. We'll wait until the app gains focus.
|
||||
return;
|
||||
}
|
||||
// Authentication modal may be displayed on lose focus just before the app is closing.
|
||||
// In this state however, we don't want to begin auth. We'll wait until the app gains focus.
|
||||
let isLosingFocus = ApplicationState.get().getMostRecentState() == ApplicationState.LosingFocus;
|
||||
|
||||
if(source.type == "biometric") {
|
||||
if(source.type == "biometric" && !isLosingFocus) {
|
||||
// Begin authentication right away, we're not waiting for any input
|
||||
this.validateAuthentication(source);
|
||||
} else if(source.type == "input") {
|
||||
@@ -128,6 +127,7 @@ export default class Authenticate extends Abstract {
|
||||
source.inputRef.focus();
|
||||
}
|
||||
}
|
||||
|
||||
source.setWaitingForInput();
|
||||
this.setState({activeSource: source});
|
||||
this.forceUpdate();
|
||||
@@ -160,10 +160,14 @@ export default class Authenticate extends Abstract {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable submit while we're processing. Will be re-enabled below.
|
||||
this.setState({submitDisabled: true});
|
||||
|
||||
let result = await source.authenticate();
|
||||
if(source.isInSuccessState()) {
|
||||
this.successfulSources.push(source);
|
||||
_.pull(this.pendingSources, source);
|
||||
this.forceUpdate();
|
||||
} else {
|
||||
if(result.error && result.error.message) {
|
||||
Alert.alert("Unsuccessful", result.error.message);
|
||||
|
||||
@@ -9,6 +9,10 @@ export default class AuthenticationSourceAccountPassword extends AuthenticationS
|
||||
super();
|
||||
}
|
||||
|
||||
get sort() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
get identifier() {
|
||||
return "account-password-auth-source";
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ export default class AuthenticationSourceBiometric extends AuthenticationSource
|
||||
})
|
||||
}
|
||||
|
||||
get sort() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
get identifier() {
|
||||
return "biometric-auth-source";
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ export default class AuthenticationSourceLocalPasscode extends AuthenticationSou
|
||||
});
|
||||
}
|
||||
|
||||
get sort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
get identifier() {
|
||||
return "local-passcode-auth-source";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Alert, View, WebView, Linking, Platform, Text } from 'react-native';
|
||||
import { Alert, View, Linking, Platform, Text } from 'react-native';
|
||||
import { WebView } from 'react-native-webview';
|
||||
|
||||
import ComponentManager from '@Lib/componentManager'
|
||||
import ModelManager from '@Lib/sfjs/modelManager'
|
||||
@@ -8,7 +9,7 @@ import StyleKit from "@Style/StyleKit"
|
||||
import ApplicationState from "@Lib/ApplicationState"
|
||||
import Icon from 'react-native-vector-icons/Ionicons';
|
||||
|
||||
export default class Webview extends Component {
|
||||
export default class ComponentView extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -25,12 +26,6 @@ export default class Webview extends Component {
|
||||
}
|
||||
});
|
||||
|
||||
this.keyboardListener = ApplicationState.get().addEventHandler((event, data) => {
|
||||
if(event == ApplicationState.KeyboardChangeEvent) {
|
||||
this.webView.injectJavaScript(`window.scrollTo(0,0); document.body.scrollTop = 0`);
|
||||
}
|
||||
});
|
||||
|
||||
this.reloadData();
|
||||
|
||||
if(!this.note) {
|
||||
@@ -49,7 +44,7 @@ export default class Webview extends Component {
|
||||
componentDidMount() {
|
||||
if(Platform.OS == "android" && Platform.Version <= 23) {
|
||||
// postMessage doesn't work on Android <= 6 (API version 23) https://github.com/facebook/react-native/issues/11594
|
||||
Alert.alert('Editors Not Supported', `Your version of Android does not support web editors. Changes you make may not be properly saved. Please switch to the Plain Editor for the best experience.`, [{text: 'OK'}])
|
||||
Alert.alert('Editors Not Supported', `Web editors require Android 7.0 or greater. Your version does not support web editors. Changes you make may not be properly saved. Please switch to the Plain Editor for the best experience.`, [{text: 'OK'}])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +66,6 @@ export default class Webview extends Component {
|
||||
componentWillUnmount() {
|
||||
ComponentManager.get().deregisterHandler(this.identifier);
|
||||
ComponentManager.get().deactivateComponent(this.editor);
|
||||
ApplicationState.get().removeEventHandler(this.keyboardListener);
|
||||
}
|
||||
|
||||
onMessage = (message) => {
|
||||
@@ -80,7 +74,7 @@ export default class Webview extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
var data;
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(message.nativeEvent.data);
|
||||
} catch (e) {
|
||||
@@ -88,14 +82,6 @@ export default class Webview extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore any incoming events (like save events) if the note is locked. Allow messages that are required for component setup (administrative)
|
||||
if(this.note.locked && !ComponentManager.get().isReadOnlyMessage(data)) {
|
||||
if(!this.didShowLockAlert) {
|
||||
Alert.alert('Note Locked', "This note is locked. Changes you make in the web editor will not be saved. Please unlock this note to make changes.", [{text: 'OK'}])
|
||||
this.didShowLockAlert = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
ComponentManager.get().handleMessage(this.editor, data);
|
||||
}
|
||||
|
||||
@@ -107,6 +93,7 @@ export default class Webview extends Component {
|
||||
if(this.registrationTimeout) {
|
||||
clearTimeout(this.registrationTimeout);
|
||||
}
|
||||
|
||||
this.registrationTimeout = setTimeout(() => {
|
||||
ComponentManager.get().registerComponentWindow(this.editor, this.webView);
|
||||
}, 1);
|
||||
@@ -134,6 +121,26 @@ export default class Webview extends Component {
|
||||
this.props.onLoadError();
|
||||
}
|
||||
|
||||
onShouldStartLoadWithRequest = (request) => {
|
||||
/*
|
||||
We want to handle link clicks within an editor by opening the browser instead of loading inline.
|
||||
On iOS, onShouldStartLoadWithRequest is called for all requests including the initial request to load the editor.
|
||||
On iOS, clicks in the editors have a navigationType of 'click', but on Android, this is not the case (no navigationType).
|
||||
However, on Android, this function is not called for the initial request.
|
||||
So that might be one way to determine if this request is a click or the actual editor load request.
|
||||
But I don't think it's safe to rely on this being the case in the future.
|
||||
So on Android, we'll handle url loads only if the url isn't equal to the editor url.
|
||||
*/
|
||||
|
||||
let editorUrl = ComponentManager.get().urlForComponent(this.editor);
|
||||
if((ApplicationState.isIOS && request.navigationType == 'click')
|
||||
|| (ApplicationState.isAndroid && request.url != editorUrl)) {
|
||||
ApplicationState.openURL(request.url);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
var editor = this.editor;
|
||||
var url = ComponentManager.get().urlForComponent(editor);
|
||||
@@ -158,12 +165,17 @@ export default class Webview extends Component {
|
||||
onMessage={this.onMessage}
|
||||
useWebKit={true}
|
||||
hideKeyboardAccessoryView={true}
|
||||
onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
|
||||
cacheEnabled={true}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
contentInset={{top: 0, left: 0, bottom: 0, right: 0}}
|
||||
scalesPageToFit={true /* Android only, not available with WKWebView */}
|
||||
injectedJavaScript = {
|
||||
`window.isNative = "true"`
|
||||
`(function() {
|
||||
window.parent.postMessage = function(data) {
|
||||
window.parent.ReactNativeWebView.postMessage(data);
|
||||
};
|
||||
|
||||
return true;
|
||||
})()`
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
@@ -7,7 +7,7 @@ import OptionsState from "@Lib/OptionsState"
|
||||
import SideMenuManager from "@SideMenu/SideMenuManager"
|
||||
|
||||
import Abstract from "./Abstract"
|
||||
import Webview from "./Webview"
|
||||
import ComponentView from "./ComponentView"
|
||||
import ComponentManager from '@Lib/componentManager'
|
||||
import ApplicationState from "@Lib/ApplicationState"
|
||||
import LockedView from "@Containers/LockedView";
|
||||
@@ -351,6 +351,7 @@ export default class Compose extends Abstract {
|
||||
}
|
||||
|
||||
showSavedStatus(success) {
|
||||
const debouceMs = 300; // minimum time message is shown
|
||||
if(success) {
|
||||
if(this.statusTimeout) clearTimeout(this.statusTimeout);
|
||||
this.statusTimeout = setTimeout(() => {
|
||||
@@ -361,14 +362,14 @@ export default class Compose extends Abstract {
|
||||
this.saveError = false;
|
||||
this.syncTakingTooLong = false;
|
||||
this.setSubTitle(status);
|
||||
}, 200)
|
||||
}, debouceMs)
|
||||
} else {
|
||||
if(this.statusTimeout) clearTimeout(this.statusTimeout);
|
||||
this.statusTimeout = setTimeout(function(){
|
||||
this.saveError = true;
|
||||
this.syncTakingTooLong = false;
|
||||
this.setSubTitle("Sync Unavailable (changes saved offline)", StyleKit.variables.stylekitWarningColor);
|
||||
}.bind(this), 200)
|
||||
}.bind(this), debouceMs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +404,7 @@ export default class Compose extends Abstract {
|
||||
}
|
||||
}
|
||||
this.save();
|
||||
}, 275)
|
||||
}, 325);
|
||||
}
|
||||
|
||||
sync(note, callback) {
|
||||
@@ -510,7 +511,7 @@ export default class Compose extends Abstract {
|
||||
}
|
||||
|
||||
{shouldDisplayEditor &&
|
||||
<Webview
|
||||
<ComponentView
|
||||
key={noteEditor.uuid}
|
||||
noteId={this.note.uuid}
|
||||
editorId={noteEditor.uuid}
|
||||
|
||||
@@ -26,9 +26,10 @@ export default class NoteCell extends ThemedPureComponent {
|
||||
|
||||
_onPressIn = () => {
|
||||
// Debounce
|
||||
const delay = 25;
|
||||
this.selectionTimeout = setTimeout(() => {
|
||||
this.setState({selected: true});
|
||||
}, 30);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
_onPressOut = () => {
|
||||
@@ -152,6 +153,13 @@ export default class NoteCell extends ThemedPureComponent {
|
||||
})
|
||||
}
|
||||
|
||||
if(note.content.conflict_of) {
|
||||
flags.push({
|
||||
text: "Conflicted Copy",
|
||||
color: StyleKit.variables.stylekitDangerColor
|
||||
})
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -200,10 +208,6 @@ export default class NoteCell extends ThemedPureComponent {
|
||||
<Text style={this.styles.deleting}>Deleting...</Text>
|
||||
}
|
||||
|
||||
{note.conflict_of &&
|
||||
<Text style={this.styles.deleting}>Conflicted Copy</Text>
|
||||
}
|
||||
|
||||
{flags.length > 0 &&
|
||||
<View style={this.styles.flagsContainer}>
|
||||
{flags.map((flag) =>
|
||||
|
||||
@@ -60,6 +60,7 @@ export default class NoteList extends ThemedComponent {
|
||||
locked={item.locked /* extraData */}
|
||||
protected={item.content.protected /* extraData */}
|
||||
hidePreview={item.content.hidePreview /* extraData */}
|
||||
conflictOf={item.content.conflict_of /* extraData */}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -332,7 +332,8 @@ export default class Notes extends Abstract {
|
||||
_onRefresh() {
|
||||
this.setSubTitle("Syncing...");
|
||||
this.setState({refreshing: true});
|
||||
Sync.get().sync().then(() => {
|
||||
// Perform integrity checks for hard reloads
|
||||
Sync.get().sync({performIntegrityCheck: true}).then(() => {
|
||||
setTimeout(() => {
|
||||
this.setSubTitle(null);
|
||||
}, 100);
|
||||
@@ -353,8 +354,10 @@ export default class Notes extends Abstract {
|
||||
|
||||
_onPressItem = (item: hash) => {
|
||||
var run = () => {
|
||||
if(item.conflict_of) {
|
||||
item.conflict_of = null;
|
||||
if(item.content.conflict_of) {
|
||||
item.content.conflict_of = null;
|
||||
item.setDirty(true, true);
|
||||
Sync.get().sync();
|
||||
}
|
||||
|
||||
this.selectNote(item);
|
||||
|
||||
@@ -123,6 +123,7 @@ export default class Root extends Abstract {
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
ApplicationState.get().removeStateObserver(this.stateObserver);
|
||||
Sync.get().removeEventHandler(this.syncEventHandler);
|
||||
Sync.get().removeSyncStatusObserver(this.syncStatusObserver);
|
||||
clearInterval(this.syncTimer);
|
||||
}
|
||||
@@ -163,6 +164,9 @@ export default class Root extends Abstract {
|
||||
}
|
||||
|
||||
initializeData() {
|
||||
// Ensure no sync executes until initial data load
|
||||
Sync.get().lockSyncing();
|
||||
|
||||
let encryptionEnabled = KeysManager.get().isOfflineEncryptionEnabled();
|
||||
this.setSubTitle(encryptionEnabled ? "Decrypting items..." : "Loading items...");
|
||||
let incrementalCallback = (current, total) => {
|
||||
@@ -176,10 +180,12 @@ export default class Root extends Abstract {
|
||||
}
|
||||
|
||||
let loadLocalCompletion = (items) => {
|
||||
Sync.get().unlockSyncing();
|
||||
this.setSubTitle("Syncing...");
|
||||
this.dataLoaded = true;
|
||||
|
||||
// perform initial sync
|
||||
Sync.get().sync().then(() => {
|
||||
Sync.get().sync({performIntegrityCheck: true}).then(() => {
|
||||
this.setSubTitle(null);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import ActionSheet from 'react-native-actionsheet'
|
||||
import Abstract from "@Screens/Abstract"
|
||||
import AlertManager from "@SFJS/alertManager"
|
||||
import Auth from "@SFJS/authManager"
|
||||
import Sync from '@SFJS/syncManager'
|
||||
|
||||
import SectionHeader from "@Components/SectionHeader";
|
||||
import TableSection from "@Components/TableSection";
|
||||
@@ -34,20 +35,41 @@ export default class MainSideMenu extends AbstractSideMenu {
|
||||
|
||||
this.signoutObserver = Auth.get().addEventHandler((event) => {
|
||||
if(event == SFAuthManager.DidSignOutEvent) {
|
||||
this.setState({outOfSync: false});
|
||||
this.forceUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
this.syncEventHandler = Sync.get().addEventHandler((event, data) => {
|
||||
if(event == "enter-out-of-sync") {
|
||||
this.setState({outOfSync: true});
|
||||
} else if(event == "exit-out-of-sync") {
|
||||
this.setState({outOfSync: false});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
Auth.get().removeEventHandler(this.signoutObserver);
|
||||
Sync.get().removeEventHandler(this.syncEventHandler);
|
||||
}
|
||||
|
||||
presentSettings() {
|
||||
this.props.navigation.navigate("Settings");
|
||||
}
|
||||
|
||||
outOfSyncPressed() {
|
||||
AlertManager.get().confirm({
|
||||
title: "Potentially Out of Sync",
|
||||
text: "We've detected that the data in the current application session may not match the data on the server. This can happen due to poor network conditions, or if a large note fails to download on your device. To resolve this issue, we recommend first creating a backup of your data in the Settings screen, the signing out of your account and signing back in.",
|
||||
confirmButtonText: "Open Settings",
|
||||
onConfirm: () => {
|
||||
this.presentSettings();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
get handler() {
|
||||
return SideMenuManager.get().getHandlerForLeftSideMenu();
|
||||
}
|
||||
@@ -151,7 +173,11 @@ export default class MainSideMenu extends AbstractSideMenu {
|
||||
<SafeAreaView style={this.styles.firstSafeArea} />
|
||||
<SafeAreaView style={[viewStyles, this.styles.secondSafeArea]}>
|
||||
|
||||
<SideMenuHero onPress={() => {this.presentSettings()}}/>
|
||||
<SideMenuHero
|
||||
outOfSync={this.state.outOfSync}
|
||||
onPress={() => {this.presentSettings()}}
|
||||
onOutOfSyncPress={() => {this.outOfSyncPressed()}}
|
||||
/>
|
||||
|
||||
<ScrollView style={this.styles.scrollView} removeClippedSubviews={false}>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import ModelManager from "@SFJS/modelManager"
|
||||
|
||||
import StyleKit from "@Style/StyleKit"
|
||||
import ThemedComponent from "@Components/ThemedComponent";
|
||||
import Circle from "@Components/Circle"
|
||||
|
||||
|
||||
export default class SideMenuHero extends ThemedComponent {
|
||||
@@ -43,6 +44,15 @@ export default class SideMenuHero extends ThemedComponent {
|
||||
<TouchableOpacity onPress={this.props.onPress}>
|
||||
<Text style={this.styles.subtitle}>{textData.text}</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{this.props.outOfSync &&
|
||||
<TouchableOpacity style={this.styles.outOfSyncContainer} onPress={this.props.onOutOfSyncPress}>
|
||||
<View style={this.styles.iconCircle}>
|
||||
<Circle size={10} backgroundColor={StyleKit.variables.stylekitWarningColor} borderColor={StyleKit.variables.stylekitWarningColor} />
|
||||
</View>
|
||||
<Text style={this.styles.outOfSync}>Potentially Out of Sync</Text>
|
||||
</TouchableOpacity>
|
||||
}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -70,6 +80,24 @@ export default class SideMenuHero extends ThemedComponent {
|
||||
fontSize: 13,
|
||||
color: StyleKit.variables.stylekitContrastForegroundColor,
|
||||
opacity: 0.6
|
||||
},
|
||||
|
||||
outOfSyncContainer: {
|
||||
flex: 0,
|
||||
flexDirection: 'row',
|
||||
alignItems: "center"
|
||||
},
|
||||
|
||||
iconCircle: {
|
||||
marginTop: 10,
|
||||
width: 15,
|
||||
},
|
||||
|
||||
outOfSync: {
|
||||
marginTop: 10,
|
||||
fontSize: 13,
|
||||
color: StyleKit.variables.stylekitWarningColor,
|
||||
fontWeight: "bold"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user