feat: toast component (#14376)

This commit is contained in:
yqrashawn 2022-12-20 21:52:28 +08:00 committed by GitHub
parent 01660765b7
commit 37909c2d81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 577 additions and 28 deletions

View File

@ -4,6 +4,20 @@
(:require [status-im.utils.test :as utils.test])
(:require [status-im.chat.default-chats :refer (default-chats)]))
;; to generate a js Proxy at js/__STATUS_MOBILE_JS_IDENTITY_PROXY__ that accept any (.xxx) call and return itself
;; For the convenience to mock eg.
;; (-> reanimated/slide-out-up-animation .springify (.damping 20) (.stiffness 300))
;; (-> reanimated/slide-out-up-animation (.damping 20) .springify (.stiffness 300))
(js/eval "
var globalThis
if (typeof window === \"undefined\") {
globalThis = global
} else {
globalThis = window
}
globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return () => globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__}})
")
(def action-button #js {:default #js {:Item #js {}}})
(def config #js {:default #js {}})
(def camera #js {:RNCamera #js {:Constants #js {}}})
@ -111,7 +125,9 @@
(def react-native-shake #js {})
(def react-native-share #js {:default {}})
(def react-native-svg #js {:SvgUri #js {:render identity}
:SvgXml #js {:render identity}})
:SvgXml #js {:render identity}
:default #js {:render identity}
:Path #js {:render identity}})
(def react-native-webview #js {:default {}})
(def react-native-audio-toolkit #js {:MediaStates {}})
(def net-info #js {})
@ -207,7 +223,10 @@
:withTiming (fn [])
:withDelay (fn [])
:Easing #js {:bezier identity}
:Keyframe (fn [])})
:Keyframe (fn [])
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
(def react-native-gesture-handler #js {:default #js {}
:State #js {:BEGAN nil
:ACTIVE nil

View File

@ -0,0 +1,106 @@
(ns quo2.components.notifications.count-down-circle
(:require
[goog.string :as gstring]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[react-native.svg :as svg]
[reagent.core :as reagent]))
(defn- get-path-props
[size stroke-width rotation]
(let [half-size (/ size 2)
half-stroke-width (/ stroke-width 2)
arc-radius (- half-size half-stroke-width)
arc-diameter (* arc-radius 2)
rotation-indicator (if (= rotation :clockwise) "1,0" "0,1")
path-length (* js/Math.PI arc-diameter)
path (gstring/format
"m %s,%s a %s,%s 0 %s 0,%s a %s,%s 0 %s 0 ,-%s"
half-size
half-stroke-width
arc-radius
arc-radius
rotation-indicator
arc-diameter
arc-radius
arc-radius
rotation-indicator
arc-diameter)]
{:path path
:path-length path-length}))
(defn- linear-ease
[time start goal duration]
(if (zero? duration)
start
(-> time
(/ duration)
(* goal)
(+ start))))
(defn- get-start-at
[duration initial-remaining-time]
(cond (or (zero? duration) (= duration initial-remaining-time)) 0
(number? initial-remaining-time) (- duration initial-remaining-time)
:else 0))
(def ^:private themes
{:color {:light colors/neutral-80-opa-40
:dark colors/white-opa-40}})
(defn circle-timer
[{:keys [color duration size stroke-width trail-color rotation initial-remaining-time]}]
(let [rotation (or rotation :clockwise)
duration (or duration 4)
stroke-width (or stroke-width 1)
size (or size 9)
max-stroke-width (max stroke-width 0)
{:keys [path path-length]} (get-path-props size max-stroke-width rotation)
start-at (get-start-at duration initial-remaining-time)
elapsed-time (reagent/atom 0)
prev-frame-time (reagent/atom nil)
frame-request (reagent/atom nil)
display-time (reagent/atom start-at)
;; get elapsed frame time
swap-elapsed-time-each-frame (fn swap-elapsed-time-each-frame [frame-time]
(if (nil? @prev-frame-time)
(do (reset! prev-frame-time frame-time)
(reset! frame-request (js/requestAnimationFrame
swap-elapsed-time-each-frame)))
(let [delta (- (/ frame-time 1000)
(/ @prev-frame-time 1000))
current-elapsed (swap! elapsed-time + delta)
current-display-time (+ start-at current-elapsed)
completed? (>= current-display-time duration)]
(reset! display-time (if completed?
duration
current-display-time))
(when-not completed?
(reset! prev-frame-time frame-time)
(reset! frame-request (js/requestAnimationFrame
swap-elapsed-time-each-frame))))))]
(reagent/create-class
{:component-will-unmount #(js/cancelAnimationFrame @frame-request)
:reagent-render
(fn []
(reset! frame-request (js/requestAnimationFrame swap-elapsed-time-each-frame))
[rn/view
{:style {:position :relative
:width size
:height size}}
[svg/svg
{:view-box (str "0 0 " size " " size)
:width size
:height size}
[svg/path
{:d path :fill :none :stroke (or trail-color :transparent) :stroke-width stroke-width}]
(when-not (= @display-time duration)
[svg/path
{:d path
:fill :none
:stroke (or color (get-in themes [:color (theme/get-theme)]))
:stroke-linecap :square
:stroke-width stroke-width
:stroke-dasharray path-length
:stroke-dashoffset (linear-ease @display-time 0 path-length duration)}])]])})))

View File

@ -0,0 +1,82 @@
(ns quo2.components.notifications.toast
(:require
[i18n.i18n :as i18n]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.notifications.count-down-circle :as count-down-circle]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(def ^:private themes
{:container {:light {:background-color colors/white-opa-70}
:dark {:background-color colors/neutral-80-opa-70}}
:text {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:icon {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:action-container {:light {:background-color :colors/neutral-80-opa-5}
:dark {:background-color :colors/white-opa-5}}})
(defn- merge-theme-style
[component-key styles]
(merge (get-in themes [component-key (theme/get-theme)]) styles))
(defn toast-action-container
[{:keys [on-press style]} & children]
[rn/touchable-highlight {:on-press on-press}
[into
[rn/view
{:style (merge
{:flex-direction :row
:padding-vertical 3
:padding-horizontal 8
:align-items :center
:border-radius 8
:background-color (get-in themes
[:action-container (theme/get-theme)
:background-color])}
style)}]
children]])
(defn toast-undo-action
[duration on-press]
[toast-action-container {:on-press on-press}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
[i18n/label :undo]]])
(defn- toast-container
[{:keys [left middle right]}]
[rn/view {:style {:padding-left 12 :padding-right 12}}
[rn/view
{:style (merge-theme-style :container
{:flex-direction :row
:width "100%"
:margin :auto
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12})}
[rn/view {:style {:padding 2}} left]
[rn/view {:style {:padding 4 :flex 1}}
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
middle]]
(when right right)]])
(defn toast
[{:keys [icon icon-color text action undo-duration undo-on-press]}]
[toast-container
{:left (when icon
[icon/icon icon
{:container-style {:width 20 :height 20}
:color (or icon-color
(get-in themes [:icon (theme/get-theme) :color]))}])
:middle text
:right (if undo-duration
[toast-undo-action undo-duration undo-on-press]
action)}])

View File

@ -36,6 +36,7 @@
quo2.components.tags.tags
quo2.components.tags.context-tags
quo2.components.tabs.tabs
quo2.components.notifications.toast
quo2.components.tabs.account-selector
quo2.components.navigation.floating-shell-button
quo2.components.tags.status-tags
@ -43,8 +44,10 @@
quo2.components.selectors.disclaimer
quo2.components.selectors.selectors
quo2.components.settings.privacy-option
quo2.components.loaders.skeleton))
quo2.components.loaders.skeleton
quo2.components.notifications.count-down-circle))
(def toast quo2.components.notifications.toast/toast)
(def button quo2.components.buttons.button/button)
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
(def text quo2.components.markdown.text/text)
@ -107,6 +110,7 @@
(def activity-log quo2.components.notifications.activity-log.view/view)
(def info-count quo2.components.notifications.info-count/info-count)
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
(def count-down-circle quo2.components.notifications.count-down-circle/circle-timer)
;;;; SETTINGS
(def privacy-option quo2.components.settings.privacy-option/card)

View File

@ -1,9 +1,12 @@
(ns react-native.core
(:require [reagent.core :as reagent]
(:require ["react" :as react]
["react-native" :as react-native]
[cljs-bean.core :as bean]
["@react-native-community/blur" :as blur]
[oops.core :as oops]
[react-native.flat-list :as flat-list]
[react-native.section-list :as section-list]
[reagent.core :as reagent]
[react-native.platform :as platform]))
(def app-state ^js (.-AppState ^js react-native))
@ -73,3 +76,15 @@
(merge (when platform/ios? {:behavior :padding})
props)]
children))
(defn use-effect
([effect] (use-effect effect []))
([effect deps]
(react/useEffect effect (bean/->js deps))))
(def use-ref react/useRef)
(defn use-effect-once [effect] (use-effect effect))
(defn use-unmount [f]
(let [fn-ref (use-ref f)]
(oops/oset! fn-ref "current" f)
(use-effect-once (fn [] #((oops/oget fn-ref "current"))))))

View File

@ -1,10 +1,15 @@
(ns react-native.reanimated
(:require ["react-native" :as rn]
[reagent.core :as reagent]
[clojure.string :as string]
["react-native-linear-gradient" :default LinearGradient]
["react-native-reanimated" :default reanimated
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe cancelAnimation)]))
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe cancelAnimation SlideInUp SlideOutUp LinearTransition)]
[clojure.string :as string]
[reagent.core :as reagent]))
;; Animations
(def slide-in-up-animation SlideInUp)
(def slide-out-up-animation SlideOutUp)
(def linear-transition LinearTransition)
;; Animated Components
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
@ -95,3 +100,8 @@
#js {:duration duration
:easing (get easings easing)})
number-of-repetitions reverse?)))))
(defn animate-shared-value-with-spring [anim val {:keys [mass stiffness damping]}]
(set-shared-value anim (with-spring val (js-obj "mass" mass
"damping" damping
"stiffness" stiffness))))

