Account selection: Use bottom sheet component (#18919)

Use bottom sheet component as designed in
Figma https://www.figma.com/file/h9wo4GipgZURbqqr1vShFN/Communities-for-Mobile?type=design&node-id=16409-98076&mode=design&t=jrVNb3JnWNurJwP8-0

- Fixes no animation when closing Addresses For Permissions modal:
  https://github.com/status-im/status-mobile/issues/18617
- Fixes drawer is always expanded:
  https://github.com/status-im/status-mobile/issues/18619

Additionally:

- Fixed incorrect code passing a function instance to a style prop, which leads
  to incorrect appearance for settings.category.reorder.view/view.
- Optimized Reagent a little bit by extracting functions that need to close over
  the community ID to the mount phase. That way, we avoid regenerating function
  instances on every re-render and Reagent can avoid a bit of re-work.

The challenge was to make the scrollable content work inside a
bottom sheet, while supporting the designs for a fixed (always visible) header
and footer.
This commit is contained in:
Icaro Motta 2024-03-04 09:23:30 -03:00 committed by GitHub
parent f8cd14296f
commit 27e177f18b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 143 additions and 140 deletions

View File

@ -16,9 +16,9 @@
(reagent/flush))
(defn- reorder-category-internal
[{:keys [label data blur? theme]}]
[{:keys [label data blur? theme container-style]}]
(reagent/with-let [atom-data (reagent/atom data)]
[rn/view {:style style/container}
[rn/view {:style (merge (style/container label) container-style)}
[text/text
{:weight :medium
:size :paragraph-2

View File

@ -3,18 +3,18 @@
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(def ^:private sheet-border-radius 20)
(defn sheet
[{:keys [top]} window-height selected-item]
[{:keys [max-height]}]
{:position :absolute
:max-height (- window-height top)
:z-index 1
:bottom 0
:left 0
:right 0
:border-top-left-radius 20
:border-top-right-radius 20
:overflow (when-not selected-item :hidden)
:flex 1})
:z-index 1
:max-height max-height
:border-top-left-radius sheet-border-radius
:border-top-right-radius sheet-border-radius})
(def gradient-bg
{:position :absolute
@ -31,10 +31,11 @@
:bottom 0})
(defn sheet-content
[theme padding-bottom-override {:keys [bottom]} shell? bottom-margin]
{:border-top-left-radius 20
:border-top-right-radius 20
:padding-bottom (or padding-bottom-override (+ bottom bottom-margin))
[{:keys [theme padding-bottom shell?]}]
{:overflow :scroll
:padding-bottom padding-bottom
:border-top-left-radius sheet-border-radius
:border-top-right-radius sheet-border-radius
:background-color (if shell?
:transparent
(colors/theme-colors colors/white colors/neutral-95 theme))})

View File

@ -56,6 +56,10 @@
(show translate-y bg-opacity)
(hide translate-y bg-opacity window-height on-close))))))
(defn- get-layout-height
[event]
(oops/oget event "nativeEvent.layout.height"))
(defn view
[{:keys [hide? insets]}
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
@ -64,6 +68,8 @@
(let [theme (quo.theme/use-theme-value)
sheet-height (rn/use-ref-atom 0)
item-height (rn/use-ref-atom 0)
set-sheet-height (rn/use-callback #(reset! sheet-height (get-layout-height %)))
set-item-height (rn/use-callback #(reset! item-height (get-layout-height %)))
{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value window-height)
@ -80,7 +86,10 @@
top (- window-height (:top insets) @sheet-height)
bottom (if selected-item-smaller-than-sheet?
(+ @sheet-height bottom-margin)
(:bottom insets))]
(:bottom insets))
sheet-max-height (- window-height (:top insets))
content-padding-bottom (or padding-bottom-override
(+ (:bottom insets) bottom-margin))]
(rn/use-effect
#(if hide?
(hide translate-y bg-opacity window-height on-close)
@ -105,7 +114,7 @@
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
(style/sheet insets window-height selected-item))}
(style/sheet {:max-height sheet-max-height}))}
(when shell?
[blur/ios-view
{:style style/shell-bg
@ -114,14 +123,14 @@
:overlay-color :transparent}])
(when selected-item
[rn/view
{:on-layout #(reset! item-height (.-nativeEvent.layout.height ^js %))
:style
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
{:on-layout set-item-height
:style (style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
[selected-item]])
[rn/view
{:style (style/sheet-content theme padding-bottom-override insets shell? bottom-margin)
:on-layout #(reset! sheet-height (.-nativeEvent.layout.height ^js %))}
{:on-layout set-sheet-height
:style (style/sheet-content {:theme theme
:shell? shell?
:padding-bottom content-padding-bottom})}
(when (and gradient-cover? customization-color)
[rn/view {:style style/gradient-bg}
[quo/gradient-cover

View File

@ -5,81 +5,92 @@
[react-native.gesture :as gesture]
[status-im.common.password-authentication.view :as password-authentication]
[status-im.contexts.communities.actions.accounts-selection.style :as style]
[status-im.contexts.communities.actions.addresses-for-permissions.view :as addresses-for-permissions]
[status-im.contexts.communities.actions.airdrop-addresses.view :as airdrop-addresses]
[status-im.contexts.communities.actions.community-rules.view :as community-rules]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- join-community-and-navigate-back
[id]
(rf/dispatch [:password-authentication/show {:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press #(rf/dispatch [:communities/request-to-join-with-addresses
{:community-id id :password %}])}])
(rf/dispatch [:navigate-back]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))]
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])
:accessibility-label :back-button}]
[quo/page-top
{:title (i18n/label :t/request-to-join)
:description :context-tag
:context-tag {:type :community
:size 24
:community-logo (get-in images [:thumbnail :uri])
:community-name name}}]
[gesture/scroll-view
[:<>
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/address-to-share)]
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/join-as-a {:role highest-role-text})
:on-press #(rf/dispatch [:open-modal :addresses-for-permissions
{:community-id id}])
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data selected-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
{:title (i18n/label :t/for-airdrops)
:on-press #(rf/dispatch [:open-modal :airdrop-addresses
{:community-id id}])
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data [airdrop-account]}
:description-props {:text (:name airdrop-account)}}]}]
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)]
[community-rules/view id]]]
[rn/view {:style (style/bottom-actions)}
[quo/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete #(join-community-and-navigate-back id)}]]]))
(let [{id :community-id} (rf/sub [:get-screen-params])
show-addresses-for-permissions (fn []
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content addresses-for-permissions/view}]))
show-airdrop-addresses (fn []
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content airdrop-addresses/view}]))
navigate-back #(rf/dispatch [:navigate-back])
join-and-go-back (fn []
(rf/dispatch [:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press
#(rf/dispatch
[:communities/request-to-join-with-addresses
{:community-id id :password %}])}])
(navigate-back))]
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))]
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}]
[quo/page-top
{:title (i18n/label :t/request-to-join)
:description :context-tag
:context-tag {:type :community
:size 24
:community-logo (get-in images [:thumbnail :uri])
:community-name name}}]
[gesture/scroll-view
[:<>
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/address-to-share)]
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/join-as-a {:role highest-role-text})
:on-press show-addresses-for-permissions
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data selected-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
{:title (i18n/label :t/for-airdrops)
:on-press show-airdrop-addresses
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data [airdrop-account]}
:description-props {:text (:name airdrop-account)}}]}]
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)]
[community-rules/view id]]]
[rn/view {:style (style/bottom-actions)}
[quo/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete join-and-go-back}]]]))))

