diff --git a/resources/images/ui/welcome-image.png b/resources/images/ui/welcome-image.png index 8945f0768a..7df81b3972 100644 Binary files a/resources/images/ui/welcome-image.png and b/resources/images/ui/welcome-image.png differ diff --git a/src/status_im/accounts/create/core.cljs b/src/status_im/accounts/create/core.cljs index ea79b73b57..e1195d9caa 100644 --- a/src/status_im/accounts/create/core.cljs +++ b/src/status_im/accounts/create/core.cljs @@ -107,13 +107,14 @@ (defn account-set-name [{{:accounts/keys [create] :as db} :db now :now :as cofx}] (fx/merge cofx - {:db (assoc db :accounts/create {:show-welcome? true}) + {:db db :notifications/request-notifications-permissions nil - :dispatch [:navigate-to :home]} + :dispatch-n [[:navigate-to :home] + [:navigate-to :welcome]]} ;; We set last updated as we are actually changing a field, ;; unlike on recovery where the name is not set (accounts.update/account-update {:last-updated now - :name (:name create)} {}) + :name (:name create)} {}) (mobile-network/on-network-status-change))) (fx/defn next-step diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 024b75dffb..6c65a1e108 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -52,8 +52,7 @@ [status-im.node.core :as node] [status-im.stickers.core :as stickers] [status-im.utils.config :as config] - [status-im.constants :as constants] - [status-im.utils.ethereum.core :as ethereum])) + [status-im.ui.components.bottom-sheet.core :as bottom-sheet])) ;; init module @@ -1801,3 +1800,15 @@ :tribute-to-talk.ui/remove-pressed (fn [cofx _] (tribute-to-talk/remove cofx))) + +(handlers/register-handler-fx + :bottom-sheet/show-sheet + (fn [cofx [_ view]] + (bottom-sheet/show-bottom-sheet + cofx + {:view view}))) + +(handlers/register-handler-fx + :bottom-sheet/hide-sheet + (fn [cofx _] + (bottom-sheet/hide-bottom-sheet cofx))) diff --git a/src/status_im/ui/components/action_button/action_button.cljs b/src/status_im/ui/components/action_button/action_button.cljs index c522156459..53ec72f312 100644 --- a/src/status_im/ui/components/action_button/action_button.cljs +++ b/src/status_im/ui/components/action_button/action_button.cljs @@ -2,10 +2,12 @@ (:require [status-im.ui.components.action-button.styles :as st] [status-im.ui.components.common.common :refer [list-separator]] [status-im.ui.components.icons.vector-icons :as vi] - [status-im.ui.components.react :as rn])) + [status-im.ui.components.react :as rn] + [status-im.ui.components.colors :as colors])) (defn action-button [{:keys [label accessibility-label icon icon-opts on-press label-style cyrcle-color]}] - [rn/touchable-highlight (merge {:on-press on-press} + [rn/touchable-highlight (merge {:on-press on-press + :underlay-color (colors/alpha colors/gray 0.15)} (when accessibility-label {:accessibility-label accessibility-label})) [rn/view {:style st/action-button} diff --git a/src/status_im/ui/components/action_button/styles.cljs b/src/status_im/ui/components/action_button/styles.cljs index 5865d10bb1..ad2c99c47f 100644 --- a/src/status_im/ui/components/action_button/styles.cljs +++ b/src/status_im/ui/components/action_button/styles.cljs @@ -1,15 +1,14 @@ (ns status-im.ui.components.action-button.styles (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) - (:require [status-im.ui.components.styles :as styles] - [status-im.ui.components.colors :as colors])) + (:require [status-im.ui.components.colors :as colors])) (defstyle action-button {:padding-left 16 :flex-direction :row :align-items :center - :ios {:height 63} + :ios {:height 64} :desktop {:height 50} - :android {:height 56}}) + :android {:height 64}}) (defnstyle action-button-icon-container [circle-color] {:border-radius 50 @@ -28,8 +27,7 @@ (defstyle actions-list {:background-color colors/white - :android {:padding-top 8 - :padding-bottom 8}}) + :flex 1}) (def action-button-label-disabled (merge action-button-label diff --git a/src/status_im/ui/components/bottom_sheet/styles.cljs b/src/status_im/ui/components/bottom_sheet/styles.cljs index a046f48a55..42c4ff5e61 100644 --- a/src/status_im/ui/components/bottom_sheet/styles.cljs +++ b/src/status_im/ui/components/bottom_sheet/styles.cljs @@ -35,7 +35,6 @@ :align-self :stretch :transform [{:translateY bottom-value}] :justify-content :flex-start - :align-items :center :padding-bottom bottom-padding}) (def content-header diff --git a/src/status_im/ui/screens/home/filter/views.cljs b/src/status_im/ui/screens/home/filter/views.cljs new file mode 100644 index 0000000000..d96ab865cc --- /dev/null +++ b/src/status_im/ui/screens/home/filter/views.cljs @@ -0,0 +1,140 @@ +(ns status-im.ui.screens.home.filter.views + (:require [status-im.ui.components.list.views :as list] + [status-im.ui.screens.home.styles :as styles] + [status-im.ui.components.react :as react] + [status-im.i18n :as i18n] + [status-im.ui.components.colors :as colors] + [status-im.ui.screens.home.views.inner-item :as inner-item] + [status-im.utils.utils :as utils] + [status-im.ui.components.animation :as animation] + [reagent.core :as reagent] + [re-frame.core :as re-frame] + [status-im.ui.components.icons.vector-icons :as icons])) + +(defn search-input [_ {:keys [on-cancel on-focus on-change]}] + (let [input-is-focused? (reagent/atom false) + input-ref (reagent/atom nil)] + (fn [search-filter] + (let [show-cancel? (or @input-is-focused? + search-filter)] + [react/view {:style styles/search-container} + [react/view {:style styles/search-input-container} + [icons/icon :main-icons/search {:color colors/gray + :container-style {:margin-left 6 + :margin-right 2}}] + [react/text-input {:placeholder (i18n/label :t/search) + :blur-on-submit true + :multiline false + :ref #(reset! input-ref %) + :style styles/search-input + :default-value search-filter + :on-focus #(do + (when on-focus + (on-focus search-filter)) + (reset! input-is-focused? true)) + :on-change (fn [e] + (let [native-event (.-nativeEvent e) + text (.-text native-event)] + (when on-change + (on-change text))))}]] + (when show-cancel? + [react/touchable-highlight + {:on-press #(do + (when on-cancel + (on-cancel)) + (.blur @input-ref) + (reset! input-is-focused? false)) + :style {:margin-left 16}} + [react/text {:style {:color colors/blue + :font-size 15}} + (i18n/label :t/cancel)]])])))) + +(defonce search-input-state + (reagent/atom {:show? false + :height (animation/create-value 0)})) + +(defn show-search! + [] + (swap! search-input-state assoc :show? true) + (animation/start + (animation/timing (:height @search-input-state) + {:toValue styles/search-input-height + :duration 350 + :easing (.out (animation/easing) + (.-quad (animation/easing)))}))) + +(defn hide-search! + [] + (utils/set-timeout + #(swap! search-input-state assoc :show? false) + 350) + (animation/start + (animation/timing (:height @search-input-state) + {:toValue 0 + :duration 350 + :easing (.in (animation/easing) + (.-quad (animation/easing)))}))) + +(defn set-search-state-visible! + [visible?] + (swap! search-input-state assoc :show? visible?) + (animation/set-value (:height @search-input-state) + (if visible? + styles/search-input-height + 0))) + +(defn animated-search-input + [search-filter] + (reagent/create-class + {:component-will-unmount + #(set-search-state-visible! false) + :component-did-mount + #(when search-filter + (set-search-state-visible! true)) + :reagent-render + (fn [search-filter] + (let [{:keys [show? height]} @search-input-state] + (when (or show? + search-filter) + [react/animated-view + {:style {:height height}} + [search-input search-filter + {:on-cancel #(do + (re-frame/dispatch [:search/filter-changed nil]) + (hide-search!)) + :on-focus (fn [search-filter] + (when-not search-filter + (re-frame/dispatch [:search/filter-changed ""]))) + :on-change (fn [text] + (re-frame/dispatch [:search/filter-changed text]))}]])))})) + +(defn home-filtered-items-list + [chats] + [list/section-list + {:sections [{:title :t/chats + :data chats} + {:title :t/messages + :data []}] + :key-fn first + ;; true by default on iOS + :stickySectionHeadersEnabled false + :render-section-header-fn (fn [{:keys [title data]}] + [react/view {:style {:height 40}} + [react/text {:style styles/filter-section-title} + (i18n/label title)]]) + :render-section-footer-f (fn [{:keys [title data]}] + (when (empty? data) + [list/big-list-item + {:text (i18n/label (if (= title "messages") + :t/messages-search-coming-soon + :t/no-result)) + :text-color colors/gray + :hide-chevron? true + :action-fn #() + :icon (case title + "messages" :main-icons/private-chat + "browser" :main-icons/browser + "chats" :main-icons/message) + :icon-color colors/gray}])) + :render-fn (fn [home-item] + [inner-item/home-list-item home-item])}]) \ No newline at end of file diff --git a/src/status_im/ui/screens/home/sheet/views.cljs b/src/status_im/ui/screens/home/sheet/views.cljs new file mode 100644 index 0000000000..4f30007faa --- /dev/null +++ b/src/status_im/ui/screens/home/sheet/views.cljs @@ -0,0 +1,54 @@ +(ns status-im.ui.screens.home.sheet.views + (:require [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.ui.components.action-button.action-button :as action-button] + [status-im.ui.components.action-button.styles :as action-button.styles] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.list-selection :as list-selection] + [status-im.ui.components.react :as react])) + +(defn hide-sheet-and-dispatch [event] + (re-frame/dispatch [:bottom-sheet/hide-sheet]) + (re-frame/dispatch event)) + +(defn add-new-view [] + [react/view {:flex 1 :flex-direction :row} + [react/view action-button.styles/actions-list + [action-button/action-button + {:label (i18n/label :t/start-new-chat) + :accessibility-label :start-1-1-chat-button + :icon :main-icons/private-chat + :icon-opts {:color colors/blue} + :on-press #(hide-sheet-and-dispatch [:navigate-to :new-chat])}] + [action-button/action-button + {:label (i18n/label :t/start-group-chat) + :accessibility-label :start-group-chat-button + :icon :main-icons/group-chat + :icon-opts {:color colors/blue} + :on-press #(hide-sheet-and-dispatch [:contact.ui/start-group-chat-pressed])}] + [action-button/action-button + {:label (i18n/label :t/new-public-group-chat) + :accessibility-label :join-public-chat-button + :icon :main-icons/public-chat + :icon-opts {:color colors/blue} + :on-press #(hide-sheet-and-dispatch [:navigate-to :new-public-chat])}] + [action-button/action-button + {:label (i18n/label :t/scan-qr) + :accessibility-label :scan-qr-code-button + :icon :main-icons/qr + :icon-opts {:color colors/blue} + :on-press #(hide-sheet-and-dispatch [:qr-scanner.ui/scan-qr-code-pressed + {:toolbar-title (i18n/label :t/scan-qr)} + :handle-qr-code])}] + [action-button/action-button + {:label (i18n/label :t/invite-friends) + :accessibility-label :invite-friends-button + :icon :main-icons/share + :icon-opts {:color colors/blue} + :on-press #(do + (re-frame/dispatch [:bottom-sheet/hide-sheet]) + (list-selection/open-share {:message (i18n/label :t/get-status-at)}))}]]]) + +(def add-new + {:content add-new-view + :content-height 320}) \ No newline at end of file diff --git a/src/status_im/ui/screens/home/styles.cljs b/src/status_im/ui/screens/home/styles.cljs index 431d5e6611..8cf83520ac 100644 --- a/src/status_im/ui/screens/home/styles.cljs +++ b/src/status_im/ui/screens/home/styles.cljs @@ -1,7 +1,8 @@ (ns status-im.ui.screens.home.styles (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) (:require [status-im.ui.components.colors :as colors] - [status-im.utils.platform :as platform])) + [status-im.utils.platform :as platform] + [status-im.ui.components.bottom-bar.styles :as tabs.styles])) (defn toolbar [] {:background-color colors/white}) @@ -76,14 +77,14 @@ :height 26}}) (defstyle private-group-icon-container - {:align-items :center + {:align-items :center :justify-content :center - :margin-right 6}) + :margin-right 6}) (defstyle public-group-icon-container - {:align-items :center + {:align-items :center :justify-content :center - :margin-right 6}) + :margin-right 6}) (def last-message-container {:flex-shrink 1}) @@ -115,8 +116,8 @@ :border-radius 8}) (def search-input - (merge {:flex 1 - :font-size 15} + (merge {:flex 1 + :font-size 15} (when platform/android? {:line-height 22 :margin 0 @@ -168,55 +169,51 @@ :margin-horizontal 34}) (def no-chats-text - {:line-height 21 - :text-align :center - :color colors/gray}) + {:line-height 22 + :font-size 15 + :text-align :center + :color colors/gray}) (def welcome-view {:flex 1}) -(defstyle welcome-image-container +(def welcome-image-container {:align-items :center - :android {:margin-top 38} - :ios {:margin-top 42}}) + :margin-top 42}) -(def welcome-image - {:width 320 - :height 278}) - -(defstyle welcome-text +(def welcome-text {:line-height 28 :font-size 22 :font-weight :bold - :android {:margin-top 22} - :ios {:margin-top 96} + :margin-top 32 :text-align :center :color colors/black}) -(defstyle welcome-text-description - {:line-height 21 - :margin-top 8 - :android {:margin-bottom 82} - :ios {:margin-bottom 32} - :text-align :center - :color colors/gray}) - -(def toolbar-logo - {:size 40 - :icon-size 17}) +(def welcome-text-description + {:line-height 22 + :font-size 15 + :margin-top 8 + :text-align :center + :margin-horizontal 32 + :color colors/gray}) (def action-button-container - {:position :absolute - :bottom 16 - :right 16}) + {:position :absolute + :align-items :center + :bottom (+ tabs.styles/tabs-diff 6) + :right 0 + :left 0}) (def action-button - {:width 56 - :height 56 + {:margin 10 + :width 40 + :height 40 :background-color colors/blue - :border-radius 28 + :border-radius 20 :align-items :center - :justify-content :center}) - -(def spinner-container - {:margin-right 10}) + :justify-content :center + :shadow-offset {:width 0 :height 1} + :shadow-radius 6 + :shadow-opacity 1 + :shadow-color "rgba(0, 12, 63, 0.2)" + :elevation 2}) diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index ca37dc5b6f..680c6b081b 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -3,239 +3,73 @@ [reagent.core :as reagent] [status-im.i18n :as i18n] [status-im.react-native.resources :as resources] - [status-im.ui.components.animation :as animation] [status-im.ui.components.colors :as colors] - [status-im.ui.components.common.common :as components.common] [status-im.ui.components.connectivity.view :as connectivity] [status-im.ui.components.icons.vector-icons :as icons] [status-im.ui.components.list.views :as list] [status-im.ui.components.react :as react] [status-im.ui.components.status-bar.view :as status-bar] - [status-im.ui.components.toolbar.actions :as toolbar.actions] [status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.screens.home.styles :as styles] - [status-im.ui.screens.home.views.inner-item :as inner-item] - [status-im.utils.platform :as platform] + [status-im.ui.screens.home.filter.views :as filter.views] [status-im.utils.utils :as utils] - [status-im.ui.components.bottom-bar.styles :as tabs.styles]) + [status-im.ui.components.bottom-bar.styles :as tabs.styles] + [status-im.ui.screens.home.views.inner-item :as inner-item] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.components.list-selection :as list-selection]) (:require-macros [status-im.utils.views :as views])) -(defn- toolbar [show-welcome? show-sync-state sync-state latest-block-number logged-in?] - (when-not (and show-welcome? - platform/android?) - [toolbar/toolbar nil nil - (when-not show-welcome? - (if show-sync-state - [react/view {:style styles/sync-wrapper} - [components.common/logo styles/toolbar-logo] +(views/defview les-debug-info [] + (views/letsubs [sync-state [:chain-sync-state] + latest-block-number [:latest-block-number] + rpc-network? [:current-network-uses-rpc?] + network-initialized? [:current-network-initialized?]] + (when (and network-initialized? (not rpc-network?)) + [react/view {:style styles/sync-wrapper} + [react/touchable-highlight {:on-press #(re-frame/dispatch [:home.ui/sync-info-pressed])} + [react/text {:style styles/sync-info} + (str "LES: 'latest' #" latest-block-number "\n" + (if sync-state + (str "syncing " (:currentBlock sync-state) " of " (:highestBlock sync-state) " blocks...") + (str "not syncing")))]]]))) - [react/touchable-highlight {:accessibility-label :new-chat-button - :on-press #(re-frame/dispatch [:home.ui/sync-info-pressed])} - [react/text {:style styles/sync-info} - (str "LES: 'latest' #" latest-block-number "\n" - (if sync-state - (str "syncing " (:currentBlock sync-state) " of " (:highestBlock sync-state) " blocks...") - (str "not syncing")))]]] - [components.common/logo styles/toolbar-logo])) - (cond - (and platform/ios? - logged-in?) - [toolbar/actions - [(-> (toolbar.actions/add true #(re-frame/dispatch [:navigate-to :new])) - (assoc-in [:icon-opts :accessibility-label] :new-chat-button))]] - platform/ios? - [react/view {:style styles/spinner-container} - [react/activity-indicator {:color colors/blue - :animating true}]])])) +(defn welcome [] + [react/view {:style styles/welcome-view} + [react/view {:flex 1}] + [status-bar/status-bar {:type :main}] + [react/view {:style styles/welcome-image-container} + [components.common/image-contain + {:container-style {}} + {:image (:welcome-image resources/ui) :width 750 :height 556}]] + [react/i18n-text {:style styles/welcome-text :key :welcome-to-status}] + [react/view + [react/i18n-text {:style styles/welcome-text-description + :key :welcome-to-status-description}]] + [react/view {:flex 1}] + [react/view {:align-items :center :margin-bottom 52} + [components.common/button {:on-press #(re-frame/dispatch [:navigate-back]) + :label (i18n/label :t/get-started)}]]]) -(defn- home-action-button [logged-in?] - [react/view styles/action-button-container - [react/touchable-highlight {:accessibility-label :new-chat-button - :on-press (when logged-in? #(re-frame/dispatch [:navigate-to :new]))} - [react/view styles/action-button - (if-not logged-in? - [react/activity-indicator {:color :white - :animating true}] - [icons/icon :main-icons/add {:color :white}])]]]) - -(defn home-list-item [[home-item-id home-item]] - (let [delete-action (if (and (:group-chat home-item) - (not (:public? home-item))) - :group-chats.ui/remove-chat-pressed - :chat.ui/remove-chat)] - [list/deletable-list-item {:type :chats - :id home-item-id - :on-delete #(do - (re-frame/dispatch [:set-swipe-position :chats home-item-id false]) - (re-frame/dispatch [delete-action home-item-id]))} - [inner-item/home-list-chat-item-inner-view home-item]])) - -;;do not remove view-id and will-update or will-unmount handlers, this is how it works -(views/defview welcome [view-id] - (views/letsubs [handler #(re-frame/dispatch [:set-in [:accounts/create :show-welcome?] false])] - {:component-will-update handler - :component-will-unmount handler} - [react/view {:style styles/welcome-view} - [react/view {:style styles/welcome-image-container} - [react/image {:source (:welcome-image resources/ui) - :style styles/welcome-image}]] - [react/i18n-text {:style styles/welcome-text :key :welcome-to-status}] - [react/view - [react/i18n-text {:style styles/welcome-text-description - :key :welcome-to-status-description}]]])) - -(defn search-input - [search-filter {:keys [on-cancel on-focus on-change]}] - (let [input-is-focused? (reagent/atom false) - input-ref (reagent/atom nil)] - (fn [search-filter] - (let [show-cancel? (or @input-is-focused? - search-filter)] - [react/view {:style styles/search-container} - [react/view {:style styles/search-input-container} - [icons/icon :main-icons/search {:color colors/gray - :container-style {:margin-left 6 - :margin-right 2}}] - [react/text-input {:placeholder (i18n/label :t/search) - :blur-on-submit true - :multiline false - :ref #(reset! input-ref %) - :style styles/search-input - :default-value search-filter - :on-focus - #(do - (when on-focus - (on-focus search-filter)) - (reset! input-is-focused? true)) - :on-change - (fn [e] - (let [native-event (.-nativeEvent e) - text (.-text native-event)] - (when on-change - (on-change text))))}]] - (when show-cancel? - [react/touchable-highlight - {:on-press #(do - (when on-cancel - (on-cancel)) - (.blur @input-ref) - (reset! input-is-focused? false)) - :style {:margin-left 16}} - [react/text {:style {:color colors/blue - :font-size 15}} - (i18n/label :t/cancel)]])])))) - -(defonce search-input-state - (reagent/atom {:show? false - :height (animation/create-value 0)})) - -(defn show-search! - [] - (swap! search-input-state assoc :show? true) - (animation/start - (animation/timing (:height @search-input-state) - {:toValue styles/search-input-height - :duration 350 - :easing (.out (animation/easing) - (.-quad (animation/easing)))}))) - -(defn hide-search! - [] - (utils/set-timeout - #(swap! search-input-state assoc :show? false) - 350) - (animation/start - (animation/timing (:height @search-input-state) - {:toValue 0 - :duration 350 - :easing (.in (animation/easing) - (.-quad (animation/easing)))}))) - -(defn set-search-state-visible! - [visible?] - (swap! search-input-state assoc :show? visible?) - (animation/set-value (:height @search-input-state) - (if visible? - styles/search-input-height - 0))) - -(defn animated-search-input - [search-filter] - (reagent/create-class - {:component-will-unmount - #(set-search-state-visible! false) - :component-did-mount - #(when search-filter - (set-search-state-visible! true)) - :reagent-render - (fn [search-filter] - (let [{:keys [show? height]} @search-input-state] - (when (or show? - search-filter) - [react/animated-view - {:style {:height height}} - [search-input search-filter - {:on-cancel #(do - (re-frame/dispatch [:search/filter-changed nil]) - (hide-search!)) - :on-focus (fn [search-filter] - (when-not search-filter - (re-frame/dispatch [:search/filter-changed ""]))) - :on-change (fn [text] - (re-frame/dispatch [:search/filter-changed text]))}]])))})) - -(defn home-empty-view - [] +(defn home-empty-view [] [react/view styles/no-chats - [react/i18n-text {:style styles/no-chats-text :key :no-recent-chats}]]) + [react/i18n-text {:style styles/no-chats-text :key :no-recent-chats}] + [react/view {:align-items :center :margin-top 20} + [components.common/button {:on-press #(list-selection/open-share {:message (i18n/label :t/get-status-at)}) + :label (i18n/label :t/invite-friends)}]]]) -(defn home-filtered-items-list - [chats] - [list/section-list - {:sections [{:title :t/chats - :data chats} - {:title :t/messages - :data []}] - :key-fn first - ;; true by default on iOS - :stickySectionHeadersEnabled false - :render-section-header-fn - (fn [{:keys [title data]}] - [react/view {:style {:height 40}} - [react/text {:style styles/filter-section-title} - (i18n/label title)]]) - :render-section-footer-fn - (fn [{:keys [title data]}] - (when (empty? data) - [list/big-list-item - {:text (i18n/label (if (= title "messages") - :t/messages-search-coming-soon - :t/no-result)) - :text-color colors/gray - :hide-chevron? true - :action-fn #() - :icon (case title - "messages" :main-icons/private-chat - "browser" :main-icons/browser - "chats" :main-icons/message) - :icon-color colors/gray}])) - :render-fn (fn [home-item] - [home-list-item home-item])}]) - -(defn home-items-view - [search-filter chats all-home-items] - (let [previous-touch (reagent/atom nil) +(defn home-items-view [_ _ _] + (let [previous-touch (reagent/atom nil) scrolling-from-top? (reagent/atom true)] (fn [search-filter chats all-home-items] (if (not-empty search-filter) - [home-filtered-items-list chats] + [filter.views/home-filtered-items-list chats] [react/view (merge {:style {:flex 1}} (when (and @scrolling-from-top? - (not (:show? @search-input-state))) + (not (:show? @filter.views/search-input-state))) {:on-start-should-set-responder-capture (fn [event] - (let [current-position (.-pageY (.-nativeEvent event)) + (let [current-position (.-pageY (.-nativeEvent event)) current-timestamp (.-timestamp (.-nativeEvent event))] (reset! previous-touch [current-position current-timestamp])) @@ -243,14 +77,14 @@ false) :on-move-should-set-responder (fn [event] - (let [current-position (.-pageY (.-nativeEvent event)) + (let [current-position (.-pageY (.-nativeEvent event)) current-timestamp (.-timestamp (.-nativeEvent event)) [previous-position previous-timestamp] @previous-touch] (when (and previous-position (> 100 (- current-timestamp previous-timestamp)) (< 10 (- current-position previous-position))) - (show-search!))) + (filter.views/show-search!))) false)})) [list/flat-list {:data all-home-items :key-fn first @@ -265,34 +99,31 @@ (zero? (.-y (.-contentOffset (.-nativeEvent e)))))) :render-fn (fn [home-item] - [home-list-item home-item])}]])))) + [inner-item/home-list-item home-item])}]])))) + +(views/defview home-action-button [] + (views/letsubs [logging-in? [:get :accounts/login]] + [react/view styles/action-button-container + [react/touchable-highlight {:accessibility-label :new-chat-button + :on-press (when-not logging-in? #(re-frame/dispatch [:bottom-sheet/show-sheet :add-new]))} + [react/view styles/action-button + (if logging-in? + [react/activity-indicator {:color :white + :animating true}] + [icons/icon :main-icons/add {:color :white}])]]])) (views/defview home [loading?] - (views/letsubs [show-welcome? [:get-in [:accounts/create :show-welcome?]] - view-id [:get :view-id] - logging-in? [:get :accounts/login] - sync-state [:chain-sync-state] - latest-block-number [:latest-block-number] - rpc-network? [:current-network-uses-rpc?] - network-initialized? [:current-network-initialized?] - {:keys [search-filter chats all-home-items]} [:home-items]] - {:component-did-mount - (fn [this] - (let [[_ loading?] (.. this -props -argv)] - (when loading? - (utils/set-timeout - #(re-frame/dispatch [:init-rest-of-chats]) - 100))))} + (views/letsubs [{:keys [search-filter chats all-home-items]} [:home-items]] + {:component-did-mount (fn [this] + (let [[_ loading?] (.. this -props -argv)] + (when loading? (utils/set-timeout #(re-frame/dispatch [:init-rest-of-chats]) 100))))} [react/view {:flex 1} [status-bar/status-bar {:type :main}] [react/keyboard-avoiding-view {:style {:flex 1 :background-color :white}} - [toolbar show-welcome? (and network-initialized? (not rpc-network?)) - sync-state latest-block-number (not logging-in?)] - (cond show-welcome? - [welcome view-id] - - loading? + [toolbar/toolbar nil nil [toolbar/content-title (i18n/label :t/chat)]] + [les-debug-info] + (cond loading? [react/view {:style {:flex 1 :justify-content :center :align-items :center}} @@ -303,13 +134,12 @@ :else [react/view {:style {:flex 1}} [connectivity/connectivity-view] - [animated-search-input search-filter] + [filter.views/animated-search-input search-filter] (if (and (not search-filter) (empty? all-home-items)) [home-empty-view] [home-items-view search-filter chats all-home-items])]) - (when platform/android? - [home-action-button (not logging-in?)])]])) + [home-action-button]]])) (views/defview home-wrapper [] (views/letsubs [loading? [:get :chats/loading?]] diff --git a/src/status_im/ui/screens/home/views/inner_item.cljs b/src/status_im/ui/screens/home/views/inner_item.cljs index 6894647fd5..65d8629ff9 100644 --- a/src/status_im/ui/screens/home/views/inner_item.cljs +++ b/src/status_im/ui/screens/home/views/inner_item.cljs @@ -16,7 +16,8 @@ [status-im.ui.components.common.common :as components.common] [status-im.ui.components.list-item.views :as list-item] [clojure.string :as string] - [status-im.ui.components.chat-icon.screen :as chat-icon])) + [status-im.ui.components.chat-icon.screen :as chat-icon] + [status-im.ui.components.list.views :as list])) (defview command-short-preview [message] (letsubs [id->command [:chats/id->command] @@ -112,6 +113,18 @@ :content-type last-message-content-type}] [unviewed-indicator chat-id]]]]])) +(defn home-list-item [[home-item-id home-item]] + (let [delete-action (if (and (:group-chat home-item) + (not (:public? home-item))) + :group-chats.ui/remove-chat-pressed + :chat.ui/remove-chat)] + [list/deletable-list-item {:type :chats + :id home-item-id + :on-delete #(do + (re-frame/dispatch [:set-swipe-position :chats home-item-id false]) + (re-frame/dispatch [delete-action home-item-id]))} + [home-list-chat-item-inner-view home-item]])) + (defn home-list-browser-item-inner-view [{:keys [dapp url name browser-id]}] (let [photo-path (:photo-path dapp)] [list-item/list-item (merge diff --git a/src/status_im/ui/screens/routing/modals.cljs b/src/status_im/ui/screens/routing/modals.cljs index cb70167704..c013dda365 100644 --- a/src/status_im/ui/screens/routing/modals.cljs +++ b/src/status_im/ui/screens/routing/modals.cljs @@ -20,4 +20,5 @@ :wallet-settings-assets :wallet-transaction-fee :wallet-transactions-filter - :profile-qr-viewer]) + :profile-qr-viewer + :welcome]) diff --git a/src/status_im/ui/screens/routing/screens.cljs b/src/status_im/ui/screens/routing/screens.cljs index 9a1dbd71f4..7bd5e03138 100644 --- a/src/status_im/ui/screens/routing/screens.cljs +++ b/src/status_im/ui/screens/routing/screens.cljs @@ -142,7 +142,8 @@ :tribute-to-talk tr-to-talk/tribute-to-talk :reset-card hardwallet.settings/reset-card :keycard-settings hardwallet.settings/keycard-settings - :mobile-network-settings mobile-network-settings/mobile-network-settings}) + :mobile-network-settings mobile-network-settings/mobile-network-settings + :welcome [:modal home/welcome]}) (defn get-screen [screen] (get all-screens screen #(throw (str "Screen " screen " is not defined.")))) diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 76daea5383..b5cf151a87 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -12,6 +12,7 @@ [taoensso.timbre :as log] [status-im.utils.platform :as platform] [status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings] + [status-im.ui.screens.home.sheet.views :as home.sheet] [status-im.ui.screens.routing.core :as routing])) (defonce rand-label (rand/id)) @@ -27,7 +28,11 @@ (merge mobile-network-settings/settings-sheet) (= view :mobile-network-offline) - (merge mobile-network-settings/offline-sheet))] + (merge mobile-network-settings/offline-sheet) + + (= view :add-new) + (merge home.sheet/add-new))] + [bottom-sheet/bottom-sheet opts]))) (defn main [] diff --git a/translations/en.json b/translations/en.json index d9b2b097f9..3baf07f93b 100644 --- a/translations/en.json +++ b/translations/en.json @@ -265,7 +265,7 @@ "mailserver-connection-error": "Could not connect to mailserver", "mailserver-automatic": "Automatic selection", "currency-display-name-kzt": "Kazakhstan Tenge", - "no-recent-chats": "Your Home screen will house your recent chats and DApp history. Tap the plus (+) button to get started.", + "no-recent-chats": "There are no recent chats here yet. \nUse the (+) button to discover people \nto chat with", "install": "Install", "command-requesting": "Requesting {{amount}} {{asset}}", "mailserver-details": "Mailserver details", @@ -677,7 +677,7 @@ "ethereum-node-started-incorrectly-title": "Ethereum node started incorrectly", "ethereum-node-started-incorrectly-description": "Ethereum node was started with incorrect configuration, application will be stopped to recover from that condition. Configured network id = {{network-id}}, actual = {{fetched-network-id}}", "browser-not-secure": "Connection is not secure! Do not sign transactions or send personal data on this site.", - "welcome-to-status-description": "Tap the plus (+) button to get started", + "welcome-to-status-description": "Here you can chat with people in a secure private chat, browse and interact with DApps.", "recovery-phrase-invalid": "Recovery phrase is invalid", "currency-display-name-cny": "China Yuan Renminbi", "clear-history-confirmation-content": "Are you sure you want to clear this chat history?",