View File

@ -0,0 +1,7 @@
(ns react-native.svg
(:require
["react-native-svg" :as Svg]
[reagent.core :as reagent]))
(def svg (reagent/adapt-react-class Svg/default))
(def path (reagent/adapt-react-class Svg/Path))

View File

@ -0,0 +1,48 @@
(ns status-im2.common.toasts.events
(:require
[taoensso.encore :as enc]
[utils.re-frame :as rf]))
(def ^:private next-toast-id (atom 0))
(rf/defn upsert
{:events [:toasts/upsert]}
[{:keys [db]} id opts]
(let [{:toasts/keys [index toasts]} db
update? (some #{id} index)
index (enc/conj-when index (and (not update?) id))
toasts (assoc toasts id opts)
db (-> db
(assoc
:toasts/index index
:toasts/toasts toasts)
(dissoc :toasts/hide-toasts-timer-set))]
(if (and (not update?) (= (count index) 1))
{:show-toasts []
:db db}
{:db db})))
(rf/defn create
{:events [:toasts/create]}
[{:keys [db]} opts]
{:dispatch [:toasts/upsert (str "toast-" (swap! next-toast-id inc)) opts]})
(rf/defn hide-toasts-with-check
{:events [:toasts/hide-with-check]}
[{:keys [db]}]
(when (:toasts/hide-toasts-timer-set db)
{:db (dissoc db :toasts/hide-toasts-timer-set)
:hide-toasts nil}))
(rf/defn close
{:events [:toasts/close]}
[{:keys [db]} id]
(when (get-in db [:toasts/toasts id])
(let [{:toasts/keys [toasts index]} db
toasts (dissoc toasts id)
index (remove #{id} index)
empty-index? (not (seq index))
db (assoc db :toasts/index index :toasts/toasts toasts)]
(cond-> {:db db}
empty-index? (update :db assoc :toasts/hide-toasts-timer-set true)
empty-index? (assoc :dispatch-later [{:ms 500 :dispatch [:toasts/hide-with-check]}])))))

View File

@ -0,0 +1,104 @@
(ns status-im2.common.toasts.view
(:require
[quo2.core :as quo2]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im.utils.utils :as utils.utils]
[utils.re-frame :as rf]))
(def ^:private slide-out-up-animation
(-> reanimated/slide-out-up-animation
.springify
(.damping 20)
(.stiffness 300)))
(def ^:private slide-in-up-animation
(-> reanimated/slide-in-up-animation
.springify
(.damping 20)
(.stiffness 300)))
(def ^:private linear-transition
(-> reanimated/linear-transition
.springify
(.damping 20)
(.stiffness 300)))
(defn container
[id]
(let [dismissed-locally? (reagent/atom false)
close! #(rf/dispatch [:toasts/close id])
timer (reagent/atom nil)
clear-timer #(utils.utils/clear-timeout @timer)]
(fn []
[:f>
(fn []
(let [toast-opts (rf/sub [:toasts/toast id])
duration (get toast-opts :duration 3000)
on-dismissed #((get toast-opts :on-dismissed identity) id)
translate-y (reanimated/use-shared-value 0)
create-timer (fn []
(reset! timer (utils.utils/set-timeout #(do (close!) (on-dismissed))
duration)))
pan
(->
(gesture/gesture-pan)
;; remove timer on pan start
(gesture/on-start clear-timer)
(gesture/on-update
(fn [evt]
(let [evt-translation-y (.-translationY evt)]
(cond
;; reset translate y on pan down
(> evt-translation-y 100)
(reanimated/animate-shared-value-with-spring translate-y
0
{:mass 1
:damping 20
:stiffness 300})
;; dismiss on pan up
(< evt-translation-y -30)
(do (reanimated/animate-shared-value-with-spring
translate-y
-500
{:mass 1 :damping 20 :stiffness 300})
(reset! dismissed-locally? true)
(close!))
:else
(reanimated/set-shared-value translate-y
evt-translation-y)))))
(gesture/on-end (fn [_]
(when-not @dismissed-locally?
(reanimated/set-shared-value translate-y 0)
(create-timer)))))]
;; create auto dismiss timer, clear timer when unmount or duration changed
(rn/use-effect (fn [] (create-timer) clear-timer) [duration])
(rn/use-unmount on-dismissed)
[gesture/gesture-detector {:gesture pan}
[reanimated/view
{:entering slide-in-up-animation
:exiting slide-out-up-animation
:layout reanimated/linear-transition
:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
{:width "100%"
:margin-bottom 5})}
[quo2/toast toast-opts]]]))])))
(defn toasts
[]
(let [toasts-index (rf/sub [:toasts/index])]
[into
[rn/view
{:style {:elevation 2
:pointer-events :box-none
:padding-top 52
:flex-direction :column
:justify-content :center
:align-items :center
:background-color :transparent}}]
(->> toasts-index
reverse
(map (fn [id] ^{:key id} [container id])))]))

View File

@ -56,6 +56,7 @@
[status-im2.contexts.quo-preview.wallet.network-amount :as network-amount]
[status-im2.contexts.quo-preview.navigation.page-nav :as page-nav]
[status-im2.contexts.quo-preview.avatars.account-avatar :as account-avatar]
[status-im2.contexts.quo-preview.notifications.toast :as toast]
[status-im2.contexts.quo-preview.community.token-gating :as token-gating]
[re-frame.core :as re-frame]))
@ -158,7 +159,10 @@
:component floating-shell-button/preview-floating-shell-button}]
:notifications [{:name :activity-logs
:insets {:top false}
:component activity-logs/preview-activity-logs}]
:component activity-logs/preview-activity-logs}
{:name :toast
:insets {:top false}
:component toast/preview-toasts}]
:posts-and-attachments [{:name :messages-skeleton
:insets {:top false}
:component messages-skeleton/preview-messages-skeleton}]

