mirror of
https://github.com/status-im/status-react.git
synced 2025-01-11 19:44:47 +00:00
refactored new-group events using fx and cofx
reorganized modules structure, renamed files, improved requirements
This commit is contained in:
parent
d9800fe9a7
commit
b429076cad
@ -28,17 +28,16 @@
|
|||||||
[status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]]
|
[status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]]
|
||||||
[status-im.transactions.screens.transaction-details :refer [transaction-details]]
|
[status-im.transactions.screens.transaction-details :refer [transaction-details]]
|
||||||
[status-im.chats-list.screen :refer [chats-list]]
|
[status-im.chats-list.screen :refer [chats-list]]
|
||||||
[status-im.new-chat.screen :refer [new-chat]]
|
[status-im.chat.new-chat.view :refer [new-chat]]
|
||||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
[status-im.chat.new-public-chat.view :refer [new-public-chat]]
|
||||||
[status-im.new-group.screen-private :refer [new-group
|
[status-im.group.views :refer [new-group edit-contact-group]]
|
||||||
edit-group]]
|
[status-im.group.chat-settings.views :refer [chat-group-settings]]
|
||||||
[status-im.new-group.views.chat-group-settings :refer [chat-group-settings]]
|
[status-im.group.edit-contacts.views :refer [edit-contact-group-contact-list
|
||||||
[status-im.new-group.views.contact-list :refer [edit-group-contact-list
|
|
||||||
edit-chat-group-contact-list]]
|
edit-chat-group-contact-list]]
|
||||||
[status-im.new-group.views.contact-toggle-list :refer [contact-toggle-list
|
[status-im.group.add-contacts.views :refer [contact-toggle-list
|
||||||
add-contacts-toggle-list
|
add-contacts-toggle-list
|
||||||
add-participants-toggle-list]]
|
add-participants-toggle-list]]
|
||||||
[status-im.new-group.views.reorder-groups :refer [reorder-groups]]
|
[status-im.group.reorder.views :refer [reorder-groups]]
|
||||||
[status-im.profile.screen :refer [profile my-profile]]
|
[status-im.profile.screen :refer [profile my-profile]]
|
||||||
[status-im.profile.edit.screen :refer [edit-my-profile]]
|
[status-im.profile.edit.screen :refer [edit-my-profile]]
|
||||||
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
|
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
|
||||||
@ -127,13 +126,13 @@
|
|||||||
:chat-list main-tabs
|
:chat-list main-tabs
|
||||||
:new-chat new-chat
|
:new-chat new-chat
|
||||||
:new-group new-group
|
:new-group new-group
|
||||||
:edit-group edit-group
|
:edit-contact-group edit-contact-group
|
||||||
:chat-group-settings chat-group-settings
|
:chat-group-settings chat-group-settings
|
||||||
:add-contacts-toggle-list add-contacts-toggle-list
|
:add-contacts-toggle-list add-contacts-toggle-list
|
||||||
:add-participants-toggle-list add-participants-toggle-list
|
:add-participants-toggle-list add-participants-toggle-list
|
||||||
:edit-group-contact-list edit-group-contact-list
|
:edit-group-contact-list edit-contact-group-contact-list
|
||||||
:edit-chat-group-contact-list edit-chat-group-contact-list
|
:edit-chat-group-contact-list edit-chat-group-contact-list
|
||||||
:new-public-group new-public-group
|
:new-public-chat new-public-chat
|
||||||
:contact-list main-tabs
|
:contact-list main-tabs
|
||||||
:contact-toggle-list contact-toggle-list
|
:contact-toggle-list contact-toggle-list
|
||||||
:group-contacts contact-list
|
:group-contacts contact-list
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(ns status-im.chat.handlers
|
(ns status-im.chat.handlers
|
||||||
(:require-macros [cljs.core.async.macros :as am])
|
(:require-macros [cljs.core.async.macros :as am])
|
||||||
(:require [re-frame.core :refer [enrich after debug dispatch]]
|
(:require [re-frame.core :refer [enrich after debug dispatch reg-fx]]
|
||||||
[status-im.models.commands :as commands]
|
[status-im.models.commands :as commands]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[status-im.components.styles :refer [default-chat-color]]
|
[status-im.components.styles :refer [default-chat-color]]
|
||||||
@ -20,7 +20,7 @@
|
|||||||
[status-im.utils.random :as random]
|
[status-im.utils.random :as random]
|
||||||
[status-im.chat.sign-up :as sign-up-service]
|
[status-im.chat.sign-up :as sign-up-service]
|
||||||
[status-im.navigation.handlers :as nav]
|
[status-im.navigation.handlers :as nav]
|
||||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
||||||
[status-im.handlers.server :as server]
|
[status-im.handlers.server :as server]
|
||||||
[status-im.utils.phone-number :refer [format-phone-number
|
[status-im.utils.phone-number :refer [format-phone-number
|
||||||
valid-mobile-number?]]
|
valid-mobile-number?]]
|
||||||
@ -389,6 +389,11 @@
|
|||||||
[db [_ chat-id]]
|
[db [_ chat-id]]
|
||||||
(update db :chats dissoc chat-id))
|
(update db :chats dissoc chat-id))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::delete-messages
|
||||||
|
(fn [id]
|
||||||
|
(messages/delete-by-chat-id id)))
|
||||||
|
|
||||||
(defn delete-messages!
|
(defn delete-messages!
|
||||||
[{:keys [current-chat-id]} [_ chat-id]]
|
[{:keys [current-chat-id]} [_ chat-id]]
|
||||||
(let [id (or chat-id current-chat-id)]
|
(let [id (or chat-id current-chat-id)]
|
||||||
@ -530,3 +535,38 @@
|
|||||||
(if (= network-status :offline)
|
(if (= network-status :offline)
|
||||||
(chats/inc-message-overhead chat-id)
|
(chats/inc-message-overhead chat-id)
|
||||||
(chats/reset-message-overhead chat-id)))))
|
(chats/reset-message-overhead chat-id)))))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::save-public-chat
|
||||||
|
(fn [chat]
|
||||||
|
(chats/save chat)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::start-watching-group
|
||||||
|
(fn [{:keys [group-id web3 current-public-key keypair]}]
|
||||||
|
(protocol/start-watching-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group-id group-id
|
||||||
|
:identity current-public-key
|
||||||
|
:keypair keypair
|
||||||
|
:callback #(dispatch [:incoming-message %1 %2])})))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:create-new-public-chat
|
||||||
|
(fn [{:keys [db]} [_ topic]]
|
||||||
|
(let [exists? (boolean (get-in db [:chats topic]))
|
||||||
|
chat {:chat-id topic
|
||||||
|
:name topic
|
||||||
|
:color default-chat-color
|
||||||
|
:group-chat true
|
||||||
|
:public? true
|
||||||
|
:is-active true
|
||||||
|
:timestamp (random/timestamp)}]
|
||||||
|
(merge
|
||||||
|
(when-not exists?
|
||||||
|
{:db (assoc-in db [:chats (:chat-id chat)] chat)
|
||||||
|
::save-public-chat chat
|
||||||
|
::start-watching-group (merge {:group-id topic}
|
||||||
|
(select-keys db [:web3 :current-public-key]))})
|
||||||
|
{:dispatch-n [[:navigate-to-clean :chat-list]
|
||||||
|
[:navigate-to :chat topic]]}))))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(ns status-im.new-chat.styles
|
(ns status-im.chat.new-chat.styles
|
||||||
(:require [status-im.components.styles :as common]))
|
(:require [status-im.components.styles :as common]))
|
||||||
|
|
||||||
(def contacts-list-container
|
(def contacts-list-container
|
73
src/status_im/chat/new_chat/view.cljs
Normal file
73
src/status_im/chat/new_chat/view.cljs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
(ns status-im.chat.new-chat.view
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
|
[status-im.components.common.common :as common]
|
||||||
|
[status-im.components.renderers.renderers :as renderers]
|
||||||
|
[status-im.components.action-button.action-button :refer [action-button
|
||||||
|
action-separator]]
|
||||||
|
[status-im.components.action-button.styles :refer [actions-list]]
|
||||||
|
[status-im.components.react :refer [view text list-view list-item]]
|
||||||
|
[status-im.components.contact.contact :refer [contact-view]]
|
||||||
|
[status-im.components.status-bar :refer [status-bar]]
|
||||||
|
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
||||||
|
[status-im.components.drawer.view :refer [drawer-view]]
|
||||||
|
[status-im.chat.new-chat.styles :as styles]
|
||||||
|
[status-im.utils.listview :as lw]
|
||||||
|
[status-im.i18n :refer [label]]))
|
||||||
|
|
||||||
|
(defn options-list []
|
||||||
|
[view actions-list
|
||||||
|
[action-button (label :t/new-group-chat)
|
||||||
|
:private_group_big
|
||||||
|
#(dispatch [:open-contact-toggle-list :chat-group])]
|
||||||
|
[action-separator]
|
||||||
|
[action-button (label :t/new-public-group-chat)
|
||||||
|
:public_group_big
|
||||||
|
#(dispatch [:navigate-to :new-public-chat])]
|
||||||
|
[action-separator]
|
||||||
|
[action-button (label :t/add-new-contact)
|
||||||
|
:add_blue
|
||||||
|
#(dispatch [:navigate-to :new-contact])]])
|
||||||
|
|
||||||
|
(defn contact-list-row []
|
||||||
|
(fn [row _ _]
|
||||||
|
(list-item ^{:key row}
|
||||||
|
[contact-view {:contact row
|
||||||
|
:on-press #(dispatch [:open-chat-with-contact %])}])))
|
||||||
|
|
||||||
|
(defview new-chat-toolbar []
|
||||||
|
(letsubs [show-search [:get-in [:toolbar-search :show]]
|
||||||
|
search-text [:get-in [:toolbar-search :text]]]
|
||||||
|
[view
|
||||||
|
[status-bar]
|
||||||
|
(toolbar-with-search
|
||||||
|
{:show-search? (= show-search :contact-list)
|
||||||
|
:search-text search-text
|
||||||
|
:search-key :contact-list
|
||||||
|
:title (label :t/contacts-group-new-chat)
|
||||||
|
:search-placeholder (label :t/search-for)})]))
|
||||||
|
|
||||||
|
(defview new-chat []
|
||||||
|
(letsubs [contacts [:all-added-group-contacts-filtered]
|
||||||
|
params [:get :contacts/click-params]]
|
||||||
|
[drawer-view
|
||||||
|
[view styles/contacts-list-container
|
||||||
|
[new-chat-toolbar]
|
||||||
|
(when contacts
|
||||||
|
[list-view {:dataSource (lw/to-datasource contacts)
|
||||||
|
:enableEmptySections true
|
||||||
|
:renderRow (contact-list-row)
|
||||||
|
:bounces false
|
||||||
|
:keyboardShouldPersistTaps :always
|
||||||
|
:renderHeader #(list-item
|
||||||
|
[view
|
||||||
|
[options-list]
|
||||||
|
[common/bottom-shadow]
|
||||||
|
[common/form-title (label :t/choose-from-contacts)
|
||||||
|
{:count-value (count contacts)}]
|
||||||
|
[common/list-header]])
|
||||||
|
:renderSeparator renderers/list-separator-renderer
|
||||||
|
:renderFooter #(list-item [view
|
||||||
|
[common/list-footer]
|
||||||
|
[common/bottom-shadow]])
|
||||||
|
:style styles/contacts-list}])]]))
|
20
src/status_im/chat/new_public_chat/db.cljs
Normal file
20
src/status_im/chat/new_public_chat/db.cljs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
(ns status-im.chat.new-public-chat.db
|
||||||
|
(:require [cljs.spec.alpha :as spec]
|
||||||
|
[status-im.constants :refer [console-chat-id wallet-chat-id]]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[status-im.utils.homoglyph :as utils]))
|
||||||
|
|
||||||
|
(defn legal-name? [username]
|
||||||
|
(let [username (some-> username string/trim)]
|
||||||
|
(and (not (utils/matches username console-chat-id))
|
||||||
|
(not (utils/matches username wallet-chat-id)))))
|
||||||
|
|
||||||
|
(spec/def ::legal-name legal-name?)
|
||||||
|
(spec/def ::not-empty-string (spec/and string? not-empty))
|
||||||
|
|
||||||
|
(spec/def ::name (spec/and ::not-empty-string
|
||||||
|
::legal-name))
|
||||||
|
|
||||||
|
(spec/def ::topic (spec/and ::not-empty-string
|
||||||
|
::legal-name
|
||||||
|
(partial re-matches #"[a-z0-9\-]+")))
|
46
src/status_im/chat/new_public_chat/styles.cljs
Normal file
46
src/status_im/chat/new_public_chat/styles.cljs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
(ns status-im.chat.new-public-chat.styles
|
||||||
|
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||||
|
(:require [status-im.components.styles :as common]))
|
||||||
|
|
||||||
|
(def group-chat-name-input
|
||||||
|
{:font-size 17
|
||||||
|
:padding-bottom 0
|
||||||
|
:letter-spacing -0.2
|
||||||
|
:color common/text1-color})
|
||||||
|
|
||||||
|
(defstyle group-chat-topic-input
|
||||||
|
{:font-size 14
|
||||||
|
:line-height 16
|
||||||
|
:color common/text1-color
|
||||||
|
:padding-left 13
|
||||||
|
:ios {:padding-bottom 0}})
|
||||||
|
|
||||||
|
(defstyle topic-hash-style
|
||||||
|
{:width 10
|
||||||
|
:position :absolute
|
||||||
|
:android {:top 8 :left 3}
|
||||||
|
:ios {:top 6 :left 3}})
|
||||||
|
|
||||||
|
(def topic-hash
|
||||||
|
(merge group-chat-name-input
|
||||||
|
topic-hash-style))
|
||||||
|
|
||||||
|
(def group-chat-name-wrapper
|
||||||
|
{:padding-top 0
|
||||||
|
:height 40
|
||||||
|
:padding-bottom 0})
|
||||||
|
|
||||||
|
(def group-container
|
||||||
|
{:flex 1
|
||||||
|
:flex-direction :column
|
||||||
|
:background-color common/color-white})
|
||||||
|
|
||||||
|
(def chat-name-container
|
||||||
|
{:padding-left 16
|
||||||
|
:margin-top 10})
|
||||||
|
|
||||||
|
(defstyle members-text
|
||||||
|
{:color common/color-gray4
|
||||||
|
:ios {:letter-spacing -0.2
|
||||||
|
:font-size 16}
|
||||||
|
:android {:font-size 14}})
|
57
src/status_im/chat/new_public_chat/view.cljs
Normal file
57
src/status_im/chat/new_public_chat/view.cljs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
(ns status-im.chat.new-public-chat.view
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
|
[status-im.components.react :refer [view text]]
|
||||||
|
[status-im.components.text-field.view :refer [text-field]]
|
||||||
|
[status-im.components.styles :as common]
|
||||||
|
[status-im.components.status-bar :refer [status-bar]]
|
||||||
|
[status-im.components.toolbar.view :refer [toolbar]]
|
||||||
|
[status-im.chat.new-public-chat.styles :as styles]
|
||||||
|
[status-im.chat.new-public-chat.db :as v]
|
||||||
|
[status-im.i18n :refer [label]]
|
||||||
|
[cljs.spec.alpha :as spec]))
|
||||||
|
|
||||||
|
(defview new-public-chat-toolbar []
|
||||||
|
(letsubs [topic [:get :public-group-topic]]
|
||||||
|
(let [create-btn-enabled? (spec/valid? ::v/topic topic)]
|
||||||
|
[view
|
||||||
|
[status-bar]
|
||||||
|
[toolbar
|
||||||
|
{:title (label :t/new-public-group-chat)
|
||||||
|
:actions [{:image {:source {:uri (if create-btn-enabled?
|
||||||
|
:icon_ok_blue
|
||||||
|
:icon_ok_disabled)}
|
||||||
|
:style common/icon-ok}
|
||||||
|
:handler (when create-btn-enabled?
|
||||||
|
#(dispatch [:create-new-public-chat topic]))}]}]])))
|
||||||
|
|
||||||
|
(defview chat-name-input []
|
||||||
|
(letsubs [topic [:get :public-group-topic]]
|
||||||
|
[view
|
||||||
|
[text-field
|
||||||
|
{:error (cond
|
||||||
|
(not (spec/valid? ::v/not-empty-string topic))
|
||||||
|
(label :t/empty-topic)
|
||||||
|
|
||||||
|
(not (spec/valid? ::v/topic topic))
|
||||||
|
(label :t/topic-format))
|
||||||
|
:wrapper-style styles/group-chat-name-wrapper
|
||||||
|
:error-color common/color-blue
|
||||||
|
:line-color common/color-gray4
|
||||||
|
:label-hidden? true
|
||||||
|
:input-style styles/group-chat-topic-input
|
||||||
|
:auto-focus true
|
||||||
|
:on-change-text #(dispatch [:set :public-group-topic %])
|
||||||
|
:value topic
|
||||||
|
:validator #(re-matches #"[a-z\-]*" %)
|
||||||
|
:auto-capitalize :none}]
|
||||||
|
[text {:style styles/topic-hash} "#"]]))
|
||||||
|
|
||||||
|
(defn new-public-chat []
|
||||||
|
[view styles/group-container
|
||||||
|
[new-public-chat-toolbar]
|
||||||
|
[view styles/chat-name-container
|
||||||
|
[text {:style styles/members-text
|
||||||
|
:font :medium}
|
||||||
|
(label :t/public-group-topic)]
|
||||||
|
[chat-name-input]]])
|
@ -68,7 +68,7 @@
|
|||||||
:icon :settings
|
:icon :settings
|
||||||
:icon-style {:width 20
|
:icon-style {:width 20
|
||||||
:height 13}
|
:height 13}
|
||||||
:handler #(dispatch [:show-group-settings])})
|
:handler #(dispatch [:show-group-chat-settings])})
|
||||||
|
|
||||||
(defn group-chat-items [members public?]
|
(defn group-chat-items [members public?]
|
||||||
(into (if public? [] [(item-members members)])
|
(into (if public? [] [(item-members members)])
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
[status-im.components.tabs.bottom-shadow :refer [bottom-shadow-view]]
|
[status-im.components.tabs.bottom-shadow :refer [bottom-shadow-view]]
|
||||||
[status-im.chats-list.screen :refer [chats-list]]
|
[status-im.chats-list.screen :refer [chats-list]]
|
||||||
[status-im.discover.screen :refer [discover]]
|
[status-im.discover.screen :refer [discover]]
|
||||||
[status-im.contacts.views :refer [contact-list]]
|
[status-im.contacts.views :refer [contact-groups-list]]
|
||||||
[status-im.components.tabs.tabs :refer [tabs]]
|
[status-im.components.tabs.tabs :refer [tabs]]
|
||||||
[status-im.components.tabs.styles :as st]
|
[status-im.components.tabs.styles :as st]
|
||||||
[status-im.components.styles :as common-st]
|
[status-im.components.styles :as common-st]
|
||||||
@ -31,7 +31,7 @@
|
|||||||
:index 1}
|
:index 1}
|
||||||
{:view-id :contact-list
|
{:view-id :contact-list
|
||||||
:title (label :t/contacts)
|
:title (label :t/contacts)
|
||||||
:screen contact-list
|
:screen contact-groups-list
|
||||||
:icon-inactive :icon_contacts
|
:icon-inactive :icon_contacts
|
||||||
:icon-active :icon_contacts_active
|
:icon-active :icon_contacts_active
|
||||||
:index 2}])
|
:index 2}])
|
||||||
@ -109,7 +109,7 @@
|
|||||||
:on-momentum-scroll-end (on-scroll-end swiped? scroll-ended @view-id)})
|
:on-momentum-scroll-end (on-scroll-end swiped? scroll-ended @view-id)})
|
||||||
[chats-list]
|
[chats-list]
|
||||||
[discover (= @view-id :discover)]
|
[discover (= @view-id :discover)]
|
||||||
[contact-list (= @view-id :contact-list)]]
|
[contact-groups-list (= @view-id :contact-list)]]
|
||||||
[tabs {:selected-view-id @view-id
|
[tabs {:selected-view-id @view-id
|
||||||
:prev-view-id @prev-view-id
|
:prev-view-id @prev-view-id
|
||||||
:tab-list tab-list}]
|
:tab-list tab-list}]
|
||||||
|
@ -56,8 +56,7 @@
|
|||||||
|
|
||||||
(defview contact-list []
|
(defview contact-list []
|
||||||
(letsubs [edit? [:get-in [:contacts/list-ui-props :edit?]]
|
(letsubs [edit? [:get-in [:contacts/list-ui-props :edit?]]
|
||||||
group [:get :contacts-group]
|
group [:get-contact-group]]
|
||||||
type [:get :group-type]]
|
|
||||||
[drawer-view
|
[drawer-view
|
||||||
[view {:flex 1}
|
[view {:flex 1}
|
||||||
[view
|
[view
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
(ns status-im.contacts.db
|
(ns status-im.contacts.db
|
||||||
(:require-macros [status-im.utils.db :refer [allowed-keys]])
|
(:require-macros [status-im.utils.db :refer [allowed-keys]])
|
||||||
(:require [cljs.spec.alpha :as s]
|
(:require [cljs.spec.alpha :as spec]
|
||||||
[clojure.string :as str]
|
[clojure.string :as string]
|
||||||
[status-im.data-store.contacts :as contacts]
|
[status-im.data-store.contacts :as contacts]
|
||||||
[status-im.js-dependencies :as dependencies]))
|
[status-im.js-dependencies :as dependencies]))
|
||||||
|
|
||||||
@ -14,7 +14,7 @@
|
|||||||
(.isAddress dependencies/Web3.prototype s))
|
(.isAddress dependencies/Web3.prototype s))
|
||||||
|
|
||||||
(defn hex-string? [s]
|
(defn hex-string? [s]
|
||||||
(let [s' (if (str/starts-with? s "0x")
|
(let [s' (if (string/starts-with? s "0x")
|
||||||
(subs s 2)
|
(subs s 2)
|
||||||
s)]
|
s)]
|
||||||
(boolean (re-matches #"(?i)[0-9a-f]+" s'))))
|
(boolean (re-matches #"(?i)[0-9a-f]+" s'))))
|
||||||
@ -24,45 +24,45 @@
|
|||||||
(and
|
(and
|
||||||
(hex-string? identity)
|
(hex-string? identity)
|
||||||
(or
|
(or
|
||||||
(and (= 128 length) (not (str/includes? identity "0x")))
|
(and (= 128 length) (not (string/includes? identity "0x")))
|
||||||
(and (= 130 length) (str/starts-with? identity "0x"))
|
(and (= 130 length) (string/starts-with? identity "0x"))
|
||||||
(and (= 132 length) (str/starts-with? identity "0x04"))
|
(and (= 132 length) (string/starts-with? identity "0x04"))
|
||||||
(is-address? identity)))))
|
(is-address? identity)))))
|
||||||
|
|
||||||
(s/def ::not-empty-string (s/and string? not-empty))
|
(spec/def ::not-empty-string (spec/and string? not-empty))
|
||||||
(s/def ::public-key (s/and ::not-empty-string valid-length?))
|
(spec/def ::public-key (spec/and ::not-empty-string valid-length?))
|
||||||
|
|
||||||
;;;; DB
|
;;;; DB
|
||||||
|
|
||||||
;;Contact
|
;;Contact
|
||||||
|
|
||||||
;we can't validate public key, because for dapps whisper-identity is just string
|
;we can't validate public key, because for dapps whisper-identity is just string
|
||||||
(s/def :contact/whisper-identity ::not-empty-string)
|
(spec/def :contact/whisper-identity ::not-empty-string)
|
||||||
(s/def :contact/name ::not-empty-string)
|
(spec/def :contact/name ::not-empty-string)
|
||||||
(s/def :contact/address (s/nilable is-address?))
|
(spec/def :contact/address (spec/nilable is-address?))
|
||||||
(s/def :contact/private-key (s/nilable string?))
|
(spec/def :contact/private-key (spec/nilable string?))
|
||||||
(s/def :contact/public-key (s/nilable string?))
|
(spec/def :contact/public-key (spec/nilable string?))
|
||||||
(s/def :contact/photo-path (s/nilable string?))
|
(spec/def :contact/photo-path (spec/nilable string?))
|
||||||
(s/def :contact/status (s/nilable string?))
|
(spec/def :contact/status (spec/nilable string?))
|
||||||
|
|
||||||
(s/def :contact/last-updated (s/nilable int?))
|
(spec/def :contact/last-updated (spec/nilable int?))
|
||||||
(s/def :contact/last-online (s/nilable int?))
|
(spec/def :contact/last-online (spec/nilable int?))
|
||||||
(s/def :contact/pending? boolean?)
|
(spec/def :contact/pending? boolean?)
|
||||||
(s/def :contact/unremovable? boolean?)
|
(spec/def :contact/unremovable? boolean?)
|
||||||
|
|
||||||
(s/def :contact/dapp? boolean?)
|
(spec/def :contact/dapp? boolean?)
|
||||||
(s/def :contact/dapp-url (s/nilable string?))
|
(spec/def :contact/dapp-url (spec/nilable string?))
|
||||||
(s/def :contact/dapp-hash (s/nilable int?))
|
(spec/def :contact/dapp-hash (spec/nilable int?))
|
||||||
(s/def :contact/bot-url (s/nilable string?))
|
(spec/def :contact/bot-url (spec/nilable string?))
|
||||||
(s/def :contact/global-command (s/nilable map?))
|
(spec/def :contact/global-command (spec/nilable map?))
|
||||||
(s/def :contact/commands (s/nilable (s/map-of keyword? map?)))
|
(spec/def :contact/commands (spec/nilable (spec/map-of keyword? map?)))
|
||||||
(s/def :contact/responses (s/nilable (s/map-of keyword? map?)))
|
(spec/def :contact/responses (spec/nilable (spec/map-of keyword? map?)))
|
||||||
(s/def :contact/commands-loaded? (s/nilable boolean?))
|
(spec/def :contact/commands-loaded? (spec/nilable boolean?))
|
||||||
(s/def :contact/subscriptions (s/nilable map?))
|
(spec/def :contact/subscriptions (spec/nilable map?))
|
||||||
;true when contact added using status-dev-cli
|
;true when contact added using status-dev-cli
|
||||||
(s/def :contact/debug? boolean?)
|
(spec/def :contact/debug? boolean?)
|
||||||
|
|
||||||
(s/def :contact/contact (allowed-keys
|
(spec/def :contact/contact (allowed-keys
|
||||||
:req-un [:contact/name :contact/whisper-identity]
|
:req-un [:contact/name :contact/whisper-identity]
|
||||||
:opt-un [:contact/address :contact/private-key :contact/public-key :contact/photo-path
|
:opt-un [:contact/address :contact/private-key :contact/public-key :contact/photo-path
|
||||||
:contact/status :contact/last-updated :contact/last-online :contact/pending?
|
:contact/status :contact/last-updated :contact/last-online :contact/pending?
|
||||||
@ -71,26 +71,26 @@
|
|||||||
:contact/commands :contact/responses :contact/debug? :contact/subscriptions]))
|
:contact/commands :contact/responses :contact/debug? :contact/subscriptions]))
|
||||||
|
|
||||||
;;Contact list ui props
|
;;Contact list ui props
|
||||||
(s/def :contact-list-ui/edit? boolean?)
|
(spec/def :contact-list-ui/edit? boolean?)
|
||||||
|
|
||||||
;;Contacts ui props
|
;;Contacts ui props
|
||||||
(s/def :contacts-ui/edit? boolean?)
|
(spec/def :contacts-ui/edit? boolean?)
|
||||||
|
|
||||||
|
|
||||||
(s/def :contacts/contacts (s/nilable (s/map-of ::not-empty-string :contact/contact)))
|
(spec/def :contacts/contacts (spec/nilable (spec/map-of ::not-empty-string :contact/contact)))
|
||||||
;public key of new contact during adding this new contact
|
;public key of new contact during adding this new contact
|
||||||
(s/def :contacts/new-identity (s/nilable string?))
|
(spec/def :contacts/new-identity (spec/nilable string?))
|
||||||
(s/def :contacts/new-public-key-error (s/nilable string?))
|
(spec/def :contacts/new-public-key-error (spec/nilable string?))
|
||||||
;on showing this contact's profile (andrey: better to move into profile ns)
|
;on showing this contact's profile (andrey: better to move into profile ns)
|
||||||
(s/def :contacts/identity (s/nilable ::not-empty-string))
|
(spec/def :contacts/identity (spec/nilable ::not-empty-string))
|
||||||
(s/def :contacts/list-ui-props (s/nilable (allowed-keys :opt-un [:contact-list-ui/edit?])))
|
(spec/def :contacts/list-ui-props (spec/nilable (allowed-keys :opt-un [:contact-list-ui/edit?])))
|
||||||
(s/def :contacts/ui-props (s/nilable (allowed-keys :opt-un [:contacts-ui/edit?])))
|
(spec/def :contacts/ui-props (spec/nilable (allowed-keys :opt-un [:contacts-ui/edit?])))
|
||||||
;used in modal list (for example for wallet)
|
;used in modal list (for example for wallet)
|
||||||
(s/def :contacts/click-handler (s/nilable fn?))
|
(spec/def :contacts/click-handler (spec/nilable fn?))
|
||||||
;used in modal list (for example for wallet)
|
;used in modal list (for example for wallet)
|
||||||
(s/def :contacts/click-action (s/nilable #{:send :request}))
|
(spec/def :contacts/click-action (spec/nilable #{:send :request}))
|
||||||
;used in modal list (for example for wallet)
|
;used in modal list (for example for wallet)
|
||||||
(s/def :contacts/click-params (s/nilable map?))
|
(spec/def :contacts/click-params (spec/nilable map?))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
[cljs.reader :refer [read-string]]
|
[cljs.reader :refer [read-string]]
|
||||||
[status-im.utils.js-resources :as js-res]
|
[status-im.utils.js-resources :as js-res]
|
||||||
[status-im.react-native.js-dependencies :as rn-dependencies]
|
[status-im.react-native.js-dependencies :as rn-dependencies]
|
||||||
[status-im.contacts.navigation]
|
|
||||||
[status-im.utils.identicon :refer [identicon]]
|
[status-im.utils.identicon :refer [identicon]]
|
||||||
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
||||||
[status-im.i18n :refer [label]]
|
[status-im.i18n :refer [label]]
|
||||||
[status-im.contacts.db :as v]))
|
[status-im.contacts.db :as v]
|
||||||
|
[status-im.contacts.navigation]))
|
||||||
|
|
||||||
;;;; COFX
|
;;;; COFX
|
||||||
|
|
||||||
@ -208,7 +208,7 @@
|
|||||||
(subs (.sha3 js/Web3.prototype normalized-key #js {:encoding "hex"}) 26))))
|
(subs (.sha3 js/Web3.prototype normalized-key #js {:encoding "hex"}) 26))))
|
||||||
|
|
||||||
(defn- prepare-default-groups-events [groups default-groups]
|
(defn- prepare-default-groups-events [groups default-groups]
|
||||||
[[:add-groups
|
[[:add-contact-groups
|
||||||
(for [[id {:keys [name contacts]}] default-groups
|
(for [[id {:keys [name contacts]}] default-groups
|
||||||
:let [id' (clojure.core/name id)]
|
:let [id' (clojure.core/name id)]
|
||||||
:when (not (get groups id'))]
|
:when (not (get groups id'))]
|
||||||
@ -412,9 +412,9 @@
|
|||||||
(register-handler-fx
|
(register-handler-fx
|
||||||
:remove-contact-from-group
|
:remove-contact-from-group
|
||||||
(fn [{:keys [db]} [_ whisper-identity group-id]]
|
(fn [{:keys [db]} [_ whisper-identity group-id]]
|
||||||
(let [{:keys [contact-groups]} db
|
(let [{:group/keys [contact-groups]} db
|
||||||
group' (update (contact-groups group-id) :contacts (remove-contact-from-group whisper-identity))]
|
group' (update (contact-groups group-id) :contacts (remove-contact-from-group whisper-identity))]
|
||||||
{:dispatch [:update-group group']})))
|
{:dispatch [:update-contact-group group']})))
|
||||||
|
|
||||||
(register-handler-fx
|
(register-handler-fx
|
||||||
:remove-contact
|
:remove-contact
|
||||||
@ -428,8 +428,8 @@
|
|||||||
:open-contact-toggle-list
|
:open-contact-toggle-list
|
||||||
(fn [{:keys [db]} [_ group-type]]
|
(fn [{:keys [db]} [_ group-type]]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :group-type group-type
|
(assoc :group/group-type group-type
|
||||||
:selected-contacts #{}
|
:group/selected-contacts #{}
|
||||||
:new-chat-name "")
|
:new-chat-name "")
|
||||||
(assoc-in [:toolbar-search :show] nil)
|
(assoc-in [:toolbar-search :show] nil)
|
||||||
(assoc-in [:toolbar-search :text] ""))
|
(assoc-in [:toolbar-search :text] ""))
|
||||||
|
@ -1,22 +1,6 @@
|
|||||||
(ns status-im.contacts.navigation
|
(ns status-im.contacts.navigation
|
||||||
(:require [status-im.navigation.handlers :as nav]))
|
(:require [status-im.navigation.handlers :as nav]))
|
||||||
|
|
||||||
(defmethod nav/preload-data! :group-contacts
|
|
||||||
[db [_ _ group show-search?]]
|
|
||||||
(-> db
|
|
||||||
(assoc :contacts-group group)
|
|
||||||
(update :toolbar-search assoc
|
|
||||||
:show (when show-search? :contact-list)
|
|
||||||
:text "")))
|
|
||||||
|
|
||||||
(defmethod nav/preload-data! :edit-group
|
|
||||||
[db [_ _ group group-type]]
|
|
||||||
(if group
|
|
||||||
(assoc db :contact-group-id (:group-id group)
|
|
||||||
:group-type group-type
|
|
||||||
:new-chat-name (:name group))
|
|
||||||
db))
|
|
||||||
|
|
||||||
(defmethod nav/preload-data! :contact-list
|
(defmethod nav/preload-data! :contact-list
|
||||||
[db [_ _ click-handler]]
|
[db [_ _ click-handler]]
|
||||||
(-> db
|
(-> db
|
||||||
@ -24,10 +8,3 @@
|
|||||||
(assoc-in [:contacts/list-ui-props :edit?] false)
|
(assoc-in [:contacts/list-ui-props :edit?] false)
|
||||||
(assoc-in [:contacts/ui-props :edit?] false)
|
(assoc-in [:contacts/ui-props :edit?] false)
|
||||||
(assoc :contacts/click-handler click-handler)))
|
(assoc :contacts/click-handler click-handler)))
|
||||||
|
|
||||||
(defmethod nav/preload-data! :reorder-groups
|
|
||||||
[db [_ _]]
|
|
||||||
(assoc db :groups-order (->> (vals (:contact-groups db))
|
|
||||||
(remove :pending?)
|
|
||||||
(sort-by :order >)
|
|
||||||
(map :group-id))))
|
|
@ -50,7 +50,7 @@
|
|||||||
(reg-sub
|
(reg-sub
|
||||||
:group-contacts
|
:group-contacts
|
||||||
(fn [db [_ group-id]]
|
(fn [db [_ group-id]]
|
||||||
(get-in db [:contact-groups group-id :contacts])))
|
(get-in db [:group/contact-groups group-id :contacts])))
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:all-added-group-contacts
|
:all-added-group-contacts
|
||||||
@ -98,16 +98,11 @@
|
|||||||
(fn [contacts]
|
(fn [contacts]
|
||||||
(count contacts)))
|
(count contacts)))
|
||||||
|
|
||||||
(reg-sub
|
|
||||||
:contact-groups
|
|
||||||
(fn [db]
|
|
||||||
(vals (:contact-groups db))))
|
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:all-added-groups
|
:all-added-groups
|
||||||
:<- [:contact-groups]
|
:<- [:get-contact-groups]
|
||||||
(fn [groups]
|
(fn [groups]
|
||||||
(->> (remove :pending? groups)
|
(->> (remove :pending? (vals groups))
|
||||||
(sort-by :order >))))
|
(sort-by :order >))))
|
||||||
|
|
||||||
(defn search-filter [text item]
|
(defn search-filter [text item]
|
||||||
@ -133,8 +128,9 @@
|
|||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:contact-group-contacts
|
:contact-group-contacts
|
||||||
(fn [db]
|
:<- [:get-contact-group]
|
||||||
(get-in db [:contact-groups (:contact-group-id db) :contacts])))
|
(fn [group]
|
||||||
|
(:contacts group)))
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:all-not-added-contact-group-contacts
|
:all-not-added-contact-group-contacts
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
[common/form-title subtitle
|
[common/form-title subtitle
|
||||||
{:count-value contacts-count
|
{:count-value contacts-count
|
||||||
:extended? edit?
|
:extended? edit?
|
||||||
:options [{:value #(dispatch [:navigate-to :edit-group group :contact-group])
|
:options [{:value #(dispatch [:navigate-to :edit-contact-group group :contact-group])
|
||||||
:text (label :t/edit-group)}]}])
|
:text (label :t/edit-group)}]}])
|
||||||
[view st/contacts-list
|
[view st/contacts-list
|
||||||
[common/list-footer]
|
[common/list-footer]
|
||||||
@ -85,7 +85,7 @@
|
|||||||
[touchable-highlight {:on-press #(do
|
[touchable-highlight {:on-press #(do
|
||||||
(when edit?
|
(when edit?
|
||||||
(dispatch [:set-in [:contacts/list-ui-props :edit?] true]))
|
(dispatch [:set-in [:contacts/list-ui-props :edit?] true]))
|
||||||
(dispatch [:navigate-to :group-contacts group]))}
|
(dispatch [:navigate-to :group-contacts (:group-id group)]))}
|
||||||
[view
|
[view
|
||||||
[text {:style st/show-all-text
|
[text {:style st/show-all-text
|
||||||
:uppercase? (get-in platform-specific [:uppercase?])
|
:uppercase? (get-in platform-specific [:uppercase?])
|
||||||
@ -112,7 +112,7 @@
|
|||||||
[ion-icon {:name :md-create
|
[ion-icon {:name :md-create
|
||||||
:style create-icon}]]])
|
:style create-icon}]]])
|
||||||
|
|
||||||
(defview contact-list [_]
|
(defview contact-groups-list [_]
|
||||||
(letsubs [contacts [:get-added-contacts-with-limit contacts-limit]
|
(letsubs [contacts [:get-added-contacts-with-limit contacts-limit]
|
||||||
contacts-count [:added-contacts-count]
|
contacts-count [:added-contacts-count]
|
||||||
edit? [:get-in [:contacts/ui-props :edit?]]
|
edit? [:get-in [:contacts/ui-props :edit?]]
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
:navigation-stack '()
|
:navigation-stack '()
|
||||||
:contacts/contacts {}
|
:contacts/contacts {}
|
||||||
:qr-codes {}
|
:qr-codes {}
|
||||||
:contact-groups {}
|
:group/contact-groups {}
|
||||||
:selected-contacts #{}
|
:group/selected-contacts #{}
|
||||||
:chats {}
|
:chats {}
|
||||||
:current-chat-id console-chat-id
|
:current-chat-id console-chat-id
|
||||||
:loading-allowed true
|
:loading-allowed true
|
||||||
|
102
src/status_im/group/add_contacts/views.cljs
Normal file
102
src/status_im/group/add_contacts/views.cljs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
(ns status-im.group.add-contacts.views
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
|
[status-im.components.renderers.renderers :as renderers]
|
||||||
|
[status-im.components.react :refer [view keyboard-avoiding-view
|
||||||
|
text list-view list-item]]
|
||||||
|
[status-im.components.sticky-button :refer [sticky-button]]
|
||||||
|
[status-im.components.status-bar :refer [status-bar]]
|
||||||
|
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
||||||
|
[status-im.utils.listview :refer [to-datasource]]
|
||||||
|
[status-im.group.styles :as styles]
|
||||||
|
[status-im.contacts.styles :as cstyles]
|
||||||
|
[status-im.i18n :refer [label]]
|
||||||
|
[status-im.components.contact.contact :refer [toogle-contact-view]]))
|
||||||
|
|
||||||
|
(defn on-toggle [checked? whisper-identity]
|
||||||
|
(let [action (if checked? :deselect-contact :select-contact)]
|
||||||
|
(dispatch [action whisper-identity])))
|
||||||
|
|
||||||
|
(defn on-toggle-participant [checked? whisper-identity]
|
||||||
|
(let [action (if checked? :deselect-participant :select-participant)]
|
||||||
|
(dispatch [action whisper-identity])))
|
||||||
|
|
||||||
|
(defn group-toggle-contact [{:keys [whisper-identity] :as contact}]
|
||||||
|
[toogle-contact-view contact :is-contact-selected? on-toggle])
|
||||||
|
|
||||||
|
(defn group-toggle-participant [{:keys [whisper-identity] :as contact}]
|
||||||
|
[toogle-contact-view contact :is-participant-selected? on-toggle-participant])
|
||||||
|
|
||||||
|
(defn title-with-count [title count-value]
|
||||||
|
[view styles/toolbar-title-with-count
|
||||||
|
[text {:style styles/toolbar-title-with-count-text
|
||||||
|
:font :toolbar-title}
|
||||||
|
title]
|
||||||
|
(when (pos? count-value)
|
||||||
|
[view styles/toolbar-title-with-count-container
|
||||||
|
[text {:style styles/toolbar-title-with-count-text-count
|
||||||
|
:font :toolbar-title}
|
||||||
|
count-value]])])
|
||||||
|
|
||||||
|
(defview toggle-list-toolbar [title contacts-count]
|
||||||
|
(letsubs [show-search [:get-in [:toolbar-search :show]]
|
||||||
|
search-text [:get-in [:toolbar-search :text]]]
|
||||||
|
(toolbar-with-search
|
||||||
|
{:show-search? (= show-search :contact-group-list)
|
||||||
|
:search-text search-text
|
||||||
|
:search-key :contact-group-list
|
||||||
|
:custom-title (title-with-count title contacts-count)
|
||||||
|
:search-placeholder (label :t/search-contacts)})))
|
||||||
|
|
||||||
|
(defn toggle-list [contacts render-function]
|
||||||
|
[view {:flex 1}
|
||||||
|
[list-view
|
||||||
|
{:dataSource (to-datasource contacts)
|
||||||
|
:renderRow (fn [row _ _]
|
||||||
|
(list-item ^{:key row} [render-function row]))
|
||||||
|
:renderSeparator renderers/list-separator-renderer
|
||||||
|
:renderFooter renderers/list-footer-renderer
|
||||||
|
:renderHeader renderers/list-header-renderer
|
||||||
|
:style cstyles/contacts-list
|
||||||
|
:keyboardShouldPersistTaps :always}]])
|
||||||
|
|
||||||
|
(defview contact-toggle-list []
|
||||||
|
(letsubs [contacts [:all-added-group-contacts-filtered]
|
||||||
|
selected-contacts-count [:selected-contacts-count]
|
||||||
|
group-type [:get-group-type]]
|
||||||
|
[keyboard-avoiding-view {:style styles/group-container}
|
||||||
|
[status-bar]
|
||||||
|
[toggle-list-toolbar
|
||||||
|
(label (if (= group-type :contact-group)
|
||||||
|
:t/new-group
|
||||||
|
:t/new-group-chat))
|
||||||
|
selected-contacts-count]
|
||||||
|
[toggle-list contacts group-toggle-contact]
|
||||||
|
(when (pos? selected-contacts-count)
|
||||||
|
[sticky-button (label :t/next) #(dispatch [:navigate-to :new-group])])]))
|
||||||
|
|
||||||
|
(defview add-contacts-toggle-list []
|
||||||
|
(letsubs [contacts [:all-group-not-added-contacts-filtered]
|
||||||
|
group [:get-contact-group]
|
||||||
|
selected-contacts-count [:selected-contacts-count]]
|
||||||
|
[keyboard-avoiding-view {:style styles/group-container}
|
||||||
|
[status-bar]
|
||||||
|
[toggle-list-toolbar (:name group) selected-contacts-count]
|
||||||
|
[toggle-list contacts group-toggle-contact]
|
||||||
|
(when (pos? selected-contacts-count)
|
||||||
|
[sticky-button (label :t/save) #(do
|
||||||
|
(dispatch [:add-selected-contacts-to-group])
|
||||||
|
(dispatch [:navigate-back]))])]))
|
||||||
|
|
||||||
|
(defview add-participants-toggle-list []
|
||||||
|
(letsubs [contacts [:contacts-filtered :all-new-contacts]
|
||||||
|
chat-name [:chat :name]
|
||||||
|
selected-contacts-count [:selected-participants-count]]
|
||||||
|
[keyboard-avoiding-view {:style styles/group-container}
|
||||||
|
[status-bar]
|
||||||
|
[toggle-list-toolbar chat-name selected-contacts-count]
|
||||||
|
[toggle-list contacts group-toggle-participant]
|
||||||
|
(when (pos? selected-contacts-count)
|
||||||
|
[sticky-button (label :t/save) #(do
|
||||||
|
(dispatch [:add-new-group-chat-participants])
|
||||||
|
(dispatch [:navigate-back]))])]))
|
177
src/status_im/group/chat_settings/events.cljs
Normal file
177
src/status_im/group/chat_settings/events.cljs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
(ns status-im.group.chat-settings.events
|
||||||
|
(:require [re-frame.core :refer [dispatch reg-fx]]
|
||||||
|
[status-im.utils.handlers :refer [register-handler-fx]]
|
||||||
|
[status-im.protocol.core :as protocol]
|
||||||
|
[status-im.utils.random :as random]
|
||||||
|
[status-im.chat.handlers :as chat-events]
|
||||||
|
[status-im.data-store.contacts :as contacts]
|
||||||
|
[status-im.data-store.messages :as messages]
|
||||||
|
[status-im.data-store.chats :as chats]
|
||||||
|
[status-im.constants :refer [text-content-type]]))
|
||||||
|
|
||||||
|
;;;; COFX
|
||||||
|
|
||||||
|
;;;; FX
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::save-chat-property
|
||||||
|
(fn [[current-chat-id property-name value]]
|
||||||
|
(chats/save-property current-chat-id property-name value)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::add-members-to-chat
|
||||||
|
(fn [{:keys [current-chat-id selected-participants]}]
|
||||||
|
(chats/add-contacts current-chat-id selected-participants)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::remove-members-from-chat
|
||||||
|
(fn [[current-chat-id participants]]
|
||||||
|
(chats/remove-contacts current-chat-id participants)))
|
||||||
|
|
||||||
|
(defn system-message [message-id content]
|
||||||
|
{:from "system"
|
||||||
|
:message-id message-id
|
||||||
|
:content content
|
||||||
|
:content-type text-content-type})
|
||||||
|
|
||||||
|
(defn removed-participant-message [chat-id identity]
|
||||||
|
(let [contact-name (:name (contacts/get-by-id identity))]
|
||||||
|
(->> (str "You've removed " (or contact-name identity))
|
||||||
|
(system-message (random/id))
|
||||||
|
(messages/save chat-id))))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::create-removing-messages
|
||||||
|
(fn [{:keys [current-chat-id participants]}]
|
||||||
|
(doseq [participant participants]
|
||||||
|
(removed-participant-message current-chat-id participant))))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::notify-about-new-members
|
||||||
|
(fn [{:keys [current-chat-id selected-participants
|
||||||
|
current-public-key chats web3]}]
|
||||||
|
(let [{:keys [name contacts]} (chats current-chat-id)
|
||||||
|
identities (map :identity contacts)
|
||||||
|
|
||||||
|
{:keys [public private]
|
||||||
|
:as new-keypair} (protocol/new-keypair!)
|
||||||
|
|
||||||
|
group-message {:web3 web3
|
||||||
|
:group {:id current-chat-id
|
||||||
|
:name name
|
||||||
|
:contacts (conj identities current-public-key)
|
||||||
|
:admin current-public-key}
|
||||||
|
:message {:from current-public-key
|
||||||
|
:message-id (random/id)}}]
|
||||||
|
(dispatch [:update-chat! {:chat-id current-chat-id
|
||||||
|
:public-key public
|
||||||
|
:private-key private}])
|
||||||
|
(protocol/start-watching-group! {:web3 web3
|
||||||
|
:group-id current-chat-id
|
||||||
|
:identity current-public-key
|
||||||
|
:keypair new-keypair
|
||||||
|
:callback #(dispatch [:incoming-message %1 %2])})
|
||||||
|
(protocol/invite-to-group!
|
||||||
|
(-> group-message
|
||||||
|
(assoc-in [:group :keypair] new-keypair)
|
||||||
|
(assoc :identities selected-participants)))
|
||||||
|
(protocol/update-group!
|
||||||
|
(-> group-message
|
||||||
|
(assoc-in [:group :keypair] new-keypair)
|
||||||
|
(assoc :identities identities)))
|
||||||
|
(doseq [identity selected-participants]
|
||||||
|
(protocol/add-to-group! {:web3 web3
|
||||||
|
:group-id current-chat-id
|
||||||
|
:identity identity
|
||||||
|
:keypair new-keypair
|
||||||
|
:message {:from current-public-key
|
||||||
|
:message-id (random/id)}})))))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::notify-about-removing
|
||||||
|
(fn [{:keys [web3 current-chat-id participants chats current-public-key]}]
|
||||||
|
(let [{:keys [private public] :as new-keypair} (protocol/new-keypair!)
|
||||||
|
{:keys [name private-key public-key]
|
||||||
|
:as chat} (get chats current-chat-id)
|
||||||
|
old-keypair {:private private-key
|
||||||
|
:public public-key}
|
||||||
|
contacts (get chat :contacts)
|
||||||
|
identities (-> (map :identity contacts)
|
||||||
|
set
|
||||||
|
(clojure.set/difference participants))]
|
||||||
|
(dispatch [:update-chat! {:chat-id current-chat-id
|
||||||
|
:private-key private
|
||||||
|
:public-key public}])
|
||||||
|
(doseq [participant participants]
|
||||||
|
(let [id (random/id)]
|
||||||
|
(doseq [keypair [old-keypair new-keypair]]
|
||||||
|
(protocol/remove-from-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group-id current-chat-id
|
||||||
|
:identity participant
|
||||||
|
:keypair keypair
|
||||||
|
:message {:from current-public-key
|
||||||
|
:message-id id}}))))
|
||||||
|
(protocol/start-watching-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group-id current-chat-id
|
||||||
|
:identity current-public-key
|
||||||
|
:keypair new-keypair
|
||||||
|
:callback #(dispatch [:incoming-message %1 %2])})
|
||||||
|
(protocol/update-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group {:id current-chat-id
|
||||||
|
:name name
|
||||||
|
:contacts (conj identities current-public-key)
|
||||||
|
:admin current-public-key
|
||||||
|
:keypair new-keypair}
|
||||||
|
:identities identities
|
||||||
|
:message {:from current-public-key
|
||||||
|
:message-id (random/id)}}))))
|
||||||
|
|
||||||
|
;;;; Handlers
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:show-group-chat-settings
|
||||||
|
(fn [{{:keys [current-chat-id] :as db} :db} _]
|
||||||
|
{:db (assoc db :new-chat-name (get-in db [:chats current-chat-id :name])
|
||||||
|
:group/group-type :chat-group)
|
||||||
|
:dispatch [:navigate-to :chat-group-settings]}))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:add-new-group-chat-participants
|
||||||
|
(fn [{{:keys [current-chat-id selected-participants] :as db} :db} _]
|
||||||
|
(let [new-identities (map #(hash-map :identity %) selected-participants)]
|
||||||
|
{:db (-> db
|
||||||
|
(update-in [:chats current-chat-id :contacts] concat new-identities)
|
||||||
|
(assoc :selected-participants #{}))
|
||||||
|
::add-members-to-chat (select-keys db [:current-chat-id :selected-participants])
|
||||||
|
::notify-about-new-members (select-keys db [:current-chat-id :selected-participants
|
||||||
|
:current-public-key :chats :web3])})))
|
||||||
|
|
||||||
|
(defn remove-identities [collection identities]
|
||||||
|
(remove #(identities (:identity %)) collection))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:remove-group-chat-participants
|
||||||
|
(fn [{{:keys [current-chat-id] :as db} :db} [_ participants]]
|
||||||
|
{:db (update-in db [:chats current-chat-id :contacts] remove-identities participants)
|
||||||
|
::remove-members-from-chat [current-chat-id participants]
|
||||||
|
::notify-about-removing (merge {:participants participants}
|
||||||
|
(select-keys db [:web3 :current-chat-id :chats :current-public-key]))
|
||||||
|
::create-removing-messages (merge {:participants participants}
|
||||||
|
(select-keys db [:current-chat-id]))}))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:set-chat-name
|
||||||
|
(fn [{{:keys [current-chat-id new-chat-name] :as db} :db} _]
|
||||||
|
{:db (assoc-in db [:chats current-chat-id :name] new-chat-name)
|
||||||
|
::save-chat-property [current-chat-id :name new-chat-name]}))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:clear-history
|
||||||
|
(fn [{{:keys [current-chat-id] :as db} :db} _]
|
||||||
|
{:db (-> db
|
||||||
|
(assoc-in [:chats current-chat-id :messages] '())
|
||||||
|
(assoc-in [:chats current-chat-id :last-message] nil))
|
||||||
|
::chat-events/delete-messages current-chat-id}))
|
@ -1,8 +1,9 @@
|
|||||||
(ns status-im.group-settings.subs
|
(ns status-im.group.chat-settings.subs
|
||||||
(:require [re-frame.core :refer [reg-sub]]
|
(:require [re-frame.core :refer [reg-sub]]
|
||||||
[status-im.constants :refer [max-chat-name-length]]))
|
[status-im.constants :refer [max-chat-name-length]]))
|
||||||
|
|
||||||
(reg-sub :selected-participant
|
(reg-sub
|
||||||
|
:selected-participant
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(let [identity (first (:selected-participants db))]
|
(let [identity (first (:selected-participants db))]
|
||||||
(get-in db [:contacts/contacts identity]))))
|
(get-in db [:contacts/contacts identity]))))
|
||||||
@ -14,12 +15,19 @@
|
|||||||
(when (< max-chat-name-length (count chat-name))
|
(when (< max-chat-name-length (count chat-name))
|
||||||
"Chat name is too long"))))
|
"Chat name is too long"))))
|
||||||
|
|
||||||
(reg-sub :new-chat-name-validation-messages
|
(reg-sub
|
||||||
|
:new-chat-name
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(let [chat-name (:new-chat-name db)]
|
(:new-chat-name db)))
|
||||||
(get-chat-name-validation-messages chat-name))))
|
|
||||||
|
|
||||||
(reg-sub :new-chat-name-valid?
|
(reg-sub
|
||||||
(fn [db]
|
:new-chat-name-validation-messages
|
||||||
(let [chat-name (:new-chat-name db)]
|
:<- [:new-chat-name]
|
||||||
(zero? (count (get-chat-name-validation-messages chat-name))))))
|
(fn [chat-name]
|
||||||
|
(get-chat-name-validation-messages chat-name)))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:new-chat-name-valid?
|
||||||
|
:<- [:new-chat-name]
|
||||||
|
(fn [chat-name]
|
||||||
|
(zero? (count (get-chat-name-validation-messages chat-name)))))
|
65
src/status_im/group/chat_settings/views.cljs
Normal file
65
src/status_im/group/chat_settings/views.cljs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
(ns status-im.group.chat-settings.views
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
|
[status-im.components.contact.contact :refer [contact-view]]
|
||||||
|
[status-im.components.common.common :as common]
|
||||||
|
[status-im.components.react :refer [view scroll-view keyboard-avoiding-view]]
|
||||||
|
[status-im.components.sticky-button :refer [sticky-button]]
|
||||||
|
[status-im.group.styles :as styles]
|
||||||
|
[status-im.group.views :refer [group-toolbar group-chat-settings-btns
|
||||||
|
group-name-view add-btn more-btn]]
|
||||||
|
[status-im.group.db :as v]
|
||||||
|
[status-im.i18n :refer [label]]
|
||||||
|
[cljs.spec.alpha :as spec]))
|
||||||
|
|
||||||
|
(def ^:const contacts-limit 3)
|
||||||
|
|
||||||
|
(defview chat-group-contacts-view [admin?]
|
||||||
|
(letsubs [contacts [:current-chat-contacts]]
|
||||||
|
(let [limited-contacts (take contacts-limit contacts)
|
||||||
|
contacts-count (count contacts)]
|
||||||
|
[view
|
||||||
|
(when (and admin? (pos? contacts-count))
|
||||||
|
[common/list-separator])
|
||||||
|
[view
|
||||||
|
(doall
|
||||||
|
(map (fn [row]
|
||||||
|
^{:key row}
|
||||||
|
[view
|
||||||
|
[contact-view
|
||||||
|
{:contact row
|
||||||
|
:extend-options [{:value #(dispatch [:remove-group-chat-participants #{(:whisper-identity row)}])
|
||||||
|
:text (label :t/remove)}]
|
||||||
|
:extended? admin?}]
|
||||||
|
(when-not (= row (last limited-contacts))
|
||||||
|
[common/list-separator])])
|
||||||
|
limited-contacts))]
|
||||||
|
(when (< contacts-limit contacts-count)
|
||||||
|
[more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-chat-group-contact-list])])])))
|
||||||
|
|
||||||
|
(defview chat-group-members []
|
||||||
|
(letsubs [current-pk [:get :current-public-key]
|
||||||
|
group-admin [:chat :group-admin]]
|
||||||
|
(let [admin? (= current-pk group-admin)]
|
||||||
|
[view
|
||||||
|
(when admin?
|
||||||
|
[add-btn #(dispatch [:navigate-to :add-participants-toggle-list])])
|
||||||
|
[chat-group-contacts-view admin?]])))
|
||||||
|
|
||||||
|
(defview chat-group-settings []
|
||||||
|
(letsubs [new-chat-name [:get :new-chat-name]
|
||||||
|
chat-name [:chat :name]
|
||||||
|
type [:get-group-type]]
|
||||||
|
(let [save-btn-enabled? (and (spec/valid? ::v/name new-chat-name)
|
||||||
|
(not= new-chat-name chat-name))]
|
||||||
|
[keyboard-avoiding-view {:style styles/group-container}
|
||||||
|
[view {:flex 1}
|
||||||
|
[group-toolbar type true]
|
||||||
|
[scroll-view
|
||||||
|
[group-name-view]
|
||||||
|
[chat-group-members]
|
||||||
|
[view styles/separator]
|
||||||
|
[group-chat-settings-btns]]]
|
||||||
|
(when save-btn-enabled?
|
||||||
|
[sticky-button (label :t/save) #(dispatch [:set-chat-name])
|
||||||
|
true])])))
|
36
src/status_im/group/db.cljs
Normal file
36
src/status_im/group/db.cljs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
(ns status-im.group.db
|
||||||
|
(:require-macros [status-im.utils.db :refer [allowed-keys]])
|
||||||
|
(:require [cljs.spec.alpha :as spec]
|
||||||
|
[status-im.constants :refer [console-chat-id wallet-chat-id]]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[status-im.utils.homoglyph :as utils]))
|
||||||
|
|
||||||
|
(spec/def ::not-empty-string (spec/and string? not-empty))
|
||||||
|
|
||||||
|
(spec/def ::name ::not-empty-string)
|
||||||
|
;;;; DB
|
||||||
|
|
||||||
|
(spec/def :group/group-id ::not-empty-string)
|
||||||
|
(spec/def :group/name ::not-empty-string)
|
||||||
|
(spec/def :group/timestamp int?)
|
||||||
|
(spec/def :group/pending? boolean?)
|
||||||
|
(spec/def :group/order int?)
|
||||||
|
|
||||||
|
(spec/def :group-contact/identity ::not-empty-string)
|
||||||
|
|
||||||
|
(spec/def :group/contact (allowed-keys :req-un [:group-contact/identity]))
|
||||||
|
|
||||||
|
(spec/def :group/contacts (spec/nilable (spec/* :group/contact)))
|
||||||
|
|
||||||
|
(spec/def :group/contact-group (allowed-keys
|
||||||
|
:req-un [:group/group-id :group/name :group/timestamp
|
||||||
|
:group/order :group/contacts]
|
||||||
|
:opt-un [:group/pending?]))
|
||||||
|
|
||||||
|
(spec/def :group/contact-groups (spec/nilable (spec/map-of ::not-empty-string :group/contact-group)))
|
||||||
|
;;used during editing contact group
|
||||||
|
(spec/def :group/contact-group-id (spec/nilable string?))
|
||||||
|
(spec/def :group/group-type (spec/nilable #{:chat-group :contact-group}))
|
||||||
|
(spec/def :group/selected-contacts (spec/nilable (spec/* string?)))
|
||||||
|
;;list of group ids
|
||||||
|
(spec/def :group/groups-order (spec/nilable (spec/* string?)))
|
77
src/status_im/group/edit_contacts/views.cljs
Normal file
77
src/status_im/group/edit_contacts/views.cljs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
(ns status-im.group.edit-contacts.views
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
|
[status-im.components.contact.contact :refer [contact-view]]
|
||||||
|
[status-im.components.renderers.renderers :as renderers]
|
||||||
|
[status-im.components.react :refer [view list-view list-item]]
|
||||||
|
[status-im.components.status-bar :refer [status-bar]]
|
||||||
|
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
||||||
|
[status-im.utils.listview :refer [to-datasource]]
|
||||||
|
[status-im.group.styles :as styles]
|
||||||
|
[status-im.i18n :refer [label]]))
|
||||||
|
|
||||||
|
(defview contact-list-toolbar [title]
|
||||||
|
(letsubs [show-search [:get-in [:toolbar-search :show]]
|
||||||
|
search-text [:get-in [:toolbar-search :text]]]
|
||||||
|
(toolbar-with-search
|
||||||
|
{:show-search? (= show-search :contact-list)
|
||||||
|
:search-text search-text
|
||||||
|
:search-key :contact-list
|
||||||
|
:title title
|
||||||
|
:search-placeholder (label :t/search-contacts)})))
|
||||||
|
|
||||||
|
(defn contacts-list [contacts extended? extend-options]
|
||||||
|
[view {:flex 1}
|
||||||
|
[list-view {:dataSource (to-datasource contacts)
|
||||||
|
:enableEmptySections true
|
||||||
|
:renderRow (fn [row _ _]
|
||||||
|
(list-item
|
||||||
|
^{:key row}
|
||||||
|
[contact-view {:contact row
|
||||||
|
:extended? extended?
|
||||||
|
:extend-options (extend-options row)}]))
|
||||||
|
:bounces false
|
||||||
|
:keyboardShouldPersistTaps :always
|
||||||
|
:renderSeparator renderers/list-separator-renderer
|
||||||
|
:renderFooter renderers/list-footer-renderer
|
||||||
|
:renderHeader renderers/list-header-renderer}]])
|
||||||
|
|
||||||
|
(defn chat-extended-options [item]
|
||||||
|
[{:value #(dispatch [:remove-group-chat-participants #{(:whisper-identity item)}])
|
||||||
|
:text (label :t/remove)}])
|
||||||
|
|
||||||
|
(defn contact-extended-options [group-id]
|
||||||
|
(fn [item]
|
||||||
|
[{:value #(dispatch [:remove-contact-from-group
|
||||||
|
(:whisper-identity item)
|
||||||
|
group-id])
|
||||||
|
:text (label :t/remove-from-group)}]))
|
||||||
|
|
||||||
|
(defview edit-chat-group-contact-list []
|
||||||
|
(letsubs [chat-name [:chat :name]
|
||||||
|
contacts [:contacts-filtered :current-chat-contacts]
|
||||||
|
current-pk [:get :current-public-key]
|
||||||
|
group-admin [:chat :group-admin]]
|
||||||
|
(let [admin? (= current-pk group-admin)]
|
||||||
|
[view styles/group-container
|
||||||
|
[status-bar]
|
||||||
|
[contact-list-toolbar chat-name]
|
||||||
|
[contacts-list
|
||||||
|
contacts
|
||||||
|
admin?
|
||||||
|
chat-extended-options]])))
|
||||||
|
|
||||||
|
(defview contacts-list-view [group-id]
|
||||||
|
(letsubs [contacts [:all-added-group-contacts-filtered group-id]]
|
||||||
|
[contacts-list
|
||||||
|
contacts
|
||||||
|
true
|
||||||
|
(contact-extended-options group-id)]))
|
||||||
|
|
||||||
|
(defview edit-contact-group-contact-list []
|
||||||
|
(letsubs [group [:get-contact-group]
|
||||||
|
type [:get-group-type]]
|
||||||
|
[view styles/group-container
|
||||||
|
[status-bar]
|
||||||
|
[contact-list-toolbar (:name group)]
|
||||||
|
[contacts-list-view (:group-id group)]]))
|
269
src/status_im/group/events.cljs
Normal file
269
src/status_im/group/events.cljs
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
(ns status-im.group.events
|
||||||
|
(:require [status-im.protocol.core :as protocol]
|
||||||
|
[re-frame.core :refer [dispatch reg-fx reg-cofx inject-cofx]]
|
||||||
|
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||||
|
[status-im.components.styles :refer [default-chat-color]]
|
||||||
|
[status-im.data-store.chats :as chats]
|
||||||
|
[status-im.data-store.contact-groups :as groups]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[status-im.utils.random :as random]
|
||||||
|
[status-im.group.navigation]))
|
||||||
|
|
||||||
|
;;;; COFX
|
||||||
|
|
||||||
|
(reg-cofx
|
||||||
|
::get-all-contact-groups
|
||||||
|
(fn [coeffects _]
|
||||||
|
(let [groups (->> (groups/get-all)
|
||||||
|
(map (fn [{:keys [group-id] :as group}]
|
||||||
|
[group-id group]))
|
||||||
|
(into {}))]
|
||||||
|
(assoc coeffects :all-groups groups))))
|
||||||
|
|
||||||
|
;;;; FX
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::save-chat
|
||||||
|
(fn [new-chat]
|
||||||
|
(chats/save new-chat)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::save-contact-group
|
||||||
|
(fn [new-group]
|
||||||
|
(groups/save new-group)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::save-contact-groups
|
||||||
|
(fn [new-groups]
|
||||||
|
(groups/save-all new-groups)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::save-contact-group-property
|
||||||
|
(fn [[contact-group-id property-name value]]
|
||||||
|
(groups/save-property contact-group-id property-name value)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::add-contacts-to-contact-group
|
||||||
|
(fn [[contact-group-id selected-contacts]]
|
||||||
|
(groups/add-contacts contact-group-id selected-contacts)))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::start-listen-group
|
||||||
|
(fn [{:keys [new-chat web3 current-public-key]}]
|
||||||
|
(let [{:keys [chat-id public-key private-key contacts name]} new-chat
|
||||||
|
identities (mapv :identity contacts)]
|
||||||
|
(protocol/invite-to-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group {:id chat-id
|
||||||
|
:name name
|
||||||
|
:contacts (conj identities current-public-key)
|
||||||
|
:admin current-public-key
|
||||||
|
:keypair {:public public-key
|
||||||
|
:private private-key}}
|
||||||
|
:identities identities
|
||||||
|
:message {:from current-public-key
|
||||||
|
:message-id (random/id)}})
|
||||||
|
(protocol/start-watching-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group-id chat-id
|
||||||
|
:identity current-public-key
|
||||||
|
:keypair {:public public-key
|
||||||
|
:private private-key}
|
||||||
|
:callback #(dispatch [:incoming-message %1 %2])}))))
|
||||||
|
|
||||||
|
(reg-fx
|
||||||
|
::start-watching-group
|
||||||
|
(fn [{:keys [group-id web3 current-public-key keypair]}]
|
||||||
|
(protocol/start-watching-group!
|
||||||
|
{:web3 web3
|
||||||
|
:group-id group-id
|
||||||
|
:identity current-public-key
|
||||||
|
:keypair keypair
|
||||||
|
:callback #(dispatch [:incoming-message %1 %2])})))
|
||||||
|
|
||||||
|
;;;; Handlers
|
||||||
|
|
||||||
|
(register-handler-db
|
||||||
|
:deselect-contact
|
||||||
|
(fn [db [_ id]]
|
||||||
|
(update db :group/selected-contacts disj id)))
|
||||||
|
|
||||||
|
(register-handler-db
|
||||||
|
:select-contact
|
||||||
|
(fn [db [_ id]]
|
||||||
|
(update db :group/selected-contacts conj id)))
|
||||||
|
|
||||||
|
(register-handler-db
|
||||||
|
:deselect-participant
|
||||||
|
(fn [db [_ id]]
|
||||||
|
(update db :selected-participants disj id)))
|
||||||
|
|
||||||
|
(register-handler-db
|
||||||
|
:select-participant
|
||||||
|
(fn [db [_ id]]
|
||||||
|
(update db :selected-participants conj id)))
|
||||||
|
|
||||||
|
(defn group-name-from-contacts [contacts selected-contacts username]
|
||||||
|
(->> (select-keys contacts selected-contacts)
|
||||||
|
vals
|
||||||
|
(map :name)
|
||||||
|
(cons username)
|
||||||
|
(string/join ", ")))
|
||||||
|
|
||||||
|
(defn prepare-chat [{:keys [current-public-key username]
|
||||||
|
:group/keys [selected-contacts]
|
||||||
|
:contacts/keys [contacts]} group-name]
|
||||||
|
(let [selected-contacts' (mapv #(hash-map :identity %) selected-contacts)
|
||||||
|
chat-name (if-not (string/blank? group-name)
|
||||||
|
group-name
|
||||||
|
(group-name-from-contacts contacts selected-contacts username))
|
||||||
|
{:keys [public private]} (protocol/new-keypair!)]
|
||||||
|
{:chat-id (random/id)
|
||||||
|
:public-key public
|
||||||
|
:private-key private
|
||||||
|
:name chat-name
|
||||||
|
:color default-chat-color
|
||||||
|
:group-chat true
|
||||||
|
:group-admin current-public-key
|
||||||
|
:is-active true
|
||||||
|
:timestamp (random/timestamp)
|
||||||
|
:contacts selected-contacts'}))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:create-new-group-chat-and-open
|
||||||
|
(fn [{:keys [db]} [_ group-name]]
|
||||||
|
(let [new-chat (prepare-chat (select-keys db [:group/selected-contacts :current-public-key :username
|
||||||
|
:contacts/contacts])
|
||||||
|
group-name)]
|
||||||
|
{:db (-> db
|
||||||
|
(assoc-in [:chats (:chat-id new-chat)] new-chat)
|
||||||
|
(assoc :group/selected-contacts #{}))
|
||||||
|
::save-chat new-chat
|
||||||
|
::start-listen-group (merge {:new-chat new-chat}
|
||||||
|
(select-keys db [:web3 :current-public-key]))
|
||||||
|
:dispatch-n [[:navigate-to-clean :chat-list]
|
||||||
|
[:navigate-to :chat (:chat-id new-chat)]]})))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:group-chat-invite-received
|
||||||
|
(fn [{{:keys [current-public-key] :as db} :db}
|
||||||
|
[_ {:keys [from]
|
||||||
|
{:keys [group-id group-name contacts keypair timestamp]} :payload}]]
|
||||||
|
(let [{:keys [private public]} keypair]
|
||||||
|
(let [contacts' (keep (fn [ident]
|
||||||
|
(when (not= ident current-public-key)
|
||||||
|
{:identity ident})) contacts)
|
||||||
|
chat {:chat-id group-id
|
||||||
|
:name group-name
|
||||||
|
:group-chat true
|
||||||
|
:group-admin from
|
||||||
|
:public-key public
|
||||||
|
:private-key private
|
||||||
|
:contacts contacts'
|
||||||
|
:added-to-at timestamp
|
||||||
|
:timestamp timestamp
|
||||||
|
:is-active true}
|
||||||
|
exists? (chats/exists? group-id)]
|
||||||
|
(when (or (not exists?) (chats/new-update? timestamp group-id))
|
||||||
|
{::start-watching-group (merge {:group-id group-id
|
||||||
|
:keypair keypair}
|
||||||
|
(select-keys db [:web3 :current-public-key]))
|
||||||
|
:dispatch (if exists?
|
||||||
|
[:update-chat! chat]
|
||||||
|
[:add-chat group-id chat])})))))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:create-new-contact-group
|
||||||
|
(fn [{{:group/keys [contact-groups selected-contacts] :as db} :db} [_ group-name]]
|
||||||
|
(let [selected-contacts' (mapv #(hash-map :identity %) selected-contacts)
|
||||||
|
new-group {:group-id (random/id)
|
||||||
|
:name group-name
|
||||||
|
:order (count contact-groups)
|
||||||
|
:timestamp (random/timestamp)
|
||||||
|
:contacts selected-contacts'}]
|
||||||
|
{:db (update db :group/contact-groups merge {(:group-id new-group) new-group})
|
||||||
|
::save-contact-group new-group})))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:update-contact-group
|
||||||
|
(fn [{:keys [db]} [_ new-group]]
|
||||||
|
{:db (update db :group/contact-groups merge {(:group-id new-group) new-group})
|
||||||
|
::save-contact-group new-group}))
|
||||||
|
|
||||||
|
(defn update-pending-status [old-groups {:keys [group-id pending?] :as group}]
|
||||||
|
(let [{old-pending :pending?
|
||||||
|
:as old-group} (get old-groups group-id)
|
||||||
|
pending?' (if old-pending (and old-pending pending?) pending?)]
|
||||||
|
(assoc group :pending? (boolean pending?'))))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:add-contact-groups
|
||||||
|
(fn [{{:group/keys [contact-groups] :as db} :db} [_ new-groups]]
|
||||||
|
(let [identities (set (keys contact-groups))
|
||||||
|
old-groups-count (count identities)
|
||||||
|
new-groups' (->> new-groups
|
||||||
|
(map #(update-pending-status contact-groups %))
|
||||||
|
(remove #(identities (:group-id %)))
|
||||||
|
(map #(vector (:group-id %2) (assoc %2 :order %1)) (iterate inc old-groups-count))
|
||||||
|
(into {}))]
|
||||||
|
{:db (update db :group/contact-groups merge new-groups')
|
||||||
|
::save-contact-groups (into [] (vals new-groups'))})))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:load-contact-groups
|
||||||
|
[(inject-cofx ::get-all-contact-groups)]
|
||||||
|
(fn [{:keys [db all-groups]} _]
|
||||||
|
{:db (assoc db :group/contact-groups all-groups)}))
|
||||||
|
|
||||||
|
(defn move-item [v from to]
|
||||||
|
(if (< from to)
|
||||||
|
(concat (subvec v 0 from)
|
||||||
|
(subvec v (inc from) (inc to))
|
||||||
|
[(v from)]
|
||||||
|
(subvec v (inc to)))
|
||||||
|
(concat (subvec v 0 to)
|
||||||
|
[(v from)]
|
||||||
|
(subvec v to from)
|
||||||
|
(subvec v (inc from)))))
|
||||||
|
|
||||||
|
(register-handler-db
|
||||||
|
:change-contact-group-order
|
||||||
|
(fn [{:group/keys [groups-order] :as db} [_ from to]]
|
||||||
|
(if (>= to 0)
|
||||||
|
(assoc db :group/groups-order (move-item (vec groups-order) from to))
|
||||||
|
db)))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:save-contact-group-order
|
||||||
|
(fn [{{:group/keys [contact-groups groups-order] :as db} :db} _]
|
||||||
|
(let [new-groups (mapv #(assoc (contact-groups (second %)) :order (first %))
|
||||||
|
(map-indexed vector (reverse groups-order)))]
|
||||||
|
{:db (update db :group/contact-groups merge (map #(vector (:group-id %) %) new-groups))
|
||||||
|
::save-contact-groups new-groups})))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:set-contact-group-name
|
||||||
|
(fn [{{:keys [new-chat-name] :group/keys [contact-group-id] :as db} :db} _]
|
||||||
|
{:db (assoc-in db [:group/contact-groups contact-group-id :name] new-chat-name)
|
||||||
|
::save-contact-group-property [contact-group-id :name new-chat-name]}))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:add-selected-contacts-to-group
|
||||||
|
(fn [{{:group/keys [contact-groups contact-group-id selected-contacts] :as db} :db} _]
|
||||||
|
(let [new-identities (mapv #(hash-map :identity %) selected-contacts)]
|
||||||
|
{:db (update-in db [:group/contact-groups contact-group-id :contacts] #(into [] (set (concat % new-identities))))
|
||||||
|
::add-contacts-to-contact-group [contact-group-id selected-contacts]})))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:add-contacts-to-group
|
||||||
|
(fn [{:keys [db]} [_ group-id contacts]]
|
||||||
|
(let [new-identities (mapv #(hash-map :identity %) contacts)]
|
||||||
|
(when (get-in db [:group/contact-groups group-id])
|
||||||
|
{:db (update-in db [:group/contact-groups group-id :contacts] #(into [] (set (concat % new-identities))))
|
||||||
|
::add-contacts-to-contact-group [group-id contacts]}))))
|
||||||
|
|
||||||
|
(register-handler-fx
|
||||||
|
:delete-contact-group
|
||||||
|
(fn [{{:group/keys [contact-group-id] :as db} :db} _]
|
||||||
|
{:db (assoc-in db [:group/contact-groups contact-group-id :pending?] true)
|
||||||
|
::save-contact-group-property [contact-group-id :pending? true]}))
|
48
src/status_im/group/navigation.cljs
Normal file
48
src/status_im/group/navigation.cljs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
(ns status-im.group.navigation
|
||||||
|
(:require [status-im.navigation.handlers :as nav]))
|
||||||
|
|
||||||
|
(defn clear-toolbar-search [db]
|
||||||
|
(-> db
|
||||||
|
(assoc-in [:toolbar-search :show] nil)
|
||||||
|
(assoc-in [:toolbar-search :text] "")))
|
||||||
|
|
||||||
|
(defmethod nav/preload-data! :add-contacts-toggle-list
|
||||||
|
[db _]
|
||||||
|
(->
|
||||||
|
(assoc db :group/selected-contacts #{})
|
||||||
|
(clear-toolbar-search)))
|
||||||
|
|
||||||
|
|
||||||
|
(defmethod nav/preload-data! :add-participants-toggle-list
|
||||||
|
[db _]
|
||||||
|
(->
|
||||||
|
(assoc db :selected-participants #{})
|
||||||
|
(clear-toolbar-search)))
|
||||||
|
|
||||||
|
(defmethod nav/preload-data! :new-public-chat
|
||||||
|
[db]
|
||||||
|
(dissoc db :public-group-topic))
|
||||||
|
|
||||||
|
(defmethod nav/preload-data! :group-contacts
|
||||||
|
[db [_ _ group-id show-search?]]
|
||||||
|
(-> db
|
||||||
|
(assoc :group/contact-group-id group-id)
|
||||||
|
(update :toolbar-search
|
||||||
|
assoc
|
||||||
|
:show (when show-search? :contact-list)
|
||||||
|
:text "")))
|
||||||
|
|
||||||
|
(defmethod nav/preload-data! :edit-contact-group
|
||||||
|
[db [_ _ group group-type]]
|
||||||
|
(if group
|
||||||
|
(assoc db :group/contact-group-id (:group-id group)
|
||||||
|
:group/group-type group-type
|
||||||
|
:new-chat-name (:name group))
|
||||||
|
db))
|
||||||
|
|
||||||
|
(defmethod nav/preload-data! :reorder-groups
|
||||||
|
[db [_ _]]
|
||||||
|
(assoc db :group/groups-order (->> (vals (:group/contact-groups db))
|
||||||
|
(remove :pending?)
|
||||||
|
(sort-by :order >)
|
||||||
|
(map :group-id))))
|
60
src/status_im/group/reorder/views.cljs
Normal file
60
src/status_im/group/reorder/views.cljs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
(ns status-im.group.reorder.views
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [reagent.core :as reagent]
|
||||||
|
[re-frame.core :refer [dispatch dispatch-sync]]
|
||||||
|
[status-im.components.react :refer [view text icon list-item]]
|
||||||
|
[status-im.components.sticky-button :refer [sticky-button]]
|
||||||
|
[status-im.components.status-bar :refer [status-bar]]
|
||||||
|
[status-im.components.toolbar-new.view :refer [toolbar]]
|
||||||
|
[status-im.components.sortable-list-view :refer [sortable-list-view sortable-item]]
|
||||||
|
[status-im.components.common.common :as common]
|
||||||
|
[status-im.group.styles :as styles]
|
||||||
|
[status-im.i18n :refer [label label-pluralize]]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn toolbar-view []
|
||||||
|
[toolbar {:actions [{:image :blank}]
|
||||||
|
:title (label :t/reorder-groups)}])
|
||||||
|
|
||||||
|
(defn group-item [{:keys [name contacts] :as group}]
|
||||||
|
(let [cnt (count contacts)]
|
||||||
|
[view styles/order-item-container
|
||||||
|
[view styles/order-item-inner-container
|
||||||
|
[text {:style styles/order-item-label}
|
||||||
|
name]
|
||||||
|
[text {:style styles/order-item-contacts}
|
||||||
|
(str cnt " " (label-pluralize cnt :t/contact-s))]
|
||||||
|
[view {:flex 1}]
|
||||||
|
[view styles/order-item-icon
|
||||||
|
[icon :grab_gray]]]]))
|
||||||
|
|
||||||
|
(defn render-separator [last]
|
||||||
|
(fn [_ row-id _]
|
||||||
|
(list-item
|
||||||
|
(if (= row-id last)
|
||||||
|
^{:key "bottom-shadow"}
|
||||||
|
[common/bottom-shadow]
|
||||||
|
^{:key row-id}
|
||||||
|
[view styles/order-item-separator-wrapper
|
||||||
|
[view styles/order-item-separator]]))))
|
||||||
|
|
||||||
|
(defview reorder-groups []
|
||||||
|
(letsubs [groups [:get-contact-groups]
|
||||||
|
order [:get :group/groups-order]]
|
||||||
|
(let [this (reagent/current-component)]
|
||||||
|
[view styles/reorder-groups-container
|
||||||
|
[status-bar]
|
||||||
|
[toolbar-view]
|
||||||
|
[view styles/reorder-list-container
|
||||||
|
[common/top-shadow]
|
||||||
|
[sortable-list-view
|
||||||
|
{:data groups
|
||||||
|
:order order
|
||||||
|
:on-row-moved #(do (dispatch-sync [:change-contact-group-order (:from %) (:to %)])
|
||||||
|
(.forceUpdate this))
|
||||||
|
:render-row (fn [row]
|
||||||
|
(sortable-item [group-item row]))
|
||||||
|
:render-separator (render-separator (last order))}]]
|
||||||
|
[sticky-button (label :t/save) #(do
|
||||||
|
(dispatch [:save-contact-group-order])
|
||||||
|
(dispatch [:navigate-to-clean :contact-list]))]])))
|
@ -1,17 +1,6 @@
|
|||||||
(ns status-im.new-group.styles
|
(ns status-im.group.styles
|
||||||
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||||
(:require [status-im.components.styles :refer [color-white
|
(:require [status-im.components.styles :as common]))
|
||||||
color-blue
|
|
||||||
color-black
|
|
||||||
text1-color
|
|
||||||
text2-color
|
|
||||||
color-light-blue
|
|
||||||
color-light-red
|
|
||||||
color-light-gray
|
|
||||||
selected-contact-color
|
|
||||||
color-gray4
|
|
||||||
color-gray5]]
|
|
||||||
[status-im.utils.platform :refer [platform-specific] :as p]))
|
|
||||||
|
|
||||||
(defn toolbar-icon [enabled?]
|
(defn toolbar-icon [enabled?]
|
||||||
{:width 20
|
{:width 20
|
||||||
@ -21,70 +10,38 @@
|
|||||||
(def group-container
|
(def group-container
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:flex-direction :column
|
:flex-direction :column
|
||||||
:background-color color-white})
|
:background-color common/color-white})
|
||||||
|
|
||||||
(def reorder-groups-container
|
(def reorder-groups-container
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:flex-direction :column
|
:flex-direction :column
|
||||||
:background-color color-light-gray})
|
:background-color common/color-light-gray})
|
||||||
|
|
||||||
(defstyle reorder-list-container
|
(defstyle reorder-list-container
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:android {:padding-top 16}})
|
:android {:padding-top 16}})
|
||||||
|
|
||||||
(def chat-name-container
|
|
||||||
{:padding-left 16
|
|
||||||
:margin-top 10})
|
|
||||||
|
|
||||||
(def group-name-container
|
(def group-name-container
|
||||||
{:margin-top 10})
|
{:margin-top 10})
|
||||||
|
|
||||||
(def add-button-container
|
(def add-button-container
|
||||||
{:margin-left 16})
|
{:margin-left 16})
|
||||||
|
|
||||||
(def group-chat-name-input
|
|
||||||
{:font-size 17
|
|
||||||
:padding-bottom 0
|
|
||||||
:letter-spacing -0.2
|
|
||||||
:color text1-color})
|
|
||||||
|
|
||||||
(defstyle group-chat-topic-input
|
|
||||||
{:font-size 14
|
|
||||||
:line-height 16
|
|
||||||
:color text1-color
|
|
||||||
:padding-left 13
|
|
||||||
:ios {:padding-bottom 0}})
|
|
||||||
|
|
||||||
(defstyle topic-hash-style
|
|
||||||
{:width 10
|
|
||||||
:position :absolute
|
|
||||||
:android {:top 8 :left 3}
|
|
||||||
:ios {:top 6 :left 3}})
|
|
||||||
|
|
||||||
(def topic-hash
|
|
||||||
(merge group-chat-name-input
|
|
||||||
topic-hash-style))
|
|
||||||
|
|
||||||
(def group-chat-name-wrapper
|
|
||||||
{:padding-top 0
|
|
||||||
:height 40
|
|
||||||
:padding-bottom 0})
|
|
||||||
|
|
||||||
(defstyle group-name-text
|
(defstyle group-name-text
|
||||||
{:letter-spacing -0.1
|
{:letter-spacing -0.1
|
||||||
:color color-gray4
|
:color common/color-gray4
|
||||||
:ios {:font-size 13}
|
:ios {:font-size 13}
|
||||||
:android {:font-size 12}})
|
:android {:font-size 12}})
|
||||||
|
|
||||||
(defstyle members-text
|
(defstyle members-text
|
||||||
{:color color-gray4
|
{:color common/color-gray4
|
||||||
:ios {:letter-spacing -0.2
|
:ios {:letter-spacing -0.2
|
||||||
:font-size 16}
|
:font-size 16}
|
||||||
:android {:font-size 14}})
|
:android {:font-size 14}})
|
||||||
|
|
||||||
(defstyle members-text-count
|
(defstyle members-text-count
|
||||||
{:margin-left 8
|
{:margin-left 8
|
||||||
:color color-gray4
|
:color common/color-gray4
|
||||||
:opacity 0.6
|
:opacity 0.6
|
||||||
:ios {:letter-spacing -0.2
|
:ios {:letter-spacing -0.2
|
||||||
:font-size 16}
|
:font-size 16}
|
||||||
@ -110,8 +67,8 @@
|
|||||||
:height 24})
|
:height 24})
|
||||||
|
|
||||||
(defstyle add-group-text
|
(defstyle add-group-text
|
||||||
{:color color-light-blue
|
{:color common/color-light-blue
|
||||||
:ios {:color color-light-blue
|
:ios {:color common/color-light-blue
|
||||||
:letter-spacing -0.2
|
:letter-spacing -0.2
|
||||||
:font-size 17
|
:font-size 17
|
||||||
:line-height 20}
|
:line-height 20}
|
||||||
@ -126,10 +83,10 @@
|
|||||||
|
|
||||||
(def delete-group-text
|
(def delete-group-text
|
||||||
(merge add-group-text
|
(merge add-group-text
|
||||||
{:color color-light-red}))
|
{:color common/color-light-red}))
|
||||||
|
|
||||||
(defstyle delete-group-prompt-text
|
(defstyle delete-group-prompt-text
|
||||||
{:color color-gray4
|
{:color common/color-gray4
|
||||||
:padding-top 5
|
:padding-top 5
|
||||||
:ios {:font-size 14
|
:ios {:font-size 14
|
||||||
:letter-spacing -0.2}
|
:letter-spacing -0.2}
|
||||||
@ -162,7 +119,7 @@
|
|||||||
:border-radius 50}})
|
:border-radius 50}})
|
||||||
|
|
||||||
(def order-item-container
|
(def order-item-container
|
||||||
{:background-color color-white})
|
{:background-color common/color-white})
|
||||||
|
|
||||||
(defstyle order-item-inner-container
|
(defstyle order-item-inner-container
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
@ -170,7 +127,7 @@
|
|||||||
:android {:padding-top 17
|
:android {:padding-top 17
|
||||||
:padding-bottom 15
|
:padding-bottom 15
|
||||||
:min-height 56
|
:min-height 56
|
||||||
:background-color color-white}
|
:background-color common/color-white}
|
||||||
:ios {:padding-vertical 22
|
:ios {:padding-vertical 22
|
||||||
:min-height 63}})
|
:min-height 63}})
|
||||||
|
|
||||||
@ -178,7 +135,7 @@
|
|||||||
{:padding-left 16
|
{:padding-left 16
|
||||||
:flex-shrink 1
|
:flex-shrink 1
|
||||||
:android {:font-size 16
|
:android {:font-size 16
|
||||||
:color color-black
|
:color common/color-black
|
||||||
:line-height 24}
|
:line-height 24}
|
||||||
:ios {:font-size 17
|
:ios {:font-size 17
|
||||||
:line-height 20
|
:line-height 20
|
||||||
@ -186,7 +143,7 @@
|
|||||||
|
|
||||||
(defstyle order-item-contacts
|
(defstyle order-item-contacts
|
||||||
{:padding-left 8
|
{:padding-left 8
|
||||||
:color color-gray4
|
:color common/color-gray4
|
||||||
:ios {:font-size 17
|
:ios {:font-size 17
|
||||||
:line-height 20
|
:line-height 20
|
||||||
:letter-spacing -0.2}
|
:letter-spacing -0.2}
|
||||||
@ -198,22 +155,22 @@
|
|||||||
:ios {:padding-horizontal 20}})
|
:ios {:padding-horizontal 20}})
|
||||||
|
|
||||||
(def order-item-separator-wrapper
|
(def order-item-separator-wrapper
|
||||||
{:background-color color-white})
|
{:background-color common/color-white})
|
||||||
|
|
||||||
(def order-item-separator
|
(def order-item-separator
|
||||||
{:height 1
|
{:height 1
|
||||||
:background-color color-gray5
|
:background-color common/color-gray5
|
||||||
:ios {:margin-left 16
|
:ios {:margin-left 16
|
||||||
:opacity 0.5}})
|
:opacity 0.5}})
|
||||||
|
|
||||||
(def toolbar-title-with-count-text
|
(def toolbar-title-with-count-text
|
||||||
{:color text1-color
|
{:color common/text1-color
|
||||||
:letter-spacing -0.2
|
:letter-spacing -0.2
|
||||||
:font-size 17})
|
:font-size 17})
|
||||||
|
|
||||||
(def toolbar-title-with-count-text-count
|
(def toolbar-title-with-count-text-count
|
||||||
(merge toolbar-title-with-count-text
|
(merge toolbar-title-with-count-text
|
||||||
{:color color-light-blue}))
|
{:color common/color-light-blue}))
|
||||||
|
|
||||||
(def toolbar-title-with-count
|
(def toolbar-title-with-count
|
||||||
{:flex-direction :row})
|
{:flex-direction :row})
|
||||||
@ -222,7 +179,7 @@
|
|||||||
{:padding-left 6})
|
{:padding-left 6})
|
||||||
|
|
||||||
(def separator
|
(def separator
|
||||||
{:background-color color-gray5
|
{:background-color common/color-gray5
|
||||||
:height 1
|
:height 1
|
||||||
:opacity 0.5})
|
:opacity 0.5})
|
||||||
|
|
59
src/status_im/group/subs.cljs
Normal file
59
src/status_im/group/subs.cljs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
(ns status-im.group.subs
|
||||||
|
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||||
|
[status-im.utils.subs :as utils]))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:is-contact-selected?
|
||||||
|
(utils/contains-sub :group/selected-contacts))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:is-participant-selected?
|
||||||
|
(utils/contains-sub :selected-participants))
|
||||||
|
|
||||||
|
(defn filter-selected-contacts [selected-contacts contacts]
|
||||||
|
(remove #(true? (:pending? (contacts %))) selected-contacts))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:selected-contacts-count
|
||||||
|
:<- [:get :group/selected-contacts]
|
||||||
|
:<- [:get-contacts]
|
||||||
|
(fn [[selected-contacts contacts]]
|
||||||
|
(count (filter-selected-contacts selected-contacts contacts))))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:selected-participants-count
|
||||||
|
:<- [:get :selected-participants]
|
||||||
|
(fn [selected-participants]
|
||||||
|
(count selected-participants)))
|
||||||
|
|
||||||
|
(defn filter-contacts [selected-contacts added-contacts]
|
||||||
|
(filter #(selected-contacts (:whisper-identity %)) added-contacts))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:selected-group-contacts
|
||||||
|
:<- [:get :group/selected-contacts]
|
||||||
|
:<- [:all-added-contacts]
|
||||||
|
(fn [[selected-contacts added-contacts]]
|
||||||
|
(filter-contacts selected-contacts added-contacts)))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:get-contact-groups
|
||||||
|
(fn [db]
|
||||||
|
(:group/contact-groups db)))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:get-contact-group-id
|
||||||
|
(fn [db]
|
||||||
|
(:group/contact-group-id db)))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:get-contact-group
|
||||||
|
:<- [:get-contact-groups]
|
||||||
|
:<- [:get-contact-group-id]
|
||||||
|
(fn [[groups group-id]]
|
||||||
|
(get groups group-id)))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:get-group-type
|
||||||
|
(fn [db]
|
||||||
|
(:group/group-type db)))
|
169
src/status_im/group/views.cljs
Normal file
169
src/status_im/group/views.cljs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
(ns status-im.group.views
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
|
[status-im.contacts.styles :as cstyles]
|
||||||
|
[status-im.components.common.common :as common]
|
||||||
|
[status-im.components.action-button.action-button :refer [action-button action-separator]]
|
||||||
|
[status-im.components.react :refer [view text icon touchable-highlight
|
||||||
|
keyboard-avoiding-view list-view list-item]]
|
||||||
|
[status-im.components.text-input-with-label.view :refer [text-input-with-label]]
|
||||||
|
[status-im.components.status-bar :refer [status-bar]]
|
||||||
|
[status-im.components.toolbar-new.view :refer [toolbar]]
|
||||||
|
[status-im.utils.platform :refer [platform-specific]]
|
||||||
|
[status-im.components.sticky-button :refer [sticky-button]]
|
||||||
|
[status-im.utils.listview :refer [to-datasource]]
|
||||||
|
[status-im.components.renderers.renderers :as renderers]
|
||||||
|
[status-im.components.contact.contact :refer [contact-view]]
|
||||||
|
[status-im.group.styles :as styles]
|
||||||
|
[status-im.i18n :refer [label]]
|
||||||
|
[cljs.spec.alpha :as spec]
|
||||||
|
[status-im.group.db :as v]
|
||||||
|
[status-im.utils.utils :as utils]))
|
||||||
|
|
||||||
|
(defn group-toolbar [group-type edit?]
|
||||||
|
[view
|
||||||
|
[status-bar]
|
||||||
|
[toolbar
|
||||||
|
{:title (label
|
||||||
|
(if (= group-type :contact-group)
|
||||||
|
(if edit? :t/edit-group :t/new-group)
|
||||||
|
(if edit? :t/chat-settings :t/new-group-chat)))
|
||||||
|
:actions [{:image :blank}]}]])
|
||||||
|
|
||||||
|
(defview group-name-view []
|
||||||
|
(letsubs [new-group-name [:get :new-chat-name]]
|
||||||
|
[view styles/group-name-container
|
||||||
|
[text-input-with-label
|
||||||
|
{:auto-focus true
|
||||||
|
:label (label :t/name)
|
||||||
|
:on-change-text #(dispatch [:set :new-chat-name %])
|
||||||
|
:default-value new-group-name}]]))
|
||||||
|
|
||||||
|
(defn add-btn [on-press]
|
||||||
|
[action-button (label :t/add-members)
|
||||||
|
:add_blue
|
||||||
|
on-press])
|
||||||
|
|
||||||
|
(defn delete-btn [on-press]
|
||||||
|
[view styles/settings-group-container
|
||||||
|
[touchable-highlight {:on-press on-press}
|
||||||
|
[view styles/settings-group-item
|
||||||
|
[view styles/delete-icon-container
|
||||||
|
[icon :close_red styles/add-icon]]
|
||||||
|
[view styles/settings-group-text-container
|
||||||
|
[text {:style styles/delete-group-text}
|
||||||
|
(label :t/delete-group)]
|
||||||
|
[text {:style styles/delete-group-prompt-text}
|
||||||
|
(label :t/delete-group-prompt)]]]]])
|
||||||
|
|
||||||
|
(defn group-chat-settings-btns []
|
||||||
|
[view styles/settings-group-container
|
||||||
|
[view {:opacity 0.4}
|
||||||
|
[touchable-highlight {:on-press #()}
|
||||||
|
[view styles/settings-group-item
|
||||||
|
[view styles/settings-icon-container
|
||||||
|
[icon :speaker_blue styles/add-icon]]
|
||||||
|
[view styles/settings-group-text-container
|
||||||
|
[text {:style styles/settings-group-text}
|
||||||
|
(label :t/mute-notifications)]]]]]
|
||||||
|
[action-separator]
|
||||||
|
[action-button (label :t/clear-history)
|
||||||
|
:close_blue
|
||||||
|
#(dispatch [:clear-history])]
|
||||||
|
[action-separator]
|
||||||
|
[touchable-highlight {:on-press #(dispatch [:leave-group-chat])}
|
||||||
|
[view styles/settings-group-item
|
||||||
|
[view styles/delete-icon-container
|
||||||
|
[icon :arrow_right_red styles/add-icon]]
|
||||||
|
[view styles/settings-group-text-container
|
||||||
|
[text {:style styles/delete-group-text}
|
||||||
|
(label :t/leave-chat)]]]]])
|
||||||
|
|
||||||
|
(defn more-btn [contacts-limit contacts-count on-press]
|
||||||
|
[view
|
||||||
|
[common/list-separator]
|
||||||
|
[view cstyles/show-all
|
||||||
|
[touchable-highlight {:on-press on-press}
|
||||||
|
[view
|
||||||
|
[text {:style cstyles/show-all-text
|
||||||
|
:uppercase? (get-in platform-specific [:uppercase?])
|
||||||
|
:font (get-in platform-specific [:component-styles :contacts :show-all-text-font])}
|
||||||
|
(str (- contacts-count contacts-limit) " " (label :t/more))]]]]])
|
||||||
|
|
||||||
|
(def ^:const contacts-limit 3)
|
||||||
|
|
||||||
|
(defview group-contacts-view [group]
|
||||||
|
(letsubs [contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit]
|
||||||
|
contacts-count [:all-added-group-contacts-count (:group-id group)]]
|
||||||
|
[view
|
||||||
|
(when (pos? contacts-count)
|
||||||
|
[common/list-separator])
|
||||||
|
[view
|
||||||
|
(doall
|
||||||
|
(map (fn [row]
|
||||||
|
^{:key row}
|
||||||
|
[view
|
||||||
|
[contact-view
|
||||||
|
{:contact row
|
||||||
|
:extend-options [{:value #(dispatch [:remove-contact-from-group
|
||||||
|
(:whisper-identity row)
|
||||||
|
(:group-id group)])
|
||||||
|
:text (label :t/remove-from-group)}]
|
||||||
|
:extended? true}]
|
||||||
|
(when-not (= row (last contacts))
|
||||||
|
[common/list-separator])])
|
||||||
|
contacts))]
|
||||||
|
(when (< contacts-limit contacts-count)
|
||||||
|
[more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-group-contact-list])])]))
|
||||||
|
|
||||||
|
(defview edit-contact-group []
|
||||||
|
(letsubs [group-name [:get :new-chat-name]
|
||||||
|
group [:get-contact-group]
|
||||||
|
type [:get-group-type]]
|
||||||
|
(let [save-btn-enabled? (and (spec/valid? ::v/name group-name)
|
||||||
|
(not= group-name (:name group)))]
|
||||||
|
[keyboard-avoiding-view {:style styles/group-container}
|
||||||
|
[group-toolbar type true]
|
||||||
|
[group-name-view]
|
||||||
|
[view styles/list-view-container
|
||||||
|
[add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])]
|
||||||
|
[group-contacts-view group]
|
||||||
|
[view styles/separator]
|
||||||
|
[delete-btn #(utils/show-confirmation
|
||||||
|
(str (label :t/delete-group) "?") (label :t/delete-group-confirmation) (label :t/delete)
|
||||||
|
(fn[]
|
||||||
|
(dispatch [:delete-contact-group])
|
||||||
|
(dispatch [:navigate-to-clean :contact-list])))]]
|
||||||
|
(when save-btn-enabled?
|
||||||
|
[sticky-button (label :t/save) #(dispatch [:set-contact-group-name])])])))
|
||||||
|
|
||||||
|
(defn render-row [row _ _]
|
||||||
|
(list-item
|
||||||
|
^{:key row}
|
||||||
|
[contact-view {:contact row}]))
|
||||||
|
|
||||||
|
(defview new-group []
|
||||||
|
(letsubs [contacts [:selected-group-contacts]
|
||||||
|
group-name [:get :new-chat-name]
|
||||||
|
group-type [:get-group-type]]
|
||||||
|
(let [save-btn-enabled? (and (spec/valid? ::v/name group-name) (pos? (count contacts)))]
|
||||||
|
[keyboard-avoiding-view (merge {:behavior :padding}
|
||||||
|
styles/group-container)
|
||||||
|
[group-toolbar group-type false]
|
||||||
|
[group-name-view]
|
||||||
|
[view styles/list-view-container
|
||||||
|
[list-view {:dataSource (to-datasource contacts)
|
||||||
|
:enableEmptySections true
|
||||||
|
:renderRow render-row
|
||||||
|
:bounces false
|
||||||
|
:keyboardShouldPersistTaps :always
|
||||||
|
:renderSeparator renderers/list-separator-renderer}]]
|
||||||
|
(when save-btn-enabled?
|
||||||
|
[sticky-button (label :t/save)
|
||||||
|
(if (= group-type :contact-group)
|
||||||
|
#(do
|
||||||
|
(dispatch [:create-new-contact-group group-name])
|
||||||
|
(dispatch [:navigate-to-clean :contact-list]))
|
||||||
|
#(dispatch [:create-new-group-chat-and-open group-name]))
|
||||||
|
true])])))
|
||||||
|
|
@ -1,198 +0,0 @@
|
|||||||
(ns status-im.group-settings.handlers
|
|
||||||
(:require [re-frame.core :refer [dispatch after enrich]]
|
|
||||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
|
||||||
[status-im.chat.handlers :refer [delete-messages!]]
|
|
||||||
[status-im.protocol.core :as protocol]
|
|
||||||
[status-im.utils.random :as random]
|
|
||||||
[status-im.data-store.contacts :as contacts]
|
|
||||||
[status-im.data-store.messages :as messages]
|
|
||||||
[status-im.data-store.chats :as chats]
|
|
||||||
[status-im.constants :refer [text-content-type]]
|
|
||||||
[status-im.navigation.handlers :as nav]))
|
|
||||||
|
|
||||||
(defn save-property!
|
|
||||||
[current-chat-id property-name value]
|
|
||||||
(chats/save-property current-chat-id property-name value))
|
|
||||||
|
|
||||||
(defn save-chat-property!
|
|
||||||
[db-name property-name]
|
|
||||||
(fn [{:keys [current-chat-id] :as db} _]
|
|
||||||
(let [property (db-name db)]
|
|
||||||
(save-property! current-chat-id property-name property))))
|
|
||||||
|
|
||||||
(defn update-chat-property
|
|
||||||
[db-name property-name]
|
|
||||||
(fn [{:keys [current-chat-id] :as db} _]
|
|
||||||
(let [property (db-name db)]
|
|
||||||
(assoc-in db [:chats current-chat-id property-name] property))))
|
|
||||||
|
|
||||||
(defn prepare-chat-settings
|
|
||||||
[{:keys [current-chat-id] :as db}]
|
|
||||||
(let [{:keys [name]} (-> db
|
|
||||||
(get-in [:chats current-chat-id])
|
|
||||||
(select-keys [:name :color]))]
|
|
||||||
(assoc db :new-chat-name name
|
|
||||||
:group-type :chat-group)))
|
|
||||||
|
|
||||||
(register-handler :show-group-settings
|
|
||||||
(after (fn [_ _] (dispatch [:navigate-to :chat-group-settings])))
|
|
||||||
prepare-chat-settings)
|
|
||||||
|
|
||||||
(register-handler :set-chat-name
|
|
||||||
(after (save-chat-property! :new-chat-name :name))
|
|
||||||
(update-chat-property :new-chat-name :name))
|
|
||||||
|
|
||||||
(register-handler :set-chat-color
|
|
||||||
(after (fn [{:keys [current-chat-id]} [_ color]]
|
|
||||||
(save-property! current-chat-id :color (name color))))
|
|
||||||
(fn [{:keys [current-chat-id] :as db} [_ color]]
|
|
||||||
(assoc-in db [:chats current-chat-id :color] color)))
|
|
||||||
|
|
||||||
(defn clear-messages
|
|
||||||
[{:keys [current-chat-id] :as db} _]
|
|
||||||
(-> db
|
|
||||||
(assoc-in [:chats current-chat-id :messages] '())
|
|
||||||
(assoc-in [:chats current-chat-id :last-message] nil)))
|
|
||||||
|
|
||||||
(register-handler :clear-history
|
|
||||||
(after delete-messages!)
|
|
||||||
clear-messages)
|
|
||||||
|
|
||||||
(defn remove-identities [collection identities]
|
|
||||||
(remove #(identities (:identity %)) collection))
|
|
||||||
|
|
||||||
(defn remove-members
|
|
||||||
[{:keys [current-chat-id selected-participants] :as db} _]
|
|
||||||
(update-in db [:chats current-chat-id :contacts]
|
|
||||||
remove-identities selected-participants))
|
|
||||||
|
|
||||||
(defn remove-members-from-chat!
|
|
||||||
[{:keys [current-chat-id selected-participants]} _]
|
|
||||||
(chats/remove-contacts current-chat-id selected-participants))
|
|
||||||
|
|
||||||
(defn notify-about-removing!
|
|
||||||
[{:keys [web3 current-chat-id selected-participants chats current-public-key]} _]
|
|
||||||
(let [{:keys [private public] :as new-keypair} (protocol/new-keypair!)
|
|
||||||
{:keys [name private-key public-key]
|
|
||||||
:as chat} (get chats current-chat-id)
|
|
||||||
old-keypair {:private private-key
|
|
||||||
:public public-key}
|
|
||||||
contacts (get chat :contacts)
|
|
||||||
identities (-> (map :identity contacts)
|
|
||||||
set
|
|
||||||
(clojure.set/difference selected-participants))]
|
|
||||||
(dispatch [:update-chat! {:chat-id current-chat-id
|
|
||||||
:private-key private
|
|
||||||
:public-key public}])
|
|
||||||
(doseq [participant selected-participants]
|
|
||||||
(let [id (random/id)]
|
|
||||||
(doseq [keypair [old-keypair new-keypair]]
|
|
||||||
(protocol/remove-from-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group-id current-chat-id
|
|
||||||
:identity participant
|
|
||||||
:keypair keypair
|
|
||||||
:message {:from current-public-key
|
|
||||||
:message-id id}}))))
|
|
||||||
(protocol/start-watching-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group-id current-chat-id
|
|
||||||
:identity current-public-key
|
|
||||||
:keypair new-keypair
|
|
||||||
:callback #(dispatch [:incoming-message %1 %2])})
|
|
||||||
(protocol/update-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group {:id current-chat-id
|
|
||||||
:name name
|
|
||||||
:contacts (conj identities current-public-key)
|
|
||||||
:admin current-public-key
|
|
||||||
:keypair new-keypair}
|
|
||||||
:identities identities
|
|
||||||
:message {:from current-public-key
|
|
||||||
:message-id (random/id)}})))
|
|
||||||
|
|
||||||
(defn system-message [message-id content]
|
|
||||||
{:from "system"
|
|
||||||
:message-id message-id
|
|
||||||
:content content
|
|
||||||
:content-type text-content-type})
|
|
||||||
|
|
||||||
(defn removed-participant-message [chat-id identity]
|
|
||||||
(let [contact-name (:name (contacts/get-by-id identity))]
|
|
||||||
(->> (str "You've removed " (or contact-name identity))
|
|
||||||
(system-message (random/id))
|
|
||||||
(messages/save chat-id))))
|
|
||||||
|
|
||||||
(defn create-removing-messages!
|
|
||||||
[{:keys [current-chat-id selected-participants]} _]
|
|
||||||
(doseq [participant selected-participants]
|
|
||||||
(removed-participant-message current-chat-id participant)))
|
|
||||||
|
|
||||||
(defn deselect-members [db _]
|
|
||||||
(assoc db :selected-participants #{}))
|
|
||||||
|
|
||||||
(register-handler :remove-participants
|
|
||||||
;; todo check if user have rights to add/remove participants
|
|
||||||
;; todo order of operations tb
|
|
||||||
(u/handlers->
|
|
||||||
remove-members
|
|
||||||
remove-members-from-chat!
|
|
||||||
notify-about-removing!
|
|
||||||
create-removing-messages!
|
|
||||||
deselect-members))
|
|
||||||
|
|
||||||
(defn add-members
|
|
||||||
[{:keys [current-chat-id selected-participants] :as db} _]
|
|
||||||
(let [new-identities (map #(hash-map :identity %) selected-participants)]
|
|
||||||
(update-in db [:chats current-chat-id :contacts] concat new-identities)))
|
|
||||||
|
|
||||||
(defn add-members-to-chat!
|
|
||||||
[{:keys [current-chat-id selected-participants]} _]
|
|
||||||
(chats/add-contacts current-chat-id selected-participants))
|
|
||||||
|
|
||||||
(defn notify-about-new-members!
|
|
||||||
[{:keys [current-chat-id selected-participants
|
|
||||||
current-public-key chats web3]} _]
|
|
||||||
(let [{:keys [name contacts]} (chats current-chat-id)
|
|
||||||
identities (map :identity contacts)
|
|
||||||
|
|
||||||
{:keys [public private]
|
|
||||||
:as new-keypair} (protocol/new-keypair!)
|
|
||||||
|
|
||||||
group-message {:web3 web3
|
|
||||||
:group {:id current-chat-id
|
|
||||||
:name name
|
|
||||||
:contacts (conj identities current-public-key)
|
|
||||||
:admin current-public-key}
|
|
||||||
:message {:from current-public-key
|
|
||||||
:message-id (random/id)}}]
|
|
||||||
(dispatch [:update-chat! {:chat-id current-chat-id
|
|
||||||
:public-key public
|
|
||||||
:private-key private}])
|
|
||||||
(protocol/start-watching-group! {:web3 web3
|
|
||||||
:group-id current-chat-id
|
|
||||||
:identity current-public-key
|
|
||||||
:keypair new-keypair
|
|
||||||
:callback #(dispatch [:incoming-message %1 %2])})
|
|
||||||
(protocol/invite-to-group!
|
|
||||||
(-> group-message
|
|
||||||
(assoc-in [:group :keypair] new-keypair)
|
|
||||||
(assoc :identities selected-participants)))
|
|
||||||
(protocol/update-group!
|
|
||||||
(-> group-message
|
|
||||||
(assoc-in [:group :keypair] new-keypair)
|
|
||||||
(assoc :identities identities)))
|
|
||||||
(doseq [identity selected-participants]
|
|
||||||
(protocol/add-to-group! {:web3 web3
|
|
||||||
:group-id current-chat-id
|
|
||||||
:identity identity
|
|
||||||
:keypair new-keypair
|
|
||||||
:message {:from current-public-key
|
|
||||||
:message-id (random/id)}}))))
|
|
||||||
|
|
||||||
(register-handler :add-new-participants
|
|
||||||
(u/handlers->
|
|
||||||
add-members
|
|
||||||
add-members-to-chat!
|
|
||||||
notify-about-new-members!
|
|
||||||
deselect-members))
|
|
@ -9,11 +9,11 @@
|
|||||||
[status-im.components.permissions :as permissions]
|
[status-im.components.permissions :as permissions]
|
||||||
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
||||||
status-im.chat.handlers
|
status-im.chat.handlers
|
||||||
status-im.group-settings.handlers
|
status-im.group.chat-settings.events
|
||||||
status-im.navigation.handlers
|
status-im.navigation.handlers
|
||||||
status-im.contacts.events
|
status-im.contacts.events
|
||||||
status-im.discover.handlers
|
status-im.discover.handlers
|
||||||
status-im.new-group.handlers
|
status-im.group.events
|
||||||
status-im.profile.handlers
|
status-im.profile.handlers
|
||||||
status-im.commands.handlers.loading
|
status-im.commands.handlers.loading
|
||||||
status-im.commands.handlers.jail
|
status-im.commands.handlers.jail
|
||||||
@ -79,7 +79,7 @@
|
|||||||
(dispatch [:initialize-sync-listener])
|
(dispatch [:initialize-sync-listener])
|
||||||
(dispatch [:initialize-chats])
|
(dispatch [:initialize-chats])
|
||||||
(dispatch [:load-contacts])
|
(dispatch [:load-contacts])
|
||||||
(dispatch [:load-groups])
|
(dispatch [:load-contact-groups])
|
||||||
(dispatch [:init-chat])
|
(dispatch [:init-chat])
|
||||||
(dispatch [:init-discoveries])
|
(dispatch [:init-discoveries])
|
||||||
(dispatch [:init-debug-mode address])
|
(dispatch [:init-debug-mode address])
|
||||||
|
@ -25,17 +25,16 @@
|
|||||||
[status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]]
|
[status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]]
|
||||||
[status-im.transactions.screens.transaction-details :refer [transaction-details]]
|
[status-im.transactions.screens.transaction-details :refer [transaction-details]]
|
||||||
[status-im.chats-list.screen :refer [chats-list]]
|
[status-im.chats-list.screen :refer [chats-list]]
|
||||||
[status-im.new-chat.screen :refer [new-chat]]
|
[status-im.chat.new-chat.view :refer [new-chat]]
|
||||||
[status-im.new-group.screen-private :refer [new-group
|
[status-im.chat.new-public-chat.view :refer [new-public-chat]]
|
||||||
edit-group]]
|
[status-im.group.views :refer [new-group edit-contact-group]]
|
||||||
[status-im.new-group.views.chat-group-settings :refer [chat-group-settings]]
|
[status-im.group.chat-settings.views :refer [chat-group-settings]]
|
||||||
[status-im.new-group.views.contact-list :refer [edit-group-contact-list
|
[status-im.group.edit-contacts.views :refer [edit-contact-group-contact-list
|
||||||
edit-chat-group-contact-list]]
|
edit-chat-group-contact-list]]
|
||||||
[status-im.new-group.views.contact-toggle-list :refer [contact-toggle-list
|
[status-im.group.add-contacts.views :refer [contact-toggle-list
|
||||||
add-contacts-toggle-list
|
add-contacts-toggle-list
|
||||||
add-participants-toggle-list]]
|
add-participants-toggle-list]]
|
||||||
[status-im.new-group.views.reorder-groups :refer [reorder-groups]]
|
[status-im.group.reorder.views :refer [reorder-groups]]
|
||||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
|
||||||
[status-im.profile.screen :refer [profile my-profile]]
|
[status-im.profile.screen :refer [profile my-profile]]
|
||||||
[status-im.profile.edit.screen :refer [edit-my-profile]]
|
[status-im.profile.edit.screen :refer [edit-my-profile]]
|
||||||
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
|
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
|
||||||
@ -97,14 +96,14 @@
|
|||||||
:chat-list main-tabs
|
:chat-list main-tabs
|
||||||
:new-chat new-chat
|
:new-chat new-chat
|
||||||
:new-group new-group
|
:new-group new-group
|
||||||
:edit-group edit-group
|
:edit-contact-group edit-contact-group
|
||||||
:chat-group-settings chat-group-settings
|
:chat-group-settings chat-group-settings
|
||||||
:edit-group-contact-list edit-group-contact-list
|
:edit-group-contact-list edit-contact-group-contact-list
|
||||||
:edit-chat-group-contact-list edit-chat-group-contact-list
|
:edit-chat-group-contact-list edit-chat-group-contact-list
|
||||||
:add-contacts-toggle-list add-contacts-toggle-list
|
:add-contacts-toggle-list add-contacts-toggle-list
|
||||||
:add-participants-toggle-list add-participants-toggle-list
|
:add-participants-toggle-list add-participants-toggle-list
|
||||||
:reorder-groups reorder-groups
|
:reorder-groups reorder-groups
|
||||||
:new-public-group new-public-group
|
:new-public-chat new-public-chat
|
||||||
:contact-list main-tabs
|
:contact-list main-tabs
|
||||||
:contact-toggle-list contact-toggle-list
|
:contact-toggle-list contact-toggle-list
|
||||||
:group-contacts contact-list
|
:group-contacts contact-list
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
(ns status-im.new-chat.screen
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.components.common.common :as common]
|
|
||||||
[status-im.components.renderers.renderers :as renderers]
|
|
||||||
[status-im.components.action-button.action-button :refer [action-button
|
|
||||||
action-separator]]
|
|
||||||
[status-im.components.action-button.styles :refer [actions-list]]
|
|
||||||
[status-im.components.react :refer [view text
|
|
||||||
image
|
|
||||||
touchable-highlight
|
|
||||||
list-view
|
|
||||||
list-item]]
|
|
||||||
[status-im.components.contact.contact :refer [contact-view]]
|
|
||||||
[status-im.components.status-bar :refer [status-bar]]
|
|
||||||
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
|
||||||
[status-im.components.drawer.view :refer [drawer-view]]
|
|
||||||
[status-im.new-chat.styles :as st]
|
|
||||||
[status-im.utils.listview :as lw]
|
|
||||||
[status-im.i18n :refer [label]]))
|
|
||||||
|
|
||||||
(defn options-list []
|
|
||||||
[view actions-list
|
|
||||||
[action-button (label :t/new-group-chat)
|
|
||||||
:private_group_big
|
|
||||||
#(dispatch [:open-contact-toggle-list :chat-group])]
|
|
||||||
[action-separator]
|
|
||||||
[action-button (label :t/new-public-group-chat)
|
|
||||||
:public_group_big
|
|
||||||
#(dispatch [:navigate-to :new-public-group])]
|
|
||||||
[action-separator]
|
|
||||||
[action-button (label :t/add-new-contact)
|
|
||||||
:add_blue
|
|
||||||
#(dispatch [:navigate-to :new-contact])]])
|
|
||||||
|
|
||||||
(defn contact-list-row []
|
|
||||||
(fn [row _ _]
|
|
||||||
(list-item ^{:key row}
|
|
||||||
[contact-view {:contact row
|
|
||||||
:on-press #(dispatch [:open-chat-with-contact %])}])))
|
|
||||||
|
|
||||||
(defview new-chat-toolbar []
|
|
||||||
[show-search [:get-in [:toolbar-search :show]]
|
|
||||||
search-text [:get-in [:toolbar-search :text]]]
|
|
||||||
[view
|
|
||||||
[status-bar]
|
|
||||||
(toolbar-with-search
|
|
||||||
{:show-search? (= show-search :contact-list)
|
|
||||||
:search-text search-text
|
|
||||||
:search-key :contact-list
|
|
||||||
:title (label :t/contacts-group-new-chat)
|
|
||||||
:search-placeholder (label :t/search-for)})])
|
|
||||||
|
|
||||||
(defview new-chat []
|
|
||||||
[contacts [:all-added-group-contacts-filtered]
|
|
||||||
params [:get :contacts/click-params]]
|
|
||||||
[drawer-view
|
|
||||||
[view st/contacts-list-container
|
|
||||||
[new-chat-toolbar]
|
|
||||||
(when contacts
|
|
||||||
[list-view {:dataSource (lw/to-datasource contacts)
|
|
||||||
:enableEmptySections true
|
|
||||||
:renderRow (contact-list-row)
|
|
||||||
:bounces false
|
|
||||||
:keyboardShouldPersistTaps :always
|
|
||||||
:renderHeader #(list-item
|
|
||||||
[view
|
|
||||||
[options-list]
|
|
||||||
[common/bottom-shadow]
|
|
||||||
[common/form-title (label :t/choose-from-contacts)
|
|
||||||
{:count-value (count contacts)}]
|
|
||||||
[common/list-header]])
|
|
||||||
:renderSeparator renderers/list-separator-renderer
|
|
||||||
:renderFooter #(list-item [view
|
|
||||||
[common/list-footer]
|
|
||||||
[common/bottom-shadow]])
|
|
||||||
:style st/contacts-list}])]])
|
|
@ -1,375 +0,0 @@
|
|||||||
(ns status-im.new-group.handlers
|
|
||||||
(:require [status-im.protocol.core :as protocol]
|
|
||||||
[re-frame.core :refer [after dispatch debug enrich]]
|
|
||||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
|
||||||
[status-im.components.styles :refer [default-chat-color]]
|
|
||||||
[status-im.data-store.chats :as chats]
|
|
||||||
[status-im.data-store.contact-groups :as groups]
|
|
||||||
[clojure.string :as s]
|
|
||||||
[status-im.i18n :refer [label]]
|
|
||||||
[status-im.utils.handlers :as u]
|
|
||||||
[status-im.utils.random :as random]
|
|
||||||
[taoensso.timbre :refer-macros [debug]]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.navigation.handlers :as nav]))
|
|
||||||
|
|
||||||
(defn clear-toolbar-search [db]
|
|
||||||
(-> db
|
|
||||||
(assoc-in [:toolbar-search :show] nil)
|
|
||||||
(assoc-in [:toolbar-search :text] "")))
|
|
||||||
|
|
||||||
(defmethod nav/preload-data! :add-contacts-toggle-list
|
|
||||||
[db _]
|
|
||||||
(->
|
|
||||||
(assoc db :selected-contacts #{})
|
|
||||||
(clear-toolbar-search)))
|
|
||||||
|
|
||||||
|
|
||||||
(defmethod nav/preload-data! :add-participants-toggle-list
|
|
||||||
[db _]
|
|
||||||
(->
|
|
||||||
(assoc db :selected-participants #{})
|
|
||||||
(clear-toolbar-search)))
|
|
||||||
|
|
||||||
(defn deselect-contact
|
|
||||||
[db [_ id]]
|
|
||||||
(update db :selected-contacts disj id))
|
|
||||||
|
|
||||||
(register-handler :deselect-contact deselect-contact)
|
|
||||||
|
|
||||||
(defn select-contact
|
|
||||||
[db [_ id]]
|
|
||||||
(update db :selected-contacts conj id))
|
|
||||||
|
|
||||||
(register-handler :select-contact select-contact)
|
|
||||||
|
|
||||||
(defn group-name-from-contacts
|
|
||||||
[{:keys [selected-contacts username]
|
|
||||||
:contacts/keys [contacts]}]
|
|
||||||
(->> (select-keys contacts selected-contacts)
|
|
||||||
vals
|
|
||||||
(map :name)
|
|
||||||
(cons username)
|
|
||||||
(s/join ", ")))
|
|
||||||
|
|
||||||
(defn prepare-chat
|
|
||||||
[{:keys [selected-contacts current-public-key] :as db} [_ group-name]]
|
|
||||||
(let [contacts (mapv #(hash-map :identity %) selected-contacts)
|
|
||||||
chat-name (if-not (s/blank? group-name)
|
|
||||||
group-name
|
|
||||||
(group-name-from-contacts db))
|
|
||||||
{:keys [public private]} (protocol/new-keypair!)]
|
|
||||||
(assoc db :new-chat {:chat-id (random/id)
|
|
||||||
:public-key public
|
|
||||||
:private-key private
|
|
||||||
:name chat-name
|
|
||||||
:color default-chat-color
|
|
||||||
:group-chat true
|
|
||||||
:group-admin current-public-key
|
|
||||||
:is-active true
|
|
||||||
:timestamp (random/timestamp)
|
|
||||||
:contacts contacts})))
|
|
||||||
|
|
||||||
(defn add-chat
|
|
||||||
[{:keys [new-chat] :as db} _]
|
|
||||||
(-> db
|
|
||||||
(assoc-in [:chats (:chat-id new-chat)] new-chat)
|
|
||||||
(assoc :selected-contacts #{})))
|
|
||||||
|
|
||||||
(defn create-chat!
|
|
||||||
[{:keys [new-chat]} _]
|
|
||||||
(chats/save new-chat))
|
|
||||||
|
|
||||||
(defn show-chat!
|
|
||||||
[{:keys [new-chat]} _]
|
|
||||||
(dispatch [:navigate-to-clean :chat-list])
|
|
||||||
(dispatch [:navigate-to :chat (:chat-id new-chat)]))
|
|
||||||
|
|
||||||
(defn start-listen-group!
|
|
||||||
[{:keys [new-chat web3 current-public-key]} _]
|
|
||||||
(let [{:keys [chat-id public-key private-key contacts name]} new-chat
|
|
||||||
identities (mapv :identity contacts)]
|
|
||||||
(protocol/invite-to-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group {:id chat-id
|
|
||||||
:name name
|
|
||||||
:contacts (conj identities current-public-key)
|
|
||||||
:admin current-public-key
|
|
||||||
:keypair {:public public-key
|
|
||||||
:private private-key}}
|
|
||||||
:identities identities
|
|
||||||
:message {:from current-public-key
|
|
||||||
:message-id (random/id)}})
|
|
||||||
(protocol/start-watching-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group-id chat-id
|
|
||||||
:identity current-public-key
|
|
||||||
:keypair {:public public-key
|
|
||||||
:private private-key}
|
|
||||||
:callback #(dispatch [:incoming-message %1 %2])})))
|
|
||||||
|
|
||||||
(register-handler :create-new-group-chat
|
|
||||||
(u/handlers->
|
|
||||||
prepare-chat
|
|
||||||
add-chat
|
|
||||||
create-chat!
|
|
||||||
show-chat!
|
|
||||||
start-listen-group!))
|
|
||||||
|
|
||||||
(register-handler :create-new-public-group
|
|
||||||
(after (fn [_ [_ topic]]
|
|
||||||
(dispatch [:navigate-to-clean :chat-list])
|
|
||||||
(dispatch [:navigate-to :chat topic])))
|
|
||||||
(u/side-effect!
|
|
||||||
(fn [db [_ topic]]
|
|
||||||
(let [exists? (boolean (get-in db [:chats topic]))
|
|
||||||
group {:chat-id topic
|
|
||||||
:name topic
|
|
||||||
:color default-chat-color
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:is-active true
|
|
||||||
:timestamp (random/timestamp)}]
|
|
||||||
(when-not exists?
|
|
||||||
(dispatch [::add-public-group group])
|
|
||||||
(dispatch [::save-public-group group])
|
|
||||||
(dispatch [::start-watching-group topic]))))))
|
|
||||||
|
|
||||||
(register-handler ::add-public-group
|
|
||||||
(fn [db [_ {:keys [chat-id] :as group}]]
|
|
||||||
(assoc-in db [:chats chat-id] group)))
|
|
||||||
|
|
||||||
(register-handler ::save-public-group
|
|
||||||
(u/side-effect!
|
|
||||||
(fn [_ [_ group]]
|
|
||||||
(chats/save group))))
|
|
||||||
|
|
||||||
(register-handler ::start-watching-group
|
|
||||||
(u/side-effect!
|
|
||||||
(fn [{:keys [web3 current-public-key]} [_ topic]]
|
|
||||||
(protocol/start-watching-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group-id topic
|
|
||||||
:identity current-public-key
|
|
||||||
:callback #(dispatch [:incoming-message %1 %2])}))))
|
|
||||||
|
|
||||||
(register-handler :group-chat-invite-received
|
|
||||||
(u/side-effect!
|
|
||||||
(fn [{:keys [current-public-key web3]}
|
|
||||||
[_ {:keys [from]
|
|
||||||
{:keys [group-id group-name contacts keypair timestamp]} :payload}]]
|
|
||||||
(let [{:keys [private public]} keypair]
|
|
||||||
(let [contacts' (keep (fn [ident]
|
|
||||||
(when (not= ident current-public-key)
|
|
||||||
{:identity ident})) contacts)
|
|
||||||
chat {:chat-id group-id
|
|
||||||
:name group-name
|
|
||||||
:group-chat true
|
|
||||||
:group-admin from
|
|
||||||
:public-key public
|
|
||||||
:private-key private
|
|
||||||
:contacts contacts'
|
|
||||||
:added-to-at timestamp
|
|
||||||
:timestamp timestamp
|
|
||||||
:is-active true}
|
|
||||||
|
|
||||||
exists? (chats/exists? group-id)]
|
|
||||||
(when (or (not exists?) (chats/new-update? timestamp group-id))
|
|
||||||
(if exists?
|
|
||||||
(dispatch [:update-chat! chat])
|
|
||||||
(dispatch [:add-chat group-id chat]))
|
|
||||||
(protocol/start-watching-group!
|
|
||||||
{:web3 web3
|
|
||||||
:group-id group-id
|
|
||||||
:identity current-public-key
|
|
||||||
:keypair keypair
|
|
||||||
:callback #(dispatch [:incoming-message %1 %2])})))))))
|
|
||||||
|
|
||||||
(defn prepare-group
|
|
||||||
[{:keys [selected-contacts contact-groups] :as db} [_ group-name]]
|
|
||||||
(let [contacts (mapv #(hash-map :identity %) selected-contacts)]
|
|
||||||
(assoc db :new-group {:group-id (random/id)
|
|
||||||
:name group-name
|
|
||||||
:order (count contact-groups)
|
|
||||||
:timestamp (random/timestamp)
|
|
||||||
:contacts contacts})))
|
|
||||||
|
|
||||||
(defn add-group
|
|
||||||
[{:keys [new-group] :as db} _]
|
|
||||||
(update db :contact-groups merge {(:group-id new-group) new-group}))
|
|
||||||
|
|
||||||
(defn update-group
|
|
||||||
[{:keys [new-group] :as db} _]
|
|
||||||
(update db :contact-groups merge {(:group-id new-group) new-group}))
|
|
||||||
|
|
||||||
(defn save-group!
|
|
||||||
[{:keys [new-group]} _]
|
|
||||||
(groups/save new-group))
|
|
||||||
|
|
||||||
(defn show-contact-list!
|
|
||||||
[_ _]
|
|
||||||
(dispatch [:navigate-to-clean :contact-list]))
|
|
||||||
|
|
||||||
(register-handler :create-new-group
|
|
||||||
(u/handlers->
|
|
||||||
prepare-group
|
|
||||||
add-group
|
|
||||||
save-group!
|
|
||||||
show-contact-list!))
|
|
||||||
|
|
||||||
(defn update-new-group
|
|
||||||
[db [_ new-group]]
|
|
||||||
(assoc db :new-group new-group))
|
|
||||||
|
|
||||||
(register-handler :update-group
|
|
||||||
(u/handlers->
|
|
||||||
update-new-group
|
|
||||||
update-group
|
|
||||||
save-group!))
|
|
||||||
|
|
||||||
(defn save-groups! [{:keys [new-groups]} _]
|
|
||||||
(groups/save-all new-groups))
|
|
||||||
|
|
||||||
(defn update-pending-status [old-groups {:keys [group-id pending?] :as group}]
|
|
||||||
(let [{old-pending :pending?
|
|
||||||
:as old-group} (get old-groups group-id)
|
|
||||||
pending?' (if old-pending (and old-pending pending?) pending?)]
|
|
||||||
(assoc group :pending? (boolean pending?'))))
|
|
||||||
|
|
||||||
(defn add-new-groups
|
|
||||||
[{:keys [contact-groups] :as db} [_ new-groups]]
|
|
||||||
(let [identities (set (keys contact-groups))
|
|
||||||
old-groups-count (count identities)
|
|
||||||
new-groups' (->> new-groups
|
|
||||||
(map #(update-pending-status contact-groups %))
|
|
||||||
(remove #(identities (:group-id %)))
|
|
||||||
(map #(vector (:group-id %2) (assoc %2 :order %1)) (iterate inc old-groups-count))
|
|
||||||
(into {}))]
|
|
||||||
(-> db
|
|
||||||
(update :contact-groups merge new-groups')
|
|
||||||
(assoc :new-groups (into [] (vals new-groups'))))))
|
|
||||||
|
|
||||||
(register-handler :add-groups
|
|
||||||
(after save-groups!)
|
|
||||||
add-new-groups)
|
|
||||||
|
|
||||||
(defn load-groups! [db _]
|
|
||||||
(let [groups (->> (groups/get-all)
|
|
||||||
(map (fn [{:keys [group-id] :as group}]
|
|
||||||
[group-id group]))
|
|
||||||
(into {}))]
|
|
||||||
(assoc db :contact-groups groups)))
|
|
||||||
|
|
||||||
(register-handler :load-groups load-groups!)
|
|
||||||
|
|
||||||
(defmethod nav/preload-data! :new-public-group
|
|
||||||
[db]
|
|
||||||
(dissoc db :public-group-topic))
|
|
||||||
|
|
||||||
(defn move-item [v from to]
|
|
||||||
(if (< from to)
|
|
||||||
(concat (subvec v 0 from)
|
|
||||||
(subvec v (inc from) (inc to))
|
|
||||||
[(v from)]
|
|
||||||
(subvec v (inc to)))
|
|
||||||
(concat (subvec v 0 to)
|
|
||||||
[(v from)]
|
|
||||||
(subvec v to from)
|
|
||||||
(subvec v (inc from)))))
|
|
||||||
|
|
||||||
(register-handler :change-group-order
|
|
||||||
(fn [{:keys [groups-order] :as db} [_ from to]]
|
|
||||||
(if (>= to 0)
|
|
||||||
(assoc db :groups-order (move-item (vec groups-order) from to))
|
|
||||||
db)))
|
|
||||||
|
|
||||||
(register-handler :update-groups
|
|
||||||
(after save-groups!)
|
|
||||||
(fn [db [_ new-groups]]
|
|
||||||
(-> db
|
|
||||||
(update :contact-groups merge (map #(vector (:group-id %) %) new-groups))
|
|
||||||
(assoc :new-groups new-groups))))
|
|
||||||
|
|
||||||
(register-handler :save-group-order
|
|
||||||
(u/side-effect!
|
|
||||||
(fn [{:keys [groups-order contact-groups] :as db} _]
|
|
||||||
(let [new-groups (mapv #(assoc (contact-groups (second %)) :order (first %))
|
|
||||||
(map-indexed vector (reverse groups-order)))]
|
|
||||||
(dispatch [:update-groups new-groups])
|
|
||||||
(dispatch [:navigate-to-clean :contact-list])))))
|
|
||||||
|
|
||||||
(defn save-property!
|
|
||||||
[contact-group-id property-name value]
|
|
||||||
(groups/save-property contact-group-id property-name value))
|
|
||||||
|
|
||||||
(defn save-group-property!
|
|
||||||
[db-name property-name]
|
|
||||||
(fn [{:keys [contact-group-id] :as db} _]
|
|
||||||
(let [property (db-name db)]
|
|
||||||
(save-property! contact-group-id property-name property))))
|
|
||||||
|
|
||||||
(defn update-group-property
|
|
||||||
[db-name property-name]
|
|
||||||
(fn [{:keys [contact-group-id] :as db} _]
|
|
||||||
(let [property (db-name db)]
|
|
||||||
(assoc-in db [:contact-groups contact-group-id property-name] property))))
|
|
||||||
|
|
||||||
(register-handler :set-group-name
|
|
||||||
(after (save-group-property! :new-chat-name :name))
|
|
||||||
(update-group-property :new-chat-name :name))
|
|
||||||
|
|
||||||
(defn add-selected-contacts-to-group
|
|
||||||
[{:keys [selected-contacts contact-groups contact-group-id] :as db} _]
|
|
||||||
(let [new-identities (mapv #(hash-map :identity %) selected-contacts)]
|
|
||||||
(update-in db [:contact-groups contact-group-id :contacts] #(into [] (set (concat % new-identities))))))
|
|
||||||
|
|
||||||
(defn add-selected-contacts-to-group!
|
|
||||||
[{:keys [contact-group-id selected-contacts]} _]
|
|
||||||
(groups/add-contacts contact-group-id selected-contacts))
|
|
||||||
|
|
||||||
(register-handler :add-selected-contacts-to-group
|
|
||||||
(after add-selected-contacts-to-group!)
|
|
||||||
add-selected-contacts-to-group)
|
|
||||||
|
|
||||||
(defn add-contacts-to-group
|
|
||||||
[db [_ group-id contacts]]
|
|
||||||
(let [new-identities (mapv #(hash-map :identity %) contacts)]
|
|
||||||
(if (get-in db [:contact-groups group-id])
|
|
||||||
(update-in db [:contact-groups group-id :contacts] #(into [] (set (concat % new-identities))))
|
|
||||||
db)))
|
|
||||||
|
|
||||||
(defn add-contacts-to-group!
|
|
||||||
[db [_ group-id contacts]]
|
|
||||||
(when (get-in db [:contact-groups group-id])
|
|
||||||
(groups/add-contacts group-id contacts)))
|
|
||||||
|
|
||||||
(register-handler :add-contacts-to-group
|
|
||||||
(after add-contacts-to-group!)
|
|
||||||
add-contacts-to-group)
|
|
||||||
|
|
||||||
(defn delete-group []
|
|
||||||
(fn [{:keys [contact-group-id] :as db} _]
|
|
||||||
(assoc-in db [:contact-groups contact-group-id :pending?] true)))
|
|
||||||
|
|
||||||
(defn delete-group! []
|
|
||||||
(fn [{:keys [contact-group-id]} _]
|
|
||||||
(save-property! contact-group-id :pending? true)))
|
|
||||||
|
|
||||||
(register-handler :delete-group
|
|
||||||
(after (delete-group!))
|
|
||||||
(delete-group))
|
|
||||||
|
|
||||||
(defn deselect-participant
|
|
||||||
[db [_ id]]
|
|
||||||
(update db :selected-participants disj id))
|
|
||||||
|
|
||||||
(register-handler :deselect-participant deselect-participant)
|
|
||||||
|
|
||||||
(defn select-participant
|
|
||||||
[db [_ id]]
|
|
||||||
(update db :selected-participants conj id))
|
|
||||||
|
|
||||||
(register-handler :select-participant select-participant)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
|||||||
(ns status-im.new-group.screen-private
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.components.contact.contact :refer [contact-view]]
|
|
||||||
[status-im.components.common.common :as common]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
scroll-view
|
|
||||||
keyboard-avoiding-view
|
|
||||||
list-view
|
|
||||||
list-item]]
|
|
||||||
[status-im.components.renderers.renderers :as renderers]
|
|
||||||
[status-im.components.sticky-button :refer [sticky-button]]
|
|
||||||
[status-im.utils.utils :as u]
|
|
||||||
[status-im.utils.listview :refer [to-datasource]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.new-group.views.group :refer [group-toolbar
|
|
||||||
group-chat-settings-btns
|
|
||||||
group-name-view
|
|
||||||
add-btn
|
|
||||||
more-btn
|
|
||||||
delete-btn]]
|
|
||||||
[status-im.new-group.validations :as v]
|
|
||||||
[status-im.i18n :refer [label]]
|
|
||||||
[status-im.utils.platform :refer [ios?]]
|
|
||||||
[cljs.spec.alpha :as s]))
|
|
||||||
|
|
||||||
(def contacts-limit 3)
|
|
||||||
|
|
||||||
(defview group-contacts-view [group]
|
|
||||||
[contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit]
|
|
||||||
contacts-count [:all-added-group-contacts-count (:group-id group)]]
|
|
||||||
[view
|
|
||||||
(when (pos? contacts-count)
|
|
||||||
[common/list-separator])
|
|
||||||
[view
|
|
||||||
(doall
|
|
||||||
(map (fn [row]
|
|
||||||
^{:key row}
|
|
||||||
[view
|
|
||||||
[contact-view
|
|
||||||
{:contact row
|
|
||||||
:extend-options [{:value #(dispatch [:remove-contact-from-group
|
|
||||||
(:whisper-identity row)
|
|
||||||
(:group-id group)])
|
|
||||||
:text (label :t/remove-from-group)}]
|
|
||||||
:extended? true}]
|
|
||||||
(when-not (= row (last contacts))
|
|
||||||
[common/list-separator])])
|
|
||||||
contacts))]
|
|
||||||
(when (< contacts-limit contacts-count)
|
|
||||||
[more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-group-contact-list])])])
|
|
||||||
|
|
||||||
(defview edit-group []
|
|
||||||
[group-name [:get :new-chat-name]
|
|
||||||
group [:get-contact-group]
|
|
||||||
type [:get :group-type]]
|
|
||||||
(let [save-btn-enabled? (and (s/valid? ::v/name group-name)
|
|
||||||
(not= group-name (:name group)))]
|
|
||||||
[keyboard-avoiding-view {:style st/group-container}
|
|
||||||
[group-toolbar type true]
|
|
||||||
[group-name-view]
|
|
||||||
[view st/list-view-container
|
|
||||||
[add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])]
|
|
||||||
[group-contacts-view group]
|
|
||||||
[view st/separator]
|
|
||||||
[delete-btn #(u/show-confirmation
|
|
||||||
(str (label :t/delete-group) "?") (label :t/delete-group-confirmation) (label :t/delete)
|
|
||||||
(fn[]
|
|
||||||
(dispatch [:delete-group])
|
|
||||||
(dispatch [:navigate-to-clean :contact-list])))]]
|
|
||||||
(when save-btn-enabled?
|
|
||||||
[sticky-button (label :t/save) #(dispatch [:set-group-name])])]))
|
|
||||||
|
|
||||||
(defn render-row [row _ _]
|
|
||||||
(list-item
|
|
||||||
^{:key row}
|
|
||||||
[contact-view {:contact row}]))
|
|
||||||
|
|
||||||
(defview new-group []
|
|
||||||
[contacts [:selected-group-contacts]
|
|
||||||
group-name [:get :new-chat-name]
|
|
||||||
group-type [:get :group-type]]
|
|
||||||
(let [save-btn-enabled? (and (s/valid? ::v/name group-name) (pos? (count contacts)))]
|
|
||||||
[(if ios? keyboard-avoiding-view view) (merge {:behavior :padding}
|
|
||||||
st/group-container)
|
|
||||||
[group-toolbar group-type false]
|
|
||||||
[group-name-view]
|
|
||||||
[view st/list-view-container
|
|
||||||
[list-view {:dataSource (to-datasource contacts)
|
|
||||||
:enableEmptySections true
|
|
||||||
:renderRow render-row
|
|
||||||
:bounces false
|
|
||||||
:keyboardShouldPersistTaps :always
|
|
||||||
:renderSeparator renderers/list-separator-renderer}]]
|
|
||||||
(when save-btn-enabled?
|
|
||||||
[sticky-button (label :t/save)
|
|
||||||
(if (= group-type :contact-group)
|
|
||||||
#(dispatch [:create-new-group group-name])
|
|
||||||
#(dispatch [:create-new-group-chat group-name]))
|
|
||||||
;; once? set to true, so once component is mounted, on-press handler
|
|
||||||
;; will be executed only once
|
|
||||||
true])]))
|
|
@ -1,67 +0,0 @@
|
|||||||
(ns status-im.new-group.screen-public
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
|
||||||
[status-im.react-native.resources :as res]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
text
|
|
||||||
image
|
|
||||||
icon
|
|
||||||
touchable-highlight
|
|
||||||
list-view
|
|
||||||
list-item]]
|
|
||||||
[status-im.components.text-field.view :refer [text-field]]
|
|
||||||
[status-im.components.styles :refer [icon-ok
|
|
||||||
color-blue
|
|
||||||
color-gray4]]
|
|
||||||
[status-im.components.status-bar :refer [status-bar]]
|
|
||||||
[status-im.components.toolbar.view :refer [toolbar]]
|
|
||||||
[status-im.utils.listview :refer [to-datasource]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.new-group.validations :as v]
|
|
||||||
[status-im.i18n :refer [label]]
|
|
||||||
[cljs.spec.alpha :as s]))
|
|
||||||
|
|
||||||
(defview new-group-toolbar []
|
|
||||||
[topic [:get :public-group-topic]]
|
|
||||||
(let [create-btn-enabled? (s/valid? ::v/topic topic)]
|
|
||||||
[view
|
|
||||||
[status-bar]
|
|
||||||
[toolbar
|
|
||||||
{:title (label :t/new-public-group-chat)
|
|
||||||
:actions [{:image {:source {:uri (if create-btn-enabled?
|
|
||||||
:icon_ok_blue
|
|
||||||
:icon_ok_disabled)}
|
|
||||||
:style icon-ok}
|
|
||||||
:handler (when create-btn-enabled?
|
|
||||||
#(dispatch [:create-new-public-group topic]))}]}]]))
|
|
||||||
|
|
||||||
(defview group-name-input []
|
|
||||||
[topic [:get :public-group-topic]]
|
|
||||||
[view
|
|
||||||
[text-field
|
|
||||||
{:error (cond
|
|
||||||
(not (s/valid? ::v/not-empty-string topic))
|
|
||||||
(label :t/empty-topic)
|
|
||||||
|
|
||||||
(not (s/valid? ::v/topic topic))
|
|
||||||
(label :t/topic-format))
|
|
||||||
:wrapper-style st/group-chat-name-wrapper
|
|
||||||
:error-color color-blue
|
|
||||||
:line-color color-gray4
|
|
||||||
:label-hidden? true
|
|
||||||
:input-style st/group-chat-topic-input
|
|
||||||
:auto-focus true
|
|
||||||
:on-change-text #(dispatch [:set :public-group-topic %])
|
|
||||||
:value topic
|
|
||||||
:validator #(re-matches #"[a-z\-]*" %)
|
|
||||||
:auto-capitalize :none}]
|
|
||||||
[text {:style st/topic-hash} "#"]])
|
|
||||||
|
|
||||||
(defn new-public-group []
|
|
||||||
[view st/group-container
|
|
||||||
[new-group-toolbar]
|
|
||||||
[view st/chat-name-container
|
|
||||||
[text {:style st/members-text
|
|
||||||
:font :medium}
|
|
||||||
(label :t/public-group-topic)]
|
|
||||||
[group-name-input]]])
|
|
@ -1,11 +0,0 @@
|
|||||||
(ns status-im.new-group.specs
|
|
||||||
(:require [cljs.spec.alpha :as s]))
|
|
||||||
|
|
||||||
(s/def :group/contact-groups (s/nilable map?)) ;; {id (string) group (map)}
|
|
||||||
(s/def :group/contact-group-id (s/nilable string?)) ;;used during editing contact group
|
|
||||||
(s/def :group/group-type (s/nilable keyword?)) ;;contact group or chat group
|
|
||||||
(s/def :group/new-group (s/nilable map?)) ;;used during creating or edeting contact group
|
|
||||||
(s/def :group/new-groups (s/nilable vector?)) ;;used during creating or edeting contact groups
|
|
||||||
(s/def :group/contacts-group (s/nilable map?))
|
|
||||||
(s/def :group/selected-contacts (s/nilable set?))
|
|
||||||
(s/def :group/groups-order (s/nilable seq?)) ;;list of group ids
|
|
@ -1,37 +0,0 @@
|
|||||||
(ns status-im.new-group.subs
|
|
||||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
|
||||||
[status-im.utils.subs :as u]))
|
|
||||||
|
|
||||||
(reg-sub :is-contact-selected?
|
|
||||||
(u/contains-sub :selected-contacts))
|
|
||||||
|
|
||||||
(reg-sub :is-participant-selected?
|
|
||||||
(u/contains-sub :selected-participants))
|
|
||||||
|
|
||||||
(defn filter-selected-contacts [selected-contacts contacts]
|
|
||||||
(remove #(true? (:pending? (contacts %))) selected-contacts))
|
|
||||||
|
|
||||||
(reg-sub :selected-contacts-count
|
|
||||||
:<- [:get :selected-contacts]
|
|
||||||
:<- [:get-contacts]
|
|
||||||
(fn [[selected-contacts contacts]]
|
|
||||||
;TODO temporary, contact should be deleted from group after contact deletion from contacts
|
|
||||||
(count (filter-selected-contacts selected-contacts contacts))))
|
|
||||||
|
|
||||||
(reg-sub :selected-participants-count
|
|
||||||
:<- [:get :selected-participants]
|
|
||||||
(fn [selected-participants]
|
|
||||||
(count selected-participants)))
|
|
||||||
|
|
||||||
(defn filter-contacts [selected-contacts added-contacts]
|
|
||||||
(filter #(selected-contacts (:whisper-identity %)) added-contacts))
|
|
||||||
|
|
||||||
(reg-sub :selected-group-contacts
|
|
||||||
:<- [:get :selected-contacts]
|
|
||||||
:<- [:all-added-contacts]
|
|
||||||
(fn [[selected-contacts added-contacts]]
|
|
||||||
(filter-contacts selected-contacts added-contacts)))
|
|
||||||
|
|
||||||
(reg-sub :get-contact-group
|
|
||||||
(fn [db]
|
|
||||||
((:contact-groups db) (:contact-group-id db))))
|
|
@ -1,21 +0,0 @@
|
|||||||
(ns status-im.new-group.validations
|
|
||||||
(:require [cljs.spec.alpha :as s]
|
|
||||||
[status-im.utils.phone-number :refer [valid-mobile-number?]]
|
|
||||||
[status-im.constants :refer [console-chat-id wallet-chat-id]]
|
|
||||||
[clojure.string :as str]
|
|
||||||
[status-im.utils.homoglyph :as h]))
|
|
||||||
|
|
||||||
(defn not-illegal-name? [username]
|
|
||||||
(let [username (some-> username (str/trim))]
|
|
||||||
(and (not (h/matches username console-chat-id))
|
|
||||||
(not (h/matches username wallet-chat-id)))))
|
|
||||||
|
|
||||||
(s/def ::not-empty-string (s/and string? not-empty))
|
|
||||||
(s/def ::not-illegal-name not-illegal-name?)
|
|
||||||
|
|
||||||
(s/def ::name (s/and ::not-empty-string
|
|
||||||
::not-illegal-name))
|
|
||||||
|
|
||||||
(s/def ::topic (s/and ::not-empty-string
|
|
||||||
::not-illegal-name
|
|
||||||
(partial re-matches #"[a-z0-9\-]+")))
|
|
@ -1,78 +0,0 @@
|
|||||||
(ns status-im.new-group.views.chat-group-settings
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.components.contact.contact :refer [contact-view]]
|
|
||||||
[status-im.components.common.common :as common]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
scroll-view
|
|
||||||
keyboard-avoiding-view
|
|
||||||
icon
|
|
||||||
touchable-highlight]]
|
|
||||||
[status-im.components.sticky-button :refer [sticky-button]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.new-group.views.group :refer [group-toolbar
|
|
||||||
group-chat-settings-btns
|
|
||||||
group-name-view
|
|
||||||
add-btn
|
|
||||||
more-btn
|
|
||||||
delete-btn]]
|
|
||||||
[status-im.new-group.validations :as v]
|
|
||||||
[status-im.i18n :refer [label]]
|
|
||||||
[status-im.utils.platform :refer [ios?]]
|
|
||||||
[cljs.spec.alpha :as s]))
|
|
||||||
|
|
||||||
(def contacts-limit 3)
|
|
||||||
|
|
||||||
(defview chat-group-contacts-view [admin?]
|
|
||||||
[contacts [:current-chat-contacts]]
|
|
||||||
(let [limited-contacts (take contacts-limit contacts)
|
|
||||||
contacts-count (count contacts)]
|
|
||||||
[view
|
|
||||||
(when (and admin? (pos? contacts-count))
|
|
||||||
[common/list-separator])
|
|
||||||
[view
|
|
||||||
(doall
|
|
||||||
(map (fn [row]
|
|
||||||
^{:key row}
|
|
||||||
[view
|
|
||||||
[contact-view
|
|
||||||
{:contact row
|
|
||||||
:extend-options [{:value #(do
|
|
||||||
(dispatch [:set :selected-participants #{(:whisper-identity row)}])
|
|
||||||
(dispatch [:remove-participants]))
|
|
||||||
:text (label :t/remove)}]
|
|
||||||
:extended? admin?}]
|
|
||||||
(when-not (= row (last limited-contacts))
|
|
||||||
[common/list-separator])])
|
|
||||||
limited-contacts))]
|
|
||||||
(when (< contacts-limit contacts-count)
|
|
||||||
[more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-chat-group-contact-list])])]))
|
|
||||||
|
|
||||||
(defview chat-group-members []
|
|
||||||
[current-pk [:get :current-public-key]
|
|
||||||
group-admin [:chat :group-admin]]
|
|
||||||
(let [admin? (= current-pk group-admin)]
|
|
||||||
[view
|
|
||||||
(when admin?
|
|
||||||
[add-btn #(dispatch [:navigate-to :add-participants-toggle-list])])
|
|
||||||
[chat-group-contacts-view admin?]]))
|
|
||||||
|
|
||||||
(defview chat-group-settings []
|
|
||||||
[new-chat-name [:get :new-chat-name]
|
|
||||||
chat-name [:chat :name]
|
|
||||||
type [:get :group-type]]
|
|
||||||
(let [save-btn-enabled? (and (s/valid? ::v/name new-chat-name)
|
|
||||||
(not= new-chat-name chat-name))]
|
|
||||||
[keyboard-avoiding-view {:style st/group-container}
|
|
||||||
[view {:flex 1}
|
|
||||||
[group-toolbar type true]
|
|
||||||
[scroll-view
|
|
||||||
[group-name-view]
|
|
||||||
[chat-group-members]
|
|
||||||
[view st/separator]
|
|
||||||
[group-chat-settings-btns]]]
|
|
||||||
(when save-btn-enabled?
|
|
||||||
[sticky-button (label :t/save) #(dispatch [:set-chat-name])
|
|
||||||
;; once? set to true, so once component is mounted, on-press handler
|
|
||||||
;; will be executed only once
|
|
||||||
true])]))
|
|
@ -1,78 +0,0 @@
|
|||||||
(ns status-im.new-group.views.contact-list
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.components.contact.contact :refer [contact-view]]
|
|
||||||
[status-im.components.renderers.renderers :as renderers]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
text
|
|
||||||
list-view
|
|
||||||
list-item]]
|
|
||||||
[status-im.components.status-bar :refer [status-bar]]
|
|
||||||
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
|
||||||
[status-im.utils.listview :refer [to-datasource]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.i18n :refer [label]]))
|
|
||||||
|
|
||||||
(defview contact-list-toolbar [title]
|
|
||||||
[show-search [:get-in [:toolbar-search :show]]
|
|
||||||
search-text [:get-in [:toolbar-search :text]]]
|
|
||||||
(toolbar-with-search
|
|
||||||
{:show-search? (= show-search :contact-list)
|
|
||||||
:search-text search-text
|
|
||||||
:search-key :contact-list
|
|
||||||
:title title
|
|
||||||
:search-placeholder (label :t/search-contacts)}))
|
|
||||||
|
|
||||||
(defn contacts-list [contacts renderer-function]
|
|
||||||
[view {:flex 1}
|
|
||||||
[list-view {:dataSource (to-datasource contacts)
|
|
||||||
:enableEmptySections true
|
|
||||||
:renderRow renderer-function
|
|
||||||
:bounces false
|
|
||||||
:keyboardShouldPersistTaps :always
|
|
||||||
:renderSeparator renderers/list-separator-renderer
|
|
||||||
:renderFooter renderers/list-footer-renderer
|
|
||||||
:renderHeader renderers/list-header-renderer}]])
|
|
||||||
|
|
||||||
(defview chat-contacts-list-view []
|
|
||||||
[contacts [:contacts-filtered :current-chat-contacts]
|
|
||||||
current-pk [:get :current-public-key]
|
|
||||||
group-admin [:chat :group-admin]]
|
|
||||||
(let [admin? (= current-pk group-admin)]
|
|
||||||
[contacts-list contacts (fn [row _ _]
|
|
||||||
(list-item
|
|
||||||
^{:key row}
|
|
||||||
[contact-view {:contact row
|
|
||||||
:extended? admin?
|
|
||||||
:extend-options [{:value #(do
|
|
||||||
(dispatch [:set :selected-participants
|
|
||||||
#{(:whisper-identity row)}])
|
|
||||||
(dispatch [:remove-participants]))
|
|
||||||
:text (label :t/remove)}]}]))]))
|
|
||||||
|
|
||||||
(defview contacts-list-view [group]
|
|
||||||
[contacts [:all-added-group-contacts-filtered (:group-id group)]]
|
|
||||||
[contacts-list contacts (fn [row _ _]
|
|
||||||
(list-item
|
|
||||||
^{:key row}
|
|
||||||
[contact-view {:contact row
|
|
||||||
:extended? true
|
|
||||||
:extend-options [{:value #(dispatch [:remove-contact-from-group
|
|
||||||
(:whisper-identity row)
|
|
||||||
(:group-id group)])
|
|
||||||
:text (label :t/remove-from-group)}]}]))])
|
|
||||||
|
|
||||||
(defview edit-chat-group-contact-list []
|
|
||||||
[chat-name [:chat :name]]
|
|
||||||
[view st/group-container
|
|
||||||
[status-bar]
|
|
||||||
[contact-list-toolbar chat-name]
|
|
||||||
[chat-contacts-list-view]])
|
|
||||||
|
|
||||||
(defview edit-group-contact-list []
|
|
||||||
[group [:get-contact-group]
|
|
||||||
type [:get :group-type]]
|
|
||||||
[view st/group-container
|
|
||||||
[status-bar]
|
|
||||||
[contact-list-toolbar (:name group)]
|
|
||||||
[contacts-list-view group]])
|
|
@ -1,95 +0,0 @@
|
|||||||
(ns status-im.new-group.views.contact-toggle-list
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.components.contact.contact :refer [contact-view]]
|
|
||||||
[status-im.components.renderers.renderers :as renderers]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
keyboard-avoiding-view
|
|
||||||
text
|
|
||||||
list-view
|
|
||||||
list-item]]
|
|
||||||
[status-im.components.sticky-button :refer [sticky-button]]
|
|
||||||
[status-im.components.status-bar :refer [status-bar]]
|
|
||||||
[status-im.components.toolbar-new.view :refer [toolbar-with-search]]
|
|
||||||
[status-im.utils.listview :refer [to-datasource]]
|
|
||||||
[status-im.utils.platform :refer [ios?]]
|
|
||||||
[status-im.new-group.views.toggle-contact :refer [group-toggle-contact
|
|
||||||
group-toggle-participant]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.contacts.styles :as cst]
|
|
||||||
[status-im.i18n :refer [label]]
|
|
||||||
[status-im.components.toolbar-new.actions :as act]))
|
|
||||||
|
|
||||||
(defn title-with-count [title count-value]
|
|
||||||
[view st/toolbar-title-with-count
|
|
||||||
[text {:style st/toolbar-title-with-count-text
|
|
||||||
:font :toolbar-title}
|
|
||||||
title]
|
|
||||||
(when (pos? count-value)
|
|
||||||
[view st/toolbar-title-with-count-container
|
|
||||||
[text {:style st/toolbar-title-with-count-text-count
|
|
||||||
:font :toolbar-title}
|
|
||||||
count-value]])])
|
|
||||||
|
|
||||||
(defview toggle-list-toolbar [title contacts-count]
|
|
||||||
[show-search [:get-in [:toolbar-search :show]]
|
|
||||||
search-text [:get-in [:toolbar-search :text]]]
|
|
||||||
(toolbar-with-search
|
|
||||||
{:show-search? (= show-search :contact-group-list)
|
|
||||||
:search-text search-text
|
|
||||||
:search-key :contact-group-list
|
|
||||||
:custom-title (title-with-count title contacts-count)
|
|
||||||
:search-placeholder (label :t/search-contacts)}))
|
|
||||||
|
|
||||||
(defn toggle-list [contacts render-function]
|
|
||||||
[view {:flex 1}
|
|
||||||
[list-view
|
|
||||||
{:dataSource (to-datasource contacts)
|
|
||||||
:renderRow (fn [row _ _]
|
|
||||||
(list-item ^{:key row} [render-function row]))
|
|
||||||
:renderSeparator renderers/list-separator-renderer
|
|
||||||
:renderFooter renderers/list-footer-renderer
|
|
||||||
:renderHeader renderers/list-header-renderer
|
|
||||||
:style cst/contacts-list
|
|
||||||
:keyboardShouldPersistTaps :always}]])
|
|
||||||
|
|
||||||
(defview contact-toggle-list []
|
|
||||||
[contacts [:all-added-group-contacts-filtered]
|
|
||||||
selected-contacts-count [:selected-contacts-count]
|
|
||||||
group-type [:get :group-type]]
|
|
||||||
[keyboard-avoiding-view {:style st/group-container}
|
|
||||||
[status-bar]
|
|
||||||
[toggle-list-toolbar
|
|
||||||
(label (if (= group-type :contact-group)
|
|
||||||
:t/new-group
|
|
||||||
:t/new-group-chat))
|
|
||||||
selected-contacts-count]
|
|
||||||
[toggle-list contacts group-toggle-contact]
|
|
||||||
(when (pos? selected-contacts-count)
|
|
||||||
[sticky-button (label :t/next) #(dispatch [:navigate-to :new-group])])])
|
|
||||||
|
|
||||||
(defview add-contacts-toggle-list []
|
|
||||||
[contacts [:all-group-not-added-contacts-filtered]
|
|
||||||
group [:get-contact-group]
|
|
||||||
selected-contacts-count [:selected-contacts-count]]
|
|
||||||
[keyboard-avoiding-view {:style st/group-container}
|
|
||||||
[status-bar]
|
|
||||||
[toggle-list-toolbar (:name group) selected-contacts-count]
|
|
||||||
[toggle-list contacts group-toggle-contact]
|
|
||||||
(when (pos? selected-contacts-count)
|
|
||||||
[sticky-button (label :t/save) #(do
|
|
||||||
(dispatch [:add-selected-contacts-to-group])
|
|
||||||
(dispatch [:navigate-back]))])])
|
|
||||||
|
|
||||||
(defview add-participants-toggle-list []
|
|
||||||
[contacts [:contacts-filtered :all-new-contacts]
|
|
||||||
chat-name [:chat :name]
|
|
||||||
selected-contacts-count [:selected-participants-count]]
|
|
||||||
[keyboard-avoiding-view {:style st/group-container}
|
|
||||||
[status-bar]
|
|
||||||
[toggle-list-toolbar chat-name selected-contacts-count]
|
|
||||||
[toggle-list contacts group-toggle-participant]
|
|
||||||
(when (pos? selected-contacts-count)
|
|
||||||
[sticky-button (label :t/save) #(do
|
|
||||||
(dispatch [:add-new-participants])
|
|
||||||
(dispatch [:navigate-back]))])])
|
|
@ -1,90 +0,0 @@
|
|||||||
(ns status-im.new-group.views.group
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.contacts.styles :as cst]
|
|
||||||
[status-im.components.common.common :as common]
|
|
||||||
[status-im.components.action-button.action-button :refer [action-button
|
|
||||||
action-button-disabled
|
|
||||||
action-separator]]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
text
|
|
||||||
icon
|
|
||||||
touchable-highlight]]
|
|
||||||
[status-im.components.text-input-with-label.view :refer [text-input-with-label]]
|
|
||||||
[status-im.components.styles :refer [color-blue color-gray5 color-light-blue]]
|
|
||||||
[status-im.components.status-bar :refer [status-bar]]
|
|
||||||
[status-im.components.toolbar-new.view :refer [toolbar]]
|
|
||||||
[status-im.utils.platform :refer [platform-specific]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.i18n :refer [label]]))
|
|
||||||
|
|
||||||
(defn group-toolbar [group-type edit?]
|
|
||||||
[view
|
|
||||||
[status-bar]
|
|
||||||
[toolbar
|
|
||||||
{:title (label
|
|
||||||
(if (= group-type :contact-group)
|
|
||||||
(if edit? :t/edit-group :t/new-group)
|
|
||||||
(if edit? :t/chat-settings :t/new-group-chat)))
|
|
||||||
:actions [{:image :blank}]}]])
|
|
||||||
|
|
||||||
(defview group-name-view []
|
|
||||||
[new-group-name [:get :new-chat-name]]
|
|
||||||
[view st/group-name-container
|
|
||||||
[text-input-with-label
|
|
||||||
{:auto-focus true
|
|
||||||
:label (label :t/name)
|
|
||||||
:on-change-text #(dispatch [:set :new-chat-name %])
|
|
||||||
:default-value new-group-name}]])
|
|
||||||
|
|
||||||
(defn add-btn [on-press]
|
|
||||||
[action-button (label :t/add-members)
|
|
||||||
:add_blue
|
|
||||||
on-press])
|
|
||||||
|
|
||||||
(defn delete-btn [on-press]
|
|
||||||
[view st/settings-group-container
|
|
||||||
[touchable-highlight {:on-press on-press}
|
|
||||||
[view st/settings-group-item
|
|
||||||
[view st/delete-icon-container
|
|
||||||
[icon :close_red st/add-icon]]
|
|
||||||
[view st/settings-group-text-container
|
|
||||||
[text {:style st/delete-group-text}
|
|
||||||
(label :t/delete-group)]
|
|
||||||
[text {:style st/delete-group-prompt-text}
|
|
||||||
(label :t/delete-group-prompt)]]]]])
|
|
||||||
|
|
||||||
(defn group-chat-settings-btns []
|
|
||||||
[view st/settings-group-container
|
|
||||||
[view {:opacity 0.4}
|
|
||||||
[touchable-highlight {:on-press #()}
|
|
||||||
[view st/settings-group-item
|
|
||||||
[view st/settings-icon-container
|
|
||||||
[icon :speaker_blue st/add-icon]]
|
|
||||||
[view st/settings-group-text-container
|
|
||||||
[text {:style st/settings-group-text}
|
|
||||||
(label :t/mute-notifications)]]]]]
|
|
||||||
[action-separator]
|
|
||||||
[action-button (label :t/clear-history)
|
|
||||||
:close_blue
|
|
||||||
#(dispatch [:clear-history])]
|
|
||||||
[action-separator]
|
|
||||||
[touchable-highlight {:on-press #(dispatch [:leave-group-chat])}
|
|
||||||
[view st/settings-group-item
|
|
||||||
[view st/delete-icon-container
|
|
||||||
[icon :arrow_right_red st/add-icon]]
|
|
||||||
[view st/settings-group-text-container
|
|
||||||
[text {:style st/delete-group-text}
|
|
||||||
(label :t/leave-chat)]]]]])
|
|
||||||
|
|
||||||
(defn more-btn [contacts-limit contacts-count on-press]
|
|
||||||
[view
|
|
||||||
[common/list-separator]
|
|
||||||
[view cst/show-all
|
|
||||||
[touchable-highlight {:on-press on-press}
|
|
||||||
[view
|
|
||||||
[text {:style cst/show-all-text
|
|
||||||
:uppercase? (get-in platform-specific [:uppercase?])
|
|
||||||
:font (get-in platform-specific [:component-styles :contacts :show-all-text-font])}
|
|
||||||
(str (- contacts-count contacts-limit) " " (label :t/more))]]]]])
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
|||||||
(ns status-im.new-group.views.reorder-groups
|
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
|
||||||
(:require [re-frame.core :refer [dispatch dispatch-sync]]
|
|
||||||
[status-im.components.react :refer [view
|
|
||||||
text
|
|
||||||
icon
|
|
||||||
touchable-highlight
|
|
||||||
list-item]]
|
|
||||||
[status-im.components.sticky-button :refer [sticky-button]]
|
|
||||||
[status-im.components.status-bar :refer [status-bar]]
|
|
||||||
[status-im.components.toolbar-new.view :refer [toolbar]]
|
|
||||||
[status-im.components.sortable-list-view :refer [sortable-list-view sortable-item]]
|
|
||||||
[status-im.components.common.common :as common]
|
|
||||||
[status-im.utils.listview :refer [to-datasource]]
|
|
||||||
[status-im.utils.platform :refer [android?]]
|
|
||||||
[status-im.new-group.styles :as st]
|
|
||||||
[status-im.i18n :refer [label label-pluralize]]
|
|
||||||
[status-im.utils.platform :refer [platform-specific]]
|
|
||||||
[reagent.core :as r]))
|
|
||||||
|
|
||||||
(defn toolbar-view []
|
|
||||||
[toolbar {:actions [{:image :blank}]
|
|
||||||
:title (label :t/reorder-groups)}])
|
|
||||||
|
|
||||||
(defn group-item [{:keys [name contacts] :as group}]
|
|
||||||
(let [cnt (count contacts)]
|
|
||||||
[view st/order-item-container
|
|
||||||
[view st/order-item-inner-container
|
|
||||||
[text {:style st/order-item-label}
|
|
||||||
name]
|
|
||||||
[text {:style st/order-item-contacts}
|
|
||||||
(str cnt " " (label-pluralize cnt :t/contact-s))]
|
|
||||||
[view {:flex 1}]
|
|
||||||
[view st/order-item-icon
|
|
||||||
[icon :grab_gray]]]]))
|
|
||||||
|
|
||||||
(defn render-separator [last]
|
|
||||||
(fn [_ row-id _]
|
|
||||||
(list-item
|
|
||||||
(if (= row-id last)
|
|
||||||
^{:key "bottom-shadow"}
|
|
||||||
[common/bottom-shadow]
|
|
||||||
^{:key row-id}
|
|
||||||
[view st/order-item-separator-wrapper
|
|
||||||
[view st/order-item-separator]]))))
|
|
||||||
|
|
||||||
(defview reorder-groups []
|
|
||||||
[groups [:get :contact-groups]
|
|
||||||
order [:get :groups-order]]
|
|
||||||
(let [this (r/current-component)]
|
|
||||||
[view st/reorder-groups-container
|
|
||||||
[status-bar]
|
|
||||||
[toolbar-view]
|
|
||||||
[view st/reorder-list-container
|
|
||||||
[common/top-shadow]
|
|
||||||
[sortable-list-view
|
|
||||||
{:data groups
|
|
||||||
:order order
|
|
||||||
:on-row-moved #(do (dispatch-sync [:change-group-order (:from %) (:to %)])
|
|
||||||
(.forceUpdate this))
|
|
||||||
:render-row (fn [row]
|
|
||||||
(sortable-item [group-item row]))
|
|
||||||
:render-separator (render-separator (last order))}]]
|
|
||||||
[sticky-button (label :t/save) #(dispatch [:save-group-order])]]))
|
|
@ -1,17 +0,0 @@
|
|||||||
(ns status-im.new-group.views.toggle-contact
|
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
|
||||||
[status-im.components.contact.contact :refer [toogle-contact-view]]))
|
|
||||||
|
|
||||||
(defn on-toggle [checked? whisper-identity]
|
|
||||||
(let [action (if checked? :deselect-contact :select-contact)]
|
|
||||||
(dispatch [action whisper-identity])))
|
|
||||||
|
|
||||||
(defn on-toggle-participant [checked? whisper-identity]
|
|
||||||
(let [action (if checked? :deselect-participant :select-participant)]
|
|
||||||
(dispatch [action whisper-identity])))
|
|
||||||
|
|
||||||
(defn group-toggle-contact [{:keys [whisper-identity] :as contact}]
|
|
||||||
[toogle-contact-view contact :is-contact-selected? on-toggle])
|
|
||||||
|
|
||||||
(defn group-toggle-participant [{:keys [whisper-identity] :as contact}]
|
|
||||||
[toogle-contact-view contact :is-participant-selected? on-toggle-participant])
|
|
@ -35,17 +35,17 @@
|
|||||||
(debug :send-group-message message)
|
(debug :send-group-message message)
|
||||||
(d/add-pending-message! web3 message)))
|
(d/add-pending-message! web3 message)))
|
||||||
|
|
||||||
(s/def :group/message
|
(s/def ::message
|
||||||
(s/merge :protocol/message (s/keys :req-un [:chat-message/payload])))
|
(s/merge :protocol/message (s/keys :req-un [:chat-message/payload])))
|
||||||
|
|
||||||
(s/def :public-group/username (s/and string? (complement str/blank?)))
|
(s/def :public-group/username (s/and string? (complement str/blank?)))
|
||||||
(s/def :public-group/message
|
(s/def :public-group/message
|
||||||
(s/merge :group/message (s/keys :username :public-group/username)))
|
(s/merge ::message (s/keys :username :public-group/username)))
|
||||||
|
|
||||||
(defn send!
|
(defn send!
|
||||||
[{:keys [keypair message] :as options}]
|
[{:keys [keypair message] :as options}]
|
||||||
{:pre [(valid? :message/keypair keypair)
|
{:pre [(valid? :message/keypair keypair)
|
||||||
(valid? :group/message message)]}
|
(valid? ::message message)]}
|
||||||
(send-group-message! options :group-message))
|
(send-group-message! options :group-message))
|
||||||
|
|
||||||
(defn send-to-public-group!
|
(defn send-to-public-group!
|
||||||
@ -74,16 +74,15 @@
|
|||||||
identity)]
|
identity)]
|
||||||
(send-group-message! options' :remove-group-identity)))
|
(send-group-message! options' :remove-group-identity)))
|
||||||
|
|
||||||
(s/def :group/admin :message/from)
|
|
||||||
(s/def ::identities (s/* string?))
|
(s/def ::identities (s/* string?))
|
||||||
|
|
||||||
(s/def :group/name string?)
|
(s/def ::name string?)
|
||||||
(s/def :group/id string?)
|
(s/def ::id string?)
|
||||||
(s/def :group/admin string?)
|
(s/def ::admin string?)
|
||||||
(s/def :group/contacts (s/* string?))
|
(s/def ::contacts (s/* string?))
|
||||||
(s/def ::group
|
(s/def ::group
|
||||||
(s/keys :req-un
|
(s/keys :req-un
|
||||||
[:group/name :group/id :group/contacts :message/keypair :group/admin]))
|
[::name ::id ::contacts :message/keypair ::admin]))
|
||||||
(s/def :invite/options
|
(s/def :invite/options
|
||||||
(s/keys :req-un [:options/web3 :protocol/message ::group ::identities]))
|
(s/keys :req-un [:options/web3 :protocol/message ::group ::identities]))
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
(ns status-im.specs
|
(ns status-im.specs
|
||||||
(:require-macros [status-im.utils.db :refer [allowed-keys]])
|
(:require-macros [status-im.utils.db :refer [allowed-keys]])
|
||||||
(:require [cljs.spec.alpha :as s]
|
(:require [cljs.spec.alpha :as spec]
|
||||||
[status-im.accounts.specs]
|
[status-im.accounts.specs]
|
||||||
[status-im.navigation.specs]
|
[status-im.navigation.specs]
|
||||||
[status-im.contacts.db]
|
[status-im.contacts.db]
|
||||||
[status-im.qr-scanner.specs]
|
[status-im.qr-scanner.specs]
|
||||||
[status-im.new-group.specs]
|
[status-im.group.db]
|
||||||
[status-im.chat.specs]
|
[status-im.chat.specs]
|
||||||
|
[status-im.chat.new-public-chat.db]
|
||||||
[status-im.profile.specs]
|
[status-im.profile.specs]
|
||||||
[status-im.transactions.specs]
|
[status-im.transactions.specs]
|
||||||
[status-im.discover.specs]))
|
[status-im.discover.specs]))
|
||||||
@ -14,39 +15,39 @@
|
|||||||
;;;;GLOBAL
|
;;;;GLOBAL
|
||||||
|
|
||||||
;;public key of current logged in account
|
;;public key of current logged in account
|
||||||
(s/def ::current-public-key (s/nilable string?))
|
(spec/def ::current-public-key (spec/nilable string?))
|
||||||
;;true when application running at first time
|
;;true when application running at first time
|
||||||
(s/def ::first-run (s/nilable boolean?))
|
(spec/def ::first-run (spec/nilable boolean?))
|
||||||
(s/def ::was-modal? (s/nilable boolean?))
|
(spec/def ::was-modal? (spec/nilable boolean?))
|
||||||
;;"http://localhost:8545"
|
;;"http://localhost:8545"
|
||||||
(s/def ::rpc-url (s/nilable string?))
|
(spec/def ::rpc-url (spec/nilable string?))
|
||||||
;;object? doesn't work
|
;;object? doesn't work
|
||||||
(s/def ::web3 (s/nilable any?))
|
(spec/def ::web3 (spec/nilable any?))
|
||||||
;;object?
|
;;object?
|
||||||
(s/def ::webview-bridge (s/nilable any?))
|
(spec/def ::webview-bridge (spec/nilable any?))
|
||||||
(s/def ::status-module-initialized? (s/nilable boolean?))
|
(spec/def ::status-module-initialized? (spec/nilable boolean?))
|
||||||
(s/def ::status-node-started? (s/nilable boolean?))
|
(spec/def ::status-node-started? (spec/nilable boolean?))
|
||||||
(s/def ::toolbar-search (s/nilable map?))
|
(spec/def ::toolbar-search (spec/nilable map?))
|
||||||
;;height of native keyboard if shown
|
;;height of native keyboard if shown
|
||||||
(s/def ::keyboard-height (s/nilable number?))
|
(spec/def ::keyboard-height (spec/nilable number?))
|
||||||
(s/def ::keyboard-max-height (s/nilable number?))
|
(spec/def ::keyboard-max-height (spec/nilable number?))
|
||||||
;;:unknown - not used
|
;;:unknown - not used
|
||||||
(s/def ::orientation (s/nilable keyword?))
|
(spec/def ::orientation (spec/nilable keyword?))
|
||||||
;;:online - presence of internet connection in the phone
|
;;:online - presence of internet connection in the phone
|
||||||
(s/def ::network-status (s/nilable keyword?))
|
(spec/def ::network-status (spec/nilable keyword?))
|
||||||
|
|
||||||
;;;;NODE
|
;;;;NODE
|
||||||
|
|
||||||
(s/def ::sync-listening-started (s/nilable boolean?))
|
(spec/def ::sync-listening-started (spec/nilable boolean?))
|
||||||
(s/def ::sync-state (s/nilable keyword?))
|
(spec/def ::sync-state (spec/nilable keyword?))
|
||||||
(s/def ::sync-data (s/nilable map?))
|
(spec/def ::sync-data (spec/nilable map?))
|
||||||
|
|
||||||
;;;;NETWORK
|
;;;;NETWORK
|
||||||
|
|
||||||
;;network name :testnet
|
;;network name :testnet
|
||||||
(s/def ::network (s/nilable keyword?))
|
(spec/def ::network (spec/nilable keyword?))
|
||||||
|
|
||||||
(s/def ::db (allowed-keys
|
(spec/def ::db (allowed-keys
|
||||||
:opt
|
:opt
|
||||||
[:contacts/contacts
|
[:contacts/contacts
|
||||||
:contacts/new-identity
|
:contacts/new-identity
|
||||||
@ -56,7 +57,12 @@
|
|||||||
:contacts/list-ui-props
|
:contacts/list-ui-props
|
||||||
:contacts/click-handler
|
:contacts/click-handler
|
||||||
:contacts/click-action
|
:contacts/click-action
|
||||||
:contacts/click-params]
|
:contacts/click-params
|
||||||
|
:group/contact-groups
|
||||||
|
:group/contact-group-id
|
||||||
|
:group/group-type
|
||||||
|
:group/selected-contacts
|
||||||
|
:group/groups-order]
|
||||||
:opt-un
|
:opt-un
|
||||||
[::current-public-key
|
[::current-public-key
|
||||||
::first-run
|
::first-run
|
||||||
@ -89,14 +95,6 @@
|
|||||||
:qr/qr-codes
|
:qr/qr-codes
|
||||||
:qr/qr-modal
|
:qr/qr-modal
|
||||||
:qr/current-qr-context
|
:qr/current-qr-context
|
||||||
:group/contact-groups
|
|
||||||
:group/contact-group-id
|
|
||||||
:group/group-type
|
|
||||||
:group/new-group
|
|
||||||
:group/new-groups
|
|
||||||
:group/contacts-group
|
|
||||||
:group/selected-contacts
|
|
||||||
:group/groups-order
|
|
||||||
:chat/chats
|
:chat/chats
|
||||||
:chat/current-chat-id
|
:chat/current-chat-id
|
||||||
:chat/chat-id
|
:chat/chat-id
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||||
status-im.chat.subs
|
status-im.chat.subs
|
||||||
status-im.chats-list.subs
|
status-im.chats-list.subs
|
||||||
status-im.group-settings.subs
|
status-im.group.chat-settings.subs
|
||||||
status-im.discover.subs
|
status-im.discover.subs
|
||||||
status-im.contacts.subs
|
status-im.contacts.subs
|
||||||
status-im.new-group.subs
|
status-im.group.subs
|
||||||
status-im.transactions.subs
|
status-im.transactions.subs
|
||||||
status-im.bots.subs))
|
status-im.bots.subs))
|
||||||
|
|
||||||
|
@ -127,5 +127,5 @@
|
|||||||
([] (register-exception-handler default-alert-handler))
|
([] (register-exception-handler default-alert-handler))
|
||||||
([f] (register-exception-handler true f))
|
([f] (register-exception-handler true f))
|
||||||
([dev? f]
|
([dev? f]
|
||||||
(if (or dev? (not js/goog.DEBUG))
|
(if (and dev? (not js/goog.DEBUG))
|
||||||
(.setGlobalHandler js/ErrorUtils f dev?))))
|
(.setGlobalHandler js/ErrorUtils f dev?))))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user