chats list UI refresh

This commit is contained in:
Gustavo Nunes 2017-03-02 14:35:58 -03:00 committed by Roman Volosovskyi
parent 9345f77dd8
commit 9f2af87393
18 changed files with 302 additions and 187 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 B

After

Width:  |  Height:  |  Size: 522 B

View File

@ -27,6 +27,19 @@
:toolbar-with-search-content {:padding-left 30}
:sized-text {:margin-top 0
:additional-height 0}
:chat-list {:list-container {:background-color styles/color-light-gray}
:chat-container {:height 76}
:chat-icon-container {:height 76}
:chat-info-container {:margin-top 16}
:chat-options-container {:margin-top 16}
:item-lower-container {:margin-top 4}
:chat-name {:height 24}
:last-message {:font-size 14
:height 24}
:last-message-timestamp {:font-size 14}
:unread-count {:top 2}
:public-group-icon-container {:margin-top 4}
:private-group-icon-container {:margin-top 4}}
:chat {:new-message {:border-top-color styles/color-transparent
:border-top-width 0.5}}
:discover {:subtitle {:color styles/color-gray2
@ -114,11 +127,11 @@
:font-size 12}})
(def fonts
{:light {:font-family "sans-serif-light"}
:default {:font-family "sans-serif"}
:medium {:font-family "sans-serif-medium"}
{:light {:font-family "Roboto-Light"}
:default {:font-family "Roboto-Regular"}
:medium {:font-family "Roboto-Medium"}
:toolbar-title {:font-family "sans-serif"}})
:toolbar-title {:font-family "Roboto-Regular"}})
;; Dialogs
@ -140,7 +153,8 @@
:list-selection-fn show-dialog
:tabs {:tab-shadows? true}
:chats {:action-button? true
:new-chat-in-toolbar? false}
:new-chat-in-toolbar? false
:render-separator? false}
:uppercase? true
:contacts {:action-button? true
:new-contact-in-toolbar? false

View File

@ -14,74 +14,99 @@
[status-im.components.drawer.view :refer [open-drawer]]
[status-im.components.styles :refer [color-blue]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar-with-search]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar-new.view :refer [toolbar toolbar-with-search]]
[status-im.components.toolbar-new.actions :as act]
[status-im.components.toolbar-new.styles :as tst]
[status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.components.react :refer [linear-gradient]]
[status-im.components.sync-state.offline :refer [offline-view]]
[status-im.components.context-menu :refer [context-menu]]
[status-im.components.tabs.styles :refer [tabs-height]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.chats-list.views.chat-list-item :refer [chat-list-item]]
[status-im.i18n :refer [label]]
[status-im.utils.platform :refer [platform-specific]]
[status-im.chats-list.styles :as st]
[status-im.components.tabs.styles :refer [tabs-height]]))
[status-im.i18n :refer [label]]
[status-im.utils.platform :refer [platform-specific ios?]]))
(defview toolbar-view []
[chats-scrolled? [:get :chats-scrolled?]]
(let [new-chat? (get-in platform-specific [:chats :new-chat-in-toolbar?])
actions (if new-chat?
[(act/add #(dispatch [:navigate-to :group-contacts :people]))])]
[toolbar-with-search
{:show-search? false
:search-key :chat-list
:title (label :t/chats)
:search-placeholder (label :t/search-for)
:nav-action (act/hamburger open-drawer)
:style (st/toolbar chats-scrolled?)
:actions actions}]))
(def android-toolbar-popup-options
[{:text (label :t/edit) :value #(dispatch [:set-in [:chat-list-ui-props :edit?] true])}])
(defn android-toolbar-actions []
[(act/search #(dispatch [:set-in [:toolbar-search :show] true]))
(act/opts android-toolbar-popup-options)])
(def ios-toolbar-popup-options
[{:text (label :t/edit-chats) :value #(dispatch [:set-in [:chat-list-ui-props :edit?] true])}
{:text (label :t/search-chats) :value #(dispatch [:set-in [:toolbar-search :show] true])}])
(defn ios-toolbar-actions []
[(act/opts ios-toolbar-popup-options)
(act/add #(dispatch [:navigate-to :group-contacts :people]))])
(defn toolbar-view []
[toolbar {:title (label :t/chats)
:nav-action (act/hamburger open-drawer)
:actions (if ios?
(ios-toolbar-actions)
(android-toolbar-actions))}])
(defn toolbar-edit []
[toolbar {:nav-action (act/back #(dispatch [:set-in [:chat-list-ui-props :edit?] false]))
:title (label :t/edit-chats)}])
(defn toolbar-search []
[toolbar-with-search
{:show-search? true
:search-key :chat-list
:title (label :t/chats)
:search-placeholder (label :t/search-for)}])
(defn chats-action-button []
[action-button {:button-color color-blue
:offset-x 16
:offset-y 22
:hide-shadow true
:spacing 13}
[action-button-item
{:title (label :t/new-chat)
:buttonColor :#9b59b6
:onPress #(dispatch [:navigate-to :group-contacts :people])}
[ion-icon {:name :md-create
:style st/create-icon}]]
[action-button-item
{:title (label :t/new-group-chat)
:buttonColor :#1abc9c
:onPress #(dispatch [:open-contact-toggle-list :chat-group])}
[icon :private_group_big st/group-icon]]
[action-button-item
{:title (label :t/new-public-group-chat)
:buttonColor :#1abc9c
:onPress #(dispatch [:navigate-to :new-public-group])}
[icon :public_group_big st/group-icon]]])
:spacing 13
:on-press #(dispatch [:navigate-to :group-contacts :people])}])
(defn chat-list-padding []
[view {:height (if ios? 0 8)
:background-color :white}])
(defn chat-shadow-item []
[view {:height 3}
[linear-gradient {:style {:height 3}
:colors st/gradient-top-bottom-shadow}]])
(when-not ios?
[view {:height 12}
[chat-list-padding]
[linear-gradient {:style {:height 4}
:colors st/gradient-top-bottom-shadow}]]))
(defn render-separator-fn [chats]
(fn [_ row-id _]
(list-item
(when (< row-id (dec (count chats)))
^{:key (str "separator-" row-id)}
[view st/chat-separator-wrapper
[view st/chat-separator-item]]))))
(defview chats-list []
[chats [:get :chats]]
[chats [:filtered-chats]
edit? [:get-in [:chat-list-ui-props :edit?]]
search? [:get-in [:toolbar-search :show]]]
[view st/chats-container
[toolbar-view]
(cond
edit? [toolbar-edit]
search? [toolbar-search]
:else [toolbar-view])
[list-view {:dataSource (to-datasource chats)
:renderRow (fn [[id :as row] _ _]
(list-item ^{:key id} [chat-list-item row]))
:renderFooter #(list-item [chat-shadow-item])
:renderSeparator #(list-item
(when (< %2 (- (count chats) 1))
^{:key (str "separator-" %2)}
[view st/chat-separator-wrapper
[view st/chat-separator-item]]))
(list-item ^{:key id} [chat-list-item row edit?]))
:renderHeader #(when (seq chats) (list-item [chat-list-padding]))
:renderFooter #(when (seq chats) (list-item [chat-shadow-item]))
:renderSeparator (when (get-in platform-specific [:chats :render-separator?])
(render-separator-fn chats))
:style st/list-container}]
(when (get-in platform-specific [:chats :action-button?])
(when (and (not edit?)
(not search?)
(get-in platform-specific [:chats :action-button?]))
[chats-action-button])
[offline-view]])

View File

@ -1,20 +1,20 @@
(ns status-im.chats-list.styles
(:require [status-im.components.styles :refer [color-white
color-light-gray
color-separator
color-blue
color-gray5
text1-color
text2-color
text4-color
separator-color
new-messages-count-color]]
[status-im.components.tabs.styles :refer [tabs-height]]
[status-im.components.toolbar.styles :refer [toolbar-background1
toolbar-background2]]
[status-im.utils.platform :as p]))
(defn toolbar [chats-scrolled?]
(merge {:background-color (if chats-scrolled?
toolbar-background1
toolbar-background2)}
(defn toolbar []
(merge {:background-color toolbar-background1}
(get-in p/platform-specific [:component-styles :toolbar])))
@ -25,84 +25,89 @@
(def chat-separator-wrapper
{:background-color color-white
:height 0.5
:padding-left 74})
:opacity 0.5
:height 1
:padding-left 72})
(def chat-separator-item
{:border-bottom-width 0.5
:border-bottom-color color-separator})
{:border-bottom-width 1
:border-bottom-color color-gray5})
(def chat-container
{:flex-direction :row
:background-color color-white
:height 94})
(merge {:flex-direction :row
:background-color color-white}
(get-in p/platform-specific [:component-styles :chat-list :chat-container])))
(def chat-icon-container
{:margin-top -2
:margin-left -4
:padding 16
:width 48
:height 48})
(merge {:padding-top 18
:padding-bottom 18
:padding-left 12
:padding-right 20
:width 72}
(get-in p/platform-specific [:component-styles :chat-list :chat-icon-container])))
(def item-container
{:flex-direction :column
:margin-left 30
:padding-top 16
:padding-right 16
:flex 1})
(def chat-info-container
(merge {:margin-bottom 13
:justify-content :space-between
:flex 1
:flex-direction :column}
(get-in p/platform-specific [:component-styles :chat-list :chat-info-container])))
(def chat-options-container
(merge {:margin-right 16
:padding-top 10}
(get-in p/platform-specific [:component-styles :chat-list :chat-options-container])))
(def item-upper-container
{:flex 1
:flex-direction :row
:justify-content :space-between})
(def item-lower-container
(merge {:flex 1
:flex-direction :row
:justify-content :space-between}
(get-in p/platform-specific [:component-styles :chat-list :item-lower-container])))
(def name-view
{:flex-direction :row})
{:flex-direction :row
:flex-shrink 1})
(def name-text
{:color text1-color
:font-size 14})
(merge {:color text1-color
:font-size 16}
(get-in p/platform-specific [:component-styles :chat-list :chat-name])))
(def private-group-icon-container
{:width 16
:height 9
:padding-top -4
:margin-top (get-in p/platform-specific [:private-group-icon-container :margin-top])
:margin-right 6})
(merge {:width 16
:height 12
:margin-right 6}
(get-in p/platform-specific [:component-styles :chat-list :private-group-icon-container])))
(def private-group-icon
{:width 16
:height 16})
(def public-group-icon-container
{:width 16
:height 12
:padding-top -2
:margin-top (get-in p/platform-specific [:public-group-icon-container :margin-top])
:margin-right 6})
(merge {:width 16
:height 12
:margin-right 6}
(get-in p/platform-specific [:component-styles :chat-list :public-group-icon-container])))
(def public-group-icon
{:width 16
:height 16
:margin-bottom -20})
(def memebers-text
{:marginTop 2
:marginLeft 4
:fontSize 12
:color text2-color})
{:width 16
:height 16})
(def last-message-container
{:margin-top 5
:margin-right 40})
{:flex-shrink 1})
(def last-message-text
{:color text1-color
:fontSize 14
:lineHeight 20})
(def last-message-text-no-messages
(merge last-message-text
{:color text2-color}))
(merge {:color text4-color}
(get-in p/platform-specific [:component-styles :chat-list :last-message])))
(def status-container
{:flex-direction :row
:top 18
:top 16
:right 16})
(def status-image
@ -111,33 +116,46 @@
:height 7})
(def datetime-text
{:fontSize 12
:color text2-color
:marginLeft 5})
(merge {:color text4-color}
(get-in p/platform-specific [:component-styles :chat-list :last-message-timestamp])))
(def new-messages-container
{:position :absolute
:top 54
:right 16
:width 24
:height 24
{:width 22
:height 22
:margin-left 15
:backgroundColor new-messages-count-color
:borderRadius 50})
(def new-messages-text
{:top 5
:left 0
:fontSize 10
:color color-blue
:textAlign :center})
(merge {:left 0
:fontSize 12
:color color-blue
:textAlign :center}
(get-in p/platform-specific [:component-styles :chat-list :unread-count])))
(def chats-container
{:flex 1})
(def list-container
(merge (get-in p/platform-specific [:component-styles :main-tab-list])
{:background-color color-light-gray}))
(get-in p/platform-specific [:component-styles :chat-list :list-container])))
(def toolbar-actions
{:flex-direction :row
:padding-right 14})
(def toolbar-btn
{:width 24
:height 56
:margin-left 24
:alignItems :center
:justifyContent :center})
(def opts-btn
{:width 24
:height 24
:alignItems :center
:justifyContent :center})
(def create-icon
{:fontSize 20
@ -145,6 +163,8 @@
:color color-white})
(def group-icon
{:height 22
:width 22
:tint-color :white})
{:margin-top 8
:margin-right 6
:width 14
:height 9
:tint-color :white})

View File

@ -0,0 +1,19 @@
(ns status-im.chats-list.subs
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub subscribe]]
[clojure.string :as str]))
(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 :filtered-chats
(fn [_ _]
(let [chats (subscribe [:get :chats])
search-text (subscribe [:get-in [:toolbar-search :text]])]
(reaction
(if @search-text
(filter #(search-filter @search-text (second %)) @chats)
@chats)))))

View File

@ -6,7 +6,7 @@
touchable-highlight]]
[status-im.chats-list.views.inner-item :refer [chat-list-item-inner-view]]))
(defn chat-list-item [[chat-id chat]]
(defn chat-list-item [[chat-id chat] edit?]
[touchable-highlight {:on-press #(dispatch [:navigate-to :chat chat-id])}
[view
[chat-list-item-inner-view (assoc chat :chat-id chat-id)]]])
[chat-list-item-inner-view (assoc chat :chat-id chat-id) edit?]]])