View File

@ -1,3 +0,0 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.style)
(def container {:flex 1})

View File

@ -1,11 +1,9 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
@ -56,8 +54,15 @@
:customization-color community-color}]))
(defn view
[{:keys [scroll-enabled? on-scroll]}]
(let [{id :community-id} (rf/sub [:get-screen-params])]
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
toggle-share-all-addresses #(rf/dispatch [:communities/toggle-share-all-addresses id])
update-previous-addresses (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
(rf/dispatch [:hide-bottom-sheet]))
reset-selected-addresses (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:hide-bottom-sheet]))]
(rf/dispatch [:communities/get-permissioned-balances id])
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
@ -67,7 +72,7 @@
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
share-all-addresses? (rf/sub [:communities/share-all-addresses? id])
unsaved-address-changes? (rf/sub [:communities/unsaved-address-changes? id])]
[rn/safe-area-view {:style style/container}
[:<>
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
@ -79,26 +84,24 @@
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/share-all-current-and-future-addresses)
:action :selector
:action-props {:on-change #(rf/dispatch
[:communities/toggle-share-all-addresses
id])
:customization-color color
:checked? share-all-addresses?}}]
:container-style {:padding-bottom 16}}]
[gesture/flat-list
{:render-fn account-item
:render-data {:selected-addresses selected-addresses
:community-id id
:share-all-addresses? share-all-addresses?
:community-color color}
:header [quo/category
{:list-type :settings
:data [{:title
(i18n/label
:t/share-all-current-and-future-addresses)
:action :selector
:action-props
{:on-change toggle-share-all-addresses
:customization-color color
:checked? share-all-addresses?}}]
:container-style {:padding-bottom 16 :padding-horizontal 0}}]
:content-container-style {:padding-horizontal 20}
:scroll-enabled @scroll-enabled?
:on-scroll on-scroll
:key-fn :address
:data accounts}]
@ -110,25 +113,18 @@
(empty? selected-addresses)
(not highest-permission-role)
(not unsaved-address-changes?))
:on-press (fn []
(rf/dispatch
[:communities/update-previous-permission-addresses
id])
(rf/dispatch [:navigate-back]))}
:on-press update-previous-addresses}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press (fn []
(rf/dispatch
[:communities/reset-selected-permission-addresses id])
(rf/dispatch [:navigate-back]))}
:on-press reset-selected-addresses}
:description (if (or (empty? selected-addresses)
(not highest-permission-role))
:top-error
:top)
:role (when-not checking? (role-keyword highest-permission-role))
:error-message (cond
(empty? selected-addresses) (i18n/label :t/no-addresses-selected)
(not highest-permission-role) (i18n/label
:t/addresses-dont-contain-tokens-needed)
:else nil)}]]))))
(empty? selected-addresses)
(i18n/label :t/no-addresses-selected)
(not highest-permission-role)
(i18n/label :t/addresses-dont-contain-tokens-needed))}]]))))

