Style header group-chats
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
2430992fb4
commit
52ae2c2bfe
|
@ -21,11 +21,7 @@
|
|||
(defn active-chats
|
||||
[contacts chats {:keys [dev-mode?]}]
|
||||
(reduce (fn [acc [chat-id {:keys [group-chat public? is-active] :as chat}]]
|
||||
(if (and is-active
|
||||
;; not a group chat
|
||||
(or (not (and group-chat (not public?)))
|
||||
;; if it's a group chat
|
||||
utils.config/group-chats-enabled?))
|
||||
(if is-active
|
||||
(assoc acc chat-id (if-let [contact (get contacts chat-id)]
|
||||
(-> chat
|
||||
(assoc :name (:name contact))
|
||||
|
|
|
@ -242,7 +242,10 @@
|
|||
(cond
|
||||
(and (= :group-user-message message-type)
|
||||
(and (get-in cofx [:db :chats chat-id :contacts from])
|
||||
(get-in cofx [:db :chats chat-id :members-joined (accounts.db/current-public-key cofx)]))) chat-id
|
||||
;; Version 0 does not have a concept of joining, so any message is ok
|
||||
;; otherwise check we joined
|
||||
(or (= 0 (get-in cofx [:db :chats chat-id :group-chat-local-version]))
|
||||
(get-in cofx [:db :chats chat-id :members-joined (accounts.db/current-public-key cofx)])))) chat-id
|
||||
(and (= :public-group-user-message message-type)
|
||||
(get-in cofx [:db :chats chat-id :public?])) chat-id
|
||||
(and (= :user-message message-type)
|
||||
|
|
|
@ -246,3 +246,8 @@
|
|||
(def v13
|
||||
(update v12 :properties assoc
|
||||
:members-joined {:type "string[]"}))
|
||||
|
||||
(def v14
|
||||
(update v13 :properties assoc
|
||||
:group-chat-local-version {:type :int
|
||||
:optional true}))
|
||||
|
|
|
@ -371,6 +371,20 @@
|
|||
dapp-permissions/v9
|
||||
contact-recovery/v1])
|
||||
|
||||
(def v34 [chat/v14
|
||||
transport/v7
|
||||
contact/v3
|
||||
message/v9
|
||||
mailserver/v11
|
||||
mailserver-topic/v1
|
||||
user-status/v2
|
||||
membership-update/v1
|
||||
installation/v3
|
||||
local-storage/v1
|
||||
browser/v8
|
||||
dapp-permissions/v9
|
||||
contact-recovery/v1])
|
||||
|
||||
;; put schemas ordered by version
|
||||
(def schemas [{:schema v1
|
||||
:schemaVersion 1
|
||||
|
@ -470,4 +484,7 @@
|
|||
:migration (constantly nil)}
|
||||
{:schema v33
|
||||
:schemaVersion 33
|
||||
:migration (constantly nil)}])
|
||||
:migration (constantly nil)}
|
||||
{:schema v34
|
||||
:schemaVersion 34
|
||||
:migration migrations/v34}])
|
||||
|
|
|
@ -339,3 +339,10 @@
|
|||
content-type (aget last-message "content-type")]
|
||||
(aset chat "last-message-content" content)
|
||||
(aset chat "last-message-content-type" content-type)))))))
|
||||
|
||||
(defn v34 [old-realm new-realm]
|
||||
(let [chats (.objects new-realm "chat")]
|
||||
(dotimes [i (.-length chats)]
|
||||
(let [chat (aget chats i)
|
||||
chat-id (aget chat "chat-id")]
|
||||
(aset chat "group-chat-local-version" 0)))))
|
||||
|
|
|
@ -52,12 +52,6 @@
|
|||
js/JSON.parse
|
||||
(js->clj :keywordize-keys true)))
|
||||
|
||||
(defn joined? [public-key {:keys [members-joined]}]
|
||||
(contains? members-joined public-key))
|
||||
|
||||
(defn invited? [my-public-key {:keys [contacts]}]
|
||||
(contains? contacts my-public-key))
|
||||
|
||||
(defn extract-creator
|
||||
"Takes a chat as an input, returns the creator"
|
||||
[{:keys [membership-updates]}]
|
||||
|
@ -67,6 +61,20 @@
|
|||
first
|
||||
:from))
|
||||
|
||||
(defn joined-event? [public-key {:keys [members-joined] :as chat}]
|
||||
(contains? members-joined public-key))
|
||||
|
||||
(defn joined? [public-key {:keys [group-chat-local-version] :as chat}]
|
||||
;; We consider group chats with local version of 0 as joined for local events
|
||||
(or (zero? group-chat-local-version)
|
||||
(joined-event? public-key chat)))
|
||||
|
||||
(defn creator? [public-key chat]
|
||||
(= public-key (extract-creator chat)))
|
||||
|
||||
(defn invited? [my-public-key {:keys [contacts]}]
|
||||
(contains? contacts my-public-key))
|
||||
|
||||
(defn signature-material
|
||||
"Transform an update into a signable string"
|
||||
[chat-id events]
|
||||
|
@ -130,13 +138,14 @@
|
|||
;; If a member has joined is listening to the shared topic and we send there
|
||||
;; to ourselves we send always on contact-discovery to make sure all devices
|
||||
;; are informed, in case of dropped messages.
|
||||
;; We send on the discovery topic to the creator as it's automatically
|
||||
;; joined or for contact that have not joined yet,
|
||||
;; for backward compatibility
|
||||
;; We check that it has explicitly joined, regardless of the local
|
||||
;; version of the group chat, for backward compatibility
|
||||
destinations (map (fn [member]
|
||||
(if (and (joined? member chat)
|
||||
(not= creator member)
|
||||
(not= current-public-key member))
|
||||
(if (and
|
||||
config/group-chats-publish-to-topic?
|
||||
(joined-event? member chat)
|
||||
(not= creator member)
|
||||
(not= current-public-key member))
|
||||
{:public-key member
|
||||
:chat chat-id}
|
||||
{:public-key member
|
||||
|
@ -476,14 +485,11 @@
|
|||
(fx/defn set-up-topic [cofx chat-id previous-chat]
|
||||
(let [my-public-key (accounts.db/current-public-key cofx)
|
||||
new-chat (get-in cofx [:db :chats chat-id])]
|
||||
(cond
|
||||
(and (not (joined? my-public-key previous-chat))
|
||||
(joined? my-public-key new-chat))
|
||||
(transport.public-chat/join-group-chat cofx chat-id)
|
||||
|
||||
(and (joined? my-public-key previous-chat)
|
||||
(not (joined? my-public-key new-chat)))
|
||||
(transport.chat/unsubscribe-from-chat cofx chat-id))))
|
||||
;; If we left the chat, teardown, otherwise upsert
|
||||
(if (and (joined? my-public-key previous-chat)
|
||||
(not (joined? my-public-key new-chat)))
|
||||
(transport.chat/unsubscribe-from-chat cofx chat-id)
|
||||
(transport.public-chat/join-group-chat cofx chat-id))))
|
||||
|
||||
(fx/defn handle-membership-update
|
||||
"Upsert chat and receive message if valid"
|
||||
|
@ -495,8 +501,7 @@
|
|||
raw-payload
|
||||
sender-signature]
|
||||
(let [dev-mode? (get-in cofx [:db :account/account :dev-mode?])]
|
||||
(when (and config/group-chats-enabled?
|
||||
(valid-chat-id? chat-id (extract-creator membership-update)))
|
||||
(when (valid-chat-id? chat-id (extract-creator membership-update))
|
||||
(let [previous-chat (get-in cofx [:db :chats chat-id])
|
||||
all-updates (clojure.set/union (set (:membership-updates previous-chat))
|
||||
(set (:membership-updates membership-update)))
|
||||
|
@ -505,15 +510,16 @@
|
|||
new-group (build-group unwrapped-events)
|
||||
member? (contains? (:contacts new-group) my-public-key)]
|
||||
(fx/merge cofx
|
||||
(models.chat/upsert-chat {:chat-id chat-id
|
||||
:name (:name new-group)
|
||||
:is-active (or member?
|
||||
(get previous-chat :is-active true))
|
||||
:group-chat true
|
||||
:membership-updates (into [] all-updates)
|
||||
:admins (:admins new-group)
|
||||
:members-joined (:members-joined new-group)
|
||||
:contacts (:contacts new-group)})
|
||||
(models.chat/upsert-chat {:chat-id chat-id
|
||||
:name (:name new-group)
|
||||
:group-chat-local-version (get previous-chat :group-chat-local-version 1)
|
||||
:is-active (or member?
|
||||
(get previous-chat :is-active true))
|
||||
:group-chat true
|
||||
:membership-updates (into [] all-updates)
|
||||
:admins (:admins new-group)
|
||||
:members-joined (:members-joined new-group)
|
||||
:contacts (:contacts new-group)})
|
||||
(add-system-messages chat-id previous-chat new-group)
|
||||
(set-up-topic chat-id previous-chat)
|
||||
#(when (and message
|
||||
|
|
|
@ -113,12 +113,7 @@
|
|||
:ShhextConfig {:BackupDisabledDataDir (utils.platform/no-backup-directory)
|
||||
:InstallationID installation-id
|
||||
:MailServerConfirmations config/mailserver-confirmations-enabled?
|
||||
:PFSEnabled (or config/pfs-encryption-enabled?
|
||||
;; We don't check dev-mode? here as
|
||||
;; otherwise we would have to restart the node
|
||||
;; when the user enables it
|
||||
config/group-chats-enabled?
|
||||
(config/pairing-enabled? true))}
|
||||
:PFSEnabled true}
|
||||
:RequireTopics (get-topics network))
|
||||
|
||||
(and
|
||||
|
|
|
@ -160,15 +160,15 @@
|
|||
:default-chat-icon (styles/default-chat-icon-profile colors/default-chat-color size)
|
||||
:default-chat-icon-text styles/default-chat-icon-text}])
|
||||
|
||||
(defn profile-icon-view [photo-path name color edit? size]
|
||||
(let [styles {:container {:width size :height size}
|
||||
:online-view styles/online-view-profile
|
||||
:online-dot-left styles/online-dot-left-profile
|
||||
:online-dot-right styles/online-dot-right-profile
|
||||
:size size
|
||||
:chat-icon styles/chat-icon-profile
|
||||
:default-chat-icon (styles/default-chat-icon-profile color size)
|
||||
:default-chat-icon-text styles/default-chat-icon-text}]
|
||||
(defn profile-icon-view [photo-path name color edit? size override-styles]
|
||||
(let [styles (merge {:container {:width size :height size}
|
||||
:online-view styles/online-view-profile
|
||||
:online-dot-left styles/online-dot-left-profile
|
||||
:online-dot-right styles/online-dot-right-profile
|
||||
:size size
|
||||
:chat-icon styles/chat-icon-profile
|
||||
:default-chat-icon (styles/default-chat-icon-profile color size)
|
||||
:default-chat-icon-text styles/default-chat-icon-text} override-styles)]
|
||||
[react/view (:container styles)
|
||||
(when edit?
|
||||
[react/view (styles/profile-icon-mask size)])
|
||||
|
@ -183,4 +183,4 @@
|
|||
edit? :edit?}]
|
||||
(let [color colors/default-chat-color
|
||||
size 56]
|
||||
[profile-icon-view photo-path name color edit? size]))
|
||||
[profile-icon-view photo-path name color edit? size {}]))
|
||||
|
|
|
@ -22,16 +22,13 @@
|
|||
:icon-opts {:color colors/blue}
|
||||
:on-press #(re-frame/dispatch [:navigate-to :new-chat])}]
|
||||
[action-button/action-separator]
|
||||
;; Hide behind flag (false by default), till everything is fixed in group chats
|
||||
(when config/group-chats-enabled?
|
||||
[action-button/action-button
|
||||
{:label (i18n/label :t/start-group-chat)
|
||||
:accessibility-label :start-group-chat-button
|
||||
:icon :icons/contacts
|
||||
:icon-opts {:color colors/blue}
|
||||
:on-press #(re-frame/dispatch [:contact.ui/start-group-chat-pressed])}])
|
||||
(when config/group-chats-enabled?
|
||||
[action-button/action-separator])
|
||||
[action-button/action-button
|
||||
{:label (i18n/label :t/start-group-chat)
|
||||
:accessibility-label :start-group-chat-button
|
||||
:icon :icons/contacts
|
||||
:icon-opts {:color colors/blue}
|
||||
:on-press #(re-frame/dispatch [:contact.ui/start-group-chat-pressed])}]
|
||||
[action-button/action-separator]
|
||||
[action-button/action-button
|
||||
{:label (i18n/label :t/new-public-group-chat)
|
||||
:accessibility-label :join-public-chat-button
|
||||
|
|
|
@ -233,7 +233,34 @@
|
|||
:text-align :center})
|
||||
|
||||
(def empty-chat-text-name
|
||||
{:color colors/black})
|
||||
{:margin-bottom 5
|
||||
:color colors/black})
|
||||
|
||||
(def join-button
|
||||
{:margin-bottom 5})
|
||||
{:margin-top 24
|
||||
:margin-bottom 15})
|
||||
|
||||
(def group-chat-icon
|
||||
{:color colors/white
|
||||
:font-size 40
|
||||
:font-weight :bold
|
||||
:line-height 55})
|
||||
|
||||
(def group-chat-join-footer
|
||||
{:position :absolute
|
||||
:justify-content :center
|
||||
:margin-bottom 30
|
||||
:bottom 0})
|
||||
|
||||
(def group-chat-join-name
|
||||
{:color :black
|
||||
:font-weight :bold
|
||||
:font-size 22})
|
||||
|
||||
(def group-chat-join-container
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def decline-chat
|
||||
{:color colors/blue})
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[status-im.ui.screens.chat.message.message :as message]
|
||||
[status-im.ui.screens.chat.message.options :as message-options]
|
||||
[status-im.ui.screens.chat.message.datemark :as message-datemark]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[status-im.ui.screens.chat.toolbar-content :as toolbar-content]
|
||||
[status-im.ui.components.animation :as animation]
|
||||
[status-im.ui.components.button.view :as buttons]
|
||||
|
@ -121,18 +122,35 @@
|
|||
(i18n/label :t/empty-chat-description))]])))
|
||||
|
||||
(defn join-chat-button [chat-id]
|
||||
[buttons/primary-button {:style style/join-button
|
||||
:on-press #(re-frame/dispatch [:group-chats.ui/join-pressed chat-id])}
|
||||
[buttons/secondary-button {:style style/join-button
|
||||
:on-press #(re-frame/dispatch [:group-chats.ui/join-pressed chat-id])}
|
||||
(i18n/label :t/join-group-chat)])
|
||||
|
||||
(defview group-chat-join-section [my-public-key {:keys [name chat-id] :as chat}]
|
||||
(defn decline-chat [chat-id]
|
||||
[react/touchable-highlight
|
||||
{:on-press
|
||||
#(re-frame/dispatch [:group-chats.ui/remove-chat-confirmed chat-id])}
|
||||
[react/text {:style style/decline-chat}
|
||||
(i18n/label :t/group-chat-decline-invitation)]])
|
||||
|
||||
(defview group-chat-join-section [my-public-key {:keys [name
|
||||
group-chat
|
||||
color
|
||||
chat-id] :as chat}]
|
||||
(letsubs [contact [:contacts/contact-by-identity (models.group-chats/get-inviter-pk my-public-key chat)]]
|
||||
[react/view style/empty-chat-container
|
||||
[join-chat-button chat-id]
|
||||
[react/text {:style style/empty-chat-text}
|
||||
[react/text style/empty-chat-container-one-to-one
|
||||
(i18n/label :t/join-group-chat-description {:username (:name contact)
|
||||
:group-name name})]]]))
|
||||
[react/view {:style {:margin-bottom 170}}
|
||||
[chat-icon.screen/profile-icon-view nil name color false 100 {:default-chat-icon-text style/group-chat-icon}]]
|
||||
[react/view {:style style/group-chat-join-footer}
|
||||
[react/view {:style style/group-chat-join-container}
|
||||
[react/view
|
||||
[react/text {:style style/group-chat-join-name} name]]
|
||||
[react/text {:style style/empty-chat-text}
|
||||
[react/text style/empty-chat-container-one-to-one
|
||||
(i18n/label :t/join-group-chat-description {:username (:name contact)
|
||||
:group-name name})]]
|
||||
[join-chat-button chat-id]
|
||||
[decline-chat chat-id]]]]))
|
||||
|
||||
(defview messages-view [{:keys [group-chat] :as chat} modal?]
|
||||
(letsubs [messages [:chats/current-chat-messages-stream]
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
(:require [status-im.ui.screens.desktop.main.views :as main.views]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.intro.views :as intro.views]
|
||||
[status-im.ui.screens.group.add-contacts.views :refer [contact-toggle-list
|
||||
add-participants-toggle-list]]
|
||||
[status-im.ui.screens.group.views :refer [new-group]]
|
||||
[status-im.ui.screens.group.views :refer [contact-toggle-list
|
||||
new-group
|
||||
add-participants-toggle-list]]
|
||||
[status-im.ui.screens.profile.group-chat.views :refer [group-chat-profile]]
|
||||
[status-im.ui.screens.accounts.create.views :as create.views]
|
||||
[status-im.ui.screens.accounts.login.views :as login.views]
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
(ns status-im.ui.screens.group.add-contacts.views
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.platform :as utils.platform]
|
||||
[status-im.ui.components.button.view :as buttons]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ui.components.contact.contact :refer [toggle-contact-view]]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.list-selection :as list-selection]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :refer [status-bar]]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.screens.group.styles :as styles]))
|
||||
|
||||
(defn- on-toggle [allow-new-users? checked? public-key]
|
||||
(cond
|
||||
|
||||
checked?
|
||||
(re-frame/dispatch [:deselect-contact public-key allow-new-users?])
|
||||
|
||||
;; Only allow new users if not reached the maximum
|
||||
(and (not checked?)
|
||||
allow-new-users?)
|
||||
(re-frame/dispatch [:select-contact public-key allow-new-users?])))
|
||||
|
||||
(defn- on-toggle-participant [allow-new-users? checked? public-key]
|
||||
(cond
|
||||
|
||||
checked?
|
||||
(re-frame/dispatch [:deselect-participant public-key allow-new-users?])
|
||||
|
||||
;; Only allow new users if not reached the maximum
|
||||
(and (not checked?)
|
||||
allow-new-users?)
|
||||
(re-frame/dispatch [:select-participant public-key allow-new-users?])))
|
||||
|
||||
(defn- group-toggle-contact [allow-new-users? contact]
|
||||
[toggle-contact-view
|
||||
contact
|
||||
:is-contact-selected?
|
||||
(partial on-toggle allow-new-users?)
|
||||
(and (not (:is-contact-selected? contact))
|
||||
(not allow-new-users?))])
|
||||
|
||||
(defn- group-toggle-participant [allow-new-users? contact]
|
||||
[toggle-contact-view
|
||||
contact
|
||||
:is-participant-selected?
|
||||
(partial on-toggle-participant allow-new-users?)
|
||||
;; Disable if not-checked and we don't allow new users
|
||||
(and (not (:is-participant-selected? contact))
|
||||
(not allow-new-users?))])
|
||||
|
||||
(defn- handle-invite-friends-pressed []
|
||||
(if utils.platform/desktop?
|
||||
(re-frame/dispatch [:navigate-to :new-contact])
|
||||
(list-selection/open-share {:message (i18n/label :t/get-status-at)})))
|
||||
|
||||
(defn- toggle-list-toolbar [{:keys [handler count label]} title]
|
||||
[toolbar/toolbar {}
|
||||
toolbar/default-nav-back
|
||||
[toolbar/content-title title]
|
||||
(when (pos? count)
|
||||
[toolbar/text-action {:handler handler
|
||||
:accessibility-label :next-button}
|
||||
label])])
|
||||
|
||||
(defn toggle-list [contacts render-function]
|
||||
[react/scroll-view {:flex 1}
|
||||
(if utils.platform/desktop?
|
||||
(for [contact contacts]
|
||||
^{:key (:public-key contact)}
|
||||
(render-function contact))
|
||||
[list/flat-list {:style styles/contacts-list
|
||||
:data contacts
|
||||
:key-fn :address
|
||||
:render-fn render-function
|
||||
:keyboardShouldPersistTaps :always}])])
|
||||
|
||||
(defn no-contacts []
|
||||
[react/view {:style {:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center}}
|
||||
[react/text
|
||||
{:style styles/no-contact-text}
|
||||
(i18n/label :t/group-chat-no-contacts)]
|
||||
[buttons/secondary-button {:on-press handle-invite-friends-pressed} (i18n/label :t/invite-friends)]])
|
||||
|
||||
(defn number-of-participants-disclaimer [number-of-participants-available]
|
||||
[react/view {:style styles/number-of-participants-disclaimer}
|
||||
[react/text (if (> number-of-participants-available
|
||||
0)
|
||||
(i18n/label-pluralize number-of-participants-available :t/available-participants)
|
||||
(i18n/label :t/no-more-participants-available))]])
|
||||
|
||||
;; Start group chat
|
||||
(defview contact-toggle-list []
|
||||
(letsubs [contacts [:contacts/all-added-people-contacts]
|
||||
selected-contacts-count [:selected-contacts-count]]
|
||||
[react/keyboard-avoiding-view {:style styles/group-container}
|
||||
[status-bar]
|
||||
[toggle-list-toolbar {:handler #(re-frame/dispatch [:navigate-to :new-group])
|
||||
:label (i18n/label :t/next)
|
||||
:count (pos? selected-contacts-count)}
|
||||
(i18n/label :t/group-chat)]
|
||||
(when (seq contacts)
|
||||
[number-of-participants-disclaimer (- (dec constants/max-group-chat-participants) selected-contacts-count)])
|
||||
(if (seq contacts)
|
||||
[toggle-list contacts (partial group-toggle-contact (< selected-contacts-count (dec constants/max-group-chat-participants)))]
|
||||
[no-contacts])]))
|
||||
|
||||
;; Add participants to existing group chat
|
||||
(defview add-participants-toggle-list []
|
||||
(letsubs [contacts [:contacts/all-contacts-not-in-current-chat]
|
||||
{:keys [name] :as current-chat} [:chats/current-chat]
|
||||
selected-contacts-count [:selected-participants-count]]
|
||||
(let [current-participants-count (count (:contacts current-chat))]
|
||||
[react/keyboard-avoiding-view {:style styles/group-container}
|
||||
[status-bar]
|
||||
[toggle-list-toolbar {:count selected-contacts-count
|
||||
:handler #(do
|
||||
(re-frame/dispatch [:group-chats.ui/add-members-pressed])
|
||||
(re-frame/dispatch [:navigate-back]))
|
||||
:label (i18n/label :t/add)}
|
||||
name]
|
||||
|
||||
[number-of-participants-disclaimer (- constants/max-group-chat-participants current-participants-count)]
|
||||
(when (seq contacts)
|
||||
[toggle-list contacts (partial group-toggle-participant (< (+ current-participants-count
|
||||
selected-contacts-count) constants/max-group-chat-participants))])])))
|
|
@ -30,3 +30,22 @@
|
|||
:font-size 12
|
||||
:margin-horizontal 17})
|
||||
|
||||
(def bottom-container
|
||||
{:padding-horizontal 12
|
||||
:padding-vertical 15})
|
||||
|
||||
(def toolbar-header-container
|
||||
{:align-items :center})
|
||||
|
||||
(def toolbar-header
|
||||
{:font-size 15
|
||||
:color colors/black})
|
||||
|
||||
(def toolbar-sub-header
|
||||
{:font-size 15
|
||||
:color colors/gray})
|
||||
|
||||
(def no-contacts
|
||||
{:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
(ns status-im.ui.screens.group.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [cljs.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.main-tabs.styles :as main-tabs.styles]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.platform :as utils.platform]
|
||||
[status-im.ui.components.contact.contact :refer [toggle-contact-view]]
|
||||
[status-im.ui.components.button.view :as buttons]
|
||||
[status-im.ui.components.list-selection :as list-selection]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
|
@ -12,38 +21,123 @@
|
|||
[status-im.ui.screens.add-new.styles :as add-new.styles]
|
||||
[status-im.ui.screens.group.styles :as styles]))
|
||||
|
||||
(views/defview group-name-view []
|
||||
(views/letsubs [new-group-name [:get :new-chat-name]]
|
||||
[react/view add-new.styles/input-container
|
||||
[react/text-input
|
||||
{:auto-focus true
|
||||
:on-change-text #(re-frame/dispatch [:set :new-chat-name %])
|
||||
:default-value new-group-name
|
||||
:placeholder (i18n/label :t/set-a-topic)
|
||||
:style add-new.styles/input
|
||||
:accessibility-label :chat-name-input}]]))
|
||||
(views/defview group-name-view [new-group-name]
|
||||
[react/view add-new.styles/input-container
|
||||
[react/text-input
|
||||
{:auto-focus true
|
||||
:on-change-text #(re-frame/dispatch [:set :new-chat-name %])
|
||||
:default-value new-group-name
|
||||
:placeholder (i18n/label :t/set-a-topic)
|
||||
:style add-new.styles/input
|
||||
:accessibility-label :chat-name-input}]])
|
||||
|
||||
(defn- render-contact [contact]
|
||||
[contact/contact-view {:contact contact
|
||||
:style styles/contact
|
||||
:accessibility-label :chat-member-item}])
|
||||
|
||||
(defn- toolbar [group-name save-btn-enabled?]
|
||||
(defn- toolbar [header sub-header]
|
||||
[toolbar/toolbar {}
|
||||
toolbar/default-nav-back
|
||||
[toolbar/content-title (i18n/label :t/group-chat)]
|
||||
(when save-btn-enabled?
|
||||
(let [handler #(re-frame/dispatch [:group-chats.ui/create-pressed group-name])]
|
||||
(if platform/android?
|
||||
[toolbar/actions [{:icon :icons/ok
|
||||
:icon-opts {:color :blue
|
||||
:accessibility-label :create-button}
|
||||
:handler handler}]]
|
||||
[toolbar/text-action {:handler handler
|
||||
:accessibility-label :create-button}
|
||||
(i18n/label :t/create)])))])
|
||||
[react/view {:style styles/toolbar-header-container}
|
||||
[react/view
|
||||
[react/text {:style styles/toolbar-header} header]]
|
||||
[react/view
|
||||
[react/text {:style styles/toolbar-sub-header} sub-header]]]])
|
||||
|
||||
;; New Group Chat
|
||||
(defn- on-toggle [allow-new-users? checked? public-key]
|
||||
(cond
|
||||
|
||||
checked?
|
||||
(re-frame/dispatch [:deselect-contact public-key allow-new-users?])
|
||||
|
||||
;; Only allow new users if not reached the maximum
|
||||
(and (not checked?)
|
||||
allow-new-users?)
|
||||
(re-frame/dispatch [:select-contact public-key allow-new-users?])))
|
||||
|
||||
(defn- on-toggle-participant [allow-new-users? checked? public-key]
|
||||
(cond
|
||||
|
||||
checked?
|
||||
(re-frame/dispatch [:deselect-participant public-key allow-new-users?])
|
||||
|
||||
;; Only allow new users if not reached the maximum
|
||||
(and (not checked?)
|
||||
allow-new-users?)
|
||||
(re-frame/dispatch [:select-participant public-key allow-new-users?])))
|
||||
|
||||
(defn- group-toggle-contact [allow-new-users? contact]
|
||||
[toggle-contact-view
|
||||
contact
|
||||
:is-contact-selected?
|
||||
(partial on-toggle allow-new-users?)
|
||||
(and (not (:is-contact-selected? contact))
|
||||
(not allow-new-users?))])
|
||||
|
||||
(defn- group-toggle-participant [allow-new-users? contact]
|
||||
[toggle-contact-view
|
||||
contact
|
||||
:is-participant-selected?
|
||||
(partial on-toggle-participant allow-new-users?)
|
||||
;; Disable if not-checked and we don't allow new users
|
||||
(and (not (:is-participant-selected? contact))
|
||||
(not allow-new-users?))])
|
||||
|
||||
(defn- handle-invite-friends-pressed []
|
||||
(if utils.platform/desktop?
|
||||
(re-frame/dispatch [:navigate-to :new-contact])
|
||||
(list-selection/open-share {:message (i18n/label :t/get-status-at)})))
|
||||
|
||||
(defn toggle-list [contacts render-function]
|
||||
[react/scroll-view {:flex 1}
|
||||
(if utils.platform/desktop?
|
||||
(for [contact contacts]
|
||||
^{:key (:public-key contact)}
|
||||
(render-function contact))
|
||||
[list/flat-list {:style styles/contacts-list
|
||||
:data contacts
|
||||
:key-fn :address
|
||||
:render-fn render-function
|
||||
:keyboardShouldPersistTaps :always}])])
|
||||
|
||||
(defn no-contacts []
|
||||
[react/view {:style styles/no-contacts}
|
||||
[react/text
|
||||
{:style styles/no-contact-text}
|
||||
(i18n/label :t/group-chat-no-contacts)]
|
||||
[buttons/secondary-button {:on-press handle-invite-friends-pressed} (i18n/label :t/invite-friends)]])
|
||||
|
||||
(views/defview bottom-container [{:keys [on-press disabled label]}]
|
||||
[react/view {:style main-tabs.styles/tabs-container}
|
||||
[react/view {:style components.styles/flex}]
|
||||
[react/view {:style styles/bottom-container}
|
||||
[components.common/bottom-button
|
||||
{:forward? true
|
||||
:accessibility-label :next-button
|
||||
:label label
|
||||
:disabled? disabled
|
||||
:on-press on-press}]]])
|
||||
|
||||
;; Start group chat
|
||||
(views/defview contact-toggle-list []
|
||||
(views/letsubs [contacts [:contacts/all-added-people-contacts]
|
||||
selected-contacts-count [:selected-contacts-count]]
|
||||
[react/keyboard-avoiding-view {:style styles/group-container}
|
||||
[status-bar/status-bar]
|
||||
[toolbar
|
||||
(i18n/label :t/new-group-chat)
|
||||
(i18n/label :t/group-chat-members-count
|
||||
{:selected selected-contacts-count
|
||||
:max (dec constants/max-group-chat-participants)})]
|
||||
(if (seq contacts)
|
||||
[toggle-list contacts (partial group-toggle-contact (< selected-contacts-count (dec constants/max-group-chat-participants)))]
|
||||
[no-contacts])
|
||||
[bottom-container {:on-press #(re-frame/dispatch [:navigate-to :new-group])
|
||||
:disabled (zero? selected-contacts-count)
|
||||
:label (i18n/label :t/next)}]]))
|
||||
|
||||
;; Set name of new group-chat
|
||||
(views/defview new-group []
|
||||
(views/letsubs [contacts [:selected-group-contacts]
|
||||
group-name [:get :new-chat-name]]
|
||||
|
@ -51,13 +145,42 @@
|
|||
[react/keyboard-avoiding-view (merge {:behavior :padding}
|
||||
styles/group-container)
|
||||
[status-bar/status-bar]
|
||||
[toolbar group-name save-btn-enabled?]
|
||||
[toolbar
|
||||
(i18n/label :t/new-group-chat)
|
||||
(i18n/label :t/group-chat-members-count
|
||||
{:selected (count contacts)
|
||||
:max (dec constants/max-group-chat-participants)})]
|
||||
[group-name-view]
|
||||
[list/list-with-label {:flex 1}
|
||||
(i18n/label :t/members-title)
|
||||
[list/flat-list {:data contacts
|
||||
:key-fn :address
|
||||
:render-fn render-contact
|
||||
:bounces false
|
||||
:keyboard-should-persist-taps :always
|
||||
:enable-empty-sections true}]]])))
|
||||
[react/scroll-view
|
||||
[list/list-with-label {:flex 1}
|
||||
(i18n/label :t/members-title)
|
||||
[list/flat-list {:data contacts
|
||||
:key-fn :address
|
||||
:render-fn render-contact
|
||||
:bounces false
|
||||
:keyboard-should-persist-taps :always
|
||||
:enable-empty-sections true}]]]
|
||||
[bottom-container {:on-press #(re-frame/dispatch [:group-chats.ui/create-pressed group-name])
|
||||
:disabled (string/blank? group-name)
|
||||
:label (i18n/label :t/create-group-chat)}]])))
|
||||
|
||||
;; Add participants to existing group chat
|
||||
(views/defview add-participants-toggle-list []
|
||||
(views/letsubs [contacts [:contacts/all-contacts-not-in-current-chat]
|
||||
{:keys [name] :as current-chat} [:chats/current-chat]
|
||||
selected-contacts-count [:selected-participants-count]]
|
||||
(let [current-participants-count (count (:contacts current-chat))]
|
||||
[react/keyboard-avoiding-view {:style styles/group-container}
|
||||
[status-bar/status-bar]
|
||||
[toolbar
|
||||
name
|
||||
(i18n/label :t/group-chat-members-count
|
||||
{:selected (dec (+ current-participants-count selected-contacts-count))
|
||||
:max (dec constants/max-group-chat-participants)})]
|
||||
(when (seq contacts)
|
||||
[toggle-list contacts (partial group-toggle-participant (< (+ current-participants-count
|
||||
selected-contacts-count) constants/max-group-chat-participants))])
|
||||
[bottom-container {:on-press
|
||||
#(re-frame/dispatch [:group-chats.ui/add-members-pressed])
|
||||
:disabled (zero? selected-contacts-count)
|
||||
:label (i18n/label :t/add)}]])))
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
|
||||
[status-im.ui.screens.qr-scanner.views :refer [qr-scanner]]
|
||||
|
||||
[status-im.ui.screens.group.views :refer [new-group]]
|
||||
[status-im.ui.screens.group.add-contacts.views :refer [contact-toggle-list
|
||||
add-participants-toggle-list]]
|
||||
[status-im.ui.screens.group.views :refer [new-group
|
||||
contact-toggle-list
|
||||
add-participants-toggle-list]]
|
||||
[status-im.ui.screens.profile.user.views :as profile.user]
|
||||
[status-im.ui.screens.profile.contact.views :as profile.contact]
|
||||
[status-im.ui.screens.profile.group-chat.views :as profile.group-chat]
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
(def bootnodes-settings-enabled? (enabled? (get-config :BOOTNODES_SETTINGS_ENABLED "1")))
|
||||
(def rpc-networks-only? (enabled? (get-config :RPC_NETWORKS_ONLY "1")))
|
||||
(def group-chats-enabled? (enabled? (get-config :GROUP_CHATS_ENABLED "0")))
|
||||
(def group-chats-publish-to-topic? (enabled? (get-config :GROUP_CHATS_PUBLISH_TO_TOPIC "0")))
|
||||
(defn pairing-enabled? [dev-mode?]
|
||||
(and (enabled? (get-config :PAIRING_ENABLED "0"))
|
||||
(or dev-mode? platform/desktop?)))
|
||||
|
|
|
@ -15,17 +15,4 @@
|
|||
cofx {:db {:accounts/accounts {address {:installation-id "id"}}}}]
|
||||
(testing "installation-id"
|
||||
(let [actual (parse-node-config (node/start cofx address))]
|
||||
(is (= "id" (:InstallationID actual)))))
|
||||
(testing "pfs & group chats disabled"
|
||||
(with-redefs [config/pfs-encryption-enabled? false
|
||||
config/group-chats-enabled? false]
|
||||
(let [actual (parse-node-config (node/start cofx address))]
|
||||
(is (not (:PFSEnabled actual)))))
|
||||
(testing "pfs is enabled"
|
||||
(with-redefs [config/pfs-encryption-enabled? true]
|
||||
(let [actual (parse-node-config (node/start cofx address))]
|
||||
(is (:PFSEnabled actual)))))
|
||||
(testing "group chats is enabled"
|
||||
(with-redefs [config/group-chats-enabled? true]
|
||||
(let [actual (parse-node-config (node/start cofx address))]
|
||||
(is (:PFSEnabled actual))))))))
|
||||
(is (= "id" (:InstallationID actual)))))))
|
||||
|
|
|
@ -47,7 +47,10 @@
|
|||
},
|
||||
"no-more-participants-available": "You can't add anymore participants",
|
||||
"join-group-chat-description": "{{username}} invited you to join the group {{group-name}}",
|
||||
"join-group-chat": "Join chat",
|
||||
"join-group-chat": "Join group",
|
||||
"create-group-chat": "Create group chat",
|
||||
"group-chat-decline-invitation": "Decline invitation",
|
||||
"group-chat-members-count": "{{selected}}/{{max}} members",
|
||||
"group-chat-created": "*{{member}}* created the group *{{name}}*",
|
||||
"group-chat-admin": "Admin",
|
||||
"group-chat-name-changed": "*{{member}}* changed the group's name to *{{name}}*",
|
||||
|
|
Loading…
Reference in New Issue