View File

@ -4,6 +4,7 @@
[clojure.string :as str]
[status-im.components.react :refer [view image icon text]]
[status-im.components.chat-icon.screen :refer [chat-icon-view-chat-list]]
[status-im.components.context-menu :refer [context-menu]]
[status-im.models.commands :refer [parse-command-message-content]]
[status-im.chats-list.styles :as st]
[status-im.utils.utils :refer [truncate-str]]
@ -36,16 +37,16 @@
(cond
(not message)
[text {:style st/last-message-text-no-messages}
[text {:style st/last-message-text}
(label :t/no-messages)]
(str/blank? content)
[text {:style st/last-message-text-no-messages}
[text {:style st/last-message-text}
""]
(:content content)
[text {:style st/last-message-text
:number-of-lines 2}
:number-of-lines 1}
(:content content)]
(:command content)
@ -53,7 +54,7 @@
:else
[text {:style st/last-message-text
:number-of-lines 2}
:number-of-lines 1}
content])]))})))
(defview message-status [{:keys [chat-id contacts]}
@ -85,40 +86,51 @@
:font :medium}
unviewed-messages]]))
(defn chat-list-item-inner-view [{:keys [chat-id name color
online group-chat contacts public?]
:as chat}]
(let [last-message (subscribe [:get-last-message chat-id])
name (or (get-contact-translated chat-id :name name)
(generate-gfy))
private-group? (and group-chat (not public?))
public-group? (and group-chat public?)]
(defn options-btn [chat-id]
(let [options [{:value #(dispatch [:remove-chat chat-id])
:text (label :t/delete-chat)
:destructive? true}]]
[view st/opts-btn
[context-menu
[icon :options_gray]
options]]))
(defn chat-list-item-name [name group-chat? public?]
(let [private-group? (and group-chat? (not public?))
public-group? (and group-chat? public?)
chat-name (if (str/blank? name)
(generate-gfy)
(truncate-str name 30))]
[view st/name-view
(when public-group?
[view st/public-group-icon-container
[icon :public_group st/public-group-icon]])
(when private-group?
[view st/private-group-icon-container
[icon :private_group st/private-group-icon]])
[text {:style st/name-text}
(if public-group?
(str "#" chat-name)
chat-name)]]))
(defn chat-list-item-inner-view [{:keys [chat-id name color online
group-chat contacts public?] :as chat}
edit?]
(let [last-message (subscribe [:get-last-message chat-id])
name (or (get-contact-translated chat-id :name name)
(generate-gfy))]
[view st/chat-container
[view st/chat-icon-container
[chat-icon-view-chat-list chat-id group-chat name color online]]
[view st/item-container
[view st/name-view
(when public-group?
[view st/public-group-icon-container
[icon :public_group st/public-group-icon]])
(when private-group?
[view st/private-group-icon-container
[icon :private_group st/private-group-icon]])
(let [chat-name (if (str/blank? name)
(generate-gfy)
(truncate-str name 30))]
[text {:style st/name-text
:font :medium}
(if public-group?
(str "#" chat-name)
chat-name)])
#_(when private-group?
[text {:style st/memebers-text}
(label-pluralize (inc (count contacts)) :t/members)])]
[message-content-text chat-id]]
[view
(when @last-message
[view st/status-container
[message-status chat @last-message]
[message-timestamp @last-message]])
[unviewed-indicator chat-id]]]))
[view st/chat-info-container
[view st/item-upper-container
[chat-list-item-name name group-chat public?]
(when (and (not edit?) @last-message)
[view
[message-status chat @last-message]
[message-timestamp @last-message]])]
[view st/item-lower-container
[message-content-text chat-id]
(when-not edit? [unviewed-indicator chat-id])]]
[view st/chat-options-container
(when edit? [options-btn chat-id])]]))

