|
@ -25,6 +25,7 @@
|
|||
"identicon.js",
|
||||
"react-native-fs",
|
||||
"react-native-dialogs",
|
||||
"react-native-popup-menu",
|
||||
"react-native-image-resizer",
|
||||
"react-native-image-crop-picker",
|
||||
"react-native-webview-bridge",
|
||||
|
|
After Width: | Height: | Size: 353 B |
After Width: | Height: | Size: 450 B |
After Width: | Height: | Size: 316 B |
After Width: | Height: | Size: 335 B |
After Width: | Height: | Size: 292 B |
After Width: | Height: | Size: 295 B |
After Width: | Height: | Size: 888 B |
After Width: | Height: | Size: 179 B |
After Width: | Height: | Size: 387 B |
After Width: | Height: | Size: 223 B |
After Width: | Height: | Size: 184 B |
After Width: | Height: | Size: 171 B |
After Width: | Height: | Size: 179 B |
After Width: | Height: | Size: 555 B |
After Width: | Height: | Size: 354 B |
After Width: | Height: | Size: 573 B |
After Width: | Height: | Size: 385 B |
After Width: | Height: | Size: 345 B |
After Width: | Height: | Size: 400 B |
After Width: | Height: | Size: 374 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 530 B |
After Width: | Height: | Size: 772 B |
After Width: | Height: | Size: 552 B |
After Width: | Height: | Size: 575 B |
After Width: | Height: | Size: 594 B |
After Width: | Height: | Size: 568 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 762 B |
After Width: | Height: | Size: 991 B |
After Width: | Height: | Size: 787 B |
After Width: | Height: | Size: 814 B |
After Width: | Height: | Size: 856 B |
After Width: | Height: | Size: 780 B |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 170 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_add_blue.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 354 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_back_dark.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 573 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_check_on.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 385 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_hamburger_dark.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/icon_hamburger_dark.png
vendored
Normal file
After Width: | Height: | Size: 345 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_dots_horizontal_dark.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png
vendored
Normal file
After Width: | Height: | Size: 251 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_dots_horizontal_gray.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_dots_horizontal_gray.png
vendored
Normal file
After Width: | Height: | Size: 250 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_search_dark.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/icon_search_dark.imageset/icon_search_dark.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
|
@ -65,6 +65,7 @@
|
|||
"react-native-linear-gradient": "1.5.7",
|
||||
"react-native-network-info": "github:alwx/react-native-network-info",
|
||||
"react-native-orientation": "github:youennPennarun/react-native-orientation",
|
||||
"react-native-popup-menu": "^0.7.1",
|
||||
"react-native-qrcode": "^0.2.2",
|
||||
"react-native-randombytes": "^2.1.0",
|
||||
"react-native-share": "1.0.17",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
splash-screen
|
||||
http-bridge]]
|
||||
[status-im.components.main-tabs :refer [main-tabs]]
|
||||
[status-im.components.context-menu :refer [menu-context]]
|
||||
[status-im.contacts.search-results :refer [contacts-search-results]]
|
||||
[status-im.contacts.views.contact-list :refer [contact-list]]
|
||||
[status-im.contacts.views.new-contact :refer [new-contact]]
|
||||
|
@ -23,8 +24,9 @@
|
|||
[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-private :refer [new-group]]
|
||||
[status-im.new-group.screen-public :refer [new-public-group]]
|
||||
[status-im.new-group.screen-private :refer [new-group contact-group]];; TODO: confusion with names
|
||||
[status-im.new-group.views.contact-list :refer [contact-group-list]]
|
||||
[status-im.participants.views.add :refer [new-participants]]
|
||||
[status-im.participants.views.remove :refer [remove-participants]]
|
||||
[status-im.group-settings.screen :refer [group-settings]]
|
||||
|
@ -33,7 +35,8 @@
|
|||
status-im.data-store.core
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.chat.styles.screen :as st]
|
||||
[status-im.components.styles :as st]
|
||||
[status-im.chat.styles.screen :as chat-st]
|
||||
[status-im.accounts.views.qr-code :refer [qr-code-view]]))
|
||||
|
||||
(defn init-back-button-handler! []
|
||||
|
@ -105,6 +108,8 @@
|
|||
:chat-list main-tabs
|
||||
:new-group new-group
|
||||
:new-public-group new-public-group
|
||||
:contact-group contact-group
|
||||
:contact-group-list contact-group-list
|
||||
:group-settings group-settings
|
||||
:contact-list main-tabs
|
||||
:contact-list-search-results contacts-search-results
|
||||
|
@ -118,12 +123,11 @@
|
|||
:login login
|
||||
:recover recover
|
||||
:my-profile my-profile)]
|
||||
[view
|
||||
{:flex 1}
|
||||
[menu-context st/flex
|
||||
[view st/flex
|
||||
[component]
|
||||
(when @modal-view
|
||||
[view
|
||||
st/chat-modal
|
||||
[view chat-st/chat-modal
|
||||
[modal {:animation-type :slide
|
||||
:transparent false
|
||||
:on-request-close #(dispatch [:navigate-back])}
|
||||
|
@ -132,7 +136,7 @@
|
|||
:qr-code-view qr-code-view
|
||||
:confirm confirm
|
||||
:contact-list-modal contact-list)]
|
||||
[component])]])]))))})))
|
||||
[component])]])]]))))})))
|
||||
|
||||
(defn init []
|
||||
(status/call-module status/init-jail)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.android.platform
|
||||
(:require [status-im.components.styles :as styles]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background2]]))
|
||||
(:require [status-im.components.styles :as styles]))
|
||||
|
||||
(def component-styles
|
||||
{:status-bar {:default {:height 0
|
||||
|
@ -8,7 +7,7 @@
|
|||
:color styles/color-white}
|
||||
:main {:height 0
|
||||
:bar-style "dark-content"
|
||||
:color toolbar-background2}
|
||||
:color styles/color-white}
|
||||
:transparent {:height 20
|
||||
:bar-style "light-content"
|
||||
:translucent? true
|
||||
|
@ -34,8 +33,17 @@
|
|||
:item {:status-text {:color styles/color-black
|
||||
:line-height 22
|
||||
:font-size 14}}}
|
||||
:contacts {:subtitle {:color styles/color-gray2
|
||||
:font-size 14}}
|
||||
:contacts {:subtitle {:color styles/color-gray4
|
||||
:font-size 14}
|
||||
:separator {:height 0}
|
||||
:icon-check {:border-radius 2
|
||||
:width 17
|
||||
:height 17}
|
||||
:group-header {:flexDirection :row
|
||||
:alignItems :center
|
||||
:height 56
|
||||
:padding-top 10
|
||||
:backgroundColor styles/color-light-gray}}
|
||||
:bottom-gradient {:height 3}
|
||||
:input-label {:left 4}
|
||||
:input-error-text {:margin-left 4}
|
||||
|
@ -47,7 +55,8 @@
|
|||
:toolbar-last-activity {:color styles/text2-color
|
||||
:background-color :transparent
|
||||
:top 0
|
||||
:font-size 12}})
|
||||
:font-size 12}
|
||||
:toolbar-title-container {:padding-left 16}})
|
||||
|
||||
(def fonts
|
||||
{:light {:font-family "sans-serif-light"}
|
||||
|
@ -56,7 +65,6 @@
|
|||
|
||||
:toolbar-title {:font-family "sans-serif"}})
|
||||
|
||||
|
||||
;; Dialogs
|
||||
|
||||
(def react-native-dialogs (js/require "react-native-dialogs"))
|
||||
|
|
|
@ -108,8 +108,7 @@
|
|||
[db [_ _ {:keys [handler action params]}]]
|
||||
(assoc db :contacts-click-handler handler
|
||||
:contacts-click-action action
|
||||
:contacts-click-params params
|
||||
:contacts-filter #(not (nil? (:address %)))))
|
||||
:contacts-click-params params))
|
||||
|
||||
(def qr-context {:toolbar-title (label :t/address)})
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
[status-im.commands.utils :refer [reg-handler]]
|
||||
[status-im.constants :refer [console-chat-id wallet-chat-id]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.homoglyph :as h]
|
||||
[status-im.utils.js-resources :as js-res]))
|
||||
[status-im.utils.js-resources :as js-res]
|
||||
[status-im.utils.random :as random]))
|
||||
|
||||
(def commands-js "commands.js")
|
||||
|
||||
|
@ -164,3 +166,28 @@
|
|||
(reg-handler ::clear-commands-callbacks
|
||||
(fn [db [chat-id]]
|
||||
(assoc-in db [::commands-callbacks chat-id] nil)))
|
||||
|
||||
(reg-handler :load-default-contacts!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [chats groups]}]
|
||||
(let [default-contacts js-res/default-contacts
|
||||
default-dapps-group-contacts (mapv #(hash-map :identity (clojure.core/name (first %)))
|
||||
(filter #(true? (:dapp? (second %))) default-contacts))]
|
||||
(doseq [[id {:keys [name photo-path public-key add-chat?
|
||||
dapp? dapp-url dapp-hash]}] default-contacts]
|
||||
(let [id' (clojure.core/name id)]
|
||||
(when-not (chats id')
|
||||
(when add-chat?
|
||||
(dispatch [:add-chat id' {:name (:en name)}]))
|
||||
(dispatch [:add-contacts [{:whisper-identity id'
|
||||
:name (:en name)
|
||||
:photo-path photo-path
|
||||
:public-key public-key
|
||||
:dapp? dapp?
|
||||
:dapp-url (:en dapp-url)
|
||||
:dapp-hash dapp-hash}]]))))
|
||||
(dispatch [:add-groups [{:group-id "dapps"
|
||||
:name (label :t/contacts-group-dapps)
|
||||
:order 0
|
||||
:timestamp (random/timestamp)
|
||||
:contacts default-dapps-group-contacts}]])))))
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
(ns status-im.components.confirm-button
|
||||
(:require [status-im.components.styles :as st]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
touchable-highlight]]))
|
||||
|
||||
(defn confirm-button [label on-press]
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view st/confirm-button
|
||||
[text {:style st/confirm-button-label} label]]])
|
|
@ -0,0 +1,49 @@
|
|||
(ns status-im.components.context-menu
|
||||
(:require [reagent.core :as r]
|
||||
[status-im.components.styles :as st]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.platform :refer [platform-specific ios?]]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[status-im.components.react :refer [view touchable-highlight]]))
|
||||
|
||||
(def react-native-popup-menu (js/require "react-native-popup-menu"))
|
||||
|
||||
(defn get-property [name]
|
||||
(aget react-native-popup-menu name))
|
||||
|
||||
(defn adapt-class [class]
|
||||
(when class
|
||||
(r/adapt-react-class class)))
|
||||
|
||||
(defn get-class [name]
|
||||
(adapt-class (get-property name)))
|
||||
|
||||
(def menu (get-class "Menu"))
|
||||
(def menu-context (get-class "MenuContext"))
|
||||
(def menu-trigger (get-class "MenuTrigger"))
|
||||
(def menu-options (get-class "MenuOptions"))
|
||||
(def menu-option (get-class "MenuOption"))
|
||||
|
||||
(def list-selection-fn (:list-selection-fn platform-specific))
|
||||
|
||||
(defn open-ios-menu [options]
|
||||
(list-selection-fn {:options (mapv :text options)
|
||||
:callback (fn [index]
|
||||
(when (< index (count options))
|
||||
(when-let [handler (:value (nth options index))]
|
||||
(handler))))
|
||||
:cancel-text (label :t/cancel)})
|
||||
nil)
|
||||
|
||||
(defn context-menu [trigger options]
|
||||
(if ios?
|
||||
[touchable-highlight
|
||||
{:on-press #(open-ios-menu options)}
|
||||
[view
|
||||
trigger]]
|
||||
[menu {:onSelect #(when % (do (%) nil))}
|
||||
[menu-trigger trigger]
|
||||
[menu-options st/context-menu
|
||||
(for [option options]
|
||||
^{:key option}
|
||||
[menu-option option])]]))
|
|
@ -85,7 +85,7 @@
|
|||
(assoc :style (merge style font))))]))
|
||||
|
||||
(defn icon
|
||||
([n] (icon n {}))
|
||||
([n] (icon n st/icon-default))
|
||||
([n style]
|
||||
[image {:source {:uri (keyword (str "icon_" (name n)))}
|
||||
:style style}]))
|
||||
|
|
|
@ -8,11 +8,16 @@
|
|||
(def color-gray "#838c93de")
|
||||
(def color-gray2 "#8f838c93")
|
||||
(def color-gray3 "#00000040")
|
||||
(def color-gray4 "#939ba1")
|
||||
(def color-gray5 "#d9dae1")
|
||||
(def color-steel "#838b91")
|
||||
(def color-white "white")
|
||||
(def color-light-blue-transparent "#bbc4cb32")
|
||||
(def color-light-blue "#628fe3")
|
||||
(def color-light-blue2 "#eff3fc")
|
||||
(def color-light-gray "#EEF2F5")
|
||||
(def color-red "red")
|
||||
(def color-light-red "#e86363")
|
||||
|
||||
(def color-separator "#D6D6D6")
|
||||
|
||||
(def text1-color color-black)
|
||||
|
@ -23,15 +28,16 @@
|
|||
(def new-messages-count-color color-blue-transparent)
|
||||
(def chat-background color-light-gray)
|
||||
(def selected-message-color "#E4E9ED")
|
||||
(def separator-color "#0000001f")
|
||||
(def selected-contact-color color-light-blue2)
|
||||
(def separator-color color-gray4)
|
||||
(def default-chat-color color-purple)
|
||||
|
||||
(def flex
|
||||
{:flex 1})
|
||||
|
||||
(def icon-search
|
||||
{:width 17
|
||||
:height 17})
|
||||
{:width 24
|
||||
:height 24})
|
||||
|
||||
(def create-icon
|
||||
{:fontSize 20
|
||||
|
@ -39,8 +45,12 @@
|
|||
:color :white})
|
||||
|
||||
(def icon-back
|
||||
{:width 8
|
||||
:height 14})
|
||||
{:width 24
|
||||
:height 24})
|
||||
|
||||
(def icon-default
|
||||
{:width 24
|
||||
:height 24})
|
||||
|
||||
(def icon-add
|
||||
{:width 14
|
||||
|
@ -78,3 +88,25 @@
|
|||
(def button-input
|
||||
{:flex 1
|
||||
:flexDirection :column})
|
||||
|
||||
(def confirm-button
|
||||
{:flex-direction :row
|
||||
:height 52
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color color-light-blue})
|
||||
|
||||
(def confirm-button-label
|
||||
{:color color-white
|
||||
:font-size 17
|
||||
:line-height 20
|
||||
:letter-spacing -0.2})
|
||||
|
||||
(def context-menu
|
||||
{:customStyles {:optionsContainer {:padding-top 8
|
||||
:padding-bottom 8}
|
||||
:optionWrapper {:padding-left 16
|
||||
:justify-content :center
|
||||
:height 48}
|
||||
:text {:font-size 15
|
||||
:line-height 20}}})
|
||||
|
|
|
@ -3,29 +3,34 @@
|
|||
|
||||
(def nothing
|
||||
{:image {:source nil
|
||||
:style st/action-search}})
|
||||
:style st/action-default}})
|
||||
|
||||
(defn hamburger [handler]
|
||||
{:image {:source {:uri :icon_hamburger}
|
||||
:style st/action-hamburger}
|
||||
{:image {:source {:uri :icon_hamburger_dark}
|
||||
:style st/action-default}
|
||||
:handler handler})
|
||||
|
||||
(defn add [handler]
|
||||
{:image {:source {:uri :icon_add}
|
||||
:style st/action-add}
|
||||
:style st/action-default}
|
||||
:handler handler})
|
||||
|
||||
(defn opts [handler]
|
||||
{:image {:source {:uri :icon_options_dark}
|
||||
:style st/action-default}
|
||||
:handler handler})
|
||||
|
||||
(defn search [handler]
|
||||
{:image {:source {:uri :icon_search}
|
||||
:style st/action-search}
|
||||
{:image {:source {:uri :icon_search_dark}
|
||||
:style st/action-default}
|
||||
:handler handler})
|
||||
|
||||
(defn back [handler]
|
||||
{:image {:source {:uri :icon_back}
|
||||
:style st/action-back}
|
||||
{:image {:source {:uri :icon_back_dark}
|
||||
:style st/action-default}
|
||||
:handler handler})
|
||||
|
||||
(defn back-white [handler]
|
||||
{:image {:source {:uri :icon_back_white}
|
||||
:style st/action-back}
|
||||
:style st/action-default}
|
||||
:handler handler})
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
(:require [status-im.components.styles :refer [text1-color
|
||||
color-white
|
||||
color-light-gray
|
||||
color-gray5
|
||||
color-blue
|
||||
color-black]]))
|
||||
color-black]]
|
||||
[status-im.utils.platform :as p]))
|
||||
|
||||
(def toolbar-background1 color-white)
|
||||
(def toolbar-background2 color-light-gray)
|
||||
|
||||
(def toolbar-height 56)
|
||||
(def toolbar-icon-width 32)
|
||||
(def toolbar-icon-spacing 8)
|
||||
(def toolbar-icon-width 24)
|
||||
(def toolbar-icon-spacing 24)
|
||||
|
||||
(def toolbar-gradient
|
||||
{:height 4})
|
||||
|
@ -23,6 +25,11 @@
|
|||
{:flex-direction :row
|
||||
:height toolbar-height})
|
||||
|
||||
(def toolbar-line
|
||||
{:height 1
|
||||
:background-color color-gray5
|
||||
:opacity 0.4})
|
||||
|
||||
(defn toolbar-nav-actions-container [actions]
|
||||
{:width (when (and actions (> (count actions) 0))
|
||||
(-> (+ toolbar-icon-width toolbar-icon-spacing)
|
||||
|
@ -38,9 +45,9 @@
|
|||
:padding-right 12})
|
||||
|
||||
(def toolbar-title-container
|
||||
(merge (get-in p/platform-specific [:component-styles :toolbar-title-container])
|
||||
{:flex 1
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
:justifyContent :center}))
|
||||
|
||||
(def toolbar-title-text
|
||||
{:margin-top 0
|
||||
|
@ -61,12 +68,11 @@
|
|||
:justify-content :center})
|
||||
|
||||
(def toolbar-with-search
|
||||
{:background-color toolbar-background2
|
||||
{:background-color toolbar-background1
|
||||
:elevation 0})
|
||||
|
||||
(def toolbar-with-search-content
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def toolbar-search-input
|
||||
|
@ -79,25 +85,8 @@
|
|||
|
||||
(def toolbar-with-search-title
|
||||
{:color color-black
|
||||
:align-self :center
|
||||
:text-align :center
|
||||
:font-size 16})
|
||||
|
||||
|
||||
;; Specific actions
|
||||
|
||||
(def action-hamburger
|
||||
{:width 16
|
||||
:height 12})
|
||||
|
||||
(def action-add
|
||||
{:width 17
|
||||
:height 17})
|
||||
|
||||
(def action-search
|
||||
{:width 17
|
||||
:height 17})
|
||||
|
||||
(def action-back
|
||||
{:width 8
|
||||
:height 14})
|
||||
(def action-default
|
||||
{:width 24
|
||||
:height 24})
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
image
|
||||
touchable-highlight]]
|
||||
[status-im.components.sync-state.gradient :refer [sync-state-gradient-view]]
|
||||
[status-im.components.styles :refer [icon-back
|
||||
[status-im.components.styles :refer [icon-default
|
||||
icon-search]]
|
||||
[status-im.components.toolbar.actions :as act]
|
||||
[status-im.components.toolbar.styles :as st]
|
||||
|
@ -34,8 +34,8 @@
|
|||
[touchable-highlight {:on-press #(dispatch [:navigate-back])
|
||||
:accessibility-label id/toolbar-back-button}
|
||||
[view (get-in platform-specific [:component-styles :toolbar-nav-action])
|
||||
[image {:source {:uri :icon_back}
|
||||
:style icon-back}]]]))]
|
||||
[image {:source {:uri :icon_back_dark}
|
||||
:style icon-default}]]]))]
|
||||
(or custom-content
|
||||
[view {:style st/toolbar-title-container}
|
||||
[text {:style st/toolbar-title-text
|
||||
|
@ -50,7 +50,8 @@
|
|||
[view st/toolbar-action
|
||||
[image action-image]]])
|
||||
custom-action)]]
|
||||
[sync-state-gradient-view]]))
|
||||
[sync-state-gradient-view]
|
||||
[view st/toolbar-line]]))
|
||||
|
||||
(defn- toolbar-search-submit [on-search-submit]
|
||||
(let [text @(subscribe [:get-in [:toolbar-search :text]])]
|
||||
|
@ -67,10 +68,7 @@
|
|||
{:style st/toolbar-search-input
|
||||
:auto-focus true
|
||||
:placeholder search-placeholder
|
||||
:return-key-type "search"
|
||||
:on-blur #(dispatch [:set-in [:toolbar-search :show] nil])
|
||||
:on-change-text #(dispatch [:set-in [:toolbar-search :text] %])
|
||||
:on-submit-editing #(toolbar-search-submit on-search-submit)}]
|
||||
:on-change-text #(dispatch [:set-in [:toolbar-search :text] %])}]
|
||||
[view
|
||||
[text {:style st/toolbar-with-search-title
|
||||
:font :toolbar-title}
|
||||
|
@ -83,9 +81,11 @@
|
|||
style
|
||||
on-search-submit]
|
||||
:as opts}]
|
||||
(let [toggle-search-fn #(dispatch [:set-in [:toolbar-search :show] %])
|
||||
(let [toggle-search-fn #(do
|
||||
(dispatch [:set-in [:toolbar-search :show] %])
|
||||
(dispatch [:set-in [:toolbar-search :text] ""]))
|
||||
actions (if-not show-search?
|
||||
(into actions [(act/search #(toggle-search-fn search-key))]))]
|
||||
(into [(act/search #(toggle-search-fn search-key))] actions))]
|
||||
[toolbar {:style (merge st/toolbar-with-search style)
|
||||
:nav-action (if show-search?
|
||||
(act/back #(toggle-search-fn nil))
|
||||
|
|
|
@ -17,12 +17,24 @@
|
|||
[status-im.utils.js-resources :as js-res]))
|
||||
|
||||
(defmethod nav/preload-data! :group-contacts
|
||||
[db [_ _ group show-search?]]
|
||||
(-> db
|
||||
(assoc :contacts-group group)
|
||||
(update :toolbar-search assoc
|
||||
:show (when show-search? :contact-list)
|
||||
:text "")))
|
||||
|
||||
(defmethod nav/preload-data! :contact-group
|
||||
[db [_ _ group]]
|
||||
(dissoc
|
||||
(if group
|
||||
(assoc db :contacts-group group)
|
||||
db)
|
||||
:contacts-filter))
|
||||
(-> db
|
||||
(assoc :contact-group group
|
||||
:selected-contacts (into #{} (map :identity (:contacts group)))
|
||||
:new-chat-name (:name group))
|
||||
(update :toolbar-search assoc
|
||||
:show :contact-list
|
||||
:text ""))
|
||||
db))
|
||||
|
||||
(defmethod nav/preload-data! :new-group
|
||||
[db _]
|
||||
|
@ -34,8 +46,7 @@
|
|||
[db [_ _ click-handler]]
|
||||
(-> db
|
||||
(assoc-in [:toolbar-search :show] nil)
|
||||
(assoc :contacts-click-handler click-handler
|
||||
:contacts-filter nil)))
|
||||
(assoc :contacts-click-handler click-handler)))
|
||||
|
||||
(register-handler :remove-contacts-click-handler
|
||||
(fn [db]
|
||||
|
@ -167,16 +178,15 @@
|
|||
(defn save-contacts! [{:keys [new-contacts]} _]
|
||||
(contacts/save-all new-contacts))
|
||||
|
||||
(defn update-pending-status [old-contacts {:keys [whisper-identity pending] :as contact}]
|
||||
(let [{old-pending :pending
|
||||
:as old-contact} (get old-contacts whisper-identity)]
|
||||
(if old-contact
|
||||
(assoc contact :pending (and old-pending pending))
|
||||
(assoc contact :pending pending))))
|
||||
(defn update-pending-status [old-contacts {:keys [whisper-identity pending?] :as contact}]
|
||||
(let [{old-pending :pending?
|
||||
:as old-contact} (get old-contacts whisper-identity)
|
||||
pending?' (if old-contact (and old-pending pending?) pending?)]
|
||||
(assoc contact :pending? (boolean pending?'))))
|
||||
|
||||
(defn add-new-contacts
|
||||
[{:keys [contacts] :as db} [_ new-contacts]]
|
||||
(let [identities (set (map :whisper-identity contacts))
|
||||
(let [identities (set (keys contacts))
|
||||
new-contacts' (->> new-contacts
|
||||
(map #(update-pending-status contacts %))
|
||||
(remove #(identities (:whisper-identity %)))
|
||||
|
@ -245,7 +255,7 @@
|
|||
(fn [{:keys [chats contacts]} [_ chat-id]]
|
||||
(let [contact (if-let [contact-info (get-in chats [chat-id :contact-info])]
|
||||
(read-string contact-info)
|
||||
(assoc (get contacts chat-id) :pending false))
|
||||
(assoc (get contacts chat-id) :pending? false))
|
||||
contact' (assoc contact :address (public-key->address chat-id))]
|
||||
(dispatch [::prepare-contact contact'])
|
||||
(dispatch [:watch-contact contact'])
|
||||
|
@ -283,6 +293,8 @@
|
|||
(let [{{:keys [public private]} :keypair
|
||||
timestamp :timestamp} payload
|
||||
prev-last-updated (get-in db [:contacts from :keys-last-updated])]
|
||||
|
||||
|
||||
(when (<= prev-last-updated timestamp)
|
||||
(let [contact {:whisper-identity from
|
||||
:public-key public
|
||||
|
@ -305,9 +317,19 @@
|
|||
(after stop-watching-contact)
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [whisper-identity] :as contact}]]
|
||||
(dispatch [:update-contact! (assoc contact :pending true)])
|
||||
(dispatch [:update-contact! (assoc contact :pending? true)])
|
||||
(dispatch [:account-update-keys]))))
|
||||
|
||||
(defn remove-contact-from-group [whisper-identity]
|
||||
(fn [contacts]
|
||||
(remove #(= whisper-identity (:identity %)) contacts)))
|
||||
|
||||
(register-handler :remove-contact-from-group
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [whisper-identity]} group]]
|
||||
(let [group' (update group :contacts (remove-contact-from-group whisper-identity))]
|
||||
(dispatch [:update-group group'])))))
|
||||
|
||||
(register-handler :remove-contact
|
||||
(fn [db [_ whisper-identity pred]]
|
||||
(if-let [contact (contacts/get-by-id whisper-identity)]
|
||||
|
@ -329,3 +351,14 @@
|
|||
0 (dispatch [:hide-contact contact])
|
||||
:default))
|
||||
:cancel-text (label :t/cancel)}))))
|
||||
|
||||
(register-handler
|
||||
:open-contact-group-list
|
||||
(after #(dispatch [:navigate-to :contact-group-list]))
|
||||
(fn [db _]
|
||||
(->
|
||||
(assoc db :contact-group nil
|
||||
:selected-contacts #{}
|
||||
:new-chat-name "")
|
||||
(assoc-in [:toolbar-search :show] nil)
|
||||
(assoc-in [:toolbar-search :text] ""))))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
[status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight
|
||||
linear-gradient
|
||||
scroll-view
|
||||
|
@ -14,10 +15,12 @@
|
|||
[status-im.components.action-button :refer [action-button
|
||||
action-button-item]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar.view :refer [toolbar-with-search]]
|
||||
[status-im.components.toolbar.view :refer [toolbar-with-search toolbar]]
|
||||
[status-im.components.toolbar.actions :as act]
|
||||
[status-im.components.toolbar.styles :as tst]
|
||||
[status-im.components.drawer.view :refer [open-drawer]]
|
||||
[status-im.components.icons.custom-icons :refer [ion-icon]]
|
||||
[status-im.components.context-menu :refer [context-menu]]
|
||||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.utils.platform :refer [platform-specific]]
|
||||
[status-im.i18n :refer [label]]
|
||||
|
@ -25,30 +28,45 @@
|
|||
[status-im.components.styles :refer [color-blue
|
||||
create-icon]]))
|
||||
|
||||
(def contacts-limit 50)
|
||||
(def contacts-limit 5)
|
||||
|
||||
(defn toolbar-view [show-search?]
|
||||
(let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])
|
||||
actions (if new-contact?
|
||||
[(act/add #(dispatch [:navigate-to :new-contact]))])]
|
||||
(toolbar-with-search
|
||||
{:show-search? show-search?
|
||||
:search-key :contact-list
|
||||
(def toolbar-options
|
||||
[{:text (label :t/new-contact) :value #(dispatch [:navigate-to :new-contact])}
|
||||
{:text (label :t/edit) :value #(dispatch [:set-in [:contacts-ui-props :edit?] true])}
|
||||
{:text (label :t/new-group) :value #(dispatch [:open-contact-group-list])}])
|
||||
|
||||
(defn toolbar-actions []
|
||||
(let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])]
|
||||
[view st/toolbar-actions
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:navigate-to :group-contacts nil :show-search])}
|
||||
[view st/search-btn
|
||||
[icon :search_dark]]]
|
||||
[view st/more-btn
|
||||
[context-menu
|
||||
[icon :options_dark]
|
||||
(if new-contact? toolbar-options (rest toolbar-options))]]]))
|
||||
|
||||
(defn toolbar-view []
|
||||
[toolbar {:style tst/toolbar-with-search
|
||||
:title (label :t/contacts)
|
||||
:search-placeholder (label :t/search-for)
|
||||
:nav-action (act/hamburger open-drawer)
|
||||
:actions actions
|
||||
:on-search-submit (fn [text]
|
||||
(when-not (str/blank? text)
|
||||
(dispatch [:set :contacts-filter #(let [name (-> (or (:name %) "")
|
||||
(str/lower-case))
|
||||
text (str/lower-case text)]
|
||||
(not= (.indexOf name text) -1))])
|
||||
(dispatch [:set :contact-list-search-text text])
|
||||
(dispatch [:navigate-to :contact-list-search-results])))})))
|
||||
:custom-action (toolbar-actions)}])
|
||||
|
||||
(defn subtitle-view [subtitle contacts-count]
|
||||
[view st/contact-group-header-inner
|
||||
(defn toolbar-edit []
|
||||
[toolbar {:style tst/toolbar-with-search
|
||||
:nav-action (act/back #(dispatch [:set-in [:contacts-ui-props :edit?] false]))
|
||||
:title (label :t/edit-contacts)}])
|
||||
|
||||
(defn options-btn [group]
|
||||
(let [options [{:value #(dispatch [:navigate-to :contact-group group]) :text (label :t/edit-group)}]]
|
||||
[view st/more-btn
|
||||
[context-menu
|
||||
[icon :options_gray]
|
||||
options]]))
|
||||
|
||||
(defn subtitle-view [subtitle contacts-count group extended?]
|
||||
[view (get-in platform-specific [:component-styles :contacts :group-header])
|
||||
[text {:style (merge st/contact-group-subtitle
|
||||
(get-in platform-specific [:component-styles :contacts :subtitle]))
|
||||
:uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?])
|
||||
|
@ -58,7 +76,9 @@
|
|||
(get-in platform-specific [:component-styles :contacts :subtitle]))
|
||||
:uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?])
|
||||
:font :medium}
|
||||
(str contacts-count)]])
|
||||
(str contacts-count)]
|
||||
(when extended?
|
||||
[options-btn group])])
|
||||
|
||||
(defn group-top-view []
|
||||
[linear-gradient {:style st/contact-group-header-gradient-bottom
|
||||
|
@ -68,37 +88,47 @@
|
|||
[linear-gradient {:style st/contact-group-header-gradient-top
|
||||
:colors st/contact-group-header-gradient-top-colors}])
|
||||
|
||||
(defn line-view []
|
||||
[view {:style {:background-color "#D7D7D7"
|
||||
:height 1}}])
|
||||
(defn on-scroll-animation [e show-toolbar-shadow?]
|
||||
(let [offset (.. e -nativeEvent -contentOffset -y)]
|
||||
(reset! show-toolbar-shadow? (pos? offset))))
|
||||
|
||||
(defn contact-group-view [contacts contacts-count subtitle group click-handler]
|
||||
(let [shadows? (get-in platform-specific [:contacts :group-block-shadows?])]
|
||||
(defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}]
|
||||
(let [shadows? (get-in platform-specific [:contacts :group-block-shadows?])
|
||||
subtitle (:name group)]
|
||||
[view st/contact-group
|
||||
[view st/contact-group-header
|
||||
[subtitle-view subtitle contacts-count]]
|
||||
(if shadows?
|
||||
[group-top-view]
|
||||
[line-view])
|
||||
(when subtitle
|
||||
[subtitle-view subtitle contacts-count group edit?])
|
||||
(when (and subtitle shadows?)
|
||||
[group-top-view])
|
||||
[view
|
||||
(doall
|
||||
(map (fn [contact]
|
||||
^{:key contact}
|
||||
[contact-view {:contact contact
|
||||
:extended? true
|
||||
:on-click click-handler
|
||||
:more-on-click nil}])
|
||||
[contact-view
|
||||
{:contact contact
|
||||
:extended? edit?
|
||||
:on-click (when-not edit? click-handler)
|
||||
:extend-options (when group
|
||||
[{:value #(dispatch [:hide-contact contact])
|
||||
:text (label :t/delete-contact)}
|
||||
{:value #(dispatch [:remove-contact-from-group contact group])
|
||||
:text (label :t/remove-from-group)}])}])
|
||||
contacts))]
|
||||
(when (<= contacts-limit (count contacts))
|
||||
(when (< contacts-limit contacts-count)
|
||||
[view st/show-all
|
||||
[touchable-highlight {:on-press #(dispatch [:navigate-to :group-contacts group])}
|
||||
[touchable-highlight (when-not edit? {:on-press #(dispatch [:navigate-to :group-contacts group])})
|
||||
[view
|
||||
[text {:style st/show-all-text
|
||||
:font :medium}
|
||||
(label :t/show-all)]]]])
|
||||
(if shadows?
|
||||
[group-bottom-view]
|
||||
[line-view])]))
|
||||
(str (- contacts-count contacts-limit) " " (label :t/more))]]]])
|
||||
(when shadows?
|
||||
[group-bottom-view])]))
|
||||
|
||||
(defview contact-group-view [{:keys [group] :as params}]
|
||||
[contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit]
|
||||
contacts-count [:all-added-group-contacts-count (:group-id group)]]
|
||||
[contact-group-form (merge params {:contacts contacts
|
||||
:contacts-count contacts-count})])
|
||||
|
||||
(defn contacts-action-button []
|
||||
[action-button {:button-color color-blue
|
||||
|
@ -113,44 +143,35 @@
|
|||
[ion-icon {:name :md-create
|
||||
:style create-icon}]]])
|
||||
|
||||
(defn contact-list [_]
|
||||
(let [peoples (subscribe [:get-added-people-with-limit contacts-limit])
|
||||
dapps (subscribe [:get-added-dapps-with-limit contacts-limit])
|
||||
people-count (subscribe [:added-people-count])
|
||||
dapps-count (subscribe [:added-dapps-count])
|
||||
click-handler (subscribe [:get :contacts-click-handler])
|
||||
show-search (subscribe [:get-in [:toolbar-search :show]])
|
||||
(defview contact-list [current-view?]
|
||||
[contacts [:get-added-contacts-with-limit contacts-limit]
|
||||
contacts-count [:added-contacts-count]
|
||||
click-handler [:get :contacts-click-handler]
|
||||
edit? [:get-in [:contacts-ui-props :edit?]]
|
||||
groups [:all-added-groups]
|
||||
show-toolbar-shadow? (r/atom false)]
|
||||
(fn [current-view?]
|
||||
[view st/contacts-list-container
|
||||
[toolbar-view (and current-view?
|
||||
(= @show-search :contact-list))]
|
||||
[view {:style st/toolbar-shadow}
|
||||
(if edit?
|
||||
[toolbar-edit]
|
||||
[toolbar-view])
|
||||
(when @show-toolbar-shadow?
|
||||
[linear-gradient {:style st/contact-group-header-gradient-bottom
|
||||
:colors st/contact-group-header-gradient-bottom-colors}])]
|
||||
(if (pos? (+ @dapps-count @people-count))
|
||||
:colors st/contact-group-header-gradient-bottom-colors}])
|
||||
(if (pos? (+ (count groups) contacts-count))
|
||||
[scroll-view {:style st/contact-groups
|
||||
:onScroll (fn [e]
|
||||
(let [offset (.. e -nativeEvent -contentOffset -y)]
|
||||
(reset! show-toolbar-shadow?
|
||||
(<= st/contact-group-header-height offset))))}
|
||||
(when (pos? @dapps-count)
|
||||
[contact-group-view
|
||||
@dapps
|
||||
@dapps-count
|
||||
(label :t/contacts-group-dapps)
|
||||
:dapps
|
||||
@click-handler])
|
||||
(when (pos? @people-count)
|
||||
[contact-group-view
|
||||
@peoples
|
||||
@people-count
|
||||
(label :t/contacts-group-people)
|
||||
:people
|
||||
@click-handler])]
|
||||
:onScroll #(on-scroll-animation % show-toolbar-shadow?)}
|
||||
(when (pos? contacts-count)
|
||||
[contact-group-form {:contacts contacts
|
||||
:contacts-count contacts-count
|
||||
:edit? edit?
|
||||
:click-handler click-handler}])
|
||||
(for [group groups]
|
||||
^{:key group}
|
||||
[contact-group-view {:group group
|
||||
:edit? edit?
|
||||
:click-handler click-handler}])]
|
||||
[view st/empty-contact-groups
|
||||
[react/icon :group_big st/empty-contacts-icon]
|
||||
[text {:style st/empty-contacts-text} (label :t/no-contacts)]])
|
||||
(when (get-in platform-specific [:contacts :action-button?])
|
||||
[contacts-action-button])])))
|
||||
(when (and (not edit?) (get-in platform-specific [:contacts :action-button?]))
|
||||
[contacts-action-button])])
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
color-separator
|
||||
color-gray2
|
||||
color-gray]]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background2]]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background1 toolbar-background2]]
|
||||
[status-im.utils.platform :as p]))
|
||||
|
||||
;; Contacts list
|
||||
|
@ -15,6 +15,9 @@
|
|||
{:height 2
|
||||
:background-color toolbar-background2})
|
||||
|
||||
(def toolbar-actions
|
||||
{:flex-direction :row})
|
||||
|
||||
(def contact-groups
|
||||
{:flex 1
|
||||
:background-color toolbar-background2})
|
||||
|
@ -43,22 +46,13 @@
|
|||
(def contact-group
|
||||
{:flex-direction :column})
|
||||
|
||||
(def contact-group-header
|
||||
{:flex-direction :column
|
||||
:background-color toolbar-background2})
|
||||
|
||||
(def contact-group-header-inner
|
||||
{:flexDirection :row
|
||||
:alignItems :center
|
||||
:height 48
|
||||
:backgroundColor toolbar-background2})
|
||||
|
||||
(def contact-group-subtitle
|
||||
{:flex 1
|
||||
:margin-left 16})
|
||||
{:margin-left 16})
|
||||
|
||||
(def contact-group-count
|
||||
{:margin-right 14})
|
||||
{:flex 1
|
||||
:margin-left 8
|
||||
:opacity 0.6})
|
||||
|
||||
(def contact-group-header-gradient-top
|
||||
{:flexDirection :row
|
||||
|
@ -79,9 +73,6 @@
|
|||
["rgba(24, 52, 76, 0.01)"
|
||||
"rgba(24, 52, 76, 0.05)"])
|
||||
|
||||
(def contact-group-header-height (+ (:height contact-group-header-inner)
|
||||
(:height contact-group-header-gradient-bottom)))
|
||||
|
||||
(def show-all
|
||||
{:flexDirection :row
|
||||
:alignItems :center
|
||||
|
@ -95,6 +86,9 @@
|
|||
;; ios only:
|
||||
:letterSpacing 0.5})
|
||||
|
||||
(def contact-separator-container
|
||||
{:background-color color-white})
|
||||
|
||||
(def contact-container
|
||||
{:flex-direction :row
|
||||
:background-color color-white})
|
||||
|
@ -167,14 +161,18 @@
|
|||
:color text2-color})
|
||||
|
||||
(def more-btn
|
||||
{:width 56
|
||||
{:width 24
|
||||
:height 56
|
||||
:margin-right 14
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def more-btn-icon
|
||||
{:width 4
|
||||
:height 16})
|
||||
(def search-btn
|
||||
{:width 24
|
||||
:height 56
|
||||
:margin-right 24
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
; New contact
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.contacts.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub subscribe]]
|
||||
[status-im.utils.identicon :refer [identicon]]))
|
||||
[status-im.utils.identicon :refer [identicon]]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(register-sub :current-contact
|
||||
(fn [db [_ k]]
|
||||
|
@ -29,47 +30,66 @@
|
|||
(sort-contacts)
|
||||
(reaction)))))
|
||||
|
||||
(register-sub :all-added-people
|
||||
(fn []
|
||||
(let [contacts (subscribe [:all-added-contacts])]
|
||||
(reaction (remove :dapp? @contacts)))))
|
||||
(register-sub :all-added-group-contacts
|
||||
(fn [db [_ group-id]]
|
||||
(let [contacts (subscribe [:all-added-contacts])
|
||||
group-contacts (reaction (into #{} (map #(:identity %)
|
||||
(get-in @db [:contact-groups group-id :contacts]))))]
|
||||
(reaction (filter #(@group-contacts (:whisper-identity %)) @contacts)))))
|
||||
|
||||
(register-sub :all-added-dapps
|
||||
(fn []
|
||||
(let [contacts (subscribe [:all-added-contacts])]
|
||||
(reaction (filter :dapp? @contacts)))))
|
||||
|
||||
(register-sub :get-added-people-with-limit
|
||||
(fn [_ [_ limit]]
|
||||
(let [contacts (subscribe [:all-added-people])]
|
||||
(register-sub :all-added-group-contacts-with-limit
|
||||
(fn [db [_ group-id limit]]
|
||||
(let [contacts (subscribe [:all-added-group-contacts group-id])]
|
||||
(reaction (take limit @contacts)))))
|
||||
|
||||
(register-sub :get-added-dapps-with-limit
|
||||
(register-sub :all-added-group-contacts-count
|
||||
(fn [_ [_ group-id]]
|
||||
(let [contacts (subscribe [:all-added-group-contacts group-id])]
|
||||
(reaction (count @contacts)))))
|
||||
|
||||
(register-sub :get-added-contacts-with-limit
|
||||
(fn [_ [_ limit]]
|
||||
(let [contacts (subscribe [:all-added-dapps])]
|
||||
(let [contacts (subscribe [:all-added-contacts])]
|
||||
(reaction (take limit @contacts)))))
|
||||
|
||||
(register-sub :added-people-count
|
||||
(register-sub :added-contacts-count
|
||||
(fn [_ _]
|
||||
(let [contacts (subscribe [:all-added-people])]
|
||||
(let [contacts (subscribe [:all-added-contacts])]
|
||||
(reaction (count @contacts)))))
|
||||
|
||||
(register-sub :added-dapps-count
|
||||
(fn [_ _]
|
||||
(let [contacts (subscribe [:all-added-dapps])]
|
||||
(reaction (count @contacts)))))
|
||||
(register-sub :all-added-groups
|
||||
(fn [db _]
|
||||
(let [groups (reaction (vals (:contact-groups @db)))]
|
||||
(->> (remove :pending? @groups)
|
||||
(sort-by :order >)
|
||||
(reaction)))))
|
||||
|
||||
(defn get-contact-letter [contact]
|
||||
(when-let [letter (first (:name contact))]
|
||||
(clojure.string/upper-case letter)))
|
||||
|
||||
(defn search-filter [text item]
|
||||
(let [name (-> (or (:name item) "")
|
||||
(str/lower-case))
|
||||
text (str/lower-case text)]
|
||||
(not= (str/index-of name text) nil)))
|
||||
|
||||
(register-sub :all-added-group-contacts-filtered
|
||||
(fn [_ [_ group-id]]
|
||||
(let [contacts (if group-id
|
||||
(subscribe [:all-added-group-contacts group-id])
|
||||
(subscribe [:all-added-contacts]))
|
||||
text (subscribe [:get-in [:toolbar-search :text]])]
|
||||
(reaction
|
||||
(if @text
|
||||
(filter #(search-filter @text %) @contacts)
|
||||
@contacts)))))
|
||||
|
||||
(register-sub :contacts-with-letters
|
||||
(fn [db _]
|
||||
(let [contacts (reaction (:contacts @db))
|
||||
pred (subscribe [:get :contacts-filter])]
|
||||
(let [contacts (reaction (:contacts @db))]
|
||||
(reaction
|
||||
(let [ordered (sort-contacts @contacts)
|
||||
ordered (if @pred (filter @pred ordered) ordered)]
|
||||
(let [ordered (sort-contacts @contacts)]
|
||||
(reduce (fn [prev cur]
|
||||
(let [prev-letter (get-contact-letter (last prev))
|
||||
cur-letter (get-contact-letter cur)]
|
||||
|
|
|
@ -4,31 +4,40 @@
|
|||
[re-frame.core :refer [dispatch]]
|
||||
[status-im.contacts.styles :as st]
|
||||
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]
|
||||
[status-im.components.context-menu :refer [context-menu]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn- on-press [{:keys [whisper-identity] :as contact}]
|
||||
(dispatch [:send-contact-request! contact])
|
||||
(dispatch [:start-chat whisper-identity {} :navigation-replace]))
|
||||
|
||||
(defn- more-on-press [contact]
|
||||
(dispatch [:open-contact-menu (:list-selection-fn platform-specific) contact]))
|
||||
|
||||
(defn letter-view [letter]
|
||||
[view st/letter-container
|
||||
(when letter
|
||||
[text {:style st/letter-text} letter])])
|
||||
|
||||
(defn options-btn [contact more-options]
|
||||
(let [options [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact)}]]
|
||||
[view st/more-btn
|
||||
[context-menu
|
||||
[icon :options_gray]
|
||||
(or more-options options)]]))
|
||||
|
||||
;;TODO: maybe it's better to have only one global component contact-view with the types: default, extended and toggle
|
||||
;;TODO: at the moment toggle in the other component new-group-contact
|
||||
(defview contact-view [{{:keys [whisper-identity letter dapp?] :as contact} :contact
|
||||
:keys [extended? letter? on-click more-on-click info]}]
|
||||
:keys [extended? letter? on-click extend-options info]}]
|
||||
[chat [:get-chat whisper-identity]]
|
||||
[touchable-highlight
|
||||
{:on-press #((or on-click on-press) contact)}
|
||||
(when-not extended?
|
||||
{:on-press #((or on-click on-press) contact)})
|
||||
[view
|
||||
[view st/contact-container
|
||||
(when letter?
|
||||
[letter-view letter])
|
||||
[contact-inner-view contact info]
|
||||
(when (and extended? (not dapp?))
|
||||
[touchable-highlight
|
||||
{:on-press #((or more-on-click more-on-press) contact)}
|
||||
[view st/more-btn
|
||||
[icon :more_vertical st/more-btn-icon]]])]])
|
||||
[contact-inner-view {:contact contact :info info}]
|
||||
(when extended?
|
||||
[options-btn contact extend-options])]
|
||||
[view st/contact-separator-container
|
||||
[view (get-in platform-specific [:component-styles :contacts :separator])]]]])
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
[contact-icon-contacts-tab contact]])
|
||||
|
||||
(defn contact-inner-view
|
||||
([contact]
|
||||
(contact-inner-view contact nil))
|
||||
([{:keys [whisper-identity name] :as contact} info]
|
||||
[view st/contact-inner-container
|
||||
([{:keys [info style] {:keys [whisper-identity name] :as contact} :contact}]
|
||||
[view (merge st/contact-inner-container style)
|
||||
[contact-photo contact]
|
||||
[view st/info-container
|
||||
[text {:style st/name-text
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.components.text-field.view :refer [text-field]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar.view :refer [toolbar]]
|
||||
[status-im.components.toolbar.view :refer [toolbar-with-search toolbar]]
|
||||
[status-im.components.toolbar.actions :as act]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background1]]
|
||||
[status-im.components.drawer.view :refer [drawer-view open-drawer]]
|
||||
|
@ -17,8 +17,7 @@
|
|||
[status-im.contacts.styles :as st]
|
||||
[status-im.utils.listview :as lw]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.platform :refer [platform-specific]]
|
||||
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]))
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn new-group-chat-view []
|
||||
[view
|
||||
|
@ -46,6 +45,7 @@
|
|||
(defn render-row [chat-modal click-handler action params]
|
||||
(fn [row _ _]
|
||||
(list-item
|
||||
^{:key row}
|
||||
[contact-view {:contact row
|
||||
:letter? chat-modal
|
||||
:on-click (when click-handler
|
||||
|
@ -65,29 +65,44 @@
|
|||
|
||||
(defview contact-list-toolbar []
|
||||
[group [:get :contacts-group]
|
||||
modal [:get :modal]]
|
||||
modal [:get :modal]
|
||||
show-search [:get-in [:toolbar-search :show]]]
|
||||
[view
|
||||
[status-bar]
|
||||
[toolbar {:title (label (if-not group
|
||||
:t/contacts
|
||||
(if (= group :dapps)
|
||||
:t/contacts-group-dapps
|
||||
:t/contacts-group-new-chat)))
|
||||
:nav-action (when modal
|
||||
(act/back #(dispatch [:navigate-back])))
|
||||
:background-color toolbar-background1
|
||||
:style (get-in platform-specific [:component-styles :toolbar])
|
||||
:actions [(act/search #())]}]])
|
||||
(toolbar-with-search
|
||||
{:show-search? (= show-search :contact-list)
|
||||
:search-key :contact-list
|
||||
:title (if-not group
|
||||
(label :t/contacts)
|
||||
(or (:name group) (label :t/contacts-group-new-chat)))
|
||||
:search-placeholder (label :t/search-for)
|
||||
:actions (when modal
|
||||
(act/back #(dispatch [:navigate-back])))})])
|
||||
|
||||
(defview contact-list []
|
||||
[contacts [:contacts-with-letters]
|
||||
group [:get :contacts-group]
|
||||
modal [:get :modal]
|
||||
click-handler [:get :contacts-click-handler]
|
||||
action [:get :contacts-click-action]
|
||||
(defview contacts-list-view [group modal click-handler action]
|
||||
[contacts [:all-added-group-contacts-filtered (:group-id group)]
|
||||
params [:get :contacts-click-params]]
|
||||
(let [show-new-group-chat? (and (= group :people)
|
||||
(get-in platform-specific [:chats :new-chat-in-toolbar?]))]
|
||||
(when contacts
|
||||
[list-view {:dataSource (lw/to-datasource contacts)
|
||||
:enableEmptySections true
|
||||
:renderRow (render-row modal click-handler action params)
|
||||
:bounces false
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderHeader #(list-item
|
||||
[view
|
||||
(if show-new-group-chat?
|
||||
[new-group-chat-view])
|
||||
[view st/spacing-top]])
|
||||
:renderFooter #(list-item [view st/spacing-bottom])
|
||||
:style st/contacts-list}])))
|
||||
|
||||
(defview contact-list []
|
||||
[action [:get :contacts-click-action]
|
||||
modal [:get :modal]
|
||||
click-handler [:get :contacts-click-handler]
|
||||
group [:get :contacts-group]]
|
||||
[drawer-view
|
||||
[view st/contacts-list-container
|
||||
[contact-list-toolbar]
|
||||
|
@ -107,15 +122,4 @@
|
|||
:label (label (if (= :request action)
|
||||
:t/show-qr
|
||||
:t/scan-qr))}]])
|
||||
(when contacts
|
||||
[list-view {:dataSource (lw/to-datasource contacts)
|
||||
:enableEmptySections true
|
||||
:renderRow (render-row modal click-handler action params)
|
||||
:bounces false
|
||||
:renderHeader #(list-item
|
||||
[view
|
||||
(if show-new-group-chat?
|
||||
[new-group-chat-view])
|
||||
[view st/spacing-top]])
|
||||
:renderFooter #(list-item [view st/spacing-bottom])
|
||||
:style st/contacts-list}])]]))
|
||||
[contacts-list-view group modal click-handler action]]])
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
(:refer-clojure :exclude [exists?]))
|
||||
|
||||
(defn- normalize-contacts
|
||||
[chats]
|
||||
(map #(update % :contacts vals) chats))
|
||||
[item]
|
||||
(update item :contacts vals))
|
||||
|
||||
(defn get-all
|
||||
[]
|
||||
(normalize-contacts (data-store/get-all-active)))
|
||||
(map normalize-contacts (data-store/get-all-active)))
|
||||
|
||||
(defn get-by-id
|
||||
[id]
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
(ns status-im.data-store.contact-groups
|
||||
(:require [status-im.data-store.realm.contact-groups :as data-store])
|
||||
(:refer-clojure :exclude [exists?]))
|
||||
|
||||
(defn- normalize-contacts
|
||||
[item]
|
||||
(update item :contacts vals))
|
||||
|
||||
(defn get-all
|
||||
[]
|
||||
(map normalize-contacts (data-store/get-all-as-list)))
|
||||
|
||||
(defn save
|
||||
[{:keys [group-id] :as group}]
|
||||
(data-store/save group (data-store/exists? group-id)))
|
||||
|
||||
(defn save-all
|
||||
[groups]
|
||||
(mapv save groups))
|
||||
|
||||
(defn delete
|
||||
[group-id]
|
||||
(data-store/delete group-id))
|
|
@ -0,0 +1,26 @@
|
|||
(ns status-im.data-store.realm.contact-groups
|
||||
(:require [status-im.data-store.realm.core :as realm]
|
||||
[status-im.utils.random :refer [timestamp]])
|
||||
(:refer-clojure :exclude [exists?]))
|
||||
|
||||
(defn get-all
|
||||
[]
|
||||
(-> @realm/account-realm
|
||||
(realm/get-all :contact-group)))
|
||||
|
||||
(defn get-all-as-list
|
||||
[]
|
||||
(realm/realm-collection->list (get-all)))
|
||||
|
||||
(defn save
|
||||
[group update?]
|
||||
(realm/save @realm/account-realm :contact-group group update?))
|
||||
|
||||
(defn exists?
|
||||
[group-id]
|
||||
(realm/exists? @realm/account-realm :contact-group {:group-id group-id}))
|
||||
|
||||
(defn delete
|
||||
[group-id]
|
||||
(when-let [group (realm/get-one-by-field @realm/account-realm :contact-group :group-id group-id)]
|
||||
(realm/delete @realm/account-realm group)))
|
|
@ -3,7 +3,8 @@
|
|||
[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.v4.core :as v4]
|
||||
))
|
||||
[status-im.data-store.realm.schemas.account.v5.core :as v5]))
|
||||
|
||||
|
||||
; put schemas ordered by version
|
||||
(def schemas [{:schema v1/schema
|
||||
|
@ -17,4 +18,7 @@
|
|||
:migration v3/migration}
|
||||
{:schema v4/schema
|
||||
:schemaVersion 4
|
||||
:migration v4/migration}])
|
||||
:migration v4/migration}
|
||||
{:schema v5/schema
|
||||
:schemaVersion 5
|
||||
:migration v5/migration}])
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v5.contact-group
|
||||
(:require [taoensso.timbre :as log]))
|
||||
|
||||
(def schema {:name :contact-group
|
||||
:primaryKey :group-id
|
||||
:properties {:group-id :string
|
||||
:name :string
|
||||
:timestamp :int
|
||||
:order :int
|
||||
:pending? {:type :bool :default false}
|
||||
:contacts {:type :list
|
||||
:objectType :group-contact}}})
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating group schema v5"))
|
|
@ -0,0 +1,36 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v5.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]
|
||||
[status-im.data-store.realm.schemas.account.v5.contact-group :as contact-group]
|
||||
[status-im.data-store.realm.schemas.account.v5.group-contact :as group-contact]
|
||||
[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
|
||||
contact-group/schema
|
||||
group-contact/schema])
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating v5 account database: " old-realm new-realm)
|
||||
(chat/migration old-realm new-realm)
|
||||
(contact/migration old-realm new-realm))
|
|
@ -0,0 +1,8 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v5.group-contact
|
||||
(:require [taoensso.timbre :as log]))
|
||||
|
||||
(def schema {:name :group-contact
|
||||
:properties {:identity "string"}})
|
||||
|
||||
(defn migration [_ _]
|
||||
(log/debug "migrating group-contact schema v5"))
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
:new-contact-identity ""
|
||||
:contacts {}
|
||||
:contact-groups {}
|
||||
:discoveries {}
|
||||
:discover-search-tags []
|
||||
:tags {}
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
(dispatch [:initialize-sync-listener])
|
||||
(dispatch [:initialize-chats])
|
||||
(dispatch [:load-contacts])
|
||||
(dispatch [:load-groups])
|
||||
(dispatch [:init-chat])
|
||||
(dispatch [:init-discoveries])
|
||||
(dispatch [:init-debug-mode address])
|
||||
|
|
|
@ -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-private :refer [new-group]]
|
||||
[status-im.new-group.screen-private :refer [new-group contact-group]]
|
||||
[status-im.new-group.views.contact-list :refer [contact-group-list]]
|
||||
[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]]
|
||||
|
@ -92,6 +93,8 @@
|
|||
:contact-list main-tabs
|
||||
:contact-list-search-results contacts-search-results
|
||||
:group-contacts contact-list
|
||||
:contact-group contact-group
|
||||
:contact-group-list contact-group-list
|
||||
:new-contact new-contact
|
||||
:qr-scanner qr-scanner
|
||||
:chat chat
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.ios.platform
|
||||
(:require [status-im.components.styles :as styles]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background2]]))
|
||||
(:require [status-im.components.styles :as styles]))
|
||||
|
||||
(def component-styles
|
||||
{:status-bar {:default {:height 20
|
||||
|
@ -8,7 +7,7 @@
|
|||
:color styles/color-white}
|
||||
:main {:height 20
|
||||
:bar-style "default"
|
||||
:color toolbar-background2}
|
||||
:color styles/color-white}
|
||||
:transparent {:height 20
|
||||
:bar-style "light-content"
|
||||
:color styles/color-transparent}
|
||||
|
@ -41,9 +40,21 @@
|
|||
:icon {:padding-top 0
|
||||
:bottom -4
|
||||
:justify-content :flex-end}}}
|
||||
:contacts {:subtitle {:color styles/color-steel
|
||||
:font-size 13
|
||||
:letter-spacing 1}}
|
||||
:contacts {:subtitle {:color styles/color-black
|
||||
:font-size 16
|
||||
:letter-spacing -0.2}
|
||||
:separator {:margin-left 68
|
||||
:height 1
|
||||
:background-color styles/color-gray5
|
||||
:opacity 0.4}
|
||||
:icon-check {:border-radius 50
|
||||
:width 24
|
||||
:height 24}
|
||||
:group-header {:flexDirection :row
|
||||
:alignItems :center
|
||||
:margin-top 24
|
||||
:height 53
|
||||
:backgroundColor styles/color-white}}
|
||||
:bottom-gradient {:height 1}
|
||||
:input-label {:left 0}
|
||||
:input-error-text {:margin-left 0}
|
||||
|
@ -55,7 +66,8 @@
|
|||
:toolbar-last-activity {:color styles/text2-color
|
||||
:background-color :transparent
|
||||
:top 0
|
||||
:font-size 14}})
|
||||
:font-size 14}
|
||||
:toolbar-title-container {:align-items :center}})
|
||||
|
||||
(def fonts
|
||||
{:light {:font-family "SFUIText-Light"}
|
||||
|
@ -75,7 +87,6 @@
|
|||
:cancelButtonIndex (count options)})
|
||||
callback))
|
||||
|
||||
|
||||
;; Structure to be exported
|
||||
|
||||
(def platform-specific
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.components.styles :refer [default-chat-color]]
|
||||
[status-im.data-store.chats :as chats]
|
||||
[status-im.data-store.contact-groups :as groups]
|
||||
[clojure.string :as s]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.random :as random]
|
||||
[taoensso.timbre :refer-macros [debug]]
|
||||
|
@ -86,7 +88,7 @@
|
|||
:private private-key}
|
||||
:callback #(dispatch [:incoming-message %1 %2])})))
|
||||
|
||||
(register-handler :create-new-group
|
||||
(register-handler :create-new-group-chat
|
||||
(-> prepare-chat
|
||||
((enrich add-chat))
|
||||
((after create-chat!))
|
||||
|
@ -161,6 +163,98 @@
|
|||
:keypair keypair
|
||||
:callback #(dispatch [:incoming-message %1 %2])})))))))
|
||||
|
||||
(defn prepare-group
|
||||
[{:keys [selected-contacts contact-groups] :as db} [_ group-name]]
|
||||
(let [contacts (mapv #(hash-map :identity %) selected-contacts)]
|
||||
(assoc db :new-group {:group-id (random/id)
|
||||
:name group-name
|
||||
:order (count contact-groups)
|
||||
:timestamp (random/timestamp)
|
||||
:contacts contacts})))
|
||||
|
||||
(defn add-group
|
||||
[{:keys [new-group] :as db} _]
|
||||
(update db :contact-groups merge {(:group-id new-group) new-group}))
|
||||
|
||||
(defn update-group
|
||||
[{:keys [new-group] :as db} _]
|
||||
(update db :contact-groups merge {(:group-id new-group) new-group}))
|
||||
|
||||
(defn create-group!
|
||||
[{:keys [new-group]} _]
|
||||
(groups/save new-group))
|
||||
|
||||
(defn update-group!
|
||||
[{:keys [new-group] :as db} _]
|
||||
(groups/save new-group))
|
||||
|
||||
(defn show-contact-list!
|
||||
[_ _]
|
||||
(dispatch [:navigate-to-clean :contact-list]))
|
||||
|
||||
(register-handler
|
||||
:create-new-group
|
||||
(-> prepare-group
|
||||
((enrich add-group))
|
||||
((after create-group!))
|
||||
((after show-contact-list!))))
|
||||
|
||||
(defn prepare-group-after-edit
|
||||
[{:keys [selected-contacts] :as db} [_ group group-name]]
|
||||
(let [contacts (mapv #(hash-map :identity %) selected-contacts)
|
||||
group' (assoc group :name group-name
|
||||
:contacts contacts)]
|
||||
(assoc db :new-group group')))
|
||||
|
||||
(register-handler
|
||||
:update-group-after-edit
|
||||
(-> prepare-group-after-edit
|
||||
((enrich update-group))
|
||||
((after update-group!))
|
||||
((after show-contact-list!))))
|
||||
|
||||
(register-handler
|
||||
:update-group
|
||||
(-> (fn [db [_ new-group]]
|
||||
(assoc db :new-group new-group))
|
||||
((enrich update-group))
|
||||
((after update-group!))
|
||||
((after show-contact-list!))))
|
||||
|
||||
(defn save-groups! [{:keys [new-groups]} _]
|
||||
(groups/save-all new-groups))
|
||||
|
||||
(defn update-pending-status [old-groups {:keys [group-id pending?] :as group}]
|
||||
(let [{old-pending :pending?
|
||||
:as old-group} (get old-groups group-id)
|
||||
pending?' (if old-pending (and old-pending pending?) pending?)]
|
||||
(assoc group :pending? (boolean pending?'))))
|
||||
|
||||
(defn add-new-groups
|
||||
[{:keys [contact-groups] :as db} [_ new-groups]]
|
||||
(let [identities (set (keys contact-groups))
|
||||
new-groups' (->> new-groups
|
||||
(map #(update-pending-status contact-groups %))
|
||||
(remove #(identities (:group-id %)))
|
||||
(map #(vector (:group-id %) %))
|
||||
(into {}))]
|
||||
(-> db
|
||||
(update :contact-groups merge new-groups')
|
||||
(assoc :new-groups (vals new-groups')))))
|
||||
|
||||
(register-handler :add-groups
|
||||
(after save-groups!)
|
||||
add-new-groups)
|
||||
|
||||
(defn load-groups! [db _]
|
||||
(let [groups (->> (groups/get-all)
|
||||
(map (fn [{:keys [group-id] :as group}]
|
||||
[group-id group]))
|
||||
(into {}))]
|
||||
(assoc db :contact-groups groups)))
|
||||
|
||||
(register-handler :load-groups load-groups!)
|
||||
|
||||
(defmethod nav/preload-data! :new-public-group
|
||||
[db]
|
||||
(dissoc db :public-group/topic))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.resources :as res]
|
||||
[status-im.contacts.views.contact :refer [contact-view]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
|
@ -10,10 +11,12 @@
|
|||
list-view
|
||||
list-item]]
|
||||
[status-im.components.text-field.view :refer [text-field]]
|
||||
[status-im.components.confirm-button :refer [confirm-button]]
|
||||
[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.components.toolbar.view :refer [toolbar-with-search toolbar]]
|
||||
[status-im.utils.platform :refer [platform-specific]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.new-group.views.contact :refer [new-group-contact]]
|
||||
[status-im.new-group.styles :as st]
|
||||
|
@ -21,7 +24,7 @@
|
|||
[status-im.i18n :refer [label]]
|
||||
[cljs.spec :as s]))
|
||||
|
||||
(defview new-group-toolbar []
|
||||
(defview new-chat-group-toolbar []
|
||||
[new-chat-name [:get :new-chat-name]]
|
||||
(let [create-btn-enabled? (s/valid? ::v/name new-chat-name)]
|
||||
[view
|
||||
|
@ -31,15 +34,13 @@
|
|||
:actions [{:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style (st/toolbar-icon create-btn-enabled?)}
|
||||
:handler (when create-btn-enabled?
|
||||
#(dispatch [:create-new-group new-chat-name]))}]}]]))
|
||||
#(dispatch [:create-new-group-chat new-chat-name]))}]}]]))
|
||||
|
||||
(defview group-name-input []
|
||||
[new-chat-name [:get :new-chat-name]]
|
||||
[view
|
||||
[text-field
|
||||
{:error (cond
|
||||
(not (s/valid? ::v/not-empty-string new-chat-name))
|
||||
(label :t/empty-group-chat-name)
|
||||
{:error (when
|
||||
(not (s/valid? ::v/not-illegal-name new-chat-name))
|
||||
(label :t/illegal-group-chat-name))
|
||||
:wrapper-style st/group-chat-name-wrapper
|
||||
|
@ -54,7 +55,7 @@
|
|||
(defview new-group []
|
||||
[contacts [:all-added-contacts]]
|
||||
[view st/new-group-container
|
||||
[new-group-toolbar]
|
||||
[new-chat-group-toolbar]
|
||||
[view st/chat-name-container
|
||||
[text {:style st/members-text
|
||||
:font :medium}
|
||||
|
@ -72,3 +73,56 @@
|
|||
:renderRow (fn [row _ _]
|
||||
(list-item [new-group-contact row]))
|
||||
:style st/contacts-list}]]])
|
||||
|
||||
(defview new-contacts-group-toolbar [edit?]
|
||||
[view
|
||||
[status-bar]
|
||||
[toolbar
|
||||
{:title (label (if edit? :t/edit-group :t/new-group))}]])
|
||||
|
||||
(defn chat-name-view [contacts-count]
|
||||
[view st/chat-name-container
|
||||
[text {:style st/group-name-text
|
||||
:font :medium}
|
||||
(label :t/group-name)]
|
||||
[group-name-input]
|
||||
[text {:style st/members-text
|
||||
:font :medium}
|
||||
(str (label :t/group-members) " " contacts-count)]
|
||||
[touchable-highlight {:on-press #(dispatch [:navigate-forget :contact-group-list])}
|
||||
[view st/add-container
|
||||
[icon :add_blue st/add-icon]
|
||||
[text {:style st/add-text} (label :t/add-members)]]]])
|
||||
|
||||
(defn delete-btn [on-press]
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view st/delete-group-container
|
||||
[text {:style st/delete-group-text} (label :t/delete-group)]
|
||||
[text {:style st/delete-group-prompt-text} (label :t/delete-group-prompt)]]])
|
||||
|
||||
;;TODO: should be refactored into one common function for group chats and contact groups
|
||||
(defview contact-group []
|
||||
[contacts [:selected-group-contacts]
|
||||
group-name [:get :new-chat-name]
|
||||
group [:get :contact-group]]
|
||||
(let [save-btn-enabled? (and (s/valid? ::v/name group-name) (pos? (count contacts)))]
|
||||
[view st/new-group-container
|
||||
[new-contacts-group-toolbar (boolean group)]
|
||||
[chat-name-view (count contacts)]
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item
|
||||
^{:key row}
|
||||
[contact-view
|
||||
{:contact row
|
||||
:extend-options [{:value #(dispatch [:deselect-contact (:whisper-identity row)])
|
||||
:text (label :t/remove-from-group)}]
|
||||
:extended? true}]))
|
||||
:style st/contacts-list}]
|
||||
(when group
|
||||
[delete-btn #(dispatch [:update-group (assoc group :pending? true)])])
|
||||
(when save-btn-enabled?
|
||||
[confirm-button (label :t/save) (if group
|
||||
#(dispatch [:update-group-after-edit group group-name])
|
||||
#(dispatch [:create-new-group group-name]))])]))
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
(:require [status-im.components.styles :refer [color-white
|
||||
color-blue
|
||||
text1-color
|
||||
text2-color]]
|
||||
text2-color
|
||||
color-light-blue
|
||||
color-light-red
|
||||
selected-contact-color
|
||||
color-gray4]]
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn toolbar-icon [enabled?]
|
||||
|
@ -37,27 +41,49 @@
|
|||
(def group-chat-name-wrapper
|
||||
{:padding-top 0})
|
||||
|
||||
(def members-text
|
||||
{:margin-top 24
|
||||
:margin-bottom 8
|
||||
:color text2-color
|
||||
:font-size 14
|
||||
(def group-name-text
|
||||
{:margin-top 11
|
||||
:margin-bottom 10
|
||||
:letter-spacing -0.1
|
||||
:color color-gray4
|
||||
:font-size 13
|
||||
:line-height 20})
|
||||
|
||||
(def members-text
|
||||
{:margin-top 10
|
||||
:margin-bottom 8
|
||||
:letter-spacing -0.2
|
||||
:color color-gray4
|
||||
:font-size 16
|
||||
:line-height 19})
|
||||
|
||||
(def add-container
|
||||
{:flex-direction :row
|
||||
:margin-bottom 16})
|
||||
:align-items :center
|
||||
:margin-top 16
|
||||
:margin-bottom 16
|
||||
:margin-right 20})
|
||||
|
||||
(def add-icon
|
||||
{:margin-vertical 18
|
||||
:margin-horizontal 3
|
||||
:width 17
|
||||
:height 17})
|
||||
{:align-items :center
|
||||
:width 24
|
||||
:height 24})
|
||||
|
||||
(def add-text
|
||||
{:margin-top 16
|
||||
:margin-left 32
|
||||
:color text2-color
|
||||
{:margin-left 32
|
||||
:color color-light-blue
|
||||
:letter-spacing -0.2
|
||||
:font-size 17
|
||||
:line-height 20})
|
||||
|
||||
(def delete-group-text
|
||||
{:color color-light-red
|
||||
:letter-spacing 0.5
|
||||
:font-size 14
|
||||
:line-height 20})
|
||||
|
||||
(def delete-group-prompt-text
|
||||
{:color color-gray4
|
||||
:font-size 14
|
||||
:line-height 20})
|
||||
|
||||
|
@ -70,9 +96,25 @@
|
|||
:align-items :center
|
||||
:height 56})
|
||||
|
||||
(def contact-item-checkbox
|
||||
{:outer-size 20
|
||||
:filter-size 16
|
||||
:inner-size 12
|
||||
:outer-color color-blue
|
||||
:inner-color color-blue})
|
||||
(def selected-contact
|
||||
{:background-color selected-contact-color})
|
||||
|
||||
(def icon-check-container
|
||||
(merge (get-in platform-specific [:component-styles :contacts :icon-check])
|
||||
{:alignItems :center
|
||||
:justifyContent :center}))
|
||||
|
||||
(def toggle-container
|
||||
{:width 56
|
||||
:height 56
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def check-icon
|
||||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def delete-group-container
|
||||
{:height 56
|
||||
:padding-left 72
|
||||
:margin-top 15})
|
|
@ -1,7 +1,19 @@
|
|||
(ns status-im.new-group.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]
|
||||
(:require [re-frame.core :refer [register-sub subscribe]]
|
||||
[status-im.utils.subs :as u]))
|
||||
|
||||
(register-sub :is-contact-selected?
|
||||
(u/contains-sub :selected-contacts))
|
||||
|
||||
(register-sub :selected-contacts-count
|
||||
(fn [_ _]
|
||||
(let [contacts (subscribe [:get :selected-contacts])]
|
||||
(reaction (count @contacts)))))
|
||||
|
||||
(register-sub :selected-group-contacts
|
||||
(fn [_ _]
|
||||
(let [selected-contacts (subscribe [:get :selected-contacts])
|
||||
added-contacts (subscribe [:all-added-contacts])]
|
||||
(reaction (do @selected-contacts ;;TODO: doesn't work without this line :(
|
||||
(filter #(@selected-contacts (:whisper-identity %)) @added-contacts))))))
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
(ns status-im.new-group.views.contact
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[status-im.components.react :refer [view]]
|
||||
[status-im.components.react :refer [view icon touchable-highlight]]
|
||||
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]
|
||||
[status-im.components.item-checkbox :refer [item-checkbox]]
|
||||
[status-im.new-group.styles :as st]))
|
||||
[status-im.new-group.styles :as st]
|
||||
[status-im.contacts.styles :as cst]
|
||||
[status-im.components.styles :refer [color-light-blue color-gray5]]
|
||||
[status-im.utils.platform :refer [platform-specific]]))
|
||||
|
||||
(defn on-toggle [whisper-identity]
|
||||
(fn [checked?]
|
||||
(let [action (if checked? :select-contact :deselect-contact)]
|
||||
(dispatch [action whisper-identity]))))
|
||||
(defn on-toggle [checked? whisper-identity]
|
||||
(let [action (if checked? :deselect-contact :select-contact)]
|
||||
(dispatch [action whisper-identity])))
|
||||
|
||||
;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle)
|
||||
(defview new-group-contact [{:keys [whisper-identity] :as contact}]
|
||||
[checked [:is-contact-selected? whisper-identity]]
|
||||
[view st/contact-container
|
||||
[item-checkbox (merge {:on-toggle (on-toggle whisper-identity)
|
||||
:checked checked}
|
||||
st/contact-item-checkbox)]
|
||||
[contact-inner-view contact]])
|
||||
[touchable-highlight {:on-press #(on-toggle checked whisper-identity)}
|
||||
[view
|
||||
[view (merge st/contact-container (when checked {:style st/selected-contact}))
|
||||
[contact-inner-view (merge {:contact contact}
|
||||
(when checked {:style st/selected-contact}))]
|
||||
[view st/toggle-container
|
||||
[view (merge st/icon-check-container
|
||||
{:background-color (if checked color-light-blue color-gray5)})
|
||||
(when checked
|
||||
[icon :check_on st/check-icon])]]]
|
||||
[view cst/contact-separator-container
|
||||
[view (get-in platform-specific [:component-styles :contacts :separator])]]]])
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
(ns status-im.new-group.views.contact-list
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.components.confirm-button :refer [confirm-button]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar.view :refer [toolbar-with-search]]
|
||||
[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.i18n :refer [label]]))
|
||||
|
||||
(defn contact-list-toolbar [contacts-count show-search?]
|
||||
(toolbar-with-search
|
||||
{:show-search? (= show-search? :contact-group-list)
|
||||
:search-key :contact-group-list
|
||||
:title (str (label :t/new-group) " (" contacts-count ")")
|
||||
:search-placeholder (label :t/search-for)}))
|
||||
|
||||
(defview contact-group-list []
|
||||
[contacts [:all-added-group-contacts-filtered]
|
||||
selected-contacts-count [:selected-contacts-count]
|
||||
show-search [:get-in [:toolbar-search :show]]]
|
||||
[view st/new-group-container
|
||||
[status-bar]
|
||||
[contact-list-toolbar selected-contacts-count show-search]
|
||||
[view {:flex 1}
|
||||
[list-view
|
||||
{:dataSource (to-datasource contacts)
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item ^{:key row} [new-group-contact row]))
|
||||
:style st/contacts-list
|
||||
:keyboardShouldPersistTaps true}]]
|
||||
(when (pos? selected-contacts-count)
|
||||
[confirm-button (label :t/next) #(dispatch [:navigation-replace :contact-group])])])
|
|
@ -19,4 +19,4 @@
|
|||
[item-checkbox {:onToggle (on-toggle whisper-identity)
|
||||
:checked checked
|
||||
:size 30}]
|
||||
[contact-inner-view contact]])
|
||||
[contact-inner-view {:contact contact}]])
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
:offline "Offline"
|
||||
:search-for "Search for..."
|
||||
:cancel "Cancel"
|
||||
:next "Next"
|
||||
|
||||
;drawer
|
||||
:invite-friends "Invite friends"
|
||||
|
@ -141,8 +142,10 @@
|
|||
|
||||
;contacts
|
||||
:contacts "Contacts"
|
||||
:new-contact "New Contact"
|
||||
:remove-contact "Remove contact"
|
||||
:new-contact "New contact"
|
||||
:delete-contact "Delete contact"
|
||||
:remove-from-group "Remove from group"
|
||||
:edit-contacts "Edit contacts"
|
||||
:show-all "SHOW ALL"
|
||||
:contacts-group-dapps "ÐApps"
|
||||
:contacts-group-people "People"
|
||||
|
@ -150,6 +153,7 @@
|
|||
:no-contacts "No contacts yet"
|
||||
:show-qr "Show QR"
|
||||
:enter-address "Enter address"
|
||||
:more "more"
|
||||
|
||||
;group-settings
|
||||
:remove "Remove"
|
||||
|
@ -185,6 +189,13 @@
|
|||
:group-chat-name "Chat name"
|
||||
:empty-group-chat-name "Please enter a name"
|
||||
:illegal-group-chat-name "Please select another name"
|
||||
:new-group "New Group"
|
||||
:reorder-groups "Reorder Group"
|
||||
:group-name "Group name"
|
||||
:edit-group "Edit Group"
|
||||
:delete-group "DELETE GROUP"
|
||||
:delete-group-prompt "This will not affect group members"
|
||||
:group-members "Group members"
|
||||
|
||||
;participants
|
||||
:add-participants "Add Participants"
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
:chat-name "Имя чата"
|
||||
:notifications-title "Уведомления и звуки"
|
||||
:offline "Оффлайн"
|
||||
:cancel "Отмена"
|
||||
:next "Продолжить"
|
||||
|
||||
;drawer
|
||||
:invite-friends "Пригласить друзей"
|
||||
|
@ -119,6 +121,7 @@
|
|||
;contacts
|
||||
:contacts "Контакты"
|
||||
:new-contact "Новый контакт"
|
||||
:edit-contacts "Редактирование контактов"
|
||||
:show-all "ПОКАЗАТЬ ВСЕ"
|
||||
:contacts-group-dapps "ÐApps"
|
||||
:contacts-group-people "Люди"
|
||||
|
@ -161,6 +164,9 @@
|
|||
:group-chat-name "Имя чата"
|
||||
:empty-group-chat-name "Введите имя"
|
||||
:illegal-group-chat-name "Выберите другое имя"
|
||||
:new-group "Новая группа"
|
||||
:group-name "Название группы"
|
||||
:reorder-groups "Упорядочить группы"
|
||||
|
||||
;participants
|
||||
:add-participants "Добавить участников"
|
||||
|
|