* Simplifies community banner and adds style property * Add animation for communities banner card * Moves value-in-range to `utils.number` and removes `bounded-val` * Moves animated values to view namespace * Make `community.banner` component themeable
This commit is contained in:
parent
3b8f66d2ec
commit
c4b142ea68
|
@ -2,18 +2,21 @@
|
|||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn community-card
|
||||
[radius]
|
||||
{:shadow-offset {:width 0
|
||||
:height 2}
|
||||
:shadow-radius radius
|
||||
:shadow-opacity 1
|
||||
:shadow-color colors/shadow
|
||||
:elevation 1
|
||||
:border-radius radius
|
||||
:justify-content :space-between
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)})
|
||||
[theme]
|
||||
{:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 16
|
||||
:shadow-opacity 1
|
||||
:shadow-color colors/shadow
|
||||
:elevation 1
|
||||
:border-radius 16
|
||||
:justify-content :space-between
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:flex-direction :row
|
||||
:margin-horizontal 20
|
||||
:margin-top 8
|
||||
:margin-bottom 8
|
||||
:height 56
|
||||
:padding-right 12})
|
||||
|
||||
(def banner-content
|
||||
{:flex 1
|
||||
|
@ -25,13 +28,6 @@
|
|||
{:flex 1
|
||||
:padding-horizontal 12})
|
||||
|
||||
(def banner-card
|
||||
{:flex-direction :row
|
||||
:margin-horizontal 20
|
||||
:margin-vertical 8
|
||||
:height 56
|
||||
:padding-right 12})
|
||||
|
||||
(def discover-illustration
|
||||
{:position :absolute
|
||||
:top -4
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
(:require [quo2.components.community.banner.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- card-title-and-description
|
||||
[title description]
|
||||
[rn/view
|
||||
{:style style/banner-content}
|
||||
[rn/view
|
||||
{:style style/banner-title}
|
||||
[title description theme]
|
||||
[rn/view {:style style/banner-content}
|
||||
[rn/view {:style style/banner-title}
|
||||
[text/text
|
||||
{:accessibility-label :community-name-text
|
||||
:ellipsize-mode :tail
|
||||
|
@ -21,26 +20,21 @@
|
|||
{:accessibility-label :community-name-text
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40)
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
description]]])
|
||||
|
||||
(defn view
|
||||
[{:keys [title description on-press accessibility-label banner]}]
|
||||
(defn view-internal
|
||||
[{:keys [title description on-press accessibility-label banner style theme]}]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press on-press
|
||||
:accessibility-label accessibility-label}
|
||||
[rn/view
|
||||
(merge (style/community-card 16)
|
||||
{:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)}
|
||||
style/banner-card)
|
||||
[card-title-and-description title description]
|
||||
[rn/view {:style (merge (style/community-card theme) style)}
|
||||
[card-title-and-description title description theme]
|
||||
[rn/image
|
||||
{:style style/discover-illustration
|
||||
:source banner
|
||||
:accessibility-label :discover-communities-illustration}]]])
|
||||
|
||||
(def view (theme/with-theme view-internal))
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[react-native.masked-view :as masked-view]
|
||||
[reagent.core :as reagent]
|
||||
[utils.collection :as utils.collection]
|
||||
[utils.number :as utils.number]
|
||||
[utils.number]
|
||||
[react-native.gesture :as gesture]))
|
||||
|
||||
(def default-tab-size 32)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.number :as utils.number]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn reenter-screen-effect
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
(ns status-im2.contexts.chat.composer.gesture
|
||||
(:require
|
||||
[oops.core :as oops]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[oops.core :as oops]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn set-opacity
|
||||
|
@ -83,7 +84,7 @@
|
|||
(let [translation (oops/oget event "translationY")
|
||||
min-height (utils/get-min-height lines images link-previews?)
|
||||
new-height (- (reanimated/get-shared-value saved-height) translation)
|
||||
bounded-height (utils/bounded-val new-height min-height max-height)]
|
||||
bounded-height (utils.number/value-in-range new-height min-height max-height)]
|
||||
(when keyboard-shown
|
||||
(if (>= new-height min-height)
|
||||
(do ; expand sheet
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[status-im2.contexts.chat.composer.selection :as selection]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn focus
|
||||
|
@ -82,7 +83,9 @@
|
|||
content-size (if (or (= lines 1) (empty? @text-value))
|
||||
constants/input-height
|
||||
(if (= lines 2) constants/multiline-minimized-height content-size))
|
||||
new-height (utils/bounded-val content-size constants/input-height max-height)
|
||||
new-height (utils.number/value-in-range content-size
|
||||
constants/input-height
|
||||
max-height)
|
||||
bottom-content-height (utils/calc-bottom-content-height images link-previews?)
|
||||
new-height (min (+ new-height bottom-content-height) max-height)]
|
||||
(reset! content-height content-size)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.selection :as selection]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn bounded-val
|
||||
|
@ -142,7 +143,7 @@
|
|||
base (+ base (- curr-height constants/input-height))
|
||||
base (+ base (calc-top-content-height reply edit))
|
||||
view-height (- window-height keyboard-height (:top insets))
|
||||
container-height (bounded-val
|
||||
container-height (utils.number/value-in-range
|
||||
(* (/ constants/mentions-max-height 4) size)
|
||||
(/ constants/mentions-max-height 4)
|
||||
constants/mentions-max-height)]
|
||||
|
@ -228,7 +229,7 @@
|
|||
:saved-height (reanimated/use-shared-value
|
||||
initial-height)
|
||||
:last-height (reanimated/use-shared-value
|
||||
(bounded-val
|
||||
(utils.number/value-in-range
|
||||
(+ @content-height bottom-content-height)
|
||||
constants/input-height
|
||||
max-height))
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
(ns status-im2.contexts.communities.home.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(def header-height 245)
|
||||
|
||||
(def tabs
|
||||
{:padding-horizontal 20
|
||||
:padding-top 16
|
||||
:padding-top 8
|
||||
:padding-bottom 12})
|
||||
|
||||
(def blur
|
||||
|
@ -17,8 +19,8 @@
|
|||
:bottom 0})
|
||||
|
||||
(defn empty-state-container
|
||||
[top]
|
||||
{:margin-top (+ header-height top)
|
||||
[]
|
||||
{:margin-top (+ header-height (safe-area/get-top))
|
||||
:margin-bottom 44
|
||||
:flex 1
|
||||
:justify-content :center})
|
||||
|
@ -29,16 +31,46 @@
|
|||
:background-color colors/danger-50})
|
||||
|
||||
(defn header-spacing
|
||||
[top]
|
||||
{:height (+ header-height top)})
|
||||
[]
|
||||
{:height (+ header-height (safe-area/get-top))})
|
||||
|
||||
(defn blur-container
|
||||
[top]
|
||||
{:overflow (if platform/ios? :visible :hidden)
|
||||
(defn blur-banner-layer
|
||||
[animated-translation-y]
|
||||
(let [fixed-height (+ (safe-area/get-top) 244)]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y animated-translation-y}]}
|
||||
{:overflow (if platform/ios? :visible :hidden)
|
||||
:z-index 1
|
||||
:position :absolute
|
||||
:top 0
|
||||
:right 0
|
||||
:left 0
|
||||
:height fixed-height})))
|
||||
|
||||
(defn hiding-banner-layer
|
||||
[]
|
||||
{:z-index 2
|
||||
:position :absolute
|
||||
:z-index 1
|
||||
:top 0
|
||||
:right 0
|
||||
:left 0
|
||||
:padding-top top})
|
||||
:padding-top (safe-area/get-top)})
|
||||
|
||||
(defn tabs-banner-layer
|
||||
[animated-translation-y]
|
||||
(let [top-offset (+ (safe-area/get-top) 192)]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y animated-translation-y}]}
|
||||
{:z-index 3
|
||||
:position :absolute
|
||||
:top top-offset
|
||||
:right 0
|
||||
:left 0})))
|
||||
|
||||
(def animated-card-container {:overflow :hidden})
|
||||
|
||||
(defn animated-card
|
||||
[opacity translate-y]
|
||||
(reanimated/apply-animations-to-style {:opacity opacity
|
||||
:transform [{:translate-y translate-y}]}
|
||||
{}))
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
(ns status-im2.contexts.communities.home.view
|
||||
(:require [quo2.core :as quo]
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[utils.debounce :as debounce]
|
||||
[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.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]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn item-render
|
||||
|
@ -60,9 +62,10 @@
|
|||
:no-opened-communities-dark))}
|
||||
nil))
|
||||
|
||||
(defn empty-state
|
||||
[{:keys [style selected-tab customization-color]}]
|
||||
(let [{:keys [image title description]} (empty-state-content selected-tab)]
|
||||
(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
|
||||
|
@ -70,56 +73,116 @@
|
|||
: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)))
|
||||
|
||||
(defn home
|
||||
[]
|
||||
(let [selected-tab (or (rf/sub [:communities/selected-tab]) :joined)
|
||||
{:keys [joined pending opened]} (rf/sub [:communities/grouped-by-status])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
selected-items (case selected-tab
|
||||
:joined joined
|
||||
:pending pending
|
||||
:opened opened)
|
||||
top (safe-area/get-top)]
|
||||
[:<>
|
||||
(if (empty? selected-items)
|
||||
[empty-state
|
||||
{:style (style/empty-state-container top)
|
||||
:selected-tab selected-tab
|
||||
:customization-color customization-color}]
|
||||
[rn/flat-list
|
||||
{:key-fn :id
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [rn/view {:style (style/header-spacing top)}]
|
||||
:render-fn item-render
|
||||
:data selected-items}])
|
||||
|
||||
[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/communities)
|
||||
:handler #(rf/dispatch [:show-bottom-sheet {:content actions.home-plus/view}])
|
||||
:accessibility-label :new-communities-button
|
||||
:customization-color customization-color}]
|
||||
[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}]
|
||||
^{:key (str "tabs-" selected-tab)}
|
||||
[quo/tabs
|
||||
{:size 32
|
||||
:style style/tabs
|
||||
:on-change (fn [tab]
|
||||
(rf/dispatch [:communities/select-tab tab]))
|
||||
:default-active selected-tab
|
||||
:data tabs-data}]]]))
|
||||
(let [flat-list-ref (atom nil)]
|
||||
(fn []
|
||||
(let [selected-tab (or (rf/sub [:communities/selected-tab]) :joined)
|
||||
{:keys [joined pending opened]} (rf/sub [:communities/grouped-by-status])
|
||||
selected-items (case selected-tab
|
||||
:joined joined
|
||||
:pending pending
|
||||
:opened opened)
|
||||
animated-opacity (reanimated/use-shared-value 1)
|
||||
animated-translation-y (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 %)
|
||||
:key-fn :id
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [rn/view {:style (style/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}]]))))
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
:z-index (get shared-values
|
||||
(get shell.constants/stacks-z-index-keywords stack-id))})}
|
||||
(case stack-id
|
||||
:communities-stack [communities/home]
|
||||
:communities-stack [:f> communities/home]
|
||||
:chats-stack [chat/home]
|
||||
:wallet-stack [wallet.accounts/accounts-overview-old]
|
||||
:browser-stack [browser.stack/browser-stack]
|
||||
|
|
|
@ -23,3 +23,9 @@
|
|||
(if (integer? maybe-int)
|
||||
maybe-int
|
||||
default))))
|
||||
|
||||
(defn value-in-range
|
||||
"Returns `num` if is in the range [`lower-bound` `upper-bound`]
|
||||
if `num` exceeds a given bound, then returns the bound exceeded."
|
||||
[number lower-bound upper-bound]
|
||||
(max lower-bound (min number upper-bound)))
|
||||
|
|
Loading…
Reference in New Issue