public group chat
BIN
android/app/src/main/res/drawable-hdpi/icon_private_group.png
Normal file
After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 1.3 KiB |
BIN
android/app/src/main/res/drawable-hdpi/icon_public_group.png
Normal file
After Width: | Height: | Size: 621 B |
BIN
android/app/src/main/res/drawable-hdpi/icon_public_group_big.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
android/app/src/main/res/drawable-mdpi/icon_private_group.png
Normal file
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 875 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_public_group.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_public_group_big.png
Normal file
After Width: | Height: | Size: 654 B |
BIN
android/app/src/main/res/drawable-xhdpi/icon_private_group.png
Normal file
After Width: | Height: | Size: 793 B |
After Width: | Height: | Size: 1.5 KiB |
BIN
android/app/src/main/res/drawable-xhdpi/icon_public_group.png
Normal file
After Width: | Height: | Size: 751 B |
After Width: | Height: | Size: 1.4 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_private_group.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.6 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_public_group.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_private_group.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.1 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_public_group.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.8 KiB |
@ -202,5 +202,14 @@ var TopLevel = {
|
||||
"IBGLog": function() {},
|
||||
"getCardId": function() {},
|
||||
"readTag": function() {},
|
||||
"writeTag": function() {}
|
||||
"writeTag": function() {},
|
||||
"Error": function() {},
|
||||
"Linking": function() {},
|
||||
"reload": function() {},
|
||||
"stop": function() {},
|
||||
"toLocaleString": function() {},
|
||||
"openURL": function() {},
|
||||
"Number" : function () {},
|
||||
"toAscii" : function () {},
|
||||
"toNumber" : function () {}
|
||||
};
|
||||
|
23
ios/StatusIm/Images.xcassets/icon_private_group.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "con_group_chat.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "con_group_chat-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "con_group_chat-2.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_private_group.imageset/con_group_chat-1.png
vendored
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_private_group.imageset/con_group_chat-2.png
vendored
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_private_group.imageset/con_group_chat.png
vendored
Normal file
After Width: | Height: | Size: 793 B |
23
ios/StatusIm/Images.xcassets/icon_private_group_big.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_private_group_big.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_private_group_big-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_private_group_big-2.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_private_group_big.imageset/icon_private_group_big-1.png
vendored
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_private_group_big.imageset/icon_private_group_big-2.png
vendored
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_private_group_big.imageset/icon_private_group_big.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
23
ios/StatusIm/Images.xcassets/icon_public_group.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_public_group.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_public_group-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_public_group-2.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_public_group.imageset/icon_public_group-1.png
vendored
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_public_group.imageset/icon_public_group-2.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_public_group.imageset/icon_public_group.png
vendored
Normal file
After Width: | Height: | Size: 751 B |
23
ios/StatusIm/Images.xcassets/icon_public_group_big.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_public_group_big.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_public_group_big-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_public_group_big-2.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_public_group_big.imageset/icon_public_group_big-1.png
vendored
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_public_group_big.imageset/icon_public_group_big-2.png
vendored
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
ios/StatusIm/Images.xcassets/icon_public_group_big.imageset/icon_public_group_big.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
@ -23,7 +23,8 @@
|
||||
[status-im.accounts.screen :refer [accounts]]
|
||||
[status-im.transactions.screen :refer [confirm]]
|
||||
[status-im.chats-list.screen :refer [chats-list]]
|
||||
[status-im.new-group.screen :refer [new-group]]
|
||||
[status-im.new-group.screen-private :refer [new-group]]
|
||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
||||
[status-im.participants.views.add :refer [new-participants]]
|
||||
[status-im.participants.views.remove :refer [remove-participants]]
|
||||
[status-im.group-settings.screen :refer [group-settings]]
|
||||
@ -98,6 +99,7 @@
|
||||
:remove-participants remove-participants
|
||||
:chat-list main-tabs
|
||||
:new-group new-group
|
||||
:new-public-group new-public-group
|
||||
:group-settings group-settings
|
||||
:contact-list main-tabs
|
||||
:contact-list-search-results contacts-search-results
|
||||
|
@ -20,7 +20,7 @@
|
||||
:additional-height 0}
|
||||
:chat {:new-message {:border-top-color styles/color-transparent
|
||||
:border-top-width 0.5}}
|
||||
:discover {:subtitle {:color styles/color-gray2
|
||||
:discover {:subtitle {:color styles/color-gray2
|
||||
:font-size 14}
|
||||
:popular {:border-radius 1
|
||||
:margin-top 2
|
||||
@ -72,14 +72,17 @@
|
||||
;; Structure to be exported
|
||||
|
||||
(def platform-specific
|
||||
{:component-styles component-styles
|
||||
:fonts fonts
|
||||
:list-selection-fn show-dialog
|
||||
:tabs {:tab-shadows? true}
|
||||
:chats {:action-button? true
|
||||
:new-chat-in-toolbar? false}
|
||||
:contacts {:action-button? true
|
||||
:new-contact-in-toolbar? false
|
||||
:uppercase-subtitles? false
|
||||
:group-block-shadows? true}
|
||||
:discover {:uppercase-subtitles? false}})
|
||||
{:component-styles component-styles
|
||||
:fonts fonts
|
||||
:list-selection-fn show-dialog
|
||||
:tabs {:tab-shadows? true}
|
||||
:chats {:action-button? true
|
||||
:new-chat-in-toolbar? false}
|
||||
:contacts {:action-button? true
|
||||
:new-contact-in-toolbar? false
|
||||
:uppercase-subtitles? false
|
||||
:group-block-shadows? true}
|
||||
:discover {:uppercase-subtitles? false}
|
||||
:public-group-icon-container {:margin-top 4}
|
||||
:private-group-icon-container {:margin-top 6}
|
||||
:public-group-chat-hash-style {:top 10 :left 4}})
|
||||
|
@ -511,17 +511,18 @@
|
||||
(after (fn [_ _] (dispatch [:navigation-replace :chat-list])))
|
||||
(u/side-effect!
|
||||
(fn [{:keys [web3 current-chat-id chats current-public-key]} _]
|
||||
(let [{:keys [public-key private-key]} (chats current-chat-id)]
|
||||
(let [{:keys [public-key private-key public?]} (chats current-chat-id)]
|
||||
(protocol/stop-watching-group!
|
||||
{:web3 web3
|
||||
:group-id current-chat-id})
|
||||
(protocol/leave-group-chat!
|
||||
{:web3 web3
|
||||
:group-id current-chat-id
|
||||
:keypair {:public public-key
|
||||
:private private-key}
|
||||
:message {:from current-public-key
|
||||
:message-id (random/id)}}))
|
||||
(when-not public?
|
||||
(protocol/leave-group-chat!
|
||||
{:web3 web3
|
||||
:group-id current-chat-id
|
||||
:keypair {:public public-key
|
||||
:private private-key}
|
||||
:message {:from current-public-key
|
||||
:message-id (random/id)}})))
|
||||
(dispatch [:remove-chat current-chat-id]))))
|
||||
|
||||
(register-handler :remove-chat
|
||||
@ -563,12 +564,13 @@
|
||||
[{:keys [web3 current-public-key chats]}
|
||||
[_ {:keys [from chat-id message-id]}]]
|
||||
(when-not (console? chat-id)
|
||||
(let [{:keys [group-chat]} (chats chat-id)]
|
||||
(protocol/send-seen! {:web3 web3
|
||||
:message {:from current-public-key
|
||||
:to from
|
||||
:group-id (when group-chat chat-id)
|
||||
:message-id message-id}}))))
|
||||
(let [{:keys [group-chat public?]} (chats chat-id)]
|
||||
(when-not public?
|
||||
(protocol/send-seen! {:web3 web3
|
||||
:message {:from current-public-key
|
||||
:to from
|
||||
:group-id (when group-chat chat-id)
|
||||
:message-id message-id}})))))
|
||||
(register-handler :send-seen!
|
||||
[(after (fn [_ [_ {:keys [message-id]}]]
|
||||
(messages/update {:message-id message-id
|
||||
@ -579,7 +581,7 @@
|
||||
|
||||
(defn send-clock-value-request!
|
||||
[{:keys [web3 current-public-key]} [_ {:keys [message-id from]}]]
|
||||
(protocol/send-clock-value-request! {:web3 web3
|
||||
(protocol/send-clock-value-request! {:web3 web3
|
||||
:message {:from current-public-key
|
||||
:to from
|
||||
:message-id message-id}}))
|
||||
@ -605,9 +607,9 @@
|
||||
|
||||
(register-handler :send-clock-value!
|
||||
(u/side-effect!
|
||||
(fn [db [_ to message-id]]
|
||||
(let [{:keys [clock-value]} (messages/get-by-id message-id)]
|
||||
(send-clock-value! db to message-id clock-value)))))
|
||||
(fn [db [_ to message-id]]
|
||||
(let [{:keys [clock-value]} (messages/get-by-id message-id)]
|
||||
(send-clock-value! db to message-id clock-value)))))
|
||||
|
||||
(register-handler :set-web-view-url
|
||||
(fn [{:keys [current-chat-id] :as db} [_ url]]
|
||||
@ -663,7 +665,7 @@
|
||||
|
||||
(register-handler :update-message-overhead!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ chat-id network-status]]
|
||||
(if (= network-status :offline)
|
||||
(chats/inc-message-overhead chat-id)
|
||||
(chats/reset-message-overhead chat-id)))))
|
||||
(fn [_ [_ chat-id network-status]]
|
||||
(if (= network-status :offline)
|
||||
(chats/inc-message-overhead chat-id)
|
||||
(chats/reset-message-overhead chat-id)))))
|
||||
|
@ -25,23 +25,23 @@
|
||||
to-message handler-data content-type]}]
|
||||
(let [content (or request {:command (command :name)
|
||||
:params params})]
|
||||
{:message-id id
|
||||
:from identity
|
||||
:to chat-id
|
||||
:timestamp (time/now-ms)
|
||||
:content (assoc content :handler-data handler-data
|
||||
:type (name (:type command))
|
||||
:content-command (:name command))
|
||||
:content-type (or content-type
|
||||
(if request
|
||||
content-type-command-request
|
||||
content-type-command))
|
||||
:outgoing true
|
||||
:to-message to-message
|
||||
:type (:type command)
|
||||
:has-handler (:has-handler command)
|
||||
:clock-value (inc clock-value)
|
||||
:show? true}))
|
||||
{:message-id id
|
||||
:from identity
|
||||
:to chat-id
|
||||
:timestamp (time/now-ms)
|
||||
:content (assoc content :handler-data handler-data
|
||||
:type (name (:type command))
|
||||
:content-command (:name command))
|
||||
:content-type (or content-type
|
||||
(if request
|
||||
content-type-command-request
|
||||
content-type-command))
|
||||
:outgoing true
|
||||
:to-message to-message
|
||||
:type (:type command)
|
||||
:has-handler (:has-handler command)
|
||||
:clock-value (inc clock-value)
|
||||
:show? true}))
|
||||
|
||||
(register-handler :send-chat-message
|
||||
(u/side-effect!
|
||||
@ -173,7 +173,7 @@
|
||||
(register-handler ::prepare-message
|
||||
(u/side-effect!
|
||||
(fn [{:keys [network-status] :as db} [_ {:keys [chat-id identity message] :as params}]]
|
||||
(let [{:keys [group-chat]} (get-in db [:chats chat-id])
|
||||
(let [{:keys [group-chat public?]} (get-in db [:chats chat-id])
|
||||
clock-value (messages/get-last-clock-value chat-id)
|
||||
message' (cu/check-author-direction
|
||||
db chat-id
|
||||
@ -186,9 +186,13 @@
|
||||
:timestamp (time/now-ms)
|
||||
:clock-value (inc clock-value)
|
||||
:show? true})
|
||||
message'' (if group-chat
|
||||
(assoc message' :group-id chat-id :message-type :group-user-message)
|
||||
(assoc message' :to chat-id :message-type :user-message))
|
||||
message'' (cond-> message'
|
||||
(and group-chat public?)
|
||||
(assoc :group-id chat-id :message-type :public-group-user-message)
|
||||
(and group-chat (not public?))
|
||||
(assoc :group-id chat-id :message-type :group-user-message)
|
||||
(not group-chat)
|
||||
(assoc :to chat-id :message-type :user-message))
|
||||
params' (assoc params :message message'')]
|
||||
(dispatch [:update-message-overhead! chat-id network-status])
|
||||
(dispatch [:set-chat-ui-props :sending-disabled? false])
|
||||
@ -258,7 +262,7 @@
|
||||
|
||||
(register-handler ::send-message!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [web3 chats network-status]
|
||||
(fn [{:keys [web3 chats network-status current-account-id accounts]
|
||||
:as db} [_ {{:keys [message-type]
|
||||
:as message} :message
|
||||
chat-id :chat-id}]]
|
||||
@ -274,23 +278,33 @@
|
||||
payload)
|
||||
options {:web3 web3
|
||||
:message (assoc message' :payload payload)}]
|
||||
(if (= message-type :group-user-message)
|
||||
(cond
|
||||
(= message-type :group-user-message)
|
||||
(let [{:keys [public-key private-key]} (chats chat-id)]
|
||||
(protocol/send-group-message! (assoc options
|
||||
:group-id chat-id
|
||||
:keypair {:public public-key
|
||||
:private private-key})))
|
||||
|
||||
(= message-type :public-group-user-message)
|
||||
(protocol/send-public-group-message!
|
||||
(let [username (get-in accounts [current-account-id :name])]
|
||||
(assoc options :group-id chat-id
|
||||
:username username)))
|
||||
|
||||
:else
|
||||
(protocol/send-message! (assoc-in options
|
||||
[:message :to] (:to message)))))))))))
|
||||
|
||||
(register-handler ::send-command-protocol!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [web3 current-public-key chats network-status] :as db}
|
||||
[_ {:keys [chat-id command command-message]}]]
|
||||
(fn [{:keys [web3 current-public-key chats network-status
|
||||
current-account-id accounts] :as db}
|
||||
[_ {:keys [chat-id command]}]]
|
||||
(log/debug "sending command: " command)
|
||||
(when (cu/not-console? chat-id)
|
||||
(let [{:keys [public-key private-key]} (chats chat-id)
|
||||
{:keys [group-chat]} (get-in db [:chats chat-id])
|
||||
{:keys [group-chat public?]} (get-in db [:chats chat-id])
|
||||
|
||||
payload (-> command
|
||||
(select-keys [:content :content-type
|
||||
@ -303,10 +317,19 @@
|
||||
:message {:from current-public-key
|
||||
:message-id (:message-id command)
|
||||
:payload payload}}]
|
||||
(if group-chat
|
||||
(cond
|
||||
(and group-chat (not public?))
|
||||
(protocol/send-group-message! (assoc options
|
||||
:group-id chat-id
|
||||
:keypair {:public public-key
|
||||
:private private-key}))
|
||||
|
||||
(and group-chat public?)
|
||||
(protocol/send-public-group-message!
|
||||
(let [username (get-in accounts [current-account-id :name])]
|
||||
(assoc options :group-id chat-id
|
||||
:username username)))
|
||||
|
||||
:else
|
||||
(protocol/send-message! (assoc-in options
|
||||
[:message :to] chat-id))))))))
|
||||
|
@ -4,7 +4,8 @@
|
||||
color-blue
|
||||
selected-message-color
|
||||
text1-color
|
||||
text2-color]]
|
||||
text2-color
|
||||
color-gray]]
|
||||
[status-im.constants :refer [text-content-type
|
||||
content-type-command]]))
|
||||
|
||||
@ -125,6 +126,9 @@
|
||||
(when selected
|
||||
{:backgroundColor selected-message-color}))))
|
||||
|
||||
(def author
|
||||
{:color color-gray})
|
||||
|
||||
(def comand-request-view
|
||||
{:paddingRight 16})
|
||||
|
||||
|
@ -54,9 +54,10 @@
|
||||
:fontSize 16})
|
||||
|
||||
(def group-icon
|
||||
{:marginTop 4
|
||||
:width 14
|
||||
:height 9})
|
||||
{:margin-top 4
|
||||
:margin-bottom 2.7
|
||||
:width 14
|
||||
:height 9})
|
||||
|
||||
(def up-icon
|
||||
{:width 14
|
||||
|
@ -70,11 +70,11 @@
|
||||
:height 13}
|
||||
:handler #(dispatch [:show-group-settings])})
|
||||
|
||||
(defn group-chat-items [members]
|
||||
[(item-members members)
|
||||
item-search
|
||||
item-notifications
|
||||
item-settings])
|
||||
(defn group-chat-items [members public?]
|
||||
(into (if public? [] [(item-members members)])
|
||||
[item-search
|
||||
item-notifications
|
||||
item-settings]))
|
||||
|
||||
(defn user-chat-items [chat-id]
|
||||
[(item-user chat-id)
|
||||
@ -114,21 +114,22 @@
|
||||
subtitle])]]])
|
||||
|
||||
(defn actions-list-view []
|
||||
(let [{:keys [group-chat chat-id]}
|
||||
(subscribe [:chat-properties [:group-chat :chat-id]])
|
||||
(let [{:keys [group-chat chat-id public?]}
|
||||
(subscribe [:chat-properties [:group-chat :chat-id :public?]])
|
||||
members (subscribe [:current-chat-contacts])
|
||||
status-bar-height (get-in platform-specific [:component-styles :status-bar :default :height])]
|
||||
(when-let [actions (if @group-chat
|
||||
(group-chat-items @members)
|
||||
(user-chat-items @chat-id))]
|
||||
[view (merge
|
||||
(st/actions-wrapper status-bar-height)
|
||||
(get-in platform-specific [:component-styles :actions-list-view]))
|
||||
[view st/actions-separator]
|
||||
[view st/actions-view
|
||||
(for [action actions]
|
||||
(if action
|
||||
^{:key action} [action-view action]))]])))
|
||||
(fn []
|
||||
(when-let [actions (if @group-chat
|
||||
(group-chat-items @members @public?)
|
||||
(user-chat-items @chat-id))]
|
||||
[view (merge
|
||||
(st/actions-wrapper status-bar-height)
|
||||
(get-in platform-specific [:component-styles :actions-list-view]))
|
||||
[view st/actions-separator]
|
||||
[view st/actions-view
|
||||
(for [action actions]
|
||||
(if action
|
||||
^{:key action} [action-view action]))]]))))
|
||||
|
||||
(defn actions-view []
|
||||
[overlay {:on-click-outside #(dispatch [:set-chat-ui-props :show-actions? false])}
|
||||
|
@ -46,10 +46,10 @@
|
||||
members (subscribe [:current-chat-contacts])]
|
||||
(fn [{:keys [messages-count content datemark]}]
|
||||
(let [{:keys [status]} (if @group-chat
|
||||
{:photo-path nil
|
||||
:status nil
|
||||
:last-online 0}
|
||||
(first @members))]
|
||||
{:photo-path nil
|
||||
:status nil
|
||||
:last-online 0}
|
||||
(first @members))]
|
||||
[view st/status-container
|
||||
[chat-icon-message-status @chat-id @group-chat @name @color false]
|
||||
[text {:style st/status-from
|
||||
@ -143,11 +143,10 @@
|
||||
:current-chat-id current-chat-id}]]))
|
||||
|
||||
(defn message-view
|
||||
[message content]
|
||||
[{:keys [username same-author index] :as message} content]
|
||||
[view (st/message-view message)
|
||||
#_(when incoming-group
|
||||
[text {:style message-author-text}
|
||||
"Justas"])
|
||||
(when (and username (or (= 1 index) (not same-author)))
|
||||
[text {:style st/author} username])
|
||||
content])
|
||||
|
||||
(defmulti message-content (fn [_ message _]
|
||||
@ -202,7 +201,7 @@
|
||||
(defn text-message
|
||||
[{:keys [content] :as message}]
|
||||
[message-view message
|
||||
(let [parsed-text (parse-text content)
|
||||
(let [parsed-text (parse-text content)
|
||||
simple-text? (= (count parsed-text) 2)]
|
||||
(if simple-text?
|
||||
[autolink {:style (st/text-message message)
|
||||
@ -374,10 +373,10 @@
|
||||
children)])}))
|
||||
(into [view] children)))
|
||||
|
||||
(defn chat-message [{:keys [outgoing message-id chat-id user-statuses from content] :as message}]
|
||||
(let [my-identity (subscribe [:get :current-public-key])
|
||||
status (subscribe [:get-in [:message-data :user-statuses message-id my-identity]])
|
||||
preview (subscribe [:get-in [:message-data :preview message-id]])]
|
||||
(defn chat-message [{:keys [outgoing message-id chat-id user-statuses from] :as message}]
|
||||
(let [my-identity (subscribe [:get :current-public-key])
|
||||
status (subscribe [:get-in [:message-data :user-statuses message-id my-identity]])
|
||||
preview (subscribe [:get-in [:message-data :preview message-id]])]
|
||||
(r/create-class
|
||||
{:component-will-mount
|
||||
(fn []
|
||||
|
@ -49,22 +49,31 @@
|
||||
:synced (label :t/sync-synced)
|
||||
online-text)}])
|
||||
|
||||
(defn group-last-activity [{:keys [contacts sync-state]}]
|
||||
(defn group-last-activity [{:keys [contacts sync-state public?]}]
|
||||
(if (or (= sync-state :in-progress)
|
||||
(= sync-state :synced))
|
||||
[last-activity {:sync-state sync-state}]
|
||||
[view {:flex-direction :row}
|
||||
[icon :group st/group-icon]
|
||||
[text {:style st/members
|
||||
:font :medium}
|
||||
(let [cnt (inc (count contacts))]
|
||||
(label-pluralize cnt :t/members-active))]]))
|
||||
(if public?
|
||||
[view {:flex-direction :row}
|
||||
[text {:font :default
|
||||
:style (get-in platform-specific [:component-styles :toolbar-last-activity])}
|
||||
(label :t/public-group-status)]]
|
||||
[view {:flex-direction :row}
|
||||
[icon :group st/group-icon]
|
||||
[text {:style st/members
|
||||
:font :medium}
|
||||
(if public?
|
||||
(label :t/public-group-status)
|
||||
(let [cnt (inc (count contacts))]
|
||||
(label-pluralize cnt :t/members-active)))]])))
|
||||
|
||||
(defn toolbar-content-view []
|
||||
(let [{:keys [group-chat
|
||||
name
|
||||
contacts
|
||||
chat-id]} (subscribe [:chat-properties [:group-chat :name :contacts :chat-id]])
|
||||
chat-id
|
||||
public?]}
|
||||
(subscribe [:chat-properties [:group-chat :name :contacts :chat-id :public?]])
|
||||
show-actions? (subscribe [:chat-ui-props :show-actions?])
|
||||
accounts (subscribe [:get :accounts])
|
||||
contact (subscribe [:get-in [:contacts @chat-id]])
|
||||
@ -72,15 +81,19 @@
|
||||
(fn []
|
||||
[view (st/chat-name-view (or (empty? @accounts)
|
||||
@show-actions?))
|
||||
[text {:style st/chat-name-text
|
||||
:number-of-lines 1
|
||||
:font :toolbar-title}
|
||||
(if (str/blank? @name)
|
||||
(generate-gfy)
|
||||
(or (get-contact-translated @chat-id :name @name)
|
||||
(label :t/chat-name)))]
|
||||
(let [chat-name (if (str/blank? @name)
|
||||
(generate-gfy)
|
||||
(or (get-contact-translated @chat-id :name @name)
|
||||
(label :t/chat-name)))]
|
||||
[text {:style st/chat-name-text
|
||||
:number-of-lines 1
|
||||
:font :toolbar-title}
|
||||
(if @public?
|
||||
(str "#" chat-name)
|
||||
chat-name)])
|
||||
(if @group-chat
|
||||
[group-last-activity {:contacts @contacts
|
||||
:public? @public?
|
||||
:sync-state @sync-state}]
|
||||
[last-activity {:online-text (online-text @contact @chat-id)
|
||||
:sync-state @sync-state}])])))
|
||||
|
@ -6,6 +6,7 @@
|
||||
view
|
||||
animated-view
|
||||
text
|
||||
icon
|
||||
image
|
||||
touchable-highlight]]
|
||||
[status-im.components.action-button :refer [action-button
|
||||
@ -55,8 +56,12 @@
|
||||
{:title (label :t/new-group-chat)
|
||||
:buttonColor :#1abc9c
|
||||
:onPress #(dispatch [:navigate-to :new-group])}
|
||||
[ion-icon {:name :md-person
|
||||
:style st/person-stalker-icon}]]])
|
||||
[icon :private_group_big st/group-icon]]
|
||||
[action-button-item
|
||||
{:title (label :t/new-public-group-chat)
|
||||
:buttonColor :#1abc9c
|
||||
:onPress #(dispatch [:navigate-to :new-public-group])}
|
||||
[icon :public_group_big st/group-icon]]])
|
||||
|
||||
(defn chat-shadow-item []
|
||||
[view {:height 3}
|
||||
|
@ -32,9 +32,9 @@
|
||||
:border-bottom-color color-separator})
|
||||
|
||||
(def chat-container
|
||||
{:flex-direction :row
|
||||
:background-color color-white
|
||||
:height 94})
|
||||
{:flex-direction :row
|
||||
:background-color color-white
|
||||
:height 94})
|
||||
|
||||
(def chat-icon-container
|
||||
{:margin-top -2
|
||||
@ -44,24 +44,41 @@
|
||||
:height 48})
|
||||
|
||||
(def item-container
|
||||
{:flex-direction :column
|
||||
:margin-left 30
|
||||
:padding-top 16
|
||||
:padding-right 16
|
||||
:flex 1})
|
||||
{:flex-direction :column
|
||||
:margin-left 30
|
||||
:padding-top 16
|
||||
:padding-right 16
|
||||
:flex 1})
|
||||
|
||||
(def name-view
|
||||
{:flex-direction :row})
|
||||
|
||||
(def name-text
|
||||
{:color text1-color
|
||||
:font-size 14})
|
||||
{:color text1-color
|
||||
:font-size 14})
|
||||
|
||||
(def group-icon
|
||||
{:margin-top 5
|
||||
:margin-left 8
|
||||
:width 14
|
||||
:height 9})
|
||||
(def private-group-icon-container
|
||||
{:width 16
|
||||
:height 9
|
||||
:padding-top -4
|
||||
:margin-top (get-in p/platform-specific [:private-group-icon-container :margin-top])
|
||||
:margin-right 6})
|
||||
|
||||
(def private-group-icon
|
||||
{:width 16
|
||||
:height 16})
|
||||
|
||||
(def public-group-icon-container
|
||||
{:width 16
|
||||
:height 12
|
||||
:padding-top -2
|
||||
:margin-top (get-in p/platform-specific [:public-group-icon-container :margin-top])
|
||||
:margin-right 6})
|
||||
|
||||
(def public-group-icon
|
||||
{:width 16
|
||||
:height 16
|
||||
:margin-bottom -20})
|
||||
|
||||
(def memebers-text
|
||||
{:marginTop 2
|
||||
@ -124,7 +141,7 @@
|
||||
:height 22
|
||||
:color color-white})
|
||||
|
||||
(def person-stalker-icon
|
||||
{:fontSize 20
|
||||
:height 22
|
||||
:color color-white})
|
||||
(def group-icon
|
||||
{:height 22
|
||||
:width 22
|
||||
:tint-color :white})
|
||||
|
@ -77,24 +77,34 @@
|
||||
unviewed-messages]]))
|
||||
|
||||
(defn chat-list-item-inner-view [{:keys [chat-id name color last-message
|
||||
online group-chat contacts] :as chat}]
|
||||
online group-chat contacts public?]
|
||||
:as chat}]
|
||||
(let [last-message (or (first (sort-by :clock-value > (:messages chat)))
|
||||
last-message)
|
||||
name (or (get-contact-translated chat-id :name name)
|
||||
(generate-gfy))]
|
||||
(generate-gfy))
|
||||
private-group? (and group-chat (not public?))
|
||||
public-group? (and group-chat public?)]
|
||||
[view st/chat-container
|
||||
[view st/chat-icon-container
|
||||
[chat-icon-view-chat-list chat-id group-chat name color online]]
|
||||
[view st/item-container
|
||||
[view st/name-view
|
||||
[text {:style st/name-text
|
||||
:font :medium}
|
||||
(if (str/blank? name)
|
||||
(generate-gfy)
|
||||
(truncate-str name 30))]
|
||||
(when group-chat
|
||||
[icon :group st/group-icon])
|
||||
(when group-chat
|
||||
(when public-group?
|
||||
[view st/public-group-icon-container
|
||||
[icon :public_group st/public-group-icon]])
|
||||
(when private-group?
|
||||
[view st/private-group-icon-container
|
||||
[icon :private_group st/private-group-icon]])
|
||||
(let [chat-name (if (str/blank? name)
|
||||
(generate-gfy)
|
||||
(truncate-str name 30))]
|
||||
[text {:style st/name-text
|
||||
:font :medium}
|
||||
(if public-group?
|
||||
(str "#" chat-name)
|
||||
chat-name)])
|
||||
#_(when private-group?
|
||||
[text {:style st/memebers-text}
|
||||
(label-pluralize (inc (count contacts)) :t/members)])]
|
||||
[message-content-text last-message]]
|
||||
|
@ -34,11 +34,12 @@
|
||||
:on-focus #()
|
||||
:on-blur #()
|
||||
:on-change-text #()
|
||||
:on-change #()})
|
||||
:on-change #()
|
||||
:auto-capitalize :sentences})
|
||||
|
||||
(defn field-animation [{:keys [top to-top font-size to-font-size
|
||||
line-width to-line-width]}]
|
||||
(let [duration (:label-animation-duration config)
|
||||
(let [duration (:label-animation-duration config)
|
||||
animation (anim/parallel [(anim/timing top {:toValue to-top
|
||||
:duration duration})
|
||||
(anim/timing font-size {:toValue to-font-size
|
||||
@ -101,10 +102,14 @@
|
||||
label-font-size
|
||||
line-width
|
||||
current-value
|
||||
max-line-width]} (r/state component)
|
||||
max-line-width
|
||||
valid-value
|
||||
temp-value
|
||||
max-length]} (r/state component)
|
||||
{:keys [wrapper-style input-style label-hidden? line-color focus-line-color secure-text-entry
|
||||
label-color error-color error label value on-focus on-blur
|
||||
on-change-text on-change on-end-editing editable placeholder]} (merge default-props (r/props component))
|
||||
label-color error-color error label value on-focus on-blur validator auto-focus
|
||||
on-change-text on-change on-end-editing editable placeholder auto-capitalize]}
|
||||
(merge default-props (r/props component))
|
||||
line-color (if error error-color line-color)
|
||||
focus-line-color (if error error-color focus-line-color)
|
||||
label-color (if (and error (not float-label?)) error-color label-color)
|
||||
@ -118,6 +123,7 @@
|
||||
:placeholder (or placeholder "")
|
||||
:editable editable
|
||||
:secure-text-entry secure-text-entry
|
||||
:auto-capitalize auto-capitalize
|
||||
:on-focus #(on-input-focus {:component component
|
||||
:animation {:top label-top
|
||||
:to-top (:label-top config)
|
||||
@ -137,21 +143,34 @@
|
||||
:onBlur on-blur})
|
||||
:on-change-text (fn [text]
|
||||
(r/set-state component {:current-value text})
|
||||
(on-change-text text))
|
||||
(if (or (not validator) (validator text))
|
||||
(do
|
||||
(r/set-state component {:valid-value text
|
||||
:temp-value nil})
|
||||
(on-change-text text))
|
||||
(r/set-state component {:temp-value valid-value
|
||||
:max-length (count valid-value)})))
|
||||
:on-change #(on-change %)
|
||||
:default-value value
|
||||
:value temp-value
|
||||
:max-length max-length
|
||||
:on-submit-editing #(.blur @input-ref)
|
||||
:on-end-editing (when on-end-editing
|
||||
on-end-editing)}]
|
||||
:on-end-editing (when on-end-editing on-end-editing)
|
||||
:auto-focus (true? auto-focus)}]
|
||||
[view {:style (st/underline-container line-color)
|
||||
:onLayout #(r/set-state component {:max-line-width (get-width %)})}
|
||||
[animated-view {:style (st/underline focus-line-color line-width)}]]
|
||||
[text {:style (st/error-text error-color)} error]]))
|
||||
|
||||
(defn text-field [_ _]
|
||||
(let [component-data {:get-initial-state get-initial-state
|
||||
:component-will-mount component-will-mount
|
||||
:display-name "text-field"
|
||||
:reagent-render reagent-render}]
|
||||
(let [component-data {:get-initial-state get-initial-state
|
||||
:component-will-mount component-will-mount
|
||||
:display-name "text-field"
|
||||
:reagent-render reagent-render
|
||||
:component-did-update (fn [comp]
|
||||
(let [{:keys [temp-value]} (r/state comp)]
|
||||
(when temp-value
|
||||
(r/set-state comp {:temp-value nil
|
||||
:max-length nil}))))}]
|
||||
;(log/debug "Creating text-field component: " data)
|
||||
(r/create-class component-data)))
|
||||
|
@ -132,6 +132,10 @@
|
||||
:top 16
|
||||
:left 13})
|
||||
|
||||
(def group-icon
|
||||
(assoc option-inner-image
|
||||
:tint-color color-gray))
|
||||
|
||||
(def spacing-top
|
||||
{:background-color color-white
|
||||
:height 8})
|
||||
|
@ -21,24 +21,35 @@
|
||||
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]))
|
||||
|
||||
(defn new-group-chat-view []
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:navigate-to :new-group])}
|
||||
[view st/contact-container
|
||||
[view st/option-inner-container
|
||||
[view st/option-inner
|
||||
[image {:source {:uri :icon_menu_group}
|
||||
:style st/option-inner-image}]]
|
||||
[view st/info-container
|
||||
[text {:style st/name-text}
|
||||
(label :t/new-group-chat)]]]]])
|
||||
[view
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:navigate-to :new-group])}
|
||||
[view st/contact-container
|
||||
[view st/option-inner-container
|
||||
[view st/option-inner
|
||||
[image {:source {:uri :icon_private_group_big}
|
||||
:style st/group-icon}]]
|
||||
[view st/info-container
|
||||
[text {:style st/name-text}
|
||||
(label :t/new-group-chat)]]]]]
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:navigate-to :new-public-group])}
|
||||
[view st/contact-container
|
||||
[view st/option-inner-container
|
||||
[view st/option-inner
|
||||
[image {:source {:uri :icon_public_group_big}
|
||||
:style st/group-icon}]]
|
||||
[view st/info-container
|
||||
[text {:style st/name-text}
|
||||
(label :t/new-public-group-chat)]]]]]])
|
||||
|
||||
(defn render-row [chat-modal click-handler action params]
|
||||
(fn [row _ _]
|
||||
(list-item
|
||||
[contact-view {:contact row
|
||||
:letter? chat-modal
|
||||
:on-click (if click-handler
|
||||
#(click-handler row action params))}])))
|
||||
[contact-view {:contact row
|
||||
:letter? chat-modal
|
||||
:on-click (when click-handler
|
||||
#(click-handler row action params))}])))
|
||||
|
||||
(defn contact-list-entry [{:keys [click-handler icon icon-style label]}]
|
||||
[touchable-highlight
|
||||
|
@ -29,12 +29,19 @@
|
||||
(defn get-active-group-chats
|
||||
[]
|
||||
(map
|
||||
(fn [{:keys [chat-id public-key private-key]}]
|
||||
{:chat-id chat-id
|
||||
:keypair {:private private-key
|
||||
:public public-key}})
|
||||
(fn [{:keys [chat-id public-key private-key public?]}]
|
||||
(let [group {:group-id chat-id
|
||||
:public? public?}]
|
||||
(if (and public-key private-key)
|
||||
(assoc group :keypair {:private private-key
|
||||
:public public-key})
|
||||
group)))
|
||||
(realm/realm-collection->list (groups true))))
|
||||
|
||||
(defn- get-by-id-obj
|
||||
[chat-id]
|
||||
(realm/get-one-by-field @realm/account-realm :chat :chat-id chat-id))
|
||||
|
||||
(defn get-by-id
|
||||
[chat-id]
|
||||
(-> @realm/account-realm
|
||||
@ -56,12 +63,12 @@
|
||||
|
||||
(defn set-inactive
|
||||
[chat-id]
|
||||
(when-let [chat (get-by-id chat-id)]
|
||||
(when-let [chat (get-by-id-obj chat-id)]
|
||||
(realm/write @realm/account-realm
|
||||
(fn []
|
||||
(doto chat
|
||||
(aset "is-active" false)
|
||||
(aset "removed-at" timestamp))))))
|
||||
(aset "removed-at" (timestamp)))))))
|
||||
|
||||
(defn get-contacts
|
||||
[chat-id]
|
||||
@ -72,8 +79,8 @@
|
||||
(defn has-contact?
|
||||
[chat-id identity]
|
||||
(let [contacts (get-contacts chat-id)
|
||||
contact (.find contacts (fn [object _ _]
|
||||
(= identity (aget object "identity"))))]
|
||||
contact (.find contacts (fn [object _ _]
|
||||
(= identity (aget object "identity"))))]
|
||||
(if contact true false)))
|
||||
|
||||
(defn- save-contacts
|
||||
@ -97,9 +104,9 @@
|
||||
(defn- delete-contacts
|
||||
[identities contacts]
|
||||
(doseq [contact-identity identities]
|
||||
(when-let [contact (.find contacts (fn [object _ _]
|
||||
(= contact-identity (aget object "identity"))))]
|
||||
(realm/delete @realm/account-realm contact))))
|
||||
(when-let [contact (.find contacts (fn [object _ _]
|
||||
(= contact-identity (aget object "identity"))))]
|
||||
(realm/delete @realm/account-realm contact))))
|
||||
|
||||
(defn remove-contacts
|
||||
[chat-id identities]
|
||||
|
@ -1,7 +1,9 @@
|
||||
(ns status-im.data-store.realm.schemas.account.core
|
||||
(:require [status-im.data-store.realm.schemas.account.v1.core :as v1]
|
||||
[status-im.data-store.realm.schemas.account.v2.core :as v2]
|
||||
[status-im.data-store.realm.schemas.account.v3.core :as v3]))
|
||||
[status-im.data-store.realm.schemas.account.v3.core :as v3]
|
||||
[status-im.data-store.realm.schemas.account.v4.core :as v4]
|
||||
))
|
||||
|
||||
; put schemas ordered by version
|
||||
(def schemas [{:schema v1/schema
|
||||
@ -12,4 +14,7 @@
|
||||
:migration v2/migration}
|
||||
{:schema v3/schema
|
||||
:schemaVersion 3
|
||||
:migration v3/migration}])
|
||||
:migration v3/migration}
|
||||
{:schema v4/schema
|
||||
:schemaVersion 4
|
||||
:migration v4/migration}])
|
||||
|
42
src/status_im/data_store/realm/schemas/account/v4/chat.cljs
Normal file
@ -0,0 +1,42 @@
|
||||
(ns status-im.data-store.realm.schemas.account.v4.chat
|
||||
(:require [taoensso.timbre :as log]
|
||||
[status-im.components.styles :refer [default-chat-color]]))
|
||||
|
||||
(def schema {:name :chat
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id :string
|
||||
:name :string
|
||||
:color {:type :string
|
||||
:default default-chat-color}
|
||||
:group-chat {:type :bool
|
||||
:indexed true}
|
||||
:group-admin {:type :string
|
||||
:optional true}
|
||||
:is-active :bool
|
||||
:timestamp :int
|
||||
:contacts {:type :list
|
||||
:objectType :chat-contact}
|
||||
:removed-at {:type :int
|
||||
:optional true}
|
||||
:removed-from-at {:type :int
|
||||
:optional true}
|
||||
:added-to-at {:type :int
|
||||
:optional true}
|
||||
:updated-at {:type :int
|
||||
:optional true}
|
||||
:last-message-id :string
|
||||
:message-overhead {:type :int
|
||||
:default 0}
|
||||
:public-key {:type :string
|
||||
:optional true}
|
||||
:private-key {:type :string
|
||||
:optional true}
|
||||
:contact-info {:type :string
|
||||
:optional true}
|
||||
:debug? {:type :bool
|
||||
:default false}
|
||||
:public? {:type :bool
|
||||
:default false}}})
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating chat schema v4"))
|
32
src/status_im/data_store/realm/schemas/account/v4/core.cljs
Normal file
@ -0,0 +1,32 @@
|
||||
(ns status-im.data-store.realm.schemas.account.v4.core
|
||||
(:require [status-im.data-store.realm.schemas.account.v4.chat :as chat]
|
||||
[status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact]
|
||||
[status-im.data-store.realm.schemas.account.v1.command :as command]
|
||||
[status-im.data-store.realm.schemas.account.v3.contact :as contact]
|
||||
[status-im.data-store.realm.schemas.account.v1.discover :as discover]
|
||||
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
|
||||
[status-im.data-store.realm.schemas.account.v4.message :as message]
|
||||
[status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message]
|
||||
[status-im.data-store.realm.schemas.account.v1.processed-message :as processed-message]
|
||||
[status-im.data-store.realm.schemas.account.v1.request :as request]
|
||||
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
|
||||
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def schema [chat/schema
|
||||
chat-contact/schema
|
||||
command/schema
|
||||
contact/schema
|
||||
discover/schema
|
||||
kv-store/schema
|
||||
message/schema
|
||||
pending-message/schema
|
||||
processed-message/schema
|
||||
request/schema
|
||||
tag/schema
|
||||
user-status/schema])
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating v4 account database: " old-realm new-realm)
|
||||
(chat/migration old-realm new-realm)
|
||||
(contact/migration old-realm new-realm))
|
@ -0,0 +1,38 @@
|
||||
(ns status-im.data-store.realm.schemas.account.v4.message
|
||||
(:require [taoensso.timbre :as log]))
|
||||
|
||||
(def schema {:name :message
|
||||
:primaryKey :message-id
|
||||
:properties {:message-id :string
|
||||
:from :string
|
||||
:to {:type :string
|
||||
:optional true}
|
||||
:group-id {:type :string
|
||||
:optional true}
|
||||
:content :string ;; TODO make it ArrayBuffer
|
||||
:content-type :string
|
||||
:username {:type :string
|
||||
:optional true}
|
||||
:timestamp :int
|
||||
:chat-id {:type :string
|
||||
:indexed true}
|
||||
:outgoing :bool
|
||||
:retry-count {:type :int
|
||||
:default 0}
|
||||
:same-author :bool
|
||||
:same-direction :bool
|
||||
:preview {:type :string
|
||||
:optional true}
|
||||
:message-type {:type :string
|
||||
:optional true}
|
||||
:message-status {:type :string
|
||||
:optional true}
|
||||
:user-statuses {:type :list
|
||||
:objectType "user-status"}
|
||||
:clock-value {:type :int
|
||||
:default 0}
|
||||
:show? {:type :bool
|
||||
:default true}}})
|
||||
|
||||
(defn migration [_ _]
|
||||
(log/debug "migrating message schema"))
|
@ -160,11 +160,12 @@
|
||||
(label :t/add-members)]]]
|
||||
[chat-members]]))
|
||||
|
||||
(defn group-settings []
|
||||
(defview group-settings []
|
||||
[public? [:chat :public?]]
|
||||
[view st/group-settings
|
||||
[new-group-toolbar]
|
||||
[scroll-view st/body
|
||||
[chat-name]
|
||||
(when-not public? [chat-name])
|
||||
[members]
|
||||
[text {:style st/settings-text}
|
||||
(label :t/settings)]
|
||||
|
@ -22,7 +22,8 @@
|
||||
[status-im.accounts.screen :refer [accounts]]
|
||||
[status-im.transactions.screen :refer [confirm]]
|
||||
[status-im.chats-list.screen :refer [chats-list]]
|
||||
[status-im.new-group.screen :refer [new-group]]
|
||||
[status-im.new-group.screen-private :refer [new-group]]
|
||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
||||
[status-im.participants.views.add :refer [new-participants]]
|
||||
[status-im.participants.views.remove :refer [remove-participants]]
|
||||
[status-im.group-settings.screen :refer [group-settings]]
|
||||
@ -86,6 +87,7 @@
|
||||
:remove-participants remove-participants
|
||||
:chat-list main-tabs
|
||||
:new-group new-group
|
||||
:new-public-group new-public-group
|
||||
:group-settings group-settings
|
||||
:contact-list main-tabs
|
||||
:contact-list-search-results contacts-search-results
|
||||
|
@ -23,7 +23,7 @@
|
||||
:border-bottom-width 0.5}
|
||||
:chat {:new-message {:border-top-color styles/color-gray3
|
||||
:border-top-width 0.5}}
|
||||
:discover {:subtitle {:color styles/color-steel
|
||||
:discover {:subtitle {:color styles/color-steel
|
||||
:font-size 13
|
||||
:letter-spacing 1}
|
||||
:popular {:border-radius 3
|
||||
@ -79,15 +79,18 @@
|
||||
;; Structure to be exported
|
||||
|
||||
(def platform-specific
|
||||
{:component-styles component-styles
|
||||
:fonts fonts
|
||||
:list-selection-fn show-action-sheet
|
||||
:tabs {:tab-shadows? false}
|
||||
:chats {:action-button? false
|
||||
:new-chat-in-toolbar? true}
|
||||
:contacts {:action-button? false
|
||||
:new-contact-in-toolbar? true
|
||||
:uppercase-subtitles? true
|
||||
:group-block-shadows? false}
|
||||
:discover {:uppercase-subtitles? true}})
|
||||
{:component-styles component-styles
|
||||
:fonts fonts
|
||||
:list-selection-fn show-action-sheet
|
||||
:tabs {:tab-shadows? false}
|
||||
:chats {:action-button? false
|
||||
:new-chat-in-toolbar? true}
|
||||
:contacts {:action-button? false
|
||||
:new-contact-in-toolbar? true
|
||||
:uppercase-subtitles? true
|
||||
:group-block-shadows? false}
|
||||
:discover {:uppercase-subtitles? true}
|
||||
:public-group-icon-container {:margin-top 2}
|
||||
:private-group-icon-container {:margin-top 2}
|
||||
:public-group-chat-hash-style {:top 6 :left 3}})
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
||||
[clojure.string :as s]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.random :as random]
|
||||
[taoensso.timbre :refer-macros [debug]]))
|
||||
[taoensso.timbre :refer-macros [debug]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.navigation.handlers :as nav]))
|
||||
|
||||
(defn deselect-contact
|
||||
[db [_ id]]
|
||||
@ -44,7 +46,7 @@
|
||||
:group-chat true
|
||||
:group-admin current-public-key
|
||||
:is-active true
|
||||
:timestamp (.getTime (js/Date.))
|
||||
:timestamp (random/timestamp)
|
||||
:contacts contacts})))
|
||||
|
||||
(defn add-chat
|
||||
@ -91,6 +93,42 @@
|
||||
((after show-chat!))
|
||||
((after start-listen-group!))))
|
||||
|
||||
(register-handler :create-new-public-group
|
||||
(after (fn [_ [_ topic]]
|
||||
(dispatch [:navigation-replace :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]}
|
||||
@ -122,3 +160,7 @@
|
||||
:identity current-public-key
|
||||
:keypair keypair
|
||||
:callback #(dispatch [:incoming-message %1 %2])})))))))
|
||||
|
||||
(defmethod nav/preload-data! :new-public-group
|
||||
[db]
|
||||
(dissoc db :public-group/topic))
|
||||
|
@ -1,4 +1,4 @@
|
||||
(ns status-im.new-group.screen
|
||||
(ns status-im.new-group.screen-private
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.resources :as res]
|
65
src/status_im/new_group/screen_public.cljs
Normal file
@ -0,0 +1,65 @@
|
||||
(ns status-im.new-group.screen-public
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.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 [color-blue
|
||||
separator-color]]
|
||||
[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.views.contact :refer [new-group-contact]]
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.new-group.validations :as v]
|
||||
[status-im.i18n :refer [label]]
|
||||
[cljs.spec :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 res/v ;; {:uri "icon_search"}
|
||||
:style (st/toolbar-icon create-btn-enabled?)}
|
||||
: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 separator-color
|
||||
: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/new-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]]])
|
@ -2,7 +2,8 @@
|
||||
(:require [status-im.components.styles :refer [color-white
|
||||
color-blue
|
||||
text1-color
|
||||
text2-color]]))
|
||||
text2-color]]
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn toolbar-icon [enabled?]
|
||||
{:width 20
|
||||
@ -18,8 +19,20 @@
|
||||
{:margin-left 16})
|
||||
|
||||
(def group-chat-name-input
|
||||
{:font-size 14
|
||||
:color text1-color})
|
||||
{:font-size 14
|
||||
:color text1-color})
|
||||
|
||||
(def group-chat-topic-input
|
||||
{:font-size 14
|
||||
:color text1-color
|
||||
:padding-left 13})
|
||||
|
||||
(def topic-hash
|
||||
(merge group-chat-name-input
|
||||
{:width 10
|
||||
:height 16
|
||||
:position :absolute}
|
||||
(get-in platform-specific [:public-group-chat-hash-style])))
|
||||
|
||||
(def group-chat-name-wrapper
|
||||
{:padding-top 0})
|
||||
@ -52,10 +65,10 @@
|
||||
{:background-color :white})
|
||||
|
||||
(def contact-container
|
||||
{:flex-direction :row
|
||||
{:flex-direction :row
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:height 56})
|
||||
:align-items :center
|
||||
:height 56})
|
||||
|
||||
(def contact-item-checkbox
|
||||
{:outer-size 20
|
||||
|
@ -15,3 +15,7 @@
|
||||
|
||||
(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\-]+")))
|
||||
|
@ -8,6 +8,7 @@
|
||||
[status-im.protocol.web3.utils :as u]
|
||||
[status-im.protocol.chat :as chat]
|
||||
[status-im.protocol.group :as group]
|
||||
[status-im.protocol.web3.public-group :as public-group]
|
||||
[status-im.protocol.listeners :as l]
|
||||
[status-im.protocol.encryption :as e]
|
||||
[status-im.protocol.discoveries :as discoveries]
|
||||
@ -25,6 +26,7 @@
|
||||
(def start-watching-group! group/start-watching-group!)
|
||||
(def stop-watching-group! group/stop-watching-group!)
|
||||
(def send-group-message! group/send!)
|
||||
(def send-public-group-message! group/send-to-public-group!)
|
||||
(def invite-to-group! group/invite!)
|
||||
(def update-group! group/update-group!)
|
||||
(def remove-from-group! group/remove-identity!)
|
||||
@ -51,7 +53,11 @@
|
||||
(s/def ::rpc-url string?)
|
||||
(s/def ::identity string?)
|
||||
(s/def :message/chat-id string?)
|
||||
(s/def ::group (s/keys :req-un [:message/chat-id :message/keypair]))
|
||||
(s/def ::public? (s/and boolean? true?))
|
||||
(s/def ::group-id :message/chat-id)
|
||||
(s/def ::group (s/or
|
||||
:group (s/keys :req-un [::group-id :message/keypair])
|
||||
:public-group (s/keys :req-un [::group-id ::public?])))
|
||||
(s/def ::groups (s/* ::group))
|
||||
(s/def ::callback fn?)
|
||||
(s/def ::contact (s/keys :req-un [::identity :message/keypair]))
|
||||
@ -76,20 +82,18 @@
|
||||
(d/reset-all-pending-messages!)
|
||||
(let [web3 (u/make-web3 rpc-url)
|
||||
listener-options {:web3 web3
|
||||
:identity identity}]
|
||||
:identity identity
|
||||
:callback callback}]
|
||||
;; start listening to groups
|
||||
(doseq [{:keys [chat-id keypair]} groups]
|
||||
(f/add-filter!
|
||||
web3
|
||||
{:topics [chat-id]}
|
||||
(l/message-listener (assoc listener-options :callback callback
|
||||
:keypair keypair))))
|
||||
(doseq [group groups]
|
||||
(let [options (merge listener-options group)]
|
||||
(group/start-watching-group! options)))
|
||||
;; start listening to user's inbox
|
||||
(f/add-filter!
|
||||
web3
|
||||
{:to identity
|
||||
:topics [f/status-topic]}
|
||||
(l/message-listener (assoc listener-options :callback callback)))
|
||||
(l/message-listener listener-options))
|
||||
;; start listening to profiles
|
||||
(doseq [{:keys [identity keypair]} contacts]
|
||||
(watch-user! {:web3 web3
|
||||
@ -98,10 +102,10 @@
|
||||
:callback callback}))
|
||||
(d/set-pending-mesage-callback! callback)
|
||||
(let [online-message #(discoveries/send-online!
|
||||
{:web3 web3
|
||||
:message {:from identity
|
||||
:message-id (random/id)
|
||||
:keypair profile-keypair}})]
|
||||
{:web3 web3
|
||||
:message {:from identity
|
||||
:message-id (random/id)
|
||||
:keypair profile-keypair}})]
|
||||
(d/run-delivery-loop!
|
||||
web3
|
||||
(assoc options :online-message online-message)))
|
||||
|
@ -6,22 +6,23 @@
|
||||
[taoensso.timbre :refer-macros [debug]]
|
||||
[status-im.protocol.validation :refer-macros [valid?]]
|
||||
[status-im.protocol.web3.filtering :as f]
|
||||
[status-im.protocol.listeners :as l]))
|
||||
[status-im.protocol.listeners :as l]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn prepare-mesage
|
||||
[{:keys [message group-id keypair new-keypair type]}]
|
||||
[{:keys [message group-id keypair new-keypair type username requires-ack?]}]
|
||||
(let [message' (-> message
|
||||
(update :payload assoc
|
||||
:username username
|
||||
:group-id group-id
|
||||
:type type
|
||||
:timestamp (u/timestamp))
|
||||
(assoc :topics [group-id]
|
||||
:requires-ack? true
|
||||
:keypair keypair
|
||||
:requires-ack? (or (nil? requires-ack?) requires-ack?)
|
||||
:type type))]
|
||||
(if new-keypair
|
||||
(assoc message' :new-keypair keypair)
|
||||
message')))
|
||||
(cond-> message'
|
||||
keypair (assoc :keypair keypair)
|
||||
new-keypair (assoc :new-keypair keypair))))
|
||||
|
||||
(defn- send-group-message!
|
||||
[{:keys [web3] :as opts} type]
|
||||
@ -31,15 +32,25 @@
|
||||
(debug :send-group-message message)
|
||||
(d/add-pending-message! web3 message)))
|
||||
|
||||
(s/def ::group-message
|
||||
(s/def :group/message
|
||||
(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/message
|
||||
(s/merge :group/message (s/keys :username :public-group/username)))
|
||||
|
||||
(defn send!
|
||||
[{:keys [keypair message] :as options}]
|
||||
{:pre [(valid? :message/keypair keypair)
|
||||
(valid? ::group-message message)]}
|
||||
(valid? :group/message message)]}
|
||||
(send-group-message! options :group-message))
|
||||
|
||||
(defn send-to-public-group!
|
||||
[{:keys [message] :as options}]
|
||||
{:pre [(valid? :public-group/message message)]}
|
||||
(send-group-message! (assoc options :requires-ack? false)
|
||||
:public-group-message))
|
||||
|
||||
(defn leave!
|
||||
[options]
|
||||
(send-group-message! options :leave-group))
|
||||
|
@ -35,7 +35,7 @@
|
||||
:ack-not-received-s-interval 125
|
||||
:default-ttl 120
|
||||
:send-online-s-interval 180
|
||||
:ttl {}
|
||||
:ttl-config {:public-group-message 2400}
|
||||
:max-attempts-number 3
|
||||
:delivery-loop-ms-interval 500
|
||||
:profile-keypair {:public updates-public-key
|
||||
@ -79,10 +79,12 @@
|
||||
(register-handler :check-sync
|
||||
(u/side-effect!
|
||||
(fn [{:keys [web3] :as db}]
|
||||
(.getSyncing
|
||||
(.-eth web3)
|
||||
(fn [error sync]
|
||||
(dispatch [:update-sync-state error sync]))))))
|
||||
(if web3
|
||||
(.getSyncing
|
||||
(.-eth web3)
|
||||
(fn [error sync]
|
||||
(dispatch [:update-sync-state error sync])))
|
||||
(s/execute-later #(dispatch [:check-sync]) (s/s->ms 10))))))
|
||||
|
||||
(register-handler :initialize-sync-listener
|
||||
(fn [{:keys [sync-listening-started] :as db} _]
|
||||
@ -107,6 +109,7 @@
|
||||
(case type
|
||||
:message (dispatch [:received-protocol-message! message])
|
||||
:group-message (dispatch [:received-protocol-message! message])
|
||||
:public-group-message (dispatch [:received-protocol-message! message])
|
||||
:ack (if (#{:message :group-message} (:type payload))
|
||||
(dispatch [:message-delivered message])
|
||||
(dispatch [:pending-message-remove message]))
|
||||
@ -417,8 +420,8 @@
|
||||
(u/side-effect!
|
||||
(fn [_ [_ error]]
|
||||
(.log js/console error)
|
||||
(let [message (.-message error)
|
||||
ios-error? (re-find (re-pattern "Could not connect to the server.") message)
|
||||
(let [message (.-message error)
|
||||
ios-error? (re-find (re-pattern "Could not connect to the server.") message)
|
||||
android-error? (re-find (re-pattern "Failed to connect") message)]
|
||||
(when (or ios-error? android-error?)
|
||||
(when android-error? (status/init-jail))
|
||||
|
@ -19,7 +19,7 @@
|
||||
(s/def :payload/new-keypair :message/keypair)
|
||||
|
||||
(s/def :group-message/type
|
||||
#{:group-message :group-invitation :add-group-identity
|
||||
#{:public-group-message :group-message :group-invitation :add-group-identity
|
||||
:remove-group-identity :leave-group :update-group})
|
||||
|
||||
(s/def :discover-message/type #{:online :status :discover :contact-request :update-keys})
|
||||
|
7
src/status_im/protocol/web3/public_group.cljs
Normal file
@ -0,0 +1,7 @@
|
||||
(ns status-im.protocol.web3.public-group
|
||||
(:require [status-im.protocol.web3.filtering :as f]
|
||||
[status-im.protocol.listeners :as l]
|
||||
[status-im.protocol.validation :refer-macros [valid?]]
|
||||
[status-im.protocol.web3.delivery :as d]
|
||||
[cljs.spec :as s]))
|
||||
|
@ -27,6 +27,7 @@
|
||||
:members-active {:one "1 member, 1 active"
|
||||
:other "{{count}} members, {{count}} active"
|
||||
:zero "no members"}
|
||||
:public-group-status "Public"
|
||||
:active-online "Online"
|
||||
:active-unknown "Unknown"
|
||||
:available "Available"
|
||||
@ -119,6 +120,10 @@
|
||||
:chats "Chats"
|
||||
:new-chat "New chat"
|
||||
:new-group-chat "New group chat"
|
||||
:new-public-group-chat "Join public group chat"
|
||||
:empty-topic "Empty topic"
|
||||
:topic-format "Wrong format [a-z0-9\\-]+"
|
||||
:public-group-topic "Topic"
|
||||
|
||||
;discover
|
||||
:discover "Discover"
|
||||
|