Improve home animations (#15247)

This commit is contained in:
flexsurfer 2023-03-13 19:47:04 +01:00 committed by GitHub
parent 4810e1d7bf
commit 0fe6fea7e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 493 additions and 434 deletions

View File

@ -0,0 +1,7 @@
import {useAnimatedScrollHandler} from "react-native-reanimated";
export function useAnimatedScrollHandlerWorklet(scrollY) {
return useAnimatedScrollHandler((event) => {
scrollY.value = event.contentOffset.y;
})
}

View File

@ -355,11 +355,6 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def worklet-factory (def worklet-factory
#js {:applyAnimationsToStyle (fn [])}) #js {:applyAnimationsToStyle (fn [])})
(def shell-worklets #js {})
(def bottom-sheet #js {})
(def record-audio-worklets #js {})
;; Update i18n_resources.cljs ;; Update i18n_resources.cljs
(defn mock (defn mock
[module] [module]
@ -407,10 +402,11 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
"@react-native-async-storage/async-storage" async-storage "@react-native-async-storage/async-storage" async-storage
"react-native-svg" react-native-svg "react-native-svg" react-native-svg
"react-native-orientation-locker" react-native-orientation-locker "react-native-orientation-locker" react-native-orientation-locker
"../src/js/worklet_factory.js" worklet-factory "../src/js/worklets/core.js" worklet-factory
"../src/js/shell_worklets.js" shell-worklets "../src/js/worklets/shell.js" #js {}
"../src/js/bottom_sheet.js" bottom-sheet "../src/js/worklets/bottom_sheet.js" #js {}
"../src/js/record_audio_worklets.js" record-audio-worklets "../src/js/worklets/record_audio.js" #js {}
"../src/js/worklets/scroll_view.js" #js {}
"./fleets.js" default-fleets "./fleets.js" default-fleets
"@walletconnect/client" wallet-connect-client "@walletconnect/client" wallet-connect-client
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json")) "../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))

View File

@ -78,22 +78,22 @@
[props [props
{:keys [name {:keys [name
muted? muted?
unread-messages? unviewed-messages-count
unread-mentions-count unviewed-mentions-count
status status
community-icon images
tokens tokens
locked?]}] locked?
style]}]
[rn/touchable-highlight [rn/touchable-highlight
(merge {:underlay-color (colors/theme-colors (merge {:underlay-color (colors/theme-colors
colors/neutral-5 colors/neutral-5
colors/neutral-95) colors/neutral-95)
:style {:border-radius 12}} :style {:border-radius 12}}
props) props)
[rn/view {:flex 1} [rn/view (merge (style/membership-info-container) style)
[rn/view (style/membership-info-container)
[community-icon/community-icon [community-icon/community-icon
{:images community-icon} 32] {:images images} 32]
[rn/view [rn/view
{:flex 1 {:flex 1
:margin-left 12 :margin-left 12
@ -115,5 +115,5 @@
:tokens tokens}] :tokens tokens}]
[notification-view [notification-view
{:muted? muted? {:muted? muted?
:unread-mentions-count unread-mentions-count :unread-mentions-count unviewed-mentions-count
:unread-messages? unread-messages?}])]]]]) :unread-messages? (pos? unviewed-messages-count)}])]]])

View File

@ -92,6 +92,7 @@
colors/neutral-90)} colors/neutral-90)}
{:flex-direction :row {:flex-direction :row
:margin-horizontal 20 :margin-horizontal 20
:margin-vertical 8
:height 56 :height 56
:padding-right 12}) :padding-right 12})
[card-title-and-description title description] [card-title-and-description title description]

View File

@ -15,9 +15,9 @@
:shadow-radius radius :shadow-radius radius
:shadow-opacity 1 :shadow-opacity 1
:shadow-color colors/shadow :shadow-color colors/shadow
:elevation 1
:border-radius radius :border-radius radius
:justify-content :space-between :justify-content :space-between
:elevation 2
:background-color (colors/theme-colors :background-color (colors/theme-colors
colors/white colors/white
colors/neutral-90)}) colors/neutral-90)})

View File

