* Small typo fix * Move header-spacing & empty-state to common.home namespace * Create common animated banner component for chats and communities * Add animated banner to chats tab
This commit is contained in:
parent
f6ce63734c
commit
7ad378e9c8
|
@ -32,7 +32,7 @@
|
|||
|
||||
(defn section-list
|
||||
"A wrapper for SectionList.
|
||||
To render something on empty sections, use renderSectionFooter and conditionaly
|
||||
To render something on empty sections, use renderSectionFooter and conditionally
|
||||
render on empty data
|
||||
See https://facebook.github.io/react-native/docs/sectionlist.html"
|
||||
[{:keys [sections render-section-header-fn render-section-footer-fn style] :as props}]
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
(ns status-im2.common.home.banner.style
|
||||
(:require [react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def ^:private card-height (+ 56 16))
|
||||
(def ^:private max-scroll (+ card-height 8))
|
||||
|
||||
(def fill-space
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:right 0
|
||||
:left 0
|
||||
:bottom 0})
|
||||
|
||||
(defn- animated-card-translation-y
|
||||
[scroll-shared-value]
|
||||
(reanimated/interpolate scroll-shared-value [0 max-scroll] [0 (- max-scroll)] :clamp))
|
||||
|
||||
(defn banner-card-blur-layer
|
||||
[scroll-shared-value]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y (animated-card-translation-y scroll-shared-value)}]}
|
||||
{:overflow (if platform/ios? :visible :hidden)
|
||||
:z-index 1
|
||||
:position :absolute
|
||||
:top 0
|
||||
:right 0
|
||||
:left 0
|
||||
:height (+ (safe-area/get-top) 244)}))
|
||||
|
||||
(defn banner-card-hiding-layer
|
||||
[]
|
||||
{:z-index 2
|
||||
:position :absolute
|
||||
:top 0
|
||||
:right 0
|
||||
:left 0
|
||||
:padding-top (safe-area/get-top)})
|
||||
|
||||
(def animated-banner-card-container {:overflow :hidden})
|
||||
|
||||
(defn animated-banner-card
|
||||
[scroll-shared-value]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity (reanimated/interpolate scroll-shared-value [0 card-height] [1 0] :clamp)
|
||||
:transform [{:translate-y (animated-card-translation-y scroll-shared-value)}]}
|
||||
{}))
|
||||
|
||||
(defn banner-card-tabs-layer
|
||||
[scroll-shared-value]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y (animated-card-translation-y scroll-shared-value)}]}
|
||||
{:z-index 3
|
||||
:position :absolute
|
||||
:top (+ (safe-area/get-top) 192)
|
||||
:right 0
|
||||
:left 0}))
|
||||
|
||||
(def banner-card-tabs
|
||||
{:padding-horizontal 20
|
||||
:padding-top 8
|
||||
:padding-bottom 12})
|
|
@ -0,0 +1,78 @@
|
|||
(ns status-im2.common.home.banner.view
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.common.home.banner.style :as style]
|
||||
[status-im2.common.home.view :as common.home]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- reset-banner-animation
|
||||
[scroll-shared-value]
|
||||
(reanimated/animate-shared-value-with-timing scroll-shared-value 0 200 :easing3))
|
||||
|
||||
(defn- reset-scroll
|
||||
[scroll-ref]
|
||||
(cond
|
||||
(.-scrollToLocation scroll-ref)
|
||||
(oops/ocall! scroll-ref "scrollToLocation" #js {:itemIndex 0 :sectionIndex 0 :viewOffset 0})
|
||||
(.-scrollToOffset scroll-ref)
|
||||
(oops/ocall! scroll-ref "scrollToOffset" #js {:offset 0})))
|
||||
|
||||
(defn- banner-card-blur-layer
|
||||
[scroll-shared-value]
|
||||
(let [open-sheet? (-> (rf/sub [:bottom-sheet]) :sheets seq)]
|
||||
[reanimated/view {:style (style/banner-card-blur-layer scroll-shared-value)}
|
||||
[blur/view
|
||||
{:style style/fill-space
|
||||
:blur-amount (if platform/ios? 20 10)
|
||||
:blur-type (theme/theme-value (if platform/ios? :light :xlight) :dark)
|
||||
:overlay-color (if open-sheet?
|
||||
(colors/theme-colors colors/white colors/neutral-95-opa-70)
|
||||
(theme/theme-value nil colors/neutral-95-opa-70))}]]))
|
||||
|
||||
(defn- banner-card-hiding-layer
|
||||
[{:keys [title-props card-props scroll-shared-value]}]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])]
|
||||
[rn/view {:style (style/banner-card-hiding-layer)}
|
||||
[common.home/top-nav {:type :grey}]
|
||||
[common.home/title-column (assoc title-props :customization-color customization-color)]
|
||||
[rn/view {:style style/animated-banner-card-container}
|
||||
[reanimated/view {:style (style/animated-banner-card scroll-shared-value)}
|
||||
[quo/discover-card card-props]]]]))
|
||||
|
||||
(defn- banner-card-tabs-layer
|
||||
[{:keys [selected-tab tabs on-tab-change scroll-ref scroll-shared-value]}]
|
||||
[reanimated/view {:style (style/banner-card-tabs-layer scroll-shared-value)}
|
||||
^{:key (str "tabs-" selected-tab)}
|
||||
[quo/tabs
|
||||
{:style style/banner-card-tabs
|
||||
:size 32
|
||||
:default-active selected-tab
|
||||
:data tabs
|
||||
:on-change (fn [tab]
|
||||
(reset-banner-animation scroll-shared-value)
|
||||
(some-> scroll-ref
|
||||
deref
|
||||
reset-scroll)
|
||||
(on-tab-change tab))}]])
|
||||
|
||||
(defn animated-banner
|
||||
[{:keys [scroll-ref tabs selected-tab on-tab-change scroll-shared-value content]}]
|
||||
[:<>
|
||||
[:f> banner-card-blur-layer scroll-shared-value]
|
||||
[:f> banner-card-hiding-layer (assoc content :scroll-shared-value scroll-shared-value)]
|
||||
[:f> banner-card-tabs-layer
|
||||
{:scroll-shared-value scroll-shared-value
|
||||
:selected-tab selected-tab
|
||||
:tabs tabs
|
||||
:on-tab-change on-tab-change
|
||||
:scroll-ref scroll-ref}]])
|
||||
|
||||
(defn set-scroll-shared-value
|
||||
[{:keys [shared-value scroll-input]}]
|
||||
(reanimated/set-shared-value shared-value scroll-input))
|
|
@ -1,4 +1,5 @@
|
|||
(ns status-im2.common.home.style)
|
||||
(ns status-im2.common.home.style
|
||||
(:require [react-native.safe-area :as safe-area]))
|
||||
|
||||
(def title-column
|
||||
{:flex-direction :row
|
||||
|
@ -44,3 +45,16 @@
|
|||
|
||||
(def top-nav-container
|
||||
{:height 56})
|
||||
|
||||
(def header-height 245)
|
||||
|
||||
(defn header-spacing
|
||||
[]
|
||||
{:height (+ header-height (safe-area/get-top))})
|
||||
|
||||
(defn empty-state-container
|
||||
[]
|
||||
{:flex 1
|
||||
:margin-top (+ header-height (safe-area/get-top))
|
||||
:margin-bottom 44
|
||||
:justify-content :center})
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.common.home.style :as style]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im2.common.home.style :as style]
|
||||
[status-im2.common.plus-button.view :as plus-button]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.debounce :refer [dispatch-and-chill]]))
|
||||
[utils.debounce :refer [dispatch-and-chill]]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn title-column
|
||||
[{:keys [label handler accessibility-label customization-color]}]
|
||||
|
@ -130,3 +130,18 @@
|
|||
[rn/view {:style (merge style/top-nav-container style)}
|
||||
[left-section {:avatar avatar}]
|
||||
[right-section {:button-type type :button-background background :search? search?}]]))
|
||||
|
||||
(defn header-spacing
|
||||
[]
|
||||
[rn/view {:style (style/header-spacing)}])
|
||||
|
||||
(defn empty-state-image
|
||||
[{:keys [selected-tab tab->content]}]
|
||||
(let [{:keys [image title description]} (tab->content selected-tab)
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[rn/view {:style (style/empty-state-container)}
|
||||
[quo/empty-state
|
||||
{:customization-color customization-color
|
||||
:image image
|
||||
:title title
|
||||
:description description}]]))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im2.contexts.chat.home.style
|
||||
(:require [react-native.platform :as platform]))
|
||||
(:require [react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def tabs
|
||||
{:padding-horizontal 20
|
||||
|
@ -14,24 +15,11 @@
|
|||
:bottom 0})
|
||||
|
||||
(defn blur-container
|
||||
[top]
|
||||
[]
|
||||
{:overflow (if platform/ios? :visible :hidden)
|
||||
:position :absolute
|
||||
:z-index 1
|
||||
:top 0
|
||||
:right 0
|
||||
:left 0
|
||||
:padding-top top})
|
||||
|
||||
(def header-height 245)
|
||||
|
||||
(defn header-space
|
||||
[top]
|
||||
{:height (+ header-height top)})
|
||||
|
||||
(defn empty-content-container
|
||||
[top]
|
||||
{:flex 1
|
||||
:margin-top (+ header-height top)
|
||||
:margin-bottom 44
|
||||
:justify-content :center})
|
||||
:padding-top (safe-area/get-top)})
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
(ns status-im2.contexts.chat.home.view
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.theme :as theme]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.common.contact-list-item.view :as contact-list-item]
|
||||
[status-im2.common.contact-list.view :as contact-list]
|
||||
[status-im2.common.home.actions.view :as actions]
|
||||
[status-im2.common.home.banner.view :as common.home.banner]
|
||||
[status-im2.common.home.view :as common.home]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im2.contexts.chat.actions.view :as home.sheet]
|
||||
[status-im2.contexts.chat.actions.view :as chat.actions.view]
|
||||
[status-im2.contexts.chat.home.chat-list-item.view :as chat-list-item]
|
||||
[status-im2.contexts.chat.home.contact-request.view :as contact-request]
|
||||
[status-im2.contexts.chat.home.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -30,50 +27,45 @@
|
|||
(filter k)
|
||||
(sort-by :timestamp >))))
|
||||
|
||||
(defn empty-state-content
|
||||
[selected-tab]
|
||||
(case selected-tab
|
||||
:tab/contacts
|
||||
{:title (i18n/label :t/no-contacts)
|
||||
:description (i18n/label :t/no-contacts-description)
|
||||
:image (resources/get-image
|
||||
(theme/theme-value :no-contacts-light :no-contacts-dark))}
|
||||
:tab/groups
|
||||
{:title (i18n/label :t/no-group-chats)
|
||||
:description (i18n/label :t/no-group-chats-description)
|
||||
:image (resources/get-image
|
||||
(theme/theme-value :no-group-chats-light :no-group-chats-dark))}
|
||||
:tab/recent
|
||||
{:title (i18n/label :t/no-messages)
|
||||
:description (i18n/label :t/no-messages-description)
|
||||
:image (resources/get-image
|
||||
(theme/theme-value :no-messages-light :no-messages-dark))}
|
||||
nil))
|
||||
|
||||
(defn empty-state
|
||||
[{:keys [selected-tab top]}]
|
||||
(let [{:keys [image title description]} (empty-state-content selected-tab)]
|
||||
[rn/view {:style (style/empty-content-container top)}
|
||||
[quo/empty-state
|
||||
{:image image
|
||||
:title title
|
||||
:description description}]]))
|
||||
(def empty-state-content
|
||||
#:tab{:contacts
|
||||
{:title (i18n/label :t/no-contacts)
|
||||
:description (i18n/label :t/no-contacts-description)
|
||||
:image (resources/get-image
|
||||
(theme/theme-value :no-contacts-light :no-contacts-dark))}
|
||||
:groups
|
||||
{:title (i18n/label :t/no-group-chats)
|
||||
:description (i18n/label :t/no-group-chats-description)
|
||||
:image (resources/get-image
|
||||
(theme/theme-value :no-group-chats-light :no-group-chats-dark))}
|
||||
:recent
|
||||
{:title (i18n/label :t/no-messages)
|
||||
:description (i18n/label :t/no-messages-description)
|
||||
:image (resources/get-image
|
||||
(theme/theme-value :no-messages-light :no-messages-dark))}})
|
||||
|
||||
(defn chats
|
||||
[selected-tab top]
|
||||
[{:keys [selected-tab set-scroll-ref scroll-shared-value]}]
|
||||
(let [unfiltered-items (rf/sub [:chats-stack-items])
|
||||
items (filter-and-sort-items-by-tab selected-tab unfiltered-items)]
|
||||
(if (empty? items)
|
||||
[empty-state {:top top :selected-tab selected-tab}]
|
||||
[rn/flat-list
|
||||
{:key-fn #(or (:chat-id %) (:public-key %) (:id %))
|
||||
[common.home/empty-state-image
|
||||
{:selected-tab selected-tab
|
||||
:tab->content empty-state-content}]
|
||||
[reanimated/flat-list
|
||||
{:ref set-scroll-ref
|
||||
:key-fn #(or (:chat-id %) (:public-key %) (:id %))
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [rn/view {:style (style/header-space top)}]
|
||||
:header [common.home/header-spacing]
|
||||
:get-item-layout get-item-layout
|
||||
:on-end-reached #(re-frame/dispatch [:chat/show-more-chats])
|
||||
:keyboard-should-persist-taps :always
|
||||
:data items
|
||||
:render-fn chat-list-item/chat-list-item}])))
|
||||
:render-fn chat-list-item/chat-list-item
|
||||
:scroll-event-throttle 8
|
||||
:on-scroll #(common.home.banner/set-scroll-shared-value
|
||||
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})}])))
|
||||
|
||||
(defn contact-item-render
|
||||
[{:keys [public-key] :as item}]
|
||||
|
@ -89,23 +81,30 @@
|
|||
item]))
|
||||
|
||||
(defn contacts
|
||||
[pending-contact-requests top]
|
||||
[{:keys [pending-contact-requests set-scroll-ref scroll-shared-value]}]
|
||||
(let [items (rf/sub [:contacts/active-sections])]
|
||||
(if (and (empty? items) (empty? pending-contact-requests))
|
||||
[empty-state {:top top :selected-tab :tab/contacts}]
|
||||
[common.home/empty-state-image
|
||||
{:selected-tab :tab/contacts
|
||||
:tab->content empty-state-content}]
|
||||
[rn/section-list
|
||||
{:key-fn :public-key
|
||||
{:ref set-scroll-ref
|
||||
:key-fn :public-key
|
||||
:get-item-layout get-item-layout
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [:<>
|
||||
[rn/view {:style (style/header-space top)}]
|
||||
[common.home/header-spacing]
|
||||
(when (seq pending-contact-requests)
|
||||
[contact-request/contact-requests
|
||||
pending-contact-requests])]
|
||||
:sections items
|
||||
:sticky-section-headers-enabled false
|
||||
:render-section-header-fn contact-list/contacts-section-header
|
||||
:render-fn contact-item-render}])))
|
||||
:render-fn contact-item-render
|
||||
:scroll-event-throttle 8
|
||||
:on-scroll #(common.home.banner/set-scroll-shared-value
|
||||
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})}])))
|
||||
|
||||
(defn get-tabs-data
|
||||
[dot?]
|
||||
|
@ -116,41 +115,39 @@
|
|||
:accessibility-label :tab-contacts
|
||||
:notification-dot? dot?}])
|
||||
|
||||
(def ^:private banner-data
|
||||
{:title-props
|
||||
{:label (i18n/label :t/messages)
|
||||
:handler #(rf/dispatch
|
||||
[:show-bottom-sheet {:content chat.actions.view/new-chat}])
|
||||
:accessibility-label :new-chat-button}
|
||||
:card-props
|
||||
{:banner (resources/get-image :invite-friends)
|
||||
:title (i18n/label :t/invite-friends-to-status)
|
||||
:description (i18n/label :t/share-invite-link)}})
|
||||
|
||||
(defn home
|
||||
[]
|
||||
(let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
|
||||
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
top (safe-area/get-top)]
|
||||
[:<>
|
||||
(if (= selected-tab :tab/contacts)
|
||||
[contacts pending-contact-requests top]
|
||||
[chats selected-tab top])
|
||||
[rn/view {:style (style/blur-container top)}
|
||||
(let [{:keys [sheets]} (rf/sub [:bottom-sheet])]
|
||||
[blur/view
|
||||
{:blur-amount (if platform/ios? 20 10)
|
||||
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
|
||||
:style style/blur
|
||||
:overlay-color (if (seq sheets)
|
||||
(theme/theme-value colors/white colors/neutral-95-opa-70)
|
||||
(when (colors/dark?)
|
||||
colors/neutral-95-opa-70))}])
|
||||
[common.home/top-nav {:type :grey}]
|
||||
[common.home/title-column
|
||||
{:label (i18n/label :t/messages)
|
||||
:handler #(rf/dispatch [:show-bottom-sheet {:content home.sheet/new-chat}])
|
||||
:accessibility-label :new-chat-button
|
||||
:customization-color customization-color}]
|
||||
[quo/discover-card
|
||||
{:banner (resources/get-image :invite-friends)
|
||||
:title (i18n/label :t/invite-friends-to-status)
|
||||
:description (i18n/label :t/share-invite-link)}]
|
||||
^{:key (str "tabs-" selected-tab)}
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:on-change (fn [tab]
|
||||
(rf/dispatch [:messages-home/select-tab tab]))
|
||||
:default-active selected-tab
|
||||
:data (get-tabs-data (pos? (count pending-contact-requests)))}]]]))
|
||||
(let [scroll-ref (atom nil)
|
||||
set-scroll-ref #(reset! scroll-ref %)]
|
||||
(fn []
|
||||
(let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])
|
||||
selected-tab (or (rf/sub [:messages-home/selected-tab]) :tab/recent)
|
||||
scroll-shared-value (reanimated/use-shared-value 0)]
|
||||
[:<>
|
||||
(if (= selected-tab :tab/contacts)
|
||||
[contacts
|
||||
{:pending-contact-requests pending-contact-requests
|
||||
:set-scroll-ref set-scroll-ref
|
||||
:scroll-shared-value scroll-shared-value}]
|
||||
[chats
|
||||
{:selected-tab selected-tab
|
||||
:set-scroll-ref set-scroll-ref
|
||||
:scroll-shared-value scroll-shared-value}])
|
||||
[:f> common.home.banner/animated-banner
|
||||
{:content banner-data
|
||||
:scroll-ref scroll-ref
|
||||
:tabs (get-tabs-data (pos? (count pending-contact-requests)))
|
||||
:selected-tab selected-tab
|
||||
:on-tab-change (fn [tab] (rf/dispatch [:messages-home/select-tab tab]))
|
||||
:scroll-shared-value scroll-shared-value}]]))))
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
(ns status-im2.contexts.communities.home.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(def header-height 245)
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def tabs
|
||||
{:padding-horizontal 20
|
||||
|
@ -18,22 +16,11 @@
|
|||
:left 0
|
||||
:bottom 0})
|
||||
|
||||
(defn empty-state-container
|
||||
[]
|
||||
{:margin-top (+ header-height (safe-area/get-top))
|
||||
:margin-bottom 44
|
||||
:flex 1
|
||||
:justify-content :center})
|
||||
|
||||
(def empty-state-placeholder
|
||||
{:height 120
|
||||
:width 120
|
||||
:background-color colors/danger-50})
|
||||
|
||||
(defn header-spacing
|
||||
[]
|
||||
{:height (+ header-height (safe-area/get-top))})
|
||||
|
||||
(defn blur-banner-layer
|
||||
[animated-translation-y]
|
||||
(let [fixed-height (+ (safe-area/get-top) 244)]
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
(ns status-im2.contexts.communities.home.view
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.common.home.banner.view :as common.home.banner]
|
||||
[status-im2.common.home.view :as common.home]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im2.contexts.communities.actions.community-options.view :as options]
|
||||
[status-im2.contexts.communities.actions.home-plus.view :as actions.home-plus]
|
||||
[status-im2.contexts.communities.home.style :as style]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.number]
|
||||
|
@ -40,122 +37,43 @@
|
|||
{:id :pending :label (i18n/label :t/pending) :accessibility-label :pending-tab}
|
||||
{:id :opened :label (i18n/label :t/opened) :accessibility-label :opened-tab}])
|
||||
|
||||
(defn empty-state-content
|
||||
[selected-tab]
|
||||
(case selected-tab
|
||||
:joined
|
||||
{:title (i18n/label :t/no-communities)
|
||||
:description [:<>
|
||||
[rn/text {:style {:text-decoration-line :line-through}}
|
||||
(i18n/label :t/no-communities-description-strikethrough)]
|
||||
" "
|
||||
(i18n/label :t/no-communities-description)]
|
||||
:image (resources/get-image (theme/theme-value :no-communities-light
|
||||
:no-communities-dark))}
|
||||
:pending
|
||||
{:title (i18n/label :t/no-pending-communities)
|
||||
:description (i18n/label :t/no-pending-communities-description)
|
||||
:image (resources/get-image (theme/theme-value :no-pending-communities-light
|
||||
:no-pending-communities-dark))}
|
||||
:opened
|
||||
{:title (i18n/label :t/no-opened-communities)
|
||||
:description (i18n/label :t/no-opened-communities-description)
|
||||
:image (resources/get-image (theme/theme-value :no-opened-communities-light
|
||||
:no-opened-communities-dark))}
|
||||
nil))
|
||||
(def empty-state-content
|
||||
{:joined
|
||||
{:title (i18n/label :t/no-communities)
|
||||
:description [:<>
|
||||
[rn/text {:style {:text-decoration-line :line-through}}
|
||||
(i18n/label :t/no-communities-description-strikethrough)]
|
||||
" "
|
||||
(i18n/label :t/no-communities-description)]
|
||||
:image (resources/get-image (theme/theme-value :no-communities-light
|
||||
:no-communities-dark))}
|
||||
:pending
|
||||
{:title (i18n/label :t/no-pending-communities)
|
||||
:description (i18n/label :t/no-pending-communities-description)
|
||||
:image (resources/get-image (theme/theme-value :no-pending-communities-light
|
||||
:no-pending-communities-dark))}
|
||||
:opened
|
||||
{:title (i18n/label :t/no-opened-communities)
|
||||
:description (i18n/label :t/no-opened-communities-description)
|
||||
:image (resources/get-image (theme/theme-value :no-opened-communities-light
|
||||
:no-opened-communities-dark))}})
|
||||
|
||||
(defn- empty-state
|
||||
[{:keys [style selected-tab]}]
|
||||
(let [{:keys [image title description]} (empty-state-content selected-tab)
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[rn/view {:style style}
|
||||
[quo/empty-state
|
||||
{:customization-color customization-color
|
||||
:image image
|
||||
:title title
|
||||
:description description}]]))
|
||||
|
||||
(defn- blur-banner-layer
|
||||
[animated-translation-y]
|
||||
(let [open-sheet? (-> (rf/sub [:bottom-sheet]) :sheets seq)]
|
||||
[reanimated/view {:style (style/blur-banner-layer animated-translation-y)}
|
||||
[blur/view
|
||||
{:blur-amount (if platform/ios? 20 10)
|
||||
:blur-type (theme/theme-value (if platform/ios? :light :xlight) :dark)
|
||||
:style style/blur
|
||||
:overlay-color (if open-sheet?
|
||||
(colors/theme-colors colors/white colors/neutral-95-opa-70)
|
||||
(theme/theme-value nil colors/neutral-95-opa-70))}]]))
|
||||
|
||||
(defn- hiding-banner-layer
|
||||
[animated-translation-y animated-opacity]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])]
|
||||
[rn/view {:style (style/hiding-banner-layer)}
|
||||
[common.home/top-nav {:type :grey}]
|
||||
[common.home/title-column
|
||||
{:label (i18n/label :t/communities)
|
||||
:handler #(rf/dispatch
|
||||
[:show-bottom-sheet {:content actions.home-plus/view}])
|
||||
:accessibility-label :new-communities-button
|
||||
:customization-color customization-color}]
|
||||
[rn/view {:style style/animated-card-container}
|
||||
[reanimated/view {:style (style/animated-card animated-opacity animated-translation-y)}
|
||||
[quo/discover-card
|
||||
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
|
||||
:title (i18n/label :t/discover)
|
||||
:description (i18n/label :t/favorite-communities)
|
||||
:banner (resources/get-image :discover)
|
||||
:accessibility-label :communities-home-discover-card}]]]]))
|
||||
|
||||
(defn- reset-banner-animation
|
||||
[animated-opacity animated-translation-y]
|
||||
(reanimated/animate-shared-value-with-timing animated-opacity 1 200 :easing3)
|
||||
(reanimated/animate-shared-value-with-timing animated-translation-y 0 200 :easing3))
|
||||
|
||||
(defn- reset-scroll
|
||||
[flat-list-ref]
|
||||
(some-> flat-list-ref
|
||||
(.scrollToOffset #js {:offset 0 :animated? true})))
|
||||
|
||||
(defn- tabs-banner-layer
|
||||
[animated-translation-y animated-opacity selected-tab flat-list-ref]
|
||||
(let [on-tab-change (fn [tab]
|
||||
(if (empty? (get (rf/sub [:communities/grouped-by-status]) tab))
|
||||
(reset-banner-animation animated-opacity animated-translation-y)
|
||||
(reset-scroll @flat-list-ref))
|
||||
(rf/dispatch [:communities/select-tab tab]))]
|
||||
[reanimated/view {:style (style/tabs-banner-layer animated-translation-y)}
|
||||
^{:key (str "tabs-" selected-tab)}
|
||||
[quo/tabs
|
||||
{:size 32
|
||||
:style style/tabs
|
||||
:on-change on-tab-change
|
||||
:default-active selected-tab
|
||||
:data tabs-data}]]))
|
||||
|
||||
(defn- animated-banner
|
||||
[{:keys [selected-tab animated-translation-y animated-opacity flat-list-ref]}]
|
||||
[:<>
|
||||
[:f> blur-banner-layer animated-translation-y]
|
||||
[:f> hiding-banner-layer animated-translation-y animated-opacity]
|
||||
[:f> tabs-banner-layer animated-translation-y animated-opacity selected-tab flat-list-ref]])
|
||||
|
||||
(def ^:private card-height (+ 56 16)) ; Card height + its vertical margins
|
||||
(def ^:private card-opacity-factor (/ 100 card-height 100))
|
||||
(def ^:private max-scroll (- (+ card-height 8))) ; added 8 from tabs top padding
|
||||
|
||||
(defn- set-animated-banner-values
|
||||
[{:keys [scroll-offset translation-y opacity]}]
|
||||
(let [new-opacity (-> (* (- card-height scroll-offset) card-opacity-factor)
|
||||
(utils.number/value-in-range 0 1))
|
||||
new-translation-y (-> (- scroll-offset)
|
||||
(utils.number/value-in-range max-scroll 0))]
|
||||
(reanimated/animate-shared-value-with-timing opacity new-opacity 80 :easing4)
|
||||
(reanimated/animate-shared-value-with-timing translation-y new-translation-y 80 :easing4)))
|
||||
(def ^:private banner-data
|
||||
{:title-props
|
||||
{:label (i18n/label :t/communities)
|
||||
:handler #(rf/dispatch [:show-bottom-sheet {:content actions.home-plus/view}])
|
||||
:accessibility-label :new-communities-button}
|
||||
:card-props
|
||||
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
|
||||
:title (i18n/label :t/discover)
|
||||
:description (i18n/label :t/favorite-communities)
|
||||
:banner (resources/get-image :discover)
|
||||
:accessibility-label :communities-home-discover-card}})
|
||||
|
||||
(defn home
|
||||
[]
|
||||
(let [flat-list-ref (atom nil)]
|
||||
(let [flat-list-ref (atom nil)
|
||||
set-flat-list-ref #(reset! flat-list-ref %)]
|
||||
(fn []
|
||||
(let [selected-tab (or (rf/sub [:communities/selected-tab]) :joined)
|
||||
{:keys [joined pending opened]} (rf/sub [:communities/grouped-by-status])
|
||||
|
@ -163,28 +81,29 @@
|
|||
:joined joined
|
||||
:pending pending
|
||||
:opened opened)
|
||||
animated-opacity (reanimated/use-shared-value 1)
|
||||
animated-translation-y (reanimated/use-shared-value 0)]
|
||||
scroll-shared-value (reanimated/use-shared-value 0)]
|
||||
[:<>
|
||||
(if (empty? selected-items)
|
||||
[empty-state
|
||||
{:style (style/empty-state-container)
|
||||
:selected-tab selected-tab}]
|
||||
[rn/flat-list
|
||||
{:ref #(reset! flat-list-ref %)
|
||||
[common.home/empty-state-image
|
||||
{:selected-tab selected-tab
|
||||
:tab->content empty-state-content}]
|
||||
[reanimated/flat-list
|
||||
{:ref set-flat-list-ref
|
||||
:key-fn :id
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [rn/view {:style (style/header-spacing)}]
|
||||
:header [common.home/header-spacing]
|
||||
:render-fn item-render
|
||||
:data selected-items
|
||||
:on-scroll #(set-animated-banner-values
|
||||
{:scroll-offset (oops/oget
|
||||
%
|
||||
"nativeEvent.contentOffset.y")
|
||||
:translation-y animated-translation-y
|
||||
:opacity animated-opacity})}])
|
||||
[:f> animated-banner
|
||||
{:selected-tab selected-tab
|
||||
:animated-translation-y animated-translation-y
|
||||
:animated-opacity animated-opacity
|
||||
:flat-list-ref flat-list-ref}]]))))
|
||||
:scroll-event-throttle 8
|
||||
:on-scroll #(common.home.banner/set-scroll-shared-value
|
||||
{:scroll-input (oops/oget
|
||||
%
|
||||
"nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})}])
|
||||
[:f> common.home.banner/animated-banner
|
||||
{:content banner-data
|
||||
:scroll-ref flat-list-ref
|
||||
:tabs tabs-data
|
||||
:selected-tab selected-tab
|
||||
:on-tab-change (fn [tab] (rf/dispatch [:communities/select-tab tab]))
|
||||
:scroll-shared-value scroll-shared-value}]]))))
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
(get shell.constants/stacks-z-index-keywords stack-id))})}
|
||||
(case stack-id
|
||||
:communities-stack [:f> communities/home]
|
||||
:chats-stack [chat/home]
|
||||
:chats-stack [:f> chat/home]
|
||||
:wallet-stack [wallet.accounts/accounts-overview-old]
|
||||
:browser-stack [browser.stack/browser-stack]
|
||||
[:<>])])
|
||||
|
|
Loading…
Reference in New Issue