From 68ffddbb51f07ba05eba28cafa5e49ad43097634 Mon Sep 17 00:00:00 2001 From: Brian Sztamfater Date: Mon, 30 Aug 2021 19:51:19 -0300 Subject: [PATCH] Add ability to Share image from Status Signed-off-by: Brian Sztamfater --- .../im/status/ethereum/MainApplication.java | 1 + android/settings.gradle | 2 + ios/Podfile | 2 + ios/Podfile.lock | 20 ++-- package.json | 1 + resources/images/icons/share_default@2x.png | Bin 0 -> 442 bytes resources/images/icons/share_default@3x.png | Bin 0 -> 647 bytes .../ui/screens/chat/image/preview/views.cljs | 111 ++++++++++-------- src/status_im/utils/fs.cljs | 8 ++ src/status_im/utils/share.cljs | 8 ++ yarn.lock | 5 + 11 files changed, 100 insertions(+), 58 deletions(-) create mode 100755 resources/images/icons/share_default@2x.png create mode 100755 resources/images/icons/share_default@3x.png create mode 100644 src/status_im/utils/share.cljs diff --git a/android/app/src/main/java/im/status/ethereum/MainApplication.java b/android/app/src/main/java/im/status/ethereum/MainApplication.java index b518c52405..6f0edb8c64 100644 --- a/android/app/src/main/java/im/status/ethereum/MainApplication.java +++ b/android/app/src/main/java/im/status/ethereum/MainApplication.java @@ -9,6 +9,7 @@ import com.facebook.react.PackageList; import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage; import com.facebook.react.ReactApplication; +import cl.json.RNSharePackage; import com.facebook.react.ReactNativeHost; import com.reactnativenavigation.NavigationApplication; import com.reactnativenavigation.react.NavigationReactNativeHost; diff --git a/android/settings.gradle b/android/settings.gradle index be6cd9eccc..b7e21aeb2c 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,6 @@ pluginManagement { +include ':react-native-share' +project(':react-native-share').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-share/android') repositories { mavenLocal() // Let's prioritize local Maven repos so that Nix can provide them offline gradlePluginPortal() diff --git a/ios/Podfile b/ios/Podfile index 8adf9294a8..acc1dbf037 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -25,6 +25,8 @@ abstract_target 'Status' do pod 'secp256k1', git: "https://github.com/status-im/secp256k1.swift.git", submodules: true target 'StatusIm' do + pod 'RNShare', :path => '../node_modules/react-native-share' + target 'StatusImTests' do inherit! :complete # Pods for testing diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f9e6be59bc..b4174f5837 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2,7 +2,7 @@ PODS: - boost-for-react-native (1.63.0) - BVLinearGradient (2.5.6): - React - - CryptoSwift (1.3.8) + - CryptoSwift (1.4.1) - DoubleConversion (1.1.6) - FBLazyVector (0.63.4) - FBReactNativeSpec (0.63.4): @@ -224,7 +224,7 @@ PODS: - react-native-status-keycard (2.5.35): - Keycard - React - - react-native-webview (10.9.2): + - react-native-webview (11.3.0): - React-Core - React-RCTActionSheet (0.63.4): - React-Core/RCTActionSheetHeaders (= 0.63.4) @@ -359,6 +359,8 @@ PODS: - React-RCTVibration - ReactCommon/turbomodule/core - Yoga + - RNShare (7.0.1): + - React-Core - RNSVG (9.13.6): - React - secp256k1 (0.1.6) @@ -367,7 +369,7 @@ PODS: - SQLCipher/common (3.4.2) - SQLCipher/standard (3.4.2): - SQLCipher/common - - SSZipArchive (2.2.3) + - SSZipArchive (2.4.2) - TOCropViewController (2.6.0) - TouchID (4.4.1): - React @@ -435,6 +437,7 @@ DEPENDENCIES: - RNPermissions (from `../node_modules/react-native-permissions`) - RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`) - RNReanimated (from `../node_modules/react-native-reanimated`) + - RNShare (from `../node_modules/react-native-share`) - RNSVG (from `../node_modules/react-native-svg`) - secp256k1 (from `https://github.com/status-im/secp256k1.swift.git`) - SQLCipher (~> 3.0) @@ -569,6 +572,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-haptic-feedback" RNReanimated: :path: "../node_modules/react-native-reanimated" + RNShare: + :path: "../node_modules/react-native-share" RNSVG: :path: "../node_modules/react-native-svg" secp256k1: @@ -591,7 +596,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872 - CryptoSwift: 01b0f0cba1d5c212e5a335ff6c054fb75a204f00 + CryptoSwift: 0bc800a7e6a24c4fc9ebeab97d44b0d5f73a78bd DoubleConversion: cde416483dac037923206447da6e1454df403714 FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e @@ -623,7 +628,7 @@ SPEC CHECKSUMS: react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-status: 45dbf1302ce3c258b459dfab137cd1c2c68c295d react-native-status-keycard: de55c01648d24ff7c17a77f3aa29a0421f44143c - react-native-webview: 4e96d493f9f90ba4f03b28933f30b2964df07e39 + react-native-webview: af9990b21a9aeafa8e8347746eb4116c0de086af React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0 @@ -650,14 +655,15 @@ SPEC CHECKSUMS: RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467 RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071 RNReanimated: 70f662b5232dd5d19ccff581e919a54ea73df51c + RNShare: 2dc2fcac3f7321cfd6b60a23ed4bf4d549f86f5f RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f secp256k1: f61d67e6fdcb85fd727acf1bf35ace6036db540c SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990 - SSZipArchive: 62d4947b08730e4cda640473b0066d209ff033c9 + SSZipArchive: e7b4f3d9e780c2acc1764cd88fbf2de28f26e5b2 TOCropViewController: 3105367e808b7d3d886a74ff59bf4804e7d3ab38 TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4 Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6 -PODFILE CHECKSUM: 27b3929c4d7f0b5afd76276d0bd4ae289ec11f18 +PODFILE CHECKSUM: 2769eb02c836ad1eaddf5f34a0c61153c4c5fbec COCOAPODS: 1.10.1 diff --git a/package.json b/package.json index 3de5328c16..442ed3d30e 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "react-native-redash": "^16.0.11", "react-native-safe-area-context": "^2.0.0", "react-native-shake": "^3.3.1", + "react-native-share": "^7.0.1", "react-native-splash-screen": "^3.2.0", "react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.5.35", "react-native-svg": "^9.8.4", diff --git a/resources/images/icons/share_default@2x.png b/resources/images/icons/share_default@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..aeb279a80fb2727ea8cedb31d95e3dee7794535b GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-s_5nU2u0Wa+uvxW9AE;lXB*-tA zp+RB4!2N{!_w(Zm*5^B%H(0P?f_>&bRt5$}F;5rAkczmwS8jG4Q4nZN)SbQ}a#!`U z`v2*&9A~E7=zR3_%T5lKKMT10lk6-uo@wMc{p6?S#6+)@8A6iFT-r1zHs$wS)QLj_4?+4c8omZ2tVU{lTuX@&I?!`@7Bj4@5W={$|NE z^ldnFeT5WX&fg$6g=@yD6@3j3KbQ~f@OEH#(U28zaI=4`zNG49MpfqYZ4cZMR-b;@ zxS0Fa?$Rh;-{{^u+Vhv`&Y#w-Q2yXT)%EJbVe{TQENbqqKQ!xwi+y14o_CGA=Y^F` g&u}idHv9Z3{$h1$r}go_1wb+2>FVdQ&MBb@06T-BjQ{`u literal 0 HcmV?d00001 diff --git a/resources/images/icons/share_default@3x.png b/resources/images/icons/share_default@3x.png new file mode 100755 index 0000000000000000000000000000000000000000..122680892d3c64af1831b43637cee5d44b0d7288 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAjKY=BRQE0Crg*vT&P0cg5hNswPK zgG0mo{r43N-Y+;mL7@L%LVUqJ#{Bj5=NuI`?0YwFg;;(l0|Vo3PZ!6KinzDeqKlgq z1XvS7^te`Z`p$~``QLu?;UiysRHehtIIB}QRS-8r7=^y2-KmJ4@| zHg37w81l~H)*FXgK=Pe~R=L7d>rL5oGq3P5 z5@#1s+053&tl`x#qcELaVBYRYr+F@1^X3!yB)?F734iaVwx*sf$D7j(7V{WRYr0Zd zIeoQrtEI@5bFW{CJ^fwKxmZD5@1^b23~TMRYhE6fd-{Hv$-^_LC$+A-hn9PPN_U@? zBmZ#ewaL?y&c0o2b>z!R<3lH%CtPA>Rp)mMI@$JN3OA?Z(p2l49GPYg+~p$w9_4}m#usLv~Hgf8u`q(ZN|y_QWJcq2I~3DFj{Q3<#dl%D3>O{RBlX3OBm{Tll8%;sU$ - [react/touchable-opacity - {:on-press (fn [] - (on-close) - (re-frame/dispatch [:chat.ui/save-image-to-gallery (get-in message [:content :image])])) - :style {:background-color colors/black-transparent-86 - :border-radius 44 - :padding 8 - :position :absolute - :bottom 0 - :right 0}} - [icons/icon :main-icons/download {:container-style {:width 24 - :height 24} - :color colors/white-persist}]]] - [:<> - [react/touchable-opacity - {:on-press #(reset! show-sheet true) - :style {:background-color colors/black-transparent-86 - :border-radius 44 - :padding 8 - :position :absolute - :bottom 0 - :right 0}} - [icons/icon :main-icons/more {:container-style {:width 24 + [react/view {:style {:flex-direction :row + :background-color colors/black-transparent-86 + :border-radius 44 + :padding-vertical 8 + :padding-horizontal 12 + :position :absolute + :right 0}} + [react/touchable-opacity + {:on-press (fn [] + (on-close) + (re-frame/dispatch [:chat.ui/save-image-to-gallery (get-in message [:content :image])])) + :style {:margin-right 10} + :accessibility-label :save-button} + [icons/icon :main-icons/download {:container-style {:width 24 :height 24} :color colors/white-persist}]] - ;; NOTE(Ferossgp): If we use global bottom sheet, then it is rendered under the preview - [quo/bottom-sheet {:visible? @show-sheet - :on-cancel #(reset! show-sheet false)} - [sheets/image-long-press message #(do (reset! show-sheet false) - (on-close))]]])))) + [react/touchable-opacity + {:on-press (fn [] + (fs/write-file + temp-image-url + (last (string/split (get-in message [:content :image]) ",")) "base64" + #(share) + #(log/error "error writing image to cache dir"))) + :style {:margin-left 10} + :accessibility-label :share-button} + [icons/icon :main-icons/share-default {:container-style {:width 24 + :height 24} + :color colors/white-persist}]]])) -(defn footer [{:keys [on-close] :as props}] +(defn header [{:keys [on-close] :as props}] [safe-area/consumer (fn [insets] - [react/view {:style {:padding-horizontal 24 - :padding-bottom (+ (:bottom insets) 8)}} - [react/view {:style {:justify-content :center - :align-items :center}} + [react/view {:style {:padding-horizontal 15 + :padding-top (+ (:bottom insets) 50)}} + [react/view {:style {:justify-content :center}} [react/touchable-opacity {:on-press on-close - :style {:background-color colors/black-transparent-86 - :padding-horizontal 24 - :padding-vertical 11 - :border-radius 44}} - [quo/text {:style {:color colors/white-persist}} - (i18n/label :t/close)]] - [footer-options props]]])]) + :style {:padding-vertical 11 + :border-radius 44} + :accessibility-label :close-button} + [react/view {:style {:background-color colors/black-transparent-86 + :border-radius 20 + :width 40 + :height 40 + :justify-content :center + :align-items :center}} + [icons/icon :main-icons/close {:container-style {:width 24 + :height 24} + :color colors/white-persist}]]] + [header-options props]]])]) (defn preview-image [{{:keys [content] :as message} :message visible :visible @@ -73,7 +82,7 @@ :hide-footer-on-zoom false :swipe-to-close-enabled platform/ios? :presentation-style "overFullScreen" - :HeaderComponent #(reagent/as-element [:<>]) ; NOTE: Keep it to remove default header - :FooterComponent #(reagent/as-element [footer {:on-close on-close + :HeaderComponent #(reagent/as-element [header {:on-close on-close :message message}]) + :FooterComponent #(reagent/as-element [:<>]) :visible visible}]) diff --git a/src/status_im/utils/fs.cljs b/src/status_im/utils/fs.cljs index df2a951452..1aa4f4db1e 100644 --- a/src/status_im/utils/fs.cljs +++ b/src/status_im/utils/fs.cljs @@ -14,6 +14,11 @@ (.then on-read) (.catch on-error))) +(defn write-file [path content encoding on-write on-error] + (-> (.writeFile react-native-fs path content encoding) + (.then on-write) + (.catch on-error))) + (defn read-dir [path] (.readDir react-native-fs path)) @@ -25,3 +30,6 @@ (defn file-exists? [path] (.exists react-native-fs path)) + +(defn cache-dir [] + (.-CachesDirectoryPath ^js react-native-fs)) diff --git a/src/status_im/utils/share.cljs b/src/status_im/utils/share.cljs new file mode 100644 index 0000000000..18106a24d9 --- /dev/null +++ b/src/status_im/utils/share.cljs @@ -0,0 +1,8 @@ +(ns status-im.utils.share + (:require ["react-native-share" :default react-native-share])) + +(defn open [options on-success on-error] + (-> ^js react-native-share + (.open (clj->js options)) + (.then on-success) + (.catch on-error))) diff --git a/yarn.lock b/yarn.lock index 2ed8c81c11..8ae1dba141 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6725,6 +6725,11 @@ react-native-shake@^3.3.1: dependencies: invariant "^2.2.x" +react-native-share@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/react-native-share/-/react-native-share-7.0.1.tgz#1deef27afcd8275222ba0efeac337e7cea99bc4b" + integrity sha512-hq7nOirgih/zIF9UU9FuYKZ3NGvasu2c/eJesvyPKYiykTtgQZM+mvDwFk/ogEsGwRtTPJBtj8/6IyIFcGa7lw== + react-native-splash-screen@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45"