@ -8,7 +8,8 @@
[taoensso.timbre :as log] [taoensso.timbre :as log]
[cljs-bean.core :as bean] [cljs-bean.core :as bean]
[reagent.core :as reagent] [reagent.core :as reagent]
[quo2.components.record-audio.record-audio.helpers :as helpers])) [quo2.components.record-audio.record-audio.helpers :as helpers]
[utils.worklets.record-audio :as worklets.record-audio]))
(def ^:private scale-to-each 1.8) (def ^:private scale-to-each 1.8)
(def ^:private scale-to-total 2.6) (def ^:private scale-to-total 2.6)
@ -18,14 +19,6 @@
(def ^:private signal-anim-duration 3900) (def ^:private signal-anim-duration 3900)
(def ^:private signal-anim-duration-2 1950) (def ^:private signal-anim-duration-2 1950)
(def ^:private record-audio-worklets (js/require "../src/js/record_audio_worklets.js"))
(defn- ring-scale
[scale substract]
(.ringScale ^js record-audio-worklets
scale
substract))
(def ^:private animated-ring (def ^:private animated-ring
(reagent/adapt-react-class (reagent/adapt-react-class
(rn/memo (rn/memo
@ -45,7 +38,9 @@
opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default) opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default)
animations (map animations (map
(fn [index] (fn [index]
(let [ring-scale (ring-scale scale (* scale-padding index))] (let [ring-scale (worklets.record-audio/ring-scale scale
(* scale-padding
index))]
{:scale ring-scale {:scale ring-scale
:opacity (reanimated/interpolate ring-scale :opacity (reanimated/interpolate ring-scale
[1 scale-to-each] [1 scale-to-each]

View File

@ -98,6 +98,10 @@
(def use-ref react/useRef) (def use-ref react/useRef)
(defn current-ref
[ref]
(oops/oget ref "current"))
(defn use-effect (defn use-effect
([effect-fn] ([effect-fn]
(use-effect effect-fn [])) (use-effect effect-fn []))

View File

@ -18,7 +18,8 @@
LinearTransition)] LinearTransition)]
[reagent.core :as reagent] [reagent.core :as reagent]
[react-native.flat-list :as rn-flat-list] [react-native.flat-list :as rn-flat-list]
[utils.collection])) [utils.collection]
[utils.worklets.core :as worklets.core]))
;; Animations ;; Animations
(def slide-in-up-animation SlideInUp) (def slide-in-up-animation SlideInUp)
@ -29,14 +30,14 @@
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated))) (def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
(def view (reagent/adapt-react-class (.-View reanimated))) (def view (reagent/adapt-react-class (.-View reanimated)))
(def scroll-view (reagent/adapt-react-class (.-ScrollView reanimated)))
(def image (reagent/adapt-react-class (.-Image reanimated))) (def image (reagent/adapt-react-class (.-Image reanimated)))
(def reanimated-flat-list (reagent/adapt-react-class (.-FlatList ^js rn))) (def reanimated-flat-list (create-animated-component (.-FlatList ^js rn)))
(defn flat-list (defn flat-list
[props] [props]
[reanimated-flat-list (rn-flat-list/base-list-props props)]) [reanimated-flat-list (rn-flat-list/base-list-props props)])
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn))) (def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
(def linear-gradient (create-animated-component LinearGradient)) (def linear-gradient (create-animated-component LinearGradient))
(def fast-image (create-animated-component FastImage)) (def fast-image (create-animated-component FastImage))
(def blur-view (create-animated-component (.-BlurView blur))) (def blur-view (create-animated-component (.-BlurView blur)))
@ -77,24 +78,20 @@
(when (and anim (some? val)) (when (and anim (some? val))
(set! (.-value anim) val))) (set! (.-value anim) val)))
;; Worklets
(def worklet-factory (js/require "../src/js/worklet_factory.js"))
(defn interpolate (defn interpolate
([shared-value input-range output-range] ([shared-value input-range output-range]
(interpolate shared-value input-range output-range nil)) (interpolate shared-value input-range output-range nil))
([shared-value input-range output-range extrapolation] ([shared-value input-range output-range extrapolation]
(.interpolateValue ^js worklet-factory (worklets.core/interpolate-value
shared-value shared-value
(clj->js input-range) (clj->js input-range)
(clj->js output-range) (clj->js output-range)
(clj->js extrapolation)))) (clj->js extrapolation))))
;;;; Component Animations
(defn apply-animations-to-style (defn apply-animations-to-style
[animations style] [animations style]
(use-animated-style (use-animated-style
(.applyAnimationsToStyle ^js worklet-factory (clj->js animations) (clj->js style)))) (worklets.core/apply-animations-to-style (clj->js animations) (clj->js style))))
;; Animators ;; Animators
(defn animate-shared-value-with-timing (defn animate-shared-value-with-timing

View File

@ -10,9 +10,8 @@
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[reagent.core :as reagent])) [reagent.core :as reagent]
[utils.worklets.bottom-sheet :as worklets.bottom-sheet]))
(def bottom-sheet-js (js/require "../src/js/bottom_sheet.js"))
(def animation-delay 450) (def animation-delay 450)
@ -129,9 +128,9 @@
bg-height (max (min @content-height bg-height-expanded) 109) bg-height (max (min @content-height bg-height-expanded) 109)
bottom-sheet-dy (reanimated/use-shared-value 0) bottom-sheet-dy (reanimated/use-shared-value 0)
pan-y (reanimated/use-shared-value 0) pan-y (reanimated/use-shared-value 0)
translate-y (.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y) translate-y (worklets.bottom-sheet/use-translate-y window-height bottom-sheet-dy pan-y)
bg-opacity bg-opacity
(.useBackgroundOpacity ^js bottom-sheet-js translate-y bg-height window-height) (worklets.bottom-sheet/use-background-opacity translate-y bg-height window-height)
on-content-layout (fn [evt] on-content-layout (fn [evt]
(let [height (oget evt "nativeEvent" "layout" "height")] (let [height (oget evt "nativeEvent" "layout" "height")]
(reset! content-height height))) (reset! content-height height)))

View File

