[#11046] Add local contact names

Signed-off-by: andrey <motor4ik@gmail.com>
This commit is contained in:
andrey 2020-08-20 16:26:40 +02:00
parent fea916590a
commit 4304a5dd97
No known key found for this signature in database
GPG Key ID: 89B67245FD2F0272
23 changed files with 375 additions and 205 deletions

View File

@ -12,7 +12,8 @@
[status-im.navigation :as navigation]
[status-im.utils.fx :as fx]
[status-im.waku.core :as waku]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[clojure.string :as string]))
(fx/defn load-contacts
{:events [::contacts-loaded]}
@ -59,7 +60,9 @@
[{:keys [db]} contacts]
{:db (update db :contacts/contacts
#(reduce (fn [acc {:keys [public-key] :as contact}]
(update acc public-key merge contact))
(-> acc
(update public-key merge contact)
(assoc-in [public-key :nickname] (:nickname contact))))
%
contacts))})
@ -81,12 +84,15 @@
(fx/defn add-contact
"Add a contact and set pending to false"
[{:keys [db] :as cofx} public-key]
[{:keys [db] :as cofx} public-key nickname]
(when (not= (get-in db [:multiaccount :public-key]) public-key)
(let [contact (-> (get-in db [:contacts/contacts public-key]
(build-contact cofx public-key))
(update :system-tags
(fnil #(conj % :contact/added) #{})))]
(let [contact (cond-> (get-in db [:contacts/contacts public-key]
(build-contact cofx public-key))
nickname
(assoc :nickname nickname)
:else
(update :system-tags
(fnil #(conj % :contact/added) #{})))]
(fx/merge cofx
{:db (dissoc db :contacts/new-identity)}
(upsert-contact contact)
@ -179,3 +185,13 @@
:ens-verified true})}
(upsert-contact {:public-key public-key})))
(fx/defn update-nickname
{:events [:contacts/update-nickname]}
[{:keys [db] :as cofx} public-key nickname]
(fx/merge cofx
{:db (if (string/blank? nickname)
(update-in db [:contacts/contacts public-key] dissoc :nickname)
(assoc-in db [:contacts/contacts public-key :nickname] nickname))}
(upsert-contact {:public-key public-key})
(navigation/navigate-back)))

View File

@ -3,7 +3,8 @@
[clojure.string :as clojure.string]
[status-im.ethereum.core :as ethereum]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]))
[status-im.utils.identicon :as identicon]
[status-im.multiaccounts.core :as multiaccounts]))
(defn public-key->new-contact [public-key]
(let [alias (gfycat/generate-gfy public-key)]
@ -135,7 +136,8 @@
(assoc :pending? (pending? contact)
:blocked? (blocked? contact)
:active? (active? contact)
:added? (contains? system-tags :contact/added))))
:added? (contains? system-tags :contact/added))
(multiaccounts/contact-with-names)))
(defn enrich-contacts
[contacts]

View File

@ -32,18 +32,18 @@
admins
contacts
current-multiaccount)
[{:name "generated"
:identicon "generated"
:alias "generated"
:admin? true
:public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"
:system-tags #{}}
{:alias "User A"
:photo-path "photo2"
[{:name "generated"
:identicon "generated"
:alias "generated"
:admin? true
:public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"
:system-tags #{}}
{:alias "User A"
:photo-path "photo2"
:public-key "0x048a2f8b80c60f89a91b4c1316e56f75b087f446e7b8701ceca06a40142d8efe1f5aa36bd0fee9e248060a8d5207b43ae98bef4617c18c71e66f920f324869c09f"}
{:last-updated 0
:name "User B"
:photo-path "photo1"
:last-online 0
:public-key "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f"
:system-tags #{}}]))))))
{:last-updated 0
:name "User B"
:photo-path "photo1"
:last-online 0
:public-key "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f"
:system-tags #{}}]))))))

View File

@ -27,7 +27,8 @@
:ensVerificationRetries :ens-verification-retries
:lastENSClockValue :last-ens-clock-value
:systemTags :system-tags
:lastUpdated :last-updated})))
:lastUpdated :last-updated
:localNickname :nickname})))
(defn ->rpc [contact]
(-> contact
@ -41,7 +42,8 @@
:photo-path :photoPath
:tribute-to-talk :tributeToTalk
:system-tags :systemTags
:last-updated :lastUpdated})))
:last-updated :lastUpdated
:nickname :localNickname})))
(fx/defn fetch-contacts-rpc
[cofx on-success]

View File

@ -816,7 +816,7 @@
:contact.ui/add-to-contact-pressed
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx [_ public-key]]
(contact/add-contact cofx public-key)))
(contact/add-contact cofx public-key nil)))
(handlers/register-handler-fx
:contact.ui/block-contact-confirmed
@ -842,11 +842,11 @@
(handlers/register-handler-fx
:contact.ui/contact-code-submitted
[(re-frame/inject-cofx :random-id-generator)]
(fn [{{:contacts/keys [new-identity]} :db :as cofx} [_ new-contact?]]
(fn [{{:contacts/keys [new-identity]} :db :as cofx} [_ new-contact? nickname]]
(let [{:keys [public-key ens-name]} new-identity]
(fx/merge cofx
#(if new-contact?
(contact/add-contact % public-key)
(contact/add-contact % public-key nickname)
(chat/start-chat % public-key))
#(when new-contact?
(navigation/navigate-back %))

View File

@ -8,7 +8,40 @@
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]
[status-im.utils.theme :as utils.theme]
[status-im.theme.core :as theme]))
[status-im.theme.core :as theme]
[status-im.utils.utils :as utils]
[clojure.string :as string]))
(defn contact-names
"Returns map of all existing names for contact"
[{:keys [name preferred-name alias public-key ens-verified nickname]}]
(let [ens-name (or preferred-name
name)]
(cond-> {:nickname nickname
:three-words-name (or alias (gfycat/generate-gfy public-key))}
;; Preferred name is our own otherwise we make sure it's verified
(or preferred-name (and ens-verified name))
(assoc :ens-name (str "@" (or (stateofus/username ens-name) ens-name))))))
(defn contact-two-names
"Returns vector of two names in next order nickname, ens name, three word name, public key"
[{:keys [names public-key] :as contact} public-key?]
(let [{:keys [nickname ens-name three-words-name]} (or names (contact-names contact))
short-public-key (when public-key? (utils/get-shortened-address public-key))]
(cond (not (string/blank? nickname))
[nickname (or ens-name three-words-name short-public-key)]
(not (string/blank? ens-name))
[ens-name (or three-words-name short-public-key)]
(not (string/blank? three-words-name))
[three-words-name short-public-key]
:else
(when public-key?
[short-public-key short-public-key]))))
(defn contact-with-names
"Returns contact with :names map "
[contact]
(assoc contact :names (contact-names contact)))
(defn displayed-name
"Use preferred name, name or alias in that order"

View File

@ -2,7 +2,8 @@
(:require [reagent.core :as reagent]
[status-im.ui.components.react :as react]
[status-im.react-native.resources :as resources]
[status-im.ui.components.colors :as colors]))
[status-im.ui.components.colors :as colors]
[re-frame.core :as re-frame]))
(def cnt (reagent/atom 0))
(defonce cnt-prev (reagent/atom 0))
@ -14,6 +15,7 @@
(defn reload []
(reset! warning? false)
(reset! label "reloading UI")
(re-frame/clear-subscription-cache!)
(swap! cnt inc))
(defn build-competed []

View File

@ -1543,16 +1543,17 @@
:<- [:contacts/contacts]
:<- [:contacts/current-contact-identity]
(fn [[contacts identity]]
(or (contacts identity)
(or (get contacts identity)
(-> identity
contact.db/public-key->new-contact
contact.db/enrich-contact))))
(re-frame/reg-sub
:contacts/contact-by-identity
:<- [::contacts]
:<- [:contacts/contacts]
(fn [contacts [_ identity]]
(get contacts identity)))
(or (get contacts identity)
(multiaccounts/contact-with-names {:public-key identity}))))
(re-frame/reg-sub
:contacts/contact-added?
@ -1562,27 +1563,23 @@
(contact.db/added? contact)))
(re-frame/reg-sub
:contacts/raw-contact-name-by-identity
:contacts/contact-two-names-by-identity
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])])
(fn [[db-contact] _]
(if (and (:ens-verified db-contact) (seq (:name db-contact)))
(str "@" (:name db-contact))
(:alias db-contact))))
[(re-frame/subscribe [:contacts/contact-by-identity identity])
(re-frame/subscribe [:multiaccount])])
(fn [[contact current-multiaccount] [_ identity]]
(let [me? (= (:public-key current-multiaccount) identity)]
(if me?
[(or (:preferred-name current-multiaccount)
(gfycat/generate-gfy identity))]
(multiaccounts/contact-two-names contact false)))))
(re-frame/reg-sub
:contacts/contact-name-by-identity
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/raw-contact-name-by-identity identity])
(re-frame/subscribe [:multiaccount])])
(fn [[contact-name current-multiaccount] [_ identity]]
(let [me? (= (:public-key current-multiaccount) identity)]
(if me?
(or (:preferred-name current-multiaccount)
(gfycat/generate-gfy identity))
(or (stateofus/username contact-name)
contact-name
(gfycat/generate-gfy identity))))))
[(re-frame/subscribe [:contacts/contact-two-names-by-identity identity])])
(fn [[names] _]
(first names)))
(re-frame/reg-sub
:messages/quote-info
@ -1612,8 +1609,7 @@
:<- [::query-current-chat-contacts remove]
(fn [contacts]
(->> contacts
(filter contact.db/added?)
(sort-by (comp clojure.string/lower-case multiaccounts/displayed-name)))))
(filter contact.db/added?))))
(re-frame/reg-sub
:contacts/current-chat-contacts
@ -1764,16 +1760,19 @@
(string/lower-case (or alias
(get-in contacts [chat-id :alias])
(gfycat/generate-gfy chat-id)))
"")]
"")
nickname (get-in contacts [chat-id :nickname])]
(or
(string/includes? (string/lower-case (str name)) search-filter)
(string/includes? (string/lower-case alias) search-filter)
(when nickname
(string/includes? (string/lower-case nickname) search-filter))
(and
(get-in contacts [chat-id :ens-verified])
(string/includes? (string/lower-case
(str (get-in contacts [chat-id :name])))
search-filter)))))
(re-frame/reg-sub
:search/filtered-chats
:<- [:chats/active-chats]

View File

@ -1,8 +0,0 @@
(ns status-im.ui.components.contact.contact
(:require [status-im.ethereum.stateofus :as stateofus]
[status-im.utils.gfycat.core :as gfycat]))
(defn format-name [{:keys [ens-verified name public-key]}]
(if ens-verified
(str "@" (or (stateofus/username name) name))
(gfycat/generate-gfy public-key)))

View File

@ -93,7 +93,7 @@
(if-not validation-result
(if new-contact?
(fx/merge cofx
(contact/add-contact chat-key)
(contact/add-contact chat-key nil)
(navigation/navigate-to-cofx :contacts-list {}))
(chat/start-chat cofx chat-key))
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)

View File

@ -13,17 +13,20 @@
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.add-new.new-chat.styles :as styles]
[status-im.utils.debounce :as debounce]
[status-im.utils.utils :as utils])
[status-im.utils.utils :as utils]
[reagent.core :as reagent])
(:require-macros [status-im.utils.views :as views]))
(defn- render-row [row _ _]
[quo/list-item
{:title (multiaccounts/displayed-name row)
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo row)]
:chevron true
:on-press #(re-frame/dispatch [:chat.ui/start-chat
(:public-key row)])}])
(let [[first-name second-name] (multiaccounts/contact-two-names row false)]
[quo/list-item
{:title first-name
:subtitle second-name
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo row)]
:chevron true
:on-press #(re-frame/dispatch [:chat.ui/start-chat
(:public-key row)])}]))
(defn- icon-wrapper [color icon]
[react/view
@ -36,7 +39,7 @@
icon])
(defn- input-icon
[state new-contact?]
[state new-contact? entered-nickname]
(let [icon (if new-contact? :main-icons/add :main-icons/arrow-right)]
(case state
:searching
@ -45,7 +48,7 @@
:valid
[react/touchable-highlight
{:on-press #(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted new-contact?] 3000)}
{:on-press #(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted new-contact? entered-nickname] 3000)}
[icon-wrapper colors/blue
[vector-icons/icon icon {:color colors/white-persist}]]]
@ -83,7 +86,7 @@
(debounce/debounce-and-dispatch [:new-chat/set-new-identity %] 600))
:on-submit-editing
#(when (= state :valid)
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted false] 3000))
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted false nil] 3000))
:placeholder (i18n/label :t/enter-contact-code)
:show-cancel false
:accessibility-label :enter-contact-code-input
@ -91,7 +94,7 @@
:return-key-type :go}]]
[react/view {:justify-content :center
:align-items :center}
[input-icon state false]]]
[input-icon state false nil]]]
[react/view {:min-height 30 :justify-content :flex-end}
[quo/text {:style styles/message
:size :small
@ -118,8 +121,20 @@
:enableEmptySections true
:keyboardShouldPersistTaps :always}]]))
(defn- nickname-input [entered-nickname]
[quo/text-input
{:on-change-text #(reset! entered-nickname %)
:auto-capitalize :none
:max-length 32
:auto-focus false
:accessibility-label :nickname-input
:placeholder (i18n/label :t/add-nickname)
:return-key-type :done
:auto-correct false}])
(views/defview new-contact []
(views/letsubs [{:keys [state ens-name public-key error]} [:contacts/new-identity]]
(views/letsubs [{:keys [state ens-name public-key error]} [:contacts/new-identity]
entered-nickname (reagent/atom "")]
[react/view {:style {:flex 1}}
[topbar/topbar
{:title (i18n/label :t/new-contact)
@ -142,7 +157,7 @@
(debounce/debounce-and-dispatch [:new-chat/set-new-identity %] 600))
:on-submit-editing
#(when (= state :valid)
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted true] 3000))
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted true @entered-nickname] 3000))
:placeholder (i18n/label :t/enter-contact-code)
:show-cancel false
:accessibility-label :enter-contact-code-input
@ -150,12 +165,23 @@
:return-key-type :go}]]
[react/view {:justify-content :center
:align-items :center}
[input-icon state true]]]
[react/view {:min-height 30 :justify-content :flex-end}
[react/text {:style styles/message}
[input-icon state true @entered-nickname]]]
[react/view {:min-height 30 :justify-content :flex-end :margin-bottom 16}
[quo/text {:style styles/message
:size :small
:align :center
:color :secondary}
(cond (= state :error)
(get-validation-label error)
(= state :valid)
(str (when ens-name (str ens-name " • "))
(utils/get-shortened-address public-key))
:else "")]]]))
:else "")]]
[react/text {:style {:margin-horizontal 16 :color colors/gray}}
(i18n/label :t/nickname-description)]
[react/view {:padding 16}
[nickname-input entered-nickname]
[react/text {:style {:align-self :flex-end :margin-top 16
:color colors/gray}}
(str (count @entered-nickname) " / 32")]]]))