View File

@ -0,0 +1,116 @@
(ns status-im2.contexts.quo-preview.notifications.toast
(:require
[quo2.components.buttons.button :as button]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.re-frame :as rf]))
(defn toast-button
([id opts] (toast-button id id opts))
([text id opts]
(let [toast-opts (rf/sub [:toasts/toast id])
dismiss! #(rf/dispatch [:toasts/close id])
toast! #(rf/dispatch [:toasts/upsert id opts])
dismissed? (not toast-opts)]
[rn/view {:style {:margin-bottom 10}}
[button/button
{:size 32
:on-press #(if dismissed? (toast!) (dismiss!))}
(if dismissed? text (str "DISMISS " text))]])))
(defn toast-button-basic
[]
[toast-button
"Toast: basic"
{:icon :placeholder :icon-color "green" :text "This is an example toast"}])
(defn toast-button-with-undo-action
[]
[toast-button
"Toast: with undo action"
{:icon :info
:icon-color colors/danger-50-opa-40
:text "This is an example toast"
:duration 4000
:undo-duration 4
:undo-on-press #(do
(rf/dispatch [:toasts/create
{:icon :placeholder
:icon-color "green"
:text "Undo pressed"}])
(rf/dispatch [:toasts/close
"Toast: with undo action"]))}])
(defn toast-button-multiline
[]
[toast-button
"Toast: multiline"
{:icon :placeholder
:icon-color "green"
:text
"This is an example multiline toast This is an example multiline toast This is an example multiline toast"
:undo-duration 4
:undo-on-press
#(do
(rf/dispatch
[:toasts/create
{:icon :placeholder :icon-color "green" :text "Undo pressed"}])
(rf/dispatch [:toasts/close "Toast: with undo action"]))}])
(defn toast-button-30s-duration
[]
[toast-button
"Toast: 30s duration"
{:icon :placeholder
:icon-color "green"
:text "This is an example toast"
:duration 30000}])
(defn update-toast-button
[]
(let [suffix (reagent/atom 0)]
(fn []
(let [toast-opts (rf/sub [:toasts/toast "Toast: 30s duration"])]
(when toast-opts
[rn/view {:style {:margin-bottom 10}}
[button/button
{:size 32
:on-press
#(rf/dispatch
[:toasts/upsert
"Toast: 30s duration"
{:icon :placeholder
:icon-color "red"
:text (str "This is an updated example toast" " - " (swap! suffix inc))
:duration 3000}])}
"update above toast"]])))))
(defn preview
[]
(fn []
[rn/view
[rn/view
{:background-color "#508485"
:flex-direction :column
:justify-content :flex-start
:height 300}]
[into
[rn/view
{:flex 1
:padding 16}]
[^{:key :basic} [toast-button-basic]
^{:key :with-undo-action} [toast-button-with-undo-action]
^{:key :with-multiline} [toast-button-multiline]
^{:key :30s-duration} [toast-button-30s-duration]
^{:key :upsert}
[update-toast-button]]]]))
(defn preview-toasts
[]
[rn/view {:flex 1}
[rn/flat-list
{:flex 1
:header [preview]
:key-fn str
:keyboardShouldPersistTaps :always}]])