@ -46,7 +46,7 @@
:style override-style :style override-style
:avatar user-avatar} :avatar user-avatar}
" "
[{:keys [type style avatar hide-search]}] [{:keys [type style avatar search?] :or {type :default}}]
(let [button-common-props (get-button-common-props type) (let [button-common-props (get-button-common-props type)
notif-count (rf/sub [:activity-center/unread-count]) notif-count (rf/sub [:activity-center/unread-count])
new-notifications? (pos? notif-count) new-notifications? (pos? notif-count)
@ -71,7 +71,7 @@
:right 20 :right 20
:top 12 :top 12
:flex-direction :row}} :flex-direction :row}}
(when-not hide-search (when search?
[base-button :i/search #() :open-search-button button-common-props]) [base-button :i/search #() :open-search-button button-common-props])
[base-button :i/scan #() :open-scanner-button button-common-props] [base-button :i/scan #() :open-scanner-button button-common-props]
[base-button :i/qr-code #() :show-qr-button button-common-props] [base-button :i/qr-code #() :show-qr-button button-common-props]

View File

@ -11,9 +11,7 @@
(defn icon-color (defn icon-color
[] []
(colors/theme-colors (colors/theme-colors colors/white-opa-40 colors/neutral-80-opa-40))
colors/white-opa-40
colors/neutral-80-opa-40))
(def negative-scroll-position-0 (if platform/ios? -44 0)) (def negative-scroll-position-0 (if platform/ios? -44 0))
(def scroll-position-0 (if platform/ios? 44 0)) (def scroll-position-0 (if platform/ios? 44 0))
@ -27,15 +25,7 @@
(min maximum))) (min maximum)))
(defn scroll-page-header (defn scroll-page-header
[scroll-height [scroll-height height name page-nav logo sticky-header top-nav title-colum navigate-back?]
height
name
page-nav
logo
sticky-header
top-nav
title-colum
navigate-back?]
(let [input-range (if platform/ios? [-47 10] [0 10]) (let [input-range (if platform/ios? [-47 10] [0 10])
output-range (if platform/ios? [-208 0] [-208 -45]) output-range (if platform/ios? [-208 0] [-208 -45])
y (reanimated/use-shared-value scroll-height) y (reanimated/use-shared-value scroll-height)
@ -120,17 +110,8 @@
(defn scroll-page (defn scroll-page
[_ _ _] [_ _ _]
(let [scroll-height (reagent/atom negative-scroll-position-0)] (let [scroll-height (reagent/atom negative-scroll-position-0)]
(fn (fn [{:keys [name cover-image logo page-nav-right-section-buttons on-scroll
[{:keys [cover-image height top-nav title-colum background-color navigate-back?]}
logo
page-nav-right-section-buttons
name
on-scroll
height
top-nav
title-colum
background-color
navigate-back?]}
sticky-header sticky-header
children] children]
[:<> [:<>

View File

@ -0,0 +1,100 @@
(ns status-im2.common.sticky-scroll-view.view
(:require [react-native.reanimated :as reanimated]
[react-native.core :as rn]
[react-native.platform :as platform]
[utils.worklets.scroll-view :as worklets.scroll-view]
[quo2.foundations.colors :as colors]))
(defn sticky-item
[{:keys [height translation-y background-color]} content]
[:f>
(fn []
[rn/view (merge {:height height} (when platform/ios? {:z-index 1}))
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translation-y}]}
{:position :absolute
:z-index (when platform/android? 1)
:top 0
:left 0
:right 0
:height height
:background-color background-color})}
content]])])
(defn scroll-view
[{:keys [ref scroll-y blur]} & content]
[:f>
(fn []
(let [scroll-handler (worklets.scroll-view/use-animated-scroll-handler scroll-y)
opacity (when blur
(reanimated/interpolate scroll-y
[0 (:delta blur)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"}))]
(into [reanimated/scroll-view
{:ref ref
:scroll-event-throttle 1
:shows-vertical-scroll-indicator false
:contentInsetAdjustmentBehavior :never
:on-scroll scroll-handler}]
(concat
(when blur
;bug on Android
;https://github.com/Kureev/react-native-blur/issues/520}
[[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY scroll-y}]
:opacity opacity}
{:overflow (if platform/ios? :visible :hidden)
:position :absolute
:z-index 1
:top 0
:height (:height blur)
:right 0
:left 0})}
[reanimated/blur-view
{:blur-amount 10
:blur-type (if (colors/dark?) :dark :xlight)
:style {:position :absolute
:top 0
:height (:height blur)
:right 0
:left 0}}]]])
content))))])
(defn flat-list
[{:keys [scroll-y blur header render-fn data]}]
[:f>
(fn []
(let [scroll-handler (worklets.scroll-view/use-animated-scroll-handler scroll-y)
opacity (when blur
(reanimated/interpolate scroll-y
[0 (:delta blur)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"}))]
[reanimated/flat-list
{:scroll-event-throttle 1
:shows-vertical-scroll-indicator false
:contentInsetAdjustmentBehavior :never
:data data
:render-fn render-fn
:header (if blur
[:<>
[reanimated/blur-view
{:blur-amount 10
:blur-type :xlight
:style (reanimated/apply-animations-to-style
{:transform [{:translateY scroll-y}]
:opacity opacity}
{:z-index 1
:position :absolute
:top 0
:height (:height blur)
:right 0
:left 0})}]
header]
header)
:on-scroll scroll-handler}]))])

View File

@ -0,0 +1,24 @@
(ns status-im2.contexts.chat.home.style
(:require [react-native.platform :as platform]))
(def tabs
{:padding-horizontal 20
:padding-top 16
:padding-bottom 12})
(def blur
{:position :absolute
:top 0
:right 0
:left 0
: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})

View File

@ -10,11 +10,16 @@
[status-im2.contexts.chat.home.contact-request.view :as contact-request] [status-im2.contexts.chat.home.contact-request.view :as contact-request]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[status-im2.common.contact-list-item.view :as contact-list-item] [status-im2.common.contact-list-item.view :as contact-list-item]
[status-im2.common.home.actions.view :as actions])) [status-im2.common.home.actions.view :as actions]
[react-native.safe-area :as safe-area]
[quo2.foundations.colors :as colors]
[react-native.blur :as blur]
[status-im2.contexts.chat.home.style :as style]
[react-native.platform :as platform]))
(defn get-item-layout (defn get-item-layout
[_ index] [_ index]
#js {:length 64 :offset (* 64 index) :index index}) #js {:length 56 :offset (* 56 index) :index index})
(defn filter-items-by-tab (defn filter-items-by-tab
[tab items] [tab items]
@ -30,7 +35,7 @@
[quo/text (i18n/label :t/blank-messages-text)]]) [quo/text (i18n/label :t/blank-messages-text)]])
(defn chats (defn chats
[selected-tab] [selected-tab top]
(let [{:keys [items search-filter]} (rf/sub [:home-items]) (let [{:keys [items search-filter]} (rf/sub [:home-items])
items (filter-items-by-tab selected-tab items)] items (filter-items-by-tab selected-tab items)]
(if (and (empty? items) (if (and (empty? items)
@ -38,12 +43,13 @@
[welcome-blank-chats] [welcome-blank-chats]
[rn/flat-list [rn/flat-list
{:key-fn #(or (:chat-id %) (:public-key %) (:id %)) {:key-fn #(or (:chat-id %) (:public-key %) (:id %))
:content-inset-adjustment-behavior :never
:header [rn/view {:height (+ 245 top)}]
:get-item-layout get-item-layout :get-item-layout get-item-layout
:on-end-reached #(re-frame/dispatch [:chat/show-more-chats]) :on-end-reached #(re-frame/dispatch [:chat/show-more-chats])
:keyboard-should-persist-taps :always :keyboard-should-persist-taps :always
:data items :data items
:render-fn chat-list-item/chat-list-item :render-fn chat-list-item/chat-list-item}])))
:content-container-style {:padding-bottom 30}}])))
(defn welcome-blank-contacts (defn welcome-blank-contacts
[] []
@ -65,63 +71,63 @@
:on-press show-profile-actions}}) :on-press show-profile-actions}})
item])) item]))
(defn contacts-section-list
[sections]
[rn/section-list
{:key-fn :title
:sticky-section-headers-enabled false
:sections sections
:render-section-header-fn contact-list/contacts-section-header
:content-container-style {:padding-bottom 20}
:render-fn contact-item-render}])
(defn contacts (defn contacts
[pending-contact-requests] [pending-contact-requests top]
(let [items (rf/sub [:contacts/active-sections])] (let [items (rf/sub [:contacts/active-sections])]
(if (and (empty? items) (empty? pending-contact-requests)) (if (and (empty? items) (empty? pending-contact-requests))
[welcome-blank-contacts] [welcome-blank-contacts]
[:<> [rn/section-list
{:key-fn :public-key
:get-item-layout get-item-layout
:content-inset-adjustment-behavior :never
:header [:<>
[rn/view {:height (+ 245 top)}]
(when (seq pending-contact-requests) (when (seq pending-contact-requests)
[contact-request/contact-requests pending-contact-requests]) [contact-request/contact-requests
(when (seq items) pending-contact-requests])]
[contacts-section-list items])]))) :sections items
:sticky-section-headers-enabled false
:render-section-header-fn contact-list/contacts-section-header
:render-fn contact-item-render}])))
(defn tabs (defn get-tabs-data
[dot?]
[{:id :recent :label (i18n/label :t/recent) :accessibility-label :tab-recent}
{:id :groups :label (i18n/label :t/groups) :accessibility-label :tab-groups}
{:id :contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? dot?}])
(defn home
[] []
(let [selected-tab (reagent/atom :recent)] (let [selected-tab (reagent/atom :recent)]
(fn [] (fn []
(let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])] (let [pending-contact-requests (rf/sub [:activity-center/pending-contact-requests])]
[safe-area/consumer
(fn [{:keys [top]}]
[:<> [:<>
(if (= @selected-tab :contacts)
[contacts pending-contact-requests top]
[chats @selected-tab top])
[rn/view
{:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:bottom-sheet/show-sheet :new-chat-bottom-sheet
{}])
:accessibility-label :new-chat-button}]
[quo/discover-card [quo/discover-card
{:title (i18n/label :t/invite-friends-to-status) {:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}] :description (i18n/label :t/share-invite-link)}]
[quo/tabs [quo/tabs
{:style {:margin-left 20 {:style style/tabs
:margin-bottom 20
:margin-top 24}
:size 32 :size 32
:on-change #(reset! selected-tab %) :on-change #(reset! selected-tab %)
:default-active @selected-tab :default-active @selected-tab
:data [{:id :recent :data (get-tabs-data (pos? (count pending-contact-requests)))}]]])]))))
:label (i18n/label :t/recent)
:accessibility-label :tab-recent}
{:id :groups
:label (i18n/label :t/groups)
:accessibility-label :tab-groups}
{:id :contacts
:label (i18n/label :t/contacts)
:accessibility-label :tab-contacts
:notification-dot? (pos? (count pending-contact-requests))}]}]
(if (= @selected-tab :contacts)
[contacts pending-contact-requests]
[chats @selected-tab])]))))
(defn home
[]
[:<>
[common.home/top-nav {:type :default :hide-search true}]
[common.home/title-column
{:label (i18n/label :t/messages)
:handler #(rf/dispatch [:bottom-sheet/show-sheet :new-chat-bottom-sheet {}])
:accessibility-label :new-chat-button}]
[tabs]])

