diff --git a/resources/images/icons/tiny_edit@2x.png b/resources/images/icons/tiny_edit@2x.png new file mode 100644 index 0000000000..8b30392bf9 Binary files /dev/null and b/resources/images/icons/tiny_edit@2x.png differ diff --git a/resources/images/icons/tiny_edit@3x.png b/resources/images/icons/tiny_edit@3x.png new file mode 100644 index 0000000000..ffb8c6d2fc Binary files /dev/null and b/resources/images/icons/tiny_edit@3x.png differ diff --git a/src/status_im/chat/models/mentions.cljs b/src/status_im/chat/models/mentions.cljs index 8603c01120..032efbbda1 100644 --- a/src/status_im/chat/models/mentions.cljs +++ b/src/status_im/chat/models/mentions.cljs @@ -196,7 +196,7 @@ group-contacts)) :else users) - {:keys [name preferred-name public-key photo-path]} + {:keys [name preferred-name public-key]} (:multiaccount db)] (reduce (fn [acc [key {:keys [alias name identicon]}]] @@ -210,7 +210,6 @@ public-key {:alias name :name (or preferred-name name) - :identicon photo-path :public-key public-key}) contacts))) diff --git a/src/status_im/contact/core.cljs b/src/status_im/contact/core.cljs index 6e3a927038..44cd1e7c4f 100644 --- a/src/status_im/contact/core.cljs +++ b/src/status_im/contact/core.cljs @@ -4,8 +4,6 @@ [status-im.data-store.contacts :as contacts-store] [status-im.ethereum.json-rpc :as json-rpc] [status-im.mailserver.core :as mailserver] - [status-im.multiaccounts.model :as multiaccounts.model] - [status-im.multiaccounts.update.core :as multiaccounts.update] [status-im.transport.filters.core :as transport.filters] [status-im.tribute-to-talk.db :as tribute-to-talk] [status-im.tribute-to-talk.whitelist :as whitelist] @@ -44,17 +42,11 @@ (defn- own-info [db] - (let [{:keys [name preferred-name photo-path address]} (:multiaccount db)] + (let [{:keys [name preferred-name identicon address]} (:multiaccount db)] {:name (or preferred-name name) - :profile-image photo-path + :profile-image identicon :address address})) -(fx/defn handle-update-from-contact-request [{:keys [db] :as cofx} {:keys [last-updated photo-path]}] - (when (> last-updated (get-in db [:multiaccount :last-updated])) - (fx/merge cofx - (multiaccounts.update/multiaccount-update :last-updated last-updated {:dont-sync? true}) - (multiaccounts.update/multiaccount-update :photo-path photo-path {:dont-sync? true})))) - (fx/defn ensure-contacts [{:keys [db]} contacts] {:db (update db :contacts/contacts @@ -126,37 +118,6 @@ {:db (dissoc db :contacts/new-identity)} (upsert-contact contact))))) -(fx/defn handle-contact-update - [{{:contacts/keys [contacts] :as db} :db :as cofx} - public-key - timestamp - {:keys [name profile-image address] :as m}] - ;; We need to convert to timestamp ms as before we were using now in ms to - ;; set last updated - ;; Using whisper timestamp mostly works but breaks in a few scenarios: - ;; 2 updates sent in the same second - ;; when using multi-device & clocks are out of sync - ;; Using logical clocks is probably the correct way to handle it, but an overkill - ;; for now - (let [timestamp-ms (* timestamp 1000) - prev-last-updated (get-in db [:contacts/contacts public-key :last-updated]) - current-public-key (multiaccounts.model/current-public-key cofx)] - (when (and (not= current-public-key public-key) - (< prev-last-updated timestamp-ms)) - (let [contact (get contacts public-key) - - ;; Backward compatibility with <= 0.9.21, as they don't send - ;; address in contact updates - contact-props - (cond-> {:public-key public-key - :photo-path profile-image - :name name - :last-updated timestamp-ms - :system-tags (conj (get contact :system-tags #{}) - :contact/request-received)} - address (assoc :address address))] - (upsert-contact cofx contact-props))))) - (fx/defn initialize-contacts [cofx] (contacts-store/fetch-contacts-rpc cofx #(re-frame/dispatch [::contacts-loaded %]))) diff --git a/src/status_im/contact/core_test.cljs b/src/status_im/contact/core_test.cljs index 8848cbf651..aa9f47e57e 100644 --- a/src/status_im/contact/core_test.cljs +++ b/src/status_im/contact/core_test.cljs @@ -1,98 +1,2 @@ -(ns status-im.contact.core-test - (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.contact.core :as model] - [status-im.ethereum.json-rpc :as json-rpc])) +(ns status-im.contact.core-test) -(def public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917") - -(deftest handle-contact-update-test - (with-redefs [json-rpc/call (constantly nil)] - (testing "the contact is not in contacts" - (let [actual (model/handle-contact-update - {:db {}} - public-key - 1 - {:name "name" - :profile-image "image"}) - contact (get-in actual [:db :contacts/contacts public-key])] - (testing "it adds a new contact" - (is (= {:public-key public-key - :photo-path "image" - :name "name" - :last-updated 1000 - :system-tags #{:contact/request-received}} - contact))))) - (testing "the contact is already in contacts" - (testing "timestamp is greater than last-updated" - (let [actual (model/handle-contact-update - {:db {:contacts/contacts - {public-key {:public-key public-key - :photo-path "old-image" - :name "old-name" - :last-updated 0 - :system-tags #{:contact/added}}}}} - public-key - 1 - {:name "new-name" - :profile-image "new-image"}) - contact (get-in actual [:db :contacts/contacts public-key])] - (testing "it updates the contact and adds contact/request-received to system tags" - (is (= {:public-key public-key - :photo-path "new-image" - :name "new-name" - :last-updated 1000 - - :system-tags #{:contact/added :contact/request-received}} - contact))))) - (testing "timestamp is equal to last-updated" - (let [actual (model/handle-contact-update - {:db {:contacts/contacts - {public-key {:public-key public-key - :photo-path "old-image" - :name "old-name" - :last-updated 1000 - :system-tags #{:contact/added}}}}} - public-key - 1 - {:name "new-name" - :profile-image "new-image"})] - (testing "it does nothing" - (is (nil? actual))))) - (testing "timestamp is less than last-updated" - (let [actual (model/handle-contact-update - {:db {:contacts/contacts - {public-key {:public-key public-key - :photo-path "old-image" - :name "old-name" - :last-updated 1000 - :system-tags #{:contact/added :contact/request-received}}}}} - public-key - 0 - {:name "new-name" - :profile-image "new-image"})] - (testing "it does nothing" - (is (nil? actual)))))) - (testing "backward compatibility" - (let [actual (model/handle-contact-update - {:db {:contacts/contacts - {public-key {:public-key public-key - :photo-path "old-image" - - :name "old-name" - :last-updated 0 - :system-tags #{:contact/added}}}}} - public-key - 1 - {:name "new-name" - :profile-image "new-image"}) - contact (get-in actual [:db :contacts/contacts public-key])] - (testing "it updates the contact" - (is (= {:public-key public-key - :photo-path "new-image" - :name "new-name" - - :last-updated 1000 - :system-tags #{:contact/added :contact/request-received}} contact))))) - (testing "the message is coming from us" - (testing "it does not update contacts" - (is (nil? (model/handle-contact-update {:db {:multiaccount {:public-key "me"}}} "me" 1 {}))))))) diff --git a/src/status_im/contact/db.cljs b/src/status_im/contact/db.cljs index b799aca954..28a886e68c 100644 --- a/src/status_im/contact/db.cljs +++ b/src/status_im/contact/db.cljs @@ -20,8 +20,8 @@ (get contacts public-key (public-key->new-contact public-key)))) -(defn- contact-by-address [[_ contact] address] - (when (ethereum/address= (:address contact) address) +(defn- contact-by-address [[addr contact] address] + (when (ethereum/address= addr address) contact)) (defn find-contact-by-address [contacts address] @@ -54,7 +54,7 @@ [members admins contacts {:keys [public-key] :as current-account}] (let [current-contact (some-> current-account - (select-keys [:name :preferred-name :public-key :photo-path]) + (select-keys [:name :preferred-name :public-key :identicon]) (clojure.set/rename-keys {:name :alias :preferred-name :name})) all-contacts (cond-> contacts diff --git a/src/status_im/contact/db_test.cljs b/src/status_im/contact/db_test.cljs index 298b12c940..8088e86b91 100644 --- a/src/status_im/contact/db_test.cljs +++ b/src/status_im/contact/db_test.cljs @@ -13,21 +13,21 @@ "0x048a2f8b80c60f89a91b4c1316e56f75b087f446e7b8701ceca06a40142d8efe1f5aa36bd0fee9e248060a8d5207b43ae98bef4617c18c71e66f920f324869c09f"} admins #{"0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"} - contacts {"0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f" - {:last-updated 0, - :name "User B", - :photo-path "photo1", - :last-online 0, - :public-key - "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f" - :system-tags #{}}} - current-multiaccount {:last-updated 0, - :signed-up? true, - :sharing-usage-data? false, - :name "User A", - :photo-path "photo2", + contacts {"0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f" + {:last-updated 0, + :name "User B", + :identicon "photo1", + :last-online 0, :public-key - "0x048a2f8b80c60f89a91b4c1316e56f75b087f446e7b8701ceca06a40142d8efe1f5aa36bd0fee9e248060a8d5207b43ae98bef4617c18c71e66f920f324869c09f"}] + "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f" + :system-tags #{}}} + current-multiaccount {:last-updated 0, + :signed-up? true, + :sharing-usage-data? false, + :name "User A", + :identicon "photo2", + :public-key + "0x048a2f8b80c60f89a91b4c1316e56f75b087f446e7b8701ceca06a40142d8efe1f5aa36bd0fee9e248060a8d5207b43ae98bef4617c18c71e66f920f324869c09f"}] (is (= (contact.db/get-all-contacts-in-group-chat chat-contact-ids admins contacts @@ -39,11 +39,11 @@ :public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917" :system-tags #{}} {:alias "User A" - :photo-path "photo2" + :identicon "photo2" :public-key "0x048a2f8b80c60f89a91b4c1316e56f75b087f446e7b8701ceca06a40142d8efe1f5aa36bd0fee9e248060a8d5207b43ae98bef4617c18c71e66f920f324869c09f"} {:last-updated 0 :name "User B" - :photo-path "photo1" + :identicon "photo1" :last-online 0 :public-key "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f" :system-tags #{}}])))))) diff --git a/src/status_im/data_store/contacts.cljs b/src/status_im/data_store/contacts.cljs index 1efaf10606..ecb9068099 100644 --- a/src/status_im/data_store/contacts.cljs +++ b/src/status_im/data_store/contacts.cljs @@ -19,7 +19,6 @@ #{} %)) (clojure.set/rename-keys {:id :public-key - :photoPath :photo-path :tributeToTalk :tribute-to-talk :ensVerifiedAt :ens-verified-at :ensVerified :ens-verified @@ -38,7 +37,6 @@ :ens-verified-at :ensVerifiedAt :last-ens-clock-value :lastENSClockValue :ens-verification-retries :ensVerificationRetries - :photo-path :photoPath :tribute-to-talk :tributeToTalk :system-tags :systemTags :last-updated :lastUpdated diff --git a/src/status_im/data_store/contacts_test.cljs b/src/status_im/data_store/contacts_test.cljs index 3626b3b4f2..9732ad52eb 100644 --- a/src/status_im/data_store/contacts_test.cljs +++ b/src/status_im/data_store/contacts_test.cljs @@ -6,14 +6,14 @@ (let [contact {:public-key "pk" :address "address" :name "name" - :photo-path "photo-path" + :identicon "identicon" :tribute-to-talk "tribute-to-talk" :last-updated 1 :system-tags #{:a :b}} expected-contact {:id "pk" :address "address" :name "name" - :photoPath "photo-path" + :identicon "identicon" :tributeToTalk "\"tribute-to-talk\"" :lastUpdated 1 @@ -28,14 +28,14 @@ (let [contact {:id "pk" :address "address" :name "name" - :photoPath "photo-path" + :identicon "identicon" :tributeToTalk "\"tribute-to-talk\"" :lastUpdated 1 :systemTags [":a" ":b"]} expected-contact {:public-key "pk" :address "address" :name "name" - :photo-path "photo-path" + :identicon "identicon" :tribute-to-talk "tribute-to-talk" :last-updated 1 diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index f5bd110638..9001f1b880 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -111,6 +111,10 @@ "wakuext_getPushNotificationsServers" {} "wakuext_enablePushNotificationsBlockMentions" {} "wakuext_disablePushNotificationsBlockMentions" {} + "multiaccounts_getIdentityImages" {} + "multiaccounts_getIdentityImage" {} + "multiaccounts_storeIdentityImage" {} + "multiaccounts_deleteIdentityImage" {} "status_chats" {} "localnotifications_switchWalletNotifications" {} "localnotifications_notificationPreferences" {} diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 29ed531018..c42c08a265 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -139,14 +139,13 @@ (handlers/register-handler-fx :multiaccounts.login.ui/multiaccount-selected (fn [{:keys [db] :as cofx} [_ key-uid]] - (let [{:keys [photo-path name public-key]} - (get-in db [:multiaccounts/multiaccounts key-uid])] + (let [multiaccount (get-in db [:multiaccounts/multiaccounts key-uid])] (fx/merge cofx {:db (-> db (dissoc :intro-wizard) (update :keycard dissoc :application-info))} - (multiaccounts.login/open-login key-uid photo-path name public-key))))) + (multiaccounts.login/open-login multiaccount))))) (handlers/register-handler-fx :login/filters-initialized diff --git a/src/status_im/init/core.cljs b/src/status_im/init/core.cljs index 03635ee58c..5a67136aa3 100644 --- a/src/status_im/init/core.cljs +++ b/src/status_im/init/core.cljs @@ -27,9 +27,8 @@ [cofx {:keys [logout?]}] (let [{{:multiaccounts/keys [multiaccounts]} :db} cofx] (when (and (seq multiaccounts) (not logout?)) - (let [{:keys [key-uid public-key photo-path name]} - (first (sort-by :timestamp > (vals multiaccounts)))] - (multiaccounts.login/open-login cofx key-uid photo-path name public-key))))) + (let [multiaccount (first (sort-by :timestamp > (vals multiaccounts)))] + (multiaccounts.login/open-login cofx multiaccount))))) (fx/defn initialize-multiaccounts {:events [::initialize-multiaccounts]} diff --git a/src/status_im/keycard/common.cljs b/src/status_im/keycard/common.cljs index 428c149389..bf3b2dd0ce 100644 --- a/src/status_im/keycard/common.cljs +++ b/src/status_im/keycard/common.cljs @@ -311,11 +311,11 @@ [{:keys [db] :as cofx} data] (let [{:keys [key-uid encryption-public-key whisper-private-key] :as account-data} (js->clj data :keywordize-keys true) - {:keys [photo-path name]} (get-in db [:multiaccounts/multiaccounts key-uid]) + {:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid]) key-uid (get-in db [:keycard :application-info :key-uid]) multiaccount-data (types/clj->json {:name name :key-uid key-uid - :photo-path photo-path}) + :identicon identicon}) save-keys? (get-in db [:multiaccounts/login :save-password?])] (fx/merge cofx {:db @@ -328,7 +328,7 @@ (update :multiaccounts/login assoc :password encryption-public-key :key-uid key-uid - :photo-path photo-path + :identicon identicon :name name)) :keycard/get-application-info {:pairing (get-pairing db key-uid)} diff --git a/src/status_im/keycard/login.cljs b/src/status_im/keycard/login.cljs index 7137fcae92..b553a8ab78 100644 --- a/src/status_im/keycard/login.cljs +++ b/src/status_im/keycard/login.cljs @@ -145,13 +145,13 @@ [{:keys [db] :as cofx} key-uid [encryption-public-key whisper-private-key :as creds]] (if (nil? creds) (navigation/navigate-to-cofx cofx :keycard-login-pin nil) - (let [{:keys [photo-path name]} (get-in db [:multiaccounts/multiaccounts key-uid]) - multiaccount-data (types/clj->json {:name name - :key-uid key-uid - :photo-path photo-path}) - account-data {:key-uid key-uid - :encryption-public-key encryption-public-key - :whisper-private-key whisper-private-key}] + (let [{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid]) + multiaccount-data (types/clj->json {:name name + :key-uid key-uid + :identicon identicon}) + account-data {:key-uid key-uid + :encryption-public-key encryption-public-key + :whisper-private-key whisper-private-key}] {:db (-> db (assoc-in [:keycard :pin :status] nil) @@ -162,7 +162,7 @@ (update :multiaccounts/login assoc :password encryption-public-key :key-uid key-uid - :photo-path photo-path + :identicon identicon :name name :save-password? true)) :keycard/login-with-keycard diff --git a/src/status_im/keycard/recovery.cljs b/src/status_im/keycard/recovery.cljs index ba5ce299da..2699d158fc 100644 --- a/src/status_im/keycard/recovery.cljs +++ b/src/status_im/keycard/recovery.cljs @@ -137,7 +137,7 @@ (let [{{:keys [multiaccount secrets flow]} :keycard} db {:keys [address name - photo-path + identicon public-key whisper-public-key wallet-public-key @@ -149,14 +149,14 @@ encryption-public-key instance-uid key-uid - recovered]} multiaccount - {:keys [pairing paired-on]} secrets - {:keys [name photo-path]} + recovered]} multiaccount + {:keys [pairing paired-on]} secrets + {:keys [name identicon]} (if (nil? name) ;; name might have been generated during recovery via passphrase (get-in db [:intro-wizard :derived constants/path-whisper-keyword]) {:name name - :photo-path photo-path})] + :identicon identicon})] ;; if a name is still `nil` we have to generate it before multiaccount's ;; creation otherwise spec validation will fail (if (nil? name) @@ -176,7 +176,7 @@ {:public-key whisper-public-key :address (eip55/address->checksum whisper-address) :name name - :photo-path photo-path} + :identicon identicon} constants/path-default-wallet-keyword {:public-key wallet-public-key :address (eip55/address->checksum wallet-address)}} @@ -264,7 +264,7 @@ {:events [::on-name-and-photo-generated] :interceptors [(re-frame/inject-cofx :random-guid-generator) (re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]} - [{:keys [db] :as cofx} whisper-name photo-path] + [{:keys [db] :as cofx} whisper-name identicon] (fx/merge cofx {:db (update-in db [:keycard :multiaccount] @@ -272,5 +272,5 @@ (assoc multiacc :recovered true :name whisper-name - :photo-path photo-path)))} + :identicon identicon)))} (create-keycard-multiaccount))) diff --git a/src/status_im/keycard/simulated_keycard.cljs b/src/status_im/keycard/simulated_keycard.cljs index 19ff3bcf80..2535d79785 100644 --- a/src/status_im/keycard/simulated_keycard.cljs +++ b/src/status_im/keycard/simulated_keycard.cljs @@ -183,7 +183,7 @@ (let [derived-data-extended (update derived-data constants/path-whisper-keyword - merge {:name name :photo-path photo-path})] + merge {:name name :identicon photo-path})] (reset! derived-acc {:root-key root-data :derived derived-data-extended}))))))))))) diff --git a/src/status_im/multiaccounts/core.cljs b/src/status_im/multiaccounts/core.cljs index 6b21d1ef91..4bb2f3d65f 100644 --- a/src/status_im/multiaccounts/core.cljs +++ b/src/status_im/multiaccounts/core.cljs @@ -2,7 +2,9 @@ (:require [re-frame.core :as re-frame] [status-im.ethereum.stateofus :as stateofus] [status-im.multiaccounts.update.core :as multiaccounts.update] + [status-im.ui.components.bottom-sheet.core :as bottom-sheet] [status-im.native-module.core :as native-module] + [status-im.ethereum.json-rpc :as json-rpc] [status-im.utils.fx :as fx] [status-im.utils.gfycat.core :as gfycat] [status-im.utils.identicon :as identicon] @@ -10,6 +12,7 @@ [status-im.theme.core :as theme] [status-im.utils.utils :as utils] [quo.platform :as platform] + [taoensso.timbre :as log] [clojure.string :as string])) (defn contact-names @@ -54,12 +57,23 @@ (str "@" (or username ens-name))) (or alias (gfycat/generate-gfy public-key))))) +(def photo-quality-thumbnail :thumbnail) +(def photo-quality-large :large) + (defn displayed-photo - "If a photo-path is set use it, otherwise fallback on identicon or generate" - [{:keys [photo-path identicon public-key]}] - (or photo-path - identicon - (identicon/identicon public-key))) + "If a photo, a image or an images array is set use it, otherwise fallback on identicon or generate" + [{:keys [images identicon public-key]}] + (cond + (pos? (count images)) + (:uri (or (photo-quality-thumbnail images) + (photo-quality-large images) + (first images))) + + (not (string/blank? identicon)) + identicon + + :else + (identicon/identicon public-key))) (re-frame/reg-fx ::chaos-mode-changed @@ -145,3 +159,45 @@ (fx/merge cofx {::switch-theme theme} (multiaccounts.update/multiaccount-update :appearance theme {}))) + +(defn clean-path [path] + (if path + (string/replace-first path #"file://" "") + (log/warn "[nativ-module] Empty path was provided"))) + +(fx/defn save-profile-picture + {:events [::save-profile-picture]} + [cofx path ax ay bx by] + (let [key-uid (get-in cofx [:db :multiaccount :key-uid])] + (fx/merge cofx + {::json-rpc/call [{:method "multiaccounts_storeIdentityImage" + :params [key-uid (clean-path path) ax ay bx by] + ;; NOTE: In case of an error we can show a toast error + :on-success #(re-frame/dispatch [::update-local-picture %])}]} + (multiaccounts.update/optimistic :images [{:url path + :type (name photo-quality-large)}]) + (bottom-sheet/hide-bottom-sheet)))) + +(fx/defn delete-profile-picture + {:events [::delete-profile-picture]} + [cofx name] + (let [key-uid (get-in cofx [:db :multiaccount :key-uid])] + (fx/merge cofx + {::json-rpc/call [{:method "multiaccounts_deleteIdentityImage" + :params [key-uid] + ;; NOTE: In case of an error we could fallback to previous image in UI with a toast error + :on-success #(log/info "[multiaccount] Delete profile image" %)}]} + (multiaccounts.update/optimistic :images nil) + (bottom-sheet/hide-bottom-sheet)))) + +(fx/defn get-profile-picture + [cofx] + (let [key-uid (get-in cofx [:db :multiaccount :key-uid])] + {::json-rpc/call [{:method "multiaccounts_getIdentityImages" + :params [key-uid] + :on-success #(re-frame/dispatch [::update-local-picture %])}]})) + +(fx/defn store-profile-picture + {:events [::update-local-picture]} + [cofx pics] + (multiaccounts.update/optimistic cofx :images pics)) diff --git a/src/status_im/multiaccounts/create/core.cljs b/src/status_im/multiaccounts/create/core.cljs index 194ed5194a..73b5e1e77f 100644 --- a/src/status_im/multiaccounts/create/core.cljs +++ b/src/status_im/multiaccounts/create/core.cljs @@ -80,11 +80,11 @@ public-key (get-in derived-data [constants/path-whisper-keyword :public-key])] (status/gfycat-identicon-async public-key - (fn [name photo-path] + (fn [name identicon] (let [derived-whisper (derived-data constants/path-whisper-keyword) derived-data-extended (assoc-in derived-data [constants/path-whisper-keyword] - (merge derived-whisper {:name name :photo-path photo-path}))] + (merge derived-whisper {:name name :identicon identicon}))] (re-frame/dispatch [::store-multiaccount-success key-code derived-data-extended]))))))] {::store-multiaccount [selected-id key-uid hashed-password callback]})) @@ -192,12 +192,12 @@ :wallet true :path constants/path-default-wallet :name (i18n/label :t/ethereum-account)}) - (let [{:keys [public-key address name photo-path]} + (let [{:keys [public-key address name identicon]} (get-in multiaccount [:derived constants/path-whisper-keyword])] {:public-key public-key :address (eip55/address->checksum address) :name name - :photo-path photo-path + :identicon identicon :path constants/path-whisper :chat true})]) @@ -221,10 +221,10 @@ :as multiaccount} password {:keys [save-mnemonic? login?] :or {login? true save-mnemonic? false}}] - (let [[wallet-account {:keys [public-key photo-path name]} :as accounts-data] (prepare-accounts-data multiaccount) + (let [[wallet-account {:keys [public-key identicon name]} :as accounts-data] (prepare-accounts-data multiaccount) multiaccount-data {:name name :address address - :photo-path photo-path + :identicon identicon :key-uid key-uid :keycard-pairing keycard-pairing} keycard-multiaccount? (boolean keycard-pairing) @@ -243,7 +243,7 @@ constants/path-wallet-root-keyword :address]) :name name - :photo-path photo-path + :identicon identicon ;; public key of the chat account :public-key public-key ;; default address for Dapps @@ -269,7 +269,7 @@ db (assoc db :multiaccounts/login {:key-uid key-uid :name name - :photo-path photo-path + :identicon identicon :password password :creating? true :processing true} diff --git a/src/status_im/multiaccounts/login/core.cljs b/src/status_im/multiaccounts/login/core.cljs index c3918dafef..53fdb66419 100644 --- a/src/status_im/multiaccounts/login/core.cljs +++ b/src/status_im/multiaccounts/login/core.cljs @@ -19,7 +19,6 @@ [status-im.ui.screens.mobile-network-settings.events :as mobile-network] [status-im.navigation :as navigation] [status-im.utils.fx :as fx] - [status-im.utils.identicon :as identicon] [status-im.utils.keychain.core :as keychain] [status-im.utils.logging.core :as logging] [status-im.utils.security :as security] @@ -76,7 +75,7 @@ (fx/defn login {:events [:multiaccounts.login.ui/password-input-submitted]} [{:keys [db]}] - (let [{:keys [key-uid password name photo-path]} (:multiaccounts/login db)] + (let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)] {:db (-> db (assoc-in [:multiaccounts/login :processing] true) (dissoc :intro-wizard) @@ -84,7 +83,7 @@ ::login [key-uid (types/clj->json {:name name :key-uid key-uid - :photo-path photo-path}) + :identicon identicon}) (ethereum/sha3 (security/safe-unmask-data password))]})) (fx/defn finish-keycard-setup @@ -227,6 +226,7 @@ (mobile-network/on-network-status-change) (get-group-chat-invitations) (logging/set-log-level (:log-level multiaccount)) + (multiaccounts/get-profile-picture) (multiaccounts/switch-preview-privacy-mode-flag) (link-preview/request-link-preview-whitelist)))) @@ -337,19 +337,12 @@ (navigation/navigate-to-cofx :tabs {:screen :chat-stack :params {:screen :home}}))))) +;; FIXME(Ferossgp): We should not copy keys as we denormalize the database, +;; this create desync between actual accounts and the one on login causing broken state (fx/defn open-login - [{:keys [db] :as cofx} key-uid photo-path name public-key] + [{:keys [db] :as cofx} {:keys [key-uid] :as multiaccount}] (fx/merge cofx - {:db (-> db - (update :multiaccounts/login assoc - :public-key public-key - :key-uid key-uid - :photo-path photo-path - :name name) - (assoc :profile/photo-added? (= (identicon/identicon public-key) photo-path)) - (update :multiaccounts/login dissoc - :error - :password))} + {:db (assoc db :multiaccounts/login multiaccount)} (keychain/get-auth-method key-uid))) (fx/defn open-login-callback diff --git a/src/status_im/multiaccounts/login/data_test.cljs b/src/status_im/multiaccounts/login/data_test.cljs index 504c8dda75..6c1296c6d3 100644 --- a/src/status_im/multiaccounts/login/data_test.cljs +++ b/src/status_im/multiaccounts/login/data_test.cljs @@ -5,14 +5,14 @@ :tags #{} :address "2f88d65f3cb52605a54a833ae118fb1363acccd2" :name "Darkviolet Lightgreen Halcyon" - :photo-path "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX///+M2KwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdPOdBAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5UBARL8TK8AAAAASUVORK5CYII=" + :identicon "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX///+M2KwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdPOdBAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5UBARL8TK8AAAAASUVORK5CYII=" :system-tags #{:contact/added} :last-online 0 :public-key "0x04d6e56a475cd35f512d6ce0bf76c2c2af435c85ff48c2b9bdefd129f620e051a436f50961eae5717b2a750e59c3f5b60647d927da46d0b8b11621640b5678fc24"} {:last-updated 1547271764000 :address "b267ff8336ac10b3a1986c04a70ff91fb03d0b78" :name "rv" - :photo-path "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////VjNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwYzy6AAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAAAAAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQAAAAABAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6IYA4bRtf+EAAAAASUVORK5CYII=" + :identicon "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////VjNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwYzy6AAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAAAAAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQAAAAABAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6IYA4bRtf+EAAAAASUVORK5CYII=" :system-tags #{:contact/added} :last-online 0 :public-key "0x043ae31038ff45a31b096a91d3f8290e079366fbbae76a00fbbd349cd0e5b8d7598965d206772ec4504f68908649a08383cdc51a52cdae5e9ccc744ace4d37020f"}]) @@ -96,7 +96,7 @@ :poa #{}} :preview-privacy? true :fleet :eth.prod - :photo-path "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////YsYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPGFwxAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAAAAAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQAAAAABAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAloYA4a9rBHIAAAAASUVORK5CYII=" + :identicon "data:image/png;base64iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////YsYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPGFwxAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAAAAAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQAAAAABAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAAAAAEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAloYA4a9rBHIAAAAASUVORK5CYII=" :wallet-set-up-passed? false :public-key "0x04173f7cdea0076a7998abb674cc79fe61337c42db77043c01d5b0f3e3ac1e5a45bca0c93bb9f3c3d38b7cc9a7337cd64f9f9b2114fe4bbdfe1ae2633ba14d8c9c" :keycard-key-uid nil diff --git a/src/status_im/multiaccounts/login/flow_test.cljs b/src/status_im/multiaccounts/login/flow_test.cljs index 1f4389b2de..97e08abcf4 100644 --- a/src/status_im/multiaccounts/login/flow_test.cljs +++ b/src/status_im/multiaccounts/login/flow_test.cljs @@ -14,11 +14,11 @@ (let [cofx {:db {:multiaccounts/login {:key-uid "key-uid" :password "password" :name "user" - :photo-path "photo"}}} + :identicon "photo"}}} efx (login.core/login cofx)] (testing "Change multiaccount." (is (= (::login.core/login efx) - ["key-uid" "{\"name\":\"user\",\"key-uid\":\"key-uid\",\"photo-path\":\"photo\"}" (ethereum/sha3 "password")]))) + ["key-uid" "{\"name\":\"user\",\"key-uid\":\"key-uid\",\"identicon\":\"photo\"}" (ethereum/sha3 "password")]))) (testing "start activity indicator" (is (= (get-in efx [:db :multiaccounts/login :processing]) true)))))) diff --git a/src/status_im/multiaccounts/recover/core.cljs b/src/status_im/multiaccounts/recover/core.cljs index 6522662010..4ff2d2f3db 100644 --- a/src/status_im/multiaccounts/recover/core.cljs +++ b/src/status_im/multiaccounts/recover/core.cljs @@ -108,11 +108,11 @@ public-key (get-in derived-data [constants/path-whisper-keyword :public-key])] (status/gfycat-identicon-async public-key - (fn [name photo-path] + (fn [name identicon] (let [derived-data-extended (update derived-data constants/path-whisper-keyword - merge {:name name :photo-path photo-path})] + merge {:name name :identicon identicon})] (re-frame/dispatch [::import-multiaccount-success root-data derived-data-extended])))))))))))) diff --git a/src/status_im/multiaccounts/update/core.cljs b/src/status_im/multiaccounts/update/core.cljs index e8baa1ef88..ee4e61a011 100644 --- a/src/status_im/multiaccounts/update/core.cljs +++ b/src/status_im/multiaccounts/update/core.cljs @@ -5,9 +5,9 @@ (fx/defn send-multiaccount-update [{:keys [db] :as cofx}] (let [multiaccount (:multiaccount db) - {:keys [name preferred-name photo-path address]} multiaccount] + {:keys [name preferred-name address]} multiaccount] {::json-rpc/call [{:method (json-rpc/call-ext-method "sendContactUpdates") - :params [(or preferred-name name) photo-path] + :params [(or preferred-name name) ""] :on-success #(log/debug "sent contact update")}]})) (fx/defn multiaccount-update @@ -30,7 +30,7 @@ :params [setting setting-value] :on-success on-success}]} (when (and (not dont-sync?) - (#{:name :photo-path :prefered-name} setting)) + (#{:name :prefered-name} setting)) (send-multiaccount-update)))))) (fx/defn clean-seed-phrase diff --git a/src/status_im/multiaccounts/update/publisher.cljs b/src/status_im/multiaccounts/update/publisher.cljs deleted file mode 100644 index 4b323bfe47..0000000000 --- a/src/status_im/multiaccounts/update/publisher.cljs +++ /dev/null @@ -1,29 +0,0 @@ -(ns status-im.multiaccounts.update.publisher - (:require [re-frame.core :as re-frame] - [status-im.ethereum.json-rpc :as json-rpc] - [taoensso.timbre :as log])) - -;; Publish updates every 48 hours -(def publish-updates-interval (* 48 60 60 1000)) - -(defn publish-update! [{:keys [db now]}] - (let [peers-count (:peers-count db) - last-updated (get-in - db - [:multiaccount :last-updated])] - (when (and (pos? peers-count) - (pos? last-updated) - (< publish-updates-interval - (- now last-updated))) - (let [multiaccount (:multiaccount db) - {:keys [name preferred-name photo-path]} multiaccount] - - (log/debug "sending contact updates") - (json-rpc/call {:method (json-rpc/call-ext-method "sendContactUpdates") - :params [(or preferred-name name) photo-path] - :on-failure #(do - (log/warn "failed to send contact updates") - (re-frame/dispatch [:multiaccounts.update.callback/failed-to-publish])) - :on-success #(do - (log/debug "sent contact updates") - (re-frame/dispatch [:multiaccounts.update.callback/published]))}))))) diff --git a/src/status_im/pairing/core.cljs b/src/status_im/pairing/core.cljs index ae050407e6..9479fe11ed 100644 --- a/src/status_im/pairing/core.cljs +++ b/src/status_im/pairing/core.cljs @@ -171,9 +171,9 @@ (defn send-installation-messages [{:keys [db]}] (let [multiaccount (:multiaccount db) - {:keys [name preferred-name photo-path]} multiaccount] + {:keys [name preferred-name identicon]} multiaccount] {::json-rpc/call [{:method (json-rpc/call-ext-method "syncDevices") - :params [(or preferred-name name) photo-path] + :params [(or preferred-name name) identicon] :on-success #(log/debug "successfully synced devices")}]})) (defn installation<-rpc [{:keys [metadata id enabled]}] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 167fae1b52..8c692ec254 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -99,7 +99,6 @@ (reg-root-key-sub :my-profile/advanced? :my-profile/advanced?) (reg-root-key-sub :my-profile/editing? :my-profile/editing?) (reg-root-key-sub :my-profile/profile :my-profile/profile) -(reg-root-key-sub :profile/photo-added? :profile/photo-added?) ;;multiaccount (reg-root-key-sub :multiaccounts/multiaccounts :multiaccounts/multiaccounts) @@ -275,9 +274,9 @@ :intro-wizard/recovery-success :<- [:intro-wizard] (fn [wizard-state] - {:pubkey (get-in wizard-state [:derived constants/path-whisper-keyword :public-key]) - :name (get-in wizard-state [:derived constants/path-whisper-keyword :name]) - :photo-path (get-in wizard-state [:derived constants/path-whisper-keyword :photo-path]) + {:pubkey (get-in wizard-state [:derived constants/path-whisper-keyword :public-key]) + :name (get-in wizard-state [:derived constants/path-whisper-keyword :name]) + :identicon (get-in wizard-state [:derived constants/path-whisper-keyword :identicon]) :processing? (:processing? wizard-state)})) (re-frame/reg-sub @@ -477,7 +476,7 @@ (fn [current-account] (some-> current-account - (select-keys [:name :preferred-name :public-key :photo-path]) + (select-keys [:name :preferred-name :public-key :identicon :image :images]) (clojure.set/rename-keys {:name :alias}) (multiaccounts/contact-with-names)))) @@ -811,13 +810,16 @@ (re-frame/reg-sub :chats/photo-path - :<- [:contacts/contacts] + :<- [::contacts] :<- [:multiaccount] - (fn [[contacts multiaccount] [_ id]] - (multiaccounts/displayed-photo (or (get contacts id) - (when (= id (:public-key multiaccount)) - multiaccount) - (contact.db/public-key->new-contact id))))) + (fn [[contacts multiaccount] [_ id identicon]] + (let [contact (or (get contacts id) + (when (= id (:public-key multiaccount) + multiaccount)) + (if identicon + {:identicon identicon} + (contact.db/public-key->new-contact id)))] + (multiaccounts/displayed-photo contact)))) (re-frame/reg-sub :chats/unread-messages-number @@ -935,10 +937,13 @@ :<- [:contacts/contacts] (fn [contacts] (reduce - (fn [acc [key {:keys [alias name identicon public-key nickname] :as contact}]] + (fn [acc [key {:keys [alias name added? blocked? identicon public-key nickname]}]] (if (and alias (not= alias "") - (not (contact.db/blocked? contact))) + (or name + nickname + added?) + (not blocked?)) (let [name (utils/safe-replace name ".stateofus.eth" "")] (assoc acc public-key (mentions/add-searchable-phrases @@ -957,14 +962,13 @@ :<- [:chats/mentionable-contacts] :<- [:contacts/blocked-set] :<- [:multiaccount] - (fn [[{:keys [users]} contacts blocked {:keys [name preferred-name photo-path public-key]}]] + (fn [[{:keys [users]} contacts blocked {:keys [name preferred-name public-key]}]] (apply dissoc (-> users (merge contacts) (assoc public-key (mentions/add-searchable-phrases {:alias name :name (or preferred-name name) - :identicon photo-path :public-key public-key}))) blocked))) @@ -1844,8 +1848,11 @@ (re-frame/reg-sub :contacts/contact-by-address :<- [:contacts/contacts] - (fn [contacts [_ address]] - (contact.db/find-contact-by-address contacts address))) + :<- [:multiaccount/contact] + (fn [[contacts multiaccount] [_ address]] + (if (ethereum/address= address (:public-key multiaccount)) + multiaccount + (contact.db/find-contact-by-address contacts address)))) (re-frame/reg-sub :contacts/contacts-by-address @@ -2416,3 +2423,9 @@ (first (filter #(notifications/preference= % {:service "wallet" :event "transaction" :identifier "all"}) pref)))) + +(re-frame/reg-sub + :profile/has-picture + :<- [:multiaccount] + (fn [multiaccount] + (pos? (count (get multiaccount :images))))) diff --git a/src/status_im/ui/components/chat_icon/screen.cljs b/src/status_im/ui/components/chat_icon/screen.cljs index 7b67bc8083..0032366e8b 100644 --- a/src/status_im/ui/components/chat_icon/screen.cljs +++ b/src/status_im/ui/components/chat_icon/screen.cljs @@ -2,6 +2,7 @@ (:require [clojure.string :as string] [re-frame.core :as re-frame.core] [status-im.multiaccounts.core :as multiaccounts] + [status-im.ui.components.icons.vector-icons :as icons] [status-im.ui.components.chat-icon.styles :as styles] [status-im.ui.components.colors :as colors] [status-im.ui.components.react :as react] @@ -125,11 +126,9 @@ :default-chat-icon (styles/default-chat-icon-profile color size) :default-chat-icon-text (styles/default-chat-icon-text size)} override-styles)] [react/view (:container styles) - (when edit? - [react/view (styles/profile-icon-mask size)]) - (when edit? - [react/view (styles/profile-icon-edit-text-containter size) - [react/i18n-text {:style styles/profile-icon-edit-text :key :edit}]]) (if (and photo-path (seq photo-path)) [photos/photo photo-path styles] - [default-chat-icon name styles])])) + [default-chat-icon name styles]) + (when edit? + [react/view {:style (styles/chat-icon-profile-edit)} + [icons/tiny-icon :tiny-icons/tiny-edit {:color colors/white-persist}]])])) diff --git a/src/status_im/ui/components/chat_icon/styles.cljs b/src/status_im/ui/components/chat_icon/styles.cljs index 2141e5ddfb..c3a3bb8c65 100644 --- a/src/status_im/ui/components/chat_icon/styles.cljs +++ b/src/status_im/ui/components/chat_icon/styles.cljs @@ -121,23 +121,15 @@ {:width 36 :height 36}) -(defn profile-icon-mask [size] - {:height size - :width size +(defn chat-icon-profile-edit [] + {:width 24 + :height 24 + :border-radius 12 + :border-width 1 + :border-color colors/white-persist + :background-color colors/blue + :justify-content :center + :align-items :center :position :absolute - :z-index 1 - :background-color colors/black - :opacity 0.4 - :border-radius 50}) - -(defn profile-icon-edit-text-containter [size] - {:height size - :width size - :position :absolute - :z-index 2 - :align-items :center - :justify-content :center}) - -(def profile-icon-edit-text - {:color colors/white - :background-color :transparent}) + :bottom -2 + :right -2}) diff --git a/src/status_im/ui/components/profile_header/view.cljs b/src/status_im/ui/components/profile_header/view.cljs index 3d68f92c1d..5efaf144dc 100644 --- a/src/status_im/ui/components/profile_header/view.cljs +++ b/src/status_im/ui/components/profile_header/view.cljs @@ -37,23 +37,27 @@ (when-not minimized {:padding-top subtitle-margin}))) -(defn extended-header [{:keys [title photo color subtitle subtitle-icon on-press monospace bottom-separator] - :or {bottom-separator true}}] +(defn extended-header [{:keys [title photo color subtitle subtitle-icon on-edit on-press monospace bottom-separator] + :or {bottom-separator true}}] (fn [{:keys [animation minimized]}] - (let [wrapper (if on-press - [rn/touchable-opacity {:on-press on-press}] - [:<>])] + (let [wrapper (if on-press + [rn/touchable-opacity {:on-press on-press}] + [:<>]) + editable (if (and (not minimized) on-edit) + [rn/touchable-opacity {:on-press on-edit}] + [:<>])] (into wrapper [[animated/view {:pointer-events :box-none} [animated/view {:style (container-style {:animation animation :minimized minimized}) :pointer-events :box-none} - [animated/view {:pointer-events :box-none} - [chat-icon.screen/profile-icon-view - photo title color nil - (if minimized avatar-minimized-size avatar-extended-size) - nil]] + (into editable + [[animated/view {:pointer-events :box-none} + [chat-icon.screen/profile-icon-view + photo title color (and (not minimized) on-edit) + (if minimized avatar-minimized-size avatar-extended-size) + nil]]]) [animated/view {:style (header-text) :pointer-events :box-none} [quo/text {:animated? true diff --git a/src/status_im/ui/components/react.cljs b/src/status_im/ui/components/react.cljs index 5ddd584f30..648df0aca2 100644 --- a/src/status_im/ui/components/react.cljs +++ b/src/status_im/ui/components/react.cljs @@ -194,9 +194,12 @@ (defn show-image-picker ([images-fn] (show-image-picker images-fn nil)) - ([images-fn {:keys [multiple media-type]}] + ([images-fn {:keys [media-type] + :or {media-type "any"} + :as props}] (-> ^js image-picker - (.openPicker (clj->js {:multiple multiple :mediaType (or media-type "any")})) + (.openPicker (clj->js (merge {:mediaType media-type} + props))) (.then images-fn) (.catch show-access-error)))) diff --git a/src/status_im/ui/screens/chat/components/input.cljs b/src/status_im/ui/screens/chat/components/input.cljs index 161dfc1454..761967ba9e 100644 --- a/src/status_im/ui/screens/chat/components/input.cljs +++ b/src/status_im/ui/screens/chat/components/input.cljs @@ -18,7 +18,7 @@ [status-im.chat.models.mentions :as mentions] [status-im.ui.components.list.views :as list] [quo.components.list.item :as list-item] - [status-im.ui.screens.chat.styles.photos :as photo-style] + [status-im.ui.screens.chat.photos :as photos] [reagent.core :as reagent])) (def panel->icons {:extensions :main-icons/commands @@ -199,18 +199,10 @@ input-with-mentions)]])) (defn mention-item - [[_ {:keys [identicon alias name nickname] :as user}] _ _ text-input-ref] + [[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref] (let [ens-name? (not= alias name)] [list-item/list-item - (cond-> {:icon - [rn/view {:style {}} - [rn/image - {:source {:uri identicon} - :style (photo-style/photo-border - photo-style/default-size - nil) - :resize-mode :cover}]] - :icon-container-style {} + (cond-> {:icon [photos/member-photo public-key] :size :small :text-size :small :title diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index 65c71d2b5b..ca188ddd47 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -211,7 +211,8 @@ (defn message-content-wrapper "Author, userpic and delivery wrapper" - [{:keys [first-in-group? display-photo? identicon display-username? + [{:keys [first-in-group? display-photo? display-username? + identicon from outgoing] :as message} content {:keys [modal close-modal]}] [react/view {:style (style/message-wrapper message) @@ -224,7 +225,7 @@ (when first-in-group? [react/touchable-highlight {:on-press #(do (when modal (close-modal)) (re-frame/dispatch [:chat.ui/show-profile-without-adding-contact from]))} - [photos/member-identicon identicon]])]) + [photos/member-photo from identicon]])]) [react/view {:style (style/message-author-wrapper outgoing display-photo?)} (when display-username? [react/touchable-opacity {:style style/message-author-touchable diff --git a/src/status_im/ui/screens/chat/photos.cljs b/src/status_im/ui/screens/chat/photos.cljs index 6a23b2019c..4e2ea16eda 100644 --- a/src/status_im/ui/screens/chat/photos.cljs +++ b/src/status_im/ui/screens/chat/photos.cljs @@ -1,9 +1,10 @@ (ns status-im.ui.screens.chat.photos - (:require [status-im.ui.components.react :as react] + (:require [re-frame.core :as re-frame] + [status-im.ui.components.react :as react] [status-im.ui.screens.chat.styles.photos :as style] [status-im.ui.screens.profile.db :as profile.db] - [status-im.utils.image :as utils.image]) - (:require-macros [status-im.utils.views :refer [defview letsubs]])) + [status-im.multiaccounts.core :as multiaccounts] + [status-im.utils.image :as utils.image])) (defn photo [photo-path {:keys [size accessibility-label]}] (let [identicon? (when photo-path (profile.db/base64-png? photo-path))] @@ -15,11 +16,16 @@ (when identicon? [react/view {:style (style/photo-border size)}])])) -(defview member-photo [from & [identicon size]] - (letsubs [photo-path [:chats/photo-path from]] - (photo (or photo-path identicon) - {:accessibility-label :member-photo - :size (or size style/default-size)}))) +;; We optionally pass identicon for perfomance reason, so it does not have to be calculated for each message +(defn member-photo [pub-key identicon] + (let [path @(re-frame/subscribe [:chats/photo-path pub-key identicon])] + [photo path {:size style/default-size + :accessibility-label :member-photo}])) + +(defn account-photo [account] + (let [path (multiaccounts/displayed-photo account)] + [photo path {:size style/default-size + :accessibility-label :own-account-photo}])) (defn member-identicon [identicon] (let [size style/default-size] @@ -28,4 +34,4 @@ :style (style/photo size) :resize-mode :cover :accessibility-label :member-photo}] - [react/view {:style (style/photo-border size)}]])) \ No newline at end of file + [react/view {:style (style/photo-border size)}]])) diff --git a/src/status_im/ui/screens/intro/views.cljs b/src/status_im/ui/screens/intro/views.cljs index 421c0a8399..415357550e 100644 --- a/src/status_im/ui/screens/intro/views.cljs +++ b/src/status_im/ui/screens/intro/views.cljs @@ -376,7 +376,7 @@ wizard-state)]]])) (defview wizard-recovery-success [] - (letsubs [{:keys [pubkey processing? name photo-path]} [:intro-wizard/recovery-success] + (letsubs [{:keys [pubkey processing? name identicon]} [:intro-wizard/recovery-success] existing-account? [:intro-wizard/recover-existing-account?]] [react/view {:style {:flex 1}} [topbar/topbar @@ -386,7 +386,7 @@ [react/view {:style {:flex 1 :justify-content :space-between}} [top-bar {:step :recovery-success}] - [recovery-success pubkey name photo-path] + [recovery-success pubkey name identicon] [bottom-bar {:step :recovery-success :forward-action :multiaccounts.recover/re-encrypt-pressed :processing? processing? diff --git a/src/status_im/ui/screens/keycard/views.cljs b/src/status_im/ui/screens/keycard/views.cljs index 40ebfbf3c8..cfac84e3ff 100644 --- a/src/status_im/ui/screens/keycard/views.cljs +++ b/src/status_im/ui/screens/keycard/views.cljs @@ -166,8 +166,8 @@ {:should-component-update (fn [_ [_ old-account] [_ new-account]] (and (not (nil? new-account)) - (and (not (:photo-path old-account)) - (nil? (:photo-path new-account))))) + (and (not (:identicon old-account)) + (nil? (:identicon new-account))))) :reagent-render (fn [account small-screen?] diff --git a/src/status_im/ui/screens/multiaccounts/login/views.cljs b/src/status_im/ui/screens/multiaccounts/login/views.cljs index 5d412436c3..699269c9f5 100644 --- a/src/status_im/ui/screens/multiaccounts/login/views.cljs +++ b/src/status_im/ui/screens/multiaccounts/login/views.cljs @@ -24,14 +24,12 @@ (defn multiaccount-login-badge [{:keys [public-key name] :as multiaccount}] [react/view styles/login-badge [photos/photo - ;;TODO this should be done in a subscription (multiaccounts/displayed-photo multiaccount) {:size styles/login-badge-image-size}] [react/view [react/text {:style styles/login-badge-name :ellipsize-mode :middle :numberOfLines 1} - ;;TODO this should be done in a subscription name] [quo/text {:monospace true :align :center diff --git a/src/status_im/ui/screens/multiaccounts/views.cljs b/src/status_im/ui/screens/multiaccounts/views.cljs index a109387d2b..1963a1c681 100644 --- a/src/status_im/ui/screens/multiaccounts/views.cljs +++ b/src/status_im/ui/screens/multiaccounts/views.cljs @@ -2,6 +2,7 @@ (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [re-frame.core :as re-frame] [status-im.ui.screens.chat.photos :as photos] + [status-im.multiaccounts.core :as multiaccounts] [status-im.ui.screens.multiaccounts.styles :as styles] [status-im.ui.components.list.views :as list] [status-im.ui.components.react :as react] @@ -14,10 +15,10 @@ [status-im.react-native.resources :as resources])) (defn multiaccount-view - [{:keys [key-uid photo-path name keycard-pairing]}] + [{:keys [key-uid name keycard-pairing] :as account}] [quo/list-item {:on-press #(re-frame/dispatch [:multiaccounts.login.ui/multiaccount-selected key-uid]) - :icon [photos/photo photo-path {:size styles/multiaccount-image-size}] + :icon [photos/photo (multiaccounts/displayed-photo account) {:size styles/multiaccount-image-size}] :title name :accessory (when keycard-pairing [react/view {:justify-content :center diff --git a/src/status_im/ui/screens/profile/events.cljs b/src/status_im/ui/screens/profile/events.cljs index de9bf3b1ec..a87d7641c5 100644 --- a/src/status_im/ui/screens/profile/events.cljs +++ b/src/status_im/ui/screens/profile/events.cljs @@ -1,48 +1,9 @@ (ns status-im.ui.screens.profile.events (:require [re-frame.core :as re-frame] - [status-im.multiaccounts.model :as multiaccounts.model] [status-im.ui.screens.profile.models :as profile.models] [status-im.ui.components.list-selection :as list-selection] [status-im.utils.handlers :as handlers] - [status-im.utils.identicon :as identicon] - [status-im.utils.universal-links.utils :as universal-links] - [status-im.utils.fx :as fx])) - -(handlers/register-handler-fx - :profile/send-transaction - (fn [cofx [_ chat-id]] - (profile.models/send-transaction chat-id cofx))) - -(handlers/register-handler-fx - :my-profile/update-name - (fn [cofx [_ name]] - (profile.models/update-name name cofx))) - -(handlers/register-handler-fx - :my-profile/remove-current-photo - (fn [{:keys [db] :as cofx}] - (fx/merge cofx - {:db (-> db - (assoc-in [:my-profile/profile :photo-path] - (identicon/identicon (multiaccounts.model/current-public-key cofx))) - (assoc :my-profile/editing? true - :profile/photo-added? false))} - (profile.models/save)))) - -(handlers/register-handler-fx - :my-profile/start-editing-profile - (fn [cofx _] - (profile.models/start-editing cofx))) - -(handlers/register-handler-fx - :my-profile/save-profile - (fn [cofx _] - (profile.models/save cofx))) - -(handlers/register-handler-fx - :group-chat-profile/start-editing - (fn [cofx _] - (profile.models/start-editing-group-chat-profile cofx))) + [status-im.utils.universal-links.utils :as universal-links])) (handlers/register-handler-fx :my-profile/enter-two-random-words diff --git a/src/status_im/ui/screens/profile/models.cljs b/src/status_im/ui/screens/profile/models.cljs index 8d5028727c..b35598d045 100644 --- a/src/status_im/ui/screens/profile/models.cljs +++ b/src/status_im/ui/screens/profile/models.cljs @@ -1,57 +1,11 @@ (ns status-im.ui.screens.profile.models - (:require [clojure.spec.alpha :as spec] - [clojure.string :as clojure.string] + (:require [clojure.string :as clojure.string] [re-frame.core :as re-frame] [status-im.ui.components.react :as react] [status-im.multiaccounts.update.core :as multiaccounts.update] - [status-im.chat.models :as chat-models] [taoensso.timbre :as log] [status-im.utils.fx :as fx])) -(defn send-transaction [chat-id cofx] - ;;TODO start send transaction command flow - (chat-models/start-chat cofx chat-id)) - -(defn- valid-name? [name] - (spec/valid? :profile/name name)) - -(defn update-name [name {:keys [db]}] - {:db (-> db - (assoc-in [:my-profile/profile :valid-name?] (valid-name? name)) - (assoc-in [:my-profile/profile :name] name))}) - -(defn- clean-name [db edit-view] - (let [name (get-in db [edit-view :name])] - (if (valid-name? name) - name - (get-in db [:multiaccount :name])))) - -(fx/defn clear-profile - [{:keys [db]}] - {:db (dissoc db :my-profile/profile :my-profile/default-name :my-profile/editing?)}) - -(defn start-editing [{:keys [db]}] - (let [profile (select-keys (:multiaccount db) [:name :photo-path])] - {:db (assoc db - :my-profile/editing? true - :my-profile/profile profile)})) - -(fx/defn save [{:keys [db now] :as cofx}] - (let [{:keys [photo-path]} (:my-profile/profile db) - cleaned-name (clean-name db :my-profile/profile)] - (fx/merge cofx - (clear-profile) - (multiaccounts.update/multiaccount-update :name cleaned-name {}) - (multiaccounts.update/multiaccount-update :last-updated now {}) - (when photo-path - (multiaccounts.update/multiaccount-update :photo-path photo-path {}))))) - -(defn start-editing-group-chat-profile [{:keys [db]}] - (let [current-chat-name (get-in db [:chats (:current-chat-id db) :name])] - {:db (-> db - (assoc :group-chat-profile/editing? true) - (assoc-in [:group-chat-profile/profile :name] current-chat-name))})) - (defn enter-two-random-words [{:keys [db]}] (let [{:keys [mnemonic]} (:multiaccount db) shuffled-mnemonic (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))] @@ -62,7 +16,7 @@ (defn set-step [step {:keys [db]}] {:db (update db :my-profile/seed assoc :step step :error nil :word nil)}) -(defn finish [{:keys [db] :as cofx}] +(fx/defn finish [{:keys [db] :as cofx}] (fx/merge cofx {:db (update db :my-profile/seed assoc :step :finish :error nil :word nil)} (multiaccounts.update/clean-seed-phrase))) diff --git a/src/status_im/ui/screens/profile/user/edit_picture.cljs b/src/status_im/ui/screens/profile/user/edit_picture.cljs new file mode 100644 index 0000000000..ebbcb13dab --- /dev/null +++ b/src/status_im/ui/screens/profile/user/edit_picture.cljs @@ -0,0 +1,44 @@ +(ns status-im.ui.screens.profile.user.edit-picture + (:require [quo.core :as quo] + [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.utils.config :as config] + [status-im.multiaccounts.core :as multiaccounts] + [status-im.ui.components.react :as react])) + +(def crop-size 1000) +(def crop-opts {:cropping true + :cropperCircleOverlay true + :width crop-size + :height crop-size}) + +(defn pick-pic [] + (react/show-image-picker + #(re-frame/dispatch [::multiaccounts/save-profile-picture (.-path ^js %) 0 0 crop-size crop-size]) + crop-opts)) + +(defn take-pic [] + (react/show-image-picker-camera + #(re-frame/dispatch [::multiaccounts/save-profile-picture (.-path ^js %) 0 0 crop-size crop-size]) + crop-opts)) + +(defn bottom-sheet [has-picture] + (fn [] + [:<> + [quo/list-item {:accessibility-label :take-photo + :theme :accent + :icon :main-icons/camera + :title (i18n/label :t/profile-pic-take) + :on-press take-pic}] + [quo/list-item {:accessibility-label :pick-photo + :icon :main-icons/gallery + :theme :accent + :title (i18n/label :t/profile-pic-pick) + :on-press pick-pic}] + (when (and config/enable-remove-profile-picture? + has-picture) + [quo/list-item {:accessibility-label :remove-photo + :icon :main-icons/delete + :theme :accent + :title (i18n/label :t/profile-pic-remove) + :on-press #(re-frame/dispatch [::multiaccounts/delete-profile-picture nil])}])])) diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index d937fb90ae..28d3aad119 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -16,6 +16,7 @@ [status-im.utils.gfycat.core :as gfy] [status-im.utils.universal-links.utils :as universal-links] [status-im.ui.components.profile-header.view :as profile-header] + [status-im.ui.screens.profile.user.edit-picture :as edit] [status-im.utils.utils :as utils] [status-im.ethereum.stateofus :as stateofus]) (:require-macros [status-im.utils.views :as views])) @@ -167,10 +168,11 @@ (fn [] (let [{:keys [public-key ens-verified preferred-name] :as account} @(re-frame/subscribe [:multiaccount]) - on-share #(re-frame/dispatch [:show-popover - {:view :share-chat-key - :address public-key - :ens-name preferred-name}])] + on-share #(re-frame/dispatch [:show-popover + {:view :share-chat-key + :address public-key + :ens-name preferred-name}]) + has-picture @(re-frame/subscribe [:profile/has-picture])] [react/view {:flex 1} [quo/animated-header {:right-accessories [{:accessibility-label :share-header-button @@ -178,11 +180,13 @@ :on-press on-share}] :use-insets true :extended-header (profile-header/extended-header - {:on-press on-share - :title (multiaccounts/displayed-name account) - :photo (multiaccounts/displayed-photo account) - :monospace (not ens-verified) - :subtitle (if (and ens-verified public-key) - (gfy/generate-gfy public-key) - (utils/get-shortened-address public-key))})} + {:on-press on-share + :on-edit #(re-frame/dispatch [:bottom-sheet/show-sheet + {:content (edit/bottom-sheet has-picture)}]) + :title (multiaccounts/displayed-name account) + :photo (multiaccounts/displayed-photo account) + :monospace (not ens-verified) + :subtitle (if (and ens-verified public-key) + (gfy/generate-gfy public-key) + (utils/get-shortened-address public-key))})} [content]]]))) diff --git a/src/status_im/ui/screens/status/views.cljs b/src/status_im/ui/screens/status/views.cljs index c71fd30103..6205650327 100644 --- a/src/status_im/ui/screens/status/views.cljs +++ b/src/status_im/ui/screens/status/views.cljs @@ -17,7 +17,6 @@ [status-im.ui.screens.chat.photos :as photos] [status-im.ui.components.tabs :as tabs] [status-im.utils.contenthash :as contenthash] - [status-im.multiaccounts.core :as multiaccounts] [status-im.ui.screens.chat.message.reactions :as reactions] [status-im.chat.models.reactions :as models.reactions] [status-im.ui.screens.chat.components.reply :as components.reply] @@ -101,7 +100,7 @@ [message-content-image (:image content) false]]]))) (defn message-item [account] - (fn [{:keys [content-type content from timestamp identicon outgoing] :as message} + (fn [{:keys [content-type content from timestamp outgoing] :as message} {:keys [modal on-long-press close-modal]}] [react/view (merge {:padding-vertical 8 :flex-direction :row @@ -114,8 +113,8 @@ (re-frame/dispatch [:chat.ui/show-profile-without-adding-contact from]))} [react/view {:padding-top 2 :padding-right 8} (if outgoing - [photos/member-identicon (multiaccounts/displayed-photo account)] - [photos/member-identicon identicon])]] + [photos/account-photo account] + [photos/member-photo from])]] [react/view {:flex 1} [react/view {:flex-direction :row :justify-content :space-between} diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index 4b7e345b2c..df9ad7de84 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -55,6 +55,8 @@ (def pow-target (js/parseFloat (get-config :POW_TARGET "0.0001"))) (def pow-time (js/parseInt (get-config :POW_TIME "1"))) (def max-installations 2) +; currently not supported in status-go +(def enable-remove-profile-picture? false) (def verify-transaction-chain-id (js/parseInt (get-config :VERIFY_TRANSACTION_CHAIN_ID "1"))) (def verify-transaction-url (if (= :mainnet (ethereum/chain-id->chain-keyword verify-transaction-chain-id)) diff --git a/status-go-version.json b/status-go-version.json index f627ee17f2..f2f68b36e5 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -2,7 +2,7 @@ "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh ' instead", "owner": "status-im", "repo": "status-go", - "version": "v0.64.8", - "commit-sha1": "50b17308bde0008daf4c8365782575d4f22b1515", - "src-sha256": "140xbx3xlzgcbp3iv98if9gbjslmg94gpzzbwqa303fh6mg460fw" + "version": "v0.65.0", + "commit-sha1": "cdca42b90f7fd5f302a5eb31802b9ae526d566d7", + "src-sha256": "1qpq9y099bfa6x36afbimn2p5inzrsgbb8qzigmchl513mkhp5s1" } diff --git a/translations/en.json b/translations/en.json index 42fa951777..9d5ead875e 100644 --- a/translations/en.json +++ b/translations/en.json @@ -529,6 +529,9 @@ "image-source-gallery": "Select from gallery", "image-source-make-photo": "Capture", "image-source-title": "Edit picture", + "profile-pic-take": "Take photo", + "profile-pic-pick": "Select from gallery", + "profile-pic-remove": "Remove photo", "in-contacts": "In contacts", "incoming": "Incoming", "incoming-transaction": "Incoming transaction",