feat: implement interactive graphs (#17029)

Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
Brian Sztamfater 2023-08-31 13:45:54 -03:00 committed by GitHub
parent 62030497e5
commit 1c730bc692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 643 additions and 75 deletions

View File

@ -49,7 +49,7 @@
"react-native-fetch-polyfill": "^1.1.2",
"react-native-fs": "^2.14.1",
"react-native-gesture-handler": "2.6.1",
"react-native-gifted-charts": "^1.3.2",
"react-native-gifted-charts": "git+https://github.com/status-im/react-native-gifted-charts.git#refs/tags/1.3.2-status.1",
"react-native-haptic-feedback": "^1.9.0",
"react-native-hole-view": "git+https://github.com/status-im/react-native-hole-view.git#refs/tags/v2.1.3-status",
"react-native-image-crop-picker": "git+https://github.com/status-im/react-native-image-crop-picker.git#refs/tags/v0.36.2-status.0",

View File

@ -0,0 +1,13 @@
(ns quo2.components.graph.interactive-graph.component-spec
(:require [test-helpers.component :as h]
[quo2.components.graph.interactive-graph.view :as interactive-graph]))
(defn data
[num-elements]
(vec (take num-elements (repeat {:value 10}))))
(h/describe "interactive-graph"
(h/test "render interactive graph"
(h/render [interactive-graph/view
{:data data}])
(h/is-truthy (h/get-by-label-text :interactive-graph))))

View File

@ -0,0 +1,49 @@
(ns quo2.components.graph.interactive-graph.style
(:require [quo2.foundations.typography :as typography]))
(defn x-axis-label-text
[width y-axis-label-text-color]
(merge
typography/label
{:color y-axis-label-text-color
:height 16
:text-align :center
:width width}))
(defn y-axis-text
[y-axis-label-text-color y-axis-label-background-color]
(merge
typography/label
{:color y-axis-label-text-color
:padding-horizontal 3
:margin-left 23
:height 16
:border-radius 6
:overflow :hidden
:background-color y-axis-label-background-color}))
(defn pointer-component
[customization-color]
{:width 8
:height 8
:border-radius 4
:margin-left 1
:background-color customization-color})
(defn reference-line-label
[border-color background-color text-color]
(merge
typography/label
{:align-self :flex-end
:right 10
:margin-top -9
:padding-horizontal 5
:padding-top -10
:height 19
:line-height 14.62
:border-radius 6
:overflow :hidden
:border-color border-color
:border-width 2
:background-color background-color
:color text-color}))

View File

@ -0,0 +1,141 @@
(ns quo2.components.graph.interactive-graph.view
(:require [quo2.components.graph.utils :as utils]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.charts :as charts]
[react-native.core :as rn]
[reagent.core :as reagent]
[quo2.components.graph.interactive-graph.style :as style]))
(def chart-height 375)
(def max-data-points 500)
(def no-of-sections 4)
(def initial-spacing 56)
(def end-spacing 22)
(def y-axis-label-width -33)
(def inspecting? (reagent/atom false))
(defn- pointer
[customization-color]
(reagent/as-element
[rn/view
{:style
(style/pointer-component
customization-color)}]))
(defn- pointer-config
[customization-color]
{:stroke-dash-array [2 2]
:pointer-component #(pointer customization-color)
:pointer-strip-color customization-color
:pointer-color customization-color
:pointer-strip-enable-gradient true})
(defn- get-pointer-props
[pointer-props]
(let [pointer-index (.-pointerIndex ^js pointer-props)]
(reset! inspecting? (not= pointer-index -1))))
(defn- get-line-color
[state theme]
(if @inspecting?
(colors/theme-colors colors/neutral-80-opa-40
colors/white-opa-20
theme)
(if (= state :positive)
(colors/theme-colors colors/success-50
colors/success-60
theme)
(colors/theme-colors colors/danger-50
colors/danger-60
theme))))
(defn- view-internal
[{:keys [data state customization-color theme reference-value reference-prefix decimal-separator]
:or {reference-prefix "$"
decimal-separator :dot}}]
(let [data (if (> (count data) max-data-points)
(utils/downsample-data data max-data-points)
data)
highest-value (utils/find-highest-value data)
lowest-value (utils/find-lowest-value data)
min-value (utils/calculate-rounded-min lowest-value)
max-value (- (utils/calculate-rounded-max highest-value) min-value)
step-value (/ max-value 4)
width (:width (rn/get-window))
line-color (get-line-color state theme)
rules-color (colors/theme-colors colors/neutral-80-opa-10
colors/white-opa-5
theme)
y-axis-label-text-color (colors/theme-colors colors/neutral-80-opa-40
colors/white-opa-40
theme)
price-reference-label-text-color (colors/theme-colors colors/neutral-100 colors/white theme)
reference-label-border-color (colors/theme-colors colors/white colors/neutral-95 theme)
y-axis-label-background-color (colors/theme-colors colors/white-70-blur-opaque
colors/neutral-95
theme)
customization-color (colors/theme-colors
(colors/custom-color customization-color 60)
(colors/custom-color customization-color 50)
theme)
y-axis-label-texts (utils/calculate-y-axis-labels min-value step-value 4)
x-axis-label-texts (utils/calculate-x-axis-labels data 5)
reference-label-background-color (colors/theme-colors colors/neutral-80-opa-5-opaque
colors/neutral-80
theme)
reference-value (or reference-value (/ (+ highest-value lowest-value) 2))
formatted-reference-value (utils/format-currency-number reference-value decimal-separator)
chart-width (+ width 13)]
[rn/view {:accessibility-label :interactive-graph}
[charts/line-chart
{:height chart-height
:width chart-width
:max-value max-value
:x-axis-length chart-width
:y-axis-offset min-value
:y-axis-label-texts y-axis-label-texts
:y-axis-label-texts-ignore-offset true
:adjust-to-width true
:data data
:hide-data-points true
:no-of-sections no-of-sections
:step-value step-value
:rules-color rules-color
:dash-width 2
:dash-gap 2
:hide-y-axis-text false
:thickness 1
:color line-color
:y-axis-thickness 0
:x-axis-thickness 0
:initial-spacing initial-spacing
:end-spacing end-spacing
:disable-scroll true
:hide-origin true
:show-reference-line-1 true
:get-pointer-props get-pointer-props
:show-strip-on-focus true
:reference-line-1-config {:color rules-color}
:reference-line-1-position 0
:show-reference-line-2 (and (not @inspecting?)
(<= reference-value highest-value)
(>= reference-value lowest-value))
:reference-line-2-config {:color y-axis-label-text-color
:label-text-style (style/reference-line-label
reference-label-border-color
reference-label-background-color
price-reference-label-text-color)
:label-text (str reference-prefix
formatted-reference-value)
:dash-width 2}
:reference-line-2-position (- reference-value min-value)
:y-axis-text-style (style/y-axis-text y-axis-label-text-color
y-axis-label-background-color)
:y-axis-label-width y-axis-label-width
:pointer-config (pointer-config customization-color)
:x-axis-label-text-style (style/x-axis-label-text (/ width (count x-axis-label-texts))
y-axis-label-text-color)
:x-axis-label-texts x-axis-label-texts}]]))
(def view (quo.theme/with-theme view-internal))