View File

@ -132,6 +132,7 @@
(log/debug "screen-appear-reg" view-id)
(when (get views/screens view-id)
(when (and (not= view-id :bottom-sheet)
(not= view-id :toasts)
(not= view-id :popover)
(not= view-id :visibility-status-popover))
(set-view-id view-id)
@ -212,7 +213,9 @@
;; OVERLAY (Popover and bottom sheets)
(def dissmiss-overlay navigation/dissmiss-overlay)
(defn show-overlay [comp]
(defn show-overlay
([comp] (show-overlay comp {}))
([comp opts]
(dissmiss-overlay comp)
(navigation/show-overlay
{:component {:name comp
@ -223,12 +226,17 @@
{:layout {:componentBackgroundColor (if platform/android?
colors/neutral-80-opa-20 ;; TODO adjust color
"transparent")}
:overlay {:interceptTouchOutside true}})}}))
:overlay {:interceptTouchOutside true}}
opts)}})))
;; POPOVER
(re-frame/reg-fx :show-popover (fn [] (show-overlay "popover")))
(re-frame/reg-fx :hide-popover (fn [] (dissmiss-overlay "popover")))
;; TOAST
(re-frame/reg-fx :show-toasts (fn [] (show-overlay "toasts" {:overlay {:interceptTouchOutside false} :layout {:componentBackgroundColor :transparent}})))
(re-frame/reg-fx :hide-toasts (fn [] (dissmiss-overlay "toasts")))
;; VISIBILITY STATUS POPOVER
(re-frame/reg-fx :show-visibility-status-popover
(fn [] (show-overlay "visibility-status-popover")))
@ -270,6 +278,11 @@
(fn [] (gesture/gesture-handler-root-hoc views/popover-comp))
(fn [] views/popover-comp))
(navigation/register-component
"toasts"
(fn [] views/toasts-comp)
js/undefined)
(navigation/register-component
"visibility-status-popover"
(fn [] (gesture/gesture-handler-root-hoc views/visibility-status-popover-comp))

View File

@ -7,6 +7,7 @@
[status-im2.navigation.screens :as screens]
[status-im2.setup.config :as config]
[status-im2.setup.hot-reload :as reloader]
[status-im2.common.toasts.view :as toasts]
;; TODO (14/11/22 flexsurfer) move to status-im2 namespace
[status-im.ui.screens.popover.views :as popover]
@ -92,6 +93,13 @@
(when js/goog.DEBUG
[reloader/reload-view])])))
(def toasts-comp
(reagent/reactify-component
(fn []
;; DON'T wrap this in safe-area-provider, it makes it unable to click through toasts
^{:key (str "toasts" @reloader/cnt)}
[toasts/toasts])))
(def visibility-status-popover-comp
(reagent/reactify-component
(fn []

View File

@ -1,17 +1,18 @@
(ns status-im2.setup.events
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im2.setup.db :as db]
[status-im2.common.theme.core :as theme]
[quo2.theme :as quo2.theme]
[utils.re-frame :as rf]
[re-frame.core :as re-frame]
;; TODO (14/11/22 flexsurfer move to status-im2 namespace
[quo.theme :as quo.theme]
[status-im.native-module.core :as status]
[status-im.multiaccounts.login.core :as multiaccounts.login]
[status-im.utils.keychain.core :as keychain]
[status-im2.navigation.events :as navigation]))
[status-im2.common.theme.core :as theme]
[status-im2.common.toasts.events]
[status-im2.navigation.events :as navigation]
[status-im2.setup.db :as db]
[utils.re-frame :as rf]))
(re-frame/reg-fx
:setup/open-multiaccounts

View File

@ -3,10 +3,10 @@
status-im2.subs.activity-center
status-im2.subs.bootnodes
status-im2.subs.browser
status-im2.subs.communities
status-im2.subs.contact
status-im2.subs.chat.chats
status-im2.subs.chat.messages
status-im2.subs.communities
status-im2.subs.contact
status-im2.subs.ens
status-im2.subs.general
status-im2.subs.home
@ -19,6 +19,7 @@
status-im2.subs.search
status-im2.subs.stickers
status-im2.subs.shell
status-im2.subs.toasts
status-im2.subs.wallet.signing
status-im2.subs.wallet.transactions
status-im2.subs.wallet.wallet))
@ -196,6 +197,8 @@
;;intro-wizard
(reg-root-key-sub :intro-wizard-state :intro-wizard)
(reg-root-key-sub :toasts/toasts :toasts/toasts)
(reg-root-key-sub :toasts/index :toasts/index)
(reg-root-key-sub :popover/popover :popover/popover)
(reg-root-key-sub :visibility-status-popover/popover :visibility-status-popover/popover)
(reg-root-key-sub :add-account :add-account)

View File

@ -0,0 +1,9 @@
(ns status-im2.subs.toasts
(:require
[re-frame.core :as re-frame]))
(re-frame/reg-sub
:toasts/toast
:<- [:toasts/toasts]
(fn [toasts [_ toast-id]]
(get toasts toast-id)))