parent
8f39f113fa
commit
a598200ace
|
@ -9,8 +9,8 @@
|
|||
[re-frame "0.7.0"]
|
||||
[prismatic/schema "1.0.4"]
|
||||
^{:voom {:repo "git@github.com:status-im/status-lib.git"
|
||||
:branch "discover-rework"}}
|
||||
[status-im/protocol "0.1.1-20160706_085008-ge61756a"]
|
||||
:branch "discover-rework"}}
|
||||
[status-im/protocol "0.1.3-20160818_085900-gda79e8e"]
|
||||
[natal-shell "0.3.0"]
|
||||
[com.andrewmcveigh/cljs-time "0.4.0"]]
|
||||
:plugins [[lein-cljsbuild "1.1.1"]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require [status-im.models.accounts :as accounts]
|
||||
[re-frame.core :refer [register-handler after dispatch dispatch-sync debug]]
|
||||
[status-im.utils.logging :as log]
|
||||
[status-im.protocol.api :as api]
|
||||
[status-im.components.geth :as geth]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.persistence.simple-kv-store :as kv]
|
||||
|
@ -13,11 +14,13 @@
|
|||
[status-im.i18n :refer [label]]
|
||||
[status-im.constants :refer [content-type-command-request]]
|
||||
status-im.accounts.login.handlers
|
||||
[clojure.string :as str]))
|
||||
[clojure.string :as str]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :as u]))
|
||||
|
||||
|
||||
(defn save-account [_ [_ account]]
|
||||
(accounts/save-accounts [account] false))
|
||||
(accounts/save-accounts [account] true))
|
||||
|
||||
(register-handler
|
||||
:add-account
|
||||
|
@ -28,14 +31,14 @@
|
|||
(defn save-password [password]
|
||||
(storage/put kv/kv-store :password password))
|
||||
|
||||
(defn account-created [db result password]
|
||||
(defn account-created [result password]
|
||||
(let [data (json->clj result)
|
||||
public-key (:pubkey data)
|
||||
address (:address data)
|
||||
account {:public-key public-key
|
||||
:address address
|
||||
:name address
|
||||
:photo-path (identicon address)}]
|
||||
:photo-path (identicon public-key)}]
|
||||
(log/debug "account-created: " account)
|
||||
(when (not (str/blank? public-key))
|
||||
(do
|
||||
|
@ -45,17 +48,37 @@
|
|||
(register-handler
|
||||
:create-account
|
||||
(fn [db [_ password]]
|
||||
(geth/create-account password (fn [result] (account-created db result password)))
|
||||
(geth/create-account password (fn [result] (account-created result password)))
|
||||
db))
|
||||
|
||||
(defn save-account-to-realm!
|
||||
[{:keys [current-account-id accounts]} _]
|
||||
(accounts/save-accounts [(get accounts current-account-id)] true))
|
||||
|
||||
(defn send-account-update
|
||||
[{:keys [current-account-id accounts]} _]
|
||||
(api/send-account-update (get accounts current-account-id)))
|
||||
|
||||
(register-handler
|
||||
:account-update
|
||||
(fn [db [_ data]]
|
||||
(let [current-account-id (get db :current-account-id)
|
||||
account (-> (get-in db [:accounts current-account-id])
|
||||
(merge data))]
|
||||
(accounts/save-accounts [account] true)
|
||||
(assoc-in db [:accounts current-account-id] account))))
|
||||
(-> (fn [{:keys [current-account-id accounts] :as db} [_ data]]
|
||||
(let [data (assoc data :last-updated (time/now-ms))
|
||||
account (-> (get accounts current-account-id)
|
||||
(merge data))]
|
||||
(assoc-in db [:accounts current-account-id] account)))
|
||||
((after save-account-to-realm!))
|
||||
((after send-account-update))))
|
||||
|
||||
(register-handler
|
||||
:send-account-update-if-needed
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-account-id accounts]} _]
|
||||
(let [{:keys [last-updated]} (get accounts current-account-id)
|
||||
now (time/now-ms)
|
||||
needs-update? (> (- now last-updated) time/week)]
|
||||
(log/info "Need to send account-update: " needs-update?)
|
||||
(when needs-update?
|
||||
(dispatch [:account-update]))))))
|
||||
|
||||
(defn initialize-account [db address]
|
||||
(let [is-login-screen? (= (:view-id db) :login)]
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
[status-im.contacts.views.contact-list :refer [contact-list]]
|
||||
[status-im.contacts.views.new-contact :refer [new-contact]]
|
||||
[status-im.qr-scanner.screen :refer [qr-scanner]]
|
||||
[status-im.discovery.screen :refer [discovery]]
|
||||
[status-im.discovery.tag :refer [discovery-tag]]
|
||||
[status-im.chat.screen :refer [chat]]
|
||||
[status-im.accounts.login.screen :refer [login]]
|
||||
|
|
|
@ -479,13 +479,13 @@
|
|||
[{:keys [current-chat-id]} _]
|
||||
(r/write :account
|
||||
(fn []
|
||||
(r/delete :account (r/get-by-field :account :msgs :chat-id current-chat-id)))))
|
||||
(r/delete :account (r/get-by-field :account :message :chat-id current-chat-id)))))
|
||||
|
||||
(defn delete-chat!
|
||||
[{:keys [current-chat-id]} _]
|
||||
(r/write :account
|
||||
(fn [] :account
|
||||
(->> (r/get-by-field :account :chats :chat-id current-chat-id)
|
||||
(->> (r/get-by-field :account :chat :chat-id current-chat-id)
|
||||
(r/single)
|
||||
(r/delete :account)))))
|
||||
|
||||
|
@ -550,3 +550,9 @@
|
|||
j/adjust-resize)))))
|
||||
(fn [db [_ chat-id mode]]
|
||||
(assoc-in db [:kb-mode chat-id] mode)))
|
||||
|
||||
(register-handler :update-chat!
|
||||
(fn [db [_ chat-id new-chat-data]]
|
||||
(if (get-in db [:chats chat-id])
|
||||
(update-in db [:chats chat-id] merge new-chat-data)
|
||||
db)))
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
[{:keys [current-chat-id] :as db} [_ chat-id]]
|
||||
(let [chat-id' (or chat-id current-chat-id)
|
||||
requests (-> ;; todo maybe limit is needed
|
||||
(realm/get-by-fields :account :requests
|
||||
(realm/get-by-fields :account :request
|
||||
{:chat-id chat-id'
|
||||
:status "open"})
|
||||
(realm/sorted :added :desc)
|
||||
|
@ -36,7 +36,7 @@
|
|||
[_ [_ chat-id message-id]]
|
||||
(realm/write :account
|
||||
(fn []
|
||||
(-> (realm/get-by-fields :account :requests
|
||||
(-> (realm/get-by-fields :account :request
|
||||
{:chat-id chat-id
|
||||
:message-id message-id})
|
||||
(realm/single)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
(defn delivered-messages []
|
||||
(-> (realm/get-by-fields
|
||||
:account :msgs
|
||||
:account :message
|
||||
{:delivery-status :delivered
|
||||
:outgoing false})
|
||||
(realm/collection->map)))
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
[status-im.chat.styles.screen :as st]
|
||||
[status-im.utils.listview :refer [to-datasource-inverted]]
|
||||
[status-im.utils.utils :refer [truncate-str]]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.chat.views.message :refer [chat-message]]
|
||||
|
@ -23,7 +24,8 @@
|
|||
[status-im.chat.views.new-message :refer [chat-message-new]]
|
||||
[status-im.i18n :refer [label label-pluralize]]
|
||||
[status-im.components.animation :as anim]
|
||||
[reagent.core :as r]))
|
||||
[reagent.core :as r]
|
||||
[clojure.string :as str]))
|
||||
|
||||
|
||||
(defn contacts-by-identity [contacts]
|
||||
|
@ -191,16 +193,27 @@
|
|||
[overlay {:on-click-outside #(dispatch [:set-show-actions false])}
|
||||
[actions-list-view platform-specific]])
|
||||
|
||||
(defn online-text [contact chat-id]
|
||||
(if contact
|
||||
(if (> (get contact :last-online) 0)
|
||||
(time/time-ago (time/to-date (get contact :last-online)))
|
||||
(label :t/active-unknown))
|
||||
(if (= chat-id "console")
|
||||
(label :t/active-online)
|
||||
(label :t/active-unknown))))
|
||||
|
||||
(defn toolbar-content [platform-specific]
|
||||
(let [{:keys [group-chat name contacts]}
|
||||
(subscribe [:chat-properties [:group-chat :name :contacts]])
|
||||
(let [{:keys [group-chat chat-id name contacts]} (subscribe [:chat-properties [:group-chat :chat-id :name :contacts]])
|
||||
contact (subscribe [:get-in [:contacts @chat-id]])
|
||||
show-actions (subscribe [:show-actions])]
|
||||
(fn []
|
||||
[view (st/chat-name-view @show-actions)
|
||||
[text {:style st/chat-name-text
|
||||
:platform-specific platform-specific
|
||||
:font :medium}
|
||||
(truncate-str (or @name (label :t/chat-name)) 30)]
|
||||
(if (str/blank? @name)
|
||||
(label :t/user-anonymous)
|
||||
(truncate-str (or @name (label :t/chat-name)) 30))]
|
||||
(if @group-chat
|
||||
[view {:flexDirection :row}
|
||||
[icon :group st/group-icon]
|
||||
|
@ -209,11 +222,10 @@
|
|||
:font :medium}
|
||||
(let [cnt (inc (count @contacts))]
|
||||
(label-pluralize cnt :t/members))]]
|
||||
;; TODO stub data: last activity
|
||||
[text {:style st/last-activity
|
||||
:platform-specific platform-specific
|
||||
:font :default}
|
||||
(label :t/last-active)])])))
|
||||
(online-text @contact @chat-id)])])))
|
||||
|
||||
(defn toolbar-action []
|
||||
(let [show-actions (subscribe [:show-actions])]
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
:renderRow (fn [row _ _]
|
||||
(list-item [chat-list-item row]))
|
||||
:style st/list-container
|
||||
;;; if "maximazing" chat list will make scroll to 0,
|
||||
;;; if "maximizing" chat list will make scroll to 0,
|
||||
;;; then disable maximazing
|
||||
:onLayout (fn [event]
|
||||
(when-not @chats-scrolled?
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
image
|
||||
touchable-highlight]]
|
||||
[status-im.components.styles :refer [font]]
|
||||
[status-im.chats-list.views.inner-item :refer
|
||||
[chat-list-item-inner-view]]))
|
||||
[status-im.chats-list.views.inner-item :refer [chat-list-item-inner-view]]))
|
||||
|
||||
(defn chat-list-item [[chat-id chat]]
|
||||
[touchable-highlight
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
[status-im.components.chat-icon.screen :refer [chat-icon-view-chat-list]]
|
||||
[status-im.chats-list.styles :as st]
|
||||
[status-im.utils.utils :refer [truncate-str]]
|
||||
[status-im.utils.datetime :as time]))
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.datetime :as time]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defview chat-list-item-inner-view
|
||||
[{:keys [chat-id name color new-messages-count
|
||||
|
@ -16,7 +18,9 @@
|
|||
[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} (truncate-str name 20)]
|
||||
[text {:style st/name-text} (if (str/blank? name)
|
||||
(label :t/user-anonymous)
|
||||
(truncate-str name 20))]
|
||||
(when group-chat
|
||||
[icon :group st/group-icon])
|
||||
(when group-chat
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
[_ [identity]]
|
||||
(dispatch [::fetch-commands! identity])
|
||||
;; todo uncomment
|
||||
#_(if-let [{:keys [file]} (realm/get-one-by-field :account :commands
|
||||
#_(if-let [{:keys [file]} (realm/get-one-by-field :account :command
|
||||
:chat-id identity)]
|
||||
(dispatch [::parse-commands! identity file])
|
||||
(dispatch [::fetch-commands! identity])))
|
||||
|
@ -73,7 +73,7 @@
|
|||
|
||||
(defn save-commands-js!
|
||||
[_ [id file]]
|
||||
(realm/create-object :account :commands {:chat-id id :file file}))
|
||||
(realm/create-object :account :command {:chat-id id :file file}))
|
||||
|
||||
(defn loading-failed!
|
||||
[db [id reason details]]
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
(defn window-page-width []
|
||||
(.-width (.get (.. r/react-native -Dimensions) "window")))
|
||||
|
||||
(def defaults {:gap 10
|
||||
:sneak 10
|
||||
(def defaults {:gap 8
|
||||
:sneak 8
|
||||
:pageStyle {}
|
||||
:scrollThreshold 20})
|
||||
|
||||
|
@ -175,5 +175,4 @@
|
|||
:component-did-update component-did-update
|
||||
:display-name "carousel"
|
||||
:reagent-render reagent-render}]
|
||||
(log/debug "Creating carousel component: " data)
|
||||
(reagent.core/create-class component-data)))
|
||||
|
|
|
@ -95,10 +95,10 @@
|
|||
[animated-view {:style (st/tab-view-container anim-value)}
|
||||
content])})))
|
||||
|
||||
(defn tab-view [{:keys [view-id screen]}]
|
||||
(defn tab-view [platform-specific {:keys [view-id screen]}]
|
||||
^{:key view-id}
|
||||
[tab-view-container view-id
|
||||
[screen]])
|
||||
[screen {:platform-specific platform-specific}]])
|
||||
|
||||
(defview main-tabs [{platform-specific :platform-specific}]
|
||||
[view-id [:get :view-id]
|
||||
|
@ -109,6 +109,6 @@
|
|||
[drawer-view {:platform-specific platform-specific}
|
||||
[view {:style common-st/flex
|
||||
:pointerEvents (if tab-animation? :none :auto)}
|
||||
(doall (map #(tab-view %) tab-list))
|
||||
(doall (map #(tab-view platform-specific %) tab-list))
|
||||
[tabs {:selected-view-id view-id
|
||||
:tab-list tab-list}]]]]])
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
text2-color
|
||||
toolbar-background1]]))
|
||||
|
||||
(def tabs-height 59)
|
||||
(def tabs-height 60)
|
||||
(def tab-height 56)
|
||||
|
||||
(defn tabs-container [hidden? animation? offset-y]
|
||||
|
@ -67,5 +67,5 @@
|
|||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:padding-bottom 59
|
||||
:padding-bottom 60
|
||||
:transform [{:translateX offset-x}]})
|
||||
|
|
|
@ -4,18 +4,26 @@
|
|||
[status-im.models.contacts :as contacts]
|
||||
[status-im.utils.crypt :refer [encrypt]]
|
||||
[clojure.string :as s]
|
||||
[status-im.protocol.api :as api]
|
||||
[status-im.utils.utils :refer [http-post]]
|
||||
[status-im.utils.phone-number :refer [format-phone-number]]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.utils :refer [require]]))
|
||||
[status-im.utils.utils :refer [require]]
|
||||
[status-im.utils.logging :as log]))
|
||||
|
||||
(defn save-contact
|
||||
[_ [_ contact]]
|
||||
(contacts/save-contacts [contact]))
|
||||
|
||||
(register-handler :add-contact
|
||||
(defn watch-contact
|
||||
[_ [_ contact]]
|
||||
(api/watch-user contact))
|
||||
|
||||
(register-handler :watch-contact (u/side-effect! watch-contact))
|
||||
|
||||
(register-handler :update-contact
|
||||
(-> (fn [db [_ {:keys [whisper-identity] :as contact}]]
|
||||
(update db :contacts assoc whisper-identity contact))
|
||||
(update-in db [:contacts whisper-identity] merge contact))
|
||||
((after save-contact))))
|
||||
|
||||
(defn load-contacts! [db _]
|
||||
|
@ -23,6 +31,8 @@
|
|||
(map (fn [{:keys [whisper-identity] :as contact}]
|
||||
[whisper-identity contact]))
|
||||
(into {}))]
|
||||
(doseq [[_ contact] contacts]
|
||||
(dispatch [:watch-contact contact]))
|
||||
(assoc db :contacts contacts)))
|
||||
|
||||
(register-handler :load-contacts load-contacts!)
|
||||
|
@ -108,17 +118,34 @@
|
|||
(defn add-new-contact [db [_ {:keys [whisper-identity] :as contact}]]
|
||||
(-> db
|
||||
(update :contacts assoc whisper-identity contact)
|
||||
(assoc :new-contact {:name ""
|
||||
:address ""
|
||||
:whisper-identity ""
|
||||
:phone-number ""})))
|
||||
(assoc :new-contact-identity "")))
|
||||
|
||||
(register-handler :add-new-contact
|
||||
(after save-contact)
|
||||
add-new-contact)
|
||||
(-> add-new-contact
|
||||
((after save-contact))
|
||||
((after watch-contact))))
|
||||
|
||||
(defn set-new-contact-from-qr
|
||||
[{:keys [new-contact] :as db} [_ _ qr-contact]]
|
||||
(assoc db :new-contact (merge new-contact qr-contact)))
|
||||
(defn set-contact-identity-from-qr
|
||||
[db [_ _ contact-identity]]
|
||||
(assoc db :new-contact-identity contact-identity))
|
||||
|
||||
(register-handler :set-new-contact-from-qr set-new-contact-from-qr)
|
||||
(register-handler :set-contact-identity-from-qr set-contact-identity-from-qr)
|
||||
|
||||
(register-handler :contact-update-received
|
||||
(u/side-effect!
|
||||
;; TODO: security issue: we should use `from` instead of `public-key` here, but for testing it is much easier to use `public-key`
|
||||
(fn [db [_ from {{:keys [public-key last-updated name] :as account} :account}]]
|
||||
(let [prev-last-updated (get-in db [:contacts public-key :last-updated])]
|
||||
(if (< prev-last-updated last-updated)
|
||||
(let [contact (-> (assoc account :whisper-identity public-key)
|
||||
(dissoc :public-key))]
|
||||
(dispatch [:update-contact contact])
|
||||
(dispatch [:update-chat! public-key {:name name}])))))))
|
||||
|
||||
(register-handler :contact-online-received
|
||||
(u/side-effect!
|
||||
(fn [db [_ from {last-online :at :as payload}]]
|
||||
(let [prev-last-online (get-in db [:contacts from :last-online])]
|
||||
(if (< prev-last-online last-online)
|
||||
(dispatch [:update-contact {:whisper-identity from
|
||||
:last-online last-online}]))))))
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
(.isAddress js/Web3.prototype s))
|
||||
|
||||
(defn unique-identity? [identity]
|
||||
(not (realm/exists? :account :contacts :whisper-identity identity)))
|
||||
(not (realm/exists? :account :contact :whisper-identity identity)))
|
||||
|
||||
(defn valid-length? [identity]
|
||||
(let [length (count identity)]
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
(if (pos? (count (:name contact)))
|
||||
name
|
||||
;; todo is this correct behaviour?
|
||||
(label :t/no-name))]
|
||||
(label :t/user-anonymous))]
|
||||
(when info
|
||||
[text {:style st/info-text}
|
||||
info])]]))
|
||||
|
|
|
@ -37,14 +37,32 @@
|
|||
[text {:style toolbar-title-text}
|
||||
(label :t/add-new-contact)]])
|
||||
|
||||
(defview contact-name-input [name]
|
||||
[]
|
||||
[text-field
|
||||
{:error (if (str/blank? name) "" nil)
|
||||
:errorColor "#7099e6"
|
||||
:value name
|
||||
:label (label :t/name)
|
||||
:onChangeText #(dispatch [:set-in [:new-contact :name] %])}])
|
||||
(defn on-add-contact [id]
|
||||
(if (v/is-address? id)
|
||||
(http-post "get-contacts-by-address" {:addresses [id]}
|
||||
(fn [{:keys [contacts]}]
|
||||
(if (> (count contacts) 0)
|
||||
(let [{:keys [whisper-identity]} (first contacts)
|
||||
contact {:name ""
|
||||
:address id
|
||||
:photo-path (identicon whisper-identity)
|
||||
:whisper-identity whisper-identity}]
|
||||
(dispatch [:add-new-contact contact]))
|
||||
(dispatch [:set :new-contact-address-error (label :t/unknown-address)]))))
|
||||
(dispatch [:add-new-contact {:name ""
|
||||
:photo-path (identicon id)
|
||||
:whisper-identity id}])))
|
||||
|
||||
(defn toolbar-action [new-contact-identity error]
|
||||
(let [valid-contact? (and
|
||||
(s/valid? ::v/whisper-identity new-contact-identity)
|
||||
(nil? error))]
|
||||
{:image {:source {:uri (if valid-contact?
|
||||
:icon_ok_blue
|
||||
:icon_ok_disabled)}
|
||||
:style icon-search}
|
||||
:handler #(when valid-contact?
|
||||
(on-add-contact new-contact-identity))}))
|
||||
|
||||
(defview contact-whisper-id-input [whisper-identity error]
|
||||
[]
|
||||
|
@ -53,48 +71,20 @@
|
|||
error
|
||||
(label :t/enter-valid-address))]
|
||||
[view button-input-container
|
||||
[text-field
|
||||
{:error error
|
||||
:errorColor "#7099e6"
|
||||
:value whisper-identity
|
||||
:wrapperStyle (merge button-input)
|
||||
:label (label :t/address)
|
||||
:onChangeText #(do
|
||||
(dispatch [:set-in [:new-contact :whisper-identity] %])
|
||||
(dispatch [:set :new-contact-address-error nil]))}]
|
||||
[scan-button {:showLabel (zero? (count whisper-identity))
|
||||
:handler #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-new-contact-from-qr])}]]))
|
||||
|
||||
(defn on-add-contact [whisper-identity new-contact]
|
||||
(if (v/is-address? whisper-identity)
|
||||
(http-post "get-contacts-by-address" {:addresses [whisper-identity]}
|
||||
(fn [{:keys [contacts]}]
|
||||
(if (> (count contacts) 0)
|
||||
(let [contact (first contacts)
|
||||
new-contact (merge
|
||||
new-contact
|
||||
{:address whisper-identity
|
||||
:whisper-identity (:whisper-identity contact)})]
|
||||
(dispatch [:add-new-contact new-contact]))
|
||||
(dispatch [:set :new-contact-address-error (label :t/unknown-address)]))))
|
||||
(dispatch [:add-new-contact new-contact])))
|
||||
|
||||
(defn toolbar-action [whisper-identity new-contact error]
|
||||
(let [valid-contact? (and
|
||||
(s/valid? ::v/contact new-contact)
|
||||
(nil? error))]
|
||||
{:image {:source {:uri (if valid-contact?
|
||||
:icon_ok_blue
|
||||
:icon_ok_disabled)}
|
||||
:style icon-search}
|
||||
:handler #(when valid-contact?
|
||||
(let [contact (merge
|
||||
{:photo-path (identicon whisper-identity)}
|
||||
new-contact)]
|
||||
(on-add-contact whisper-identity contact)))}))
|
||||
[text-field
|
||||
{:error error
|
||||
:errorColor "#7099e6"
|
||||
:value whisper-identity
|
||||
:wrapperStyle (merge button-input)
|
||||
:label (label :t/address)
|
||||
:onChangeText #(do
|
||||
(dispatch [:set-in [:new-contact-identity] %])
|
||||
(dispatch [:set :new-contact-address-error nil]))}]
|
||||
[scan-button {:showLabel (zero? (count whisper-identity))
|
||||
:handler #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-contact-identity-from-qr])}]]))
|
||||
|
||||
(defview new-contact [{platform-specific :platform-specific}]
|
||||
[{:keys [name whisper-identity phone-number] :as new-contact} [:get :new-contact]
|
||||
[new-contact-identity [:get :new-contact-identity]
|
||||
error [:get :new-contact-address-error]]
|
||||
[view st/contact-form-container
|
||||
[view
|
||||
|
@ -104,9 +94,11 @@
|
|||
:style icon-back}
|
||||
:handler #(dispatch [:navigate-back])}
|
||||
:custom-content toolbar-title
|
||||
:action (toolbar-action whisper-identity new-contact error)}]]
|
||||
:action (toolbar-action new-contact-identity error)}]]
|
||||
[view st/form-container
|
||||
[contact-name-input name]
|
||||
[contact-whisper-id-input whisper-identity error]]
|
||||
[contact-whisper-id-input new-contact-identity error]]
|
||||
[view st/address-explication-container
|
||||
[text {:style st/address-explication} (label :t/address-explication)]]])
|
||||
[text {:style st/address-explication
|
||||
:platform-specific platform-specific
|
||||
:font :default}
|
||||
(label :t/address-explication)]]])
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
:status nil
|
||||
:photo-path nil}
|
||||
|
||||
:contacts []
|
||||
:new-contact-identity ""
|
||||
:contacts {}
|
||||
|
||||
:contacts-ids #{}
|
||||
:selected-contacts #{}
|
||||
:current-chat-id "console"
|
||||
|
@ -36,10 +38,6 @@
|
|||
:navigation-stack (list default-view)
|
||||
:current-tag nil
|
||||
:qr-codes {}
|
||||
:new-contact {:name ""
|
||||
:address ""
|
||||
:whisper-identity ""
|
||||
:phone-number ""}
|
||||
:keyboard-height 0
|
||||
:disable-group-creation false
|
||||
:animations {;; todo clear this
|
||||
|
|
|
@ -1,67 +1,72 @@
|
|||
(ns status-im.discovery.handlers
|
||||
(:require [re-frame.core :refer [after dispatch enrich]]
|
||||
[status-im.utils.utils :refer [first-index]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.protocol.api :as api]
|
||||
[status-im.navigation.handlers :as nav]
|
||||
[status-im.discovery.model :as discoveries]
|
||||
[status-im.utils.handlers :as u]))
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.datetime :as time]))
|
||||
|
||||
(register-handler :init-discoveries
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(assoc :discoveries []))))
|
||||
|
||||
(defn calculate-priority [{:keys [chats contacts]} from payload]
|
||||
(let [contact (get contacts from)
|
||||
chat (get chats from)
|
||||
seen-online-recently? (< (- (time/now-ms) (get contact :last-online))
|
||||
time/hour)]
|
||||
(+ (time/now-ms) ;; message is newer => priority is higher
|
||||
(if contact time/day 0) ;; user exists in contact list => increase priority
|
||||
(if chat time/day 0) ;; chat with this user exists => increase priority
|
||||
(if seen-online-recently? time/hour 0) ;; the user was online recently => increase priority
|
||||
)))
|
||||
|
||||
(defmethod nav/preload-data! :discovery
|
||||
[{:keys [discoveries] :as db} _]
|
||||
(if-not (seq discoveries)
|
||||
(-> db
|
||||
(assoc :tags (discoveries/all-tags))
|
||||
;; todo add limit
|
||||
;; todo hash-map with whisper-id as key and sorted by last-update
|
||||
;; may be more efficient here
|
||||
(assoc :discoveries (discoveries/discovery-list)))
|
||||
db))
|
||||
(-> db
|
||||
(assoc :tags (discoveries/all-tags))
|
||||
;; todo add limit
|
||||
;; todo hash-map with whisper-id as key and sorted by last-update
|
||||
;; may be more efficient here
|
||||
(assoc :discoveries (discoveries/discovery-list))))
|
||||
|
||||
(register-handler :discovery-response-received
|
||||
(u/side-effect!
|
||||
(fn [_ [_ from payload]]
|
||||
(let [{:keys [name status hashtags location]} payload
|
||||
location (or location "")
|
||||
discovery [{:name name
|
||||
:status status
|
||||
:whisper-id from
|
||||
:photo ""
|
||||
:location location
|
||||
:tags (map #(hash-map :name %) hashtags)
|
||||
:last-updated (js/Date.)}]]
|
||||
(fn [db [_ from payload]]
|
||||
(let [{:keys [msg-id name photo-path status hashtags]} payload
|
||||
discovery {:msg-id msg-id
|
||||
:name name
|
||||
:photo-path photo-path
|
||||
:status status
|
||||
:whisper-id from
|
||||
:tags (map #(hash-map :name %) hashtags)
|
||||
:last-updated (js/Date.)
|
||||
:priority (calculate-priority db from payload)}]
|
||||
(dispatch [:add-discovery discovery])))))
|
||||
|
||||
(register-handler :broadcast-status
|
||||
(u/side-effect!
|
||||
(fn [{:keys [name]} [_ status hashtags]]
|
||||
(api/broadcast-discover-status name status hashtags))))
|
||||
(fn [{:keys [current-account-id accounts]} [_ status hashtags]]
|
||||
(let [account (get accounts current-account-id)]
|
||||
(api/broadcast-discover-status account status hashtags)))))
|
||||
|
||||
(register-handler :show-discovery-tag
|
||||
(fn [db [_ tag]]
|
||||
(dispatch [:navigate-to :discovery-tag])
|
||||
(assoc db :current-tag tag)))
|
||||
|
||||
;; todo remove this
|
||||
(register-handler :create-fake-discovery!
|
||||
(u/side-effect!
|
||||
(fn [_ _]
|
||||
(let [number (rand-int 999)
|
||||
discovery {:name (str "Name " number)
|
||||
:status (str "Status This is some longer status to get the second line " number)
|
||||
:whisper-id (str number)
|
||||
:photo ""
|
||||
:location ""
|
||||
:tags [{:name "tag1"}
|
||||
{:name "tag2"}
|
||||
{:name "tag3"}]
|
||||
:last-updated (new js/Date)}]
|
||||
(dispatch [:add-discovery discovery])))))
|
||||
|
||||
(defn add-discovery
|
||||
[db [_ discovery]]
|
||||
(-> db
|
||||
(assoc :new-discovery discovery)
|
||||
(update :discoveries conj discovery)))
|
||||
[{db-discoveries :discoveries
|
||||
:as db} [_ {:keys [msg-id] :as discovery}]]
|
||||
(let [updated-discoveries (if-let [i (first-index #(= (:msg-id %) msg-id) db-discoveries)]
|
||||
(assoc db-discoveries i discovery)
|
||||
(conj db-discoveries discovery))]
|
||||
(-> db
|
||||
(assoc :new-discovery discovery)
|
||||
(assoc :discoveries updated-discoveries))))
|
||||
|
||||
(defn save-discovery!
|
||||
[{:keys [new-discovery]} _]
|
||||
|
@ -75,3 +80,9 @@
|
|||
(-> add-discovery
|
||||
((after save-discovery!))
|
||||
((enrich reload-tags!))))
|
||||
|
||||
(register-handler
|
||||
:remove-old-discoveries!
|
||||
(u/side-effect!
|
||||
(fn [_ _]
|
||||
(discoveries/remove-discoveries! :priority :asc 1000 200))))
|
||||
|
|
|
@ -5,87 +5,72 @@
|
|||
|
||||
(defn get-tag [tag]
|
||||
(log/debug "Getting tag: " tag)
|
||||
(-> (r/get-by-field :base :tag :name tag)
|
||||
(-> (r/get-by-field :account :tag :name tag)
|
||||
(r/single-cljs)))
|
||||
|
||||
(defn decrease-tag-counter [tag]
|
||||
(defn update-tag-counter [func tag]
|
||||
(let [tag (:name tag)
|
||||
tag-object (get-tag tag)]
|
||||
(if tag-object
|
||||
(let [counter (dec (:count tag-object))]
|
||||
(if (zero? counter)
|
||||
(r/delete :base tag-object)
|
||||
(r/create :base :tag
|
||||
{:name tag
|
||||
:count counter}
|
||||
true))))))
|
||||
|
||||
(defn increase-tag-counter [tag]
|
||||
(let [tag (:name tag)
|
||||
tag-object (get-tag tag)]
|
||||
(if tag-object
|
||||
(r/create :base :tag
|
||||
(r/create :account :tag
|
||||
{:name tag
|
||||
:count (inc (:count tag-object))}
|
||||
:count (func (:count tag-object))}
|
||||
true))))
|
||||
|
||||
(defn decrease-tags-counter [tags]
|
||||
(doseq [tag tags]
|
||||
(decrease-tag-counter tag)))
|
||||
(defn update-tags-counter [func tags]
|
||||
(doseq [tag (distinct tags)]
|
||||
(update-tag-counter func tag)))
|
||||
|
||||
(defn increase-tags-counter [tags]
|
||||
(doseq [tag tags]
|
||||
(increase-tag-counter tag)))
|
||||
(defn get-tags [msg-id]
|
||||
(-> (r/get-by-field :account :discovery :msg-id msg-id)
|
||||
(r/single-cljs)
|
||||
(:tags)
|
||||
(vals)))
|
||||
|
||||
(defn get-tags [whisper-id]
|
||||
(:tags (-> (r/get-by-field :base :discoveries :whisper-id whisper-id)
|
||||
(r/single-cljs))))
|
||||
|
||||
(defn- create-discovery [{:keys [tags] :as discovery}]
|
||||
(log/debug "Creating discovery: " discovery tags)
|
||||
(r/create :base :discoveries discovery true)
|
||||
(increase-tags-counter tags))
|
||||
|
||||
(defn- update-discovery [{:keys [whisper-id tags] :as discovery}]
|
||||
(let [old-tags (get-tags whisper-id)
|
||||
tags (map :name tags)]
|
||||
(decrease-tags-counter old-tags)
|
||||
(r/create :base :discoveries discovery true)
|
||||
(increase-tags-counter tags)))
|
||||
|
||||
(defn- discovery-exist? [discoveries discovery]
|
||||
(some #(= (:whisper-id discovery) (:whisper-id %)) discoveries))
|
||||
(defn- upsert-discovery [{:keys [msg-id tags] :as discovery}]
|
||||
(log/debug "Creating/updating discovery with tags: " tags)
|
||||
(let [prev-tags (get-tags msg-id)]
|
||||
(if prev-tags
|
||||
(update-tags-counter dec prev-tags))
|
||||
(r/create :account :discovery discovery true)
|
||||
(update-tags-counter inc tags)))
|
||||
|
||||
(defn discovery-list []
|
||||
(->> (-> (r/get-all :base :discoveries)
|
||||
(r/sorted :last-updated :desc)
|
||||
r/collection->map)
|
||||
(map #(update % :tags vals))))
|
||||
(->> (-> (r/get-all :account :discovery)
|
||||
(r/sorted :priority :desc)
|
||||
(r/collection->map))
|
||||
(mapv #(update % :tags vals))))
|
||||
|
||||
(defn- add-discoveries [discoveries]
|
||||
(r/write :base
|
||||
(r/write :account
|
||||
(fn []
|
||||
(let [db-discoveries (discovery-list)]
|
||||
(mapv (fn [discovery]
|
||||
(if-not (discovery-exist? db-discoveries
|
||||
discovery)
|
||||
(create-discovery discovery)
|
||||
(update-discovery discovery)))
|
||||
discoveries)))))
|
||||
(doseq [discovery discoveries]
|
||||
(upsert-discovery discovery)))))
|
||||
|
||||
(defn save-discoveries [discoveries]
|
||||
(add-discoveries discoveries))
|
||||
|
||||
(defn remove-discoveries! [by ordering critical-count to-delete-count]
|
||||
(let [objs (r/get-all :account :discovery)
|
||||
count (r/get-count objs)]
|
||||
(if (> count critical-count)
|
||||
(let [to-delete (-> (r/sorted objs by ordering)
|
||||
(r/page 0 to-delete-count))]
|
||||
(r/write :account
|
||||
(fn []
|
||||
(log/debug (str "Deleting " (r/get-count to-delete) " discoveries"))
|
||||
(r/delete :account to-delete)))))))
|
||||
|
||||
(defn discoveries-by-tag [tag limit]
|
||||
(let [discoveries (-> (r/get-by-filter :base :discoveries (str "tags.name = '" tag "'"))
|
||||
(r/sorted :last-updated :desc))]
|
||||
(let [discoveries (-> (r/get-by-filter :account :discovery (str "tags.name = '" tag "'"))
|
||||
(r/sorted :priority :desc))]
|
||||
(log/debug "Discoveries by tag: " tag)
|
||||
(if (pos? limit)
|
||||
(r/page discoveries 0 limit)
|
||||
discoveries)))
|
||||
|
||||
(defn all-tags []
|
||||
(-> (r/get-all :base :tag)
|
||||
(-> (r/get-all :account :tag)
|
||||
(r/sorted :count :desc)
|
||||
r/collection->map))
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
text-input]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.components.drawer.view :refer [open-drawer]]
|
||||
[status-im.discovery.views.popular :refer [popular]]
|
||||
[status-im.discovery.views.recent :refer [discovery-recent]]
|
||||
[status-im.discovery.styles :as st]
|
||||
|
@ -19,18 +20,21 @@
|
|||
(let [hashtags (map #(subs % 1) (re-seq #"#[^ !?,;:.]+" status))]
|
||||
(or hashtags [])))
|
||||
|
||||
(defn title-content [show-search]
|
||||
(defn title-content [platform-specific show-search]
|
||||
[view st/discovery-toolbar-content
|
||||
(if show-search
|
||||
[text-input {:style st/discovery-search-input
|
||||
:autoFocus true
|
||||
:placeholder (label :t/search-tags)
|
||||
:onSubmitEditing (fn [e]
|
||||
(let [search (aget e "nativeEvent" "text")
|
||||
(let [search (aget e "nativeEvent" "text")
|
||||
hashtags (get-hashtags search)]
|
||||
(dispatch [:broadcast-status search hashtags])))}]
|
||||
[view
|
||||
[text {:style st/discovery-title} (label :t/discovery)]])])
|
||||
[text {:style st/discovery-title
|
||||
:platform-specific platform-specific
|
||||
:font :default}
|
||||
(label :t/discovery)]])])
|
||||
|
||||
(defn toogle-search [current-value]
|
||||
(dispatch [:set ::show-search (not current-value)]))
|
||||
|
@ -42,21 +46,33 @@
|
|||
{:style st/discovery-toolbar
|
||||
:nav-action {:image {:source {:uri :icon_hamburger}
|
||||
:style st/hamburger-icon}
|
||||
:handler #(dispatch [:create-fake-discovery!])}
|
||||
:custom-content [title-content show-search]
|
||||
:handler open-drawer}
|
||||
:custom-content [title-content platform-specific show-search]
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:style st/search-icon}
|
||||
:handler #(toogle-search show-search)}}]])
|
||||
|
||||
(defview discovery [{platform-specific :platform-specific}]
|
||||
[show-search [:get ::show-search]]
|
||||
[show-search [:get ::show-search]
|
||||
contacts [:get :contacts]]
|
||||
[view st/discovery-container
|
||||
[discovery-toolbar show-search platform-specific]
|
||||
[scroll-view st/scroll-view-container
|
||||
|
||||
[view st/section-spacing
|
||||
[text {:style st/discovery-subtitle} (label :t/popular-tags)]]
|
||||
[popular]
|
||||
[text {:style st/discovery-subtitle
|
||||
:platform-specific platform-specific
|
||||
:font :medium}
|
||||
(label :t/popular-tags)]]
|
||||
[popular {:contacts contacts
|
||||
:platform-specific platform-specific}]
|
||||
|
||||
[view st/section-spacing
|
||||
[text {:style st/discovery-subtitle} (label :t/recent)]]
|
||||
[discovery-recent]]
|
||||
[text {:style st/discovery-subtitle
|
||||
:platform-specific platform-specific
|
||||
:font :medium}
|
||||
(label :t/recent)]]
|
||||
[discovery-recent {:contacts contacts
|
||||
:platform-specific platform-specific}]]
|
||||
|
||||
[bottom-gradient]])
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
(ns status-im.discovery.styles
|
||||
(:require [status-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
||||
(:require [status-im.components.styles :refer [color-white
|
||||
color-gray2
|
||||
chat-background
|
||||
online-color
|
||||
|
@ -14,55 +12,51 @@
|
|||
;; common
|
||||
|
||||
(def row-separator
|
||||
{:borderBottomWidth 1
|
||||
:borderBottomColor "#eff2f3"})
|
||||
{:border-bottom-width 1
|
||||
:border-bottom-color "#eff2f3"})
|
||||
|
||||
(def row
|
||||
{:flexDirection :row})
|
||||
{:flex-direction :row})
|
||||
|
||||
(def column
|
||||
{:flexDirection "column"})
|
||||
{:flex-direction :column})
|
||||
|
||||
;; discovery.cljs
|
||||
;; Toolbar
|
||||
|
||||
(def discovery-toolbar-content
|
||||
{:flex 1
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def discovery-search-input
|
||||
{:flex 1
|
||||
:marginLeft 18
|
||||
:lineHeight 42
|
||||
:fontSize 14
|
||||
:fontFamily "Avenir-Roman"
|
||||
:color "#9CBFC0"})
|
||||
|
||||
(def discovery-title
|
||||
{:color "#000000de"
|
||||
:alignSelf :center
|
||||
:textAlign :center
|
||||
:fontFamily "sans-serif"
|
||||
:fontSize 16})
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def discovery-toolbar
|
||||
{:backgroundColor "#eef2f5"
|
||||
:elevation 0})
|
||||
{:background-color "#eef2f5"
|
||||
:elevation 0})
|
||||
|
||||
(def discovery-search-input
|
||||
{:flex 1
|
||||
:align-self "stretch"
|
||||
:margin-left 18
|
||||
:line-height 42
|
||||
:font-size 14
|
||||
:color "#9CBFC0"})
|
||||
|
||||
(def discovery-title
|
||||
{:color "#000000de"
|
||||
:align-self :center
|
||||
:text-align :center
|
||||
:font-size 16})
|
||||
|
||||
(def discovery-subtitle
|
||||
{:color color-gray2
|
||||
:fontFamily "sans-serif-medium"
|
||||
:fontSize 14})
|
||||
{:color color-gray2
|
||||
:font-size 14})
|
||||
|
||||
(def section-spacing
|
||||
{:paddingLeft 30
|
||||
:paddingTop 15
|
||||
:paddingBottom 15})
|
||||
{:padding 16})
|
||||
|
||||
(def scroll-view-container
|
||||
{})
|
||||
|
||||
;; discovery_popular.cljs
|
||||
;; Popular
|
||||
|
||||
(def carousel-page-style
|
||||
{:borderRadius 1
|
||||
|
@ -72,91 +66,84 @@
|
|||
:elevation 2
|
||||
:marginBottom 10})
|
||||
|
||||
;; discovery_populat_list.cljs
|
||||
|
||||
(def tag-name
|
||||
{:color "#7099e6"
|
||||
:fontFamily "sans-serif-medium"
|
||||
:fontSize 14
|
||||
:paddingRight 5
|
||||
:paddingBottom 2
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
{:color "#7099e6"
|
||||
:font-size 14
|
||||
:padding-right 5
|
||||
:padding-bottom 2
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def tag-name-container
|
||||
{:flexDirection "column"
|
||||
:backgroundColor "#eef2f5"
|
||||
:borderRadius 5
|
||||
:padding 4})
|
||||
{:flex-direction "column"
|
||||
:background-color "#eef2f5"
|
||||
:border-radius 5
|
||||
:padding 4})
|
||||
|
||||
(def tag-count
|
||||
{:color "#838c93"
|
||||
:fontFamily "sans-serif"
|
||||
:fontSize 12
|
||||
:paddingRight 5
|
||||
:paddingBottom 2
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
{:color "#838c93"
|
||||
:font-size 12
|
||||
:padding-right 5
|
||||
:padding-bottom 2
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def tag-count-container
|
||||
{:flex 0.2
|
||||
:flexDirection "column"
|
||||
:alignItems "flex-end"
|
||||
:paddingTop 10
|
||||
:paddingRight 9})
|
||||
{:flex 0.2
|
||||
:flex-direction "column"
|
||||
:align-items "flex-end"
|
||||
:padding-top 10
|
||||
:padding-right 9})
|
||||
|
||||
(def popular-list-container
|
||||
{:flex 1
|
||||
:backgroundColor :white
|
||||
:paddingLeft 10
|
||||
:paddingTop 16})
|
||||
{:flex 1
|
||||
:background-color :white
|
||||
:padding-left 10
|
||||
:padding-top 16})
|
||||
|
||||
(def popular-list
|
||||
{:backgroundColor :white
|
||||
:paddingTop 13})
|
||||
{:background-color :white
|
||||
:padding-top 13})
|
||||
|
||||
;; discover_popular_list_item.cjls
|
||||
;; Popular list item
|
||||
|
||||
(def popular-list-item
|
||||
{:flexDirection :row
|
||||
:paddingTop 10
|
||||
:paddingBottom 10})
|
||||
{:flex-direction :row
|
||||
:padding-top 10
|
||||
:padding-bottom 10})
|
||||
|
||||
(def popular-list-item-status
|
||||
{:color "black"
|
||||
:fontFamily "sans-serif"
|
||||
:lineHeight 22
|
||||
:fontSize 14})
|
||||
{:color "black"
|
||||
:line-height 22
|
||||
:font-size 14})
|
||||
|
||||
(def popular-list-item-name
|
||||
{:color "black"
|
||||
:fontFamily "sans-serif-medium"
|
||||
:fontSize 14
|
||||
:lineHeight 24})
|
||||
{:color "black"
|
||||
:font-size 14
|
||||
:line-height 24})
|
||||
|
||||
(def popular-list-item-name-container
|
||||
{:flex 0.8
|
||||
:flexDirection "column"})
|
||||
{:flex 0.8
|
||||
:flex-direction "column"})
|
||||
|
||||
(def popular-list-item-avatar-container
|
||||
{:flex 0.2
|
||||
:flexDirection "column"
|
||||
:alignItems :center
|
||||
:paddingTop 5})
|
||||
{:flex 0.2
|
||||
:flex-direction "column"
|
||||
:align-items :center
|
||||
:padding-top 5})
|
||||
|
||||
(def popular-list-item-avatar
|
||||
{:resizeMode "contain"
|
||||
:borderRadius 20
|
||||
:width 40
|
||||
:height 40})
|
||||
{:border-radius 18
|
||||
:width 36
|
||||
:height 36})
|
||||
|
||||
;; discovery_recent
|
||||
|
||||
(def recent-list
|
||||
{:backgroundColor :white
|
||||
:paddingLeft 15})
|
||||
{:background-color :white
|
||||
:padding-left 16})
|
||||
|
||||
;; discovery_tag
|
||||
;; Discovery tag
|
||||
|
||||
(def discovery-tag-container
|
||||
{:flex 1
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
(ns status-im.discovery.tag
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.components.react :refer [view text list-view list-item]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.discovery.views.popular-list-item :refer [popular-list-item]]
|
||||
[status-im.discovery.styles :as st]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [popular-list-item row]))
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.components.react :refer [view text list-view list-item]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]
|
||||
[status-im.discovery.styles :as st]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item [view {:style st/row-separator
|
||||
|
@ -19,22 +16,21 @@
|
|||
[view {:style st/tag-container}
|
||||
[text {:style st/tag-title} (str " #" tag)]]])
|
||||
|
||||
(defn discovery-tag []
|
||||
(let [tag (subscribe [:get :current-tag])
|
||||
discoveries (subscribe [:get-discoveries-by-tag])]
|
||||
(fn []
|
||||
(let [items @discoveries
|
||||
datasource (to-datasource items)]
|
||||
[view st/discovery-tag-container
|
||||
[toolbar {:nav-action {:image {:source {:uri :icon_back}
|
||||
(defview discovery-tag [{platform-specific :platform-specific}]
|
||||
[tag [:get :current-tag]
|
||||
discoveries [:get-discoveries-by-tag]]
|
||||
(let [datasource (to-datasource discoveries)]
|
||||
[view st/discovery-tag-container
|
||||
[toolbar {:nav-action {:image {:source {:uri :icon_back}
|
||||
:style st/icon-back}
|
||||
:handler #(dispatch [:navigate-back])}
|
||||
:custom-content (title-content @tag)
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:custom-content (title-content tag)
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:style st/icon-search}
|
||||
:handler (fn [])}}]
|
||||
|
||||
[list-view {:dataSource datasource
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}]]))))
|
||||
[list-view {:dataSource datasource
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item [discovery-list-item row platform-specific]))
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}]]))
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
(ns status-im.discovery.views.discovery-list-item
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[clojure.string :as str]
|
||||
[status-im.components.react :refer [view text image]]
|
||||
[status-im.discovery.styles :as st]
|
||||
[status-im.utils.identicon :refer [identicon]]
|
||||
[status-im.i18n :refer [label]]))
|
||||
|
||||
(defview discovery-list-item [{:keys [name photo-path status whisper-id]} platform-specific]
|
||||
[{contact-name :name
|
||||
contact-photo-path :photo-path} [:get-in [:contacts whisper-id]]]
|
||||
[view st/popular-list-item
|
||||
[view st/popular-list-item-name-container
|
||||
[text {:style st/popular-list-item-name
|
||||
:platform-specific platform-specific
|
||||
:font :medium
|
||||
:number-of-lines 1}
|
||||
(cond
|
||||
(not (str/blank? contact-name)) contact-name
|
||||
(not (str/blank? name)) name
|
||||
:else (label :t/user-anonymous))]
|
||||
[text {:style st/popular-list-item-status
|
||||
:platform-specific platform-specific
|
||||
:font :default
|
||||
:number-of-lines 2}
|
||||
status]]
|
||||
[view st/popular-list-item-avatar-container
|
||||
[image {:style st/popular-list-item-avatar
|
||||
:source {:uri (cond
|
||||
(not (str/blank? contact-photo-path)) contact-photo-path
|
||||
(not (str/blank? photo-path)) photo-path
|
||||
:else (identicon whisper-id))}}]]])
|
|
@ -13,11 +13,13 @@
|
|||
(defn page-width []
|
||||
(.-width (.get (.. r/react-native -Dimensions) "window")))
|
||||
|
||||
(defview popular []
|
||||
[popular-tags [:get-popular-tags 3]]
|
||||
(defview popular [{:keys [contacts platform-specific]}]
|
||||
[popular-tags [:get-popular-tags 10]]
|
||||
(if (pos? (count popular-tags))
|
||||
[carousel {:pageStyle st/carousel-page-style
|
||||
:sneak 20}
|
||||
[carousel {:pageStyle st/carousel-page-style}
|
||||
(for [{:keys [name count]} popular-tags]
|
||||
[discovery-popular-list name count])]
|
||||
[discovery-popular-list {:tag name
|
||||
:count count
|
||||
:contacts contacts
|
||||
:platform-specific platform-specific}])]
|
||||
[text (label :t/none)]))
|
||||
|
|
|
@ -9,27 +9,28 @@
|
|||
text]]
|
||||
[status-im.discovery.styles :as st]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.discovery.views.popular-list-item :refer [popular-list-item]]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [popular-list-item row]))
|
||||
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item [view {:style st/row-separator
|
||||
:key row-id}]))
|
||||
|
||||
(defview discovery-popular-list [tag count]
|
||||
(defview discovery-popular-list [{:keys [tag count contacts platform-specific]}]
|
||||
[discoveries [:get-discoveries-by-tag tag 3]]
|
||||
[view st/popular-list-container
|
||||
[view st/row
|
||||
[view st/tag-name-container
|
||||
[touchable-highlight {:onPress #(dispatch [:show-discovery-tag tag])}
|
||||
[view
|
||||
[text {:style st/tag-name} (str " #" (name tag))]]]]
|
||||
[text {:style st/tag-name
|
||||
:platform-specific platform-specific
|
||||
:font :medium}
|
||||
(str " #" (name tag))]]]]
|
||||
[view st/tag-count-container
|
||||
[text {:style st/tag-count} count]]]
|
||||
[list-view {:dataSource (to-datasource discoveries)
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/popular-list}]])
|
||||
[text {:style st/tag-count
|
||||
:platform-specific platform-specific
|
||||
:font :default}
|
||||
count]]]
|
||||
(for [{:keys [msg-id] :as discovery} discoveries]
|
||||
^{:key (str "message-" msg-id)}
|
||||
[discovery-list-item discovery platform-specific])])
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
(ns status-im.discovery.views.popular-list-item
|
||||
(:require [status-im.components.react :refer [view text image]]
|
||||
[status-im.discovery.styles :as st]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn popular-list-item
|
||||
[{:keys [name status]}]
|
||||
[view st/popular-list-item
|
||||
[view st/popular-list-item-name-container
|
||||
[text {:style st/popular-list-item-name} name]
|
||||
[text {:style st/popular-list-item-status
|
||||
:numberOfLines 2} status]]
|
||||
[view st/popular-list-item-avatar-container
|
||||
[image {:style st/popular-list-item-avatar
|
||||
:source {:uri :icon_avatar}}]]])
|
|
@ -5,19 +5,15 @@
|
|||
[status-im.components.react :refer [view list-view list-item]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.discovery.styles :as st]
|
||||
[status-im.discovery.views.popular-list-item
|
||||
:refer [popular-list-item]]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [popular-list-item row]))
|
||||
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item [view {:style st/row-separator
|
||||
:key row-id}]))
|
||||
|
||||
(defview discovery-recent []
|
||||
(defview discovery-recent [{platform-specific :platform-specific}]
|
||||
[discoveries [:get :discoveries]]
|
||||
[list-view {:dataSource (to-datasource discoveries)
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}])
|
||||
[view st/recent-list
|
||||
(for [{:keys [msg-id] :as discovery} discoveries]
|
||||
^{:key (str "message-" msg-id)}
|
||||
[discovery-list-item discovery platform-specific])])
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(let [property (db-name db)]
|
||||
(r/write :account
|
||||
(fn []
|
||||
(-> (r/get-by-field :account :chats :chat-id current-chat-id)
|
||||
(-> (r/get-by-field :account :chat :chat-id current-chat-id)
|
||||
(r/single)
|
||||
(aset (name property-name) property)))))))
|
||||
|
||||
|
@ -80,7 +80,7 @@
|
|||
(r/write :account
|
||||
(fn []
|
||||
(r/create :account
|
||||
:chats
|
||||
:chat
|
||||
(update chat :contacts remove-identities selected-participants)
|
||||
true)))))
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
status-im.commands.handlers.jail
|
||||
status-im.qr-scanner.handlers
|
||||
status-im.accounts.handlers
|
||||
status-im.protocol.handlers))
|
||||
status-im.protocol.handlers
|
||||
[status-im.utils.datetime :as time]))
|
||||
|
||||
;; -- Middleware ------------------------------------------------------------
|
||||
;;
|
||||
|
@ -72,7 +73,10 @@
|
|||
(dispatch [:initialize-account-db])
|
||||
(dispatch [:initialize-chats])
|
||||
(dispatch [:load-contacts])
|
||||
(dispatch [:init-chat]))))
|
||||
(dispatch [:init-chat])
|
||||
(dispatch [:init-discoveries])
|
||||
(dispatch [:send-account-update-if-needed])
|
||||
(dispatch [:remove-old-discoveries!]))))
|
||||
|
||||
(register-handler :reset-app
|
||||
(u/side-effect!
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
[status-im.contacts.views.contact-list :refer [contact-list]]
|
||||
[status-im.contacts.views.new-contact :refer [new-contact]]
|
||||
[status-im.qr-scanner.screen :refer [qr-scanner]]
|
||||
[status-im.discovery.screen :refer [discovery]]
|
||||
[status-im.discovery.tag :refer [discovery-tag]]
|
||||
[status-im.chat.screen :refer [chat]]
|
||||
[status-im.accounts.login.screen :refer [login]]
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
(:require [status-im.persistence.realm.core :as r]))
|
||||
|
||||
(defn get-accounts []
|
||||
(-> (r/get-all :base :accounts)
|
||||
(-> (r/get-all :base :account)
|
||||
r/collection->map))
|
||||
|
||||
(defn save-account [update?]
|
||||
#(r/create :base :accounts % update?))
|
||||
#(r/create :base :account % update?))
|
||||
|
||||
(defn save-accounts [accounts update?]
|
||||
(r/write :base #(mapv (save-account update?) accounts)))
|
||||
|
@ -15,7 +15,7 @@
|
|||
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
|
||||
|
||||
(defn accounts-list []
|
||||
(r/get-all :base :accounts))
|
||||
(r/get-all :base :account))
|
||||
|
||||
(defn account-by-address [address]
|
||||
(r/single-cljs (r/get-by-field :base :accounts :address address)))
|
||||
(r/single-cljs (r/get-by-field :base :account :address address)))
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
(defn chat-name-from-contacts [identities]
|
||||
(let [chat-name (->> identities
|
||||
(map (fn [identity]
|
||||
(-> (r/get-by-field :account :contacts :whisper-identity identity)
|
||||
(-> (r/get-by-field :account :contact :whisper-identity identity)
|
||||
(r/single-cljs)
|
||||
:name)))
|
||||
(filter identity)
|
||||
|
@ -25,7 +25,7 @@
|
|||
chat-id))
|
||||
|
||||
(defn chat-exists? [chat-id]
|
||||
(r/exists? :account :chats :chat-id chat-id))
|
||||
(r/exists? :account :chat :chat-id chat-id))
|
||||
|
||||
(defn add-status-message [chat-id]
|
||||
;; TODO Get real status
|
||||
|
@ -42,7 +42,7 @@
|
|||
(defn create-chat
|
||||
([{:keys [last-msg-id] :as chat}]
|
||||
(let [chat (assoc chat :last-msg-id (or last-msg-id ""))]
|
||||
(r/write :account #(r/create :account :chats chat))))
|
||||
(r/write :account #(r/create :account :chat chat))))
|
||||
([db chat-id identities group-chat? chat-name]
|
||||
(when-not (chat-exists? chat-id)
|
||||
(let [chat-name (or chat-name
|
||||
|
@ -52,7 +52,7 @@
|
|||
(fn []
|
||||
(let [contacts (mapv (fn [ident]
|
||||
{:identity ident}) identities)]
|
||||
(r/create :account :chats
|
||||
(r/create :account :chat
|
||||
{:chat-id chat-id
|
||||
:is-active true
|
||||
:name chat-name
|
||||
|
@ -63,7 +63,7 @@
|
|||
(add-status-message chat-id)))))
|
||||
|
||||
(defn chat-contacts [chat-id]
|
||||
(-> (r/get-by-field :account :chats :chat-id chat-id)
|
||||
(-> (r/get-by-field :account :chat :chat-id chat-id)
|
||||
(r/single)
|
||||
(aget "contacts")))
|
||||
|
||||
|
@ -79,7 +79,7 @@
|
|||
(mapv (fn [ident]
|
||||
{:identity ident}))
|
||||
(concat only-old-contacts))]
|
||||
(r/create :account :chats
|
||||
(r/create :account :chat
|
||||
{:chat-id group-id
|
||||
:is-active true
|
||||
:name group-name
|
||||
|
@ -91,18 +91,18 @@
|
|||
(map #(update % :contacts vals) chats))
|
||||
|
||||
(defn chats-list []
|
||||
(-> (r/get-all :account :chats)
|
||||
(-> (r/get-all :account :chat)
|
||||
(r/sorted :timestamp :desc)
|
||||
r/collection->map
|
||||
normalize-contacts))
|
||||
|
||||
(defn chat-by-id [chat-id]
|
||||
(-> (r/get-by-field :account :chats :chat-id chat-id)
|
||||
(-> (r/get-by-field :account :chat :chat-id chat-id)
|
||||
(r/single-cljs)
|
||||
(r/list-to-array :contacts)))
|
||||
|
||||
(defn chat-by-id2 [chat-id]
|
||||
(-> (r/get-by-field :account :chats :chat-id chat-id)
|
||||
(-> (r/get-by-field :account :chat :chat-id chat-id)
|
||||
r/collection->map
|
||||
first))
|
||||
|
||||
|
@ -123,14 +123,14 @@
|
|||
(r/write :account
|
||||
(fn []
|
||||
(let [query (include-query :identity identities)
|
||||
chat (r/single (r/get-by-field :account :chats :chat-id chat-id))]
|
||||
chat (r/single (r/get-by-field :account :chat :chat-id chat-id))]
|
||||
(-> (aget chat "contacts")
|
||||
(r/filtered query)
|
||||
(.forEach (fn [object _ _]
|
||||
(aset object "is-in-chat" false))))))))
|
||||
|
||||
(defn active-group-chats []
|
||||
(let [results (r/filtered (r/get-all :account :chats)
|
||||
(let [results (r/filtered (r/get-all :account :chat)
|
||||
"group-chat = true && is-active = true")]
|
||||
(js->clj (.map results (fn [object _ _]
|
||||
(aget object "chat-id"))))))
|
||||
|
@ -138,6 +138,6 @@
|
|||
(defn set-chat-active [chat-id active?]
|
||||
(r/write :account
|
||||
(fn []
|
||||
(-> (r/get-by-field :account :chats :chat-id chat-id)
|
||||
(-> (r/get-by-field :account :chat :chat-id chat-id)
|
||||
(r/single)
|
||||
(aset "is-active" active?)))))
|
||||
|
|
|
@ -5,18 +5,14 @@
|
|||
exclude-query]]))
|
||||
|
||||
(defn get-contacts []
|
||||
(-> (r/get-all :account :contacts)
|
||||
(-> (r/get-all :account :contact)
|
||||
(r/sorted :name :asc)
|
||||
r/collection->map))
|
||||
|
||||
(defn create-contact [{:keys [name photo-path whisper-identity] :as contact}]
|
||||
(let [contact-from-db (r/get-one-by-field :account :contacts
|
||||
(defn create-contact [{:keys [whisper-identity] :as contact}]
|
||||
(let [contact-from-db (r/get-one-by-field :account :contact
|
||||
:whisper-identity whisper-identity)]
|
||||
(when-not contact-from-db
|
||||
(->> {:name (or name "")
|
||||
:photo-path (or photo-path (identicon whisper-identity))}
|
||||
(merge contact)
|
||||
(r/create :account :contacts)))))
|
||||
(r/create :account :contact contact (if contact-from-db true false))))
|
||||
|
||||
(defn save-contacts [contacts]
|
||||
(r/write :account #(mapv create-contact contacts)))
|
||||
|
@ -25,13 +21,13 @@
|
|||
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
|
||||
|
||||
(defn contacts-list []
|
||||
(r/sorted (r/get-all :account :contacts) :name :asc))
|
||||
(r/sorted (r/get-all :account :contact) :name :asc))
|
||||
|
||||
(defn contacts-list-exclude [exclude-idents]
|
||||
(if (empty? exclude-idents)
|
||||
(contacts-list)
|
||||
(let [query (exclude-query :whisper-identity exclude-idents)]
|
||||
(-> (r/get-all :account :contacts)
|
||||
(-> (r/get-all :account :contact)
|
||||
(r/filtered query)
|
||||
(r/sorted :name :asc)))))
|
||||
|
||||
|
@ -39,9 +35,9 @@
|
|||
(if (empty? include-indents)
|
||||
()
|
||||
(let [query (include-query :whisper-identity include-indents)]
|
||||
(-> (r/get-all :account :contacts)
|
||||
(-> (r/get-all :account :contact)
|
||||
(r/filtered query)
|
||||
(r/sorted :name :asc)))))
|
||||
|
||||
(defn contact-by-identity [identity]
|
||||
(r/single-cljs (r/get-by-field :account :contacts :whisper-identity identity)))
|
||||
(r/single-cljs (r/get-by-field :account :contact :whisper-identity identity)))
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
[chat-id {:keys [delivery-status msg-id content]
|
||||
:or {delivery-status :pending}
|
||||
:as message}]
|
||||
(when-not (r/exists? :account :msgs :msg-id msg-id)
|
||||
(when-not (r/exists? :account :message :msg-id msg-id)
|
||||
(r/write :account
|
||||
(fn []
|
||||
(let [content' (if (string? content)
|
||||
|
@ -41,7 +41,7 @@
|
|||
:content content'
|
||||
:delivery-status delivery-status
|
||||
:timestamp (timestamp)})]
|
||||
(r/create :account :msgs message' true))))))
|
||||
(r/create :account :message message' true))))))
|
||||
|
||||
(defn command-type? [type]
|
||||
(contains?
|
||||
|
@ -51,7 +51,7 @@
|
|||
(defn get-messages
|
||||
([chat-id] (get-messages chat-id 0))
|
||||
([chat-id from]
|
||||
(->> (-> (r/get-by-field :account :msgs :chat-id chat-id)
|
||||
(->> (-> (r/get-by-field :account :message :chat-id chat-id)
|
||||
(r/sorted :timestamp :desc)
|
||||
(r/page from (+ from c/default-number-of-messages))
|
||||
(r/collection->map))
|
||||
|
@ -66,5 +66,5 @@
|
|||
(log/debug "update-message!" msg)
|
||||
(r/write :account
|
||||
(fn []
|
||||
(when (r/exists? :account :msgs :msg-id msg-id)
|
||||
(r/create :account :msgs msg true)))))
|
||||
(when (r/exists? :account :message :msg-id msg-id)
|
||||
(r/create :account :message msg true)))))
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
(:require [status-im.persistence.realm.core :as r]))
|
||||
|
||||
(defn get-requests []
|
||||
(-> (r/get-all :account :requests)
|
||||
(-> (r/get-all :account :request)
|
||||
r/collection->map))
|
||||
|
||||
(defn create-request [request]
|
||||
(r/create :account :requests request true))
|
||||
(r/create :account :request request true))
|
||||
|
||||
(defn save-request [request]
|
||||
(r/write :account
|
||||
|
@ -17,5 +17,5 @@
|
|||
(r/write :account #(mapv create-request requests)))
|
||||
|
||||
(defn requests-list []
|
||||
(r/get-all :account :requests))
|
||||
(r/get-all :account :request))
|
||||
|
||||
|
|
|
@ -1,99 +1,98 @@
|
|||
(ns status-im.persistence.realm.schemas
|
||||
(:require [status-im.components.styles :refer [default-chat-color]]))
|
||||
|
||||
(def base {:schema [{:name :accounts
|
||||
(def base {:schema [{:name :account
|
||||
:primaryKey :address
|
||||
:properties {:address "string"
|
||||
:public-key "string"
|
||||
:name "string"
|
||||
:phone {:type "string" :optional true}
|
||||
:email {:type "string" :optional true}
|
||||
:status {:type "string" :optional true}
|
||||
:photo-path "string"}}
|
||||
{:name :tag
|
||||
:primaryKey :name
|
||||
:properties {:name "string"
|
||||
:count {:type "int"
|
||||
:optional true
|
||||
:default 0}}}
|
||||
{:name :discoveries
|
||||
:primaryKey :whisper-id
|
||||
:properties {:name "string"
|
||||
:status "string"
|
||||
:whisper-id "string"
|
||||
:photo "string"
|
||||
:location "string"
|
||||
:tags {:type "list"
|
||||
:objectType "tag"}
|
||||
:last-updated "date"}}
|
||||
:properties {:address "string"
|
||||
:public-key "string"
|
||||
:name {:type "string" :optional true}
|
||||
:phone {:type "string" :optional true}
|
||||
:email {:type "string" :optional true}
|
||||
:status {:type "string" :optional true}
|
||||
:photo-path "string"
|
||||
:last-updated {:type "int" :default 0}}}
|
||||
{:name :kv-store
|
||||
:primaryKey :key
|
||||
:properties {:key "string"
|
||||
:value "string"}}]
|
||||
:schemaVersion 0})
|
||||
|
||||
(def account {:schema [{:name :contacts
|
||||
:primaryKey :whisper-identity
|
||||
:properties {:phone-number {:type "string"
|
||||
:optional true}
|
||||
:whisper-identity "string"
|
||||
:name {:type "string"
|
||||
:optional true}
|
||||
:photo-path {:type "string"
|
||||
:optinal true}}}
|
||||
{:name :requests
|
||||
:properties {:message-id :string
|
||||
:chat-id :string
|
||||
:type :string
|
||||
:status {:type :string
|
||||
:default "open"}
|
||||
:added :date}}
|
||||
{:name :kv-store
|
||||
:primaryKey :key
|
||||
:properties {:key "string"
|
||||
:value "string"}}
|
||||
{:name :msgs
|
||||
:primaryKey :msg-id
|
||||
:properties {:msg-id "string"
|
||||
:from "string"
|
||||
:to {:type "string"
|
||||
:optional true}
|
||||
:content "string" ;; TODO make it ArrayBuffer
|
||||
:content-type "string"
|
||||
:timestamp "int"
|
||||
:chat-id {:type "string"
|
||||
:indexed true}
|
||||
:outgoing "bool"
|
||||
:delivery-status {:type "string"
|
||||
:optional true}
|
||||
:same-author "bool"
|
||||
:same-direction "bool"
|
||||
:preview {:type :string
|
||||
:optional true}}}
|
||||
{:name :chat-contact
|
||||
:properties {:identity "string"
|
||||
:is-in-chat {:type "bool"
|
||||
:default true}}}
|
||||
{:name :chats
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id "string"
|
||||
:name "string"
|
||||
:color {:type "string"
|
||||
:default default-chat-color}
|
||||
:group-chat {:type "bool"
|
||||
:indexed true}
|
||||
:is-active "bool"
|
||||
:timestamp "int"
|
||||
:contacts {:type "list"
|
||||
:objectType "chat-contact"}
|
||||
:dapp-url {:type :string
|
||||
:optional true}
|
||||
:dapp-hash {:type :int
|
||||
:optional true}
|
||||
:last-msg-id "string"}}
|
||||
{:name :commands
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id "string"
|
||||
:file "string"}}]
|
||||
(def account {:schema [{:name :contact
|
||||
:primaryKey :whisper-identity
|
||||
:properties {:address {:type "string" :optional true}
|
||||
:whisper-identity "string"
|
||||
:name {:type "string" :optional true}
|
||||
:photo-path {:type "string" :optional true}
|
||||
:last-updated {:type "int" :default 0}
|
||||
:last-online {:type "int" :default 0}}}
|
||||
{:name :request
|
||||
:properties {:message-id :string
|
||||
:chat-id :string
|
||||
:type :string
|
||||
:status {:type :string
|
||||
:default "open"}
|
||||
:added :date}}
|
||||
{:name :tag
|
||||
:primaryKey :name
|
||||
:properties {:name "string"
|
||||
:count {:type "int" :optional true :default 0}}}
|
||||
{:name :discovery
|
||||
:primaryKey :msg-id
|
||||
:properties {:msg-id "string"
|
||||
:name {:type "string" :optional true}
|
||||
:status "string"
|
||||
:whisper-id "string"
|
||||
:photo-path {:type "string" :optional true}
|
||||
:tags {:type "list"
|
||||
:objectType "tag"}
|
||||
:priority {:type "int" :default 0}
|
||||
:last-updated "date"}}
|
||||
{:name :kv-store
|
||||
:primaryKey :key
|
||||
:properties {:key "string"
|
||||
:value "string"}}
|
||||
{:name :message
|
||||
:primaryKey :msg-id
|
||||
:properties {:msg-id "string"
|
||||
:from "string"
|
||||
:to {:type "string"
|
||||
:optional true}
|
||||
:content "string" ;; TODO make it ArrayBuffer
|
||||
:content-type "string"
|
||||
:timestamp "int"
|
||||
:chat-id {:type "string"
|
||||
:indexed true}
|
||||
:outgoing "bool"
|
||||
:delivery-status {:type "string"
|
||||
:optional true}
|
||||
:same-author "bool"
|
||||
:same-direction "bool"
|
||||
:preview {:type :string
|
||||
:optional true}}}
|
||||
{:name :chat-contact
|
||||
:properties {:identity "string"
|
||||
:is-in-chat {:type "bool"
|
||||
:default true}}}
|
||||
{:name :chat
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id "string"
|
||||
:name "string"
|
||||
:color {:type "string"
|
||||
:default default-chat-color}
|
||||
:group-chat {:type "bool"
|
||||
:indexed true}
|
||||
:is-active "bool"
|
||||
:timestamp "int"
|
||||
:contacts {:type "list"
|
||||
:objectType "chat-contact"}
|
||||
:dapp-url {:type :string
|
||||
:optional true}
|
||||
:dapp-hash {:type :int
|
||||
:optional true}
|
||||
:last-msg-id "string"}}
|
||||
{:name :command
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id "string"
|
||||
:file "string"}}]
|
||||
:schemaVersion 0})
|
||||
|
||||
|
|
|
@ -4,7 +4,36 @@
|
|||
[status-im.components.react :refer [show-image-picker]]
|
||||
[status-im.utils.image-processing :refer [img->base64]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.handlers :as u]))
|
||||
[status-im.utils.handlers :as u]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn get-hashtags [status]
|
||||
(let [hashtags (map #(subs % 1) (re-seq #"#[^ !?,;:.]+" status))]
|
||||
(or hashtags [])))
|
||||
|
||||
(defn message-user [identity]
|
||||
(when identity
|
||||
(dispatch [:navigate-to :chat identity])))
|
||||
|
||||
(defn update-profile [{name :name
|
||||
email :email
|
||||
photo-path :photo-path
|
||||
status :status}
|
||||
{new-name :name
|
||||
new-email :email
|
||||
new-status :status
|
||||
new-photo-path :photo-path}]
|
||||
(let [new-name (if (or (not new-name) (str/blank? new-name)) name new-name)
|
||||
status-updated? (and (not= new-status nil)
|
||||
(not= status new-status))]
|
||||
(when status-updated?
|
||||
(let [hashtags (get-hashtags new-status)]
|
||||
(when-not (empty? hashtags)
|
||||
(dispatch [:broadcast-status new-status hashtags]))))
|
||||
(dispatch [:account-update {:name new-name
|
||||
:email (or new-email email)
|
||||
:status (or new-status status)
|
||||
:photo-path (or new-photo-path photo-path)}])))
|
||||
|
||||
(register-handler :open-image-picker
|
||||
(u/side-effect!
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
my-profile-icon]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.profile.styles :as st]
|
||||
[status-im.profile.handlers :refer [get-hashtags
|
||||
message-user
|
||||
update-profile]]
|
||||
[status-im.components.qr-code :refer [qr-code]]
|
||||
[status-im.utils.phone-number :refer [format-phone-number
|
||||
valid-mobile-number?]]
|
||||
|
@ -25,32 +28,6 @@
|
|||
[status-im.i18n :refer [label]]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn- get-hashtags [status]
|
||||
(let [hashtags (map #(subs % 1) (re-seq #"#[^ !?,;:.]+" status))]
|
||||
(or hashtags [])))
|
||||
|
||||
(defn- message-user [identity]
|
||||
(when identity
|
||||
(dispatch [:navigate-to :chat identity])))
|
||||
|
||||
(defn- update-profile [{name :name
|
||||
email :email
|
||||
photo-path :photo-path
|
||||
status :status}
|
||||
{new-name :name
|
||||
new-email :email
|
||||
new-status :status
|
||||
new-photo-path :photo-path}]
|
||||
(let [new-name (if (or (not new-name) (str/blank? new-name)) name new-name)
|
||||
status-updated? (and (not= new-status nil)
|
||||
(not= status new-status))]
|
||||
(when status-updated?
|
||||
(dispatch [:broadcast-status new-status (get-hashtags new-status)]))
|
||||
(dispatch [:account-update {:name new-name
|
||||
:email (or new-email email)
|
||||
:status (or new-status status)
|
||||
:photo-path (or new-photo-path photo-path)}])))
|
||||
|
||||
(defview toolbar [{:keys [account profile-edit-data edit?]}]
|
||||
[view
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
|
@ -74,7 +51,8 @@
|
|||
:style st/ok-btn-icon}]
|
||||
[icon :dots st/edit-btn-icon])]]])
|
||||
|
||||
(defview status-image-view [{{:keys [list-selection-fn]} :platform-specific
|
||||
(defview status-image-view [{{:keys [list-selection-fn]
|
||||
:as platform-specific} :platform-specific
|
||||
{address :address
|
||||
username :name} :account
|
||||
photo-path :photo-path
|
||||
|
@ -122,19 +100,35 @@
|
|||
:on-change-text on-change-text}
|
||||
(or value (when-not edit-mode? empty-value))]]])
|
||||
|
||||
(defview profile []
|
||||
[{:keys [name whisper-identity phone-number]} [:contact]]
|
||||
(defview profile [{platform-specific :platform-specific}]
|
||||
[{whisper-identity :whisper-identity
|
||||
address :address
|
||||
username :name
|
||||
email :email
|
||||
photo-path :photo-path
|
||||
phone :phone
|
||||
status :status
|
||||
:as contact} [:contact]]
|
||||
[scroll-view {:style st/profile}
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
:on-press #(dispatch [:navigate-back])}
|
||||
[view st/back-btn-container
|
||||
[icon :back st/back-btn-icon]]]
|
||||
[status-bar {:platform-specific platform-specific}]
|
||||
[view
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
:on-press (fn []
|
||||
(dispatch [:navigate-back]))}
|
||||
[view st/back-btn-container
|
||||
[icon :back st/back-btn-icon]]]
|
||||
[touchable-highlight {:style st/actions-btn-touchable
|
||||
:on-press (fn []
|
||||
(.log js/console "Dots pressed!"))}
|
||||
[view st/actions-btn-container
|
||||
[icon :dots st/edit-btn-icon]]]]
|
||||
|
||||
[status-image-view {:platform-specific platform-specific
|
||||
:account contact
|
||||
:photo-path photo-path
|
||||
:edit? false}]
|
||||
|
||||
[view st/status-block
|
||||
[view st/user-photo-container
|
||||
[profile-icon]]
|
||||
[text {:style st/username} name]
|
||||
;; TODO stub data
|
||||
[text {:style st/status-input} (label :t/not-implemented)]
|
||||
[view st/btns-container
|
||||
[touchable-highlight {:onPress #(message-user whisper-identity)}
|
||||
[view st/message-btn
|
||||
|
@ -144,14 +138,23 @@
|
|||
)}
|
||||
[view st/more-btn
|
||||
[icon :more_vertical_blue st/more-btn-image]]]]]
|
||||
[view st/profile-properties-container
|
||||
[profile-property-view {:name (label :t/username)
|
||||
:value name}]
|
||||
[profile-property-view {:name (label :t/phone-number)
|
||||
:value phone-number}]
|
||||
;; TODO stub data
|
||||
[profile-property-view {:name (label :t/email)
|
||||
:value (label :t/not-implemented)}]
|
||||
|
||||
[scroll-view st/profile-properties-container
|
||||
[profile-property-view {:name (label :t/username)
|
||||
:value (if (not= username address)
|
||||
username)
|
||||
:empty-value (label :t/not-specified)
|
||||
:platform-specific platform-specific}]
|
||||
[profile-property-view {:name (label :t/phone-number)
|
||||
:value (if-not (or (not phone) (str/blank? phone))
|
||||
(format-phone-number phone))
|
||||
:empty-value (label :t/not-specified)
|
||||
:platform-specific platform-specific}]
|
||||
[profile-property-view {:name (label :t/email)
|
||||
:value (if-not (or (not email) (str/blank? email))
|
||||
email)
|
||||
:empty-value (label :t/not-specified)
|
||||
:platform-specific platform-specific}]
|
||||
[view st/report-user-container
|
||||
[touchable-highlight {:on-press (fn []
|
||||
;; TODO not implemented
|
||||
|
@ -180,7 +183,7 @@
|
|||
[status-image-view {:platform-specific platform-specific
|
||||
:account account
|
||||
:photo-path (or new-photo-path photo-path)
|
||||
:status (if (and new-status (not (str/blank? new-status))) new-status status)
|
||||
:status (or new-status status)
|
||||
:edit? edit?}]
|
||||
|
||||
[scroll-view st/profile-properties-container
|
||||
|
@ -205,6 +208,6 @@
|
|||
:profile-data profile-edit-data
|
||||
:platform-specific platform-specific}]
|
||||
[view st/qr-code-container
|
||||
[qr-code {:value (clj->js {:name username
|
||||
:whisper-identity public-key})
|
||||
:size 150}]]]])
|
||||
;; TODO: this public key should be replaced by address
|
||||
[qr-code {:value (str "ethereum:" public-key)
|
||||
:size 220}]]]])
|
||||
|
|
|
@ -45,4 +45,8 @@
|
|||
(dispatch [:participant-left-group from group-id msg-id]))
|
||||
:discover-response (let [{:keys [from payload]} event]
|
||||
(dispatch [:discovery-response-received from payload]))
|
||||
:contact-update (let [{:keys [from payload]} event]
|
||||
(dispatch [:contact-update-received from payload]))
|
||||
:contact-online (let [{:keys [from payload]} event]
|
||||
(dispatch [:contact-online-received from payload]))
|
||||
(log/info "Don't know how to handle" event-type)))})
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.qr-scanner.styles :as st]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.components.styles :as cst]))
|
||||
[status-im.components.styles :as cst]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn qr-scanner-toolbar [title platform-specific]
|
||||
[view
|
||||
|
@ -25,9 +26,10 @@
|
|||
[identifier [:get :current-qr-context]]
|
||||
[view st/barcode-scanner-container
|
||||
[qr-scanner-toolbar (:toolbar-title identifier) platform-specific]
|
||||
[camera {;:on-bar-code-read #(js/alert "ok")
|
||||
:onBarCodeRead #(let [data (json->clj (.-data %))]
|
||||
(dispatch [:set-qr-code identifier data]))
|
||||
[camera {:onBarCodeRead (fn [code]
|
||||
(let [data (-> (.-data code)
|
||||
(str/replace #"ethereum:" ""))]
|
||||
(dispatch [:set-qr-code identifier data])))
|
||||
:style st/barcode-scanner}]
|
||||
[view st/rectangle-container
|
||||
[view st/rectangle
|
||||
|
|
|
@ -20,7 +20,21 @@
|
|||
:members {:one "1 member, 1 active"
|
||||
:other "{{count}} members, {{count}} active"
|
||||
:zero "no members"}
|
||||
:last-active "Active a minute ago"
|
||||
:active-online "online"
|
||||
:active-unknown "unknown"
|
||||
|
||||
;datetime
|
||||
:datetime-second {:one "second"
|
||||
:other "seconds"}
|
||||
:datetime-minute {:one "minute"
|
||||
:other "minutes"}
|
||||
:datetime-hour {:one "hour"
|
||||
:other "hours"}
|
||||
:datetime-day {:one "day"
|
||||
:other "days"}
|
||||
:datetime-multiple "s"
|
||||
:datetime-ago "ago"
|
||||
:datetime-yesterday "yesterday"
|
||||
|
||||
;profile
|
||||
:profile "Profile"
|
||||
|
@ -80,7 +94,6 @@
|
|||
|
||||
;contacts
|
||||
:contacts "Contacts"
|
||||
:no-name "Noname"
|
||||
:new-contact "New Contact"
|
||||
:show-all "SHOW ALL"
|
||||
:contacs-group-dapps "Dapps"
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
(ns status-im.utils.datetime
|
||||
(:require [cljs-time.core :as t :refer [date-time now plus days hours before?]]
|
||||
[cljs-time.coerce :refer [from-long to-long]]
|
||||
[cljs-time.format :as format :refer [formatters
|
||||
formatter
|
||||
unparse]]))
|
||||
[cljs-time.format :refer [formatters
|
||||
formatter
|
||||
unparse]]
|
||||
[status-im.i18n :refer [label label-pluralize]]))
|
||||
|
||||
(def hour (* 1000 60 60))
|
||||
(def day (* hour 24))
|
||||
(def week (* 7 day))
|
||||
(def units [{:name (label :t/datetime-second) :limit 60 :in-second 1}
|
||||
{:name (label :t/datetime-minute) :limit 3600 :in-second 60}
|
||||
{:name (label :t/datetime-hour) :limit 86400 :in-second 3600}
|
||||
{:name (label :t/datetime-day) :limit nil :in-second 86400}])
|
||||
|
||||
(def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60))))
|
||||
|
||||
|
@ -17,8 +26,23 @@
|
|||
yesterday (plus today (days -1))]
|
||||
(cond
|
||||
(before? local yesterday) (unparse (formatter "dd MMM") local)
|
||||
(before? local today) "Yesterday"
|
||||
(before? local today) (label :t/datetime-yesterday)
|
||||
:else (unparse (formatters :hour-minute) local))))
|
||||
|
||||
(defn time-ago [time]
|
||||
(let [diff (t/in-seconds (t/interval time (t/now)))]
|
||||
(if (< diff 60)
|
||||
(label :t/active-online)
|
||||
(let [unit (first (drop-while #(or (>= diff (:limit %))
|
||||
(not (:limit %)))
|
||||
units))]
|
||||
(-> (/ diff (:in-second unit))
|
||||
Math/floor
|
||||
int
|
||||
(#(str % " " (label-pluralize % (:name unit)) " " (label :t/datetime-ago))))))))
|
||||
|
||||
(defn to-date [ms]
|
||||
(from-long ms))
|
||||
|
||||
(defn now-ms []
|
||||
(to-long (now)))
|
||||
|
|
|
@ -55,3 +55,13 @@
|
|||
(if (and (< max (count s)) s)
|
||||
(str (subs s 0 (- max 3)) "...")
|
||||
s))
|
||||
|
||||
(defn first-index
|
||||
[cond coll]
|
||||
(loop [index 0
|
||||
cond cond
|
||||
coll coll]
|
||||
(when (seq coll)
|
||||
(if (cond (first coll))
|
||||
index
|
||||
(recur (inc index) cond (next coll))))))
|
||||
|
|
Loading…
Reference in New Issue