View File

@ -175,13 +175,13 @@
(= outgoing-status :not-sent))
[message-not-sent-text chat-id message-id]))
(defview message-author-name [from alias modal]
(letsubs [contact-name [:contacts/raw-contact-name-by-identity from]]
(chat.utils/format-author (or contact-name alias) modal)))
(defview message-author-name [from modal]
(letsubs [contact-with-names [:contacts/contact-by-identity from]]
(chat.utils/format-author contact-with-names modal)))
(defn message-content-wrapper
"Author, userpic and delivery wrapper"
[{:keys [alias first-in-group? display-photo? identicon display-username?
[{:keys [first-in-group? display-photo? identicon display-username?
from outgoing]
:as message} content {:keys [modal close-modal]}]
[react/view {:style (style/message-wrapper message)
@ -200,7 +200,7 @@
[react/touchable-opacity {:style style/message-author-touchable
:on-press #(do (when modal (close-modal))
(re-frame/dispatch [:chat.ui/show-profile from]))}
[message-author-name from alias modal]])
[message-author-name from modal]])
;;MESSAGE CONTENT
[react/view
content]]]

View File

@ -17,7 +17,11 @@
(i18n/label-pluralize cnt :t/members-active))))]])
(defn one-to-one-name [from]
@(re-frame.core/subscribe [:contacts/contact-name-by-identity from]))
(let [[first-name _] @(re-frame.core/subscribe [:contacts/contact-two-names-by-identity from])]
[react/text {:style st/chat-name-text
:number-of-lines 1
:accessibility-label :chat-name-text}
first-name]))
(defn contact-indicator [contact-id]
(let [added? @(re-frame/subscribe [:contacts/contact-added? contact-id])]
@ -39,12 +43,12 @@
[react/view {:margin-right 10}
[chat-icon.screen/chat-icon-view-toolbar chat-id group-chat chat-name color]]
[react/view {:style st/chat-name-view}
[react/text {:style st/chat-name-text
:number-of-lines 1
:accessibility-label :chat-name-text}
(if group-chat
chat-name
[one-to-one-name chat-id])]
(if group-chat
[react/text {:style st/chat-name-text
:number-of-lines 1
:accessibility-label :chat-name-text}
chat-name]
[one-to-one-name chat-id])
(when-not group-chat
[contact-indicator chat-id])
(when group-chat

View File

@ -2,26 +2,31 @@
(:require [status-im.ethereum.stateofus :as stateofus]
[status-im.i18n :as i18n]
[status-im.ui.components.react :as react]
[status-im.ui.components.colors :as colors]))
[status-im.ui.components.colors :as colors]
[status-im.multiaccounts.core :as multiaccounts]))
(def ^:private reply-symbol "↪ ")
(defn format-author
([contact-name] (format-author contact-name false))
([contact-name modal]
(if (= (aget contact-name 0) "@")
(let [trimmed-name (subs contact-name 0 81)]
[react/text {:number-of-lines 2
:style {:color (if modal colors/white-persist colors/blue)
:font-size 13
:line-height 18
:font-weight "500"}}
(or (stateofus/username trimmed-name) trimmed-name)])
[react/text {:style {:color (if modal colors/white-persist colors/gray)
:font-size 12
:line-height 18
:font-weight "400"}}
contact-name])))
([contact] (format-author contact false))
([{:keys [names] :as contact} modal]
(let [{:keys [nickname ens-name]} names
[first-name second-name] (multiaccounts/contact-two-names contact false)]
(if (or nickname ens-name)
[react/nested-text {:number-of-lines 2
:style {:color (if modal colors/white-persist colors/blue)
:font-size 13
:line-height 18
:font-weight "500"}}
(subs first-name 0 81)
(when nickname
[{:style {:color colors/gray :font-weight "400"}}
(str " " (subs second-name 0 81))])]
[react/text {:style {:color (if modal colors/white-persist colors/gray)
:font-size 12
:line-height 18
:font-weight "400"}}
first-name]))))
(defn format-reply-author [from username current-public-key style]
(let [contact-name (str reply-symbol username)]

View File

@ -73,7 +73,8 @@
:default-chat-icon-text style/intro-header-icon-text
:size 120}]]
;; Chat title section
[react/text {:style (style/intro-header-chat-name)} (if group-chat chat-name contact-name)]
[react/text {:style (style/intro-header-chat-name)}
(if group-chat chat-name contact-name)]
;; Description section
(if group-chat
[chat.group/group-chat-description-container {:chat-id chat-id
@ -89,9 +90,9 @@
contact-name)])])
(defn chat-intro-one-to-one [{:keys [chat-id] :as opts}]
(let [contact-name @(re-frame/subscribe
[:contacts/contact-name-by-identity chat-id])]
(chat-intro (assoc opts :contact-name contact-name))))
(let [contact-names @(re-frame/subscribe
[:contacts/contact-two-names-by-identity chat-id])]
(chat-intro (assoc opts :contact-name (first contact-names)))))
(defn chat-intro-header-container
[{:keys [group-chat

View File

@ -12,12 +12,14 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn contacts-list-item [{:keys [public-key] :as contact}]
[quo/list-item
{:title (multiaccounts/displayed-name contact)
:icon [chat-icon.screen/contact-icon-contacts-tab
(multiaccounts/displayed-photo contact)]
:chevron true
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}])
(let [[first-name second-name] (multiaccounts/contact-two-names contact true)]
[quo/list-item
{:title first-name
:subtitle second-name
:icon [chat-icon.screen/contact-icon-contacts-tab
(multiaccounts/displayed-photo contact)]
:chevron true
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}]))
(defn add-new-contact []
[quo/list-item

View File

@ -628,7 +628,10 @@
(views/defview my-name []
(views/letsubs [contact-name [:multiaccount/preferred-name]]
(when-not (string/blank? contact-name)
(chat.utils/format-author (str "@" contact-name)))))
(chat.utils/format-author {:names {:ens-name
(str "@"
(or (stateofus/username contact-name)
contact-name))}}))))
(views/defview registered [names {:keys [preferred-name] :as account} _ registrations]
[react/view {:style {:flex 1}}

View File

@ -6,7 +6,6 @@
[status-im.constants :as constants]
[status-im.i18n :as i18n]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.contact.contact :as contact]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.keyboard-avoid-presentation
:as
@ -23,10 +22,12 @@
(:require-macros [status-im.utils.views :as views]))
(defn- render-contact [row]
[quo/list-item
{:title (contact/format-name row)
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo row)]}])
(let [[first-name second-name] (multiaccounts/contact-two-names row false)]
[quo/list-item
{:title first-name
:subtitle second-name
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo row)]}]))
(defn- on-toggle [allow-new-users? checked? public-key]
(cond
@ -52,9 +53,11 @@
(defn- toggle-item []
(fn [allow-new-users? subs-name {:keys [public-key] :as contact} on-toggle]
(let [contact-selected? @(re-frame/subscribe [subs-name public-key])]
(let [contact-selected? @(re-frame/subscribe [subs-name public-key])
[first-name second-name] (multiaccounts/contact-two-names contact true)]
[quo/list-item
{:title (contact/format-name contact)
{:title first-name
:subtitle second-name
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo contact)]
:on-press #(on-toggle allow-new-users? contact-selected? public-key)
@ -83,10 +86,12 @@
(defn filter-contacts [filter-text contacts]
(let [lower-filter-text (string/lower-case (str filter-text))
filter-fn (fn [{:keys [name alias]}]
filter-fn (fn [{:keys [name alias nickname]}]
(or
(string/includes? (string/lower-case (str name)) lower-filter-text)
(string/includes? (string/lower-case (str alias)) lower-filter-text)))]
(string/includes? (string/lower-case (str alias)) lower-filter-text)
(when nickname
(string/includes? (string/lower-case (str nickname)) lower-filter-text))))]
(if filter-text
(filter filter-fn contacts)
contacts)))

View File

@ -163,7 +163,7 @@
;; This looks a bit odd, but I would like only to subscribe
;; if it's a one-to-one. If wrapped in a component styling
;; won't be applied correctly.
@(re-frame/subscribe [:contacts/contact-name-by-identity chat-id]))]]
(first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))]]
[message-timestamp (if (pos? (:whisper-timestamp last-message))
(:whisper-timestamp last-message)
timestamp)]]