View File

@ -153,31 +153,24 @@
(get mock-community-item-data :data))])])) (get mock-community-item-data :data))])]))
(if communities communities communities-ids))]) (if communities communities communities-ids))])
(defn communities-lists (defn communities-lists
[selected-tab view-type] [selected-tab view-type]
(let [ids-by-user-involvement (rf/sub [:communities/community-ids-by-user-involvement])
all-communities (rf/sub [:communities/sorted-communities])
tab @selected-tab]
[rn/view {:style {:flex 1}} [rn/view {:style {:flex 1}}
(case tab (case @selected-tab
:all :all
(other-communities-list {:communities all-communities (other-communities-list {:communities (rf/sub [:communities/sorted-communities])
:view-type view-type}) :view-type view-type})
:open :open
(other-communities-list {:communities-ids (:open ids-by-user-involvement) [:<>]
:view-type view-type})
:gated :gated
(other-communities-list {:communities-ids (:gated ids-by-user-involvement) [:<>]
:view-type view-type})
[quo/information-box [quo/information-box
{:type :error {:type :error
:icon :i/info} :icon :i/info}
(i18n/label :t/error)])])) (i18n/label :t/error)])])
(defn render-communities (defn render-communities
[selected-tab [selected-tab

View File

@ -1,38 +1,25 @@
(ns status-im2.contexts.communities.home.style (ns status-im2.contexts.communities.home.style
(:require [react-native.platform :as platform])) (:require [react-native.platform :as platform]))
(defn community-segments (def tabs
[padding-top] {:padding-horizontal 20
{:padding-bottom 12 :padding-top 16
:padding-top padding-top :padding-bottom 12})
:padding-horizontal 20
:background-color :transparent})
(def communities-header-style (def blur
{:padding-vertical 8 {:position :absolute
:margin-top (if platform/ios? 208 112)}) :top 0
(def render-segments-container
{:flex 1
:padding-horizontal 20
:padding-vertical 12})
(defn home-communities-container
[background-color]
{:flex 1
:background-color background-color
:position :absolute
:top (if platform/ios? -44 0)
:bottom 0
:left 0
:right 0})
(def blur-tabs-header
{:flex 1
:position :absolute
:top (if platform/ios? 156 112)
:height 52
:left 0
:right 0 :right 0
:justify-content :center :left 0
:background-color :transparent}) :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})

View File

@ -1,136 +1,74 @@
(ns status-im2.contexts.communities.home.view (ns status-im2.contexts.communities.home.view
(:require [utils.i18n :as i18n] (:require [utils.i18n :as i18n]
[quo2.core :as quo] [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[reagent.core :as reagent] [reagent.core :as reagent]
[react-native.core :as rn] [react-native.core :as rn]
[status-im2.common.home.view :as common.home] [status-im2.common.home.view :as common.home]
[status-im2.common.scroll-page.view :as scroll-page]
[status-im2.contexts.communities.menus.community-options.view :as options] [status-im2.contexts.communities.menus.community-options.view :as options]
[utils.re-frame :as rf]
[react-native.safe-area :as safe-area]
[react-native.blur :as blur]
[quo2.foundations.colors :as colors]
[status-im2.contexts.communities.home.style :as style] [status-im2.contexts.communities.home.style :as style]
[utils.re-frame :as rf])) [react-native.platform :as platform]))
(defn community-segments (defn item-render
[selected-tab padding-top] [{:keys [id] :as item}]
[rn/view (let [unviewed-counts (rf/sub [:communities/unviewed-counts id])
{:style (style/community-segments padding-top)} item (merge item unviewed-counts)]
[quo/tabs
{:size 32
:on-change #(reset! selected-tab %)
:default-active :joined
:data [{:id :joined :label (i18n/label :chats/joined) :accessibility-label :joined-tab}
{:id :pending :label (i18n/label :t/pending) :accessibility-label :pending-tab}
{:id :opened :label (i18n/label :t/opened) :accessibility-label :opened-tab}]}]])
(defn communities-list
[communities-ids]
[rn/view
(map-indexed
(fn [index id]
(let [community (rf/sub [:communities/home-item id])]
^{:key index}
[quo/communities-membership-list-item [quo/communities-membership-list-item
{:on-press #(rf/dispatch [:navigate-to-nav2 :community-overview id]) {:style {:padding-horizontal 18}
:on-press #(rf/dispatch [:navigate-to-nav2 :community-overview id])
:on-long-press #(rf/dispatch :on-long-press #(rf/dispatch
[:bottom-sheet/show-sheet [:bottom-sheet/show-sheet
{:content (fn [] {:content (fn []
[options/community-options-bottom-sheet id]) [options/community-options-bottom-sheet id])
:selected-item (fn [] :selected-item (fn []
[quo/communities-membership-list-item {} community])}])} [quo/communities-membership-list-item {} item])}])}
community])) item]))
communities-ids)])
(def tabs-data
[{:id :joined :label (i18n/label :chats/joined) :accessibility-label :joined-tab}
{:id :pending :label (i18n/label :t/pending) :accessibility-label :pending-tab}
{:id :opened :label (i18n/label :t/opened) :accessibility-label :opened-tab}])
(defn render-communities-segments (defn home
[selected-tab] []
(let [ids-by-user-involvement (rf/sub [:communities/community-ids-by-user-involvement]) (let [selected-tab (reagent/atom :joined)]
tab @selected-tab] (fn []
[rn/view (let [{:keys [joined pending opened]} (rf/sub [:communities/grouped-by-status])
{:style style/render-segments-container} selected-items (case @selected-tab
(case tab :joined joined
:joined :pending pending
[communities-list (:joined ids-by-user-involvement)] :opened opened)]
[safe-area/consumer
:pending (fn [{:keys [top]}]
[communities-list (:pending ids-by-user-involvement)]
:opened
[communities-list (:opened ids-by-user-involvement)]
[quo/information-box
{:type :error
:icon :i/info}
(i18n/label :t/error)])]))
(defn communities-header
[selected-tab padding-top]
[:<> [:<>
[rn/flat-list
{:key-fn :id
:content-inset-adjustment-behavior :never
:header [rn/view {:height (+ 245 top)}]
:render-fn item-render
:data selected-items}]
[rn/view [rn/view
{:style style/communities-header-style} {:style (style/blur-container top)}
[blur/view
{:blur-amount (if platform/ios? 20 10)
:blur-type (if (colors/dark?) :dark (if platform/ios? :light :xlight))
:style style/blur}]
[common.home/top-nav]
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet :add-new {}])
:accessibility-label :new-chat-button}]
[quo/discover-card [quo/discover-card
{:on-press #(rf/dispatch [:navigate-to :discover-communities]) {:on-press #(rf/dispatch [:navigate-to :discover-communities])
:title (i18n/label :t/discover) :title (i18n/label :t/discover)
:description (i18n/label :t/whats-trending) :description (i18n/label :t/whats-trending)
:accessibility-label :communities-home-discover-card}]] :accessibility-label :communities-home-discover-card}]
[community-segments selected-tab padding-top]]) [quo/tabs
{:size 32
(defn home-page-comunity-lists :style style/tabs
[{:keys [selected-tab padding-top]}] :on-change #(reset! selected-tab %)
[rn/view {:style {:flex 1}} :default-active @selected-tab
[communities-header selected-tab padding-top] :data tabs-data}]]])]))))
[render-communities-segments selected-tab]])
(defn home-sticky-header
[{:keys [selected-tab scroll-height padding-top]}]
(when (> @scroll-height 80)
[rn/view
{:style style/blur-tabs-header}
[community-segments selected-tab padding-top]]))
(defn home-nav
[]
[common.home/top-nav
{:type :default
:hide-search true
:style {:background-color :transparent}}])
(defn title-column
[]
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet :add-new {}])
:accessibility-label :new-chat-button}])
(defn communities-screen-content
[]
(let [scroll-height (reagent/atom 0)
selected-tab (reagent/atom :joined)]
(fn []
[scroll-page/scroll-page
{:name (i18n/label :t/communities)
:on-scroll #(reset! scroll-height %)
:top-nav [home-nav]
:title-colum [title-column]
:background-color (colors/theme-colors
colors/white
colors/neutral-95)
:navigate-back? :false
:height (if (> @scroll-height 80)
208
156)}
[home-sticky-header
{:selected-tab selected-tab
:scroll-height scroll-height
:padding-top 8}]
[home-page-comunity-lists
{:selected-tab selected-tab
:padding-top 16
:height 60}]])))
(defn home
[]
[rn/view
{:style (style/home-communities-container (colors/theme-colors
colors/white
colors/neutral-95))}
[communities-screen-content]])