View File

@ -1,7 +1,7 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.contexts.communities.actions.airdrop-addresses.style :as style]
[utils.i18n :as i18n]
@ -14,7 +14,7 @@
:state (when (= airdrop-address (:address item)) :selected)
:on-press (fn []
(rf/dispatch [:communities/set-airdrop-address (:address item) community-id])
(rf/dispatch [:navigate-back]))
(rf/dispatch [:hide-bottom-sheet]))
:emoji (:emoji item)}])
(defn view
@ -33,7 +33,7 @@
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
[rn/flat-list
[gesture/flat-list
{:data selected-accounts
:render-fn render-item
:render-data [airdrop-address id]

View File

@ -13,9 +13,6 @@
[status-im.contexts.chat.messenger.messages.view :as chat]
[status-im.contexts.chat.messenger.photo-selector.view :as photo-selector]
[status-im.contexts.communities.actions.accounts-selection.view :as communities.accounts-selection]
[status-im.contexts.communities.actions.addresses-for-permissions.view :as
addresses-for-permissions]
[status-im.contexts.communities.actions.airdrop-addresses.view :as airdrop-addresses]
[status-im.contexts.communities.actions.request-to-join.view :as join-menu]
[status-im.contexts.communities.actions.share-community-channel.view :as share-community-channel]
[status-im.contexts.communities.discover.view :as communities.discover]
@ -126,14 +123,6 @@
:options {:sheet? true}
:component communities.accounts-selection/view}
{:name :addresses-for-permissions
:options {:sheet? true}
:component addresses-for-permissions/view}
{:name :airdrop-addresses
:options {:sheet? true}
:component airdrop-addresses/view}
{:name :lightbox
:options options/lightbox
:component lightbox/lightbox}