Communities

Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrea Maria Piana 2020-10-20 16:28:52 +02:00
parent 35c2c226df
commit 2ca39daa59
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
42 changed files with 1243 additions and 315 deletions

2
.env
View File

@ -26,3 +26,5 @@ ENABLE_REFERRAL_INVITE=1
ENABLE_QUO_PREVIEW=1
MAX_IMAGES_BATCH=5
APN_TOPIC=im.status.ethereum.pr
COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=1

View File

@ -26,3 +26,5 @@ ENABLE_REFERRAL_INVITE=1
MAX_IMAGES_BATCH=5
APN_TOPIC=im.status.ethereum.pr
VERIFY_TRANSACTION_CHAIN_ID=3
COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=0

View File

@ -26,3 +26,5 @@ APN_TOPIC=im.status.ethereum.pr
BLANK_PREVIEW=0
MAX_IMAGES_BATCH=5
GOOGLE_FREE=0
COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=0

View File

@ -20,3 +20,4 @@ ENABLE_ROOT_ALERT=1
ENABLE_REFERRAL_INVITE=0
MAX_IMAGES_BATCH=5
BLANK_PREVIEW=0
COMMUNITIES_ENABLED=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -10,6 +10,7 @@
[status-im.i18n :as i18n]
[status-im.mailserver.core :as mailserver]
[status-im.ui.components.colors :as colors]
[status-im.constants :as constants]
[status-im.navigation :as navigation]
[status-im.utils.clocks :as utils.clocks]
[status-im.utils.fx :as fx]
@ -32,6 +33,9 @@
(def one-to-one-chat?
(complement multi-user-chat?))
(defn community-chat? [{:keys [chat-type]}]
(= chat-type constants/community-chat-type))
(defn public-chat?
([chat]
(:public? chat))
@ -94,6 +98,7 @@
{:chat-id chat-id
:name (or name "")
:color (rand-nth colors/chat-colors)
:chat-type constants/one-to-one-chat-type
:group-chat false
:is-active true
:timestamp now
@ -176,6 +181,9 @@
:name topic
:chat-name (str "#" topic)
:group-chat true
:chat-type (if timeline?
constants/timeline-chat-type
constants/public-chat-type)
:contacts #{}
:public? true
:might-have-join-time-messages? (get-in cofx [:db :multiaccount :use-mailservers?])

View File

@ -1,6 +1,7 @@
(ns status-im.chat.models.mentions
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.utils.fx :as fx]
[status-im.contact.db :as contact.db]
[status-im.utils.platform :as platform]
@ -172,11 +173,11 @@
(defn get-mentionable-users
[{{:keys [current-chat-id]
:contacts/keys [contacts] :as db} :db}]
(let [{:keys [group-chat public? users] :as chat}
(let [{:keys [chat-type users] :as chat}
(get-in db [:chats current-chat-id])
chat-specific-suggestions
(cond
(and group-chat (not public?))
(= chat-type constants/private-group-chat-type)
(let [{:keys [public-key]} (:multiaccount db)
all-contacts (:contacts/contacts db)
group-contacts

View File

@ -114,20 +114,6 @@
(get-in db [:chats chat-id])]
(>= deleted-at-clock-value clock-value)))
(defn extract-chat-id
"Validate and return a valid chat-id"
[cofx {:keys [chat-id from message-type]}]
(cond
(and (= constants/message-type-private-group message-type)
(and (get-in cofx [:db :chats chat-id :contacts from])
(get-in cofx [:db :chats chat-id :members-joined (multiaccounts.model/current-public-key cofx)]))) chat-id
(and (= constants/message-type-public-group message-type)
(get-in cofx [:db :chats chat-id :public?])) chat-id
(and (= constants/message-type-one-to-one message-type)
(= (multiaccounts.model/current-public-key cofx) from)) chat-id
(= constants/message-type-private-group-system-message message-type) chat-id
(= constants/message-type-one-to-one message-type) from))
(fx/defn update-unviewed-count
[{:keys [db] :as cofx} {:keys [chat-id from message-type message-id new?]}]
(when-not (= message-type constants/message-type-private-group-system-message)
@ -159,24 +145,22 @@
(fx/defn receive-one
{:events [::receive-one]}
[{:keys [db] :as cofx} {:keys [message-id] :as message}]
(when-let [chat-id (extract-chat-id cofx message)]
(fx/merge cofx
;;If its a profile updates we want to add this message to the timeline as well
#(when (get-in cofx [:db :chats chat-id :profile-public-key])
{:dispatch-n [[::receive-one (assoc message :chat-id chat-model/timeline-chat-id)]]})
#(let [message-with-chat-id (assoc message :chat-id chat-id)]
(when-not (earlier-than-deleted-at? cofx message-with-chat-id)
(if (message-loaded? cofx message-with-chat-id)
;; If the message is already loaded, it means it's an update, that
;; happens when a message that was missing a reply had the reply
;; coming through, in which case we just insert the new message
{:db (assoc-in db [:messages chat-id message-id] message-with-chat-id)}
(fx/merge cofx
(add-received-message message-with-chat-id)
(update-unviewed-count message-with-chat-id)
(chat-model/join-time-messages-checked chat-id)
(check-for-incoming-tx message-with-chat-id))))))))
[{:keys [db] :as cofx} {:keys [message-id chat-id] :as message}]
(fx/merge cofx
;;If its a profile updates we want to add this message to the timeline as well
#(when (get-in cofx [:db :chats chat-id :profile-public-key])
{:dispatch-n [[::receive-one (assoc message :chat-id chat-model/timeline-chat-id)]]})
#(when-not (earlier-than-deleted-at? cofx message)
(if (message-loaded? cofx message)
;; If the message is already loaded, it means it's an update, that
;; happens when a message that was missing a reply had the reply
;; coming through, in which case we just insert the new message
{:db (assoc-in db [:messages chat-id message-id] message)}
(fx/merge cofx
(add-received-message message)
(update-unviewed-count message)
(chat-model/join-time-messages-checked chat-id)
(check-for-incoming-tx message))))))
;;TODO currently we process every message, we need to precess them by batches
;;or better move processing to status-go

View File

@ -3,11 +3,8 @@
[status-im.chat.models.loading :as chat-loading]
[status-im.chat.models.message :as message]
[status-im.chat.models.message-list :as models.message-list]
[status-im.constants :as constants]
[status-im.ui.screens.chat.state :as view.state]
[status-im.utils.datetime :as time]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]))
[status-im.utils.datetime :as time]))
(deftest add-received-message-test
(with-redefs [message/add-message (constantly :added)]
@ -154,129 +151,6 @@
:clock-value 0
:chat-id "a"}))))
(deftest add-own-received-message
(let [db {:multiaccount {:public-key "me"}
:view-id :chat
:loaded-chat-id "chat-id"
:current-chat-id "chat-id"
:messages {"chat-id" {}}
:chats {"chat-id" {}}}]
(testing "a message coming from you!"
(let [actual (message/receive-one {:db db}
{:from "me"
:message-type constants/message-type-one-to-one
:timestamp 0
:whisper-timestamp 0
:message-id "id"
:chat-id "chat-id"
:outgoing true
:content "b"
:clock-value 1})
message (get-in actual [:db :messages "chat-id" "id"])]
(testing "it adds the message"
(is message))))))
(deftest receive-group-chats
(let [cofx {:db {:chats {"chat-id" {:contacts #{"present"}
:members-joined #{"a"}}}
:multiaccount {:public-key "a"}
:loaded-chat-id "chat-id"
:current-chat-id "chat-id"
:view-id :chat}}
cofx-without-member (update-in cofx [:db :chats "chat-id" :members-joined] disj "a")
valid-message {:chat-id "chat-id"
:from "present"
:message-type constants/message-type-private-group
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}
bad-chat-id-message {:chat-id "bad-chat-id"
:from "present"
:message-type constants/message-type-private-group
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}
bad-from-message {:chat-id "chat-id"
:from "not-present"
:message-type constants/message-type-private-group
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}]
(testing "a valid message"
(is (get-in (message/receive-one cofx valid-message) [:db :messages "chat-id" "1"])))
(testing "a message from someone not in the list of participants"
(is (not (message/receive-one cofx bad-from-message))))
(testing "a message with non existing chat-id"
(is (not (message/receive-one cofx bad-chat-id-message))))
(testing "a message from a delete chat"
(is (not (message/receive-one cofx-without-member valid-message))))))
(deftest receive-public-chats
(let [cofx {:db {:chats {"chat-id" {:public? true}}
:multiaccount {:public-key "a"}
:loaded-chat-id "chat-id"
:current-chat-id "chat-id"
:view-id :chat}}
valid-message {:chat-id "chat-id"
:from "anyone"
:message-type constants/message-type-public-group
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}
bad-chat-id-message {:chat-id "bad-chat-id"
:from "present"
:message-type constants/message-type-public-group
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}]
(testing "a valid message"
(is (get-in (message/receive-one cofx valid-message) [:db :messages "chat-id" "1"])))
(testing "a message with non existing chat-id"
(is (not (message/receive-one cofx bad-chat-id-message))))))
(deftest receive-one-to-one
(with-redefs [gfycat/generate-gfy (constantly "generated")
identicon/identicon (constantly "generated")]
(let [cofx {:db {:chats {"matching" {}}
:multiaccount {:public-key "me"}
:current-chat-id "matching"
:loaded-chat-id "matching"
:view-id :chat}}
valid-message {:chat-id "matching"
:from "matching"
:message-type constants/message-type-one-to-one
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}
own-message {:chat-id "matching"
:from "me"
:message-type constants/message-type-one-to-one
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}
bad-chat-id-message {:chat-id "bad-chat-id"
:from "not-matching"
:message-type constants/message-type-one-to-one
:message-id "1"
:clock-value 1
:whisper-timestamp 0
:timestamp 0}]
(testing "a valid message"
(is (get-in (message/receive-one cofx valid-message) [:db :messages "matching" "1"])))
(testing "our own message"
(is (get-in (message/receive-one cofx own-message) [:db :messages "matching" "1"])))
(testing "a message with non matching chat-id"
(is (not (get-in (message/receive-one cofx bad-chat-id-message) [:db :messages "not-matching" "1"])))))))
(deftest delete-message
(with-redefs [time/day-relative (constantly "day-relative")
time/timestamp->time (constantly "timestamp")]

View File

@ -0,0 +1,319 @@
(ns status-im.communities.core
(:require
[re-frame.core :as re-frame]
[clojure.walk :as walk]
[taoensso.timbre :as log]
[status-im.utils.fx :as fx]
[status-im.constants :as constants]
[status-im.chat.models :as models.chat]
[status-im.transport.filters.core :as models.filters]
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
[status-im.data-store.chats :as data-store.chats]
[status-im.ethereum.json-rpc :as json-rpc]))
(def featured
[{:name "Status"
:id constants/status-community-id}])
(def access-no-membership 1)
(def access-invitation-only 2)
(def access-on-request 3)
(defn <-chats-rpc [chats]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
(-> v
(update :members walk/stringify-keys)
(assoc :identity {:display-name (get-in v [:identity :display_name])
:description (get-in v [:identity :description])}
:id (name k)))))
{}
chats))
(defn <-rpc [{:keys [description] :as c}]
(let [identity (:identity description)]
(-> c
(update-in [:description :members] walk/stringify-keys)
(assoc-in [:description :identity] {:display-name (:display_name identity)
:description (:description identity)})
(update-in [:description :chats] <-chats-rpc))))
(fx/defn handle-chats [cofx chats]
(models.chat/ensure-chats cofx chats))
(fx/defn handle-filters [cofx filters]
(models.filters/handle-filters cofx filters))
(fx/defn handle-removed-filters [cofx filters]
(models.filters/handle-filters-removed cofx (map models.filters/responses->filters filters)))
(fx/defn handle-removed-chats [{:keys [db]} chat-ids]
{:db (reduce (fn [db chat-id]
(update db :chats dissoc chat-id))
db
chat-ids)})
(fx/defn handle-community
[{:keys [db]} {:keys [id] :as community}]
{:db (assoc-in db [:communities id] (<-rpc community))})
(fx/defn handle-fetched
{:events [::fetched]}
[{:keys [db]} communities]
{:db (reduce (fn [db {:keys [id] :as community}]
(assoc-in db [:communities id] (<-rpc community)))
db
communities)})
(fx/defn handle-response [cofx response]
(fx/merge cofx
(handle-removed-chats (:removedChats response))
(handle-chats (map #(-> %
(data-store.chats/<-rpc)
(dissoc :unviewed-messages-count))
(:chats response)))
(handle-fetched (:communities response))
(handle-removed-filters (:removedFilters response))
(handle-filters (:filters response))))
(fx/defn left
{:events [::left]}
[cofx response]
(handle-response cofx response))
(fx/defn joined
{:events [::joined]}
[cofx response]
(handle-response cofx response))
(fx/defn export
[cofx community-id on-success]
{::json-rpc/call [{:method "wakuext_exportCommunity"
:params [community-id]
:on-success on-success
:on-error #(do
(log/error "failed to export community" community-id %)
(re-frame/dispatch [::failed-to-export %]))}]})
(fx/defn import-community
{:events [::import]}
[cofx community-key on-success]
{::json-rpc/call [{:method "wakuext_importCommunity"
:params [community-key]
:on-success on-success
:on-error #(do
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
(fx/defn join
{:events [::join]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_joinCommunity"
:params [community-id]
:on-success #(re-frame/dispatch [::joined %])
:on-error #(do
(log/error "failed to join community" community-id %)
(re-frame/dispatch [::failed-to-join %]))}]})
(fx/defn leave
{:events [::leave]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:on-success #(re-frame/dispatch [::left %])
:on-error #(do
(log/error "failed to leave community" community-id %)
(re-frame/dispatch [::failed-to-leave %]))}]})
(fx/defn fetch [_]
{::json-rpc/call [{:method "wakuext_communities"
:params []
:on-success #(re-frame/dispatch [::fetched %])
:on-error #(do
(log/error "failed to fetch communities" %)
(re-frame/dispatch [::failed-to-fetch %]))}]})
(fx/defn chat-created
{:events [::chat-created]}
[cofx community-id user-pk]
{::json-rpc/call [{:method "wakuext_sendChatMessage"
:params [{:chatId user-pk
:text "Upgrade here to see an invitation to community"
:communityId community-id
:contentType constants/content-type-community}]
:on-success
#(re-frame/dispatch [:transport/message-sent % 1])
:on-failure #(log/error "failed to send a message" %)}]})
(fx/defn invite-user [cofx
community-id
user-pk
on-success-event
on-failure-event]
(fx/merge cofx
{::json-rpc/call [{:method "wakuext_inviteUserToCommunity"
:params [community-id
user-pk]
:on-success #(re-frame/dispatch [on-success-event %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [on-failure-event %]))}]}
(models.chat/upsert-chat {:chat-id user-pk
:active (get-in cofx [:db :chats user-pk :active])}
#(re-frame/dispatch [::chat-created community-id user-pk]))))
(fx/defn create [{:keys [db]}
community-name
community-description
community-membership
on-success-event
on-failure-event]
(let [membership (js/parseInt community-membership)
my-public-key (get-in db [:multiaccount :public-key])]
{::json-rpc/call [{:method "wakuext_createCommunity"
:params [{:identity {:display_name community-name
:description community-description}
:members {my-public-key {}}
:permissions {:access membership}}]
:on-success #(re-frame/dispatch [on-success-event %])
:on-error #(do
(log/error "failed to create community" %)
(re-frame/dispatch [on-failure-event %]))}]}))
(defn create-channel [community-id
community-channel-name
community-channel-description
on-success-event
on-failure-event]
{::json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
{:identity {:display_name community-channel-name
:description community-channel-description}
:permissions {:access access-no-membership}}]
:on-success #(re-frame/dispatch [on-success-event %])
:on-error #(do
(log/error "failed to create community channel" %)
(re-frame/dispatch [on-failure-event %]))}]})
(def no-membership-access 1)
(def invitation-only-access 2)
(def on-request-access 3)
(defn require-membership? [permissions]
(not= no-membership-access (:access permissions)))
(def community-id-length 68)
;; TODO: test this
(defn can-post? [{:keys [admin] :as community} pk local-chat-id]
(let [chat-id (subs local-chat-id community-id-length)
can-access-community? (or (get-in community [:description :members pk])
(not (require-membership? (get-in community [:description :permissions]))))]
(or admin
(get-in community [:description :chats chat-id :members pk])
(and can-access-community?
(not (require-membership? (get-in community [:description :chats chat-id :permissions])))))))
(fx/defn reset-community-id-input [{:keys [db]} id]
{:db (assoc db :communities/community-id-input id)})
(defn fetch-community-id-input [{:keys [db]}]
(:communities/community-id-input db))
(fx/defn import-pressed
{:events [::import-pressed]}
[cofx]
(bottom-sheet/show-bottom-sheet cofx {:view :import-community}))
(fx/defn create-pressed
{:events [::create-pressed]}
[cofx]
(bottom-sheet/show-bottom-sheet cofx {:view :create-community}))
(fx/defn invite-people-pressed
{:events [::invite-people-pressed]}
[cofx id]
(fx/merge cofx
(reset-community-id-input id)
(bottom-sheet/show-bottom-sheet {:view :invite-people-community})))
(fx/defn create-channel-pressed
{:events [::create-channel-pressed]}
[cofx id]
(fx/merge cofx
(reset-community-id-input id)
(bottom-sheet/show-bottom-sheet {:view :create-community-channel})))
(fx/defn community-created
{:events [::community-created]}
[cofx response]
(fx/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response)))
(fx/defn community-imported
{:events [::community-imported]}
[cofx response]
(fx/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response)))
(fx/defn people-invited
{:events [::people-invited]}
[cofx response]
(fx/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response)))
(fx/defn community-channel-created
{:events [::community-channel-created]}
[cofx response]
(fx/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response)))
(fx/defn handle-export-pressed
{:events [::export-pressed]}
[cofx community-id]
(export cofx community-id
#(re-frame/dispatch [:show-popover {:view :export-community
:community-key %}])))
(fx/defn import-confirmation-pressed
{:events [::import-confirmation-pressed]}
[cofx community-key]
(import-community
cofx
community-key
#(re-frame/dispatch [::community-imported %])))
(fx/defn create-confirmation-pressed
{:events [::create-confirmation-pressed]}
[cofx community-name community-description membership]
(create
cofx
community-name
community-description
membership
::community-created
::failed-to-create-community))
(fx/defn create-channel-confirmation-pressed
{:events [::create-channel-confirmation-pressed]}
[cofx community-channel-name community-channel-description]
(create-channel
(fetch-community-id-input cofx)
community-channel-name
community-channel-description
::community-channel-created
::failed-to-create-community-channel))
(fx/defn invite-people-confirmation-pressed
{:events [::invite-people-confirmation-pressed]}
[cofx user-pk]
(invite-user
cofx
(fetch-community-id-input cofx)
user-pk
::people-invited
::failed-to-invite-people))

View File

@ -14,6 +14,7 @@
(def content-type-system-text 6)
(def content-type-image 7)
(def content-type-audio 8)
(def content-type-community 9)
(def emoji-reaction-love 1)
(def emoji-reaction-thumbs-up 2)
@ -22,6 +23,13 @@
(def emoji-reaction-sad 5)
(def emoji-reaction-angry 6)
(def one-to-one-chat-type 1)
(def public-chat-type 2)
(def private-group-chat-type 3)
(def profile-chat-type 4)
(def timeline-chat-type 5)
(def community-chat-type 6)
(def reactions {emoji-reaction-love (:love resources/reactions)
emoji-reaction-thumbs-up (:thumbs-up resources/reactions)
emoji-reaction-thumbs-down (:thumbs-down resources/reactions)
@ -199,3 +207,5 @@
(def faq "https://status.im/faq/")
(def faq-keycard (str faq "#keycard"))
(def keycard-integration-link "https://status.im/keycard-integration")
(def status-community-id "0x039b2da47552aa117a96ea8f1d4d108ba66637c7517a3c94a57b99dbb8a002eda2")

View File

@ -2,41 +2,41 @@
(:require [clojure.set :as clojure.set]
[status-im.data-store.messages :as messages]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.constants :as constants]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
(def one-to-one-chat-type 1)
(def public-chat-type 2)
(def private-group-chat-type 3)
(def profile-chat-type 4)
(def timeline-chat-type 5)
(defn type->rpc [{:keys [public? group-chat profile-public-key timeline?] :as chat}]
(assoc chat :chatType (cond
profile-public-key profile-chat-type
timeline? timeline-chat-type
public? public-chat-type
group-chat private-group-chat-type
:else one-to-one-chat-type)))
(defn type->rpc [{:keys [chat-type public? group-chat profile-public-key timeline?] :as chat}]
(if chat-type
(assoc chat :chatType chat-type)
(assoc chat :chatType (cond
profile-public-key constants/profile-chat-type
timeline? constants/timeline-chat-type
public? constants/public-chat-type
group-chat constants/private-group-chat-type
:else constants/one-to-one-chat-type))))
(defn rpc->type [{:keys [chatType name] :as chat}]
(cond
(or (= public-chat-type chatType)
(= profile-chat-type chatType)
(= timeline-chat-type chatType)) (assoc chat
:chat-name (str "#" name)
:public? true
:group-chat true
:timeline? (= timeline-chat-type chatType))
(= private-group-chat-type chatType) (assoc chat
:chat-name name
:public? false
:group-chat true)
(or (= constants/public-chat-type chatType)
(= constants/profile-chat-type chatType)
(= constants/timeline-chat-type chatType)) (assoc chat
:chat-name (str "#" name)
:public? true
:group-chat true
:timeline? (= constants/timeline-chat-type chatType))
(= constants/community-chat-type chatType) (assoc chat
:chat-name name
:group-chat true)
(= constants/private-group-chat-type chatType) (assoc chat
:chat-name name
:public? false
:group-chat true)
:else (assoc chat :public? false :group-chat false)))
(defn- marshal-members [{:keys [admins contacts members-joined chatType] :as chat}]
(defn- marshal-members [{:keys [admins contacts members-joined chat-type] :as chat}]
(cond-> chat
(= chatType private-group-chat-type)
(= chat-type constants/private-group-chat-type)
(assoc :members (map #(hash-map :id %
:admin (boolean (admins %))
:joined (boolean (members-joined %))) contacts))
@ -45,23 +45,23 @@
(defn- unmarshal-members [{:keys [members chatType] :as chat}]
(cond
(= public-chat-type chatType) (assoc chat
:contacts #{}
:admins #{}
:members-joined #{})
(= private-group-chat-type chatType) (merge chat
(reduce (fn [acc member]
(cond-> acc
(:admin member)
(update :admins conj (:id member))
(:joined member)
(update :members-joined conj (:id member))
:always
(update :contacts conj (:id member))))
{:admins #{}
:members-joined #{}
:contacts #{}}
members))
(= constants/public-chat-type chatType) (assoc chat
:contacts #{}
:admins #{}
:members-joined #{})
(= constants/private-group-chat-type chatType) (merge chat
(reduce (fn [acc member]
(cond-> acc
(:admin member)
(update :admins conj (:id member))
(:joined member)
(update :members-joined conj (:id member))
:always
(update :contacts conj (:id member))))
{:admins #{}
:members-joined #{}
:contacts #{}}
members))
:else
(assoc chat
:contacts #{(:id chat)}
@ -70,20 +70,21 @@
(defn- ->rpc [chat]
(-> chat
type->rpc
marshal-members
(update :last-message messages/->rpc)
type->rpc
(clojure.set/rename-keys {:chat-id :id
:membership-update-events :membershipUpdateEvents
:unviewed-messages-count :unviewedMessagesCount
:last-message :lastMessage
:community-id :communityId
:deleted-at-clock-value :deletedAtClockValue
:is-active :active
:last-clock-value :lastClockValue
:profile-public-key :profile})
(dissoc :public? :group-chat :messages
:might-have-join-time-messages?
:loaded-unviewed-messages-ids
:loaded-unviewed-messages-ids :chat-type
:contacts :admins :members-joined)))
(defn <-rpc [chat]
@ -91,8 +92,10 @@
rpc->type
unmarshal-members
(clojure.set/rename-keys {:id :chat-id
:communityId :community-id
:membershipUpdateEvents :membership-update-events
:deletedAtClockValue :deleted-at-clock-value
:chatType :chat-type
:unviewedMessagesCount :unviewed-messages-count
:lastMessage :last-message
:active :is-active
@ -100,7 +103,7 @@
:invitationAdmin :invitation-admin
:profile :profile-public-key})
(update :last-message #(when % (messages/<-rpc %)))
(dissoc :chatType :members)))
(dissoc :members)))
(fx/defn save-chat [cofx {:keys [chat-id] :as chat} on-success]
{::json-rpc/call [{:method (json-rpc/call-ext-method "saveChat")

View File

@ -8,6 +8,7 @@
:color "color"
:contacts #{"a" "b" "c" "d"}
:last-clock-value 10
:chat-type 3
:admins #{"a" "b"}
:members-joined #{"a" "c"}
:name "name"
@ -70,6 +71,7 @@
:color "color"
:chat-name "name"
:contacts #{"a" "b" "c" "d"}
:chat-type 3
:last-clock-value 10
:last-message nil
:admins #{"a" "b"}

View File

@ -11,6 +11,7 @@
:sticker (:sticker content))
:always
(clojure.set/rename-keys {:chat-id :chatId
:community-id :communityId
:clock-value :clock})))
(defn <-rpc [message]
@ -20,6 +21,7 @@
:commandParameters :command-parameters
:messageType :message-type
:localChatId :chat-id
:communityId :community-id
:contentType :content-type
:clock :clock-value
:quotedMessage :quoted-message
@ -27,7 +29,7 @@
:audioDurationMs :audio-duration-ms
:new :new?})
(update :quoted-message clojure.set/rename-keys {:parsedText :parsed-text})
(update :quoted-message clojure.set/rename-keys {:parsedText :parsed-text :communityId :community-id})
(update :outgoing-status keyword)
(update :command-parameters clojure.set/rename-keys {:transactionHash :transaction-hash
:commandState :command-state})

View File

@ -115,6 +115,14 @@
"multiaccounts_getIdentityImage" {}
"multiaccounts_storeIdentityImage" {}
"multiaccounts_deleteIdentityImage" {}
"wakuext_createCommunity" {}
"wakuext_createCommunityChat" {}
"wakuext_inviteUserToCommunity" {}
"wakuext_joinCommunity" {}
"wakuext_leaveCommunity" {}
"wakuext_communities" {}
"wakuext_importCommunity" {}
"wakuext_exportCommunity" {}
"status_chats" {}
"localnotifications_switchWalletNotifications" {}
"localnotifications_notificationPreferences" {}

View File

@ -5,7 +5,7 @@
(defn button [label accessibility-label handler]
[react/view
{:style {:width 50
:height 40
:height 30
:justify-content :center
:align-items :center}}
[react/text
@ -16,7 +16,7 @@
(defn test-menu []
[react/view
{:style {:position :absolute
:top 100
:top 70
:right 0
:width 50
:justify-content :center

View File

@ -234,12 +234,12 @@
(fx/defn connect-to-mailserver
"Add mailserver as a peer using `::add-peer` cofx and generate sym-key when
it doesn't exists
Peer summary will change and we will receive a signal from status go when
this is successful
A connection-check is made after `connection timeout` is reached and
mailserver-state is changed to error if it is not connected by then
No attempt is made if mailserver usage is disabled"
it doesn't exists
Peer summary will change and we will receive a signal from status go when
this is successful
A connection-check is made after `connection timeout` is reached and
mailserver-state is changed to error if it is not connected by then
No attempt is made if mailserver usage is disabled"
{:events [:mailserver.ui/reconnect-mailserver-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [address]} (fetch-current db)

View File

@ -96,7 +96,7 @@
(fx/defn update-many [cofx mailserver-topics]
(apply fx/merge cofx (map (partial update-topic true) mailserver-topics)))
(fx/defn delete [{:keys [db] :as cofx} {:keys [chat-id filter-id]}]
(fx/defn delete [{:keys [db] :as cofx} {:keys [filter-id]}]
(when-let [matching-topics (filter (fn [{:keys [filter-ids] :as topic}]
(if (not filter-ids)
(do (log/warn "topic not initialized, removing" topic)

View File

@ -14,6 +14,7 @@
[status-im.native-module.core :as status]
[status-im.notifications.core :as notifications]
[status-im.popover.core :as popover]
[status-im.communities.core :as communities]
[status-im.protocol.core :as protocol]
[status-im.stickers.core :as stickers]
[status-im.ui.screens.mobile-network-settings.events :as mobile-network]
@ -221,6 +222,7 @@
(protocol/initialize-protocol {:default-mailserver true})
(check-network-version network-id)
(chat.loading/initialize-chats)
(communities/fetch)
(contact/initialize-contacts)
(stickers/init-stickers-packs)
(mobile-network/on-network-status-change)
@ -293,6 +295,8 @@
:mailserver-ranges {}
:mailserver-topics {}
:default-mailserver true})
(communities/fetch)
(multiaccounts/switch-preview-privacy-mode-flag)
(link-preview/request-link-preview-whitelist)
(logging/set-log-level (:log-level multiaccount)))))

View File

@ -14,6 +14,7 @@
[status-im.ethereum.transactions.core :as transactions]
[status-im.fleet.core :as fleet]
[status-im.group-chats.db :as group-chats.db]
[status-im.communities.core :as communities]
[status-im.group-chats.core :as group-chat]
[status-im.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
@ -217,8 +218,58 @@
(reg-root-key-sub :push-notifications/preferences :push-notifications/preferences)
(reg-root-key-sub :acquisition :acquisition)
;; communities
(re-frame/reg-sub
:communities
(fn [db]
(cond
config/communities-management-enabled?
(:communities db)
config/communities-enabled?
;; If no management enabled, only return status-community
(select-keys (:communities db) [constants/status-community-id])
:else
[])))
(re-frame/reg-sub
:communities/community
:<- [:communities]
(fn [communities [_ id]]
(get communities id)))
(re-frame/reg-sub
:communities/status-community
:<- [:search/home-filter]
:<- [:communities]
(fn [[search-filter communities]]
(let [status-community (get communities constants/status-community-id)]
(when (and (:joined status-community)
(or (string/blank? search-filter)
(string/includes? (string/lower-case
(get-in status-community [:description :identity :display-name])) search-filter)))
status-community))))
(re-frame/reg-sub
:communities/current-community
:<- [:communities]
:<- [:chats/current-raw-chat]
(fn [[communities {:keys [community-id]}]]
(get communities community-id)))
(re-frame/reg-sub
:communities/unviewed-count
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])])
(fn [[chats]]
(reduce (fn [acc {:keys [unviewed-messages-count]}]
(+ acc (or unviewed-messages-count 0)))
0
chats)))
;;GENERAL ==============================================================================================================
(re-frame/reg-sub
:multiaccount/logged-in?
(fn [db]
@ -616,6 +667,16 @@
(fn [chats [_ chat-id]]
(get chats chat-id)))
(re-frame/reg-sub
:chats/by-community-id
:<- [:chats/active-chats]
(fn [chats [_ community-id]]
(->> chats
(keep (fn [[_ chat]]
(when (= (:community-id chat) community-id)
chat)))
(sort-by :timestamp >))))
(re-frame/reg-sub
:chats/current-chat-ui-props
:<- [::chat-ui-props]
@ -678,8 +739,11 @@
:<- [:chats/current-raw-chat]
:<- [:multiaccount/public-key]
:<- [:inactive-chat-id]
:<- [:communities/current-community]
(fn [[{:keys [group-chat] :as current-chat}
my-public-key inactive-chat-id]]
my-public-key
inactive-chat-id
community]]
(when (and current-chat (= (:chat-id current-chat) inactive-chat-id))
(cond-> current-chat
(chat.models/public-chat? current-chat)
@ -690,6 +754,10 @@
(assoc :show-input? true
:joined? true)
(and (chat.models/community-chat? current-chat)
(communities/can-post? community my-public-key (:chat-id current-chat)))
(assoc :show-input? true)
(not group-chat)
(assoc :show-input? true)))))
@ -698,7 +766,14 @@
:<- [:chats/current-raw-chat]
(fn [current-chat]
(select-keys current-chat
[:public? :group-chat :chat-id :chat-name :color :invitation-admin])))
[:community-id
:public?
:group-chat
:chat-type
:chat-id
:chat-name
:color
:invitation-admin])))
(re-frame/reg-sub
:current-chat/one-to-one-chat?
@ -2011,7 +2086,10 @@
(vals chats))
(vals chats))]
(sort-by :timestamp > filtered-chats))))
(sort-by :timestamp > (filter (fn [{:keys [community-id]}]
;; Ignore communities
(not community-id))
filtered-chats)))))
(defn extract-currency-attributes [currency]
(let [{:keys [code display-name]} (val currency)]

View File

@ -2,6 +2,7 @@
"This namespace is used to handle filters loading and unloading from statusgo"
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.contact.db :as contact.db]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.mailserver.core :as mailserver]
@ -65,10 +66,8 @@
(fx/defn upsert-group-chat-topics
"Update topics for each member of the group chat"
[{:keys [db] :as cofx}]
(let [group-chats (filter (fn [{:keys [group-chat
public?]}]
(and group-chat
(not public?)))
(let [group-chats (filter (fn [{:keys [chat-type]}]
(= chat-type constants/private-group-chat-type))
(vals (:chats db)))]
(apply fx/merge
cofx
@ -195,12 +194,12 @@
;; shh filters
(defn- responses->filters [{:keys [negotiated
discovery
filterId
chatId
topic
identity]}]
(defn responses->filters [{:keys [negotiated
discovery
filterId
chatId
topic
identity]}]
{:chat-id (if (not= identity "") (str "0x" identity) chatId)
:id chatId
:filter-id filterId
@ -232,6 +231,9 @@
(mailserver/process-next-messages-request))
(set-filters-initialized)))
(fx/defn handle-filters [cofx filters]
(handle-filters-added cofx (map responses->filters filters)))
(fx/defn handle-filters-removed
"Called when we remove a filter from status-go, it will update the mailserver
topics"

View File

@ -4,7 +4,9 @@
[status-im.chat.models :as models.chat]
[status-im.chat.models.reactions :as models.reactions]
[status-im.contact.core :as models.contact]
[status-im.communities.core :as models.communities]
[status-im.pairing.core :as models.pairing]
[status-im.transport.filters.core :as models.filters]
[status-im.data-store.messages :as data-store.messages]
[status-im.data-store.reactions :as data-store.reactions]
[status-im.data-store.contacts :as data-store.contacts]
@ -23,20 +25,32 @@
(fx/defn handle-message [cofx message]
(models.message/receive-one cofx message))
(fx/defn handle-community [cofx community]
(models.communities/handle-community cofx community))
(fx/defn handle-reactions [cofx reactions]
(models.reactions/receive-signal cofx reactions))
(fx/defn handle-invitations [cofx invitations]
(models.group/handle-invitations cofx invitations))
(fx/defn handle-filters [cofx filters]
(models.filters/handle-filters cofx filters))
(fx/defn handle-filters-removed [cofx filters]
(models.filters/handle-filters-removed cofx filters))
(fx/defn process-response
{:events [::process]}
[cofx ^js response-js]
(let [^js chats (.-chats response-js)
(let [^js communities (.-communities response-js)
^js chats (.-chats response-js)
^js contacts (.-contacts response-js)
^js installations (.-installations response-js)
^js messages (.-messages response-js)
^js emoji-reactions (.-emojiReactions response-js)
^js filters (.-filters response-js)
^js removed-filters (.-removedFilters response-js)
^js invitations (.-invitations response-js)]
(cond
(seq installations)
@ -53,6 +67,11 @@
{:utils/dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
(handle-contacts (map data-store.contacts/<-rpc contacts-clj))))
(seq communities)
(let [community (.pop communities)]
(fx/merge cofx
{:utils/dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
(handle-community (types/js->clj community))))
(seq chats)
(let [chats-clj (types/js->clj chats)]
(js-delete response-js "chats")
@ -81,7 +100,20 @@
(js-delete response-js "invitations")
(fx/merge cofx
{:utils/dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
(handle-invitations (map data-store.invitations/<-rpc invitations)))))))
(handle-invitations (map data-store.invitations/<-rpc invitations))))
(seq filters)
(let [filters (types/js->clj filters)]
(js-delete response-js "filters")
(fx/merge cofx
{:utils/dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
(handle-filters filters)))
(seq removed-filters)
(let [removed-filters (types/js->clj removed-filters)]
(js-delete response-js "removedFilters")
(fx/merge cofx
{:utils/dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
(handle-filters-removed filters))))))
(fx/defn remove-hash
[{:keys [db] :as cofx} envelope-hash]

View File

@ -9,6 +9,7 @@
text
response-to
ens-name
community-id
image-path
audio-path
audio-duration-ms
@ -21,6 +22,7 @@
:imagePath image-path
:audioPath audio-path
:audioDurationMs audio-duration-ms
:communityId community-id
:sticker sticker
:contentType content-type})

View File

@ -24,13 +24,6 @@
(second name)
(first name)))]]))
(defn dapp-badge [{:keys [online-view-wrapper online-view online-dot-left online-dot-right]}]
[react/view online-view-wrapper
[react/view online-view
[react/view
[react/view online-dot-left]
[react/view online-dot-right]]]])
(defn chat-icon-view
[chat-id group-chat name styles]
[react/view (:container styles)
@ -43,10 +36,6 @@
[chat-id group-chat name color]
[chat-icon-view chat-id group-chat name
{:container styles/container-chat-toolbar
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:size 36
:chat-icon styles/chat-icon-chat-toolbar
:default-chat-icon (styles/default-chat-icon-chat-toolbar color)
@ -56,10 +45,6 @@
[chat-id group-chat name color]
[chat-icon-view chat-id group-chat name
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:size 40
:chat-icon styles/chat-icon-chat-list
:default-chat-icon (styles/default-chat-icon-chat-list color)
@ -69,10 +54,6 @@
[chat-id group-chat name color]
[chat-icon-view chat-id group-chat name
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:size 40
:chat-icon styles/chat-icon-chat-list
:default-chat-icon (styles/default-chat-icon-chat-list color)
@ -85,13 +66,9 @@
:default-chat-icon-text (styles/default-chat-icon-text (or size 40))}]])
(defn contact-icon-view
[{:keys [name dapp?] :as contact} {:keys [container] :as styles}]
[contact {:keys [container] :as styles}]
[react/view container
(if dapp?
[default-chat-icon name styles]
[photos/photo (multiaccounts/displayed-photo contact) styles])
(when dapp?
[dapp-badge styles])])
[photos/photo (multiaccounts/displayed-photo contact) styles]])
(defn contact-icon-contacts-tab [photo-path]
[react/view styles/container-chat-list
@ -100,10 +77,6 @@
(defn dapp-icon-permission [contact size]
[contact-icon-view contact
{:container {:width size :height size}
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:size size
:chat-icon (styles/custom-size-icon size)
:default-chat-icon (styles/default-chat-icon-profile colors/default-chat-color size)
@ -118,9 +91,6 @@
(defn profile-icon-view [photo-path name color edit? size override-styles]
(let [styles (merge {:container {:width size :height size}
:online-view styles/online-view-profile
:online-dot-left styles/online-dot-left-profile
:online-dot-right styles/online-dot-right-profile
:size size
:chat-icon styles/chat-icon-profile
:default-chat-icon (styles/default-chat-icon-profile color size)

View File

@ -94,6 +94,7 @@
(def mention-outgoing "#9EE8FA")
(def text black)
(def text-gray gray)
(def default-community-color "#773377")
(def default-chat-color "#a187d5") ;; legacy

View File

@ -2,12 +2,12 @@
(:require [re-frame.core :as re-frame]
[quo.core :as quo]
[status-im.ui.components.react :as react]
[status-im.constants :as constants]
[status-im.utils.universal-links.utils :as links]
[status-im.ui.screens.chat.styles.main :as style]
[status-im.i18n :as i18n]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.colors :as colors]
[status-im.constants :as constants]
[status-im.utils.debounce :as debounce])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
@ -83,18 +83,33 @@
:size :small
:color colors/gray}]])
(defview no-messages-group-chat-description-container [chat-id]
(defn calculate-quiet-time [highest-request-to
lowest-request-from]
(let [quiet-hours (quot (- highest-request-to lowest-request-from)
(* 60 60))]
(if (<= quiet-hours 24)
(i18n/label :t/quiet-hours
{:quiet-hours quiet-hours})
(i18n/label :t/quiet-days
{:quiet-days (quot quiet-hours 24)}))))
(defview no-messages-community-chat-description-container [chat-id]
(letsubs [{:keys [highest-request-to lowest-request-from]}
[:mailserver/ranges-by-chat-id chat-id]]
[react/text {:style (merge style/intro-header-description
{:margin-bottom 36})}
(let [quiet-time (calculate-quiet-time highest-request-to
lowest-request-from)]
(i18n/label :t/empty-chat-description-community
{:quiet-hours quiet-time}))]))
(defview no-messages-private-group-chat-description-container [chat-id]
(letsubs [{:keys [highest-request-to lowest-request-from]}
[:mailserver/ranges-by-chat-id chat-id]]
[react/nested-text {:style (merge style/intro-header-description
{:margin-bottom 36})}
(let [quiet-hours (quot (- highest-request-to lowest-request-from)
(* 60 60))
quiet-time (if (<= quiet-hours 24)
(i18n/label :t/quiet-hours
{:quiet-hours quiet-hours})
(i18n/label :t/quiet-days
{:quiet-days (quot quiet-hours 24)}))]
(let [quiet-time (calculate-quiet-time highest-request-to
lowest-request-from)]
(i18n/label :t/empty-chat-description-public
{:quiet-hours quiet-time}))
[{:style {:color colors/blue}
@ -143,20 +158,23 @@
(i18n/label :t/membership-description)])
(defn group-chat-description-container
[{:keys [public?
invitation-admin
[{:keys [invitation-admin
chat-id
chat-name
chat-type
loading-messages?
no-messages?]}]
(cond loading-messages?
group-chat-description-loading
(and no-messages? public?)
[no-messages-group-chat-description-container chat-id]
(and no-messages? (= chat-type constants/public-chat-type))
[no-messages-private-group-chat-description-container chat-id]
(and no-messages? (= chat-type constants/community-chat-type))
[no-messages-community-chat-description-container chat-id]
invitation-admin
[group-chat-membership-description]
(not public?)
(= chat-type constants/private-group-chat-type)
[group-chat-inviter-description-container chat-id chat-name]))

View File

@ -2,6 +2,9 @@
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.i18n :as i18n]
[status-im.communities.core :as communities]
[status-im.utils.config :as config]
[status-im.react-native.resources :as resources]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.react :as react]
@ -10,6 +13,7 @@
[status-im.ui.screens.chat.message.command :as message.command]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.chat.sheets :as sheets]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.screens.chat.styles.message.message :as style]
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.utils.contenthash :as contenthash]
@ -209,6 +213,64 @@
(letsubs [contact-with-names [:multiaccount/contact]]
(chat.utils/format-author contact-with-names opts)))
(defview community-content [{:keys [community-id] :as message}]
(letsubs [{:keys [joined verified] :as community} [:communities/community community-id]]
(when (and
config/communities-enabled?
community)
[react/view {:style (assoc (style/message-wrapper message)
:margin-vertical 10
:width 271)}
(when verified
[react/view {:border-right-width 1
:border-left-width 1
:border-top-width 1
:border-left-color colors/gray-lighter
:border-right-color colors/gray-lighter
:border-top-left-radius 10
:border-top-right-radius 10
:padding-vertical 8
:padding-horizontal 15
:border-top-color colors/gray-lighter}
[react/text {:style {:font-size 13
:color colors/blue}} (i18n/label :t/communities-verified)]])
[react/view {:flex-direction :row
:padding-vertical 12
:border-top-left-radius (when-not verified 10)
:border-top-right-radius (when-not verified 10)
:border-right-width 1
:border-left-width 1
:border-top-width 1
:border-color colors/gray-lighter}
[react/view {:width 62
:padding-left 14}
(if (= community-id constants/status-community-id)
[react/image {:source (resources/get-image :status-logo)
:style {:width 40
:height 40}}]
(let [display-name (get-in community [:description :identity :display-name])]
[chat-icon/chat-icon-view-chat-list
display-name
true
display-name
colors/default-community-color]))]
[react/view {:padding-right 14}
[react/text {:style {:font-weight "700"
:font-size 17}}
(get-in community [:description :identity :display-name])]
[react/text (get-in community [:description :identity :description])]]]
[react/view {:border-width 1
:padding-vertical 8
:border-bottom-left-radius 10
:border-bottom-right-radius 10
:border-color colors/gray-lighter}
[react/touchable-highlight {:on-press #(re-frame/dispatch [(if joined ::communities/leave ::communities/join) (:id community)])}
[react/text {:style {:text-align :center
:color colors/blue}} (if joined (i18n/label :t/leave) (i18n/label :t/join))]]]])))
(defn message-content-wrapper
"Author, userpic and delivery wrapper"
[{:keys [first-in-group? display-photo? display-username?
@ -356,6 +418,10 @@
[collapsible-text-message message on-long-press modal]
reaction-picker])
(defmethod ->message constants/content-type-community
[message]
[community-content message])
(defmethod ->message constants/content-type-status
[{:keys [content content-type] :as message}]
[message-content-wrapper message

View File

@ -2,6 +2,7 @@
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.react :as react]
[status-im.constants :as constants]
[status-im.ui.components.list-selection :as list-selection]
[status-im.utils.universal-links.utils :as universal-links]
[status-im.ui.components.chat-icon.screen :as chat-icon]
@ -78,6 +79,27 @@
:icon :main-icons/delete
:on-press #(re-frame/dispatch [:chat.ui/remove-chat-pressed chat-id])}]]))
(defn community-chat-accents []
(fn [{:keys [chat-id group-chat chat-name color]}]
[react/view
[quo/list-item
{:theme :accent
:title chat-name
:icon [chat-icon/chat-icon-view-chat-sheet
chat-id group-chat chat-name color]}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/mark-all-read)
:accessibility-label :mark-all-read-button
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [:chat.ui/mark-all-read-pressed chat-id])}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/clear-history)
:accessibility-label :clear-history-button
:icon :main-icons/close
:on-press #(re-frame/dispatch [:chat.ui/clear-history-pressed chat-id])}]]))
(defn group-chat-accents []
(fn [{:keys [chat-id group-chat chat-name color invitation-admin]}]
(let [{:keys [joined?]} @(re-frame/subscribe [:group-chat/inviter-info chat-id])]
@ -117,11 +139,20 @@
:icon :main-icons/arrow-left
:on-press #(re-frame/dispatch [:group-chats.ui/leave-chat-pressed chat-id])}])]))))
(defn actions [{:keys [public? group-chat]
(defn actions [{:keys [chat-type]
:as current-chat}]
(cond
public? [public-chat-accents current-chat]
group-chat [group-chat-accents current-chat]
(#{constants/public-chat-type
constants/profile-chat-type
constants/timeline-chat-type} chat-type)
[public-chat-accents current-chat]
(= chat-type constants/community-chat-type)
[community-chat-accents current-chat]
(= chat-type constants/private-group-chat-type)
[group-chat-accents current-chat]
:else [one-to-one-chat-accents current-chat]))
(defn options [chat-id message-id]

View File

@ -1,5 +1,6 @@
(ns status-im.ui.screens.chat.toolbar-content
(:require [status-im.i18n :as i18n]
[status-im.constants :as constants]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.styles.main :as st]
@ -35,6 +36,7 @@
color
chat-id
contacts
chat-type
chat-name
public?]}]
[react/view {:style st/toolbar-container}
@ -49,6 +51,6 @@
[one-to-one-name chat-id])
(when-not group-chat
[contact-indicator chat-id])
(when (and group-chat (not invitation-admin))
(when (and group-chat (not invitation-admin) (not= chat-type constants/community-chat-type))
[group-last-activity {:contacts contacts
:public? public?}])]])

View File

@ -74,10 +74,10 @@
(defn chat-intro [{:keys [chat-id
chat-name
chat-type
group-chat
invitation-admin
contact-name
public?
color
loading-messages?
no-messages?]}]
@ -99,7 +99,7 @@
:invitation-admin invitation-admin
:loading-messages? loading-messages?
:chat-name chat-name
:public? public?
:chat-type chat-type
:no-messages? no-messages?}]
[react/text {:style (assoc style/intro-header-description
:margin-bottom 32)}
@ -115,6 +115,7 @@
(defn chat-intro-header-container
[{:keys [group-chat invitation-admin
chat-type
might-have-join-time-messages?
color chat-id chat-name
public?]}
@ -128,6 +129,7 @@
{:chat-id chat-id
:group-chat group-chat
:invitation-admin invitation-admin
:chat-type chat-type
:chat-name chat-name
:public? public?
:color color
@ -170,7 +172,7 @@
(defn messages-view
[{:keys [chat bottom-space pan-responder space-keeper]}]
(let [{:keys [group-chat chat-id public? invitation-admin]} chat
(let [{:keys [group-chat chat-id chat-type public? invitation-admin]} chat
messages @(re-frame/subscribe [:chats/current-chat-messages-stream])
no-messages? @(re-frame/subscribe [:chats/current-chat-no-messages?])
@ -180,11 +182,11 @@
pan-responder
{:key-fn #(or (:message-id %) (:value %))
:ref #(reset! messages-list-ref %)
:header (when (and group-chat (not public?))
:header (when (= chat-type constants/private-group-chat-type)
[chat.group/group-chat-footer chat-id invitation-admin])
:footer [:<>
[chat-intro-header-container chat no-messages?]
(when (and (not group-chat) (not public?))
(when (= chat-type constants/one-to-one-chat-type)
[invite.chat/reward-messages])]
:data messages
:inverted true

View File

@ -0,0 +1,423 @@
(ns status-im.ui.screens.communities.views (:require-macros [status-im.utils.views :as views])
(:require
[reagent.core :as reagent]
[re-frame.core :as re-frame]
[quo.core :as quo]
[status-im.i18n :as i18n]
[status-im.utils.core :as utils]
[status-im.utils.config :as config]
[status-im.constants :as constants]
[status-im.communities.core :as communities]
[status-im.ui.screens.home.views.inner-item :as inner-item]
[status-im.ui.screens.home.styles :as home.styles]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.copyable-text :as copyable-text]
[status-im.react-native.resources :as resources]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.components.icons.vector-icons :as icons]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.react :as react]))
(defn hide-sheet-and-dispatch [event]
(re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch event))
(defn community-list-item [{:keys [id description]}]
(let [identity (:identity description)]
[quo/list-item
{:icon (if (= id constants/status-community-id)
[react/image {:source (resources/get-image :status-logo)
:style {:width 40
:height 40}}]
[chat-icon.screen/chat-icon-view-chat-list
id
true
(:display-name identity)
;; TODO: should be derived by id
(or (:color identity)
(rand-nth colors/chat-colors))
false
false])
:title [react/view {:flex-direction :row
:flex 1}
[react/view {:flex-direction :row
:flex 1
:padding-right 16
:align-items :center}
[quo/text {:weight :medium
:accessibility-label :community-name-text
:ellipsize-mode :tail
:number-of-lines 1}
(utils/truncate-str (:display-name identity) 30)]]]
:title-accessibility-label :community-name-text
:subtitle [react/view {:flex-direction :row}
[react/view {:flex 1}
[quo/text
(utils/truncate-str (:description identity) 30)]]]
:on-press #(do
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:navigate-to :community id]))}]))
(defn communities-actions []
[react/view
[quo/list-item
{:theme :accent
:title (i18n/label :t/import-community)
:accessibility-label :community-import-community
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [::communities/import-pressed])}]
[quo/list-item
{:theme :accent
:title (i18n/label :t/create-community)
:accessibility-label :community-create-community
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [::communities/create-pressed])}]])
(views/defview communities []
(views/letsubs [communities [:communities]]
[react/view {:flex 1}
[topbar/topbar (cond-> {:title (i18n/label :t/communities)}
config/communities-management-enabled?
(assoc :right-accessories [{:icon :main-icons/more
:accessibility-label :chat-menu-button
:on-press
#(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[communities-actions])
:height 256}])}]))]
[react/scroll-view {:style {:flex 1}
:content-container-style {:padding-vertical 8}}
[list/flat-list
{:key-fn :id
:keyboard-should-persist-taps :always
:data (vals communities)
:render-fn (fn [community] [community-list-item community])}]]
(when config/communities-management-enabled?
[toolbar/toolbar
{:show-border? true
:center [quo/button {:on-press #(re-frame/dispatch [::communities/create-pressed])}
(i18n/label :t/create)]}])]))
(defn valid? [community-name community-description]
(and (not= "" community-name)
(not= "" community-description)))
(defn import-community []
(let [community-key (reagent/atom "")]
(fn []
[react/view {:style {:padding-left 16
:padding-right 8}}
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/community-key)
:placeholder (i18n/label :t/community-key-placeholder)
:on-change-text #(reset! community-key %)
:auto-focus true}]]
[react/view {:style {:padding-top 20
:padding-horizontal 20}}
[quo/button {:disabled (= @community-key "")
:on-press #(re-frame/dispatch [::communities/import-confirmation-pressed @community-key])}
(i18n/label :t/import)]]])))
(defn create []
(let [community-name (reagent/atom "")
membership (reagent/atom 1)
community-description (reagent/atom "")]
(fn []
[react/view {:style {:padding-left 16
:padding-right 8}}
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/name-your-community)
:placeholder (i18n/label :t/name-your-community-placeholder)
:on-change-text #(reset! community-name %)
:auto-focus true}]]
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/give-a-short-description-community)
:placeholder (i18n/label :t/give-a-short-description-community)
:multiline true
:number-of-lines 4
:on-change-text #(reset! community-description %)}]]
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/membership-type)
:placeholder (i18n/label :t/membership-type-placeholder)
:on-change-text #(reset! membership %)}]]
[react/view {:style {:padding-top 20
:padding-horizontal 20}}
[quo/button {:disabled (not (valid? @community-name @community-description))
:on-press #(re-frame/dispatch [::communities/create-confirmation-pressed @community-name @community-description @membership])}
(i18n/label :t/create)]]])))
(def create-sheet
{:content create})
(def import-sheet
{:content import-community})
(defn create-channel []
(let [channel-name (reagent/atom "")
channel-description (reagent/atom "")]
(fn []
[react/view {:style {:padding-left 16
:padding-right 8}}
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/name-your-channel)
:placeholder (i18n/label :t/name-your-channel-placeholder)
:on-change-text #(reset! channel-name %)
:auto-focus true}]]
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/give-a-short-description-channel)
:placeholder (i18n/label :t/give-a-short-description-channel)
:multiline true
:number-of-lines 4
:on-change-text #(reset! channel-description %)}]]
(when config/communities-management-enabled?
[react/view {:style {:padding-top 20
:padding-horizontal 20}}
[quo/button {:disabled (not (valid? @channel-name @channel-description))
:on-press #(re-frame/dispatch [::communities/create-channel-confirmation-pressed @channel-name @channel-description])}
(i18n/label :t/create)]])])))
(def create-channel-sheet
{:content create-channel})
(defn invite-people []
(let [user-pk (reagent/atom "")]
(fn []
[react/view {:style {:padding-left 16
:padding-right 8}}
[react/view {:style {:padding-horizontal 20}}
[quo/text-input
{:label (i18n/label :t/enter-user-pk)
:placeholder (i18n/label :t/enter-user-pk)
:on-change-text #(reset! user-pk %)
:auto-focus true}]]
[react/view {:style {:padding-top 20
:padding-horizontal 20}}
[quo/button {:disabled (= "" user-pk)
:on-press #(re-frame/dispatch [::communities/invite-people-confirmation-pressed @user-pk])}
(i18n/label :t/invite)]]])))
(def invite-people-sheet
{:content invite-people})
(defn community-actions [id admin]
[react/view
(when (and config/communities-management-enabled? admin)
[quo/list-item
{:theme :accent
:title (i18n/label :t/export-key)
:accessibility-label :community-export-key
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [::communities/export-pressed id])}])
(when (and config/communities-management-enabled? admin)
[quo/list-item
{:theme :accent
:title (i18n/label :t/create-channel)
:accessibility-label :community-create-channel
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [::communities/create-channel-pressed id])}])
(when (and config/communities-management-enabled? admin)
[quo/list-item
{:theme :accent
:title (i18n/label :t/invite-people)
:accessibility-label :community-invite-people
:icon :main-icons/close
:on-press #(re-frame/dispatch [::communities/invite-people-pressed id])}])
[quo/list-item
{:theme :accent
:title (i18n/label :t/leave)
:accessibility-label :leave
:icon :main-icons/close
:on-press #(do
(re-frame/dispatch [:navigate-to :home])
(re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch [::communities/leave id]))}]])
(defn toolbar-content [id display-name color]
[react/view {:style {:flex 1
:align-items :center
:flex-direction :row}}
[react/view {:margin-right 10}
(if (= id constants/status-community-id)
[react/image {:source (resources/get-image :status-logo)
:style {:width 40
:height 40}}]
[chat-icon.screen/chat-icon-view-toolbar
id
true
display-name
(or color
(rand-nth colors/chat-colors))])]
[react/view {:style {:flex 1 :justify-content :center}}
[react/text {:style {:typography :main-medium
:font-size 15
:line-height 22}
:number-of-lines 1
:accessibility-label :community-name-text}
display-name]]])
(defn topbar [id display-name color admin joined]
[topbar/topbar
{:content [toolbar-content id display-name color]
:navigation {:on-press #(re-frame/dispatch [:navigate-back])}
:right-accessories (when (or admin joined)
[{:icon :main-icons/more
:accessibility-label :community-menu-button
:on-press
#(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[community-actions id admin])
:height 256}])}])}])
(defn welcome-blank-page []
[react/view {:style {:flex 1 :flex-direction :row :align-items :center :justify-content :center}}
[react/i18n-text {:style home.styles/welcome-blank-text :key :welcome-blank-message}]])
(views/defview community-unviewed-count [id]
(views/letsubs [unviewed-count [:communities/unviewed-count id]]
(when-not (zero? unviewed-count)
[react/view {:style {:background-color colors/blue
:border-radius 6
:margin-right 5
:margin-top 2
:width 12
:height 12}
:accessibility-label :unviewed-messages-public}])))
(defn status-community [{:keys [id description]}]
[quo/list-item
{:icon [react/image {:source (resources/get-image :status-logo)
:style {:width 40
:height 40}}]
:title [react/view {:flex-direction :row
:flex 1}
[react/view {:flex-direction :row
:flex 1
:padding-right 16
:align-items :center}
[quo/text {:weight :medium
:accessibility-label :chat-name-text
:font-size 17
:ellipsize-mode :tail
:number-of-lines 1}
(get-in description [:identity :display-name])]]
[react/view {:flex-direction :row
:flex 1
:justify-content :flex-end
:align-items :center}
[community-unviewed-count id]]]
:title-accessibility-label :chat-name-text
:on-press #(do
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:navigate-to :community id]))
;; TODO: actions
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
nil])}])
(defn channel-preview-item [{:keys [id identity]}]
[quo/list-item
{:icon [chat-icon.screen/chat-icon-view-chat-list
id true (:display-name identity) colors/blue false false]
:title [react/view {:flex-direction :row
:flex 1}
[react/view {:flex-direction :row
:flex 1
:padding-right 16
:align-items :center}
[icons/icon :main-icons/tiny-group
{:color colors/black
:width 15
:height 15
:container-style {:width 15
:height 15
:margin-right 2}}]
[quo/text {:weight :medium
:accessibility-label :chat-name-text
:ellipsize-mode :tail
:number-of-lines 1}
(utils/truncate-str (:display-name identity) 30)]]]
:title-accessibility-label :chat-name-text
:subtitle [react/view {:flex-direction :row}
[react/text-class {:style home.styles/last-message-text
:number-of-lines 1
:ellipsize-mode :tail
:accessibility-label :chat-message-text} (:description identity)]]}])
(defn community-channel-preview-list [_ description]
(let [chats (reduce-kv
(fn [acc k v]
(conj acc (assoc v :id (name k))))
[]
(get-in description [:chats]))]
[list/flat-list
{:key-fn :id
:keyboard-should-persist-taps :always
:data chats
:render-fn channel-preview-item}]))
(defn community-chat-list [chats]
(if (empty? chats)
[welcome-blank-page]
[list/flat-list
{:key-fn :chat-id
:keyboard-should-persist-taps :always
:data chats
:render-fn (fn [home-item] [inner-item/home-list-item (assoc home-item :color colors/blue)])
:footer [react/view {:height 68}]}]))
(views/defview community-channel-list [id]
(views/letsubs [chats [:chats/by-community-id id]]
[community-chat-list chats]))
(views/defview community [route]
(views/letsubs [{:keys [id description joined admin]} [:communities/community (get-in route [:route :params])]]
[react/view {:style {:flex 1}}
[topbar
id
(get-in description [:identity :display-name])
(get-in description [:identity :color])
admin
joined]
(if joined
[community-channel-list id]
[community-channel-preview-list id description])
(when-not joined
[react/view {:style {:padding-top 20
:margin-bottom 10
:padding-horizontal 20}}
[quo/button {:on-press #(re-frame/dispatch [::communities/join id])}
(i18n/label :t/join)]])]))
(views/defview export-community []
(views/letsubs [{:keys [community-key]} [:popover/popover]]
[react/view {}
[react/view {:style {:padding-top 16 :padding-horizontal 16}}
[copyable-text/copyable-text-view
{:label :t/community-key
:container-style {:margin-top 12 :margin-bottom 4}
:copied-text community-key}
[quo/text {:number-of-lines 1
:ellipsize-mode :middle
:accessibility-label :chat-key
:monospace true}
community-key]]]]))
(defn render-featured-community [{:keys [name id]}]
^{:key id}
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :community id])
:accessibility-label :chat-item}
[react/view {:padding-right 8 :padding-vertical 8}
[react/view {:border-color colors/gray-lighter :border-radius 36 :border-width 1 :padding-horizontal 8 :padding-vertical 5}
[react/text {:style {:color colors/blue :typography :main-medium}} name]]]])

