diff --git a/android/app/build.gradle b/android/app/build.gradle index 31d08c4ef5ca8..4340d05cf596a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -243,5 +243,10 @@ task copyDownloadableDepsToLibs(type: Copy) { } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) -apply plugin: 'com.google.gms.google-services' +def googleServicesFile = rootProject.file('app/google-services.json') +if (googleServicesFile.exists()) { + apply plugin: 'com.google.gms.google-services' // Google Play services Gradle plugin +} apply plugin: 'com.google.firebase.crashlytics' + + diff --git a/android/app/src/main/assets/airshipconfig.properties b/android/app/src/main/assets/airshipconfig.properties new file mode 100644 index 0000000000000..6e37dfb7465e9 --- /dev/null +++ b/android/app/src/main/assets/airshipconfig.properties @@ -0,0 +1,9 @@ +developmentAppKey = uulSSfTDQJ2r0PMpjRrhmQ +developmentAppSecret = D4Bhf0HrQEehrPua74Tyiw + +productionAppKey = 55vypj0ARc6cN09MX7ogtQ +productionAppSecret = EsSaqbdLSvmyC6kSBFJCtQ + +# Notification Customization +notificationIcon = ic_notification +notificationAccentColor = #2EAAE2 diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification.png b/android/app/src/main/res/drawable-hdpi/ic_notification.png new file mode 100644 index 0000000000000..e084753fb90ed Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_notification.png b/android/app/src/main/res/drawable-mdpi/ic_notification.png new file mode 100644 index 0000000000000..669579148c619 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notification.png b/android/app/src/main/res/drawable-xhdpi/ic_notification.png new file mode 100644 index 0000000000000..18c06a8d16c3b Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxhdpi/ic_notification.png new file mode 100644 index 0000000000000..da94014c33f09 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png new file mode 100644 index 0000000000000..96f1cb18a2be8 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png differ diff --git a/ios/AirshipConfig.plist b/ios/AirshipConfig.plist new file mode 100644 index 0000000000000..3502dc33584f5 --- /dev/null +++ b/ios/AirshipConfig.plist @@ -0,0 +1,16 @@ + + + + + detectProvisioningMode + + developmentAppKey + uulSSfTDQJ2r0PMpjRrhmQ + developmentAppSecret + D4Bhf0HrQEehrPua74Tyiw + productionAppKey + 55vypj0ARc6cN09MX7ogtQ + productionAppSecret + EsSaqbdLSvmyC6kSBFJCtQ + + diff --git a/ios/Podfile b/ios/Podfile index 0bc36d16e8c67..175f3f2cbc656 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,7 +1,7 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, '10.0' +platform :ios, '11.0' target 'ReactNativeChat' do config = use_native_modules! diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 01144dc11cf22..6a5fc0c690fc1 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,4 +1,16 @@ PODS: + - Airship (13.5.4): + - Airship/Automation (= 13.5.4) + - Airship/Core (= 13.5.4) + - Airship/ExtendedActions (= 13.5.4) + - Airship/MessageCenter (= 13.5.4) + - Airship/Automation (13.5.4): + - Airship/Core + - Airship/Core (13.5.4) + - Airship/ExtendedActions (13.5.4): + - Airship/Core + - Airship/MessageCenter (13.5.4): + - Airship/Core - boost-for-react-native (1.63.0) - CocoaAsyncSocket (7.6.4) - CocoaLibEvent (1.0.0) @@ -141,7 +153,7 @@ PODS: - OpenSSL-Universal (1.0.2.19): - OpenSSL-Universal/Static (= 1.0.2.19) - OpenSSL-Universal/Static (1.0.2.19) - - PromisesObjC (1.2.11) + - PromisesObjC (1.2.10) - RCTRequired (0.63.3) - RCTTypeSafety (0.63.3): - FBLazyVector (= 0.63.3) @@ -395,6 +407,9 @@ PODS: - Firebase/Crashlytics (~> 6.30.0) - React-Core - RNFBApp + - urbanairship-react-native (8.1.0): + - Airship (= 13.5.4) + - React - Yoga (1.14.0) - YogaKit (1.18.1): - Yoga (~> 1.14) @@ -456,10 +471,12 @@ DEPENDENCIES: - "RNFBAnalytics (from `../node_modules/@react-native-firebase/analytics`)" - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" - "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)" + - urbanairship-react-native (from `../node_modules/urbanairship-react-native`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: + - Airship - boost-for-react-native - CocoaAsyncSocket - CocoaLibEvent @@ -555,10 +572,13 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-firebase/app" RNFBCrashlytics: :path: "../node_modules/@react-native-firebase/crashlytics" + urbanairship-react-native: + :path: "../node_modules/urbanairship-react-native" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: + Airship: cbbd372a4ffc8dcfeacec01fd623155ec41f33ed boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f @@ -585,7 +605,7 @@ SPEC CHECKSUMS: GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 nanopb: c43f40fadfe79e8b8db116583945847910cbabc9 OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 - PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f + PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151 RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047 RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab React: f36e90f3ceb976546e97df3403e37d226f79d0e3 @@ -616,9 +636,10 @@ SPEC CHECKSUMS: RNFBAnalytics: 6fe130045b06fb4173d6f44058894007bb30b9a2 RNFBApp: 570b136767f588b7eef0ab918284e9fe364d0c3e RNFBCrashlytics: 7b60463c742f830255fa76f13a837f95c6581700 + urbanairship-react-native: fa123940041a6a13ab7dac192e32833c53754f00 Yoga: 7d13633d129fd179e01b8953d38d47be90db185a YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 7f6bb9c130ea13236f8249f800f75d671c1833fa +PODFILE CHECKSUM: d03a22d8299d9564ca7fc55d0a779f6fbf0d2b37 COCOAPODS: 1.9.3 diff --git a/ios/ReactNativeChat.xcodeproj/project.pbxproj b/ios/ReactNativeChat.xcodeproj/project.pbxproj index 710ee40632db8..0fa565e0bfc75 100644 --- a/ios/ReactNativeChat.xcodeproj/project.pbxproj +++ b/ios/ReactNativeChat.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* ReactNativeChatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactNativeChatTests.m */; }; 0F5BE0CE252686330097D869 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0F5BE0CD252686320097D869 /* GoogleService-Info.plist */; }; + 11973047871545DDB8E5B212 /* libPods-ReactNativeChat-ReactNativeChatTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC449A52E4E55FAE6F278AE2 /* libPods-ReactNativeChat-ReactNativeChatTests.a */; }; 12DD1878FCB9487C9F031C86 /* GTAmericaExpMono-Rg.otf in Resources */ = {isa = PBXBuildFile; fileRef = 8437A5A38F2047E0BCCD7C2F /* GTAmericaExpMono-Rg.otf */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; @@ -20,10 +21,10 @@ 1E76D5252522316A005A268F /* GTAmericaExp-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = A292718541C841859D97DF2F /* GTAmericaExp-Thin.otf */; }; 425866037F4C482AAB46CB8B /* GTAmericaExp-BdIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = A8D6F2F722FD4E66A38EBBB6 /* GTAmericaExp-BdIt.otf */; }; 6856B78873B64C44A92E51DB /* GTAmericaExp-MdIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = DB5A1365442D4419AF6F08E5 /* GTAmericaExp-MdIt.otf */; }; - 712B637C71EDACB60BFCCFDF /* libPods-ReactNativeChat-ReactNativeChatTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5198B14DF64811534104106B /* libPods-ReactNativeChat-ReactNativeChatTests.a */; }; - 7EF88515CE8703E46E771C2D /* libPods-ReactNativeChat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2E64A28C6D8EC058C5C3144 /* libPods-ReactNativeChat.a */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 8821A238A081483FA947BC4E /* GTAmericaExp-RgIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = 918D7FEFF96242E6B5F5E14D /* GTAmericaExp-RgIt.otf */; }; + A53739628A74DEA3CA282B7A /* libPods-ReactNativeChat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DFA0FAB15AD0FB875AD1C944 /* libPods-ReactNativeChat.a */; }; + E9DF872D2525201700607FDC /* AirshipConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = E9DF872C2525201700607FDC /* AirshipConfig.plist */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -48,10 +49,8 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReactNativeChat/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeChat/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeChat/main.m; sourceTree = ""; }; - 2061509B833DB0123E4416F5 /* Pods-ReactNativeChat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat/Pods-ReactNativeChat.release.xcconfig"; sourceTree = ""; }; - 499D0486251AC7F1000B666B /* Chat.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Chat.entitlements; path = ReactNativeChat/Chat.entitlements; sourceTree = ""; }; - 5198B14DF64811534104106B /* libPods-ReactNativeChat-ReactNativeChatTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeChat-ReactNativeChatTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 66FC9F8F0AF1190BE595FC04 /* Pods-ReactNativeChat.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat/Pods-ReactNativeChat.debug.xcconfig"; sourceTree = ""; }; + 2656E49219DD99C2A26000B3 /* Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat-ReactNativeChatTests/Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig"; sourceTree = ""; }; + 3836C07D427AF7E81680B81E /* Pods-ReactNativeChat.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat/Pods-ReactNativeChat.debug.xcconfig"; sourceTree = ""; }; 67D5C3A6A7FA417C8A853FC1 /* GTAmericaExp-Light.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-Light.otf"; path = "../assets/fonts/GTAmericaExp-Light.otf"; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ReactNativeChat/LaunchScreen.storyboard; sourceTree = ""; }; 8437A5A38F2047E0BCCD7C2F /* GTAmericaExpMono-Rg.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExpMono-Rg.otf"; path = "../assets/fonts/GTAmericaExpMono-Rg.otf"; sourceTree = ""; }; @@ -59,12 +58,14 @@ 918D7FEFF96242E6B5F5E14D /* GTAmericaExp-RgIt.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-RgIt.otf"; path = "../assets/fonts/GTAmericaExp-RgIt.otf"; sourceTree = ""; }; A292718541C841859D97DF2F /* GTAmericaExp-Thin.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-Thin.otf"; path = "../assets/fonts/GTAmericaExp-Thin.otf"; sourceTree = ""; }; A5AAD008CBD84A6CAEB9AC97 /* GTAmericaExp-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-Bold.otf"; path = "../assets/fonts/GTAmericaExp-Bold.otf"; sourceTree = ""; }; + A64B7A5E2FB2ADF3F0DB4820 /* Pods-ReactNativeChat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat/Pods-ReactNativeChat.release.xcconfig"; sourceTree = ""; }; A8D6F2F722FD4E66A38EBBB6 /* GTAmericaExp-BdIt.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-BdIt.otf"; path = "../assets/fonts/GTAmericaExp-BdIt.otf"; sourceTree = ""; }; AE65058949E14DA5A2D5435D /* GTAmericaExp-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-Medium.otf"; path = "../assets/fonts/GTAmericaExp-Medium.otf"; sourceTree = ""; }; - B2E64A28C6D8EC058C5C3144 /* libPods-ReactNativeChat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeChat.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - B81A8F09B6065AF7D0A5D2CD /* Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat-ReactNativeChatTests/Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig"; sourceTree = ""; }; - BB3B578785B6B7D4E739A8C8 /* Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat-ReactNativeChatTests/Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig"; sourceTree = ""; }; + C0FF5FF7940AEF7E12B34F6D /* Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeChat-ReactNativeChatTests/Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig"; sourceTree = ""; }; DB5A1365442D4419AF6F08E5 /* GTAmericaExp-MdIt.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-MdIt.otf"; path = "../assets/fonts/GTAmericaExp-MdIt.otf"; sourceTree = ""; }; + DC449A52E4E55FAE6F278AE2 /* libPods-ReactNativeChat-ReactNativeChatTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeChat-ReactNativeChatTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DFA0FAB15AD0FB875AD1C944 /* libPods-ReactNativeChat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeChat.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + E9DF872C2525201700607FDC /* AirshipConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AirshipConfig.plist; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ @@ -74,7 +75,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 712B637C71EDACB60BFCCFDF /* libPods-ReactNativeChat-ReactNativeChatTests.a in Frameworks */, + 11973047871545DDB8E5B212 /* libPods-ReactNativeChat-ReactNativeChatTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -82,7 +83,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7EF88515CE8703E46E771C2D /* libPods-ReactNativeChat.a in Frameworks */, + A53739628A74DEA3CA282B7A /* libPods-ReactNativeChat.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,7 +111,7 @@ isa = PBXGroup; children = ( 0F5BE0CD252686320097D869 /* GoogleService-Info.plist */, - 499D0486251AC7F1000B666B /* Chat.entitlements */, + E9DF872C2525201700607FDC /* AirshipConfig.plist */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.m */, @@ -127,8 +128,8 @@ children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED2971642150620600B7C4FE /* JavaScriptCore.framework */, - B2E64A28C6D8EC058C5C3144 /* libPods-ReactNativeChat.a */, - 5198B14DF64811534104106B /* libPods-ReactNativeChat-ReactNativeChatTests.a */, + DFA0FAB15AD0FB875AD1C944 /* libPods-ReactNativeChat.a */, + DC449A52E4E55FAE6F278AE2 /* libPods-ReactNativeChat-ReactNativeChatTests.a */, ); name = Frameworks; sourceTree = ""; @@ -184,10 +185,10 @@ EC29677F0A49C2946A495A33 /* Pods */ = { isa = PBXGroup; children = ( - 66FC9F8F0AF1190BE595FC04 /* Pods-ReactNativeChat.debug.xcconfig */, - 2061509B833DB0123E4416F5 /* Pods-ReactNativeChat.release.xcconfig */, - BB3B578785B6B7D4E739A8C8 /* Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig */, - B81A8F09B6065AF7D0A5D2CD /* Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig */, + 3836C07D427AF7E81680B81E /* Pods-ReactNativeChat.debug.xcconfig */, + A64B7A5E2FB2ADF3F0DB4820 /* Pods-ReactNativeChat.release.xcconfig */, + 2656E49219DD99C2A26000B3 /* Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig */, + C0FF5FF7940AEF7E12B34F6D /* Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -199,11 +200,11 @@ isa = PBXNativeTarget; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeChatTests" */; buildPhases = ( - ECEBF6D927AD6913C7D49FAA /* [CP] Check Pods Manifest.lock */, + F8A669135F2AA86DB82558C7 /* [CP] Check Pods Manifest.lock */, 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, - 96F29378CAD503EE24A4238F /* [CP] Copy Pods Resources */, + BBCE40C93F738CAC25638238 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -219,15 +220,15 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeChat" */; buildPhases = ( - C918B32D93F5DFC09167D222 /* [CP] Check Pods Manifest.lock */, + BD561FBF598A2868A469788D /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 5BB2824F6A06E2743CB8B76F /* [CP-User] [RNFB] Core Configuration */, - F8A9FC2B4F4B70EAD371DCC7 /* [CP-User] [RNFB] Crashlytics Configuration */, - 2BEB5135F1A6A0AFC39DEE60 /* [CP] Copy Pods Resources */, + B3F9394D94FC2E48E13823AD /* [CP] Copy Pods Resources */, + C00150F40DD23A06B9111196 /* [CP-User] [RNFB] Core Configuration */, + 7876F9D130A277A31FD2253C /* [CP-User] [RNFB] Crashlytics Configuration */, ); buildRules = ( ); @@ -292,6 +293,7 @@ 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, 0F5BE0CE252686330097D869 /* GoogleService-Info.plist in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + E9DF872D2525201700607FDC /* AirshipConfig.plist in Resources */, 12DD1878FCB9487C9F031C86 /* GTAmericaExpMono-Rg.otf in Resources */, 1E76D5212522316A005A268F /* GTAmericaExp-Bold.otf in Resources */, 1E76D5222522316A005A268F /* GTAmericaExp-Light.otf in Resources */, @@ -321,17 +323,137 @@ shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; }; - 2BEB5135F1A6A0AFC39DEE60 /* [CP] Copy Pods Resources */ = { + 7876F9D130A277A31FD2253C /* [CP-User] [RNFB] Crashlytics Configuration */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + name = "[CP-User] [RNFB] Crashlytics Configuration"; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n"; + }; + B3F9394D94FC2E48E13823AD /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ReactNativeChat/Pods-ReactNativeChat-resources.sh", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAAutomationActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageBannerContentView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageBannerView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageButtonView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageFullScreenViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageHTMLViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageModalViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageResizableViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAAutomation.xcdatamodeld", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ar.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/cs.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/da.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/de.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/en.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/es-419.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/es.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/fi.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/fr.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/hi.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/hu.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/id.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/it.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/iw.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ja.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ko.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ms.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/nl.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/no.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/pl.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/pt-PT.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/pt.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ro.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ru.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/sk.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/sv.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/th.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/tr.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/UAEvents.xcdatamodeld", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/UARemoteData.xcdatamodeld", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/vi.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/zh-Hans.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/zh-Hant.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/ios/UADefaultActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/ios/UANativeBridge", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/ios/UANotificationCategories.plist", + "${PODS_ROOT}/Airship/Airship/AirshipExtendedActions/Resources/UAExtendedActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipExtendedActions/Resources/UARateAppPromptView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UADefaultMessageCenterListViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UADefaultMessageCenterMessageViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterListCell.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterListViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterMessageViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterPlaceholderIcon.png", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAInbox.xcdatamodeld", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAAutomationActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageBannerContentView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageBannerView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageButtonView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageFullScreenViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageHTMLViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageModalViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageResizableViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAAutomation.momd", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ar.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/cs.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/da.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/de.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/en.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/es-419.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/es.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/fi.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/fr.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/hi.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/hu.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/id.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/it.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/iw.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ja.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ko.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ms.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/nl.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/no.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pl.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pt-PT.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pt.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ro.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ru.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/sk.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/sv.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/th.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/tr.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAEvents.momd", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UARemoteData.momd", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/vi.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/zh-Hans.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/zh-Hant.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UADefaultActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UANativeBridge", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UANotificationCategories.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAExtendedActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UARateAppPromptView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UADefaultMessageCenterListViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UADefaultMessageCenterMessageViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterListCell.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterListViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterMessageViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterPlaceholderIcon.png", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInbox.momd", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", ); runOnlyForDeploymentPostprocessing = 0; @@ -339,27 +461,127 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeChat/Pods-ReactNativeChat-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 5BB2824F6A06E2743CB8B76F /* [CP-User] [RNFB] Core Configuration */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - name = "[CP-User] [RNFB] Core Configuration"; - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\n\n # config.admob_delay_app_measurement_init\n _ADMOB_DELAY_APP_MEASUREMENT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_delay_app_measurement_init\")\n if [[ $_ADMOB_DELAY_APP_MEASUREMENT == \"true\" ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADDelayAppMeasurementInit\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"YES\")\n fi\n\n # config.admob_ios_app_id\n _ADMOB_IOS_APP_ID=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_ios_app_id\")\n if [[ $_ADMOB_IOS_APP_ID ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADApplicationIdentifier\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_ADMOB_IOS_APP_ID\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; - }; - 96F29378CAD503EE24A4238F /* [CP] Copy Pods Resources */ = { + BBCE40C93F738CAC25638238 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ReactNativeChat-ReactNativeChatTests/Pods-ReactNativeChat-ReactNativeChatTests-resources.sh", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAAutomationActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageBannerContentView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageBannerView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageButtonView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageFullScreenViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageHTMLViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageModalViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAInAppMessageResizableViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipAutomation/Resources/UAAutomation.xcdatamodeld", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ar.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/cs.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/da.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/de.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/en.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/es-419.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/es.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/fi.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/fr.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/hi.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/hu.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/id.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/it.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/iw.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ja.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ko.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ms.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/nl.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/no.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/pl.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/pt-PT.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/pt.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ro.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/ru.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/sk.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/sv.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/th.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/tr.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/UAEvents.xcdatamodeld", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/UARemoteData.xcdatamodeld", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/vi.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/zh-Hans.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/common/zh-Hant.lproj", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/ios/UADefaultActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/ios/UANativeBridge", + "${PODS_ROOT}/Airship/Airship/AirshipCore/Resources/ios/UANotificationCategories.plist", + "${PODS_ROOT}/Airship/Airship/AirshipExtendedActions/Resources/UAExtendedActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipExtendedActions/Resources/UARateAppPromptView.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UADefaultMessageCenterListViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UADefaultMessageCenterMessageViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterActions.plist", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterListCell.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterListViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterMessageViewController.xib", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAMessageCenterPlaceholderIcon.png", + "${PODS_ROOT}/Airship/Airship/AirshipMessageCenter/Resources/UAInbox.xcdatamodeld", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAAutomationActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageBannerContentView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageBannerView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageButtonView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageFullScreenViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageHTMLViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageModalViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInAppMessageResizableViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAAutomation.momd", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ar.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/cs.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/da.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/de.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/en.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/es-419.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/es.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/fi.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/fr.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/hi.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/hu.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/id.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/it.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/iw.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ja.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ko.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ms.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/nl.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/no.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pl.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pt-PT.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pt.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ro.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ru.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/sk.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/sv.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/th.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/tr.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAEvents.momd", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UARemoteData.momd", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/vi.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/zh-Hans.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/zh-Hant.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UADefaultActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UANativeBridge", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UANotificationCategories.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAExtendedActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UARateAppPromptView.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UADefaultMessageCenterListViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UADefaultMessageCenterMessageViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterActions.plist", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterListCell.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterListViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterMessageViewController.nib", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAMessageCenterPlaceholderIcon.png", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UAInbox.momd", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", ); runOnlyForDeploymentPostprocessing = 0; @@ -367,7 +589,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeChat-ReactNativeChatTests/Pods-ReactNativeChat-ReactNativeChatTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - C918B32D93F5DFC09167D222 /* [CP] Check Pods Manifest.lock */ = { + BD561FBF598A2868A469788D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -389,7 +611,17 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - ECEBF6D927AD6913C7D49FAA /* [CP] Check Pods Manifest.lock */ = { + C00150F40DD23A06B9111196 /* [CP-User] [RNFB] Core Configuration */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + name = "[CP-User] [RNFB] Core Configuration"; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\n\n # config.admob_delay_app_measurement_init\n _ADMOB_DELAY_APP_MEASUREMENT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_delay_app_measurement_init\")\n if [[ $_ADMOB_DELAY_APP_MEASUREMENT == \"true\" ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADDelayAppMeasurementInit\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"YES\")\n fi\n\n # config.admob_ios_app_id\n _ADMOB_IOS_APP_ID=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_ios_app_id\")\n if [[ $_ADMOB_IOS_APP_ID ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADApplicationIdentifier\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_ADMOB_IOS_APP_ID\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; + }; + F8A669135F2AA86DB82558C7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -411,16 +643,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - F8A9FC2B4F4B70EAD371DCC7 /* [CP-User] [RNFB] Crashlytics Configuration */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - name = "[CP-User] [RNFB] Crashlytics Configuration"; - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n"; - }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -473,7 +695,7 @@ /* Begin XCBuildConfiguration section */ 00E356F61AD99517003FC87E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BB3B578785B6B7D4E739A8C8 /* Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig */; + baseConfigurationReference = 2656E49219DD99C2A26000B3 /* Pods-ReactNativeChat-ReactNativeChatTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -482,7 +704,7 @@ "$(inherited)", ); INFOPLIST_FILE = ReactNativeChatTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = ( "-ObjC", @@ -497,13 +719,13 @@ }; 00E356F71AD99517003FC87E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B81A8F09B6065AF7D0A5D2CD /* Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig */; + baseConfigurationReference = C0FF5FF7940AEF7E12B34F6D /* Pods-ReactNativeChat-ReactNativeChatTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = ReactNativeChatTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = ( "-ObjC", @@ -518,7 +740,7 @@ }; 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 66FC9F8F0AF1190BE595FC04 /* Pods-ReactNativeChat.debug.xcconfig */; + baseConfigurationReference = 3836C07D427AF7E81680B81E /* Pods-ReactNativeChat.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -548,7 +770,7 @@ }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2061509B833DB0123E4416F5 /* Pods-ReactNativeChat.release.xcconfig */; + baseConfigurationReference = A64B7A5E2FB2ADF3F0DB4820 /* Pods-ReactNativeChat.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -621,7 +843,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LIBRARY_SEARCH_PATHS = ( "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", @@ -674,7 +896,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LIBRARY_SEARCH_PATHS = ( "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", diff --git a/ios/ReactNativeChat/Info.plist b/ios/ReactNativeChat/Info.plist index e192eeec19c48..166936d0835cc 100644 --- a/ios/ReactNativeChat/Info.plist +++ b/ios/ReactNativeChat/Info.plist @@ -23,28 +23,28 @@ CFBundleVersion 132 ITSAppUsesNonExemptEncryption - + LSRequiresIPhoneOS - + NSAppTransportSecurity NSAllowsArbitraryLoads - + NSExceptionDomains localhost NSExceptionAllowsInsecureHTTPLoads - + NSIncludesSubdomains - + www.expensify.com.dev NSExceptionAllowsInsecureHTTPLoads - + NSIncludesSubdomains - + @@ -86,6 +86,6 @@ UIInterfaceOrientationPortraitUpsideDown UIViewControllerBasedStatusBarAppearance - + diff --git a/package-lock.json b/package-lock.json index 345a115f5b05f..f173776d81d2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17743,6 +17743,11 @@ } } }, + "urbanairship-react-native": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/urbanairship-react-native/-/urbanairship-react-native-8.1.0.tgz", + "integrity": "sha512-iyw32YwoXz7lrng2W5D+l+S4tgGx64Mi4h9qtQQLXyjXDZMtt73T8Sv6+W4KxyHq+YfbkAlWhYDCaTsN33dq/w==" + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", diff --git a/package.json b/package.json index 06552ce0150d7..0caabe9a34311 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "react-router-native": "^5.2.0", "react-web-config": "^1.0.0", "save": "^2.4.0", - "underscore": "^1.10.2" + "underscore": "^1.10.2", + "urbanairship-react-native": "^8.1.0" }, "devDependencies": { "@babel/core": "^7.11.1", diff --git a/src/IONKEYS.js b/src/IONKEYS.js index b98f91925a246..d05c5f0d8e1ee 100644 --- a/src/IONKEYS.js +++ b/src/IONKEYS.js @@ -12,6 +12,7 @@ export default { NETWORK: 'network', PERSONAL_DETAILS: 'personalDetails', SESSION: 'session', + IS_SIDEBAR_SHOWN: 'isSidebarShown', // Collection Keys COLLECTION: { diff --git a/src/libs/API.js b/src/libs/API.js index 22167e56515ba..ea5a11ce78e76 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -9,6 +9,7 @@ import ROUTES from '../ROUTES'; import Str from './Str'; import guid from './guid'; import redirectToSignIn from './actions/SignInRedirect'; +import PushNotification from './Notification/PushNotification'; // Queue for network requests so we don't lose actions done by the user while offline let networkRequestQueue = []; @@ -122,8 +123,9 @@ function createLogin(login, password) { * @param {string} exitTo */ function setSuccessfulSignInData(data, exitTo) { - const redirectTo = exitTo ? Str.normalizeUrl(exitTo) : ROUTES.ROOT; + PushNotification.register(data.accountID); + const redirectTo = exitTo ? Str.normalizeUrl(exitTo) : ROUTES.ROOT; Ion.multiSet({ [IONKEYS.SESSION]: _.pick(data, 'authToken', 'accountID', 'email'), [IONKEYS.APP_REDIRECT_TO]: redirectTo diff --git a/src/libs/Ion.js b/src/libs/Ion.js index ee6b140cb5db2..16f21901f9c4d 100644 --- a/src/libs/Ion.js +++ b/src/libs/Ion.js @@ -24,7 +24,7 @@ const evictionBlocklist = {}; * Get some data from the store * * @param {string} key - * @returns {*} + * @returns {Promise<*>} */ function get(key) { return AsyncStorage.getItem(key) @@ -346,7 +346,7 @@ function multiSet(data) { /** * Clear out all the data in the store * - * @returns {Promise} + * @returns {Promise} */ function clear() { return AsyncStorage.clear(); diff --git a/src/libs/Notification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js similarity index 97% rename from src/libs/Notification/BrowserNotifications.js rename to src/libs/Notification/LocalNotification/BrowserNotifications.js index c5c52dccf9ebe..84b6a8990388d 100644 --- a/src/libs/Notification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -1,6 +1,6 @@ -// Web and desktop implementation only. Do not import for direct use. Use Notification. -import Str from '../Str'; -import CONST from '../../CONST'; +// Web and desktop implementation only. Do not import for direct use. Use LocalNotification. +import Str from '../../Str'; +import CONST from '../../../CONST'; const EXPENSIFY_ICON_URL = `${CONST.CLOUDFRONT_URL}/images/favicon-2019.png`; const DEFAULT_DELAY = 4000; diff --git a/src/libs/Notification/index.js b/src/libs/Notification/LocalNotification/index.js similarity index 100% rename from src/libs/Notification/index.js rename to src/libs/Notification/LocalNotification/index.js diff --git a/src/libs/Notification/LocalNotification/index.native.js b/src/libs/Notification/LocalNotification/index.native.js new file mode 100644 index 0000000000000..8dca0ebb7537e --- /dev/null +++ b/src/libs/Notification/LocalNotification/index.native.js @@ -0,0 +1,4 @@ +// Local Notifications are not currently supported on mobile so we'll just noop here. +export default { + showCommentNotification: () => {}, +}; diff --git a/src/libs/Notification/PushNotification/NotificationType.js b/src/libs/Notification/PushNotification/NotificationType.js new file mode 100644 index 0000000000000..1afa89d002013 --- /dev/null +++ b/src/libs/Notification/PushNotification/NotificationType.js @@ -0,0 +1,7 @@ +/** + * See https://github.com/Expensify/Web-Expensify/blob/master/lib/MobilePushNotifications.php for the various + * types of push notifications sent by our API. + */ +export default { + REPORT_COMMENT: 'reportComment', +}; diff --git a/src/libs/Notification/PushNotification/index.js b/src/libs/Notification/PushNotification/index.js new file mode 100644 index 0000000000000..ad8c27a5ddbac --- /dev/null +++ b/src/libs/Notification/PushNotification/index.js @@ -0,0 +1,10 @@ +import NotificationType from './NotificationType'; + +// Push notifications are only supported on mobile, so we'll just noop here +export default { + register: () => {}, + deregister: () => {}, + onReceived: () => {}, + onSelected: () => {}, + TYPE: NotificationType, +}; diff --git a/src/libs/Notification/PushNotification/index.native.js b/src/libs/Notification/PushNotification/index.native.js new file mode 100644 index 0000000000000..2f48f8f921918 --- /dev/null +++ b/src/libs/Notification/PushNotification/index.native.js @@ -0,0 +1,149 @@ +import _ from 'underscore'; +import {AppState} from 'react-native'; +import {UrbanAirship, EventType} from 'urbanairship-react-native'; +import lodashGet from 'lodash.get'; +import NotificationType from './NotificationType'; + +const notificationEventActionMap = {}; + +/** + * Handle a push notification event, and trigger and bound actions. + * + * @param {string} eventType + * @param {object} notification + */ +function pushNotificationEventCallback(eventType, notification) { + const actionMap = notificationEventActionMap[eventType] || {}; + let payload = lodashGet(notification, 'extras.payload'); + + // On Android, some notification payloads are sent as a JSON string rather than an object + if (_.isString(payload)) { + payload = JSON.parse(payload); + } + + console.debug(`[PUSH_NOTIFICATION] ${eventType}`, { + title: notification.title, + message: notification.alert, + payload + }); + + if (!payload) { + console.debug('[PUSH_NOTIFICATION] Notification has null or undefined payload, not executing any callback.'); + return; + } + + // If a push notification is received while the app is in foreground, + // we'll assume pusher is connected so we'll ignore is and not fetch the same data twice. + // However, we will allow NotificationResponse events through, so that tapping on a foreground notification + // will take you to the relevant report. + // Note: We hope to prevent foreground notifications from appearing in the near future, + // so when that happens we can go back to ignoring all push notification callbacks when the app is in the foreground + if (AppState.currentState === 'active' && eventType === EventType.PushReceived) { + console.debug('[PUSH_NOTIFICATION] Push received while app is in foreground, not executing any callback.'); + return; + } + + if (!payload.type) { + console.debug('[PUSH_NOTIFICATION] No type value provided in payload, not executing any callback.'); + return; + } + + const action = actionMap[payload.type]; + if (!action) { + console.debug('[PUSH_NOTIFICATION] No callback set up: ', { + event: eventType, + notificationType: payload.type, + }); + return; + } + action(payload); +} + +/** + * Register this device for push notifications for the given accountID. + * + * @param {string|int} accountID + */ +function register(accountID) { + // Get permissions to display push notifications (prompts user on iOS, but not Android) + UrbanAirship.enableUserPushNotifications() + .then((isEnabled) => { + if (!isEnabled) { + console.debug('[PUSH_NOTIFICATIONS] User has disabled visible push notifications for this app.'); + } + }); + + // Register this device as a named user in AirshipAPI. + // Regardless of the user's opt-in status, we still want to receive silent push notifications. + console.debug(`[PUSH_NOTIFICATIONS] Subscribing to notifications for account ID ${accountID}`); + UrbanAirship.setNamedUser(accountID.toString()); + + // Setup event listeners + UrbanAirship.addListener(EventType.PushReceived, (notification) => { + pushNotificationEventCallback(EventType.PushReceived, notification); + }); + + // Note: the NotificationResponse event has a nested PushReceived event, + // so event.notification refers to the same thing as notification above ^ + UrbanAirship.addListener(EventType.NotificationResponse, (event) => { + pushNotificationEventCallback(EventType.NotificationResponse, event.notification); + }); +} + +/** + * Deregister this device from push notifications. + */ +function deregister() { + console.debug('[PUSH_NOTIFICATIONS] Unsubscribing from push notifications.'); + UrbanAirship.setNamedUser(null); + UrbanAirship.removeAllListeners(EventType.PushReceived); + UrbanAirship.removeAllListeners(EventType.NotificationResponse); +} + +/** + * Bind a callback to a push notification of a given type. + * See https://github.com/Expensify/Web-Expensify/blob/master/lib/MobilePushNotifications.php for the various + * types of push notifications sent, along with the data that they provide. + * + * Note: This implementation allows for only one callback to be bound to an Event/Type pair. For example, + * if we attempt to bind two callbacks to the PushReceived event for reportComment notifications, + * the second will overwrite the first. + * + * @param {string} notificationType + * @param {Function} callback + * @param {string?} triggerEvent - The event that should trigger this callback. Should be one of UrbanAirship.EventType + */ +function bind(notificationType, callback, triggerEvent) { + if (!notificationEventActionMap[triggerEvent]) { + notificationEventActionMap[triggerEvent] = {}; + } + notificationEventActionMap[triggerEvent][notificationType] = callback; +} + +/** + * Bind a callback to be executed when a push notification of a given type is received. + * + * @param {string} notificationType + * @param {Function} callback + */ +function onReceived(notificationType, callback) { + bind(notificationType, callback, EventType.PushReceived); +} + +/** + * Bind a callback to be executed when a push notification of a given type is tapped by the user. + * + * @param {string} notificationType + * @param {Function} callback + */ +function onSelected(notificationType, callback) { + bind(notificationType, callback, EventType.NotificationResponse); +} + +export default { + register, + deregister, + onReceived, + onSelected, + TYPE: NotificationType, +}; diff --git a/src/libs/Notification/index.native.js b/src/libs/Notification/index.native.js deleted file mode 100644 index e1b798612c610..0000000000000 --- a/src/libs/Notification/index.native.js +++ /dev/null @@ -1,4 +0,0 @@ -// Browser Notifications are not supported on mobile so we'll just noop here. -export default { - showCommentNotification: () => {}, -}; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index fffee9249d487..94959beb2145a 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -6,13 +6,15 @@ import Ion from '../Ion'; import * as API from '../API'; import IONKEYS from '../../IONKEYS'; import * as Pusher from '../Pusher/pusher'; -import Notification from '../Notification'; +import LocalNotification from '../Notification/LocalNotification'; +import PushNotification from '../Notification/PushNotification'; import * as PersonalDetails from './PersonalDetails'; import {redirect} from './App'; import * as ActiveClientManager from '../ActiveClientManager'; import Visibility from '../Visibility'; import ROUTES from '../../ROUTES'; import NetworkConnection from '../NetworkConnection'; +import {hide as hideSidebar} from './Sidebar'; let currentUserEmail; let currentUserAccountID; @@ -195,24 +197,24 @@ function updateReportWithNewAction(reportID, reportAction) { }); if (!ActiveClientManager.isClientTheLeader()) { - console.debug('[NOTIFICATION] Skipping notification because this client is not the leader'); + console.debug('[LOCAL_NOTIFICATION] Skipping notification because this client is not the leader'); return; } // If this comment is from the current user we don't want to parrot whatever they wrote back to them. if (reportAction.actorAccountID === currentUserAccountID) { - console.debug('[NOTIFICATION] No notification because comment is from the currently logged in user'); + console.debug('[LOCAL_NOTIFICATION] No notification because comment is from the currently logged in user'); return; } // If we are currently viewing this report do not show a notification. if (reportID === lastViewedReportID && Visibility.isVisible()) { - console.debug('[NOTIFICATION] No notification because it was a comment for the current report'); + console.debug('[LOCAL_NOTIFICATION] No notification because it was a comment for the current report'); return; } - console.debug('[NOTIFICATION] Creating notification'); - Notification.showCommentNotification({ + console.debug('[LOCAL_NOTIFICATION] Creating notification'); + LocalNotification.showCommentNotification({ reportAction, onClick: () => { // Navigate to this report onClick @@ -248,6 +250,16 @@ function subscribeToReportCommentEvents() { Pusher.subscribe(pusherChannelName, 'reportComment', (pushJSON) => { updateReportWithNewAction(pushJSON.reportID, pushJSON.reportAction); }); + + PushNotification.onReceived(PushNotification.TYPE.REPORT_COMMENT, ({reportID, reportAction}) => { + updateReportWithNewAction(reportID, reportAction); + }); + + // Open correct report when push notification is clicked + PushNotification.onSelected(PushNotification.TYPE.REPORT_COMMENT, ({reportID}) => { + redirect(ROUTES.getReportRoute(reportID)); + hideSidebar(); + }); } /** diff --git a/src/libs/actions/Sidebar.js b/src/libs/actions/Sidebar.js new file mode 100644 index 0000000000000..5c8789dd058d2 --- /dev/null +++ b/src/libs/actions/Sidebar.js @@ -0,0 +1,21 @@ +import Ion from '../Ion'; +import IONKEYS from '../../IONKEYS'; + +/** + * Hide the sidebar, if it is shown. + */ +function hide() { + Ion.set(IONKEYS.IS_SIDEBAR_SHOWN, false); +} + +/** + * Show the sidebar, if it is hidden. + */ +function show() { + Ion.set(IONKEYS.IS_SIDEBAR_SHOWN, true); +} + +export { + hide, + show, +}; diff --git a/src/libs/actions/SignInRedirect.js b/src/libs/actions/SignInRedirect.js index 973a6461014f3..a7c8f14e6302a 100644 --- a/src/libs/actions/SignInRedirect.js +++ b/src/libs/actions/SignInRedirect.js @@ -5,6 +5,7 @@ import {redirect} from './App'; import * as Pusher from '../Pusher/pusher'; import NetworkConnection from '../NetworkConnection'; import UnreadIndicatorUpdater from '../UnreadIndicatorUpdater'; +import PushNotification from '../Notification/PushNotification'; let currentURL; Ion.connect({ @@ -21,6 +22,7 @@ Ion.connect({ function redirectToSignIn(errorMessage) { NetworkConnection.stopListeningForReconnect(); UnreadIndicatorUpdater.stopListeningForReportChanges(); + PushNotification.deregister(); Pusher.disconnect(); Ion.clear() .then(() => { diff --git a/src/pages/home/HomePage.js b/src/pages/home/HomePage.js index 7446698f5c4c6..a3bef18cf6ce6 100644 --- a/src/pages/home/HomePage.js +++ b/src/pages/home/HomePage.js @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { StatusBar, View, @@ -7,12 +8,14 @@ import { Easing, Keyboard } from 'react-native'; +import _ from 'underscore'; import {SafeAreaInsetsContext, SafeAreaProvider} from 'react-native-safe-area-context'; import {Route} from '../../libs/Router'; import styles, {getSafeAreaPadding} from '../../styles/StyleSheet'; import Header from './HeaderView'; import Sidebar from './sidebar/SidebarView'; import Main from './MainView'; +import {hide as hideSidebar, show as showSidebar} from '../../libs/actions/Sidebar'; import { subscribeToReportCommentEvents, fetchAll as fetchAllReports, @@ -22,17 +25,25 @@ import {fetch as fetchPersonalDetails} from '../../libs/actions/PersonalDetails' import * as Pusher from '../../libs/Pusher/pusher'; import UnreadIndicatorUpdater from '../../libs/UnreadIndicatorUpdater'; import ROUTES from '../../ROUTES'; +import IONKEYS from '../../IONKEYS'; +import withIon from '../../components/withIon'; import NetworkConnection from '../../libs/NetworkConnection'; const windowSize = Dimensions.get('window'); const widthBreakPoint = 1000; -export default class App extends React.Component { +const propTypes = { + isSidebarShown: PropTypes.bool, +}; +const defaultProps = { + isSidebarShown: true, +}; + +class App extends React.Component { constructor(props) { super(props); this.state = { - hamburgerShown: true, isHamburgerEnabled: windowSize.width <= widthBreakPoint, }; @@ -40,7 +51,12 @@ export default class App extends React.Component { this.dismissHamburger = this.dismissHamburger.bind(this); this.showHamburger = this.showHamburger.bind(this); this.toggleHamburgerBasedOnDimensions = this.toggleHamburgerBasedOnDimensions.bind(this); - this.animationTranslateX = new Animated.Value(!this.state.hamburgerShown ? -300 : 0); + + // Note: This null check is only necessary because withIon passes null for bound props + // that are null-initialized initialized in Ion, and defaultProps only replaces for `undefined` values + this.animationTranslateX = new Animated.Value( + !_.isNull(props.isSidebarShown) && !props.isSidebarShown ? -300 : 0 + ); } componentDidMount() { @@ -63,6 +79,14 @@ export default class App extends React.Component { StatusBar.setTranslucent(true); } + componentDidUpdate(prevProps) { + if (this.props.isSidebarShown === prevProps.isSidebarShown) { + // Nothing changed, don't trigger animation or re-render + return; + } + this.animateHamburger(prevProps.isSidebarShown); + } + componentWillUnmount() { Dimensions.removeEventListener('change', this.toggleHamburgerBasedOnDimensions); } @@ -73,10 +97,10 @@ export default class App extends React.Component { */ toggleHamburgerBasedOnDimensions({window: changedWindow}) { this.setState({isHamburgerEnabled: changedWindow.width <= widthBreakPoint}); - if (!this.state.hamburgerShown && changedWindow.width > widthBreakPoint) { - this.setState({hamburgerShown: true}); - } else if (this.state.hamburgerShown && changedWindow.width < widthBreakPoint) { - this.setState({hamburgerShown: false}); + if (!this.props.isSidebarShown && changedWindow.width > widthBreakPoint) { + showSidebar(); + } else if (this.props.isSidebarShown && changedWindow.width < widthBreakPoint) { + hideSidebar(); } } @@ -86,7 +110,7 @@ export default class App extends React.Component { * Only changes hamburger state on small screens (e.g. Mobile and mWeb) */ dismissHamburger() { - if (!this.state.hamburgerShown) { + if (!this.props.isSidebarShown) { return; } @@ -99,7 +123,7 @@ export default class App extends React.Component { * Only changes hamburger state on smaller screens (e.g. Mobile and mWeb) */ showHamburger() { - if (this.state.hamburgerShown) { + if (this.props.isSidebarShown) { return; } @@ -120,10 +144,8 @@ export default class App extends React.Component { easing: Easing.ease, useNativeDriver: false }).start(({finished}) => { - // If the hamburger is currently shown, we want to hide it only after the animation is complete - // Otherwise, we can't see the animation if (finished && hamburgerIsShown) { - this.setState({hamburgerShown: false}); + hideSidebar(); } }); } @@ -137,20 +159,21 @@ export default class App extends React.Component { return; } - const hamburgerIsShown = this.state.hamburgerShown; - - // If the hamburger currently is not shown, we want to immediately make it visible for the animation - if (!hamburgerIsShown) { - this.setState({hamburgerShown: true}); + // If the hamburger currently is not shown, we want to make it visible before the animation + if (!this.props.isSidebarShown) { + showSidebar(); + return; } + + // Otherwise, we want to hide it after the animation Keyboard.dismiss(); - this.animateHamburger(hamburgerIsShown); + this.animateHamburger(true); } render() { - const hamburgerStyle = this.state.isHamburgerEnabled && this.state.hamburgerShown + const hamburgerStyle = this.state.isHamburgerEnabled && this.props.isSidebarShown ? styles.hamburgerOpenAbsolute : styles.hamburgerOpen; - const visibility = this.state.hamburgerShown ? styles.dFlex : styles.dNone; + const visibility = !this.state.isHamburgerEnabled || this.props.isSidebarShown ? styles.dFlex : styles.dNone; const appContentWrapperStyle = !this.state.isHamburgerEnabled ? styles.appContentWrapperLarge : null; const appContentStyle = !this.state.isHamburgerEnabled ? styles.appContentRounded : null; return ( @@ -198,3 +221,14 @@ export default class App extends React.Component { ); } } + +App.propTypes = propTypes; +App.defaultProps = defaultProps; + +export default withIon( + { + isSidebarShown: { + key: IONKEYS.IS_SIDEBAR_SHOWN + }, + }, +)(App);