View File

@ -0,0 +1,95 @@
(ns quo2.components.graph.utils
(:require [clojure.string :as string]
[goog.string :as gstring]))
(defn find-highest-value
[coll]
(apply max (map :value coll)))
(defn find-lowest-value
[coll]
(apply min (map :value coll)))
(defn downsample-data
[data max-array-size]
(let [data-size (count data)]
(if (> data-size max-array-size)
(let [step-size (max (/ data-size max-array-size) 1)]
(vec (take-nth step-size data)))
data)))
(defn format-compact-number
[number]
(let [abbreviations ["" "k" "M" "B" "T"]
log-base-1000 (js/Math.log10 1000) ; Calculate the logarithm base 1000
magnitude (int (/ (js/Math.log10 number) log-base-1000))
suffix (nth abbreviations magnitude)
scaled-number (/ number (js/Math.pow 1000.0 magnitude))
formatted-scaled-number (if (zero? (rem scaled-number 1))
(int scaled-number)
(-> (gstring/format "%.2f" scaled-number)
(string/replace #"\.?0+$" "")))]
(if (zero? magnitude)
(str number)
(if (and (>= scaled-number 1) (< scaled-number 1000))
(str formatted-scaled-number suffix)
(str formatted-scaled-number "0" suffix)))))
(defn calculate-x-axis-labels
[array num-elements]
(let [array-length (count array)
partitions (partition-all (js/Math.floor (/ array-length (min array-length num-elements)))
array)]
(->> partitions
(map first)
(map :date))))
(defn calculate-y-axis-labels
[min-value step-value no-of-steps]
(let [labels-array (for [i (range (inc no-of-steps))]
(let [value (+ min-value (* step-value i))
compact-number (format-compact-number value)]
compact-number))]
(vec labels-array)))
(defn calculate-rounded-max
[highest-value]
(let [min-percentage-above 1.05 ; 5% above
rounded-divisor 4 ; Divisor for even division by 4
target-max (* min-percentage-above highest-value)
rounded-up (js/Math.ceil target-max)
remainder (mod rounded-up rounded-divisor)
y-axis-max (if (zero? remainder)
rounded-up
(+ rounded-up (- rounded-divisor remainder)))]
y-axis-max))
(defn calculate-rounded-min
[lowest]
(let [order-of-magnitude (js/Math.pow 10 (js/Math.floor (js/Math.log10 lowest)))
rounded-min (cond
(and (< lowest 1) (>= lowest 0)) 0
(>= lowest 1)
(* (js/Math.floor (/ lowest
order-of-magnitude))
order-of-magnitude)
(< lowest 0)
(* (calculate-rounded-max (* -1 lowest))
-1))]
rounded-min))
(defn format-currency-number
[number decimal-separator]
(let [formatted (-> (if (= decimal-separator :comma)
(js/Intl.NumberFormat
"de-DE"
{:style "currency" :currency "EUR" :minimumFractionDigits 2})
(js/Intl.NumberFormat
"en-US"
{:style "currency" :currency "USD" :minimumFractionDigits 2}))
(.format number))
separator-char (if (= decimal-separator :comma) "," ".")
formatted-with-decimals (if (.includes formatted separator-char)
formatted
(str formatted separator-char "00"))]
formatted-with-decimals))

View File

@ -0,0 +1,179 @@
(ns quo2.components.graph.utils-test
(:require [cljs.test :refer-macros [deftest is testing]]
[quo2.components.graph.utils :as utils]))
(deftest find-highest-value
(testing "Find highest value with a single map"
(let [data [{:value 5}]]
(is (= (utils/find-highest-value data) 5))))
(testing "Find highest value with multiple maps"
(let [data [{:value 5} {:value 10} {:value 3} {:value 7}]]
(is (= (utils/find-highest-value data) 10))))
(testing "Find highest value with negative values"
(let [data [{:value -2} {:value -10} {:value -3} {:value -7}]]
(is (= (utils/find-highest-value data) -2))))
(testing "Find highest value with decimal values"
(let [data [{:value 3.5} {:value 7.2} {:value 2.9}]]
(is (= (utils/find-highest-value data) 7.2))))
(testing "Find highest value with a large data set"
(let [data (vec (for [num (range 1000)] {:value num}))]
(is (= (utils/find-highest-value data) 999)))))
(deftest find-lowest-value
(testing "Find lowest value with a single map"
(let [data [{:value 5}]]
(is (= (utils/find-lowest-value data) 5))))
(testing "Find lowest value with multiple maps"
(let [data [{:value 5} {:value 10} {:value 3} {:value 7}]]
(is (= (utils/find-lowest-value data) 3))))
(testing "Find lowest value with negative values"
(let [data [{:value -2} {:value -10} {:value -3} {:value -7}]]
(is (= (utils/find-lowest-value data) -10))))
(testing "Find lowest value with decimal values"
(let [data [{:value 3.5} {:value 7.2} {:value 2.9}]]
(is (= (utils/find-lowest-value data) 2.9))))
(testing "Find lowest value with a large data set"
(let [data (vec (for [num (range 1000)] {:value num}))]
(is (= (utils/find-lowest-value data) 0)))))
(deftest downsample-data
(testing "Downsampling is applied correctly when needed"
(let [input-data [1 2 3 4 5 6 7 8 9 10]
max-array-size 5
expected-output [1 3 5 7 9]]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling is not applied when not needed"
(let [input-data [1 2 3 4 5 6 7 8 9 10]
max-array-size 10
expected-output [1 2 3 4 5 6 7 8 9 10]]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling works with empty input data"
(let [input-data []
max-array-size 5
expected-output []]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling works with max-array-size of 1 (edge case)"
(let [input-data [1 2 3 4 5]
max-array-size 1
expected-output [1]]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling works with large input data and max-array-size (randomized test)"
(let [large-data (range 1000)
max-array-size 500
expected-output (range 0 1000 2)] ; expected-output contains every 2nd element from 0 to 1000
(is (= (utils/downsample-data large-data max-array-size) expected-output)))))
(deftest format-compact-number
(testing "Format a whole number less than 1000"
(is (= (utils/format-compact-number 567) "567")))
(testing "Format a whole number exactly 1000"
(is (= (utils/format-compact-number 1000) "1k")))
(testing "Format a whole number greater than 1000"
(is (= (utils/format-compact-number 2500) "2.5k")))
(testing "Format a decimal number less than 1000"
(is (= (utils/format-compact-number 123.45) "123.45")))
(testing "Format a decimal number exactly 1000"
(is (= (utils/format-compact-number 1000) "1k")))
(testing "Format a decimal number greater than 1000"
(is (= (utils/format-compact-number 7890.123) "7.89k")))
(testing "Format a number in millions"
(is (= (utils/format-compact-number 123456789) "123.46M")))
(testing "Format a number in billions"
(is (= (utils/format-compact-number 1234567890) "1.23B")))
(testing "Format a number in trillions"
(is (= (utils/format-compact-number 1234567890000) "1.23T"))))
(deftest calculate-x-axis-labels
(testing "Calculate x-axis labels with a small array and fewer elements"
(let [data [{:date "2023-01-01"} {:date "2023-01-02"} {:date "2023-01-03"} {:date "2023-01-04"}]]
(is (= (utils/calculate-x-axis-labels data 2) '("2023-01-01" "2023-01-03")))))
(testing "Calculate x-axis labels with a larger array and more elements"
(let [data (vec (for [i (range 10)] {:date (str "2023-01-0" (inc i))}))]
(is (= (utils/calculate-x-axis-labels data 5)
'("2023-01-01" "2023-01-03" "2023-01-05" "2023-01-07" "2023-01-09")))))
(testing "Calculate x-axis labels with a very small array"
(let [data [{:date "2023-01-01"}]]
(is (= (utils/calculate-x-axis-labels data 3) '("2023-01-01")))))
(testing "Calculate x-axis labels with a larger array and a single element"
(let [data (vec (for [i (range 10)] {:date (str "2023-01-0" (inc i))}))]
(is (= (utils/calculate-x-axis-labels data 1) '("2023-01-01"))))))
(deftest calculate-y-axis-labels
(testing "Calculate y-axis labels with positive values"
(is (= (utils/calculate-y-axis-labels 0 10 5) ["0" "10" "20" "30" "40" "50"])))
(testing "Calculate y-axis labels with negative values"
(is (= (utils/calculate-y-axis-labels -20 5 4) ["-20" "-15" "-10" "-5" "0"])))
(testing "Calculate y-axis labels with decimal step value"
(is (= (utils/calculate-y-axis-labels 2.5 0.5 4) ["2.5" "3" "3.5" "4" "4.5"])))
(testing "Calculate y-axis labels with a single step"
(is (= (utils/calculate-y-axis-labels 5 1 1) ["5" "6"])))
(testing "Calculate y-axis labels with large step value and number of steps"
(is (= (utils/calculate-y-axis-labels 100 1000 3) ["100" "1.1k" "2.1k" "3.1k"]))))
(deftest calculate-rounded-max
(testing "Calculate rounded max with a whole number"
(is (= (utils/calculate-rounded-max 100) 108)))
(testing "Calculate rounded max with a decimal number"
(is (= (utils/calculate-rounded-max 50.5) 56)))
(testing "Calculate rounded max with a number already divisible by divisor"
(is (= (utils/calculate-rounded-max 108) 116)))
(testing "Calculate rounded max with a number close to the next divisor"
(is (= (utils/calculate-rounded-max 250) 264)))
(testing "Calculate rounded max with a large number"
(is (= (utils/calculate-rounded-max 1000) 1052))))
(deftest calculate-rounded-min
(testing "Calculate rounded min with a whole number"
(is (= (utils/calculate-rounded-min 157) 100)))
(testing "Calculate rounded min with a decimal number"
(is (= (utils/calculate-rounded-min 49.8) 40)))
(testing "Calculate rounded min with a small number"
(is (= (utils/calculate-rounded-min 0.007) 0)))
(testing "Calculate rounded min with a number already rounded"
(is (= (utils/calculate-rounded-min 500) 500)))
(testing "Calculate rounded min with a negative number"
(is (= (utils/calculate-rounded-min -63) -68))))
(deftest format-currency-number-test
(testing "Format currency number with comma decimal separator"
(is (= (utils/format-currency-number 12345 :comma) "12.345,00"))
(is (= (utils/format-currency-number 12345.67 :comma) "12.345,67")))
(testing "Format currency number with dot decimal separator"
(is (= (utils/format-currency-number 12345 :dot) "12,345.00"))
(is (= (utils/format-currency-number 12345.67 :dot) "12,345.67"))))

View File

@ -1,13 +0,0 @@
(ns quo2.components.graph.wallet-graph.utils)
(defn find-highest-value
[coll]
(apply max (map :value coll)))
(defn downsample-data
[data max-array-size]
(let [data-size (count data)]
(if (> data-size max-array-size)
(let [step-size (max (/ data-size max-array-size) 1)]
(vec (take-nth step-size data)))
data)))

View File

@ -1,55 +0,0 @@
(ns quo2.components.graph.wallet-graph.utils-test
(:require [cljs.test :refer-macros [deftest is testing]]
[quo2.components.graph.wallet-graph.utils :as utils]))
(deftest find-highest-value
(testing "Find highest value with a single map"
(let [data [{:value 5}]]
(is (= (utils/find-highest-value data) 5))))
(testing "Find highest value with multiple maps"
(let [data [{:value 5} {:value 10} {:value 3} {:value 7}]]
(is (= (utils/find-highest-value data) 10))))
(testing "Find highest value with negative values"
(let [data [{:value -2} {:value -10} {:value -3} {:value -7}]]
(is (= (utils/find-highest-value data) -2))))
(testing "Find highest value with decimal values"
(let [data [{:value 3.5} {:value 7.2} {:value 2.9}]]
(is (= (utils/find-highest-value data) 7.2))))
(testing "Find highest value with a large data set"
(let [data (vec (for [num (range 1000)] {:value num}))]
(is (= (utils/find-highest-value data) 999)))))
(deftest downsample-data
(testing "Downsampling is applied correctly when needed"
(let [input-data [1 2 3 4 5 6 7 8 9 10]
max-array-size 5
expected-output [1 3 5 7 9]]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling is not applied when not needed"
(let [input-data [1 2 3 4 5 6 7 8 9 10]
max-array-size 10
expected-output [1 2 3 4 5 6 7 8 9 10]]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling works with empty input data"
(let [input-data []
max-array-size 5
expected-output []]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling works with max-array-size of 1 (edge case)"
(let [input-data [1 2 3 4 5]
max-array-size 1
expected-output [1]]
(is (= (utils/downsample-data input-data max-array-size) expected-output))))
(testing "Downsampling works with large input data and max-array-size (randomized test)"
(let [large-data (range 1000)
max-array-size 500
expected-output (range 0 1000 2)] ;; expected-output contains every 2nd element from 0 to 1000
(is (= (utils/downsample-data large-data max-array-size) expected-output)))))

View File

@ -6,7 +6,7 @@
[quo2.components.graph.wallet-graph.style :as style]
[quo2.foundations.colors :as colors]
[quo2.components.markdown.text :as text]
[quo2.components.graph.wallet-graph.utils :as utils]))
[quo2.components.graph.utils :as utils]))
(defn- max-data-points
[time-frame]

View File

@ -124,7 +124,8 @@
quo2.components.wallet.progress-bar.view
quo2.components.wallet.summary-info.view
quo2.components.wallet.token-input.view
quo2.components.wallet.wallet-overview.view))
quo2.components.wallet.wallet-overview.view
[quo2.components.graph.interactive-graph.view :as interactive-graph]))
(def separator quo2.components.common.separator.view/separator)
@ -205,6 +206,7 @@
(def empty-state quo2.components.empty-state.empty-state.view/empty-state)
;;;; Graph
(def interactive-graph quo2.components.graph.interactive-graph.view/view)
(def wallet-graph quo2.components.graph.wallet-graph.view/view)
;;;; Header

View File

@ -123,6 +123,7 @@
;;;;Blur
(def white-70-blur (alpha white 0.7))
(def white-70-blur-opaque (alpha-opaque white 0.7))
(def neutral-80-opa-1-blur (alpha "#192438" 0.1))
(def neutral-5-opa-70-blur (alpha neutral-5 0.7))
(def neutral-10-opa-10-blur (alpha neutral-10 0.1))

View File

@ -0,0 +1,152 @@
(ns status-im2.contexts.quo-preview.graph.interactive-graph
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]
[quo2.components.graph.utils :as utils]
[goog.string :as gstring]))
(def weekly-data
[{:value 123
:date "Sun"}
{:value 160
:date "Mon"}
{:value 435
:date "Tue"}
{:value 2345
:date "Wed"}
{:value 1444
:date "Thu"}
{:value 931
:date "Fri"}
{:value 1200
:date "Sat"}])
(defn generate-crypto-token-prices
[num-elements volatility]
(loop [n num-elements
prices []
prev-price (rand-int 100000)
volatility volatility
current-day (rand-int 31) ; Start with a random day
months ["Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"]
current-month (rand-nth months)] ; Start with a random month
(if (zero? n)
(vec (reverse prices))
(let [fluctuation (* prev-price volatility)
random-delta (- (rand fluctuation) (/ fluctuation 2))
new-price (max 1 (+ prev-price random-delta))
new-day (if (= current-day 1) 31 (dec current-day)) ; Decrease the day
new-month (if (= current-day 1)
(let [prev-month-index (dec (.indexOf months current-month))]
(if (>= prev-month-index 0)
(nth months prev-month-index)
(nth months (dec (count months)))))
current-month)
new-prices (conj prices
{:value new-price
:date (str new-day " " new-month)})]
(recur (dec n) new-prices new-price volatility new-day months new-month)))))
(def descriptor
[{:label "State:"
:key :state
:type :select
:options [{:key :positive
:value "Positive"}
{:key :negative
:value "Negative"}]}
{:label "Time frame:"
:key :time-frame
:type :select
:options [{:key :empty
:value "Empty"}
{:key :1-week
:value "1 Week"}
{:key :1-month
:value "1 Month"}
{:key :3-months
:value "3 Months"}
{:key :1-year
:value "1 Year"}
{:key :all-time
:value "All time (500 years data)"}]}
{:label "Reference value:"
:key :reference-value
:type :number}
{:label "Reference prefix:"
:key :reference-prefix
:type :text}
{:label "Reference decimal separator:"
:key :decimal-separator
:type :select
:options [{:key :dot
:value "Dot (.)"}
{:key :comma
:value "Comma (,)"}]}
(preview/customization-color-option)])
(defn generate-data
[time-frame]
(let [data-points (case time-frame
:empty 0
:1-week 7
:1-month 30
:3-months 90
:1-year 365
(* 365 500))
volatility (case time-frame
:empty 0
:1-week 2
:1-month 1
:3-months 0.5
:1-year 0.05
0.005)]
(if (= time-frame :1-week)
weekly-data
(generate-crypto-token-prices data-points volatility))))
(defn f-view
[state]
(fn []
(rn/use-effect (fn []
(let [time-frame (:time-frame @state)
data (generate-data time-frame)
highest-value (utils/find-highest-value data)
lowest-value (utils/find-lowest-value data)
average-value (gstring/format "%.2f" (/ (+ highest-value lowest-value) 2))]
(swap! state assoc :data data :reference-value average-value)))
[(:time-frame @state)])
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[quo/interactive-graph
{:data (:data @state)
:state (:state @state)
:reference-value (:reference-value @state)
:reference-prefix (:reference-prefix @state)
:customization-color (:customization-color @state)
:decimal-separator (:decimal-separator @state)}]]]))
(defn view
[]
(let [data (generate-data :1-week)
highest-value (utils/find-highest-value data)
lowest-value (utils/find-lowest-value data)
average-value (gstring/format "%.2f" (/ (+ highest-value lowest-value) 2))
state (reagent/atom {:state :positive
:time-frame :1-week
:customization-color :blue
:reference-value average-value
:reference-prefix "$"
:decimal-separator :dot
:data data})]
[rn/scroll-view
{:style
{:background-color (colors/theme-colors
colors/white
colors/neutral-95)
:flex 1}}
[:f> f-view state]]))

View File

@ -27,6 +27,7 @@
[status-im2.contexts.quo-preview.calendar.calendar-year :as calendar-year]
[status-im2.contexts.quo-preview.browser.browser-input :as browser-input]
[status-im2.contexts.quo-preview.code.snippet :as code-snippet]
[status-im2.contexts.quo-preview.graph.interactive-graph :as interactive-graph]
[status-im2.contexts.quo-preview.graph.wallet-graph :as wallet-graph]
[status-im2.contexts.quo-preview.colors.color-picker :as color-picker]
[status-im2.contexts.quo-preview.community.community-card-view :as community-card]
@ -212,7 +213,11 @@
:component empty-state/view}]
:gradient [{:name :gradient-cover
:component gradient-cover/view}]
:graph [{:name :wallet-graph
:graph [{:name :interactive-graph
:options {:topBar {:visible true}}
:component interactive-graph/view}
{:name :wallet-graph
:options {:topBar {:visible true}}
:component wallet-graph/view}]
:info [{:name :info-message
:component info-message/view}

View File

@ -8854,10 +8854,9 @@ react-native-gesture-handler@2.6.1:
lodash "^4.17.21"
prop-types "^15.7.2"
react-native-gifted-charts@^1.3.2:
"react-native-gifted-charts@git+https://github.com/status-im/react-native-gifted-charts.git#refs/tags/1.3.2-status.1":
version "1.3.2"
resolved "https://registry.yarnpkg.com/react-native-gifted-charts/-/react-native-gifted-charts-1.3.2.tgz#9e2d054b8571026eec5d6a38a7a424da065df726"
integrity sha512-MHWE0A772w57ZKz/r7cWjBFwvRzY3kWDv+PaMBACzNdL13paLl/uOHsKzPP1lZ3Hnj3iICEo7u4aqo0TQ3mGLQ==
resolved "git+https://github.com/status-im/react-native-gifted-charts.git#6c0bd2e75afe67d0423386247049257a0a0edda1"
dependencies:
react-native-linear-gradient "^2.7.3"
react-native-svg "^13.9.0"