View File

@ -4,7 +4,8 @@
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.async-storage.core :as async-storage] ;;TODO remove when not used anymore [status-im.async-storage.core :as async-storage] ;;TODO remove when not used anymore
[status-im2.contexts.shell.constants :as shell.constants])) [status-im2.contexts.shell.constants :as shell.constants]
[utils.worklets.shell :as worklets.shell]))
;; Atoms ;; Atoms
(def selected-stack-id (atom nil)) (def selected-stack-id (atom nil))
@ -66,8 +67,6 @@
:top (+ top-empty-space (shell.constants/bottom-tabs-container-height)) :top (+ top-empty-space (shell.constants/bottom-tabs-container-height))
:scale minimize-scale})) :scale minimize-scale}))
(def shell-worklets (js/require "../src/js/shell_worklets.js"))
;; Shared Values ;; Shared Values
(defn calculate-shared-values (defn calculate-shared-values
[] []
@ -87,18 +86,11 @@
(assoc (assoc
acc acc
stack-opacity-keyword stack-opacity-keyword
(.stackOpacity (worklets.shell/stack-opacity (name id) selected-stack-id-sv)
^js shell-worklets
(name id)
selected-stack-id-sv)
stack-pointer-keyword stack-pointer-keyword
(.stackPointer (worklets.shell/stack-pointer (name id) selected-stack-id-sv)
^js shell-worklets
(name id)
selected-stack-id-sv)
tabs-icon-color-keyword tabs-icon-color-keyword
(.bottomTabIconColor (worklets.shell/bottom-tab-icon-color
^js shell-worklets
(name id) (name id)
selected-stack-id-sv selected-stack-id-sv
home-stack-state-sv home-stack-state-sv
@ -110,28 +102,19 @@
:pass-through? pass-through-sv :pass-through? pass-through-sv
:home-stack-state home-stack-state-sv :home-stack-state home-stack-state-sv
:animate-home-stack-left animate-home-stack-left :animate-home-stack-left animate-home-stack-left
:home-stack-left (.homeStackLeft :home-stack-left (worklets.shell/home-stack-left
^js shell-worklets
selected-stack-id-sv selected-stack-id-sv
animate-home-stack-left animate-home-stack-left
home-stack-state-sv home-stack-state-sv
(clj->js (:left home-stack-position))) (clj->js (:left home-stack-position)))
:home-stack-top (.homeStackTop :home-stack-top (worklets.shell/home-stack-top
^js shell-worklets
home-stack-state-sv home-stack-state-sv
(:top home-stack-position)) (:top home-stack-position))
:home-stack-opacity (.homeStackOpacity :home-stack-opacity (worklets.shell/home-stack-opacity home-stack-state-sv)
^js shell-worklets :home-stack-pointer (worklets.shell/home-stack-pointer home-stack-state-sv)
home-stack-state-sv) :home-stack-scale (worklets.shell/home-stack-scale home-stack-state-sv
:home-stack-pointer (.homeStackPointer
^js shell-worklets
home-stack-state-sv)
:home-stack-scale (.homeStackScale
^js shell-worklets
home-stack-state-sv
(:scale home-stack-position)) (:scale home-stack-position))
:bottom-tabs-height (.bottomTabsHeight :bottom-tabs-height (worklets.shell/bottom-tabs-height
^js shell-worklets
home-stack-state-sv home-stack-state-sv
(shell.constants/bottom-tabs-container-height) (shell.constants/bottom-tabs-container-height)
(shell.constants/bottom-tabs-extended-container-height))} (shell.constants/bottom-tabs-extended-container-height))}

View File

@ -1,9 +1,7 @@
(ns status-im2.contexts.shell.home-stack (ns status-im2.contexts.shell.home-stack
(:require [react-native.core :as rn] (:require [react-native.reanimated :as reanimated]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts] [status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
[status-im2.contexts.chat.home.view :as chat] ;; TODO move to status-im2 [status-im2.contexts.chat.home.view :as chat]
[status-im2.contexts.communities.home.view :as communities] [status-im2.contexts.communities.home.view :as communities]
[status-im2.contexts.shell.animation :as animation] [status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.constants :as shell.constants] [status-im2.contexts.shell.constants :as shell.constants]
@ -43,8 +41,6 @@
(defn home-stack (defn home-stack
[] []
[safe-area/consumer
(fn [insets]
[:f> [:f>
(fn [] (fn []
(let [shared-values @animation/shared-values-atom (let [shared-values @animation/shared-values-atom
@ -57,8 +53,7 @@
:transform [{:scale (:home-stack-scale shared-values)}]} :transform [{:scale (:home-stack-scale shared-values)}]}
home-stack-original-style)] home-stack-original-style)]
[reanimated/view {:style home-stack-animated-style} [reanimated/view {:style home-stack-animated-style}
[rn/view {:margin-top (:top insets) :flex 1}
[stack-view :communities-stack shared-values] [stack-view :communities-stack shared-values]
[stack-view :chats-stack shared-values] [stack-view :chats-stack shared-values]
[stack-view :browser-stack shared-values] [stack-view :browser-stack shared-values]
[stack-view :wallet-stack shared-values]]]))])]) [stack-view :wallet-stack shared-values]]))])

View File

@ -40,7 +40,7 @@
height (or screen-height height)] height (or screen-height height)]
{:border-bottom-left-radius 20 {:border-bottom-left-radius 20
:border-bottom-right-radius 20 :border-bottom-right-radius 20
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95) :background-color (colors/theme-colors colors/white colors/neutral-95)
:overflow :hidden :overflow :hidden
:position :absolute :position :absolute
:width width :width width

View File

@ -110,7 +110,6 @@
[top-nav-blur-overlay (:top insets)] [top-nav-blur-overlay (:top insets)]
[common.home/top-nav [common.home/top-nav
{:type :shell {:type :shell
:hide-search true
:style {:margin-top (:top insets) :style {:margin-top (:top insets)
:z-index 2}}]])])) :z-index 2}}]])]))