View File

@ -3,7 +3,7 @@
online-color]]))
(defn default-chat-icon [color]
{:margin 4
{:margin 0
:width 40
:height 40
:alignItems :center
@ -204,8 +204,8 @@
(def pending-wrapper
{:position :absolute
:bottom 4
:right 5
:bottom 0
:right 0
:width 12
:height 12
:border-radius 6

View File

@ -27,12 +27,13 @@
(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)})
(let [cancel-option {:text (label :t/cancel)}
options (conj options cancel-option)]
(list-selection-fn {:options options
:callback (fn [index]
(when (< index (count options))
(when-let [handler (:value (nth options index))]
(handler))))}))
nil)
(defn context-menu [trigger options]
@ -44,8 +45,8 @@
[menu {:onSelect #(when % (do (%) nil))}
[menu-trigger trigger]
[menu-options st/context-menu-options
(for [{:keys [style value] :as option} options]
(for [{:keys [style value destructive?] :as option} options]
^{:key option}
[menu-option {:value value}
[text {:style (merge st/context-menu-text style)}
(:text option)]])]]))
[text {:style (merge (st/context-menu-text destructive?) style)}
(:text option)]])]]))

View File

@ -24,6 +24,7 @@
(def text1-disabled-color "#555555")
(def text2-color color-gray)
(def text3-color color-blue)
(def text4-color color-gray4)
(def online-color color-light-blue)
(def new-messages-count-color color-blue-transparent)
(def chat-background color-light-gray)
@ -107,7 +108,7 @@
:justify-content :center
:height 48}}})
(def context-menu-text
(defn context-menu-text [destructive?]
{:font-size 15
:line-height 20
:color text1-color})
:color (if destructive? color-light-red text1-color)})

