diff --git a/src/quo/components/drawers/action_drawers/style.cljs b/src/quo/components/drawers/action_drawers/style.cljs index d6c90f8f9f..12df92530f 100644 --- a/src/quo/components/drawers/action_drawers/style.cljs +++ b/src/quo/components/drawers/action_drawers/style.cljs @@ -3,9 +3,11 @@ [quo.foundations.colors :as colors])) (defn divider - [theme] + [theme blur?] {:border-top-width 1 - :border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-90 theme) + :border-top-color (if blur? + colors/white-opa-5 + (colors/theme-colors colors/neutral-10 colors/neutral-90 theme)) :margin-top 8 :margin-bottom 7 :align-items :center diff --git a/src/quo/components/drawers/action_drawers/view.cljs b/src/quo/components/drawers/action_drawers/view.cljs index 0b27585c5d..51ead43ebc 100644 --- a/src/quo/components/drawers/action_drawers/view.cljs +++ b/src/quo/components/drawers/action_drawers/view.cljs @@ -14,9 +14,9 @@ (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))) (defn- divider - [theme] + [theme blur?] [rn/view - {:style (style/divider theme) + {:style (style/divider theme blur?) :accessible true :accessibility-label :divider}]) @@ -45,7 +45,7 @@ blur?]}] [:<> (when add-divider? - [divider theme]) + [divider theme blur?]) [maybe-pressable disabled? {:accessibility-label accessibility-label :style (style/container {:sub-label sub-label diff --git a/src/status_im/contexts/onboarding/select_photo/method_menu/view.cljs b/src/status_im/common/profile_picture_picker/view.cljs similarity index 84% rename from src/status_im/contexts/onboarding/select_photo/method_menu/view.cljs rename to src/status_im/common/profile_picture_picker/view.cljs index 3fe028b4dd..aa8c58011a 100644 --- a/src/status_im/contexts/onboarding/select_photo/method_menu/view.cljs +++ b/src/status_im/common/profile_picture_picker/view.cljs @@ -1,4 +1,4 @@ -(ns status-im.contexts.onboarding.select-photo.method-menu.view +(ns status-im.common.profile-picture-picker.view (:require ["react-native-image-crop-picker" :default image-picker] [quo.core :as quo] @@ -59,7 +59,7 @@ crop-opts)) (defn view - [update-profile-pic-callback] + [{:keys [update-profile-pic-callback has-picture?]}] [quo/action-drawer [[{:icon :i/camera :accessibility-label :take-photo-button @@ -86,5 +86,15 @@ :on-allowed (fn [] (pick-pic update-profile-pic-callback)) :on-denied (fn [] (log/info - "user has denied permissions to select picture"))}))}]]]) + "user has denied permissions to select picture"))}))} + (when has-picture? + {:accessibility-label :remove-profile-picture + :add-divider? true + :danger? true + :blur? true + :icon :i/delete + :label (i18n/label :t/profile-pic-remove) + :on-press (fn [] + (rf/dispatch [:hide-bottom-sheet]) + (update-profile-pic-callback nil))})]]]) diff --git a/src/status_im/contexts/onboarding/create_profile/view.cljs b/src/status_im/contexts/onboarding/create_profile/view.cljs index 97ffa57cb0..1a6fff4da3 100644 --- a/src/status_im/contexts/onboarding/create_profile/view.cljs +++ b/src/status_im/contexts/onboarding/create_profile/view.cljs @@ -10,10 +10,10 @@ [react-native.platform :as platform] [react-native.safe-area :as safe-area] [reagent.core :as reagent] + [status-im.common.profile-picture-picker.view :as profile-picture-picker] [status-im.common.validation.profile :as profile-validator] [status-im.constants :as c] [status-im.contexts.onboarding.create-profile.style :as style] - [status-im.contexts.onboarding.select-photo.method-menu.view :as method-menu] [utils.i18n :as i18n] [utils.re-frame :as rf] [utils.responsiveness :as responsiveness])) @@ -144,7 +144,9 @@ (rf/dispatch [:show-bottom-sheet {:content (fn [] - [method-menu/view on-change-profile-pic]) + [profile-picture-picker/view + {:update-profile-pic-callback on-change-profile-pic + :has-picture? false}]) :shell? true}])) :image-picker-props {:profile-picture @profile-pic :full-name (if (seq @full-name) diff --git a/src/status_im/contexts/profile/edit/header/events.cljs b/src/status_im/contexts/profile/edit/header/events.cljs new file mode 100644 index 0000000000..64382db432 --- /dev/null +++ b/src/status_im/contexts/profile/edit/header/events.cljs @@ -0,0 +1,52 @@ +(ns status-im.contexts.profile.edit.header.events + (:require [clojure.string :as string] + [status-im.common.profile-picture-picker.view :as profile-picture-picker] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(rf/reg-event-fx :profile/update-local-picture + (fn [{:keys [db]} [images]] + {:db (if images + (assoc-in db [:profile/profile :images] images) + (update db :profile/profile dissoc :images))})) + +(rf/reg-event-fx :profile/edit-profile-picture-success + (fn [_ [images]] + {:fx [[:dispatch [:profile/update-local-picture (reverse images)]] + [:dispatch + [:toasts/upsert + {:type :positive + :theme :dark + :text (i18n/label :t/profile-picture-added)}]]]})) + +(defn edit-profile-picture + [{:keys [db]} [picture crop-width crop-height]] + (let [key-uid (get-in db [:profile/profile :key-uid]) + crop-width (or crop-width profile-picture-picker/crop-size) + crop-height (or crop-height profile-picture-picker/crop-size) + path (string/replace-first picture #"file://" "")] + {:fx [[:json-rpc/call + [{:method "multiaccounts_storeIdentityImage" + :params [key-uid path 0 0 crop-width crop-height] + :on-success [:profile/edit-profile-picture-success]}]]]})) + +(rf/reg-event-fx :profile/edit-picture edit-profile-picture) + +(rf/reg-event-fx :profile/delete-profile-picture-success + (fn [_] + {:fx [[:dispatch [:profile/update-local-picture nil]] + [:dispatch + [:toasts/upsert + {:type :positive + :theme :dark + :text (i18n/label :t/profile-picture-removed)}]]]})) + +(defn delete-profile-picture + [{:keys [db]}] + (let [key-uid (get-in db [:profile/profile :key-uid])] + {:fx [[:json-rpc/call + [{:method "multiaccounts_deleteIdentityImage" + :params [key-uid] + :on-success [:profile/delete-profile-picture-success]}]]]})) + +(rf/reg-event-fx :profile/delete-picture delete-profile-picture) diff --git a/src/status_im/contexts/profile/edit/header/events_test.cljs b/src/status_im/contexts/profile/edit/header/events_test.cljs new file mode 100644 index 0000000000..b81b1997f3 --- /dev/null +++ b/src/status_im/contexts/profile/edit/header/events_test.cljs @@ -0,0 +1,27 @@ +(ns status-im.contexts.profile.edit.header.events-test + (:require [cljs.test :refer [deftest is]] + matcher-combinators.test + [status-im.common.profile-picture-picker.view :as profile-picture-picker] + [status-im.contexts.profile.edit.header.events :as sut])) + +(deftest edit-picture-test + (let [picture "new-picture" + key-uid "key-uid" + cofx {:db {:profile/profile {:key-uid key-uid}}} + expected {:fx [[:json-rpc/call + [{:method "multiaccounts_storeIdentityImage" + :params [key-uid picture 0 0 profile-picture-picker/crop-size + profile-picture-picker/crop-size] + :on-success [:profile/edit-profile-picture-success]}]]]}] + (is (match? expected + (sut/edit-profile-picture cofx [picture]))))) + +(deftest delete-picture-test + (let [key-uid "key-uid" + cofx {:db {:profile/profile {:key-uid key-uid}}} + expected {:fx [[:json-rpc/call + [{:method "multiaccounts_deleteIdentityImage" + :params [key-uid] + :on-success [:profile/delete-profile-picture-success]}]]]}] + (is (match? expected + (sut/delete-profile-picture cofx))))) diff --git a/src/status_im/contexts/profile/edit/header/view.cljs b/src/status_im/contexts/profile/edit/header/view.cljs index 0f7143eb16..f647e08931 100644 --- a/src/status_im/contexts/profile/edit/header/view.cljs +++ b/src/status_im/contexts/profile/edit/header/view.cljs @@ -1,7 +1,7 @@ (ns status-im.contexts.profile.edit.header.view (:require [quo.core :as quo] [react-native.core :as rn] - [status-im.common.not-implemented :as not-implemented] + [status-im.common.profile-picture-picker.view :as profile-picture-picker] [status-im.contexts.profile.edit.style :as style] [status-im.contexts.profile.utils :as profile.utils] [utils.i18n :as i18n] @@ -9,22 +9,37 @@ (defn view [] - (let [profile (rf/sub [:profile/profile-with-image]) - full-name (profile.utils/displayed-name profile) - profile-picture (profile.utils/photo profile)] + (let [profile (rf/sub [:profile/profile-with-image]) + customization-color (rf/sub [:profile/customization-color]) + full-name (profile.utils/displayed-name profile) + profile-picture (profile.utils/photo profile) + has-picture? (rf/sub [:profile/has-picture]) + on-change-profile-pic (fn [picture] + (if picture + (rf/dispatch [:profile/edit-picture picture]) + (rf/dispatch [:profile/delete-picture])))] [rn/view {:key :edit-profile :style style/screen-container} [quo/text-combinations {:title (i18n/label :t/edit-profile)}] [rn/view style/avatar-wrapper [quo/user-avatar - {:full-name full-name - :profile-picture profile-picture - :status-indicator? false - :ring? true - :size :big}] + {:full-name full-name + :profile-picture profile-picture + :customization-color customization-color + :status-indicator? false + :ring? true + :size :big}] [quo/button - {:on-press not-implemented/alert + {:on-press (fn [] + (rf/dispatch + [:show-bottom-sheet + {:content (fn [] + [profile-picture-picker/view + {:update-profile-pic-callback on-change-profile-pic + :has-picture? has-picture?}]) + :theme :dark + :shell? true}])) :container-style style/camera-button :icon-only? true :type :grey diff --git a/src/status_im/contexts/profile/edit/name/events.cljs b/src/status_im/contexts/profile/edit/name/events.cljs index 3e1feda2f2..f1e4258a16 100644 --- a/src/status_im/contexts/profile/edit/name/events.cljs +++ b/src/status_im/contexts/profile/edit/name/events.cljs @@ -2,17 +2,21 @@ (:require [utils.i18n :as i18n] [utils.re-frame :as rf])) +(rf/reg-event-fx :profile/edit-profile-name-success + (fn [_] + {:fx [[:dispatch [:navigate-back]] + [:dispatch + [:toasts/upsert + {:type :positive + :theme :dark + :text (i18n/label :t/name-updated)}]]]})) + (defn edit-profile-name [{:keys [db]} [name]] {:db (assoc-in db [:profile/profile :display-name] name) :fx [[:json-rpc/call [{:method "wakuext_setDisplayName" :params [name] - :on-success (fn [] - (rf/dispatch [:navigate-back]) - (rf/dispatch [:toasts/upsert - {:type :positive - :theme :dark - :text (i18n/label :t/name-updated)}]))}]]]}) + :on-success [:profile/edit-profile-name-success]}]]]}) (rf/reg-event-fx :profile/edit-name edit-profile-name) diff --git a/src/status_im/contexts/profile/edit/name/events_test.cljs b/src/status_im/contexts/profile/edit/name/events_test.cljs index efba9bd8f9..121cdd94cf 100644 --- a/src/status_im/contexts/profile/edit/name/events_test.cljs +++ b/src/status_im/contexts/profile/edit/name/events_test.cljs @@ -10,6 +10,6 @@ :fx [[:json-rpc/call [{:method "wakuext_setDisplayName" :params [name] - :on-success fn?}]]]}] + :on-success [:profile/edit-profile-name-success]}]]]}] (is (match? expected (sut/edit-profile-name cofx [new-name]))))) diff --git a/src/status_im/contexts/profile/events.cljs b/src/status_im/contexts/profile/events.cljs index 61dafe24a9..2b36dd728e 100644 --- a/src/status_im/contexts/profile/events.cljs +++ b/src/status_im/contexts/profile/events.cljs @@ -3,6 +3,7 @@ [legacy.status-im.data-store.settings :as data-store.settings] [native-module.core :as native-module] [re-frame.core :as re-frame] + [status-im.contexts.profile.edit.header.events] [status-im.contexts.profile.edit.name.events] [status-im.contexts.profile.login.events :as profile.login] [status-im.contexts.profile.rpc :as profile.rpc] diff --git a/src/status_im/integration_test/profile_test.cljs b/src/status_im/integration_test/profile_test.cljs index 645c12ab8b..6e2b1b8830 100644 --- a/src/status_im/integration_test/profile_test.cljs +++ b/src/status_im/integration_test/profile_test.cljs @@ -2,6 +2,8 @@ (:require [cljs.test :refer [deftest is]] [day8.re-frame.test :as rf-test] + [legacy.status-im.multiaccounts.logout.core :as logout] + [legacy.status-im.utils.test :as utils.test] [status-im.contexts.profile.utils :as profile.utils] [test-helpers.integration :as h] [utils.re-frame :as rf])) @@ -19,4 +21,38 @@ [:toasts/upsert] (let [profile (rf/sub [:profile/profile]) display-name (profile.utils/displayed-name profile)] - (is (= new-name display-name)))))))))) + (is (= new-name display-name))) + (h/logout) + (rf-test/wait-for [::logout/logout-method])))))))) + +(deftest edit-profile-picture-test + (h/log-headline :edit-profile-picture-test) + (let [mock-image "resources/images/mock2/monkey.png" + absolute-path (.resolve utils.test/path mock-image)] + (rf-test/run-test-async + (h/with-app-initialized + (h/with-account + (rf/dispatch [:profile/edit-picture absolute-path 80 80]) + (rf-test/wait-for + [:profile/update-local-picture] + (rf-test/wait-for + [:toasts/upsert] + (let [profile (rf/sub [:profile/profile])] + (is (not (nil? (:images profile))))) + (h/logout) + (rf-test/wait-for [::logout/logout-method])))))))) + +(deftest delete-profile-picture-test + (h/log-headline :delete-profile-picture-test) + (rf-test/run-test-async + (h/with-app-initialized + (h/with-account + (rf/dispatch [:profile/delete-picture]) + (rf-test/wait-for + [:profile/update-local-picture] + (rf-test/wait-for + [:toasts/upsert] + (let [profile (rf/sub [:profile/profile])] + (is (nil? (:image profile)))) + (h/logout) + (rf-test/wait-for [::logout/logout-method]))))))) diff --git a/status-go-version.json b/status-go-version.json index a2a14486a0..40acc054b4 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -3,7 +3,7 @@ "_comment": "Instead use: scripts/update-status-go.sh ", "owner": "status-im", "repo": "status-go", - "version": "v0.172.10", - "commit-sha1": "69948a7024df8c4537fc4986b39aded22e89179b", - "src-sha256": "0xg32k3f4yy7gwqzh60qdgrgi2zvm8s1w7sisqmcn5vw90jya70w" + "version": "v0.172.11", + "commit-sha1": "9879b1ea7701c40d9f9cdbe67251242452b8d2e3", + "src-sha256": "147yx2dgjdalxpryq558qlmdl2aaa1vfpdyblzdyj3gd5291yck3" } diff --git a/translations/en.json b/translations/en.json index e8d5f106ca..7492694711 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1183,6 +1183,8 @@ "profile-details": "Profile details", "profile-name": "Profile name", "profile-name-is-too-long": "Profile name is too long", + "profile-picture-added": "Profile picture added", + "profile-picture-removed": "Profile picture removed", "public-chat": "Public chat", "public-chats": "Public chats", "public-group-status": "Public",