View File

@ -121,21 +121,16 @@
(map :id communities))) (map :id communities)))
(re-frame/reg-sub (re-frame/reg-sub
:communities/community-ids-by-user-involvement :communities/grouped-by-status
:<- [:communities/communities] :<- [:communities/communities]
;; Return communities splitted by level of user participation. Some communities user
;; already joined, to some of them join request sent and others were opened one day
;; and their data remained in app-db.
;; Result map has form: {:joined [id1, id2] :pending [id3, id5] :opened [id4]}"
(fn [communities] (fn [communities]
(reduce (fn [acc community] (reduce (fn [acc community]
(let [joined? (:joined community) (let [joined? (:joined community)
requested? (pos? (:requested-to-join-at community)) requested? (pos? (:requested-to-join-at community))] ;; this looks suspicious
id (:id community)]
(cond (cond
joined? (update acc :joined conj id) joined? (update acc :joined conj community)
requested? (update acc :pending conj id) requested? (update acc :pending conj community)
:else (update acc :opened conj id)))) :else (update acc :opened conj community))))
{:joined [] :pending [] :opened []} {:joined [] :pending [] :opened []}
communities))) communities)))

View File

@ -81,42 +81,6 @@
:unviewed-mentions-count 0} :unviewed-mentions-count 0}
(rf/sub [sub-name community-id]))))) (rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/community-ids-by-user-involvement
[sub-name]
(testing "Empty communities list"
(swap! rf-db/app-db assoc
:communities
{})
(is (= {:joined [] :pending [] :opened []}
(rf/sub [sub-name]))))
(testing "Only opened communities"
(swap! rf-db/app-db assoc
:communities/enabled? true
:communities
{"0x1" {:id "0x1" :name "civilized monkeys"}
"0x2" {:id "0x2" :name "Civilized rats"}
"0x3" {:id "0x3" :name "Civilized dolphins"}})
(is (= {:joined [] :pending [] :opened ["0x1" "0x2" "0x3"]}
(rf/sub [sub-name]))))
(testing "One joined community and two opened ones"
(swap! rf-db/app-db assoc
:communities/enabled? true
:communities
{"0x1" {:id "0x1" :name "civilized monkeys" :joined true}
"0x2" {:id "0x2" :name "Civilized rats"}
"0x3" {:id "0x3" :name "Civilized dolphins"}})
(is (= {:joined ["0x1"] :pending [] :opened ["0x2" "0x3"]}
(rf/sub [sub-name]))))
(testing "One joined community, one open and one pending"
(swap! rf-db/app-db assoc
:communities/enabled? true
:communities
{"0x1" {:id "0x1" :name "civilized monkeys" :joined true}
"0x2" {:id "0x2" :name "Civilized rats" :requested-to-join-at 1000}
"0x3" {:id "0x3" :name "Civilized dolphins"}})
(is (= {:joined ["0x1"] :pending ["0x2"] :opened ["0x3"]}
(rf/sub [sub-name])))))
(h/deftest-sub :communities/sorted-communities (h/deftest-sub :communities/sorted-communities
[sub-name] [sub-name]
(testing "Empty communities list" (testing "Empty communities list"

View File

@ -0,0 +1,11 @@
(ns utils.worklets.bottom-sheet)
(def bottom-sheet-js (js/require "../src/js/worklets/bottom_sheet.js"))
(defn use-translate-y
[window-height bottom-sheet-dy pan-y]
(.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y))
(defn use-background-opacity
[translate-y bg-height window-height]
(.useBackgroundOpacity ^js bottom-sheet-js translate-y bg-height window-height))

View File

@ -0,0 +1,18 @@
(ns utils.worklets.core)
(def core-js (js/require "../src/js/worklets/core.js"))
(defn interpolate-value
[shared-value
input-range
output-range
extrapolation]
(.interpolateValue ^js core-js
shared-value
(clj->js input-range)
(clj->js output-range)
(clj->js extrapolation)))
(defn apply-animations-to-style
[animations style]
(.applyAnimationsToStyle ^js core-js (clj->js animations) (clj->js style)))

View File

@ -0,0 +1,7 @@
(ns utils.worklets.record-audio)
(def ^:private record-audio-worklets (js/require "../src/js/worklets/record_audio.js"))
(defn ring-scale
[scale substract]
(.ringScale ^js record-audio-worklets scale substract))

View File

@ -0,0 +1,7 @@
(ns utils.worklets.scroll-view)
(def scroll-worklet-js (js/require "../src/js/worklets/scroll_view.js"))
(defn use-animated-scroll-handler
[scroll-y]
(.useAnimatedScrollHandlerWorklet ^js scroll-worklet-js scroll-y))

View File

@ -0,0 +1,52 @@
(ns utils.worklets.shell)
(def shell-worklets (js/require "../src/js/worklets/shell.js"))
(defn stack-opacity
[id selected-stack-id]
(.stackOpacity ^js shell-worklets id selected-stack-id))
(defn stack-pointer
[id selected-stack-id]
(.stackPointer ^js shell-worklets id selected-stack-id))
(defn bottom-tabs-height
[home-stack-state-sv container-height extended-container-height]
(.bottomTabsHeight ^js shell-worklets home-stack-state-sv container-height extended-container-height))
(defn bottom-tab-icon-color
[id selected-stack-id-sv home-stack-state-sv pass-through-sv selected-tab-color default-color
pass-through-color]
(.bottomTabIconColor ^js shell-worklets
id
selected-stack-id-sv
home-stack-state-sv
pass-through-sv
selected-tab-color
default-color
pass-through-color))
(defn home-stack-opacity
[home-stack-state-sv]
(.homeStackOpacity ^js shell-worklets home-stack-state-sv))
(defn home-stack-pointer
[home-stack-state-sv]
(.homeStackPointer ^js shell-worklets home-stack-state-sv))
(defn home-stack-scale
[home-stack-state-sv scale]
(.homeStackScale ^js shell-worklets home-stack-state-sv scale))
(defn home-stack-left
[selected-stack-id-sv animate-home-stack-left home-stack-state-sv left-home-stack-position]
(.homeStackLeft
^js shell-worklets
selected-stack-id-sv
animate-home-stack-left
home-stack-state-sv
left-home-stack-position))
(defn home-stack-top
[home-stack-state-sv top-home-stack-position]
(.homeStackTop ^js shell-worklets home-stack-state-sv top-home-stack-position))