From 272d6d7f431cd2fab9c074019a17227a19e1ff38 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Fri, 4 Jan 2019 21:39:55 -0600 Subject: [PATCH] Functioning backup export for iOS and Android --- android/app/build.gradle | 2 + .../assets/fonts/MaterialCommunityIcons.ttf | Bin 292556 -> 322456 bytes .../app/src/main/assets/fonts/Octicons.ttf | Bin 27512 -> 27520 bytes .../com/standardnotes/MainApplication.java | 4 + android/settings.gradle | 4 + ios/StandardNotes.xcodeproj/project.pbxproj | 104 ++++++++++++++- ios/StandardNotes/Info.plist | 2 +- package-lock.json | 19 +++ package.json | 2 + src/containers/account/OptionsSection.js | 2 +- src/lib/BackupsManager.js | 123 ++++++++++++++++++ src/lib/sfjs/alertManager.js | 5 +- src/screens/Settings.js | 49 +------ 13 files changed, 266 insertions(+), 50 deletions(-) create mode 100644 src/lib/BackupsManager.js diff --git a/android/app/build.gradle b/android/app/build.gradle index 49091072..0b059e29 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -159,6 +159,8 @@ android { } dependencies { + compile project(':react-native-file-viewer') + compile project(':react-native-fs') compile project(':react-native-gesture-handler') implementation fileTree(dir: "libs", include: ["*.jar"]) diff --git a/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf b/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf index 69404e3d9758bf3d6a7e4ce27e5362089366542f..82524a0c1223bfc2bf060a9b16390c3cc21577c1 100644 GIT binary patch delta 42753 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 C4>a=t delta 14905 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 W$n{;z4?=3$(9xe;uD6V@@cs|bD}N{e diff --git a/android/app/src/main/assets/fonts/Octicons.ttf b/android/app/src/main/assets/fonts/Octicons.ttf index 09e2b2d79c370d9370a772b3542acdfca66ed634..09f5a96c05af2c82a0002f0d8b0fca6ba3f08fc7 100644 GIT binary patch delta 5595 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 SQGfi?jCJ~6`b+cG=>Gt%=X(DD delta 5679 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 K&A&-sIrrZneyZC5 diff --git a/android/app/src/main/java/com/standardnotes/MainApplication.java b/android/app/src/main/java/com/standardnotes/MainApplication.java index 4d3959fd..85cff87a 100644 --- a/android/app/src/main/java/com/standardnotes/MainApplication.java +++ b/android/app/src/main/java/com/standardnotes/MainApplication.java @@ -9,6 +9,8 @@ import android.support.annotation.Nullable; import android.view.WindowManager; import com.facebook.react.ReactApplication; +import com.vinzscam.reactnativefileviewer.RNFileViewerPackage; +import com.rnfs.RNFSPackage; import com.swmansion.gesturehandler.react.RNGestureHandlerPackage; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; @@ -44,6 +46,8 @@ public class MainApplication extends Application implements ReactApplication { protected List getPackages() { return Arrays.asList( new MainReactPackage(), + new RNFileViewerPackage(), + new RNFSPackage(), new RNGestureHandlerPackage(), BugsnagReactNative.getPackage(), new KeychainPackage(), diff --git a/android/settings.gradle b/android/settings.gradle index 82525a90..7a2e98dd 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,8 @@ rootProject.name = 'StandardNotes' +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' +project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android') include ':app' include ':react-native-gesture-handler' diff --git a/ios/StandardNotes.xcodeproj/project.pbxproj b/ios/StandardNotes.xcodeproj/project.pbxproj index 0aef7106..65a06b36 100644 --- a/ios/StandardNotes.xcodeproj/project.pbxproj +++ b/ios/StandardNotes.xcodeproj/project.pbxproj @@ -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 */; }; @@ -13,6 +12,7 @@ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 00E356F31AD99517003FC87E /* StandardNotesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* StandardNotesTests.m */; }; + 0A7C7EB08AA3465C8E686821 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB6B877AE784055A8E294A8 /* libRNFS.a */; }; 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; @@ -41,6 +41,7 @@ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 965031D980094619B7DBA0FD /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1F569402A90047A59845394A /* Ionicons.ttf */; }; 9A2C235D0ABA4B0CB9A428CA /* libRNKeychain.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDCF33ADCFE845D588CC4E66 /* libRNKeychain.a */; }; + 9E1F5D0FE7C441D685DAEEAA /* libRNFileViewer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37A42F4068AE42DD8D2DF182 /* libRNFileViewer.a */; }; ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; }; C00E89E3E7F949A4AA0F613E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F30913DACE34E71895FBF91 /* libz.tbd */; }; CD17667C1F795DC100165C83 /* libSNTextView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD1766781F795AE500165C83 /* libSNTextView.a */; }; @@ -394,6 +395,27 @@ remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteInfo = RNGestureHandler; }; + CDEBDD9B21E044B500333D77 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2FAF1266E8404686B7F36870 /* RNFS.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F12AFB9B1ADAF8F800E0535D; + remoteInfo = RNFS; + }; + CDEBDD9D21E044B500333D77 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2FAF1266E8404686B7F36870 /* RNFS.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 6456441F1EB8DA9100672408; + remoteInfo = "RNFS-tvOS"; + }; + CDEBDDE221E044BD00333D77 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 645E3D9167344C3E81B7223C /* RNFileViewer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RNFileViewer; + }; CDFC05B41F79A868007EFC71 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = CD17664C1F795AE500165C83 /* SNTextView.xcodeproj */; @@ -435,12 +457,15 @@ 2416263A135F439AA3C5F9D2 /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = ""; }; 2D02E47B1E0B4A5D006451C7 /* StandardNotes-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "StandardNotes-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; + 37A42F4068AE42DD8D2DF182 /* libRNFileViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFileViewer.a; sourceTree = ""; }; 48127930FB1344778C168838 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; 5C13FDBBDDEE4F1285F88B41 /* RNStoreReview.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNStoreReview.xcodeproj; path = "../node_modules/react-native-store-review/ios/RNStoreReview.xcodeproj"; sourceTree = ""; }; 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; 6314B32C63AC4827A9329AA6 /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = ""; }; + 645E3D9167344C3E81B7223C /* RNFileViewer.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFileViewer.xcodeproj; path = "../node_modules/react-native-file-viewer/ios/RNFileViewer.xcodeproj"; sourceTree = ""; }; 6F30913DACE34E71895FBF91 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 737AF67874434967865855D8 /* BugsnagReactNative.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = BugsnagReactNative.xcodeproj; path = "../node_modules/bugsnag-react-native/cocoa/BugsnagReactNative.xcodeproj"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; @@ -454,6 +479,7 @@ CDB58A101F6C5178009EF868 /* RNMail.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNMail.xcodeproj; path = "../vendor/react-native-mail/RNMail.xcodeproj"; sourceTree = ""; }; CDC17F4A1F6E24720037D7F9 /* StandardNotes.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = StandardNotes.entitlements; path = StandardNotes/StandardNotes.entitlements; sourceTree = ""; }; CDCF33ADCFE845D588CC4E66 /* libRNKeychain.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNKeychain.a; sourceTree = ""; }; + CEB6B877AE784055A8E294A8 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = ""; }; 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 = ""; }; EFD3F9197A5F41C0904D7E60 /* libBugsnagReactNative.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBugsnagReactNative.a; sourceTree = ""; }; /* End PBXFileReference section */ @@ -494,6 +520,8 @@ C00E89E3E7F949A4AA0F613E /* libz.tbd in Frameworks */, 6C1915C4DE9040A9BB17CFBB /* libRNStoreReview.a in Frameworks */, 300BF5D7132F46BCAB353149 /* libRNGestureHandler.a in Frameworks */, + 0A7C7EB08AA3465C8E686821 /* libRNFS.a in Frameworks */, + 9E1F5D0FE7C441D685DAEEAA /* libRNFileViewer.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -699,6 +727,8 @@ 737AF67874434967865855D8 /* BugsnagReactNative.xcodeproj */, 5C13FDBBDDEE4F1285F88B41 /* RNStoreReview.xcodeproj */, 19A39FBB53A3465B81022E02 /* RNGestureHandler.xcodeproj */, + 2FAF1266E8404686B7F36870 /* RNFS.xcodeproj */, + 645E3D9167344C3E81B7223C /* RNFileViewer.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -821,6 +851,8 @@ EFD3F9197A5F41C0904D7E60 /* libBugsnagReactNative.a */, ADB6F6B9BC7144FCB2C08D40 /* libRNStoreReview.a */, 04047F33889C425483EB8244 /* libRNGestureHandler.a */, + CEB6B877AE784055A8E294A8 /* libRNFS.a */, + 37A42F4068AE42DD8D2DF182 /* libRNFileViewer.a */, ); name = "Recovered References"; sourceTree = ""; @@ -833,6 +865,23 @@ name = Products; sourceTree = ""; }; + CDEBDD9721E044B500333D77 /* Products */ = { + isa = PBXGroup; + children = ( + CDEBDD9C21E044B500333D77 /* libRNFS.a */, + CDEBDD9E21E044B500333D77 /* libRNFS.a */, + ); + name = Products; + sourceTree = ""; + }; + CDEBDDB721E044BD00333D77 /* Products */ = { + isa = PBXGroup; + children = ( + CDEBDDE321E044BD00333D77 /* libRNFileViewer.a */, + ); + name = Products; + sourceTree = ""; + }; D0C5C4528C8147238D73A75F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -1025,6 +1074,14 @@ ProductGroup = CDB58A0B1F6C5174009EF868 /* Products */; ProjectRef = CDB58A0A1F6C5174009EF868 /* ReactNativeFingerprintScanner.xcodeproj */; }, + { + ProductGroup = CDEBDDB721E044BD00333D77 /* Products */; + ProjectRef = 645E3D9167344C3E81B7223C /* RNFileViewer.xcodeproj */; + }, + { + ProductGroup = CDEBDD9721E044B500333D77 /* Products */; + ProjectRef = 2FAF1266E8404686B7F36870 /* RNFS.xcodeproj */; + }, { ProductGroup = CDE0D5F521D4012300E093B5 /* Products */; ProjectRef = 19A39FBB53A3465B81022E02 /* RNGestureHandler.xcodeproj */; @@ -1390,6 +1447,27 @@ remoteRef = CDE0D5F821D4012300E093B5 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + CDEBDD9C21E044B500333D77 /* libRNFS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNFS.a; + remoteRef = CDEBDD9B21E044B500333D77 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDEBDD9E21E044B500333D77 /* libRNFS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNFS.a; + remoteRef = CDEBDD9D21E044B500333D77 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDEBDDE321E044BD00333D77 /* libRNFileViewer.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNFileViewer.a; + remoteRef = CDEBDDE221E044BD00333D77 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -1542,6 +1620,8 @@ "$(SRCROOT)/../node_modules/bugsnag-react-native/cocoa/**", "$(SRCROOT)/../node_modules/react-native-store-review/ios", "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + "$(SRCROOT)/../node_modules/react-native-fs/**", + "$(SRCROOT)/../node_modules/react-native-file-viewer/ios", ); INFOPLIST_FILE = StandardNotesTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -1553,6 +1633,8 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1576,6 +1658,8 @@ "$(SRCROOT)/../node_modules/bugsnag-react-native/cocoa/**", "$(SRCROOT)/../node_modules/react-native-store-review/ios", "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + "$(SRCROOT)/../node_modules/react-native-fs/**", + "$(SRCROOT)/../node_modules/react-native-file-viewer/ios", ); INFOPLIST_FILE = StandardNotesTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -1587,6 +1671,8 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1614,6 +1700,8 @@ "$(SRCROOT)/../node_modules/react-native/Libraries/Text", "$(SRCROOT)/../node_modules/react-native-store-review/ios", "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + "$(SRCROOT)/../node_modules/react-native-fs/**", + "$(SRCROOT)/../node_modules/react-native-file-viewer/ios", ); INFOPLIST_FILE = StandardNotes/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -1647,6 +1735,8 @@ "$(SRCROOT)/../node_modules/react-native/Libraries/Text", "$(SRCROOT)/../node_modules/react-native-store-review/ios", "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + "$(SRCROOT)/../node_modules/react-native-fs/**", + "$(SRCROOT)/../node_modules/react-native-file-viewer/ios", ); INFOPLIST_FILE = StandardNotes/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -1683,6 +1773,8 @@ "$(SRCROOT)/../node_modules/bugsnag-react-native/cocoa/**", "$(SRCROOT)/../node_modules/react-native-store-review/ios", "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + "$(SRCROOT)/../node_modules/react-native-fs/**", + "$(SRCROOT)/../node_modules/react-native-file-viewer/ios", ); INFOPLIST_FILE = "StandardNotes-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1693,6 +1785,8 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1725,6 +1819,8 @@ "$(SRCROOT)/../node_modules/bugsnag-react-native/cocoa/**", "$(SRCROOT)/../node_modules/react-native-store-review/ios", "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + "$(SRCROOT)/../node_modules/react-native-fs/**", + "$(SRCROOT)/../node_modules/react-native-file-viewer/ios", ); INFOPLIST_FILE = "StandardNotes-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1735,6 +1831,8 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1768,6 +1866,8 @@ "\"$(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)"; @@ -1797,6 +1897,8 @@ "\"$(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)"; diff --git a/ios/StandardNotes/Info.plist b/ios/StandardNotes/Info.plist index b0c46ede..84866757 100644 --- a/ios/StandardNotes/Info.plist +++ b/ios/StandardNotes/Info.plist @@ -40,7 +40,7 @@ NSFaceIDUsageDescription Face ID is required to unlock your notes. NSLocationWhenInUseUsageDescription - + UIAppFonts Entypo.ttf diff --git a/package-lock.json b/package-lock.json index 0fb1fcdf..13fc4aa5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10442,6 +10442,20 @@ } } }, + "react-native-file-viewer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/react-native-file-viewer/-/react-native-file-viewer-1.0.10.tgz", + "integrity": "sha512-M+v/nUM1wiFSn0PkXT5dnrIxGi+UGHcNz8vydWSEbtDiyxXyUWbcpDJL+cKOarpW7lNzZlEPQHjzossyfjOEng==" + }, + "react-native-fs": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.13.3.tgz", + "integrity": "sha512-B62LSSAEYQGItg7KVTzTVVCxezOYFBYp4DMVFbdoZUd1mZVFdqR2sy1HY1mye1VI/Lf3IbxSyZEQ0GmrrdwLjg==", + "requires": { + "base-64": "0.1.0", + "utf8": "2.1.2" + } + }, "react-native-gesture-handler": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.0.12.tgz", @@ -12491,6 +12505,11 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "utf8": { + "version": "2.1.2", + "resolved": "http://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index df89d72a..3647ff34 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "moment": "^2.23.0", "react": "16.6.3", "react-native": "0.57.8", + "react-native-file-viewer": "^1.0.10", + "react-native-fs": "^2.13.3", "react-native-gesture-handler": "^1.0.12", "react-native-keychain": "^1.2.1", "react-native-store-review": "^0.1.3", diff --git a/src/containers/account/OptionsSection.js b/src/containers/account/OptionsSection.js index ba73cf50..a7c7d7a0 100644 --- a/src/containers/account/OptionsSection.js +++ b/src/containers/account/OptionsSection.js @@ -75,7 +75,7 @@ export default class OptionsSection extends Component { disabled={this.state.loadingExport} leftAligned={true} options={this.exportOptions()} - title={this.state.loadingExport ? "Preparing Data..." : "Export Data"} + title={this.state.loadingExport ? "Processing..." : "Export Data"} onPress={this.onExportPress} /> diff --git a/src/lib/BackupsManager.js b/src/lib/BackupsManager.js new file mode 100644 index 00000000..35fb0b4e --- /dev/null +++ b/src/lib/BackupsManager.js @@ -0,0 +1,123 @@ +import { Share } from 'react-native'; +import Storage from '@SFJS/storageManager' +import Auth from '@SFJS/authManager' +import KeysManager from '@Lib/keysManager' +import AlertManager from "@SFJS/alertManager"; +import UserPrefsManager from '@Lib/userPrefsManager' +import ModelManager from '@SFJS/modelManager' +import ApplicationState from "@Lib/ApplicationState" +import RNFS from 'react-native-fs'; +import FileViewer from 'react-native-file-viewer'; +const base64 = require('base-64'); + +export default class BackupsManager { + + static instance = null; + static get() { + if(this.instance == null) { + this.instance = new BackupsManager(); + } + return this.instance; + } + + /* + On iOS, we can use Share to share a file of arbitrary length. + This doesn't work on Android however. Seems to have a very low limit. + For Android, we'll use RNFS to save the file to disk, then FileViewer to + ask the user what application they would like to open the file with. + For .txt files, not many applications handle it. So, we'll want to notify the user + the path the file was saved to. + */ + + async export(encrypted) { + var auth_params = await Auth.get().getAuthParams(); + var keys = encrypted ? KeysManager.get().activeKeys() : null; + + var items = []; + + for(var item of ModelManager.get().allItems) { + var itemParams = new SFItemParams(item, keys, auth_params); + var params = await itemParams.paramsForExportFile(); + items.push(params); + } + + if(items.length == 0) { + Alert.alert('No Data', "You don't have any notes yet."); + return false; + } + + var data = {items: items} + + if(keys) { + var authParams = KeysManager.get().activeAuthParams(); + // auth params are only needed when encrypted with a standard file key + data["auth_params"] = authParams; + } + + var jsonString = JSON.stringify(data, null, 2 /* pretty print */); + let modifier = encrypted ? "Encrypted" : "Decrypted"; + let filename = `Standard Notes ${modifier} Backup - ${this._formattedDate()}.txt`; + + if(ApplicationState.isIOS) { + return this._exportIOS(filename, jsonString); + } else { + let filepath = await this._exportAndroid(filename, jsonString); + return this._showFileSavePromptAndroid(filepath); + } + } + + async _exportIOS(filename, data) { + return new Promise((resolve, reject) => { + ApplicationState.get().performActionWithoutStateChangeImpact(async () => { + Share.share({ + title: filename, + message: data, + }).then((result) => { + resolve(result != Share.dismissedAction); + }).catch((error) => { + resolve(false); + }) + }) + }) + } + + async _exportAndroid(filename, data) { + let filepath = `${RNFS.DocumentDirectoryPath}/${filename}`; + return RNFS.writeFile(filepath, data).then(() => { + return filepath; + }) + } + + async _openFileAndroid(filepath) { + return FileViewer.open(filepath).then(() => { + // success + return true; + }).catch(error => { + console.log("Error opening file", error); + return false; + }); + } + + async _showFileSavePromptAndroid(filepath) { + return AlertManager.get().confirm({ + title: "Backup Saved", + text: `Your backup file has been saved to your local disk at this location:\n\n${filepath}`, + cancelButtonText: "Done", + confirmButtonText: "Open File", + onConfirm: () => { + this._openFileAndroid(filepath); + } + }).then(() => { + return true; + }).catch(() => { + // Did Cancel, still success + return true; + }) + } + + /* Utils */ + + _formattedDate() { + return new Date().getTime(); + } +} diff --git a/src/lib/sfjs/alertManager.js b/src/lib/sfjs/alertManager.js index e63989f7..2146de4e 100644 --- a/src/lib/sfjs/alertManager.js +++ b/src/lib/sfjs/alertManager.js @@ -12,11 +12,11 @@ export default class AlertManager extends SFAlertManager { return this.instance; } - async confirm({title, text, confirmButtonText = "OK", onConfirm, onCancel} = {}) { + 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. let buttons = [ - {text: 'Cancel', onPress: () => { + {text: cancelButtonText, onPress: () => { reject(); onCancel && onCancel(); }}, @@ -28,5 +28,4 @@ export default class AlertManager extends SFAlertManager { Alert.alert(title, text, buttons, { cancelable: true }) }) } - } diff --git a/src/screens/Settings.js b/src/screens/Settings.js index 2257d2a0..3c8f1fb2 100644 --- a/src/screens/Settings.js +++ b/src/screens/Settings.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import {ScrollView, View, Alert, Keyboard, Linking, Platform, Share, NativeModules} from 'react-native'; import Sync from '../lib/sfjs/syncManager' -import ModelManager from '../lib/sfjs/modelManager' +import ModelManager from '@SFJS/modelManager' import AlertManager from '../lib/sfjs/alertManager' import SF from '@SFJS/sfjs' @@ -10,6 +10,9 @@ import Auth from '../lib/sfjs/authManager' import KeysManager from '@Lib/keysManager' import UserPrefsManager from '../lib/userPrefsManager' import OptionsState from "@Lib/OptionsState" +import ApplicationState from "@Lib/ApplicationState" +import StyleKit from "@Style/StyleKit" +import BackupsManager from "@Lib/BackupsManager" import SectionHeader from "../components/SectionHeader"; import ButtonCell from "../components/ButtonCell"; @@ -25,10 +28,6 @@ import PasscodeSection from "../containers/account/PasscodeSection" import EncryptionSection from "../containers/account/EncryptionSection" import CompanySection from "../containers/account/CompanySection" import LockedView from "../containers/LockedView"; -import ApplicationState from "@Lib/ApplicationState" -import StyleKit from "../style/StyleKit" - -var base64 = require('base-64'); export default class Settings extends Abstract { @@ -269,51 +268,13 @@ export default class Settings extends Abstract { onExportPress = async (encrypted, callback) => { this.handlePrivilegedAction(true, SFPrivilegesManager.ActionManageBackups, async () => { - let customCallback = (success) => { + BackupsManager.get().export(encrypted, callback).then((success) => { if(success) { var date = new Date(); this.setState({lastExportDate: date}); UserPrefsManager.get().setLastExportDate(date); } callback(); - } - var auth_params = await Auth.get().getAuthParams(); - var keys = encrypted ? KeysManager.get().activeKeys() : null; - - var items = []; - - for(var item of ModelManager.get().allItems) { - var itemParams = new SFItemParams(item, keys, auth_params); - var params = await itemParams.paramsForExportFile(); - items.push(params); - } - - if(items.length == 0) { - Alert.alert('No Data', "You don't have any notes yet."); - customCallback(); - return; - } - - var data = {items: items} - - if(keys) { - var authParams = KeysManager.get().activeAuthParams(); - // auth params are only needed when encrypted with a standard file key - data["auth_params"] = authParams; - } - - var jsonString = JSON.stringify(data, null, 2 /* pretty print */); - - var calledCallback = false; - - ApplicationState.get().performActionWithoutStateChangeImpact(() => { - Share.share({ - title: encrypted ? "SN-Encrypted-Backup" : 'SN-Decrypted-Backup', - message: jsonString, - }).then((event) => { - console.log("Result", event); - customCallback(event != Share.dismissedAction); - }) }) }); }