View File

@ -9,8 +9,13 @@
[status-im.ui.components.react :as react]
[status-im.ui.screens.profile.components.sheets :as sheets]
[status-im.ui.screens.profile.contact.styles :as styles]
[status-im.utils.gfycat.core :as gfy]
[status-im.utils.utils :as utils])
[status-im.utils.utils :as utils]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
[reagent.core :as reagent]
[clojure.string :as string])
(:require-macros [status-im.utils.views :as views]))
(defn actions
@ -47,26 +52,47 @@
; :content-height 150}
; contact])
(defn render-detail [{:keys [public-key names name] :as detail}]
[quo/list-item
{:title (:three-words-name names)
:subtitle [quo/text {:monospace true
:color :secondary}
(utils/get-shortened-address public-key)]
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo detail)]
:accessibility-label :profile-public-key
:on-press #(re-frame/dispatch [:show-popover (merge {:view :share-chat-key
:address public-key}
(when (and (:ens-name names) name)
{:ens-name name}))])
:accessory [icons/icon :main-icons/share styles/contact-profile-detail-share-icon]}])
(defn profile-details [{:keys [alias public-key ens-name] :as contact}]
(defn profile-details [contact]
(when contact
[react/view
[quo/list-header
[quo/text {:accessibility-label :profile-details
:color :inherit}
(i18n/label :t/profile-details)]]
[quo/list-item
{:title (or alias ens-name)
:subtitle [quo/text {:monospace true
:color :secondary}
(utils/get-shortened-address public-key)]
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo contact)]
:accessibility-label :profile-public-key
:on-press #(re-frame/dispatch [:show-popover {:view :share-chat-key
:address public-key
:ens-name ens-name}])
:accessory [icons/icon :main-icons/share styles/contact-profile-detail-share-icon]}]]))
[render-detail contact]]))
(defn render-chat-settings [{:keys [names]}]
[quo/list-item
{:title (i18n/label :t/nickname)
:size :small
:accessibility-label :profile-nickname-item
:accessory :text
:accessory-text (or (:nickname names) (i18n/label :t/none))
:on-press #(re-frame/dispatch [:navigate-to :nickname])
:chevron true}])
(defn chat-settings [contact]
[react/view
[quo/list-header
[quo/text {:accessibility-label :chat-settings
:color :inherit}
(i18n/label :t/chat-settings)]]
[render-chat-settings contact]])
;; TODO: List item
(defn block-contact-action [{:keys [blocked? public-key]}]
@ -84,10 +110,56 @@
(i18n/label :t/unblock-contact)
(i18n/label :t/block-contact))]])
(defn save-nickname [public-key nickname]
(re-frame/dispatch [:contacts/update-nickname public-key nickname]))
(defn valid-nickname? [nickname]
(not (string/blank? nickname)))
(defn- nickname-input [nickname entered-nickname public-key]
[quo/text-input
{:on-change-text #(reset! entered-nickname %)
:on-submit-editing #(when (valid-nickname? @entered-nickname)
(save-nickname public-key @entered-nickname))
:auto-capitalize :none
:auto-focus false
:max-length 32
:accessibility-label :nickname-input
:default-value nickname
:placeholder (i18n/label :t/nickname)
:return-key-type :done
:auto-correct false}])
(defn nickname-view [public-key {:keys [nickname ens-name three-words-name]}]
(let [entered-nickname (reagent/atom nickname)]
(fn []
[kb-presentation/keyboard-avoiding-view {:style {:flex 1}}
[topbar/topbar {:title (i18n/label :t/nickname)
:subtitle (or ens-name three-words-name)
:modal? true}]
[react/view {:flex 1 :padding 16}
[react/text {:style {:color colors/gray :margin-bottom 16}}
(i18n/label :t/nickname-description)]
[nickname-input nickname entered-nickname public-key]
[react/text {:style {:align-self :flex-end :margin-top 16
:color colors/gray}}
(str (count @entered-nickname) " / 32")]]
[toolbar/toolbar {:show-border? true
:center
[quo/button
{:type :secondary
:on-press #(save-nickname public-key @entered-nickname)}
(i18n/label :t/done)]}]])))
(views/defview nickname []
(views/letsubs [{:keys [public-key names]} [:contacts/current-contact]]
[nickname-view public-key names]))
(views/defview profile []
(views/letsubs [{:keys [ens-verified name public-key]
(views/letsubs [{:keys [public-key name ens-verified]
:as contact} [:contacts/current-contact]]
(let [on-share #(re-frame/dispatch [:show-popover (merge
(let [[first-name second-name] (multiaccounts/contact-two-names contact true)
on-share #(re-frame/dispatch [:show-popover (merge
{:view :share-chat-key
:address public-key}
(when (and ens-verified name)
@ -104,13 +176,11 @@
:accessibility-label :back-button
:on-press #(re-frame/dispatch [:navigate-back])}]
:extended-header (profile-header/extended-header
{:on-press on-share
:title (multiaccounts/displayed-name contact)
:photo (multiaccounts/displayed-photo contact)
{:on-press on-share
:title first-name
:photo (multiaccounts/displayed-photo contact)
:monospace (not ens-verified)
:subtitle (if (and ens-verified public-key)
(gfy/generate-gfy public-key)
public-key)})}
:subtitle second-name})}
[react/view {:padding-top 12}
(for [{:keys [label subtext accessibility-label icon action disabled?]} (actions contact)]
@ -124,7 +194,6 @@
:disabled disabled?
:on-press action}]))]
[react/view styles/contact-profile-details-container
[profile-details (cond-> contact
(and ens-verified name)
(assoc :ens-name name))]]
[profile-details contact]
[chat-settings contact]]
[block-contact-action contact]]]))))