View File

@ -1,5 +1,6 @@
(ns status-im.ios.platform
(:require [status-im.components.styles :as styles]))
(:require [status-im.components.styles :as styles]
[status-im.utils.utils :as utils]))
(def component-styles
{:status-bar {:default {:height 20
@ -27,6 +28,19 @@
:additional-height 5}
:actions-list-view {:border-bottom-color styles/color-gray3
:border-bottom-width 0.5}
:chat-list {:list-container {:background-color styles/color-white}
:chat-container {:height 74}
:chat-icon-container {:height 74}
:chat-info-container {:margin-top 14}
:chat-options-container {:margin-top 14}
:item-lower-container {:margin-top 6}
:chat-name {:height 20}
:last-message {:font-size 15
:height 24}
:last-message-timestamp {:font-size 15}
:unread-count {:top 3}
:public-group-icon-container {:margin-top 2}
:private-group-icon-container {:margin-top 2}}
:chat {:new-message {:border-top-color styles/color-gray3
:border-top-width 0.5}}
:discover {:subtitle {:color styles/color-steel
@ -150,10 +164,15 @@
(def react-native (js/require "react-native"))
(defn show-action-sheet [{:keys [options callback cancel-text]}]
(defn action-sheet-options [options]
(let [destructive-opt-index (utils/first-index :destructive? options)]
(clj->js (merge {:options (mapv :text options)
:cancelButtonIndex (count options)}
(when destructive-opt-index {:destructiveButtonIndex destructive-opt-index})))))
(defn show-action-sheet [{:keys [options callback]}]
(.showActionSheetWithOptions (.-ActionSheetIOS react-native)
(clj->js {:options (conj options cancel-text)
:cancelButtonIndex (count options)})
(action-sheet-options options)
callback))
;; Structure to be exported
@ -164,7 +183,8 @@
:list-selection-fn show-action-sheet
:tabs {:tab-shadows? false}
:chats {:action-button? false
:new-chat-in-toolbar? true}
:new-chat-in-toolbar? true
:render-separator? true}
:uppercase? false
:contacts {:action-button? false
:new-contact-in-toolbar? true
@ -174,4 +194,3 @@
:private-group-icon-container {:margin-top 2}
:group-chat-focus-line-height 1
:public-group-chat-hash-style {:top 6 :left 3}})

View File

@ -2,6 +2,7 @@
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub subscribe]]
status-im.chat.subs
status-im.chats-list.subs
status-im.group-settings.subs
status-im.discover.subs
status-im.contacts.subs

View File

@ -122,8 +122,11 @@
;chats
:chats "Chats"
:new-chat "New chat"
:delete-chat "Delete chat"
:new-group-chat "New group chat"
:new-public-group-chat "Join public group chat"
:new-public-group-chat "Join public chat"
:edit-chats "Edit chats"
:search-chats "Search chats"
:empty-topic "Empty topic"
:topic-format "Wrong format [a-z0-9\\-]+"
:public-group-topic "Topic"

View File

@ -30,7 +30,7 @@
(t/day today-date))
yesterday (plus today (days -1))]
(cond
(before? local yesterday) (unparse (formatter "dd MMM") local)
(before? local yesterday) (unparse (formatter "dd MMM hh:mm") local)
(before? local today) (label :t/datetime-yesterday)
:else (today-format-fn local)))))