Online Status Indicator (#12716)
This commit is contained in:
parent
ec319974bd
commit
1034d542db
|
@ -218,4 +218,7 @@
|
|||
(set! pin-background (:pin-background old-colors-mapping-colors)))
|
||||
(reset! theme-type type)))
|
||||
|
||||
|
||||
;; Colors related to Visibility Status
|
||||
(def color-online "#7CDA00")
|
||||
(def color-dnd "#FA6565")
|
||||
(def color-inactive "#939BA1")
|
||||
|
|
|
@ -162,3 +162,9 @@
|
|||
(def ^:const activity-center-notification-type-private-group-chat 2)
|
||||
(def ^:const activity-center-notification-type-mention 3)
|
||||
(def ^:const activity-center-notification-type-reply 4)
|
||||
|
||||
(def ^:const visibility-status-unknown 0)
|
||||
(def ^:const visibility-status-automatic 1)
|
||||
(def ^:const visibility-status-dnd 2)
|
||||
(def ^:const visibility-status-always-online 3)
|
||||
(def ^:const visibility-status-inactive 4)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.data-store.settings
|
||||
(:require
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.ethereum.eip55 :as eip55]))
|
||||
[status-im.ethereum.eip55 :as eip55]
|
||||
[status-im.data-store.visibility-status-updates :as visibility-status-updates]))
|
||||
|
||||
(defn rpc->networks [networks]
|
||||
(reduce (fn [acc {:keys [id] :as network}]
|
||||
|
@ -50,4 +51,5 @@
|
|||
(update :link-previews-enabled-sites set)
|
||||
(update :custom-bootnodes rpc->custom-bootnodes)
|
||||
(update :custom-bootnodes-enabled? rpc->custom-bootnodes)
|
||||
(update :currency keyword)))
|
||||
(update :currency keyword)
|
||||
(visibility-status-updates/<-rpc-settings)))
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
(ns status-im.data-store.visibility-status-updates
|
||||
(:require [clojure.set :as clojure.set]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.utils.fx :as fx]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn <-rpc [visibility-status-update]
|
||||
(clojure.set/rename-keys visibility-status-update {:publicKey :public-key
|
||||
:statusType :status-type}))
|
||||
(defn <-rpc-settings [settings]
|
||||
(-> settings
|
||||
(clojure.set/rename-keys
|
||||
{:current-user-status :current-user-visibility-status})
|
||||
(update :current-user-visibility-status <-rpc)))
|
||||
|
||||
(fx/defn fetch-visibility-status-updates-rpc [_]
|
||||
{::json-rpc/call [{:method "wakuext_statusUpdates"
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch
|
||||
[:visibility-status-updates/visibility-status-updates-loaded
|
||||
(:statusUpdates ^js %)])
|
||||
:on-failure #(log/error
|
||||
"failed to fetch visibility-status-updates" %)}]})
|
|
@ -32,6 +32,7 @@
|
|||
:tooltips {}
|
||||
:dimensions/window (dimensions/window)
|
||||
:registry {}
|
||||
:visibility-status-updates {}
|
||||
:stickers/packs-owned #{}
|
||||
:stickers/packs-pending #{}
|
||||
:keycard {:nfc-enabled? false
|
||||
|
|
|
@ -131,6 +131,8 @@
|
|||
"wakuext_enablePushNotificationsBlockMentions" {}
|
||||
"wakuext_disablePushNotificationsBlockMentions" {}
|
||||
"wakuext_unreadActivityCenterNotificationsCount" {}
|
||||
"wakuext_setUserStatus" {}
|
||||
"wakuext_statusUpdates" {}
|
||||
"multiaccounts_getIdentityImages" {}
|
||||
"multiaccounts_getIdentityImage" {}
|
||||
"multiaccounts_storeIdentityImage" {}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
status-im.wallet.choose-recipient.core
|
||||
status-im.wallet.accounts.core
|
||||
status-im.popover.core
|
||||
status-im.visibility-status-popover.core
|
||||
status-im.visibility-status-updates.core
|
||||
status-im.bottom-sheet.core
|
||||
status-im.add-new.core
|
||||
status-im.search.core
|
||||
|
|
|
@ -64,6 +64,17 @@
|
|||
(str "@" (or username ens-name)))
|
||||
(or alias (gfycat/generate-gfy public-key)))))
|
||||
|
||||
(defn contact-by-identity [contacts identity]
|
||||
(or (get contacts identity)
|
||||
(contact-with-names {:public-key identity})))
|
||||
|
||||
(defn contact-two-names-by-identity [contact current-multiaccount identity]
|
||||
(let [me? (= (:public-key current-multiaccount) identity)]
|
||||
(if me?
|
||||
[(or (:preferred-name current-multiaccount)
|
||||
(gfycat/generate-gfy identity))]
|
||||
(contact-two-names contact false))))
|
||||
|
||||
(def photo-quality-thumbnail :thumbnail)
|
||||
(def photo-quality-large :large)
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
[status-im.notifications-center.core :as notifications-center]
|
||||
[status-im.navigation :as navigation]
|
||||
[status-im.signing.eip1559 :as eip1559]
|
||||
[status-im.data-store.chats :as data-store.chats]))
|
||||
[status-im.data-store.chats :as data-store.chats]
|
||||
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::initialize-communities-enabled
|
||||
|
@ -338,7 +339,8 @@
|
|||
(get-group-chat-invitations)
|
||||
(multiaccounts/get-profile-picture)
|
||||
(multiaccounts/switch-preview-privacy-mode-flag)
|
||||
(link-preview/request-link-preview-whitelist))))
|
||||
(link-preview/request-link-preview-whitelist)
|
||||
(visibility-status-updates-store/fetch-visibility-status-updates-rpc))))
|
||||
|
||||
(defn get-new-auth-method [auth-method save-password?]
|
||||
(when save-password?
|
||||
|
|
|
@ -136,7 +136,9 @@
|
|||
(fn [^js evn]
|
||||
(let [view-id (keyword (.-componentName evn))]
|
||||
(when (get views/screens view-id)
|
||||
(when (and (not= view-id :bottom-sheet) (not= view-id :popover))
|
||||
(when (and (not= view-id :bottom-sheet)
|
||||
(not= view-id :popover)
|
||||
(not= view-id :visibility-status-popover))
|
||||
(set-view-id view-id)
|
||||
(when-not @curr-modal
|
||||
(reset! pushed-screen-id view-id))))))))
|
||||
|
@ -146,7 +148,8 @@
|
|||
(.registerComponentDidDisappearListener
|
||||
(.events Navigation)
|
||||
(fn [^js evn]
|
||||
(when-not (#{"popover" "bottom-sheet" "signing-sheet"} (.-componentName evn))
|
||||
(when-not (#{"popover" "bottom-sheet" "signing-sheet" "visibility-status-popover"}
|
||||
(.-componentName evn))
|
||||
(doseq [[_ {:keys [ref value]}] @quo.text-input/text-input-refs]
|
||||
(.setNativeProps ^js ref (clj->js {:text value})))
|
||||
(doseq [[^js text-input default-value] @react/text-input-refs]
|
||||
|
@ -290,6 +293,18 @@
|
|||
(re-frame/reg-fx :show-popover (fn [] (show-overlay "popover")))
|
||||
(re-frame/reg-fx :hide-popover (fn [] (dissmiss-overlay "popover")))
|
||||
|
||||
;; VISIBILITY STATUS POPOVER
|
||||
(defonce visibility-status-popover-reg
|
||||
(.registerComponent Navigation
|
||||
"visibility-status-popover"
|
||||
(fn [] (gestureHandlerRootHOC views/visibility-status-popover-comp))
|
||||
(fn [] views/visibility-status-popover-comp)))
|
||||
|
||||
(re-frame/reg-fx :show-visibility-status-popover
|
||||
(fn [] (show-overlay "visibility-status-popover")))
|
||||
(re-frame/reg-fx :hide-visibility-status-popover
|
||||
(fn [] (dissmiss-overlay "visibility-status-popover")))
|
||||
|
||||
;; BOTTOM SHEETS
|
||||
(defonce bottom-sheet-reg
|
||||
(.registerComponent Navigation
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
[status-im.notifications.local :as local-notifications]
|
||||
[status-im.chat.models.message :as models.message]
|
||||
[status-im.chat.models.link-preview :as link.preview]
|
||||
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||
[status-im.utils.fx :as fx]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
|
@ -41,7 +42,8 @@
|
|||
{:db (assoc db
|
||||
:peers-summary peers-summary
|
||||
:peers-count peers-count)}
|
||||
(mailserver/peers-summary-change previous-summary))))
|
||||
(mailserver/peers-summary-change previous-summary)
|
||||
(visibility-status-updates/peers-summary-change peers-count))))
|
||||
|
||||
(fx/defn wakuv2-peer-stats
|
||||
[{:keys [db]} peer-stats]
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
[status-im.notifications.core :as notifications]
|
||||
[status-im.utils.currency :as currency]
|
||||
[clojure.set :as clojure.set]
|
||||
[quo.design-system.colors :as colors]))
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]))
|
||||
|
||||
;; TOP LEVEL ===========================================================================================================
|
||||
|
||||
|
@ -86,6 +87,7 @@
|
|||
(reg-root-key-sub :app-state :app-state)
|
||||
(reg-root-key-sub :home-items-show-number :home-items-show-number)
|
||||
(reg-root-key-sub :waku/v2-peer-stats :peer-stats)
|
||||
(reg-root-key-sub :visibility-status-updates :visibility-status-updates)
|
||||
|
||||
;;NOTE this one is not related to ethereum network
|
||||
;; it is about cellular network/ wifi network
|
||||
|
@ -200,6 +202,7 @@
|
|||
(reg-root-key-sub :intro-wizard-state :intro-wizard)
|
||||
|
||||
(reg-root-key-sub :popover/popover :popover/popover)
|
||||
(reg-root-key-sub :visibility-status-popover/popover :visibility-status-popover/popover)
|
||||
(reg-root-key-sub :add-account :add-account)
|
||||
|
||||
(reg-root-key-sub :keycard :keycard)
|
||||
|
@ -292,6 +295,36 @@
|
|||
(fn [communities [_ id]]
|
||||
(get-in communities [id :chats])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:communities/community-members
|
||||
:<- [:communities]
|
||||
(fn [communities [_ id]]
|
||||
(get-in communities [id :members])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:communities/sorted-community-members
|
||||
(fn [[_ community-id]]
|
||||
(let [contacts (re-frame/subscribe [:contacts/contacts])
|
||||
multiaccount (re-frame/subscribe [:multiaccount])
|
||||
members (re-frame/subscribe
|
||||
[:communities/community-members community-id])]
|
||||
[contacts multiaccount members]))
|
||||
(fn [[contacts multiaccount members] _]
|
||||
(let [names (reduce
|
||||
(fn [acc identity]
|
||||
(let [me? (= (:public-key multiaccount)
|
||||
identity)
|
||||
contact (when-not me?
|
||||
(multiaccounts/contact-by-identity
|
||||
contacts identity))
|
||||
name (first
|
||||
(multiaccounts/contact-two-names-by-identity
|
||||
contact multiaccount identity))]
|
||||
(assoc acc identity name))) {} (keys members))]
|
||||
(->> members
|
||||
(sort-by #(get names (get % 0)))
|
||||
(sort-by #(visibility-status-utils/visibility-status-order (get % 0)))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:communities/communities
|
||||
:<- [:communities/enabled?]
|
||||
|
@ -355,6 +388,11 @@
|
|||
|
||||
;;GENERAL ==============================================================================================================
|
||||
|
||||
(re-frame/reg-sub
|
||||
:visibility-status-updates/visibility-status-update
|
||||
:<- [:visibility-status-updates]
|
||||
(fn [visibility-status-updates [_ public-key]]
|
||||
(get visibility-status-updates public-key)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:multiaccount/logged-in?
|
||||
|
@ -784,6 +822,12 @@
|
|||
(string/blank? (security/safe-unmask-data seed))
|
||||
false))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:multiaccount/current-user-visibility-status
|
||||
:<- [:multiaccount]
|
||||
(fn [{:keys [current-user-visibility-status]}]
|
||||
current-user-visibility-status))
|
||||
|
||||
;;CHAT ==============================================================================================================
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
@ -2208,6 +2252,15 @@
|
|||
(fn [contacts]
|
||||
(contact.db/get-active-contacts contacts)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/sorted-contacts
|
||||
:<- [:contacts/active]
|
||||
(fn [active-contacts]
|
||||
(->> active-contacts
|
||||
(sort-by :alias)
|
||||
(sort-by
|
||||
#(visibility-status-utils/visibility-status-order (:public-key %))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/active-count
|
||||
:<- [:contacts/active]
|
||||
|
@ -2265,8 +2318,7 @@
|
|||
:contacts/contact-by-identity
|
||||
:<- [:contacts/contacts]
|
||||
(fn [contacts [_ identity]]
|
||||
(or (get contacts identity)
|
||||
(multiaccounts/contact-with-names {:public-key identity}))))
|
||||
(multiaccounts/contact-by-identity contacts identity)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/contact-added?
|
||||
|
@ -2281,11 +2333,8 @@
|
|||
[(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)))))
|
||||
(multiaccounts/contact-two-names-by-identity contact current-multiaccount
|
||||
identity)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/contact-name-by-identity
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
[status-im.constants :as constants]
|
||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[status-im.notifications-center.core :as notifications-center]
|
||||
[status-im.visibility-status-updates.core :as models.visibility-status-updates]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(fx/defn process-next
|
||||
|
@ -42,6 +43,8 @@
|
|||
^js activity-notifications (.-activityCenterNotifications response-js)
|
||||
^js pin-messages (.-pinMessages response-js)
|
||||
^js removed-messages (.-removedMessages response-js)
|
||||
^js visibility-status-updates (.-statusUpdates response-js)
|
||||
^js current-visibility-status (.-currentStatus response-js)
|
||||
sync-handler (when-not process-async process-response)]
|
||||
(cond
|
||||
|
||||
|
@ -149,7 +152,23 @@
|
|||
(js-delete response-js "removedMessages")
|
||||
(fx/merge cofx
|
||||
(process-next response-js sync-handler)
|
||||
(models.message/handle-removed-messages removed-messages-clj))))))
|
||||
(models.message/handle-removed-messages removed-messages-clj)))
|
||||
|
||||
(seq visibility-status-updates)
|
||||
(let [visibility-status-updates-clj (types/js->clj visibility-status-updates)]
|
||||
(js-delete response-js "statusUpdates")
|
||||
(fx/merge cofx
|
||||
(process-next response-js sync-handler)
|
||||
(models.visibility-status-updates/handle-visibility-status-updates
|
||||
visibility-status-updates-clj)))
|
||||
|
||||
(some? current-visibility-status)
|
||||
(let [current-visibility-status-clj (types/js->clj current-visibility-status)]
|
||||
(js-delete response-js "currentStatus")
|
||||
(fx/merge cofx
|
||||
(process-next response-js sync-handler)
|
||||
(models.visibility-status-updates/sync-visibility-status-update
|
||||
current-visibility-status-clj))))))
|
||||
|
||||
(defn group-by-and-update-unviewed-counts
|
||||
"group messages by current chat, profile updates, transactions and update unviewed counters in db for not curent chats"
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
[status-im.ui.components.chat-icon.styles :as styles]
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.chat.photos :as photos]))
|
||||
[status-im.ui.screens.chat.photos :as photos]
|
||||
[status-im.profile.db :as profile.db]
|
||||
[status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]))
|
||||
|
||||
;;TODO REWORK THIS NAMESPACE
|
||||
|
||||
|
@ -42,6 +44,24 @@
|
|||
[react/view (:default-chat-icon styles)
|
||||
[react/text {:style (:default-chat-icon-text styles)} emoji]]))
|
||||
|
||||
(defn profile-photo-plus-dot-view
|
||||
[{:keys [public-key photo-container photo-path community?]}]
|
||||
(let [photo-path (if (nil? photo-path)
|
||||
@(re-frame.core/subscribe [:chats/photo-path public-key])
|
||||
photo-path)
|
||||
photo-container (if (nil? photo-container)
|
||||
styles/container-chat-list photo-container)
|
||||
size (:width photo-container)
|
||||
identicon? (when photo-path (profile.db/base64-png? photo-path))
|
||||
dot-styles (visibility-status-utils/icon-visibility-status-dot
|
||||
public-key size identicon?)]
|
||||
[react/view {:style photo-container
|
||||
:accessibility-label :profile-photo}
|
||||
[photos/photo photo-path {:size size}]
|
||||
(when-not community?
|
||||
[react/view {:style dot-styles
|
||||
:accessibility-label :profile-photo-dot}])]))
|
||||
|
||||
(defn emoji-chat-icon-view
|
||||
[chat-id group-chat name emoji styles]
|
||||
[react/view (:container styles)
|
||||
|
@ -49,8 +69,8 @@
|
|||
(if (string/blank? emoji)
|
||||
[default-chat-icon name styles]
|
||||
[emoji-chat-icon emoji styles])
|
||||
(let [photo-path @(re-frame.core/subscribe [:chats/photo-path chat-id])]
|
||||
[photos/photo photo-path styles]))])
|
||||
[profile-photo-plus-dot-view {:public-key chat-id
|
||||
:photo-container (:default-chat-icon styles)}])])
|
||||
|
||||
(defn chat-icon-view-toolbar
|
||||
[chat-id group-chat name color emoji]
|
||||
|
@ -131,7 +151,8 @@
|
|||
(if-not (string/blank? photo-path)
|
||||
[photos/photo photo-path styles]))))
|
||||
|
||||
(defn profile-icon-view [photo-path name color emoji edit? size override-styles]
|
||||
(defn profile-icon-view
|
||||
[photo-path name color emoji edit? size override-styles public-key community?]
|
||||
(let [styles (merge {:container {:width size :height size}
|
||||
:size size
|
||||
:chat-icon styles/chat-icon-profile
|
||||
|
@ -141,7 +162,10 @@
|
|||
(styles/emoji-chat-icon-text size))} override-styles)]
|
||||
[react/view (:container styles)
|
||||
(if (and photo-path (seq photo-path))
|
||||
[photos/photo photo-path styles]
|
||||
[profile-photo-plus-dot-view {:photo-path photo-path
|
||||
:public-key public-key
|
||||
:photo-container (:container styles)
|
||||
:community? community?}]
|
||||
(if (string/blank? emoji)
|
||||
[default-chat-icon name styles]
|
||||
[emoji-chat-icon emoji styles]))
|
||||
|
|
|
@ -70,51 +70,6 @@
|
|||
:height 64
|
||||
:border-radius 32}))
|
||||
|
||||
(def online-view-wrapper
|
||||
{:position :absolute
|
||||
:bottom -2
|
||||
:right -2
|
||||
:width 17
|
||||
:height 17
|
||||
:border-radius 11
|
||||
:background-color colors/white})
|
||||
|
||||
(def online-view
|
||||
{:position :absolute
|
||||
:bottom 2
|
||||
:right 2
|
||||
:width 13
|
||||
:height 13
|
||||
:border-radius 9
|
||||
:background-color colors/blue})
|
||||
|
||||
(def online-view-profile
|
||||
(merge online-view
|
||||
{:width 24
|
||||
:height 24
|
||||
:border-radius 12}))
|
||||
|
||||
(def online-dot
|
||||
{:position :absolute
|
||||
:top 5
|
||||
:width 3
|
||||
:height 3
|
||||
:border-radius 2
|
||||
:background-color colors/white})
|
||||
(def online-dot-left (merge online-dot {:left 2.8}))
|
||||
(def online-dot-right (merge online-dot {:left 7.2}))
|
||||
|
||||
(def online-dot-profile
|
||||
(merge online-dot
|
||||
{:top 8
|
||||
:width 4
|
||||
:height 4}))
|
||||
|
||||
(def online-dot-left-profile
|
||||
(merge online-dot-profile {:left 5}))
|
||||
(def online-dot-right-profile
|
||||
(merge online-dot-profile {:left 11}))
|
||||
|
||||
(def container-chat-list
|
||||
{:width 40
|
||||
:height 40})
|
||||
|
|
|
@ -37,8 +37,10 @@
|
|||
(when-not minimized
|
||||
{:padding-top subtitle-margin})))
|
||||
|
||||
(defn extended-header [{:keys [title photo color subtitle subtitle-icon on-edit on-press monospace bottom-separator emoji]
|
||||
:or {bottom-separator true}}]
|
||||
(defn extended-header
|
||||
[{:keys [title photo color subtitle subtitle-icon on-edit on-press monospace
|
||||
bottom-separator emoji public-key community?]
|
||||
:or {bottom-separator true}}]
|
||||
(fn [{:keys [animation minimized]}]
|
||||
(let [wrapper (if on-press
|
||||
[rn/touchable-opacity {:on-press on-press}]
|
||||
|
@ -57,7 +59,7 @@
|
|||
[chat-icon.screen/profile-icon-view
|
||||
photo title color emoji (and (not minimized) on-edit)
|
||||
(if minimized avatar-minimized-size avatar-extended-size)
|
||||
nil]]])
|
||||
nil public-key community?]]])
|
||||
[animated/view {:style (header-text)
|
||||
:pointer-events :box-none}
|
||||
[quo/text {:animated? true
|
||||
|
|
|
@ -51,8 +51,9 @@
|
|||
{:title first-name
|
||||
:subtitle second-name
|
||||
:accessibility-label :member-item
|
||||
:icon [chat-icon/contact-icon-contacts-tab
|
||||
(multiaccounts/displayed-photo member)]
|
||||
:icon [chat-icon/profile-photo-plus-dot-view
|
||||
{:public-key public-key
|
||||
:photo-path (multiaccounts/displayed-photo member)}]
|
||||
:accessory (when (not= public-key my-public-key)
|
||||
[quo/button {:on-press
|
||||
#(>evt [:bottom-sheet/show-sheet
|
||||
|
@ -89,17 +90,17 @@
|
|||
(let [{:keys [community-id]} (<sub [:get-screen-params])]
|
||||
(fn []
|
||||
(let [my-public-key (<sub [:multiaccount/public-key])
|
||||
{:keys [members
|
||||
permissions
|
||||
can-manage-users?]} (<sub [:communities/community community-id])]
|
||||
{:keys [permissions
|
||||
can-manage-users?]} (<sub [:communities/community community-id])
|
||||
sorted-members (<sub [:communities/sorted-community-members
|
||||
community-id])]
|
||||
[:<>
|
||||
[topbar/topbar {:title (i18n/label :t/community-members-title)
|
||||
|
||||
:subtitle (str (count members))}]
|
||||
:subtitle (str (count sorted-members))}]
|
||||
[header community-id]
|
||||
(when (and can-manage-users? (= constants/community-on-request-access (:access permissions)))
|
||||
[requests-to-join community-id])
|
||||
[rn/flat-list {:data (keys members)
|
||||
[rn/flat-list {:data (keys sorted-members)
|
||||
:render-data {:community-id community-id
|
||||
:my-public-key my-public-key
|
||||
:can-kick-users? (and can-manage-users?
|
||||
|
|
|
@ -41,7 +41,8 @@
|
|||
(get-in community [:images :large :uri]))
|
||||
:subtitle (if show-members-count?
|
||||
(i18n/label-pluralize members-count :t/community-members {:count members-count})
|
||||
(i18n/label :t/open-membership))})
|
||||
(i18n/label :t/open-membership))
|
||||
:community? true})
|
||||
:use-insets true}
|
||||
[:<>
|
||||
(when-not (string/blank? description)
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
[quo/list-item
|
||||
{:title first-name
|
||||
:subtitle second-name
|
||||
:icon [chat-icon.screen/contact-icon-contacts-tab
|
||||
(multiaccounts/displayed-photo contact)]
|
||||
:icon [chat-icon.screen/profile-photo-plus-dot-view
|
||||
{:public-key public-key
|
||||
:photo-path (multiaccounts/displayed-photo contact)}]
|
||||
:chevron true
|
||||
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}]))
|
||||
|
||||
|
@ -30,7 +31,7 @@
|
|||
|
||||
(defview contacts-list []
|
||||
(letsubs [blocked-contacts-count [:contacts/blocked-count]
|
||||
contacts [:contacts/active]]
|
||||
sorted-contacts [:contacts/sorted-contacts]]
|
||||
[react/scroll-view {:flex 1}
|
||||
[add-new-contact]
|
||||
(when (pos? blocked-contacts-count)
|
||||
|
@ -44,9 +45,9 @@
|
|||
:accessory :text
|
||||
:accessory-text blocked-contacts-count
|
||||
:on-press #(re-frame/dispatch [:navigate-to :blocked-users-list])}]])
|
||||
(if (seq contacts)
|
||||
(if (seq sorted-contacts)
|
||||
[list.views/flat-list
|
||||
{:data contacts
|
||||
{:data sorted-contacts
|
||||
:key-fn :address
|
||||
:render-fn contacts-list-item}]
|
||||
[react/view {:align-items :center
|
||||
|
|
|
@ -205,7 +205,8 @@
|
|||
:title first-name
|
||||
:photo (multiaccounts/displayed-photo contact)
|
||||
:monospace (not ens-verified)
|
||||
:subtitle second-name})]
|
||||
:subtitle second-name
|
||||
:public-key public-key})]
|
||||
[react/view {:height 1 :background-color colors/gray-lighter :margin-top 8}]
|
||||
[nickname-settings contact]
|
||||
[pin-settings public-key (count pinned-messages)]
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
[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])
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[status-im.ui.screens.profile.visibility-status.views :as visibility-status])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(views/defview share-chat-key []
|
||||
|
@ -64,6 +66,9 @@
|
|||
chain @(re-frame/subscribe [:chain-keyword])
|
||||
registrar (stateofus/get-cached-registrar chain)]
|
||||
[:<>
|
||||
[visibility-status/visibility-status-button
|
||||
visibility-status/calculate-button-height-and-dispatch-popover]
|
||||
[quo/separator {:style {:margin-top (:tiny spacing/spacing)}}]
|
||||
[quo/list-item
|
||||
(cond-> {:title (or (when registrar preferred-name)
|
||||
(i18n/label :t/ens-usernames))
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
(ns status-im.ui.screens.profile.visibility-status.styles
|
||||
(:require [quo.design-system.colors :as colors]))
|
||||
|
||||
(defn visibility-status-button-container []
|
||||
{:background-color (:interactive-02 @colors/theme)
|
||||
:margin-left 16
|
||||
:border-radius 16
|
||||
:border-top-left-radius 4
|
||||
:align-self :flex-start
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:padding 6
|
||||
:padding-right 12})
|
||||
|
||||
(defn visibility-status-dot [dot-color size]
|
||||
{:background-color dot-color
|
||||
:width size
|
||||
:height size
|
||||
:border-radius (/ size 2)
|
||||
:border-width 1
|
||||
:border-color colors/white})
|
||||
|
||||
(defn visibility-status-profile-dot [color size border-width margin-left]
|
||||
(merge (visibility-status-dot color size)
|
||||
{:margin-right 6
|
||||
:margin-left margin-left
|
||||
:border-width border-width}))
|
||||
|
||||
(defn visibility-status-text []
|
||||
{:color (:text-01 @colors/theme)
|
||||
:font-size 16
|
||||
:text-align :center})
|
||||
|
||||
(defn visibility-status-subtitle []
|
||||
{:color (:text-02 @colors/theme)
|
||||
:font-size 16
|
||||
:margin-left 22
|
||||
:margin-right 6})
|
||||
|
||||
(defn visibility-status-option []
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(defn visibility-status-options [scale position]
|
||||
{:background-color (if (colors/dark?)
|
||||
(:interactive-02 @colors/theme)
|
||||
colors/white)
|
||||
:border-radius 16
|
||||
:border-top-left-radius 4
|
||||
:justify-content :center
|
||||
:align-self :flex-start
|
||||
:left 16
|
||||
:top -76
|
||||
:padding-bottom 6
|
||||
:padding-top 8
|
||||
:transform [{:scaleY scale}
|
||||
{:translateY position}]})
|
||||
|
||||
(defn visibility-status-popover-container []
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(defn visibility-status-popover-ios-backdrop [alpha-value]
|
||||
{:flex 1
|
||||
:background-color colors/black-persist
|
||||
:opacity alpha-value})
|
||||
|
||||
(defn visibility-status-popover-child-container [window-height]
|
||||
{:position :absolute
|
||||
:height window-height
|
||||
:left 0
|
||||
:right 0})
|
|
@ -0,0 +1,95 @@
|
|||
(ns status-im.ui.screens.profile.visibility-status.utils
|
||||
(:require [status-im.constants :as constants]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.ui.screens.profile.visibility-status.styles :as styles]
|
||||
[status-im.utils.handlers :refer [<sub]]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[quo.design-system.colors :as colors]
|
||||
[clojure.string :as string]))
|
||||
|
||||
;; Specs:
|
||||
;; :visibility-status-automatic
|
||||
;; To Send - "visibility-status-automatic" status ping every 5 minutes
|
||||
;; Display - Online for up to 5 minutes from the last clock, after that Offline
|
||||
;; :visibility-status-always-online
|
||||
;; To Send - "visibility-status-always-online" status ping every 5 minutes
|
||||
;; Display - Online for up to 2 weeks from the last clock, after that Offline
|
||||
;; :visibility-status-inactive
|
||||
;; To Send - A single "visibility-status-inactive" status ping
|
||||
;; Display - Offline forever
|
||||
;; Note: Only send pings if the user interacted with the app in the last x minutes.
|
||||
(def visibility-status-type-data
|
||||
{constants/visibility-status-unknown
|
||||
{:color colors/red
|
||||
:title (i18n/label :t/error)}
|
||||
constants/visibility-status-automatic
|
||||
{:color colors/color-online
|
||||
:title (i18n/label :t/status-automatic)
|
||||
:subtitle (i18n/label :t/status-automatic-subtitle)}
|
||||
constants/visibility-status-dnd
|
||||
{:color colors/color-dnd
|
||||
:title (i18n/label :t/status-dnd)
|
||||
:subtitle (i18n/label :t/status-dnd-subtitle)}
|
||||
constants/visibility-status-always-online
|
||||
{:color colors/color-online
|
||||
:title (i18n/label :t/status-always-online)}
|
||||
constants/visibility-status-inactive
|
||||
{:color colors/color-inactive
|
||||
:title (i18n/label :t/status-inactive)
|
||||
:subtitle (i18n/label :t/status-inactive-subtitle)}})
|
||||
|
||||
;; Currently, Another user is broadcasting their status updates at the rate of 5 minutes.
|
||||
;; So for status-type automatic, we need to show
|
||||
;; that user online a little longer than that time. (broadcast receiving delay)
|
||||
(defn calculate-real-status-type-and-time-left
|
||||
[{:keys [status-type clock]}]
|
||||
(let [status-lifespan (if (= status-type
|
||||
constants/visibility-status-automatic)
|
||||
(datetime/minutes 5.05)
|
||||
(datetime/weeks 2))
|
||||
status-expire-time (+ (datetime/to-ms clock) status-lifespan)
|
||||
time-left (- status-expire-time (datetime/timestamp))
|
||||
status-type (if (or (nil? status-type)
|
||||
(and
|
||||
(not= status-type
|
||||
constants/visibility-status-inactive)
|
||||
(neg? time-left)))
|
||||
constants/visibility-status-inactive
|
||||
status-type)]
|
||||
{:real-status-type status-type
|
||||
:time-left time-left}))
|
||||
|
||||
(defn dot-color
|
||||
[{:keys [status-type] :as visibility-status-update} my-icon?]
|
||||
(if my-icon?
|
||||
(if (= status-type constants/visibility-status-inactive)
|
||||
colors/color-inactive colors/color-online)
|
||||
(let [{:keys [real-status-type]}
|
||||
(calculate-real-status-type-and-time-left visibility-status-update)]
|
||||
(:color (get visibility-status-type-data real-status-type)))))
|
||||
|
||||
(defn my-icon? [public-key]
|
||||
(or (string/blank? public-key)
|
||||
(= public-key (<sub [:multiaccount/public-key]))))
|
||||
|
||||
(defn visibility-status-update [public-key my-icon?]
|
||||
(if my-icon?
|
||||
(<sub [:multiaccount/current-user-visibility-status])
|
||||
(<sub [:visibility-status-updates/visibility-status-update public-key])))
|
||||
|
||||
(defn icon-visibility-status-dot [public-key container-size identicon?]
|
||||
(let [my-icon? (my-icon? public-key)
|
||||
visibility-status-update (visibility-status-update public-key my-icon?)
|
||||
size (/ container-size 4)
|
||||
margin (if identicon? (/ size 6) (/ size 7))
|
||||
dot-color (dot-color visibility-status-update my-icon?)]
|
||||
(merge (styles/visibility-status-dot dot-color size)
|
||||
{:bottom margin
|
||||
:right margin
|
||||
:position :absolute})))
|
||||
|
||||
(defn visibility-status-order [public-key]
|
||||
(let [my-icon? (my-icon? public-key)
|
||||
visibility-status-update (visibility-status-update public-key my-icon?)
|
||||
dot-color (dot-color visibility-status-update my-icon?)]
|
||||
(if (= dot-color colors/color-online) 0 1)))
|
|
@ -0,0 +1,200 @@
|
|||
(ns status-im.ui.screens.profile.visibility-status.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require ["react-native" :refer (BackHandler)]
|
||||
[quo.core :as quo]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.react-native :as rn]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.utils.handlers :refer [<sub]]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ui.screens.profile.visibility-status.styles :as styles]
|
||||
[status-im.ui.screens.profile.visibility-status.utils :as utils]))
|
||||
|
||||
;; === Code Related to visibility-status-button ===
|
||||
|
||||
(def button-ref (atom nil))
|
||||
|
||||
(defn dispatch-popover [top]
|
||||
(re-frame/dispatch [:show-visibility-status-popover {:top top}]))
|
||||
|
||||
(defn dispatch-visibility-status-update [status-type]
|
||||
(re-frame/dispatch
|
||||
[:visibility-status-updates/delayed-visibility-status-update status-type]))
|
||||
|
||||
(defn calculate-button-height-and-dispatch-popover []
|
||||
(.measure @button-ref
|
||||
(fn [_ _ _ _ _ py]
|
||||
(dispatch-popover py))))
|
||||
|
||||
(defn profile-visibility-status-dot [status-type color]
|
||||
(let [automatic? (= status-type
|
||||
constants/visibility-status-automatic)
|
||||
[border-width margin-left size] (if automatic? [1 -10 12] [0 6 10])]
|
||||
[:<>
|
||||
(when automatic?
|
||||
[rn/view {:style (styles/visibility-status-profile-dot
|
||||
colors/color-inactive size border-width 6)}])
|
||||
[rn/view {:style (styles/visibility-status-profile-dot
|
||||
color size border-width margin-left)}]]))
|
||||
|
||||
(defn visibility-status-button [on-press props]
|
||||
(let [logged-in? (<sub [:multiaccount/logged-in?])
|
||||
{:keys [status-type]} (<sub [:multiaccount/current-user-visibility-status])
|
||||
status-type (if (and logged-in? (nil? status-type))
|
||||
(do
|
||||
(dispatch-visibility-status-update
|
||||
constants/visibility-status-automatic)
|
||||
constants/visibility-status-automatic)
|
||||
status-type)
|
||||
{:keys [color title]} (get utils/visibility-status-type-data status-type)]
|
||||
[rn/touchable-opacity
|
||||
(merge
|
||||
{:on-press on-press
|
||||
:accessibility-label :visibility-status-button
|
||||
:style (styles/visibility-status-button-container)
|
||||
:ref #(reset! button-ref ^js %)} props)
|
||||
[profile-visibility-status-dot status-type color]
|
||||
[rn/text {:style (styles/visibility-status-text)} title]]))
|
||||
|
||||
;; === Code Related to visibility-status-popover ===
|
||||
(def scale (anim/create-value 0))
|
||||
(def position (anim/create-value 0))
|
||||
(def alpha-value (anim/create-value 0))
|
||||
|
||||
(defn hide-options []
|
||||
(anim/start
|
||||
(anim/parallel
|
||||
[(anim/timing scale {:toValue 0
|
||||
:duration 140
|
||||
:useNativeDriver true})
|
||||
(anim/timing position {:toValue 50
|
||||
:duration 210
|
||||
:useNativeDriver true})
|
||||
(anim/timing alpha-value {:toValue 0
|
||||
:duration 200
|
||||
:useNativeDriver true})])))
|
||||
|
||||
(defn show-options []
|
||||
(anim/start
|
||||
(anim/parallel
|
||||
[(anim/timing scale {:toValue 1
|
||||
:duration 210
|
||||
:useNativeDriver true})
|
||||
(anim/timing position {:toValue 80
|
||||
:duration 70
|
||||
:useNativeDriver true})
|
||||
(anim/timing alpha-value {:toValue 0.4
|
||||
:duration 200
|
||||
:useNativeDriver true})])))
|
||||
|
||||
(defn status-option-pressed [request-close status-type]
|
||||
(request-close)
|
||||
(dispatch-visibility-status-update status-type))
|
||||
|
||||
(defn status-option [{:keys [request-close status-type]}]
|
||||
(let [{:keys [color title subtitle]}
|
||||
(get utils/visibility-status-type-data status-type)]
|
||||
[rn/touchable-opacity {:style {:padding 6}
|
||||
:accessibility-label :visibility-status-option
|
||||
:on-press #(status-option-pressed
|
||||
request-close status-type)}
|
||||
[rn/view {:style (styles/visibility-status-option)}
|
||||
[profile-visibility-status-dot status-type color]
|
||||
[rn/text {:style (styles/visibility-status-text)} title]]
|
||||
(when-not (nil? subtitle)
|
||||
[rn/text {:style (styles/visibility-status-subtitle)} subtitle])]))
|
||||
|
||||
(defn visibility-status-options [request-close top]
|
||||
[react/view {:position :absolute
|
||||
:top (int top)}
|
||||
[visibility-status-button request-close {:ref nil :active-opacity 1}]
|
||||
[react/animated-view {:style
|
||||
(styles/visibility-status-options scale position)
|
||||
:accessibility-label :visibility-status-options}
|
||||
[status-option
|
||||
{:status-type constants/visibility-status-always-online
|
||||
:request-close request-close}]
|
||||
[quo/separator {:style {:margin-top 8}}]
|
||||
[status-option
|
||||
{:status-type constants/visibility-status-inactive
|
||||
:request-close request-close}]
|
||||
[quo/separator]
|
||||
[status-option
|
||||
{:status-type constants/visibility-status-automatic
|
||||
:request-close request-close}]]])
|
||||
|
||||
(defn popover-view [_ window-height]
|
||||
(let [clear-timeout (atom nil)
|
||||
current-popover (reagent/atom nil)
|
||||
update? (reagent/atom nil)
|
||||
request-close (fn []
|
||||
(reset! clear-timeout
|
||||
(js/setTimeout
|
||||
#(do (reset! current-popover nil)
|
||||
(re-frame/dispatch
|
||||
[:hide-visibility-status-popover]))
|
||||
200))
|
||||
(hide-options)
|
||||
true)
|
||||
on-show (fn []
|
||||
(show-options)
|
||||
(when platform/android?
|
||||
(.removeEventListener BackHandler
|
||||
"hardwareBackPress"
|
||||
request-close)
|
||||
(.addEventListener BackHandler
|
||||
"hardwareBackPress"
|
||||
request-close)))
|
||||
on-hide (fn []
|
||||
(when platform/android?
|
||||
(.removeEventListener BackHandler
|
||||
"hardwareBackPress"
|
||||
request-close)))]
|
||||
(reagent/create-class
|
||||
{:UNSAFE_componentWillUpdate
|
||||
(fn [_ [_ popover _]]
|
||||
(when @clear-timeout (js/clearTimeout @clear-timeout))
|
||||
(cond
|
||||
@update?
|
||||
(do (reset! update? false)
|
||||
(on-show))
|
||||
|
||||
(and @current-popover popover)
|
||||
(do (reset! update? true)
|
||||
(js/setTimeout #(reset! current-popover popover) 600)
|
||||
(hide-options))
|
||||
|
||||
popover
|
||||
(do (reset! current-popover popover)
|
||||
(on-show))
|
||||
|
||||
:else
|
||||
(do (reset! current-popover nil)
|
||||
(on-hide))))
|
||||
:component-will-unmount on-hide
|
||||
:reagent-render
|
||||
(fn []
|
||||
(when @current-popover
|
||||
(let [{:keys [top]} @current-popover]
|
||||
[react/view
|
||||
{:style (styles/visibility-status-popover-container)}
|
||||
(when platform/ios?
|
||||
[react/animated-view
|
||||
{:style (styles/visibility-status-popover-ios-backdrop
|
||||
alpha-value)}])
|
||||
[react/view
|
||||
{:style (styles/visibility-status-popover-child-container
|
||||
window-height)}
|
||||
[react/touchable-highlight
|
||||
{:style {:flex 1}
|
||||
:on-press request-close}
|
||||
[visibility-status-options request-close top]]]])))})))
|
||||
|
||||
(views/defview visibility-status-popover []
|
||||
(views/letsubs [popover [:visibility-status-popover/popover]
|
||||
{window-height :height} [:dimensions/window]]
|
||||
[popover-view popover window-height]))
|
|
@ -5,6 +5,7 @@
|
|||
[status-im.ui.screens.screens :as screens]
|
||||
[oops.core :refer [oget]]
|
||||
[status-im.ui.screens.popover.views :as popover]
|
||||
[status-im.ui.screens.profile.visibility-status.views :as visibility-status-views]
|
||||
[status-im.ui.screens.bottom-sheets.views :as bottom-sheets]
|
||||
[status-im.ui.screens.signing.views :as signing]
|
||||
[status-im.ui.screens.wallet.send.views :as wallet.send.views]
|
||||
|
@ -86,6 +87,16 @@
|
|||
(when js/goog.DEBUG
|
||||
[reloader/reload-view])])))
|
||||
|
||||
(def visibility-status-popover-comp
|
||||
(reagent/reactify-component
|
||||
(fn []
|
||||
^{:key (str "visibility-status-popover" @reloader/cnt)}
|
||||
[react/safe-area-provider
|
||||
[inactive]
|
||||
[visibility-status-views/visibility-status-popover]
|
||||
(when js/goog.DEBUG
|
||||
[reloader/reload-view])])))
|
||||
|
||||
(def sheet-comp
|
||||
(reagent/reactify-component
|
||||
(fn []
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
(def hour (* 60 minute))
|
||||
(def day (* 24 hour))
|
||||
(def week (* 7 day))
|
||||
(defn weeks [w]
|
||||
(* w week))
|
||||
(def units [{:name :t/datetime-second-short :limit 60 :in-second 1}
|
||||
{:name :t/datetime-minute-short :limit 3600 :in-second 60}
|
||||
{:name :t/datetime-hour-short :limit 86400 :in-second 3600}
|
||||
|
@ -144,6 +146,9 @@
|
|||
(defn timestamp []
|
||||
(inst-ms (js/Date.)))
|
||||
|
||||
(defn timestamp-sec []
|
||||
(int (/ (timestamp) 1000)))
|
||||
|
||||
(defn timestamp->year-month-day-date [ms]
|
||||
(unparse (:year-month-day formatters) (to-date ms)))
|
||||
|
||||
|
@ -167,3 +172,6 @@
|
|||
(str day (or (s (mod (- m 20) 10))
|
||||
(s m)
|
||||
(s 0)))))
|
||||
|
||||
(defn to-ms [sec]
|
||||
(* 1000 sec))
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
(ns status-im.visibility-status-popover.core
|
||||
(:require [status-im.utils.fx :as fx]))
|
||||
|
||||
(fx/defn show-visibility-status-popover
|
||||
{:events [:show-visibility-status-popover]}
|
||||
[_ value]
|
||||
{:show-visibility-status-popover nil
|
||||
:dispatch-later [{:ms 250
|
||||
:dispatch [:show-visibility-status-popover-db value]}]
|
||||
:dismiss-keyboard nil})
|
||||
|
||||
(fx/defn show-visibility-status-popover-db
|
||||
{:events [:show-visibility-status-popover-db]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :visibility-status-popover/popover value)})
|
||||
|
||||
(fx/defn hide-visibility-status-popover
|
||||
{:events [:hide-visibility-status-popover]}
|
||||
[{:keys [db]}]
|
||||
{:db (dissoc db :visibility-status-popover/popover)
|
||||
:hide-visibility-status-popover nil})
|
|
@ -0,0 +1,179 @@
|
|||
(ns status-im.visibility-status-updates.core
|
||||
(:require [status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.ui.screens.profile.visibility-status.utils :as utils]))
|
||||
|
||||
(defn valid-status-type? [status-type]
|
||||
(some #(= status-type %)
|
||||
(list constants/visibility-status-always-online
|
||||
constants/visibility-status-inactive
|
||||
constants/visibility-status-automatic)))
|
||||
|
||||
(defn process-visibility-status-update
|
||||
[acc {:keys [public-key clock] :as visibility-status-update}]
|
||||
(let [{:keys [real-status-type time-left]}
|
||||
(utils/calculate-real-status-type-and-time-left visibility-status-update)]
|
||||
(cond-> (assoc-in acc
|
||||
[:visibility-status-updates public-key]
|
||||
visibility-status-update)
|
||||
(= real-status-type constants/visibility-status-automatic)
|
||||
(update :dispatch-later
|
||||
#(conj % {:ms time-left
|
||||
:dispatch [:visibility-status-updates/timeout-user-online-status
|
||||
public-key clock]})))))
|
||||
|
||||
(fx/defn load-visibility-status-updates
|
||||
{:events [:visibility-status-updates/visibility-status-updates-loaded]}
|
||||
[{:keys [db]} visibility-status-updates-loaded]
|
||||
(let [{:keys [visibility-status-updates dispatch-later]}
|
||||
(reduce (fn [acc visibility-status-update-loaded]
|
||||
(let [{:keys [public-key] :as visibility-status-update}
|
||||
(visibility-status-updates-store/<-rpc
|
||||
visibility-status-update-loaded)]
|
||||
(process-visibility-status-update acc visibility-status-update)))
|
||||
{} visibility-status-updates-loaded)]
|
||||
(merge {:db (assoc db :visibility-status-updates visibility-status-updates)}
|
||||
(when dispatch-later {:utils/dispatch-later dispatch-later}))))
|
||||
|
||||
(defn handle-my-visibility-status-updates
|
||||
[acc my-current-status clock visibility-status-update]
|
||||
(let [status-type (:status-type visibility-status-update)]
|
||||
(if (and (valid-status-type? status-type)
|
||||
(or
|
||||
(nil? my-current-status)
|
||||
(> clock (:clock my-current-status))))
|
||||
(-> acc
|
||||
(update :current-user-visibility-status
|
||||
merge {:clock clock :status-type status-type})
|
||||
(assoc :dispatch [:visibility-status-updates/send-visibility-status-updates?
|
||||
(not= status-type constants/visibility-status-inactive)]))
|
||||
acc)))
|
||||
|
||||
(defn handle-other-visibility-status-updates
|
||||
[acc public-key clock visibility-status-update]
|
||||
(let [status-type (:status-type visibility-status-update)
|
||||
visibility-status-update-old
|
||||
(get-in acc [:visibility-status-updates public-key])]
|
||||
(if (and (valid-status-type? status-type)
|
||||
(or
|
||||
(nil? visibility-status-update-old)
|
||||
(> clock (:clock visibility-status-update-old))))
|
||||
(process-visibility-status-update acc visibility-status-update)
|
||||
acc)))
|
||||
|
||||
(fx/defn handle-visibility-status-updates
|
||||
[{:keys [db]} visibility-status-updates-received]
|
||||
(let [visibility-status-updates-old (get db :visibility-status-updates {})
|
||||
my-public-key (get-in
|
||||
db [:multiaccount :public-key])
|
||||
my-current-status (get-in
|
||||
db [:multiaccount :current-user-visibility-status])
|
||||
{:keys [visibility-status-updates
|
||||
current-user-visibility-status
|
||||
dispatch dispatch-later]}
|
||||
(reduce (fn [acc visibility-status-update-received]
|
||||
(let [{:keys [public-key clock] :as visibility-status-update}
|
||||
(visibility-status-updates-store/<-rpc
|
||||
visibility-status-update-received)]
|
||||
(if (= public-key my-public-key)
|
||||
(handle-my-visibility-status-updates
|
||||
acc my-current-status clock visibility-status-update)
|
||||
(handle-other-visibility-status-updates
|
||||
acc public-key clock visibility-status-update))))
|
||||
{:visibility-status-updates visibility-status-updates-old
|
||||
:current-user-visibility-status my-current-status}
|
||||
visibility-status-updates-received)]
|
||||
(merge {:db (-> db
|
||||
(update-in [:visibility-status-updates]
|
||||
merge visibility-status-updates)
|
||||
(update-in [:multiaccount :current-user-visibility-status]
|
||||
merge current-user-visibility-status))}
|
||||
(when dispatch {:dispatch dispatch})
|
||||
(when dispatch-later {:utils/dispatch-later dispatch-later}))))
|
||||
|
||||
(fx/defn update-visibility-status
|
||||
{:events [:visibility-status-updates/update-visibility-status]}
|
||||
[{:keys [db] :as cofx} status-type]
|
||||
{:db (update-in db [:multiaccount :current-user-visibility-status]
|
||||
merge {:status-type status-type
|
||||
:clock (datetime/timestamp-sec)})
|
||||
::json-rpc/call [{:method "wakuext_setUserStatus"
|
||||
:params [status-type ""]
|
||||
:on-success #()}]})
|
||||
|
||||
(fx/defn send-visibility-status-updates?
|
||||
{:events [:visibility-status-updates/send-visibility-status-updates?]}
|
||||
[cofx val]
|
||||
(multiaccounts.update/multiaccount-update cofx
|
||||
:send-status-updates? val
|
||||
{}))
|
||||
|
||||
(fx/defn visibility-status-option-pressed
|
||||
{:events [:visibility-status-updates/visibility-status-option-pressed]}
|
||||
[{:keys [db] :as cofx} status-type]
|
||||
(let [events-to-dispatch-later
|
||||
(cond-> [{:ms 10 :dispatch
|
||||
[:visibility-status-updates/update-visibility-status
|
||||
status-type]}]
|
||||
(and
|
||||
(= status-type constants/visibility-status-inactive)
|
||||
(> (:peers-count db) 0))
|
||||
;; Disable broadcasting further updates
|
||||
(conj {:ms 1000
|
||||
:dispatch
|
||||
[:visibility-status-updates/send-visibility-status-updates? false]}))]
|
||||
(fx/merge cofx
|
||||
{:dispatch-later events-to-dispatch-later}
|
||||
;; Enable broadcasting for current broadcast
|
||||
(send-visibility-status-updates? true))))
|
||||
|
||||
(fx/defn timeout-user-online-status
|
||||
{:events [:visibility-status-updates/timeout-user-online-status]}
|
||||
[{:keys [db]} public-key clock]
|
||||
(let [current-clock (get-in db [:visibility-status-updates public-key :clock] 0)]
|
||||
(when (= current-clock clock)
|
||||
{:db (update-in db [:visibility-status-updates public-key]
|
||||
merge {:status-type constants/visibility-status-inactive})})))
|
||||
|
||||
(fx/defn delayed-visibility-status-update
|
||||
{:events [:visibility-status-updates/delayed-visibility-status-update]}
|
||||
[{:keys [db]} status-type]
|
||||
{:dispatch-later
|
||||
[{:ms 200
|
||||
:dispatch
|
||||
[:visibility-status-updates/visibility-status-option-pressed status-type]}]})
|
||||
|
||||
(fx/defn peers-summary-change
|
||||
[{:keys [db] :as cofx} peers-count]
|
||||
(let [send-visibility-status-updates?
|
||||
(get-in db [:multiaccount :send-status-updates?])
|
||||
status-type
|
||||
(get-in db [:multiaccount :current-user-visibility-status :status-type])]
|
||||
(when (and
|
||||
(> peers-count 0)
|
||||
send-visibility-status-updates?
|
||||
(= status-type constants/visibility-status-inactive))
|
||||
(fx/merge cofx
|
||||
{:dispatch-later [{:ms 1000 :dispatch
|
||||
[:visibility-status-updates/send-visibility-status-updates? false]}]
|
||||
:db (assoc-in db [:multiaccount :send-status-updates?] false)}
|
||||
(update-visibility-status status-type)))))
|
||||
|
||||
(fx/defn sync-visibility-status-update
|
||||
[{:keys [db] :as cofx} visibility-status-update-received]
|
||||
(let [my-current-status (get-in db [:multiaccount :current-user-visibility-status])
|
||||
{:keys [status-type clock]} (visibility-status-updates-store/<-rpc
|
||||
visibility-status-update-received)]
|
||||
(when (and (valid-status-type? status-type)
|
||||
(or
|
||||
(nil? my-current-status)
|
||||
(> clock (:clock my-current-status))))
|
||||
(fx/merge cofx
|
||||
{:db (update-in db [:multiaccount :current-user-visibility-status]
|
||||
merge {:clock clock :status-type status-type})}
|
||||
(send-visibility-status-updates?
|
||||
(not= status-type constants/visibility-status-inactive))))))
|
|
@ -3,7 +3,7 @@
|
|||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.89.14",
|
||||
"commit-sha1": "c20e8ebdeffd14a881d8092ee64e5180ad53449e",
|
||||
"src-sha256": "0jbmgj0m1hv1nx3frbzs7lsn8nqspsir5kpzn8lldfgkfgpv96h7"
|
||||
"version": "v0.89.15",
|
||||
"commit-sha1": "9693d59e614899557e8b2f4f19ad541bbad3be39",
|
||||
"src-sha256": "19nl5g5vhrsm510mi0nddi5n67h6z27nx6vixk72bwyvlpz22sij"
|
||||
}
|
||||
|
|
|
@ -1674,5 +1674,12 @@
|
|||
"disable-later-in-settings": "You can disable this later in Settings",
|
||||
"use-as-profile-picture": "Use as profile picture",
|
||||
"view-on-opensea": "View on OpenSea",
|
||||
"profile-picture-updated": "Profile picture updated"
|
||||
"profile-picture-updated": "Profile picture updated",
|
||||
"status-automatic": "Automatic",
|
||||
"status-automatic-subtitle": "Set status automatically",
|
||||
"status-dnd": "Do not disturb",
|
||||
"status-dnd-subtitle": "Mutes all notifications",
|
||||
"status-always-online": "Always Online",
|
||||
"status-inactive": "Inactive",
|
||||
"status-inactive-subtitle": "Hides your online status"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue