From 38517127c36bf516aa850a50495f1392ec8752a5 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 24 Sep 2018 18:22:00 -0500 Subject: [PATCH] feat(dropbox): Implement react-native module. --- android/README.md | 26 +++ android/app/build.gradle | 34 ++++ android/sdk/build.gradle | 1 + .../meet/sdk/ReactInstanceManagerHolder.java | 1 + .../org/jitsi/meet/sdk/dropbox/Dropbox.java | 181 ++++++++++++++++++ android/sdk/src/main/res/values/strings.xml | 1 + ios/Podfile | 2 + ios/Podfile.lock | 6 +- ios/README.md | 34 ++++ ios/app/src/AppDelegate.m | 8 + ios/sdk/sdk.xcodeproj/project.pbxproj | 20 +- ios/sdk/src/Info.plist | 15 +- ios/sdk/src/JitsiMeetView.h | 4 + ios/sdk/src/JitsiMeetView.m | 10 + ios/sdk/src/dropbox/Dropbox.h | 27 +++ ios/sdk/src/dropbox/Dropbox.m | 163 ++++++++++++++++ 16 files changed, 524 insertions(+), 9 deletions(-) create mode 100644 android/sdk/src/main/java/org/jitsi/meet/sdk/dropbox/Dropbox.java create mode 100644 ios/sdk/src/dropbox/Dropbox.h create mode 100644 ios/sdk/src/dropbox/Dropbox.m diff --git a/android/README.md b/android/README.md index 8b9ed7f4b..e4f5af993 100644 --- a/android/README.md +++ b/android/README.md @@ -491,3 +491,29 @@ Picture-in-Picture style scenario, in a rectangle too small to accommodate its Jitsi Meet SDK automatically enables (unless explicitly disabled by a `setPictureInPictureEnabled(false)` call) Android's native Picture-in-Picture mode iff the platform is supported i.e. Android >= Oreo. + +## Dropbox integration + +To setup the Dropbox integration, follow these steps: + +1. Add the following to the app's AndroidManifest.xml and change `` to +your Dropbox app key: +``` + + + + + + + + +``` + +2. Add the following to the app's strings.xml and change `` to your +Dropbox app key: +``` + +``` diff --git a/android/app/build.gradle b/android/app/build.gradle index 61beb27ad..a70b657d6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,5 +1,7 @@ apply plugin: 'com.android.application' +def dropboxAppID = "" + android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -28,10 +30,12 @@ android { buildTypes { debug { + resValue("string", "dropbox_app_key", "${dropboxAppID}") minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro' } release { + resValue("string", "dropbox_app_key", "${dropboxAppID}") minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-release.pro' } @@ -41,6 +45,36 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + + if (dropboxAppID) { + def dropboxActivity = """ + + + + + + + """; + + + applicationVariants.all { variant -> + variant.outputs.each { output -> + output.processManifest.doLast { + File manifestOutFile = new File(output.processManifest.manifestOutputDirectory, "AndroidManifest.xml") + if (!manifestOutFile.isFile()) { + manifestOutFile = new File(new File(output.processManifest.manifestOutputDirectory, output.dirName),"AndroidManifest.xml") + } + if (manifestOutFile.exists()) { + def newFileContents = manifestOutFile.getText('UTF-8').replace("", "${dropboxActivity}") + manifestOutFile.write(newFileContents, 'UTF-8') + } + } + } + } + } } dependencies { diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle index dadd27caa..9ed7e8487 100644 --- a/android/sdk/build.gradle +++ b/android/sdk/build.gradle @@ -22,6 +22,7 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:27.0.2' + compile 'com.dropbox.core:dropbox-core-sdk:3.0.8' compile 'com.facebook.react:react-native:+' compile project(':react-native-background-timer') diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java index 42962e40d..c64c4542a 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java @@ -45,6 +45,7 @@ class ReactInstanceManagerHolder { new PictureInPictureModule(reactContext), new ProximityModule(reactContext), new WiFiStatsModule(reactContext), + new org.jitsi.meet.sdk.dropbox.Dropbox(reactContext), new org.jitsi.meet.sdk.invite.InviteModule(reactContext), new org.jitsi.meet.sdk.net.NAT64AddrInfoModule(reactContext) ); diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/dropbox/Dropbox.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/dropbox/Dropbox.java new file mode 100644 index 000000000..10c25db8e --- /dev/null +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/dropbox/Dropbox.java @@ -0,0 +1,181 @@ +package org.jitsi.meet.sdk.dropbox; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.text.TextUtils; +import android.util.Log; + +import com.dropbox.core.DbxException; +import com.dropbox.core.DbxRequestConfig; +import com.dropbox.core.v2.DbxClientV2; +import com.dropbox.core.v2.users.FullAccount; +import com.dropbox.core.v2.users.SpaceAllocation; +import com.dropbox.core.v2.users.SpaceUsage; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.dropbox.core.android.Auth; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableMap; +import org.jitsi.meet.sdk.R; + +import java.util.HashMap; +import java.util.Map; + +/** + * Implements the react-native module for the dropbox integration. + */ +public class Dropbox extends ReactContextBaseJavaModule implements LifecycleEventListener { + + private Promise promise = null; + private String clientId; + private String appID; + private boolean isEnabled = false; + + public Dropbox(ReactApplicationContext reactContext) { + super(reactContext); + reactContext.addLifecycleEventListener(this); + clientId = generateClientId(); + appID = reactContext.getString(R.string.dropbox_app_key); + if (!TextUtils.isEmpty(appID)) { + isEnabled = true; + } + } + + @Override + public String getName() { + return "Dropbox"; + } + + /** + * Executes the dropbox auth flow. + * + * @param promise The promise used to return the result of the auth flow. + */ + @ReactMethod + public void authorize(final Promise promise) { + if (!isEnabled) { + promise.reject(new Exception("Dropbox integration isn't configured.")); + return; + } + Auth.startOAuth2Authentication(this.getCurrentActivity(), appID); + this.promise = promise; + } + + @Override + public Map getConstants() { + final Map constants = new HashMap<>(); + constants.put("ENABLED", isEnabled); + return constants; + } + + + /** + * Resolves the current user dropbox display name. + * + * @param token A dropbox access token. + * @param promise The promise used to return the result of the auth flow. + */ + @ReactMethod + public void getDisplayName(final String token, final Promise promise) { + DbxRequestConfig config + = DbxRequestConfig.newBuilder(clientId).build(); + DbxClientV2 client = new DbxClientV2(config, token); + // Get current account info + try { + FullAccount account = client.users().getCurrentAccount(); + promise.resolve(account.getName().getDisplayName()); + } catch (DbxException e) { + promise.reject(e); + } + } + + /** + * Resolves the current user space usage. + * + * @param token A dropbox access token. + * @param promise The promise used to return the result of the auth flow. + */ + @ReactMethod + public void getSpaceUsage(final String token, final Promise promise) { + DbxRequestConfig config + = DbxRequestConfig.newBuilder(clientId).build(); + DbxClientV2 client = new DbxClientV2(config, token); + try { + SpaceUsage spaceUsage = client.users().getSpaceUsage(); + WritableMap map = Arguments.createMap(); + map.putString("used", String.valueOf(spaceUsage.getUsed())); + SpaceAllocation allocation = spaceUsage.getAllocation(); + long allocated = 0; + if(allocation.isIndividual()) { + allocated += allocation.getIndividualValue().getAllocated(); + } + + if(allocation.isTeam()) { + allocated += allocation.getTeamValue().getAllocated(); + } + map.putString("allocated", String.valueOf(allocated)); + promise.resolve(map); + } catch (DbxException e) { + promise.reject(e); + } + } + + /** + * Generate a client identifier for the dropbox sdk. + * + * @returns a client identifier for the dropbox sdk. + * @see {https://dropbox.github.io/dropbox-sdk-java/api-docs/v3.0.x/com/dropbox/core/DbxRequestConfig.html#getClientIdentifier--} + */ + private String generateClientId() { + Context context = getReactApplicationContext(); + PackageManager packageManager = context.getPackageManager(); + ApplicationInfo applicationInfo = null; + PackageInfo packageInfo = null; + + try { + String packageName = context.getPackageName(); + + applicationInfo + = packageManager.getApplicationInfo(packageName, 0); + packageInfo = packageManager.getPackageInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + } + + String applicationLabel + = applicationInfo == null + ? "JitsiMeet" + : packageManager.getApplicationLabel(applicationInfo) + .toString().replaceAll("\\s", ""); + String version = packageInfo == null ? "dev" : packageInfo.versionName; + + return applicationLabel + "/" + version; + } + + @Override + public void onHostResume() { + final String token = Auth.getOAuth2Token(); + if (token == null) + return; + + if (this.promise != null) { + this.promise.resolve(token); + this.promise = null; + } + } + + @Override + public void onHostPause() { + + } + + @Override + public void onHostDestroy() { + + } +} diff --git a/android/sdk/src/main/res/values/strings.xml b/android/sdk/src/main/res/values/strings.xml index 6aed30d15..c9d1ebcb9 100644 --- a/android/sdk/src/main/res/values/strings.xml +++ b/android/sdk/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ Jitsi Meet SDK + diff --git a/ios/Podfile b/ios/Podfile index bee5566b8..ff4efcd3c 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -26,6 +26,8 @@ target 'JitsiMeet' do pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' + pod 'ObjectiveDropboxOfficial' + pod 'react-native-background-timer', :path => '../node_modules/react-native-background-timer' pod 'react-native-fast-image', diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ae30eb1bb..e9d1dd964 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -27,6 +27,7 @@ PODS: - GTMSessionFetcher/Core (1.2.0) - GTMSessionFetcher/Full (1.2.0): - GTMSessionFetcher/Core (= 1.2.0) + - ObjectiveDropboxOfficial (3.9.1) - React (0.55.4): - React/Core (= 0.55.4) - react-native-background-timer (2.0.0): @@ -103,6 +104,7 @@ DEPENDENCIES: - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - ObjectiveDropboxOfficial - react-native-background-timer (from `../node_modules/react-native-background-timer`) - react-native-calendar-events (from `../node_modules/react-native-calendar-events`) - react-native-fast-image (from `../node_modules/react-native-fast-image`) @@ -132,6 +134,7 @@ SPEC REPOS: - GoogleToolboxForMac - GTMOAuth2 - GTMSessionFetcher + - ObjectiveDropboxOfficial - SDWebImage EXTERNAL SOURCES: @@ -174,6 +177,7 @@ SPEC CHECKSUMS: GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f GTMOAuth2: c77fe325e4acd453837e72d91e3b5f13116857b2 GTMSessionFetcher: 0c4baf0a73acd0041bf9f71ea018deedab5ea84e + ObjectiveDropboxOfficial: 274ce69d66286c94416daf1da5237c55e105e8c0 React: aa2040dbb6f317b95314968021bd2888816e03d5 react-native-background-timer: 63dcbf37dbcf294b5c6c071afcdc661fa06a7594 react-native-calendar-events: fe6fbc8ed337a7423c98f2c9012b25f20444de09 @@ -187,6 +191,6 @@ SPEC CHECKSUMS: SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681 yoga: a23273df0088bf7f2bb7e5d7b00044ea57a2a54a -PODFILE CHECKSUM: da74c08f6eb674668c49d8d799f8d9e2476a9fc5 +PODFILE CHECKSUM: cf8276ba4b0933b24c6082a25a5f4eabe0ba4ea6 COCOAPODS: 1.5.3 diff --git a/ios/README.md b/ios/README.md index 5bea410a6..3d7e295b8 100644 --- a/ios/README.md +++ b/ios/README.md @@ -212,3 +212,37 @@ resize `JitsiMeetView`. If `pictureInPictureEnabled` is set to `YES` or `delegate` implements `enterPictureInPicture:`, the in-call toolbar will render a button to afford the user to request entering Picture-in-Picture. + +## Dropbox integration + +To setup the dropbox integration you need to do the following steps: + +1. Add the following lines in your Info.plist file and replace `` with your dropbox app key: +``` +CFBundleURLTypes + + + CFBundleURLSchemes + + db- + + CFBundleURLName + + + +LSApplicationQueriesSchemes + + dbapi-8-emm + dbapi-2 + +``` + +2. Add the following method to `AppDelegate`: +```objc +- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url + options:(NSDictionary *)options { + return [JitsiMeetView application:app + openURL:url + options:options]; +} +``` diff --git a/ios/app/src/AppDelegate.m b/ios/app/src/AppDelegate.m index 3073dc84a..82a010159 100644 --- a/ios/app/src/AppDelegate.m +++ b/ios/app/src/AppDelegate.m @@ -46,4 +46,12 @@ annotation:annotation]; } + +- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url + options:(NSDictionary *)options { + return [JitsiMeetView application:app + openURL:url + options: options]; +} + @end diff --git a/ios/sdk/sdk.xcodeproj/project.pbxproj b/ios/sdk/sdk.xcodeproj/project.pbxproj index 0b3d5869b..8cb31a0de 100644 --- a/ios/sdk/sdk.xcodeproj/project.pbxproj +++ b/ios/sdk/sdk.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 75635B0A20751D6D00F29C9F /* joined.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0820751D6D00F29C9F /* joined.wav */; }; 75635B0B20751D6D00F29C9F /* left.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0920751D6D00F29C9F /* left.wav */; }; A4414AE020B37F1A003546E6 /* rejected.wav in Resources */ = {isa = PBXBuildFile; fileRef = A4414ADF20B37F1A003546E6 /* rejected.wav */; }; + A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; }; B386B85720981A75000DEF7A /* InviteController.m in Sources */ = {isa = PBXBuildFile; fileRef = B386B85020981A74000DEF7A /* InviteController.m */; }; B386B85820981A75000DEF7A /* AddPeopleController.m in Sources */ = {isa = PBXBuildFile; fileRef = B386B85120981A74000DEF7A /* AddPeopleController.m */; }; B386B85920981A75000DEF7A /* AddPeopleControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = B386B85220981A74000DEF7A /* AddPeopleControllerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -87,6 +88,8 @@ 98E09B5C73D9036B4ED252FC /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = ""; }; 9C77CA3CC919B081F1A52982 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = ""; }; A4414ADF20B37F1A003546E6 /* rejected.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = rejected.wav; path = ../../sounds/rejected.wav; sourceTree = ""; }; + A4A934E8212F3ADB001E9388 /* Dropbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Dropbox.m; sourceTree = ""; }; + A4A934EB21349A06001E9388 /* Dropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dropbox.h; sourceTree = ""; }; B386B85020981A74000DEF7A /* InviteController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InviteController.m; sourceTree = ""; }; B386B85120981A74000DEF7A /* AddPeopleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddPeopleController.m; sourceTree = ""; }; B386B85220981A74000DEF7A /* AddPeopleControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddPeopleControllerDelegate.h; sourceTree = ""; }; @@ -122,9 +125,6 @@ 0BCA49681EC4BBE500B793EE /* Resources */ = { isa = PBXGroup; children = ( - 6C31EDC720C06D490089C899 /* recordingOn.mp3 */, - 6C31EDC920C06D530089C899 /* recordingOff.mp3 */, - A4414ADF20B37F1A003546E6 /* rejected.wav */, 0BC4B8681F8C01E100CE8B21 /* CallKitIcon.png */, C6245F5B2053091D0040BE68 /* image-resize@2x.png */, C6245F5C2053091D0040BE68 /* image-resize@3x.png */, @@ -133,6 +133,9 @@ 75635B0920751D6D00F29C9F /* left.wav */, 0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */, 0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */, + 6C31EDC920C06D530089C899 /* recordingOff.mp3 */, + 6C31EDC720C06D490089C899 /* recordingOn.mp3 */, + A4414ADF20B37F1A003546E6 /* rejected.wav */, ); name = Resources; sourceTree = ""; @@ -162,6 +165,7 @@ 0BB9AD7C1F60356D001C08DB /* AppInfo.m */, 0BCA495C1EC4B6C600B793EE /* AudioMode.m */, C69EFA02209A0EFD0027712B /* callkit */, + A4A934E7212F3AB8001E9388 /* dropbox */, 0BA13D301EE83FF8007BEF7F /* ExternalAPI.m */, 0BD906E91EC0C00300C8C18E /* Info.plist */, B386B84F20981A11000DEF7A /* invite */, @@ -193,6 +197,15 @@ name = Frameworks; sourceTree = ""; }; + A4A934E7212F3AB8001E9388 /* dropbox */ = { + isa = PBXGroup; + children = ( + A4A934EB21349A06001E9388 /* Dropbox.h */, + A4A934E8212F3ADB001E9388 /* Dropbox.m */, + ); + path = dropbox; + sourceTree = ""; + }; B386B84F20981A11000DEF7A /* invite */ = { isa = PBXGroup; children = ( @@ -433,6 +446,7 @@ 0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */, C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */, C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */, + A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */, C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */, C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */, 0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */, diff --git a/ios/sdk/src/Info.plist b/ios/sdk/src/Info.plist index 94ad49f67..eae764135 100644 --- a/ios/sdk/src/Info.plist +++ b/ios/sdk/src/Info.plist @@ -18,12 +18,17 @@ 1.9.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) + JitsiMeetFonts + + FontAwesome.ttf + jitsi.ttf + + LSApplicationQueriesSchemes + + dbapi-2 + dbapi-8-emm + NSPrincipalClass - JitsiMeetFonts - - FontAwesome.ttf - jitsi.ttf - diff --git a/ios/sdk/src/JitsiMeetView.h b/ios/sdk/src/JitsiMeetView.h index 67d188c67..37a351271 100644 --- a/ios/sdk/src/JitsiMeetView.h +++ b/ios/sdk/src/JitsiMeetView.h @@ -39,6 +39,10 @@ continueUserActivity:(NSUserActivity * _Nonnull)userActivity restorationHandler:(void (^ _Nullable)(NSArray * _Nullable))restorationHandler; ++ (BOOL)application:(UIApplication *)app + openURL:(NSURL *)url + options:(NSDictionary *)options; + + (BOOL)application:(UIApplication * _Nonnull)application openURL:(NSURL * _Nonnull)URL sourceApplication:(NSString * _Nullable)sourceApplication diff --git a/ios/sdk/src/JitsiMeetView.m b/ios/sdk/src/JitsiMeetView.m index ea75d4697..817dd4eb7 100644 --- a/ios/sdk/src/JitsiMeetView.m +++ b/ios/sdk/src/JitsiMeetView.m @@ -23,6 +23,7 @@ #import #import +#import "Dropbox.h" #import "Invite+Private.h" #import "InviteController+Private.h" #import "JitsiMeetView+Private.h" @@ -137,6 +138,8 @@ static NSMapTable *views; // Store launch options, will be used when we create the bridge. _launchOptions = [launchOptions copy]; + [Dropbox setAppKey]; + return YES; } @@ -211,6 +214,13 @@ static NSMapTable *views; annotation:annotation]; } ++ (BOOL)application:(UIApplication *)app openURL:(NSURL *)url + options:(NSDictionary *)options { + return [Dropbox application:app + openURL:url + options: options]; +} + #pragma mark Initializers - (instancetype)init { diff --git a/ios/sdk/src/dropbox/Dropbox.h b/ios/sdk/src/dropbox/Dropbox.h new file mode 100644 index 000000000..5a53b5ff2 --- /dev/null +++ b/ios/sdk/src/dropbox/Dropbox.h @@ -0,0 +1,27 @@ +/* + * Copyright @ 2018-present Atlassian Pty Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@interface Dropbox : NSObject + ++ (BOOL)application:(UIApplication *)app + openURL:(NSURL *)url + options:(NSDictionary *)options; + ++ (void)setAppKey; + +@end diff --git a/ios/sdk/src/dropbox/Dropbox.m b/ios/sdk/src/dropbox/Dropbox.m new file mode 100644 index 000000000..b173cb747 --- /dev/null +++ b/ios/sdk/src/dropbox/Dropbox.m @@ -0,0 +1,163 @@ +/* + * Copyright @ 2017-present Atlassian Pty Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import +#import "Dropbox.h" + +RCTPromiseResolveBlock currentResolve = nil; +RCTPromiseRejectBlock currentReject = nil; + +@implementation Dropbox + ++ (NSString *)getAppKey{ + NSArray *urlTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for(NSDictionary *urlType in urlTypes) { + NSArray *urlSchemes = urlType[@"CFBundleURLSchemes"]; + if(urlSchemes != nil) { + for(NSString *urlScheme in urlSchemes) { + if(urlScheme != nil) { + if ([urlScheme hasPrefix:@"db-"]) { + return [urlScheme substringFromIndex:3]; + } + } + } + } + + } + + return nil; +} + +RCT_EXPORT_MODULE(); + +- (NSDictionary *)constantsToExport { + BOOL enabled = [Dropbox getAppKey] != nil; + + return @{ + @"ENABLED": [NSNumber numberWithBool:enabled] + }; +}; + +RCT_EXPORT_METHOD(authorize: (RCTPromiseResolveBlock)resolve + reject:(__unused RCTPromiseRejectBlock)reject) { + currentResolve = resolve; + currentReject = reject; + + dispatch_async(dispatch_get_main_queue(), ^{ + [DBClientsManager authorizeFromController:[UIApplication sharedApplication] + controller:[[self class] topMostController] + openURL:^(NSURL *url) { + [[UIApplication sharedApplication] openURL:url]; + }]; + }); +} + +RCT_EXPORT_METHOD(getDisplayName: (NSString *)token + resolve: (RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { + DBUserClient *client = [[DBUserClient alloc] initWithAccessToken:token]; + [[client.usersRoutes getCurrentAccount] setResponseBlock:^(DBUSERSFullAccount *result, DBNilObject *routeError, DBRequestError *networkError) { + if (result) { + resolve(result.name.displayName); + } else { + NSString *msg = @"Failed!"; + if (networkError != nil) { + msg = [NSString stringWithFormat:@"Failed! Error: %@", networkError]; + } + reject(@"getDisplayName", @"Failed", nil); + } + }]; + +} + +RCT_EXPORT_METHOD(getSpaceUsage: (NSString *)token + resolve: (RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { + DBUserClient *client = [[DBUserClient alloc] initWithAccessToken:token]; + [[client.usersRoutes getSpaceUsage] setResponseBlock:^(DBUSERSSpaceUsage *result, DBNilObject *routeError, DBRequestError *networkError) { + if (result) { + DBUSERSSpaceAllocation *allocation = result.allocation; + NSNumber *allocated = 0; + NSNumber *used = 0; + if([allocation isIndividual]) { + allocated = allocation.individual.allocated; + used = result.used; + } else if ([allocation isTeam]) { + allocated = allocation.team.allocated; + used = allocation.team.used; + } + id objects[] = { used, allocated }; + id keys[] = { @"used", @"allocated" }; + NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects + forKeys:keys + count:2]; + resolve(dictionary); + } else { + NSString *msg = @"Failed!"; + if (networkError != nil) { + msg = [NSString stringWithFormat:@"Failed! Error: %@", networkError]; + } + reject(@"getSpaceUsage", msg, nil); + } + }]; + +} + ++ (BOOL)application:(UIApplication *)app openURL:(NSURL *)url + options:(NSDictionary *)options { + DBOAuthResult *authResult = [DBClientsManager handleRedirectURL:url]; + if (authResult != nil) { + if ([authResult isSuccess]) { + currentResolve(authResult.accessToken.accessToken); + currentResolve = nil; + currentReject = nil; + return YES; + } else { + NSString *msg; + if ([authResult isError]) { + msg = [NSString stringWithFormat:@"%@, error type: %ld",[authResult errorDescription], [authResult errorType]]; + } else { + msg = @"OAuth canceled!"; + } + currentReject(@"authorize", msg, nil); + currentResolve = nil; + currentReject = nil; + } + } + return NO; +} + ++ (UIViewController*)topMostController +{ + UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; + + while (topController.presentedViewController) { + topController = topController.presentedViewController; + } + + return topController; +} + ++ (void)setAppKey { + NSString *appKey = [self getAppKey]; + if (appKey != nil) { + [DBClientsManager setupWithAppKey:appKey]; + } +} + + +@end