View File

@ -47,6 +47,13 @@
:accessibility-label :join-public-chat-button
:icon :main-icons/public-chat
:on-press #(hide-sheet-and-dispatch [:navigate-to :new-public-chat])}]
(when config/communities-enabled?
[quo/list-item
{:theme :accent
:title (i18n/label :t/communities-alpha)
:accessibility-label :communities-button
:icon :main-icons/communities
:on-press #(hide-sheet-and-dispatch [:navigate-to :communities])}])
[invite/list-item
{:accessibility-label :chats-menu-invite-friends-button}]])

View File

@ -3,11 +3,13 @@
[reagent.core :as reagent]
[status-im.i18n :as i18n]
[status-im.react-native.resources :as resources]
[status-im.communities.core :as communities]
[status-im.ui.components.connectivity.view :as connectivity]
[status-im.ui.components.icons.vector-icons :as icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.screens.home.styles :as styles]
[status-im.ui.screens.communities.views :as communities.views]
[status-im.ui.screens.home.views.inner-item :as inner-item]
[status-im.ui.screens.referrals.home-item :as referral-item]
[status-im.ui.components.colors :as colors]
@ -79,7 +81,14 @@
[react/view {:style styles/tags-wrapper}
[react/view {:flex-direction :row :flex-wrap :wrap :justify-content :center}
(for [chat (new-public-chat/featured-public-chats)]
(new-public-chat/render-topic chat))]]]])
(new-public-chat/render-topic chat))]]
[react/i18n-text {:style {:margin-horizontal 16
:text-align :center}
:key :join-a-community}]
[react/view {:style styles/tags-wrapper}
[react/view {:flex-direction :row :flex-wrap :wrap :justify-content :center}
(for [community communities/featured]
(communities.views/render-featured-community community))]]]])
(defn welcome-blank-page []
[react/view {:style {:flex 1 :flex-direction :row :align-items :center :justify-content :center}}
@ -136,31 +145,48 @@
(defn render-fn [home-item]
[inner-item/home-list-item home-item])
(defn communities-and-chats [chats status-community loading? search-filter hide-home-tooltip?]
(if loading?
[react/view {:flex 1 :align-items :center :justify-content :center}
[react/activity-indicator {:animating true}]]
(if (and (empty? chats)
(not status-community)
(empty? search-filter)
hide-home-tooltip?
(not @search-active?))
[welcome-blank-page]
[react/view
[:<>
(when (or (seq chats) @search-active? (seq search-filter))
[search-input-wrapper search-filter chats])
[referral-item/list-item]]
(when
(and (empty? chats)
(not status-community))
(or @search-active? (seq search-filter))
[start-suggestion search-filter])
(when status-community
;; We only support one community now, Status
[communities.views/status-community status-community])
(when (and status-community
(seq chats))
[quo/separator])
[list/flat-list
{:key-fn :chat-id
:keyboard-should-persist-taps :always
:data chats
:render-fn render-fn
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
[home-tooltip-view]
[react/view {:height 68}])}]])))
(views/defview chats-list []
(views/letsubs [loading? [:chats/loading?]
(views/letsubs [status-community [:communities/status-community]
loading? [:chats/loading?]
{:keys [chats search-filter]} [:home-items]
{:keys [hide-home-tooltip?]} [:multiaccount]]
(if loading?
[react/view {:flex 1 :align-items :center :justify-content :center}
[react/activity-indicator {:animating true}]]
(if (and (empty? chats)
(empty? search-filter)
hide-home-tooltip?
(not @search-active?))
[welcome-blank-page]
[list/flat-list
{:key-fn :chat-id
:keyboard-should-persist-taps :always
:data chats
:render-fn render-fn
:header [:<> (when (or (seq chats) @search-active? (seq search-filter))
[search-input-wrapper search-filter chats])
[referral-item/list-item]]
:empty-component (when (or @search-active? (seq search-filter))
[start-suggestion search-filter])
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
[home-tooltip-view]
[react/view {:height 68}])}]))))
[react/scroll-view
[communities-and-chats chats status-community loading? search-filter hide-home-tooltip?]]))
(views/defview plus-button []
(views/letsubs [logging-in? [:multiaccounts/login]]

View File

@ -6,6 +6,7 @@
[re-frame.core :as re-frame]
[status-im.utils.platform :as platform]
[status-im.ui.screens.wallet.signing-phrase.views :as signing-phrase]
[status-im.ui.screens.communities.views :as communities]
[status-im.ui.screens.wallet.request.views :as request]
[status-im.ui.screens.profile.user.views :as profile.user]
["react-native" :refer (BackHandler)]
@ -147,6 +148,9 @@
(= :advertiser-invite view)
[advertiser.invite/accept-popover]
(= :export-community view)
[communities/export-community]
(= :dapp-invite view)
[dapp.invite/accept-popover]

View File

@ -4,6 +4,7 @@
[status-im.ui.screens.chat.views :as chat]
[status-im.ui.screens.group.views :as group]
[status-im.ui.screens.referrals.public-chat :as referrals.public-chat]
[status-im.ui.screens.communities.views :as communities]
[status-im.ui.screens.profile.group-chat.views :as profile.group-chat]
[status-im.ui.components.tabbar.styles :as tabbar.styles]
[status-im.ui.screens.stickers.views :as stickers]))
@ -19,6 +20,14 @@
:component home/home}
{:name :referral-enclav
:component referrals.public-chat/view}
{:name :communities
:transition :presentation-ios
:insets {:bottom true}
:component communities/communities}
{:name :community
:transition :presentation-ios
:insets {:bottom true}
:component communities/community}
{:name :chat
:component chat/chat}
{:name :group-chat-profile

View File

@ -154,7 +154,6 @@
:transition :presentation-ios
:insets {:bottom true}
:component contact/profile}]
(when config/quo-preview-enabled?
[{:name :quo-preview
:insets {:top false :bottom false}

View File

@ -12,6 +12,7 @@
[status-im.ui.screens.routing.main :as routing]
[status-im.ui.screens.signing.views :as signing]
[status-im.ui.screens.popover.views :as popover]
[status-im.ui.screens.communities.views :as communities]
[status-im.ui.screens.multiaccounts.recover.views :as recover.views]
[status-im.ui.screens.wallet.send.views :as wallet]
[status-im.ui.components.status-bar.view :as statusbar]
@ -49,6 +50,18 @@
(= view :learn-more)
(merge about-app/learn-more)
(= view :create-community)
(merge communities/create-sheet)
(= view :import-community)
(merge communities/import-sheet)
(= view :create-community-channel)
(merge communities/create-channel-sheet)
(= view :invite-people-community)
(merge communities/invite-people-sheet)
(= view :recover-sheet)
(merge recover.views/bottom-sheet))]
[quo/bottom-sheet opts

View File

@ -46,6 +46,10 @@
(def referrals-invite-enabled? (enabled? (get-config :ENABLE_REFERRAL_INVITE "0")))
(def quo-preview-enabled? (enabled? (get-config :ENABLE_QUO_PREVIEW "0")))
(def google-free (enabled? (get-config :GOOGLE_FREE "0")))
(def communities-enabled? (enabled? (get-config :COMMUNITIES_ENABLED "0")))
(def communities-management-enabled? (and (enabled? (get-config :COMMUNITIES_MANAGEMENT_ENABLED "0"))
communities-enabled?))
;; CONFIG VALUES
(def log-level
(string/upper-case (get-config :LOG_LEVEL "")))

View File

@ -20,7 +20,8 @@
(when-not (= json "undefined")
(try
(js->clj (.parse js/JSON json))
(catch js/Error _ (when (string? json) json)))))
(catch js/Error _
(when (string? json) json)))))
(def serialize clj->json)
(defn deserialize [o] (try (json->clj o)

View File

@ -2,7 +2,7 @@
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
"owner": "status-im",
"repo": "status-go",
"version": "v0.66.2",
"commit-sha1": "fee08aafbe0cdad352a4bdccff2ec883a3443b9c",
"src-sha256": "0q5x70mdya3561dyigmkickhb8hkz92d14cc9hhwmbkpz41bcrd8"
"version": "v0.67.0",
"commit-sha1": "f5482ec187b981dd77d184cc7003dcc0c6ae5d22",
"src-sha256": "18bzsf1nskvsvkxxw9v8v4zpgxfaag7q6a07fbdmz7f0y3a3mxjz"
}

View File

@ -145,6 +145,17 @@
"close-app-content": "The app will stop and close. When you reopen it, the selected network will be used",
"close-app-title": "Warning!",
"command-button-send": "Send",
"communities": "Communities",
"name-your-channel": "Name your channel",
"give-a-short-description": "Give a short description",
"communities-alpha": "Communities (alpha)",
"communities-verified": "✓ Verified Status Community",
"create-community": "Create a community",
"create-channel": "Create a channel",
"import-community": "Import a community",
"name-your-community": "Name your community",
"name-your-community-placeholder": "A catchy name",
"give-a-short-description-community": "Give it a short description",
"complete-hardwallet-setup": "This card is now linked. You need it to sign transactions and unlock your keys",
"completed": "Completed",
"confirm": "Confirm",
@ -355,6 +366,7 @@
"empty-chat-description": "There are no messages \nin this chat yet",
"empty-chat-description-one-to-one": "Any messages you send here are encrypted and can only be read by you and ",
"empty-chat-description-public": "It's been quiet here for the last {{quiet-hours}}. Start the conversation or ",
"empty-chat-description-community": "It's been quiet here for the last {{quiet-hours}}.",
"empty-chat-description-public-share-this": "share this chat.",
"enable": "Enable",
"encrypt-with-password": "Encrypt with password",
@ -466,6 +478,7 @@
"ethereum-node-started-incorrectly-title": "Ethereum node started incorrectly",
"etherscan-lookup": "Look up on Etherscan",
"export-account": "Export account",
"export-key": "Export key",
"failed": "Failed",
"faq": "Frequently asked questions",
"fetch-messages": "↓ Fetch messages",
@ -574,9 +587,11 @@
"invalid-pairing-password": "Invalid pairing password",
"invalid-range": "Invalid format, must be between {{min}} and {{max}}",
"join-me": "Hey join me on Status: {{url}}",
"join-a-community": "or join a community",
"http-gateway-error": "Oops, request failed!",
"sign-request-failed": "Could not sign message",
"invite-friends": "Invite friends",
"invite-people": "Invite people",
"invite-reward": "Earn crypto for every friend you invite!",
"invite-select-account": "Select an account to receive your referral bonus",
"invited": "invited",
@ -681,6 +696,7 @@
"learn-more": "Learn more",
"learn-more-about-keycard": "Learn more about Keycard",
"leave": "Leave",
"joined": "Joined",
"leave-group": "Leave group",
"left": "left",
"lets-go": "Let's go",