View File

@ -5,7 +5,6 @@
[status-im.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.contact.contact :as contact]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.profile-header.view :as profile-header]
[status-im.ui.components.react :as react]
@ -16,56 +15,59 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn member-sheet [chat-id member us-admin?]
[react/view
[quo/list-item
{:theme :accent
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo member)]
:title (contact/format-name member)
:subtitle (i18n/label :t/view-profile)
:accessibility-label :view-chat-details-button
:chevron true
:on-press #(chat.sheets/hide-sheet-and-dispatch
[:chat.ui/show-profile
(:public-key member)])}]
(when (and us-admin?
(not (:admin? member)))
(let [[first-name _] (multiaccounts/contact-two-names member false)]
[react/view
[quo/list-item
{:theme :accent
:title (i18n/label :t/make-admin)
:accessibility-label :make-admin
:icon :main-icons/make-admin
:on-press #(chat.sheets/hide-sheet-and-dispatch [:group-chats.ui/make-admin-pressed chat-id (:public-key member)])}])
(when-not (:admin? member)
[quo/list-item
{:theme :accent
:title (i18n/label :t/remove-from-chat)
:accessibility-label :remove-from-chat
:icon :main-icons/remove-contact
:on-press #(chat.sheets/hide-sheet-and-dispatch [:group-chats.ui/remove-member-pressed chat-id (:public-key member)])}])])
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo member)]
:title first-name
:subtitle (i18n/label :t/view-profile)
:accessibility-label :view-chat-details-button
:chevron true
:on-press #(chat.sheets/hide-sheet-and-dispatch
[:chat.ui/show-profile
(:public-key member)])}]
(when (and us-admin?
(not (:admin? member)))
[quo/list-item
{:theme :accent
:title (i18n/label :t/make-admin)
:accessibility-label :make-admin
:icon :main-icons/make-admin
:on-press #(chat.sheets/hide-sheet-and-dispatch [:group-chats.ui/make-admin-pressed chat-id (:public-key member)])}])
(when-not (:admin? member)
[quo/list-item
{:theme :accent
:title (i18n/label :t/remove-from-chat)
:accessibility-label :remove-from-chat
:icon :main-icons/remove-contact
:on-press #(chat.sheets/hide-sheet-and-dispatch [:group-chats.ui/remove-member-pressed chat-id (:public-key member)])}])]))
(defn render-member [chat-id {:keys [public-key] :as member} admin? current-user-identity]
[quo/list-item
(merge
{:title (contact/format-name member)
:accessibility-label :member-item
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo member)]
:on-press (when (not= public-key current-user-identity)
#(re-frame/dispatch [:chat.ui/show-profile public-key]))}
(when (:admin? member)
{:accessory :text
:accessory-text (i18n/label :t/group-chat-admin)})
(when (and admin?
(not (:admin? member))
(not= public-key current-user-identity))
{:accessory [quo/button {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[member-sheet chat-id member admin?])}])
:type :icon
:theme :icon
:accessibility-label :menu-option}
:main-icons/more]}))])
(let [[first-name second-name] (multiaccounts/contact-two-names member false)]
[quo/list-item
(merge
{:title first-name
:subtitle second-name
:accessibility-label :member-item
:icon [chat-icon/contact-icon-contacts-tab
(multiaccounts/displayed-photo member)]
:on-press (when (not= public-key current-user-identity)
#(re-frame/dispatch [:chat.ui/show-profile public-key]))}
(when (:admin? member)
{:accessory :text
:accessory-text (i18n/label :t/group-chat-admin)})
(when (and admin?
(not (:admin? member))
(not= public-key current-user-identity))
{:accessory [quo/button {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[member-sheet chat-id member admin?])}])
:type :icon
:theme :icon
:accessibility-label :menu-option}
:main-icons/more]}))]))
(defview chat-group-members-view [chat-id admin? current-user-identity]
(letsubs [members [:contacts/current-chat-contacts]]

View File

@ -23,7 +23,8 @@
[quo.previews.main :as quo.preview]
[status-im.utils.config :as config]
[status-im.ui.screens.chat.image.preview.views :as image-preview]
[status-im.ui.screens.notifications-settings.views :as notifications-settings]))
[status-im.ui.screens.notifications-settings.views :as notifications-settings]
[status-im.ui.screens.profile.contact.views :as contact]))
(defonce main-stack (navigation/create-stack))
(defonce bottom-tabs (navigation/create-bottom-tabs))
@ -82,6 +83,10 @@
:transition :presentation-ios
:insets {:bottom true}
:component new-public-chat/new-public-chat}
{:name :nickname
:transition :presentation-ios
:insets {:bottom true}
:component contact/nickname}
{:name :edit-group-chat-name
:transition :presentation-ios
:insets {:bottom true}

View File

@ -770,7 +770,6 @@
"new-contract": "New Contract",
"new-group": "New group",
"new-group-chat": "New group chat",
"add-members": "Add members",
"new-network": "New network",
"new-pin-description": "Enter new 6-digit passcode",
"new-public-group-chat": "Join public chat",
@ -1228,5 +1227,8 @@
"audio": "Audio",
"update-to-see-image": "Update to latest version to see a nice image here!",
"update-to-listen-audio": "Update to latest version to listen to an audio message here!",
"update-to-see-sticker": "Update to latest version to see a nice sticker here!"
"update-to-see-sticker": "Update to latest version to see a nice sticker here!",
"nickname": "Nickname",
"add-nickname": "Add a nickname (optional)",
"nickname-description": "Nicknames help you identify others in Status.\nOnly you can see the nicknames youve added"
}