Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc3e398061 | ||
|
|
c81dd8e3e3 | ||
|
|
24f4c4a07e | ||
|
|
98762c74f1 | ||
|
|
f3aeddb53a | ||
|
|
f5fcc9f45e | ||
|
|
f549f9949c | ||
|
|
9aa9dc1b4c | ||
|
|
61974dae4d | ||
|
|
8b3e639abd | ||
|
|
7c901fa045 | ||
|
|
8a12ad3510 | ||
|
|
c8044cd2f2 | ||
|
|
6872d1a857 | ||
|
|
98d4969ca5 | ||
|
|
5412092ca1 | ||
|
|
a8695116e2 | ||
|
|
76773a4165 | ||
|
|
32fc7b14e8 | ||
|
|
82a8f9f44d | ||
|
|
8df72d0c29 | ||
|
|
794cd57961 | ||
|
|
6bc29088ab |
@@ -36,6 +36,12 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Fetch') {
|
||||
steps { script {
|
||||
@@ -52,7 +58,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -54,6 +54,12 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
steps { script {
|
||||
@@ -79,7 +85,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
@@ -51,7 +56,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -128,3 +128,19 @@ Status-mobile uses `shadow-cljs` for hot reloading changes and uses its own [rel
|
||||
|
||||
### Solution
|
||||
Open react native's [In-App Developer Menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) and press "Disable Fast Refresh" or "Disable Hot Reloading"
|
||||
|
||||
# App crashing after running `make run-ios`
|
||||
|
||||
### Cause
|
||||
It's possible that installing XCode from a `.xip` file might cause XCode to act funny
|
||||
Since it's not installed from the App Store, Or you might be missing a Rosetta installation.
|
||||
|
||||
[Reference/Similar issue](https://github.com/expo/expo-cli/issues/3197)
|
||||
|
||||
You might see something like this after running `make run-ios`:
|
||||
```
|
||||
Underlying error (domain=FBSOpenApplicationServiceErrorDomain, code=1):
|
||||
```
|
||||
### Solution
|
||||
Run `softwareupdate --install-rosetta --agree-to-license`
|
||||
to accept XCode's license and install Rosetta.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 707 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[legacy.status-im.browser.core :as browser]
|
||||
[legacy.status-im.browser.webview-ref :as webview-ref]
|
||||
[legacy.status-im.qr-scanner.core :as qr-scanner]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.connectivity.view :as connectivity]
|
||||
@@ -105,9 +104,7 @@
|
||||
(if empty-tab
|
||||
[react/touchable-highlight
|
||||
{:accessibility-label :universal-qr-scanner
|
||||
:on-press #(re-frame/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:handler ::qr-scanner/on-scan-success}])}
|
||||
:on-press #(re-frame/dispatch [:open-modal :shell-qr-reader])}
|
||||
[icons/icon :main-icons/qr {:color colors/black}]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
(ns legacy.status-im.ui.screens.communities.invite
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.communities.core :as communities]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -49,18 +48,35 @@
|
||||
contacts-selected (reagent/atom #{})
|
||||
{:keys [invite?]} (rf/sub [:get-screen-params])]
|
||||
(fn []
|
||||
(let [contacts-data (rf/sub [:contacts/active])
|
||||
{:keys [permissions
|
||||
can-manage-users?]}
|
||||
(let [theme (quo.theme/use-theme)
|
||||
contacts-data (rf/sub [:contacts/active])
|
||||
{community-id :id
|
||||
:keys [permissions
|
||||
can-manage-users?]}
|
||||
(rf/sub [:communities/edited-community])
|
||||
selected @contacts-selected
|
||||
selected-contacts-count (count selected)
|
||||
contacts (map (fn [{:keys [public-key] :as contact}]
|
||||
(assoc contact :active (contains? selected public-key)))
|
||||
contacts-data)
|
||||
;; no-membership communities can only be shared
|
||||
can-invite? (and can-manage-users?
|
||||
invite?
|
||||
(not= (:access permissions) constants/community-no-membership-access))]
|
||||
(not= (:access permissions) constants/community-no-membership-access))
|
||||
on-press-share-community (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:communities/share-community-confirmation-pressed
|
||||
selected community-id])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:type :positive
|
||||
:theme theme
|
||||
:text (if (= 1 selected-contacts-count)
|
||||
(i18n/label :t/one-user-was-invited)
|
||||
(i18n/label
|
||||
:t/n-users-were-invited
|
||||
{:count selected-contacts-count}))}]))
|
||||
[community-id selected selected-contacts-count theme])]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title (i18n/label (if can-invite?
|
||||
@@ -81,11 +97,8 @@
|
||||
:center
|
||||
[quo/button
|
||||
{:disabled (and (string/blank? @user-pk)
|
||||
(zero? (count selected)))
|
||||
(zero? selected-contacts-count))
|
||||
:accessibility-label :share-community-link
|
||||
:type :secondary
|
||||
:on-press #(debounce/throttle-and-dispatch
|
||||
[::communities/share-community-confirmation-pressed @user-pk
|
||||
selected]
|
||||
3000)}
|
||||
:on-press on-press-share-community}
|
||||
(i18n/label (if can-invite? :t/invite :t/share))]}]]))))
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
(ns quo.components.community.community-detail-token-gating.component-spec
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Community Detail Token Gating Component"
|
||||
(h/test "render with member permissions"
|
||||
(h/render
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 2
|
||||
:role-text "Member"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "ETH"
|
||||
:sufficient? true
|
||||
:collectible? false
|
||||
:amount 0.8
|
||||
:img-src nil}]
|
||||
[{:symbol "ETH"
|
||||
:sufficient? false
|
||||
:collectible? false
|
||||
:amount 1
|
||||
:img-src nil}
|
||||
{:symbol "STT"
|
||||
:sufficient? false
|
||||
:collectible? false
|
||||
:amount 10
|
||||
:img-src nil}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Member"}))
|
||||
(h/is-truthy (h/get-by-text "0.8 ETH"))
|
||||
(h/is-truthy (h/get-by-text "1 ETH"))
|
||||
(h/is-truthy (h/get-by-text "10 STT")))
|
||||
|
||||
(h/test "render with admin permissions"
|
||||
(h/render
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 1
|
||||
:role-text "Admin"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "ETH"
|
||||
:sufficient? true
|
||||
:collectible? false
|
||||
:amount 2
|
||||
:img-src nil}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Admin"}))
|
||||
(h/is-truthy (h/get-by-text "2 ETH")))
|
||||
|
||||
(h/test "render with token master permissions"
|
||||
(h/render-with-theme-provider
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 5
|
||||
:role-text "Token Master"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "TMANI "
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:img-src {:uri "mock-image"}}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Token Master"}))
|
||||
(h/is-truthy (h/get-by-text "TMANI")))
|
||||
|
||||
(h/test "render with token owner permissions"
|
||||
(h/render-with-theme-provider
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 6
|
||||
:role-text "Token Owner"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "TOANI"
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:img-src {:uri "mock-image"}}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Token Owner"}))
|
||||
(h/is-truthy (h/get-by-text "TOANI"))))
|
||||
@@ -0,0 +1,20 @@
|
||||
(ns quo.components.community.community-detail-token-gating.style)
|
||||
|
||||
(def container
|
||||
{:padding-horizontal 20
|
||||
:margin-vertical -4})
|
||||
|
||||
(defn token-row
|
||||
[first?]
|
||||
{:flex-direction :row
|
||||
:margin-top (if first? 8 4)
|
||||
:row-gap 10
|
||||
:column-gap 8
|
||||
:flex-wrap :wrap
|
||||
:margin-bottom 16})
|
||||
|
||||
(def divider
|
||||
{:padding-left 0
|
||||
:height 28
|
||||
:padding-top 0
|
||||
:align-items :flex-start})
|
||||
@@ -0,0 +1,74 @@
|
||||
(ns quo.components.community.community-detail-token-gating.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo.components.community.community-detail-token-gating.style :as style]
|
||||
[quo.components.dividers.divider-label.view :as divider-label]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.components.tags.collectible-tag.view :as collectible-tag]
|
||||
[quo.components.tags.token-tag.view :as token-tag]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn- token-view
|
||||
[{:keys [collectible? img-src amount sufficient?] :as token}]
|
||||
(let [token-symbol (:symbol token)]
|
||||
(if collectible?
|
||||
[collectible-tag/view
|
||||
{:collectible-name token-symbol
|
||||
:size :size-24
|
||||
:collectible-img-src img-src
|
||||
:options (when sufficient?
|
||||
:hold)}]
|
||||
[token-tag/view
|
||||
{:token-symbol token-symbol
|
||||
:size :size-24
|
||||
:token-value amount
|
||||
:token-img-src img-src
|
||||
:options (when sufficient? :hold)}])))
|
||||
|
||||
(defn- tokens-row
|
||||
[{:keys [tokens divider? first?]}]
|
||||
[:<>
|
||||
[rn/view
|
||||
{:style (style/token-row first?)}
|
||||
(map-indexed (fn [token-index token]
|
||||
^{:key (str "token-" token-index)}
|
||||
[token-view token])
|
||||
tokens)]
|
||||
(when-not divider?
|
||||
[divider-label/view
|
||||
{:container-style style/divider}
|
||||
[text/text
|
||||
{:size :label
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
(string/lower-case (i18n/label :t/or))]])])
|
||||
|
||||
(defn- role-view
|
||||
[{:keys [role tokens satisfied? role-text]}]
|
||||
(when (seq tokens)
|
||||
^{:key (str "role-" role)}
|
||||
[:<>
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:margin-top 4}}
|
||||
(if satisfied?
|
||||
(i18n/label :t/you-eligible-to-join-as {:role role-text})
|
||||
(i18n/label :t/you-not-eligible-to-join-as {:role role-text}))]
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style {:margin-bottom 8}}
|
||||
(i18n/label (if satisfied? :t/you-hodl :t/you-must-hold))]
|
||||
|
||||
(map-indexed (fn [index tokens-item]
|
||||
^{:key (str role "-tokens-" index)}
|
||||
[tokens-row
|
||||
{:tokens tokens-item
|
||||
:first? (zero? index)
|
||||
:divider? (= index (dec (count tokens)))}])
|
||||
tokens)]))
|
||||
|
||||
(defn view
|
||||
[{:keys [permissions]}]
|
||||
[rn/view {:style style/container}
|
||||
(map role-view permissions)])
|
||||
@@ -102,7 +102,7 @@
|
||||
:right 8})
|
||||
|
||||
(def token-tag-spacing
|
||||
{:margin-top 10
|
||||
{:padding-top 10
|
||||
:margin-right 8})
|
||||
|
||||
(defn token-row
|
||||
@@ -117,11 +117,12 @@
|
||||
(defn token-row-or-text
|
||||
[padding? theme]
|
||||
(merge
|
||||
{:margin-top 4
|
||||
:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40
|
||||
theme)}
|
||||
{:padding-top 4
|
||||
:margin-bottom -2
|
||||
:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40
|
||||
theme)}
|
||||
(when padding?
|
||||
{:padding-left 12})))
|
||||
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
[:blur? {:optional true} [:maybe :boolean]]
|
||||
[:collectible-img-src :schema.common/image-source]
|
||||
[:collectible-name :string]
|
||||
[:collectible-id :string]]]]
|
||||
[:collectible-id {:optional true} [:maybe :string]]]]]
|
||||
:any])
|
||||
|
||||
@@ -41,12 +41,13 @@
|
||||
:weight :medium
|
||||
:style (style/label theme)}
|
||||
collectible-name]
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:margin-left 5
|
||||
:style (style/label theme)}
|
||||
collectible-id]]]
|
||||
(when collectible-id
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:margin-left 5
|
||||
:style (style/label theme)}
|
||||
collectible-id])]]
|
||||
(when options
|
||||
[rn/view {:style (style/options-icon size)}
|
||||
[icons/icon (if (= options :hold) :i/hold :i/add-token)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
(ns quo.components.wallet.network-link.helpers)
|
||||
|
||||
(def ^:private central-figure-width 63)
|
||||
|
||||
(defn calculate-side-lines-path-1x
|
||||
"Calculates the `d` attribute for the side lines based on the SVG width."
|
||||
[width]
|
||||
(let [side-offset (/ (- width central-figure-width) 2)]
|
||||
{:left (str "M0 57 L" side-offset " 57")
|
||||
:right (str "M" (+ side-offset central-figure-width) " 1 L" width " 1")}))
|
||||
|
||||
(defn calculate-transform
|
||||
"Calculates the transform attribute for the central figure based on the SVG width."
|
||||
[width]
|
||||
(let [translate-x (/ (- width central-figure-width) 2)]
|
||||
(str "translate(" translate-x " 0)")))
|
||||
|
||||
(defn calculate-side-lines-path-2x
|
||||
"Calculates the `d` attribute for the side lines based on the SVG width."
|
||||
[width]
|
||||
(let [side-offset (/ (- width central-figure-width) 2)]
|
||||
{:left (str "M0 113 L" side-offset " 113")
|
||||
:right (str "M" (+ side-offset central-figure-width) " 1 L" width " 1")}))
|
||||
@@ -0,0 +1,34 @@
|
||||
(ns quo.components.wallet.network-link.style)
|
||||
|
||||
(def left-circle-container
|
||||
{:position :absolute
|
||||
:left -3})
|
||||
|
||||
(def right-circle-container
|
||||
{:position :absolute
|
||||
:right -3})
|
||||
|
||||
(def bottom-left-circle-container
|
||||
{:position :absolute
|
||||
:bottom -3
|
||||
:left -3})
|
||||
|
||||
(def top-right-circle-container
|
||||
{:position :absolute
|
||||
:top -3
|
||||
:right -3})
|
||||
|
||||
(def link-linear-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 10})
|
||||
|
||||
(def link-1x-container
|
||||
{:flex 1
|
||||
:height 58
|
||||
:justify-content :center})
|
||||
|
||||
(def link-2x-container
|
||||
{:flex 1
|
||||
:height 114
|
||||
:justify-content :center})
|
||||
@@ -1,82 +1,151 @@
|
||||
(ns quo.components.wallet.network-link.view
|
||||
(:require
|
||||
[oops.core :refer [oget]]
|
||||
[quo.components.wallet.network-link.helpers :as helpers]
|
||||
[quo.components.wallet.network-link.schema :as component-schema]
|
||||
[quo.components.wallet.network-link.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.svg :as svg]
|
||||
[reagent.core :as reagent]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- circle
|
||||
[fill stroke]
|
||||
[svg/svg
|
||||
{:height "8"
|
||||
:width "8"}
|
||||
[svg/circle
|
||||
{:cx "4"
|
||||
:cy "4"
|
||||
:r "3.5"
|
||||
:fill fill
|
||||
:stroke stroke
|
||||
:strokeWidth "1"}]])
|
||||
|
||||
(defn- line
|
||||
[stroke width]
|
||||
[svg/svg
|
||||
{:height "10"
|
||||
:width "100%"
|
||||
:view-box (str "0 0 " width " 10")}
|
||||
[svg/path
|
||||
{:d (str "M0,5 L" width ",5")
|
||||
:stroke stroke
|
||||
:stroke-width "1"}]])
|
||||
|
||||
(defn link-linear
|
||||
[{:keys [source theme]}]
|
||||
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "10" :fill :none}
|
||||
[svg/path {:stroke (colors/resolve-color source theme) :d "M68 5H5"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]])
|
||||
[]
|
||||
(let [container-width (reagent/atom 100)]
|
||||
(fn [{:keys [source theme]}]
|
||||
(let [stroke-color (colors/resolve-color source theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)]
|
||||
[rn/view
|
||||
{:style style/link-linear-container
|
||||
:on-layout (fn [e]
|
||||
(reset! container-width
|
||||
(oget e :nativeEvent :layout :width)))}
|
||||
[line stroke-color @container-width]
|
||||
[rn/view {:style style/left-circle-container}
|
||||
[circle fill-color stroke-color]]
|
||||
[rn/view {:style style/right-circle-container}
|
||||
[circle fill-color stroke-color]]]))))
|
||||
|
||||
(defn link-1x
|
||||
[{:keys [source destination theme]}]
|
||||
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "66" :fill :none}
|
||||
[svg/path
|
||||
{:stroke "url(#gradient)" :d "M68 5h-9.364c-11.046 0-20 8.954-20 20v16c0 11.046-8.955 20-20 20H5"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color destination theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "61"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient" :x1 "72.271" :x2 "82.385" :y1 "5" :y2 "34.155" :gradientUnits "userSpaceOnUse"}
|
||||
[svg/stop {:stopColor (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stopColor (colors/resolve-color source theme)}]]]])
|
||||
[]
|
||||
(let [container-width (reagent/atom 100)
|
||||
stroke-color "url(#gradient)"]
|
||||
(fn [{:keys [source destination theme]}]
|
||||
(let [source-color (colors/resolve-color source theme)
|
||||
destination-color (colors/resolve-color destination theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
view-box (str "0 0 " @container-width " 58")
|
||||
side-lines-path (helpers/calculate-side-lines-path-1x @container-width)
|
||||
central-transform (helpers/calculate-transform @container-width)]
|
||||
[rn/view
|
||||
{:style style/link-1x-container
|
||||
:on-layout (fn [e]
|
||||
(reset! container-width
|
||||
(oget e :nativeEvent :layout :width)))}
|
||||
[svg/svg
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:height "100%"
|
||||
:width "100%"
|
||||
:view-box view-box
|
||||
:fill :none}
|
||||
[svg/path
|
||||
{:d (:left side-lines-path)
|
||||
:stroke source-color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M63 1L53.6356 1C42.5899 1 33.6356 9.9543 33.6356 21L33.6356 37C33.6356 48.0457 24.6813 57 13.6356 57L2.85889e-05 57"
|
||||
:transform central-transform
|
||||
:stroke stroke-color}]
|
||||
[svg/path
|
||||
{:d (:right side-lines-path)
|
||||
:stroke destination-color}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.271"
|
||||
:x2 "82.385"
|
||||
:y1 "5"
|
||||
:y2 "34.155"
|
||||
:gradient-units "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]]
|
||||
[rn/view {:style style/bottom-left-circle-container}
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/top-right-circle-container}
|
||||
[circle fill-color destination-color]]]))))
|
||||
|
||||
(defn link-2x
|
||||
[{:keys [source destination theme]}]
|
||||
[svg/svg
|
||||
{:width "73" :height "122" :viewBox "0 0 73 122" :fill "none" :xmlns "http://www.w3.org/2000/svg"}
|
||||
[svg/path
|
||||
{:d
|
||||
"M67.9999 5L58.6356 5C47.5899 5 38.6356 13.9543 38.6356 25L38.6356 97C38.6356 108.046 29.6813 117 18.6356 117L5.00006 117"
|
||||
:stroke "url(#gradient)"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color destination theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "117"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.2711"
|
||||
:y1 "5.00001"
|
||||
:x2 "102.867"
|
||||
:y2 "49.0993"
|
||||
:gradientUnits "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]])
|
||||
[]
|
||||
(let [container-width (reagent/atom 100)
|
||||
stroke-color "url(#gradient)"]
|
||||
(fn [{:keys [source destination theme]}]
|
||||
(let [source-color (colors/resolve-color source theme)
|
||||
destination-color (colors/resolve-color destination theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
view-box (str "0 0 " @container-width " 114")
|
||||
side-lines-path (helpers/calculate-side-lines-path-2x @container-width)
|
||||
central-transform (helpers/calculate-transform @container-width)]
|
||||
[rn/view
|
||||
{:style style/link-2x-container
|
||||
:on-layout #(reset! container-width
|
||||
(oget % :nativeEvent :layout :width))}
|
||||
[svg/svg
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:height "100%"
|
||||
:width "100%"
|
||||
:view-box view-box
|
||||
:fill :none}
|
||||
[svg/path
|
||||
{:d (:left side-lines-path)
|
||||
:stroke source-color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M62.9999 1L53.6356 1C42.5899 1 33.6356 9.9543 33.6356 21L33.6356 93C33.6356 104.046 24.6813 113 13.6356 113L5.71778e-05 113"
|
||||
:transform central-transform
|
||||
:stroke stroke-color}]
|
||||
[svg/path
|
||||
{:d (:right side-lines-path)
|
||||
:stroke destination-color}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.2711"
|
||||
:y1 "5.00001"
|
||||
:x2 "102.867"
|
||||
:y2 "49.0993"
|
||||
:gradient-units "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]]
|
||||
[rn/view {:style style/bottom-left-circle-container}
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/top-right-circle-container}
|
||||
[circle fill-color destination-color]]]))))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [shape container-style] :as props}]
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
quo.components.community.channel-action.view
|
||||
quo.components.community.channel-actions.view
|
||||
quo.components.community.community-card-view
|
||||
quo.components.community.community-detail-token-gating.view
|
||||
quo.components.community.community-list-view
|
||||
quo.components.community.community-stat.view
|
||||
quo.components.community.community-view
|
||||
@@ -224,6 +225,7 @@
|
||||
|
||||
;;;; Community
|
||||
(def community-card-view-item quo.components.community.community-card-view/view)
|
||||
(def community-detail-token-gating quo.components.community.community-detail-token-gating.view/view)
|
||||
(def communities-membership-list-item
|
||||
quo.components.community.community-list-view/communities-membership-list-item)
|
||||
(def community-stats-column quo.components.community.community-view/community-stats-column)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
quo.components.calendar.calendar.component-spec
|
||||
quo.components.calendar.calendar.month-picker.component-spec
|
||||
quo.components.colors.color-picker.component-spec
|
||||
quo.components.community.community-detail-token-gating.component-spec
|
||||
quo.components.community.community-stat.component-spec
|
||||
quo.components.counter.collectible-counter.component-spec
|
||||
quo.components.counter.counter.component-spec
|
||||
|
||||
@@ -226,7 +226,3 @@
|
||||
(defn open-url [link] (.openURL ^js linking link))
|
||||
|
||||
(def set-status-bar-style react-native/StatusBar.setBarStyle)
|
||||
|
||||
(defn sharing
|
||||
[content]
|
||||
(.share (.-Share ^js react-native) (clj->js content)))
|
||||
|
||||
@@ -4,9 +4,5 @@
|
||||
|
||||
(defn open
|
||||
([options]
|
||||
(open options #() #()))
|
||||
([options on-success on-error]
|
||||
(-> ^js react-native-share
|
||||
(.open (clj->js options))
|
||||
(.then on-success)
|
||||
(.catch on-error))))
|
||||
(.open (clj->js options)))))
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[react-native.cameraroll :as cameraroll]
|
||||
[react-native.fs :as fs]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def config
|
||||
@@ -15,10 +14,12 @@
|
||||
(blob/fetch uri
|
||||
config
|
||||
(fn [downloaded-url]
|
||||
(share/open {:url (str (when platform/android? "file://") downloaded-url)
|
||||
:isNewTask true}
|
||||
#(fs/unlink downloaded-url)
|
||||
#(fs/unlink downloaded-url))))))
|
||||
(rf/dispatch [:open-share
|
||||
{:options {:url (str (when platform/android? "file://")
|
||||
downloaded-url)
|
||||
:isNewTask true}
|
||||
:on-success #(fs/unlink downloaded-url)
|
||||
:on-error #(fs/unlink downloaded-url)}])))))
|
||||
|
||||
(rf/reg-fx :effects.lightbox/save-image-to-gallery
|
||||
(fn [[uri on-success]]
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
ens?
|
||||
(assoc-in [:route-params :ens-name] fragment)
|
||||
|
||||
(and (or (= handler :community) (= handler :community-chat)) compressed-key?)
|
||||
(and (= handler :community) compressed-key?)
|
||||
(assoc-in [:route-params :community-id] fragment)
|
||||
|
||||
(and equal-end-of-base64url (= handler :community) (:community-data route-params))
|
||||
@@ -119,6 +119,13 @@
|
||||
(re-find constants/regx-starts-with-uuid (:community-data route-params)))
|
||||
(assoc-in [:route-params :community-channel-id] (:community-data route-params))
|
||||
|
||||
(and fragment
|
||||
(= handler :community-chat)
|
||||
(:community-data route-params)
|
||||
(string? (:community-data route-params))
|
||||
(not (re-find constants/regx-starts-with-uuid (:community-data route-params))))
|
||||
(assoc-in [:route-params :community-encoded-data?] true)
|
||||
|
||||
(and equal-end-of-base64url (= handler :user) (:user-data route-params))
|
||||
(update-in [:route-params :user-data] #(str % equal-end-of-base64url))
|
||||
|
||||
@@ -203,6 +210,10 @@
|
||||
(cb {:type :private-chat
|
||||
:error :invalid-chat-id})))))
|
||||
|
||||
(defn parse-shared-url
|
||||
[uri]
|
||||
(re-frame/dispatch [:shared-urls/parse-shared-url uri]))
|
||||
|
||||
(defn match-community-channel-async
|
||||
[{:keys [community-channel-id community-id]} cb]
|
||||
(if (validators/valid-compressed-key? community-id)
|
||||
@@ -307,9 +318,10 @@
|
||||
(and (= handler :community-chat) (:community-channel-id route-params) (:community-id route-params))
|
||||
(match-community-channel-async route-params cb)
|
||||
|
||||
(and (= handler :community-chat) (:community-id route-params))
|
||||
(cb {:type :community
|
||||
:community-id (:community-id route-params)})
|
||||
(and (= handler :community-chat)
|
||||
(:community-encoded-data? route-params)
|
||||
(:community-id route-params))
|
||||
(parse-shared-url uri)
|
||||
|
||||
;; NOTE: removed in `match-uri`, might need this in the future
|
||||
(= handler :wallet-account)
|
||||
|
||||
@@ -42,12 +42,14 @@
|
||||
[:community-chat
|
||||
{:community-data
|
||||
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
|
||||
:community-encoded-data? true
|
||||
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
|
||||
|
||||
"status-app://cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
|
||||
[:community-chat
|
||||
{:community-data
|
||||
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
|
||||
:community-encoded-data? true
|
||||
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
|
||||
|
||||
"https://status.app/cc/c432709e-fc73-440d-bb67-cb3a0929dfda#zQ3shZL6dXiFCbDyxnXxwQa9v8QFC2q19subFtyxd7kVszMVo"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
(ns status-im.common.shared-urls.data-store
|
||||
(:require
|
||||
[clojure.set :as set]))
|
||||
|
||||
(defn <-rpc
|
||||
[{:keys [community channel contact]}]
|
||||
{:community (set/rename-keys
|
||||
community
|
||||
{:communityId :community-id
|
||||
:displayName :display-name
|
||||
:membersCount :members-count
|
||||
:tagIndices :tag-indices})
|
||||
:channel (set/rename-keys
|
||||
channel
|
||||
{:displayName :display-name
|
||||
:channelUuid :channel-uuid})
|
||||
:contact (set/rename-keys
|
||||
contact
|
||||
{:displayName :display-name
|
||||
:publicKey :public-key})})
|
||||
@@ -0,0 +1,33 @@
|
||||
(ns status-im.common.shared-urls.events
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.shared-urls.data-store :as data-store]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn parse-shared-url-success
|
||||
[url response]
|
||||
(let [parsed-data (data-store/<-rpc response)
|
||||
cb #(rf/dispatch [:universal-links/match-value url %])]
|
||||
(cond
|
||||
(:channel parsed-data)
|
||||
(cb {:type :community-chat
|
||||
:chat-id (str (get-in parsed-data [:community :community-id])
|
||||
(get-in parsed-data [:channel :channel-uuid]))
|
||||
:community-id (get-in parsed-data [:community :community-id])})
|
||||
|
||||
(:community parsed-data)
|
||||
(cb {:type :community :community-id (get-in parsed-data [:community :community-id])}))))
|
||||
|
||||
(defn parse-shared-url
|
||||
[_ [uri]]
|
||||
(let [url (string/replace uri #"status-app:/" "https://status.app")]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_parseSharedURL"
|
||||
:params [url]
|
||||
:on-success #(parse-shared-url-success url %)
|
||||
:on-error (fn [err]
|
||||
(log/error "failed to parse shared url" {:error err :url url}))}]}))
|
||||
|
||||
(re-frame/reg-event-fx :shared-urls/parse-shared-url parse-shared-url)
|
||||
@@ -18,8 +18,8 @@
|
||||
[rn/view
|
||||
[quo/text
|
||||
{:accessibility-label :sync-code-generated
|
||||
:weight :bold
|
||||
:size :heading-1
|
||||
:weight :semi-bold
|
||||
:size :heading-2
|
||||
:style {:margin-bottom 4}}
|
||||
(i18n/label :t/enter-password)]
|
||||
[rn/view
|
||||
|
||||
@@ -116,14 +116,16 @@
|
||||
(log/debug "universal-links: no url")))
|
||||
|
||||
(rf/defn on-handle
|
||||
{:events [::match-value]}
|
||||
[cofx url {:keys [type chat-id] :as data}]
|
||||
{:events [:universal-links/match-value]}
|
||||
[cofx url {:keys [type chat-id community-id] :as data}]
|
||||
(case type
|
||||
:group-chat (handle-group-chat cofx data)
|
||||
:private-chat (handle-private-chat cofx data)
|
||||
:community-requests (handle-community-requests cofx data)
|
||||
:community (communities.events/navigate-to-serialized-community cofx data)
|
||||
:community-chat {:dispatch [:communities/navigate-to-community-chat chat-id :pop-to-root]}
|
||||
:community (communities.events/navigate-to-community-overview cofx [community-id])
|
||||
:community-chat (communities.events/navigate-to-community-chat cofx
|
||||
[chat-id :pop-to-root
|
||||
community-id])
|
||||
:contact (handle-view-profile cofx data)
|
||||
:browser (handle-browse cofx data)
|
||||
:eip681 (handle-eip681 cofx data)
|
||||
@@ -136,7 +138,7 @@
|
||||
{:router/handle-uri {:chain (chain/chain-keyword db)
|
||||
:chats (:chats db)
|
||||
:uri url
|
||||
:cb #(re-frame/dispatch [::match-value url %])}})
|
||||
:cb #(re-frame/dispatch [:universal-links/match-value url %])}})
|
||||
|
||||
(rf/defn store-url-for-later
|
||||
"Store the url in the db to be processed on login"
|
||||
|
||||
@@ -448,6 +448,8 @@
|
||||
(def ^:const optimism-short-name "opt")
|
||||
(def ^:const arbitrum-short-name "arb1")
|
||||
|
||||
(def ^:const default-multichain-address-prefix "eth:opt:arb1:")
|
||||
|
||||
(def ^:const mainnet-abbreviated-name "Eth.")
|
||||
(def ^:const optimism-abbreviated-name "Opt.")
|
||||
(def ^:const arbitrum-abbreviated-name "Arb1.")
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.share :as share]
|
||||
[status-im.common.contact-list-item.view :as contact-list-item]
|
||||
[status-im.common.contact-list.view :as contact-list]
|
||||
[status-im.common.home.actions.view :as actions]
|
||||
@@ -122,7 +121,7 @@
|
||||
[:show-bottom-sheet {:content chat.actions.view/new-chat}])
|
||||
:accessibility-label :new-chat-button}
|
||||
:card-props
|
||||
{:on-press #(share/open {:url profile-link})
|
||||
{:on-press #(rf/dispatch [:open-share {:options {:url profile-link}}])
|
||||
:banner (resources/get-image :invite-friends)
|
||||
:title (i18n/label :t/invite-friends-to-status)
|
||||
:description (i18n/label :t/share-invite-link)}})
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
(defn pinned-message
|
||||
[{:keys [from quoted-message timestamp-str]}]
|
||||
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])
|
||||
one-to-one-chat? (rf/sub [:current-chat/one-to-one-chat?])
|
||||
one-to-one-chat? (rf/sub [:chats/current-chat-one-to-one?])
|
||||
current-chat-color (rf/sub [:chats/current-chat-color])
|
||||
contact-customization-color (rf/sub [:contacts/contact-customization-color-by-address from])]
|
||||
[quo/system-message
|
||||
|
||||
+18
-17
@@ -9,20 +9,21 @@
|
||||
link-previews? (rf/sub [:chats/message-link-previews? chat-id message-id])]
|
||||
(when (seq status-link-previews)
|
||||
[rn/view {:style {:margin-top (when link-previews? 8)}}
|
||||
(for [{:keys [url community]} status-link-previews]
|
||||
(when community
|
||||
(let [{community-description :description
|
||||
community-icon :icon
|
||||
community-banner :banner
|
||||
community-name :display-name
|
||||
members-count :members-count} community]
|
||||
^{:key url}
|
||||
[quo/internal-link-card
|
||||
{:type :community
|
||||
:size :message
|
||||
:description community-description
|
||||
:members-count members-count
|
||||
:title community-name
|
||||
:banner (:url community-banner)
|
||||
:icon (:url community-icon)
|
||||
:on-press #(rf/dispatch [:universal-links/handle-url url])}])))])))
|
||||
(doall
|
||||
(for [{:keys [url community]} status-link-previews]
|
||||
(when community
|
||||
(let [{community-description :description
|
||||
community-icon :icon
|
||||
community-banner :banner
|
||||
community-name :display-name
|
||||
members-count :members-count} community]
|
||||
^{:key url}
|
||||
[quo/internal-link-card
|
||||
{:type :community
|
||||
:size :message
|
||||
:description community-description
|
||||
:members-count members-count
|
||||
:title community-name
|
||||
:banner (:url community-banner)
|
||||
:icon (:url community-icon)
|
||||
:on-press #(rf/dispatch [:universal-links/handle-url url])}]))))])))
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
(ns status-im.contexts.communities.actions.permissions-sheet.style)
|
||||
|
||||
(def container
|
||||
{:flex 1
|
||||
:padding-horizontal 20})
|
||||
@@ -1,38 +1,12 @@
|
||||
(ns status-im.contexts.communities.actions.permissions-sheet.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im.contexts.communities.actions.permissions-sheet.style :as style]
|
||||
[status-im.contexts.communities.utils :as communities.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- role-text
|
||||
[role]
|
||||
(i18n/label
|
||||
(communities.utils/role->translation-key role
|
||||
:t/token-master)))
|
||||
|
||||
(defn- permission-view
|
||||
[{:keys [tokens role satisfied?]}]
|
||||
(when (seq tokens)
|
||||
^{:key role}
|
||||
[rn/view {:style {:margin-bottom 20}}
|
||||
[quo/text {:weight :medium}
|
||||
(if satisfied?
|
||||
(i18n/label :t/you-eligible-to-join-as {:role (role-text role)})
|
||||
(i18n/label :t/you-not-eligible-to-join-as {:role (role-text role)}))]
|
||||
[quo/text {:size :paragraph-2 :style {:padding-bottom 8}}
|
||||
(if satisfied?
|
||||
(i18n/label :t/you-hodl)
|
||||
(i18n/label :t/you-must-hold))]
|
||||
[quo/token-requirement-list
|
||||
{:tokens tokens
|
||||
:container-style {:padding-horizontal 20}}]]))
|
||||
|
||||
(defn view
|
||||
[id]
|
||||
(let [permissions (rf/sub [:community/token-permissions id])]
|
||||
[gesture/scroll-view {:style style/container}
|
||||
(map permission-view permissions)]))
|
||||
[gesture/scroll-view
|
||||
[quo/community-detail-token-gating {:permissions permissions}]
|
||||
]))
|
||||
|
||||
@@ -149,23 +149,6 @@
|
||||
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
|
||||
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))
|
||||
|
||||
(defn initialize-permission-addresses
|
||||
[{:keys [db]} [community-id]]
|
||||
(when community-id
|
||||
(let [accounts (utils/sorted-non-watch-only-accounts db)
|
||||
addresses (set (map :address accounts))]
|
||||
{:db (update-in db
|
||||
[:communities community-id]
|
||||
assoc
|
||||
:previous-share-all-addresses? true
|
||||
:share-all-addresses? true
|
||||
:previous-permission-addresses addresses
|
||||
:selected-permission-addresses addresses
|
||||
:airdrop-address (:address (first accounts)))})))
|
||||
|
||||
(rf/reg-event-fx :communities/initialize-permission-addresses
|
||||
initialize-permission-addresses)
|
||||
|
||||
(defn update-previous-permission-addresses
|
||||
[{:keys [db]} [community-id]]
|
||||
(when community-id
|
||||
@@ -342,8 +325,8 @@
|
||||
|
||||
(rf/reg-event-fx :chat.ui/spectate-community spectate-community)
|
||||
|
||||
(rf/defn navigate-to-serialized-community
|
||||
[_ {:keys [community-id]}]
|
||||
(defn navigate-to-serialized-community
|
||||
[community-id]
|
||||
{:serialization/deserialize-and-compress-key
|
||||
{:serialized-key community-id
|
||||
:on-success #(rf/dispatch [:communities/navigate-to-community-overview %])
|
||||
@@ -351,27 +334,30 @@
|
||||
:error %
|
||||
:community-id community-id})}})
|
||||
|
||||
(rf/reg-event-fx :communities/navigate-to-community-overview
|
||||
(fn [{:keys [db] :as cofx} [deserialized-key]]
|
||||
(let [current-view-id (:view-id db)]
|
||||
(if (string/starts-with? deserialized-key constants/serialization-key)
|
||||
(navigate-to-serialized-community cofx deserialized-key)
|
||||
(rf/merge
|
||||
cofx
|
||||
{:fx [[:dispatch
|
||||
[:communities/fetch-community
|
||||
{:community-id deserialized-key
|
||||
:update-last-opened-at? true}]]
|
||||
[:dispatch [:navigate-to :community-overview deserialized-key]]
|
||||
(when (get-in db [:communities deserialized-key :joined])
|
||||
[:dispatch
|
||||
[:activity-center.notifications/dismiss-community-overview deserialized-key]])]}
|
||||
(when-not (or (= current-view-id :shell) (= current-view-id :communities-stack))
|
||||
(navigation/pop-to-root :shell-stack)))))))
|
||||
(rf/defn navigate-to-community-overview
|
||||
[{:keys [db] :as cofx} [community-id]]
|
||||
(let [current-view-id (:view-id db)]
|
||||
(if (string/starts-with? community-id constants/serialization-key)
|
||||
(navigate-to-serialized-community community-id)
|
||||
(rf/merge
|
||||
cofx
|
||||
{:fx [[:dispatch
|
||||
[:communities/fetch-community
|
||||
{:community-id community-id
|
||||
:update-last-opened-at? true}]]
|
||||
[:dispatch [:navigate-to :community-overview community-id]]
|
||||
(when (get-in db [:communities community-id :joined])
|
||||
[:dispatch
|
||||
[:activity-center.notifications/dismiss-community-overview community-id]])]}
|
||||
(when-not (or (= current-view-id :shell) (= current-view-id :communities-stack))
|
||||
(navigation/pop-to-root :shell-stack))))))
|
||||
|
||||
(rf/reg-event-fx :communities/navigate-to-community-chat
|
||||
(fn [{:keys [db]} [chat-id pop-to-root?]]
|
||||
(let [{:keys [community-id]} (get-in db [:chats chat-id])]
|
||||
(rf/reg-event-fx :communities/navigate-to-community-overview navigate-to-community-overview)
|
||||
|
||||
(defn navigate-to-community-chat
|
||||
[{:keys [db]} [chat-id pop-to-root? community-id]]
|
||||
(let [community-id (or community-id (get-in db [:chats chat-id :community-id]))]
|
||||
(merge
|
||||
{:fx [(when community-id
|
||||
[:dispatch
|
||||
[:communities/fetch-community
|
||||
@@ -379,7 +365,11 @@
|
||||
:update-last-opened-at? true}]])
|
||||
(if pop-to-root?
|
||||
[:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]]
|
||||
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
|
||||
[:dispatch [:chat/navigate-to-chat chat-id]])]}
|
||||
(when-not (get-in db [:chats chat-id :community-id])
|
||||
{:db (assoc-in db [:chats chat-id :community-id] community-id)}))))
|
||||
|
||||
(rf/reg-event-fx :communities/navigate-to-community-chat navigate-to-community-chat)
|
||||
|
||||
(defn get-revealed-accounts
|
||||
[{:keys [db]} [community-id on-success]]
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
(def community-tag-container
|
||||
{:padding-horizontal screen-horizontal-padding
|
||||
:margin-horizontal (- screen-horizontal-padding)
|
||||
:margin-bottom 20})
|
||||
:margin-bottom 16})
|
||||
|
||||
(def community-content-container
|
||||
{:padding-horizontal screen-horizontal-padding})
|
||||
@@ -64,4 +64,5 @@
|
||||
{:border-radius 16
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80)
|
||||
:border-width 1
|
||||
:padding-top 10})
|
||||
:padding-top 10
|
||||
:margin-bottom 106})
|
||||
|
||||
@@ -38,8 +38,9 @@
|
||||
{:keys [name emoji muted? id mentions-count unread-messages? on-press locked? color] :as chat}]
|
||||
(let [sheet-content [actions/chat-actions
|
||||
(assoc chat
|
||||
:chat-type constants/community-chat-type
|
||||
:chat-id (str community-id id))
|
||||
:community-id community-id
|
||||
:chat-type constants/community-chat-type
|
||||
:chat-id (str community-id id))
|
||||
false]
|
||||
notification (cond
|
||||
muted? :mute
|
||||
@@ -161,7 +162,7 @@
|
||||
(i18n/label :t/you-eligible-to-join-as {:role highest-role-text})
|
||||
(i18n/label :t/you-not-eligible-to-join))]
|
||||
[info-button]]
|
||||
[quo/text {:style {:padding-horizontal 12 :padding-bottom 18} :size :paragraph-2}
|
||||
[quo/text {:style {:padding-horizontal 12 :padding-bottom 6} :size :paragraph-2}
|
||||
(if can-request-access?
|
||||
(i18n/label :t/you-hodl)
|
||||
(i18n/label :t/you-must-hold))]
|
||||
@@ -175,7 +176,7 @@
|
||||
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
|
||||
:accessibility-label :join-community-button
|
||||
:customization-color color
|
||||
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
|
||||
:container-style {:margin-horizontal 12 :margin-top 8 :margin-bottom 12}
|
||||
:disabled? (not can-request-access?)
|
||||
:icon-left (if can-request-access? :i/unlocked :i/locked)}
|
||||
(i18n/label :t/request-to-join)]])))
|
||||
|
||||
@@ -38,23 +38,24 @@
|
||||
:url %}])]
|
||||
{:fx [[:dispatch [:communities/get-community-channel-share-data chat-id on-success]]]})))
|
||||
|
||||
(rf/reg-event-fx :communities/share-community-url-with-data
|
||||
(fn [_ [community-id]]
|
||||
(let [title (i18n/label :t/community-on-status)
|
||||
(rf/reg-event-fx :communities/share-community-channel-url-with-data
|
||||
(fn [_ [chat-id]]
|
||||
(let [title (i18n/label :t/channel-on-status)
|
||||
on-success (fn [url]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content title}
|
||||
:item {:default {:type "url"
|
||||
:content url}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message url
|
||||
:url url
|
||||
:isNewTask true})))]
|
||||
{:fx [[:dispatch [:communities/get-community-share-data community-id on-success]]]})))
|
||||
(rf/dispatch [:open-share
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources
|
||||
[{:placeholderItem {:type :text
|
||||
:content title}
|
||||
:item {:default {:type :url
|
||||
:content url}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message url
|
||||
:url url
|
||||
:isNewTask true})}]))]
|
||||
{:fx [[:dispatch [:communities/get-community-channel-share-data chat-id on-success]]]})))
|
||||
|
||||
(rf/reg-event-fx :communities/get-community-channel-share-data
|
||||
(fn [_ [chat-id on-success]]
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
(ns status-im.contexts.preview.quo.community.community-detail-token-gating
|
||||
(:require [quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:key :role
|
||||
:type :select
|
||||
:options [{:key :one-role}
|
||||
{:key :two-roles}
|
||||
{:key :three-roles}
|
||||
{:key :four-roles}]}])
|
||||
|
||||
(def roles
|
||||
{:member
|
||||
{:role 2
|
||||
:role-text "Member"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "ETH" :sufficient? true :collectible? false :loading? false :amount 0.8 :img-src nil}]
|
||||
[{:symbol "ETH" :sufficient? false :collectible? false :loading? false :amount 1 :img-src nil}
|
||||
{:symbol "STT" :sufficient? false :collectible? false :loading? false :amount 10 :img-src nil}]]}
|
||||
:admin
|
||||
{:role 1
|
||||
:role-text "Admin"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "ETH" :sufficient? true :collectible? false :loading? false :amount 2 :img-src nil}]]}
|
||||
:token-master
|
||||
{:role 5
|
||||
:role-text "Token Master"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "TMANI"
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:loading? false
|
||||
:amount nil
|
||||
:img-src (resources/mock-images :collectible1)}]]}
|
||||
:token-owner
|
||||
{:role 6
|
||||
:role-text "Token Owner"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "TOANI"
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:loading? false
|
||||
:amount nil
|
||||
:img-src (resources/mock-images :collectible)}]]}})
|
||||
|
||||
(def permissions
|
||||
{:one-role [(:member roles)]
|
||||
:two-roles [(:admin roles) (:member roles)]
|
||||
:three-roles [(:token-master roles) (:admin roles) (:member roles)]
|
||||
:four-roles [(:token-owner roles) (:token-master roles) (:admin roles) (:member roles)]})
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:role :one-role})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[quo/community-detail-token-gating {:permissions ((:role @state) permissions)}]])))
|
||||
@@ -39,6 +39,8 @@
|
||||
channel-actions]
|
||||
[status-im.contexts.preview.quo.community.community-card-view :as
|
||||
community-card]
|
||||
[status-im.contexts.preview.quo.community.community-detail-token-gating :as
|
||||
community-detail-token-gating]
|
||||
[status-im.contexts.preview.quo.community.community-membership-list-view
|
||||
:as community-membership-list-view]
|
||||
[status-im.contexts.preview.quo.community.community-stat :as community-stat]
|
||||
@@ -260,6 +262,8 @@
|
||||
:component color/view}]
|
||||
:community [{:name :community-card-view
|
||||
:component community-card/view}
|
||||
{:name :community-detail-token-gating
|
||||
:component community-detail-token-gating/view}
|
||||
{:name :community-membership-list-view
|
||||
:component community-membership-list-view/view}
|
||||
{:name :community-stat
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.contexts.preview.quo.wallet.network-link
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
@@ -23,17 +24,21 @@
|
||||
:options networks}
|
||||
{:key :destination
|
||||
:type :select
|
||||
:options networks}])
|
||||
:options networks}
|
||||
{:key :width
|
||||
:type :number}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:shape :linear
|
||||
:source :ethereum
|
||||
:destination :optimism})]
|
||||
:destination :optimism
|
||||
:width 63})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:component-container-style {:padding-top 40
|
||||
:align-items :center}}
|
||||
[quo/network-link @state]])))
|
||||
[rn/view {:style {:width (max (:width @state) 63)}}
|
||||
[quo/network-link @state]]])))
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
(fn []
|
||||
(rf/dispatch [:universal-links/generate-profile-url
|
||||
{:public-key public-key
|
||||
:on-success #(rn/sharing {:message %})}]))
|
||||
:on-success #(rf/dispatch [:open-share
|
||||
{:options {:message %}}])}]))
|
||||
[public-key])
|
||||
on-remove-contact (rn/use-callback
|
||||
(fn []
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im.contexts.profile.contact.share.view
|
||||
(:require [legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[quo.core :as quo]
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
@@ -19,7 +18,8 @@
|
||||
abbreviated-url (rn/use-memo (fn []
|
||||
(address/get-abbreviated-profile-url universal-profile-url))
|
||||
[universal-profile-url])
|
||||
on-share-press (rn/use-callback #(list-selection/open-share {:message universal-profile-url})
|
||||
on-share-press (rn/use-callback #(rf/dispatch [:open-share
|
||||
{:options {:message universal-profile-url}}])
|
||||
[universal-profile-url])
|
||||
on-copy-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:share/copy-text-and-show-toast
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
(when config/show-not-implemented-features?
|
||||
{:title (i18n/label :t/dapps)
|
||||
:on-press not-implemented/alert
|
||||
:image-props :i/placeholder
|
||||
:image-props :i/dapps
|
||||
:image :icon
|
||||
:blur? true
|
||||
:action :arrow})
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.contexts.profile.settings.header.view :as settings.header]
|
||||
[status-im.contexts.profile.settings.list-items :as settings.items]
|
||||
[status-im.contexts.profile.settings.style :as style]
|
||||
@@ -19,7 +18,7 @@
|
||||
[rf/delay-render
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:container-style {:padding-bottom 0}
|
||||
:container-style {:padding-bottom 12}
|
||||
:blur? true
|
||||
:data data}]])
|
||||
|
||||
@@ -62,7 +61,10 @@
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:right-side [{:icon-name :i/qr-code
|
||||
:on-press #(debounce/throttle-and-dispatch [:open-modal :share-shell] 1000)}
|
||||
{:icon-name :i/share :on-press not-implemented/alert}]}]]
|
||||
{:icon-name :i/share
|
||||
:on-press #(rf/dispatch [:open-share
|
||||
{:options {:message (:universal-profile-url
|
||||
profile)}}])}]}]]
|
||||
[rn/flat-list
|
||||
{:key :list
|
||||
:header [settings.header/view {:scroll-y scroll-y}]
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
|
||||
(defn floating-button
|
||||
[shared-values]
|
||||
[quo/floating-shell-button
|
||||
{:jump-to {:on-press #(animation/close-home-stack true)
|
||||
:label (i18n/label :t/jump-to)
|
||||
:customization-color (rf/sub [:profile/customization-color])}}
|
||||
{:position :absolute
|
||||
:bottom (utils/bottom-tabs-container-height)}
|
||||
(:home-stack-opacity shared-values)])
|
||||
(let [current-screen-id (rf/sub [:view-id])]
|
||||
(when-not (= current-screen-id :settings)
|
||||
[quo/floating-shell-button
|
||||
{:jump-to {:on-press #(animation/close-home-stack true)
|
||||
:label (i18n/label :t/jump-to)
|
||||
:customization-color (rf/sub [:profile/customization-color])}}
|
||||
{:position :absolute
|
||||
:bottom (utils/bottom-tabs-container-height)}
|
||||
(:home-stack-opacity shared-values)])))
|
||||
|
||||
(defn f-shell-stack
|
||||
[]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.contexts.shell.share.profile.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
@@ -30,7 +29,7 @@
|
||||
:width (- window-width (* style/screen-padding 2))
|
||||
:qr-data universal-profile-url
|
||||
:qr-data-label-shown abbreviated-url
|
||||
:on-share-press #(list-selection/open-share {:message universal-profile-url})
|
||||
:on-share-press #(rf/dispatch [:open-share {:options {:message universal-profile-url}}])
|
||||
:on-text-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}])
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.shell.share.style :as style]
|
||||
@@ -20,18 +19,18 @@
|
||||
|
||||
(defn- share-action
|
||||
[address share-title]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})))
|
||||
(rf/dispatch [:open-share
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type :text
|
||||
:content address}
|
||||
:item {:default {:type :text
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})}]))
|
||||
|
||||
(defn- open-preferences
|
||||
[selected-networks account]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.share :as share]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.account.share-address.style :as style]
|
||||
@@ -18,18 +17,18 @@
|
||||
|
||||
(defn- share-action
|
||||
[address share-title]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})))
|
||||
(rf/dispatch [:open-share
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type :text
|
||||
:content address}
|
||||
:item {:default {:type :text
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})}]))
|
||||
|
||||
(defn- open-preferences
|
||||
[selected-networks]
|
||||
|
||||
@@ -6,20 +6,10 @@
|
||||
[status-im.contexts.wallet.account.style :as style]
|
||||
[status-im.contexts.wallet.account.tabs.view :as tabs]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.common.temp :as temp]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn buy-drawer
|
||||
[]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/buy-tokens)}]
|
||||
[rn/flat-list
|
||||
{:data temp/buy-tokens-list
|
||||
:style {:padding-horizontal 8
|
||||
:padding-bottom 8}
|
||||
:render-fn quo/settings-item}]])
|
||||
|
||||
(def first-tab-id :assets)
|
||||
|
||||
(defn tabs-data
|
||||
@@ -55,7 +45,7 @@
|
||||
:flow-id :wallet-flow}]))
|
||||
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address {:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-drawer}])
|
||||
{:content buy-token/view}])
|
||||
:bridge-action #(rf/dispatch [:wallet/start-bridge])}])
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
:image :icon
|
||||
:image-props :i/derivated-path
|
||||
:action :button
|
||||
:action-props {:on-press #(if (ff/enabled? :ff/wallet.edit-derivation-path)
|
||||
:action-props {:on-press #(if (ff/enabled? ::ff/wallet.edit-derivation-path)
|
||||
(rf/dispatch [:standard-auth/authorize
|
||||
{:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/continue)}])
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
[account-switcher/view
|
||||
{:on-press #(rf/dispatch [:navigate-back])
|
||||
:icon-name :i/arrow-left
|
||||
:accessibility-label :top-bar}]
|
||||
:accessibility-label :top-bar
|
||||
:switcher-type :select-account}]
|
||||
[quo/page-top {:title bridge-to-title}]
|
||||
[rn/view style/content-container
|
||||
[bridge-token-component (assoc mainnet :network-name :t/mainnet) account-token]]
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
:button-one-label (i18n/label :t/confirm-bridge)
|
||||
:button-one-props {:icon-left :i/bridge}
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:navigate-back]))}]])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
[rn/view {:style {:flex 1}}
|
||||
[account-switcher/view
|
||||
{:on-press #(rf/dispatch [:navigate-back])
|
||||
:accessibility-label :top-bar}]
|
||||
:accessibility-label :top-bar
|
||||
:switcher-type :select-account}]
|
||||
[quo/page-top {:title (i18n/label :t/bridge)}]
|
||||
[quo/input
|
||||
{:container-style style/input-container
|
||||
|
||||
@@ -1,52 +1,80 @@
|
||||
(ns status-im.contexts.wallet.common.token-value.view
|
||||
(:require [quo.core :as quo]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- action-buy
|
||||
[]
|
||||
{:icon :i/buy
|
||||
:accessibility-label :buy
|
||||
:label (i18n/label :t/buy)
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:right-icon :i/external})
|
||||
|
||||
(defn- action-send
|
||||
[token-data]
|
||||
{:icon :i/send
|
||||
:accessibility-label :send
|
||||
:label (i18n/label :t/send)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/send-select-token
|
||||
{:token token-data
|
||||
:start-flow? true}]))})
|
||||
|
||||
(defn- action-receive
|
||||
[]
|
||||
{:icon :i/receive
|
||||
:accessibility-label :receive
|
||||
:label (i18n/label :t/receive)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/wallet.share-address {:status :receive}])})
|
||||
|
||||
(defn- action-bridge
|
||||
[]
|
||||
{:icon :i/bridge
|
||||
:accessibility-label :bridge
|
||||
:label (i18n/label :t/bridge)
|
||||
:on-press #(js/alert "to be implemented")})
|
||||
|
||||
(defn- action-manage-tokens
|
||||
[watch-only?]
|
||||
{:icon :i/settings
|
||||
:accessibility-label :settings
|
||||
:label (i18n/label :t/manage-tokens)
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:add-divider? (not watch-only?)})
|
||||
|
||||
(defn- action-hide
|
||||
[]
|
||||
{:icon :i/hide
|
||||
:accessibility-label :hide
|
||||
:label (i18n/label :t/hide)
|
||||
:on-press #(js/alert "to be implemented")})
|
||||
|
||||
(defn token-value-drawer
|
||||
[token]
|
||||
[token watch-only?]
|
||||
(let [token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered (:token token)]))]
|
||||
[:<>
|
||||
[quo/action-drawer
|
||||
[[{:icon :i/buy
|
||||
:accessibility-label :buy
|
||||
:label (i18n/label :t/buy)
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:right-icon :i/external}
|
||||
{:icon :i/send
|
||||
:accessibility-label :send
|
||||
:label (i18n/label :t/send)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/send-select-token
|
||||
{:token token-data
|
||||
:start-flow? true}]))}
|
||||
{:icon :i/receive
|
||||
:accessibility-label :receive
|
||||
:label (i18n/label :t/receive)
|
||||
:on-press #(js/alert "to be implemented")}
|
||||
{:icon :i/bridge
|
||||
:accessibility-label :bridge
|
||||
:label (i18n/label :t/bridge)
|
||||
:on-press #(js/alert "to be implemented")}
|
||||
{:icon :i/settings
|
||||
:accessibility-label :settings
|
||||
:label (i18n/label :t/manage-tokens)
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:add-divider? true}
|
||||
{:icon :i/hide
|
||||
:accessibility-label :hide
|
||||
:label (i18n/label :t/hide)
|
||||
:on-press #(js/alert "to be implemented")}]]]]))
|
||||
[quo/action-drawer
|
||||
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
|
||||
(action-manage-tokens watch-only?))
|
||||
(when (ff/enabled? ::ff/wallet.assets-modal-hide)
|
||||
(action-hide))]
|
||||
(not watch-only?) (concat [(action-buy)
|
||||
(action-send token-data)
|
||||
(action-receive)
|
||||
(action-bridge)]))]]))
|
||||
|
||||
(defn view
|
||||
[item _ _ {:keys [watch-only?]}]
|
||||
[quo/token-value
|
||||
(cond-> item
|
||||
(not watch-only?)
|
||||
(or (not watch-only?) (ff/enabled? ::ff/wallet.long-press-watch-only-asset))
|
||||
(assoc :on-long-press
|
||||
#(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn [] [token-value-drawer item])
|
||||
{:content (fn [] [token-value-drawer item watch-only?])
|
||||
:selected-item (fn [] [quo/token-value item])}])))])
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
(ns status-im.contexts.wallet.common.utils.networks
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]))
|
||||
|
||||
(defn resolve-receiver-networks
|
||||
[{:keys [prefix testnet-enabled? goerli-enabled?]}]
|
||||
(let [prefix (if (string/blank? prefix)
|
||||
constants/default-multichain-address-prefix
|
||||
prefix)
|
||||
prefix-seq (string/split prefix #":")]
|
||||
(->> prefix-seq
|
||||
(remove string/blank?)
|
||||
(mapv
|
||||
#(utils/network->chain-id
|
||||
{:network %
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})))))
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.wallet.common.utils.send
|
||||
(:require [utils.money :as money]))
|
||||
(:require [clojure.string :as string]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn calculate-gas-fee
|
||||
[data]
|
||||
@@ -20,3 +21,17 @@
|
||||
(defn calculate-full-route-gas-fee
|
||||
[route]
|
||||
(reduce money/add (map calculate-gas-fee route)))
|
||||
|
||||
(defn find-affordable-networks
|
||||
[{:keys [balances-per-chain input-value selected-networks disabled-chain-ids]}]
|
||||
(let [input-value (if (string/blank? input-value) 0 input-value)]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_
|
||||
{:keys [balance chain-id]
|
||||
:or {balance 0}}]]
|
||||
(and
|
||||
(money/greater-than-or-equals (money/bignumber balance)
|
||||
(money/bignumber input-value))
|
||||
(some #(= % chain-id) selected-networks)
|
||||
(not-any? #(= % chain-id) disabled-chain-ids))))
|
||||
(map first))))
|
||||
|
||||
@@ -20,3 +20,44 @@
|
||||
expected-eip1559-disabled-result (money/bignumber 0.000760406)]
|
||||
(is (money/equal-to (utils/calculate-gas-fee data-eip1559-disabled)
|
||||
expected-eip1559-disabled-result))))))
|
||||
|
||||
(deftest test-find-affordable-networks
|
||||
(testing "All networks affordable and selected, none disabled"
|
||||
(let [balances-per-chain {"1" {:balance "50.0" :chain-id "1"}
|
||||
"2" {:balance "40.0" :chain-id "2"}}
|
||||
input-value 20
|
||||
selected-networks ["1" "2"]
|
||||
disabled-chain-ids []
|
||||
expected ["1" "2"]]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected)))))
|
||||
|
||||
(testing "No networks affordable"
|
||||
(let [balances-per-chain {"1" {:balance "5.0" :chain-id "1"}
|
||||
"2" {:balance "1.0" :chain-id "2"}}
|
||||
input-value 10
|
||||
selected-networks ["1" "2"]
|
||||
disabled-chain-ids []
|
||||
expected []]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected)))))
|
||||
|
||||
(testing "Selected networks subset, with some disabled"
|
||||
(let [balances-per-chain {"1" {:balance "100.0" :chain-id "1"}
|
||||
"2" {:balance "50.0" :chain-id "2"}
|
||||
"3" {:balance "20.0" :chain-id "3"}}
|
||||
input-value 15
|
||||
selected-networks ["1" "2" "3"]
|
||||
disabled-chain-ids ["2"]
|
||||
expected ["1" "3"]]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected))))))
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.share :as share]))
|
||||
|
||||
(rf/reg-fx :effects.share/open
|
||||
(fn [content]
|
||||
(share/open content)))
|
||||
[re-frame.core :as rf]))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet/create-account-from-mnemonic
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
(let [tokens (data-store/rpc->tokens raw-tokens-data)
|
||||
add-tokens (fn [stored-accounts tokens-per-account]
|
||||
(reduce-kv (fn [accounts address tokens-data]
|
||||
(if (accounts address)
|
||||
(if (contains? accounts address)
|
||||
(update accounts address assoc :tokens tokens-data)
|
||||
accounts))
|
||||
stored-accounts
|
||||
@@ -402,16 +402,16 @@
|
||||
(rf/reg-event-fx :wallet/share-account
|
||||
(fn [_ [{:keys [content title]}]]
|
||||
{:fx [[:effects.share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources
|
||||
[{:placeholderItem {:type "text"
|
||||
:content content}
|
||||
:item {:default {:type "text"
|
||||
:content content}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message content})]]}))
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources
|
||||
[{:placeholderItem {:type :text
|
||||
:content content}
|
||||
:item {:default {:type :text
|
||||
:content content}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message content})}]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/blockchain-status-changed
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
|
||||
(defn home-container
|
||||
[]
|
||||
{:margin-top (safe-area/get-top)
|
||||
{:margin-top (+ (safe-area/get-top) 8)
|
||||
:flex 1})
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[native-module.core :as native-module]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
@@ -24,45 +25,71 @@
|
||||
(rf/reg-event-fx :wallet/suggested-routes-success
|
||||
(fn [{:keys [db]} [suggested-routes timestamp]]
|
||||
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
|
||||
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword suggested-routes)
|
||||
chosen-route (:best suggested-routes-data)]
|
||||
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword
|
||||
suggested-routes)
|
||||
chosen-route (:best suggested-routes-data)
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
token-display-name (get-in db [:wallet :ui :send :token-display-name])
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? false})
|
||||
from-network-values-for-ui (send-utils/network-values-for-ui from-network-amounts-by-chain)
|
||||
to-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? true})
|
||||
to-network-values-for-ui (send-utils/network-values-for-ui to-network-amounts-by-chain)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes-data)
|
||||
(assoc-in [:wallet :ui :send :route] chosen-route)
|
||||
(assoc-in [:wallet :ui :send :from-values-by-chain] from-network-values-for-ui)
|
||||
(assoc-in [:wallet :ui :send :to-values-by-chain] to-network-values-for-ui)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-error
|
||||
(fn [{:keys [db]} [_error]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes :route)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-suggested-routes
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
dissoc
|
||||
:suggested-routes
|
||||
:route
|
||||
:from-values-by-chain
|
||||
:to-values-by-chain
|
||||
:loading-suggested-routes?
|
||||
:suggested-routes-call-timestamp)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-address
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :recipient :to-address)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-disabled-from-networks
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :disabled-from-chain-ids)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/select-send-address
|
||||
(fn [{:keys [db]} [{:keys [address recipient stack-id start-flow?]}]]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)
|
||||
testnet-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
goerli-enabled? (get-in db [:profile/profile :is-goerli-enabled?])
|
||||
prefix-seq (string/split prefix #":")
|
||||
selected-networks (->> prefix-seq
|
||||
(remove string/blank?)
|
||||
(mapv
|
||||
#(utils/network->chain-id
|
||||
{:network %
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})))]
|
||||
selected-networks (network-utils/resolve-receiver-networks
|
||||
{:prefix prefix
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] to-address)
|
||||
@@ -84,7 +111,8 @@
|
||||
(fn [{:keys [db]} [{:keys [token stack-id start-flow?]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :collectible)
|
||||
(assoc-in [:wallet :ui :send :token] token))
|
||||
(assoc-in [:wallet :ui :send :token] token)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] (:symbol token)))
|
||||
:fx [[:dispatch [:wallet/clean-suggested-routes]]
|
||||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
@@ -95,13 +123,15 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/edit-token-to-send
|
||||
(fn [{:keys [db]} [token]]
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :token] token)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] token))
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:wallet/clean-suggested-routes]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-selected-token
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :token :tx-type)}))
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :token :token-display-name :tx-type)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-selected-collectible
|
||||
(fn [{:keys [db]}]
|
||||
@@ -110,18 +140,30 @@
|
||||
[:wallet :ui :send]
|
||||
dissoc
|
||||
:collectible
|
||||
:token-display-name
|
||||
:amount
|
||||
(when (= transaction-type :collecible) :tx-type))})))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id amount]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]}))
|
||||
(let [collection-data (:collection-data collectible)
|
||||
collectible-data (:collectible-data collectible)
|
||||
collectible-id (get-in collectible [:id :token-id])
|
||||
token-display-name (cond
|
||||
(and collectible
|
||||
(not (string/blank? (:name collectible-data))))
|
||||
(:name collectible-data)
|
||||
|
||||
collectible
|
||||
(str (:name collection-data) " #" collectible-id))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] token-display-name)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
|
||||
@@ -140,6 +182,12 @@
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-flow}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/disable-from-networks
|
||||
(fn [{:keys [db]} [chain-ids]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :disabled-from-chain-ids] chain-ids)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/get-suggested-routes
|
||||
(fn [{:keys [db now]} [{:keys [amount]}]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
@@ -147,6 +195,7 @@
|
||||
transaction-type (get-in db [:wallet :ui :send :tx-type])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
disabled-from-chain-ids (or (get-in db [:wallet :ui :send :disabled-from-chain-ids]) [])
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks ((if test-networks-enabled? :test :prod)
|
||||
(get-in db [:wallet :networks]))
|
||||
@@ -163,7 +212,7 @@
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in (send-utils/amount-in-hex amount (if token token-decimal 0))
|
||||
from-address wallet-address
|
||||
disabled-from-chain-ids []
|
||||
disabled-from-chain-ids disabled-from-chain-ids
|
||||
disabled-to-chain-ids (if (= transaction-type :bridge)
|
||||
(filter #(not= % bridge-to-chain-id) network-chain-ids)
|
||||
[])
|
||||
@@ -218,6 +267,7 @@
|
||||
{:fx [[:dispatch [:wallet/clean-scanned-address]]
|
||||
[:dispatch [:wallet/clean-local-suggestions]]
|
||||
[:dispatch [:wallet/clean-send-address]]
|
||||
[:dispatch [:wallet/clean-disabled-from-networks]]
|
||||
[:dispatch [:wallet/select-address-tab nil]]
|
||||
[:dispatch [:dismiss-modal :screen/wallet.transaction-progress]]]}))
|
||||
|
||||
|
||||
@@ -5,60 +5,75 @@
|
||||
[status-im.contexts.wallet.send.input-amount.view :as input-amount]
|
||||
[test-helpers.component :as h]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(set! rf/dispatch #())
|
||||
(set! debounce/debounce-and-dispatch #())
|
||||
|
||||
(def sub-mocks
|
||||
{:profile/profile {:currency :usd}
|
||||
:wallet/selected-network-details [{:source 525
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]
|
||||
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
|
||||
:emoji "💎"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:watch-only? false
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :purple
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:network-preferences-names #{:mainnet :arbitrum
|
||||
:optimism}
|
||||
:position 1
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false}
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route [{:from {:chainid 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:to {:chain-id 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:gas-amount "23487"
|
||||
:gas-fees {:base-fee "32.325296406"
|
||||
:max-priority-fee-per-gas "0.011000001"
|
||||
:eip1559-enabled true}}]
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}
|
||||
:wallet/wallet-send-selected-networks []
|
||||
:view-id :screen/wallet.send-input-amount
|
||||
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
|
||||
:profile/currency-symbol "$"
|
||||
:wallet/token-by-symbol {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}})
|
||||
{:profile/profile {:currency :usd}
|
||||
:wallet/selected-network-details [{:source 525
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]
|
||||
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
|
||||
:emoji "💎"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:watch-only? false
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :purple
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:network-preferences-names #{:mainnet :arbitrum
|
||||
:optimism}
|
||||
:position 1
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false}
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:networks [{:source 879
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:abbreviated-name "Eth."
|
||||
:chain-id 1
|
||||
:related-chain-id 1
|
||||
:layer 1}]}
|
||||
:wallet/current-viewing-account-tokens-filtered {:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route [{:from {:chainid 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:to {:chain-id 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:gas-amount "23487"
|
||||
:gas-fees {:base-fee "32.325296406"
|
||||
:max-priority-fee-per-gas "0.011000001"
|
||||
:eip1559-enabled true}}]
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}
|
||||
:wallet/wallet-send-selected-networks [1]
|
||||
:view-id :screen/wallet.send-input-amount
|
||||
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
|
||||
:profile/currency-symbol "$"
|
||||
:wallet/token-by-symbol {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-disabled-from-chain-ids []
|
||||
:wallet/wallet-send-from-values-by-chain {1 (money/bignumber "250")}
|
||||
:wallet/wallet-send-to-values-by-chain {1 (money/bignumber "250")}})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
||||
@@ -190,8 +190,9 @@
|
||||
(reset-input-error num-value current-limit-amount input-error)
|
||||
(reagent/flush))))
|
||||
on-navigate-back on-navigate-back
|
||||
fetch-routes (fn [input-num-value current-limit-amount]
|
||||
(let [nav-current-screen-id (rf/sub [:view-id])]
|
||||
fetch-routes (fn [input-num-value current-limit-amount bounce-duration-ms]
|
||||
(let [nav-current-screen-id (rf/sub [:view-id])
|
||||
input-num-value (or input-num-value 0)]
|
||||
; this check is to prevent effect being triggered when screen is
|
||||
; loaded but not being shown to the user (deep in the navigation
|
||||
; stack) and avoid undesired behaviors
|
||||
@@ -201,7 +202,7 @@
|
||||
(> input-num-value current-limit-amount))
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet/get-suggested-routes {:amount @input-value}]
|
||||
2000)
|
||||
bounce-duration-ms)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))))
|
||||
handle-on-confirm (fn []
|
||||
(rf/dispatch [:wallet/send-select-amount
|
||||
@@ -215,65 +216,92 @@
|
||||
(reset! input-selection selection)
|
||||
(reagent/flush))]
|
||||
(fn []
|
||||
(let [{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-balance :total-balance
|
||||
token-symbol :symbol
|
||||
token-networks :networks
|
||||
:as token} (rf/sub [:wallet/wallet-send-token])
|
||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||
loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
best-routes (when suggested-routes (or (:best suggested-routes) []))
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
to-address (rf/sub [:wallet/wallet-send-to-address])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or default-crypto-decimals
|
||||
(utils/get-crypto-decimals-count token))
|
||||
crypto-limit (or default-limit-crypto
|
||||
(utils/get-standard-crypto-format token token-balance))
|
||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||
limit-label (make-limit-label {:amount (current-limit)
|
||||
:currency current-currency})
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (current-limit)))
|
||||
amount-text (str @input-value " " token-symbol)
|
||||
native-currency-symbol (when-not confirm-disabled?
|
||||
(get-in route [:from :native-currency-symbol]))
|
||||
native-token (when native-currency-symbol
|
||||
(rf/sub [:wallet/token-by-symbol native-currency-symbol]))
|
||||
fee-in-native-token (when-not confirm-disabled?
|
||||
(send-utils/calculate-full-route-gas-fee route))
|
||||
fee-in-crypto-formatted (when fee-in-native-token
|
||||
(utils/get-standard-crypto-format native-token
|
||||
fee-in-native-token))
|
||||
fee-in-fiat (when-not confirm-disabled?
|
||||
(utils/calculate-token-fiat-value
|
||||
{:currency fiat-currency
|
||||
:balance fee-in-native-token
|
||||
:token native-token}))
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
fee-formatted (when fee-in-fiat
|
||||
(utils/get-standard-fiat-format fee-in-crypto-formatted
|
||||
currency-symbol
|
||||
fee-in-fiat))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet clear-input!])}])]
|
||||
(let [{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-symbol :symbol
|
||||
token-networks :networks} (rf/sub [:wallet/wallet-send-token])
|
||||
{token-balance :total-balance
|
||||
token-balances-per-chain :balances-per-chain
|
||||
:as
|
||||
token} (rf/sub
|
||||
[:wallet/current-viewing-account-tokens-filtered
|
||||
(str token-symbol)])
|
||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||
loading-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
best-routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
to-address (rf/sub [:wallet/wallet-send-to-address])
|
||||
disabled-from-chain-ids (rf/sub
|
||||
[:wallet/wallet-send-disabled-from-chain-ids])
|
||||
from-values-by-chain (rf/sub [:wallet/wallet-send-from-values-by-chain])
|
||||
to-values-by-chain (rf/sub [:wallet/wallet-send-to-values-by-chain])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or default-crypto-decimals
|
||||
(utils/get-crypto-decimals-count token))
|
||||
crypto-limit (or default-limit-crypto
|
||||
(utils/get-standard-crypto-format
|
||||
token
|
||||
token-balance))
|
||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||
limit-label (make-limit-label {:amount (current-limit)
|
||||
:currency current-currency})
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (current-limit)))
|
||||
amount-text (str @input-value " " token-symbol)
|
||||
native-currency-symbol (when-not confirm-disabled?
|
||||
(get-in route [:from :native-currency-symbol]))
|
||||
native-token (when native-currency-symbol
|
||||
(rf/sub [:wallet/token-by-symbol
|
||||
native-currency-symbol]))
|
||||
fee-in-native-token (when-not confirm-disabled?
|
||||
(send-utils/calculate-full-route-gas-fee route))
|
||||
fee-in-crypto-formatted (when fee-in-native-token
|
||||
(utils/get-standard-crypto-format
|
||||
native-token
|
||||
fee-in-native-token))
|
||||
fee-in-fiat (when-not confirm-disabled?
|
||||
(utils/calculate-token-fiat-value
|
||||
{:currency fiat-currency
|
||||
:balance fee-in-native-token
|
||||
:token native-token}))
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
fee-formatted (when fee-in-fiat
|
||||
(utils/get-standard-fiat-format
|
||||
fee-in-crypto-formatted
|
||||
currency-symbol
|
||||
fee-in-fiat))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
affordable-networks (send-utils/find-affordable-networks
|
||||
{:balances-per-chain token-balances-per-chain
|
||||
:input-value @input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-from-chain-ids})]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||
#(.remove app-keyboard-listener))))
|
||||
(rn/use-effect
|
||||
#(fetch-routes input-num-value (current-limit))
|
||||
#(when (> (count affordable-networks) 0)
|
||||
(fetch-routes input-num-value (current-limit) 2000))
|
||||
[@input-value])
|
||||
(rn/use-effect
|
||||
#(when (> (count affordable-networks) 0)
|
||||
(fetch-routes input-num-value (current-limit) 0))
|
||||
[disabled-from-chain-ids])
|
||||
[rn/view
|
||||
{:style style/screen
|
||||
:accessibility-label (str "container" (when @input-error "-error"))}
|
||||
@@ -303,11 +331,28 @@
|
||||
:limit-crypto crypto-limit})
|
||||
:on-token-press show-select-asset-sheet}]
|
||||
[routes/view
|
||||
{:amount amount-text
|
||||
:routes best-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes #(fetch-routes % (current-limit))}]
|
||||
{:from-values-by-chain from-values-by-chain
|
||||
:to-values-by-chain to-values-by-chain
|
||||
:affordable-networks affordable-networks
|
||||
:routes best-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes #(fetch-routes % (current-limit) 2000)
|
||||
:disabled-from-networks disabled-from-chain-ids
|
||||
:on-press-from-network (fn [chain-id _]
|
||||
(let [disabled-chain-ids (if (contains? (set
|
||||
disabled-from-chain-ids)
|
||||
chain-id)
|
||||
(vec (remove #(= % chain-id)
|
||||
disabled-from-chain-ids))
|
||||
(conj disabled-from-chain-ids
|
||||
chain-id))
|
||||
re-enabling-chain? (< (count disabled-chain-ids)
|
||||
(count disabled-from-chain-ids))]
|
||||
(when (or re-enabling-chain?
|
||||
(> (count affordable-networks) 1))
|
||||
(rf/dispatch [:wallet/disable-from-networks
|
||||
disabled-chain-ids]))))}]
|
||||
(when (or loading-routes? (seq route))
|
||||
[estimated-fees
|
||||
{:loading-suggested-routes? loading-routes?
|
||||
|
||||
@@ -12,20 +12,23 @@
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(def routes-inner-container
|
||||
{:margin-top 8
|
||||
(defn routes-inner-container
|
||||
[first-item?]
|
||||
{:margin-top (if first-item? 7.5 11)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between})
|
||||
|
||||
(defn section-label
|
||||
[margin-left]
|
||||
{:flex 0.5
|
||||
:margin-left margin-left})
|
||||
(def section-label-right
|
||||
{:width 135})
|
||||
|
||||
(def section-label-left
|
||||
{:width 136})
|
||||
|
||||
(def network-link
|
||||
{:right 6
|
||||
:z-index 1})
|
||||
{:margin-horizontal -1.5
|
||||
:z-index 1
|
||||
:flex 1})
|
||||
|
||||
(def empty-container
|
||||
{:flex-grow 1
|
||||
@@ -33,9 +36,8 @@
|
||||
:justify-content :center})
|
||||
|
||||
(def add-network
|
||||
{:margin-top 8
|
||||
:align-self :flex-end
|
||||
:right 12})
|
||||
{:margin-top 11
|
||||
:align-self :flex-end})
|
||||
|
||||
(defn warning-container
|
||||
[color theme]
|
||||
|
||||
@@ -7,19 +7,17 @@
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.routes.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.vector :as vector-utils]))
|
||||
|
||||
(defn- find-affordable-networks
|
||||
[{:keys [balances-per-chain]} input-value selected-networks]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [balance chain-id]}]]
|
||||
(and
|
||||
(>= (js/parseFloat balance) input-value)
|
||||
(some #(= % chain-id) selected-networks))))
|
||||
(map first)))
|
||||
(def ^:private network-priority-score
|
||||
{:ethereum 1
|
||||
:optimism 2
|
||||
:arbitrum 3})
|
||||
|
||||
(defn- make-network-item
|
||||
[{:keys [network-name chain-id] :as _network}
|
||||
@@ -34,6 +32,36 @@
|
||||
:checked? (some #(= % chain-id) @network-preferences)
|
||||
:on-change on-change}})
|
||||
|
||||
(defn- find-network-link-insertion-index
|
||||
[network-links chain-id loading-suggested-routes?]
|
||||
(let [network (utils/id->network chain-id)
|
||||
inserted-network-link-priority-score (network-priority-score network)]
|
||||
(or (->> network-links
|
||||
(keep-indexed (fn [idx network-link]
|
||||
(let [network-link (utils/id->network (if loading-suggested-routes?
|
||||
network-link
|
||||
(get-in network-link
|
||||
[:from :chain-id])))]
|
||||
(when (> (network-priority-score network-link)
|
||||
inserted-network-link-priority-score)
|
||||
idx))))
|
||||
first)
|
||||
(count network-links))))
|
||||
|
||||
(defn- add-disabled-networks
|
||||
[network-links disabled-from-networks loading-suggested-routes?]
|
||||
(let [sorted-networks (sort-by (comp network-priority-score utils/id->network) disabled-from-networks)]
|
||||
(reduce (fn [acc-network-links chain-id]
|
||||
(let [index (find-network-link-insertion-index acc-network-links
|
||||
chain-id
|
||||
loading-suggested-routes?)
|
||||
disabled-network-link {:status :disabled
|
||||
:chain-id chain-id
|
||||
:network (utils/id->network chain-id)}]
|
||||
(vector-utils/insert-element-at acc-network-links disabled-network-link index)))
|
||||
network-links
|
||||
sorted-networks)))
|
||||
|
||||
(defn networks-drawer
|
||||
[{:keys [fetch-routes theme]}]
|
||||
(let [network-details (rf/sub [:wallet/network-details])
|
||||
@@ -90,7 +118,9 @@
|
||||
:customization-color color}}]])))
|
||||
|
||||
(defn route-item
|
||||
[{:keys [amount from-network to-network status theme fetch-routes]}]
|
||||
[{:keys [first-item? from-amount to-amount token-symbol from-chain-id to-chain-id from-network
|
||||
to-network on-press-from-network on-press-to-network status theme fetch-routes disabled?
|
||||
loading?]}]
|
||||
(if (= status :add)
|
||||
[quo/network-bridge
|
||||
{:status :add
|
||||
@@ -99,59 +129,115 @@
|
||||
{:content (fn [] [networks-drawer
|
||||
{:theme theme
|
||||
:fetch-routes fetch-routes}])}])}]
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[rn/view {:style (style/routes-inner-container first-item?)}
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
{:amount (str from-amount " " token-symbol)
|
||||
:network from-network
|
||||
:status status
|
||||
:on-press #(when (and on-press-from-network (not loading?))
|
||||
(on-press-from-network from-chain-id from-amount))}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[rn/view {:style {:flex 1}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
:status status
|
||||
:container-style {:right 12}}]]))
|
||||
{:amount (str to-amount " " token-symbol)
|
||||
:network to-network
|
||||
:status (cond
|
||||
(and disabled? loading?) :loading
|
||||
(and disabled? (not loading?)) :default
|
||||
:else status)
|
||||
:on-press #(when (and on-press-to-network (not loading?))
|
||||
(on-press-to-network to-chain-id to-amount))}]]))
|
||||
|
||||
(defn- render-network-link
|
||||
[item index _
|
||||
{:keys [from-values-by-chain to-values-by-chain theme fetch-routes on-press-from-network
|
||||
on-press-to-network token-symbol loading-suggested-routes?]}]
|
||||
(let [first-item? (zero? index)
|
||||
disabled-network? (= (:status item) :disabled)
|
||||
from-chain-id (get-in item [:from :chain-id])
|
||||
to-chain-id (get-in item [:to :chain-id])
|
||||
from-amount (when from-chain-id
|
||||
(from-values-by-chain from-chain-id))
|
||||
to-amount (when to-chain-id
|
||||
(to-values-by-chain to-chain-id))]
|
||||
[route-item
|
||||
{:first-item? first-item?
|
||||
:from-amount (if disabled-network? 0 from-amount)
|
||||
:to-amount (if disabled-network? 0 to-amount)
|
||||
:token-symbol token-symbol
|
||||
:disabled? disabled-network?
|
||||
:loading? loading-suggested-routes?
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:status (cond
|
||||
(= (:status item) :add) :add
|
||||
(= (:status item) :disabled) :disabled
|
||||
loading-suggested-routes? :loading
|
||||
:else :default)
|
||||
:from-chain-id (or from-chain-id (:chain-id item))
|
||||
:to-chain-id (or to-chain-id (:chain-id item))
|
||||
:from-network (cond (and loading-suggested-routes?
|
||||
(not disabled-network?))
|
||||
(utils/id->network item)
|
||||
disabled-network?
|
||||
(utils/id->network (:chain-id
|
||||
item))
|
||||
:else
|
||||
(utils/id->network from-chain-id))
|
||||
:to-network (cond (and loading-suggested-routes?
|
||||
(not disabled-network?))
|
||||
(utils/id->network item)
|
||||
disabled-network?
|
||||
(utils/id->network (:chain-id
|
||||
item))
|
||||
:else
|
||||
(utils/id->network to-chain-id))
|
||||
:on-press-from-network on-press-from-network
|
||||
:on-press-to-network on-press-to-network}]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [amount routes token input-value theme fetch-routes]}]
|
||||
(let [selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
loading-networks (find-affordable-networks token input-value selected-networks)
|
||||
[{:keys [from-values-by-chain to-values-by-chain routes token theme fetch-routes
|
||||
affordable-networks disabled-from-networks on-press-from-network on-press-to-network]}]
|
||||
(let [token-symbol (:symbol token)
|
||||
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
data (if loading-suggested-routes? loading-networks routes)]
|
||||
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty routes))
|
||||
[rn/flat-list
|
||||
{:data (if (and (< (count data) 3) (pos? (count data)))
|
||||
(concat data [{:status :add}])
|
||||
data)
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/from-label)
|
||||
:container-style (style/section-label 0)}]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/to-label)
|
||||
:container-style (style/section-label 64)}]]
|
||||
:render-fn (fn [item]
|
||||
[route-item
|
||||
{:amount amount
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:status (cond
|
||||
(= (:status item) :add) :add
|
||||
loading-suggested-routes? :loading
|
||||
:else :default)
|
||||
:from-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(utils/id->network (get-in item [:from :chain-id])))
|
||||
:to-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(utils/id->network (get-in item
|
||||
[:to :chain-id])))}])}]
|
||||
network-links (if loading-suggested-routes? affordable-networks routes)]
|
||||
(if (or (and (not-empty affordable-networks) loading-suggested-routes?) (not-empty routes))
|
||||
(let [initial-network-links-count (count network-links)
|
||||
disabled-count (count disabled-from-networks)
|
||||
network-links (if (not-empty disabled-from-networks)
|
||||
(add-disabled-networks network-links
|
||||
disabled-from-networks
|
||||
loading-suggested-routes?)
|
||||
network-links)
|
||||
network-links-with-add-button (if (and (< (- (count network-links) disabled-count)
|
||||
constants/default-network-count)
|
||||
(pos? initial-network-links-count))
|
||||
(concat network-links [{:status :add}])
|
||||
network-links)]
|
||||
[rn/flat-list
|
||||
{:data network-links-with-add-button
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/from-label)
|
||||
:container-style style/section-label-left}]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/to-label)
|
||||
:container-style style/section-label-right}]]
|
||||
:render-data {:from-values-by-chain from-values-by-chain
|
||||
:to-values-by-chain to-values-by-chain
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:on-press-from-network on-press-from-network
|
||||
:on-press-to-network on-press-to-network
|
||||
:token-symbol token-symbol
|
||||
:loading-suggested-routes? loading-suggested-routes?}
|
||||
:render-fn render-network-link}])
|
||||
[rn/view {:style style/empty-container}
|
||||
(when (and (not (nil? routes)) (not loading-suggested-routes?))
|
||||
[quo/text (i18n/label :t/no-routes-found)])])))
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
(rf/dispatch [:wallet/clean-selected-token])
|
||||
(rf/dispatch [:wallet/clean-selected-collectible])
|
||||
(rf/dispatch [:wallet/clean-send-address])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:wallet/select-address-tab nil])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
on-change-tab #(rf/dispatch [:wallet/select-address-tab %])
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
[input-amount/view
|
||||
{:current-screen-id :screen/wallet.send-input-amount
|
||||
:button-one-label (i18n/label :t/confirm)
|
||||
:on-navigate-back #(rf/dispatch [:navigate-back])}])
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:navigate-back]))}])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-confirmation.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[native-module.core :as native-module]
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- transaction-title
|
||||
[{:keys [token-symbol amount account to-address route to-network image-url transaction-type
|
||||
[{:keys [token-display-name amount account to-address route to-network image-url transaction-type
|
||||
collectible?]}]
|
||||
(let [to-network-name (:network-name to-network)
|
||||
to-network-color (if (= to-network-name :mainnet) :ethereum to-network-name)]
|
||||
@@ -32,8 +30,8 @@
|
||||
(i18n/label :t/bridge)
|
||||
(i18n/label :t/send))]
|
||||
[quo/summary-tag
|
||||
{:token (if collectible? "" token-symbol)
|
||||
:label (str amount " " token-symbol)
|
||||
{:token (if collectible? "" token-display-name)
|
||||
:label (str amount " " token-display-name)
|
||||
:type (if collectible? :collectible :token)
|
||||
:image-source (if collectible? image-url :eth)}]]
|
||||
(if (= transaction-type :bridge)
|
||||
@@ -125,84 +123,34 @@
|
||||
:emoji (:emoji account)
|
||||
:customization-color (:color account)}]])]))
|
||||
|
||||
(defn network-name-from-chain-id
|
||||
[chain-id]
|
||||
(let [network-name (-> (rf/sub [:wallet/network-details-by-chain-id chain-id])
|
||||
:network-name)]
|
||||
(if (= network-name :mainnet) :ethereum network-name)))
|
||||
|
||||
(defn- network-amounts-from-route
|
||||
[{:keys [route token-symbol token-decimals to?]}]
|
||||
(reduce (fn [acc path]
|
||||
(let [network (if to? (:to path) (:from path))
|
||||
chain-id (:chain-id network)
|
||||
amount-hex (if to? (:amount-in path) (:amount-out path))
|
||||
amount-units (native-module/hex-to-number
|
||||
(utils.hex/normalize-hex amount-hex))
|
||||
amount (money/with-precision
|
||||
(if (= token-symbol "ETH")
|
||||
(money/wei->ether amount-units)
|
||||
(money/token->unit amount-units
|
||||
token-decimals))
|
||||
6)
|
||||
network-name (network-name-from-chain-id chain-id)]
|
||||
(merge-with money/add acc {network-name amount})))
|
||||
{}
|
||||
route))
|
||||
|
||||
(defn- network-values-from-amounts
|
||||
[network-amounts token-symbol]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc
|
||||
k
|
||||
{:amount v
|
||||
:token-symbol token-symbol}))
|
||||
{}
|
||||
network-amounts))
|
||||
|
||||
(defn- sanitize-network-values
|
||||
[network-values]
|
||||
(into {}
|
||||
(map (fn [[k v]]
|
||||
[k
|
||||
(if (money/equal-to (v :amount) 0)
|
||||
(assoc v :amount "<0.01")
|
||||
v)])
|
||||
network-values)))
|
||||
|
||||
(defn- values-by-network
|
||||
[{:keys [collectible amount token-symbol route token-decimals to?]}]
|
||||
(if collectible
|
||||
(let [collectible-chain-id (get-in collectible [:id :contract-id :chain-id])
|
||||
network-name (network-name-from-chain-id collectible-chain-id)]
|
||||
{network-name {:amount amount :token-symbol token-symbol}})
|
||||
(let [network-amounts (network-amounts-from-route {:route route
|
||||
:token-symbol token-symbol
|
||||
:token-decimals token-decimals
|
||||
:to? to?})
|
||||
network-values (network-values-from-amounts network-amounts token-symbol)]
|
||||
(sanitize-network-values network-values))))
|
||||
|
||||
(defn- user-summary
|
||||
[{:keys [account-props theme label accessibility-label
|
||||
summary-type network-values]
|
||||
:as _props}]
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-bottom 16}}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label accessibility-label}
|
||||
label]
|
||||
[quo/summary-info
|
||||
{:type summary-type
|
||||
:networks? true
|
||||
:values network-values
|
||||
:account-props account-props}]])
|
||||
[{:keys [network-values token-display-name account-props theme label accessibility-label
|
||||
summary-type]}]
|
||||
(let [network-values
|
||||
(reduce-kv
|
||||
(fn [acc chain-id amount]
|
||||
(let [network-name (wallet-utils/id->network chain-id)]
|
||||
(assoc acc
|
||||
(if (= network-name :mainnet) :ethereum network-name)
|
||||
{:amount amount :token-symbol token-display-name})))
|
||||
{}
|
||||
network-values)]
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-bottom 16}}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label accessibility-label}
|
||||
label]
|
||||
[quo/summary-info
|
||||
{:type summary-type
|
||||
:networks? true
|
||||
:values network-values
|
||||
:account-props account-props}]]))
|
||||
|
||||
(defn data-item
|
||||
(defn- data-item
|
||||
[{:keys [title subtitle]}]
|
||||
[quo/data-item
|
||||
{:container-style style/detail-item
|
||||
@@ -217,7 +165,8 @@
|
||||
:subtitle subtitle}])
|
||||
|
||||
(defn- transaction-details
|
||||
[{:keys [estimated-time-min max-fees token-symbol amount to-address to-network route transaction-type
|
||||
[{:keys [estimated-time-min max-fees token-display-name amount to-address to-network route
|
||||
transaction-type
|
||||
theme]}]
|
||||
(let [currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
route-loaded? (and route (seq route))
|
||||
@@ -253,56 +202,42 @@
|
||||
(i18n/label :t/bridged-to
|
||||
{:network (:abbreviated-name to-network)})
|
||||
(i18n/label :t/user-gets {:name (utils/get-shortened-address to-address)}))
|
||||
:subtitle (str amount " " token-symbol)}]]
|
||||
:subtitle (str amount " " token-display-name)}]]
|
||||
:else
|
||||
[quo/text {:style {:align-self :center}}
|
||||
(i18n/label :t/no-routes-found-confirmation)])]]))
|
||||
|
||||
(defn collectible-token-symbol
|
||||
[collectible]
|
||||
(let [collection-data (:collection-data collectible)
|
||||
collectible-data (:collectible-data collectible)
|
||||
collectible-id (get-in collectible [:id :token-id])]
|
||||
(first (remove
|
||||
string/blank?
|
||||
[(:name collectible-data)
|
||||
(str (:name collection-data) " #" collectible-id)]))))
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [on-close (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(rf/dispatch [:navigate-back]))]
|
||||
(fn [{:keys [theme]}]
|
||||
(let [send-transaction-data (rf/sub [:wallet/wallet-send])
|
||||
{:keys [token collectible amount route
|
||||
to-address bridge-to-chain-id]} send-transaction-data
|
||||
collectible? (some? collectible)
|
||||
token-symbol (if collectible
|
||||
(collectible-token-symbol collectible)
|
||||
(:symbol token))
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
image-url (when collectible
|
||||
(get-in collectible [:preview-url :uri]))
|
||||
transaction-type (:tx-type send-transaction-data)
|
||||
estimated-time-min (reduce + (map :estimated-time route))
|
||||
max-fees "-"
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)
|
||||
bridge-to-network (when bridge-to-chain-id
|
||||
(rf/sub [:wallet/network-details-by-chain-id
|
||||
bridge-to-chain-id]))
|
||||
from-account-props {:customization-color account-color
|
||||
:size 32
|
||||
:emoji (:emoji account)
|
||||
:type :default
|
||||
:name (:name account)
|
||||
:address (utils/get-shortened-address
|
||||
(:address
|
||||
account))}
|
||||
user-props {:full-name to-address
|
||||
:address (utils/get-shortened-address
|
||||
to-address)}]
|
||||
(let [send-transaction-data (rf/sub [:wallet/wallet-send])
|
||||
{:keys [token-display-name collectible amount route
|
||||
to-address bridge-to-chain-id
|
||||
from-values-by-chain
|
||||
to-values-by-chain]} send-transaction-data
|
||||
collectible? (some? collectible)
|
||||
image-url (when collectible
|
||||
(get-in collectible [:preview-url :uri]))
|
||||
transaction-type (:tx-type send-transaction-data)
|
||||
estimated-time-min (reduce + (map :estimated-time route))
|
||||
max-fees "-"
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)
|
||||
bridge-to-network (when bridge-to-chain-id
|
||||
(rf/sub [:wallet/network-details-by-chain-id
|
||||
bridge-to-chain-id]))
|
||||
from-account-props {:customization-color account-color
|
||||
:size 32
|
||||
:emoji (:emoji account)
|
||||
:type :default
|
||||
:name (:name account)
|
||||
:address (utils/get-shortened-address (:address
|
||||
account))}
|
||||
user-props {:full-name to-address
|
||||
:address (utils/get-shortened-address to-address)}]
|
||||
[rn/view {:style {:flex 1}}
|
||||
[floating-button-page/view
|
||||
{:footer-container-padding 0
|
||||
@@ -329,29 +264,26 @@
|
||||
:customization-color (:color account)}
|
||||
[rn/view
|
||||
[transaction-title
|
||||
{:token-symbol token-symbol
|
||||
:amount amount
|
||||
:account account
|
||||
:to-address to-address
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
{:token-display-name token-display-name
|
||||
:amount amount
|
||||
:account account
|
||||
:to-address to-address
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
[user-summary
|
||||
{:summary-type :status-account
|
||||
{:token-display-name token-display-name
|
||||
:summary-type :status-account
|
||||
:accessibility-label :summary-from-label
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:network-values from-values-by-chain
|
||||
:account-props from-account-props
|
||||
:theme theme
|
||||
:network-values (values-by-network {:collectible collectible
|
||||
:amount amount
|
||||
:token-symbol token-symbol
|
||||
:route route
|
||||
:token-decimals token-decimals
|
||||
:to? false})}]
|
||||
:theme theme}]
|
||||
[user-summary
|
||||
{:summary-type (if (= transaction-type :bridge)
|
||||
{:token-display-name token-display-name
|
||||
:summary-type (if (= transaction-type :bridge)
|
||||
:status-account
|
||||
:account)
|
||||
:accessibility-label :summary-to-label
|
||||
@@ -359,17 +291,12 @@
|
||||
:account-props (if (= transaction-type :bridge)
|
||||
from-account-props
|
||||
user-props)
|
||||
:theme theme
|
||||
:network-values (values-by-network {:collectible collectible
|
||||
:amount amount
|
||||
:token-symbol token-symbol
|
||||
:route route
|
||||
:token-decimals token-decimals
|
||||
:to? true})}]
|
||||
:network-values to-values-by-chain
|
||||
:theme theme}]
|
||||
[transaction-details
|
||||
{:estimated-time-min estimated-time-min
|
||||
:max-fees max-fees
|
||||
:token-symbol token-symbol
|
||||
:token-display-name token-display-name
|
||||
:amount amount
|
||||
:to-address to-address
|
||||
:to-network bridge-to-network
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
(ns status-im.contexts.wallet.send.utils
|
||||
(:require [utils.money :as money]))
|
||||
(:require
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[native-module.core :as native-module]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn amount-in-hex
|
||||
[amount token-decimal]
|
||||
@@ -20,3 +23,27 @@
|
||||
value1)))
|
||||
{}
|
||||
transaction-hashes))
|
||||
|
||||
(defn network-amounts-by-chain
|
||||
[{:keys [route token-decimals native-token? to?]}]
|
||||
(reduce (fn [acc path]
|
||||
(let [amount-hex (if to? (:amount-in path) (:amount-out path))
|
||||
amount-units (native-module/hex-to-number
|
||||
(utils.hex/normalize-hex amount-hex))
|
||||
amount (money/with-precision
|
||||
(if native-token?
|
||||
(money/wei->ether amount-units)
|
||||
(money/token->unit amount-units
|
||||
token-decimals))
|
||||
6)
|
||||
chain-id (if to? (get-in path [:to :chain-id]) (get-in path [:from :chain-id]))]
|
||||
(update acc chain-id money/add amount)))
|
||||
{}
|
||||
route))
|
||||
|
||||
(defn network-values-for-ui
|
||||
[amounts]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc k (if (money/equal-to v 0) "<0.01" v)))
|
||||
{}
|
||||
amounts))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.contexts.wallet.send.utils-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[status-im.contexts.wallet.send.utils :as utils]))
|
||||
[status-im.contexts.wallet.send.utils :as utils]
|
||||
[utils.money :as money]))
|
||||
|
||||
(deftest test-amount-in-hex
|
||||
(testing "Test amount-in-hex function"
|
||||
@@ -27,3 +28,68 @@
|
||||
"0x11" {:status :pending
|
||||
:id 61
|
||||
:chain-id :420}})))))
|
||||
|
||||
(deftest test-network-amounts-by-chain
|
||||
(testing "Correctly calculates network amounts for transaction with native token"
|
||||
(let [route [{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "1"}}
|
||||
{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "2"}}]
|
||||
token-decimals 18
|
||||
native-token? true
|
||||
to? true
|
||||
result (utils/network-amounts-by-chain {:route route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:to? to?})
|
||||
expected {"1" (money/bignumber "1")
|
||||
"2" (money/bignumber "1")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is (money/equal-to (get result chain-id) exp-value)))))
|
||||
|
||||
(testing
|
||||
"Correctly calculates network amounts for transaction with native token and multiple routes to same chain-id"
|
||||
(let [route [{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "1"}}
|
||||
{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "1"}}]
|
||||
token-decimals 18
|
||||
native-token? true
|
||||
to? true
|
||||
result (utils/network-amounts-by-chain {:route route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:to? to?})
|
||||
expected {"1" (money/bignumber "2")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is (money/equal-to (get result chain-id) exp-value)))))
|
||||
|
||||
(testing "Correctly calculates network amounts for transaction with non-native token"
|
||||
(let [route [{:amount-out "0x1e8480"
|
||||
:from {:chain-id "1"}}
|
||||
{:amount-out "0x1e8480"
|
||||
:from {:chain-id "2"}}]
|
||||
token-decimals 6
|
||||
native-token? false
|
||||
to? false
|
||||
result (utils/network-amounts-by-chain {:route route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:to? to?})
|
||||
expected {"1" (money/bignumber "2")
|
||||
"2" (money/bignumber "2")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is (money/equal-to (get result chain-id) exp-value))))))
|
||||
|
||||
(deftest test-network-values-for-ui
|
||||
(testing "Sanitizes values correctly for display"
|
||||
(let [amounts {"1" (money/bignumber "0")
|
||||
"2" (money/bignumber "2.5")
|
||||
"3" (money/bignumber "0.005")}
|
||||
result (utils/network-values-for-ui amounts)
|
||||
expected {"1" "<0.01"
|
||||
"2" (money/bignumber "2.5")
|
||||
"3" (money/bignumber "0.005")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is #(or (= (get result chain-id) exp-value)
|
||||
(money/equal-to (get result chain-id) exp-value)))))))
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
(ns status-im.contexts.wallet.sheets.buy-token.style)
|
||||
|
||||
(def list-container
|
||||
{:padding-horizontal 8
|
||||
:padding-bottom 8})
|
||||
@@ -0,0 +1,15 @@
|
||||
(ns status-im.contexts.wallet.sheets.buy-token.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.common.temp :as temp]
|
||||
[status-im.contexts.wallet.sheets.buy-token.style :as style]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/buy-tokens)}]
|
||||
[rn/flat-list
|
||||
{:data temp/buy-tokens-list
|
||||
:style style/list-container
|
||||
:render-fn quo/settings-item}]])
|
||||
@@ -10,6 +10,7 @@
|
||||
[status-im.common.json-rpc.events]
|
||||
status-im.common.log
|
||||
status-im.common.password-authentication.events
|
||||
status-im.common.shared-urls.events
|
||||
status-im.common.signals.events
|
||||
status-im.common.theme.events
|
||||
[status-im.common.toasts.events]
|
||||
@@ -39,6 +40,7 @@
|
||||
status-im.contexts.wallet.send.events
|
||||
status-im.contexts.wallet.signals
|
||||
[status-im.db :as db]
|
||||
status-im.navigation.effects
|
||||
status-im.navigation.events
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
|
||||
(defonce ^:private feature-flags-config
|
||||
(reagent/atom
|
||||
{::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
|
||||
::wallet.edit-derivation-path (enabled-in-env? :FLAG_EDIT_DERIVATION_PATH)
|
||||
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
|
||||
::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)}))
|
||||
{::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
|
||||
::wallet.edit-derivation-path (enabled-in-env? :FLAG_EDIT_DERIVATION_PATH)
|
||||
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
|
||||
::wallet.long-press-watch-only-asset (enabled-in-env? :FLAG_LONG_PRESS_WATCH_ONLY_ASSET_ENABLED)
|
||||
::wallet.assets-modal-manage-tokens (enabled-in-env? :FLAG_ASSETS_MODAL_MANAGE_TOKENS)
|
||||
::wallet.assets-modal-hide (enabled-in-env? :FLAG_ASSETS_MODAL_HIDE)
|
||||
::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)}))
|
||||
|
||||
(defn feature-flags [] @feature-flags-config)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.navigation :as navigation]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[status-im.contexts.shell.jump-to.constants :as shell.constants]
|
||||
[status-im.contexts.shell.jump-to.utils :as jump-to.utils]
|
||||
[status-im.navigation.options :as options]
|
||||
@@ -183,6 +184,19 @@
|
||||
|
||||
(rf/reg-fx :open-modal-fx open-modal)
|
||||
|
||||
;;;; Share
|
||||
|
||||
(rf/reg-fx :effects.share/open
|
||||
(fn [{:keys [options on-success on-error]}]
|
||||
(cond-> (share/open options)
|
||||
(fn? on-success) (.then on-success)
|
||||
:always (.catch (fn [error]
|
||||
(log/error "Failed to share content"
|
||||
{:error error
|
||||
:effect :effects.share/open})
|
||||
(when (fn? on-error)
|
||||
(on-error error)))))))
|
||||
|
||||
;;;; Overlay
|
||||
|
||||
(defn show-overlay
|
||||
|
||||
@@ -144,3 +144,9 @@
|
||||
{:events [:reload-status-nav-color]}
|
||||
[{:keys [db]} view-id]
|
||||
{:reload-status-nav-color-fx (or view-id (:view-id db))})
|
||||
|
||||
(defn open-share
|
||||
[_ [config]]
|
||||
{:fx [[:effects.share/open config]]})
|
||||
|
||||
(rf/reg-event-fx :open-share open-share)
|
||||
|
||||
@@ -241,6 +241,12 @@
|
||||
:message-pin-enabled message-pin-enabled
|
||||
:can-delete-message-for-everyone? can-delete-message-for-everyone?})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/current-chat-one-to-one?
|
||||
:<- [:chats/current-raw-chat]
|
||||
(fn [{:keys [chat-type]}]
|
||||
(= chat-type constants/one-to-one-chat-type)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/photo-path
|
||||
:<- [:contacts/contacts]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.communities.utils :as utils]
|
||||
[status-im.subs.chat.utils :as subs.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
@@ -325,11 +326,12 @@
|
||||
(let [sym (:symbol criteria)
|
||||
amount-in-wei (:amountInWei criteria)
|
||||
decimals (:decimals criteria)]
|
||||
{:symbol sym
|
||||
:sufficient? satisfied
|
||||
:loading? checking-permissions?
|
||||
:amount (money/to-fixed (money/token->unit amount-in-wei decimals))
|
||||
:img-src (get token-images sym)}))
|
||||
{:symbol sym
|
||||
:sufficient? satisfied
|
||||
:collectible? (= (:type criteria) constants/community-token-type-erc721)
|
||||
:loading? checking-permissions?
|
||||
:amount (money/to-fixed (money/token->unit amount-in-wei decimals))
|
||||
:img-src (get token-images sym)}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:communities/checking-permissions-by-id
|
||||
@@ -407,6 +409,7 @@
|
||||
roles)]
|
||||
(mapv (fn [role]
|
||||
{:role (:type role)
|
||||
:role-text (i18n/label (utils/role->translation-key (:type role)))
|
||||
:satisfied? (:satisfied role)
|
||||
:tokens (map (fn [{:keys [tokenRequirement]}]
|
||||
(map
|
||||
|
||||
@@ -321,15 +321,17 @@
|
||||
(swap! rf-db/app-db assoc-in [:communities/permissions-check community-id] checks)
|
||||
(is (match? {:can-request-access? true
|
||||
:networks-not-supported? nil
|
||||
:tokens [[{:symbol "DAI"
|
||||
:amount "5"
|
||||
:sufficient? true
|
||||
:loading? checking-permissions?}]
|
||||
[{:symbol "ETH"
|
||||
:amount "0.002"
|
||||
:sufficient? false
|
||||
:loading? checking-permissions?
|
||||
:img-src token-image-eth}]]}
|
||||
:tokens [[{:symbol "DAI"
|
||||
:amount "5"
|
||||
:collectible? false
|
||||
:sufficient? true
|
||||
:loading? checking-permissions?}]
|
||||
[{:symbol "ETH"
|
||||
:amount "0.002"
|
||||
:collectible? false
|
||||
:sufficient? false
|
||||
:loading? checking-permissions?
|
||||
:img-src token-image-eth}]]}
|
||||
(rf/sub [sub-name community-id])))))
|
||||
|
||||
(h/deftest-sub :communities/community-color
|
||||
@@ -417,18 +419,20 @@
|
||||
(match? [{:role 1
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "ETH"
|
||||
:sufficient? true
|
||||
:loading? false
|
||||
:amount "1"
|
||||
:img-src token-image-eth}]]}
|
||||
[[{:symbol "ETH"
|
||||
:sufficient? true
|
||||
:loading? false
|
||||
:collectible? false
|
||||
:amount "1"
|
||||
:img-src token-image-eth}]]}
|
||||
{:role 2
|
||||
:satisfied? false
|
||||
:tokens [[{:symbol "DAI"
|
||||
:sufficient? false
|
||||
:loading? false
|
||||
:amount "10"
|
||||
:img-src nil}]]}]
|
||||
:tokens [[{:symbol "DAI"
|
||||
:sufficient? false
|
||||
:collectible? false
|
||||
:loading? false
|
||||
:amount "10"
|
||||
:img-src nil}]]}]
|
||||
(rf/sub [sub-name community-id])))))
|
||||
(testing
|
||||
"without any visible permissions"
|
||||
|
||||
@@ -95,6 +95,21 @@
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :token)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-disabled-from-chain-ids
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :disabled-from-chain-ids)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-from-values-by-chain
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :from-values-by-chain)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-to-values-by-chain
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :to-values-by-chain)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-loading-suggested-routes?
|
||||
:<- [:wallet/wallet-send]
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
with the 1st 5 characters of the encoded data followed by an ellipsis
|
||||
followed by the last 10 characters of the compressed public key"
|
||||
[universal-profile-url]
|
||||
(when-let [re-find-result (re-find #"^https://(status.app/u/)(.*)#(.*)$" universal-profile-url)]
|
||||
(when-let [re-find-result (re-find #"^https://(status.app/u/)(.*)#(.*)$" (str universal-profile-url))]
|
||||
(let [[_whole-url base-url encoded-data public-key] re-find-result]
|
||||
(when (> (count public-key) 9)
|
||||
(let [first-part-of-encoded-data (subs encoded-data 0 5)
|
||||
|
||||
@@ -35,4 +35,7 @@
|
||||
"https://status.app/uwu/abcdefg#zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa"))))
|
||||
|
||||
(testing "Ensure the function returns nil when given a public key shorter than 10 characters"
|
||||
(is (nil? (utils.address/get-abbreviated-profile-url "https://status.app/u/abcdefg#012345678")))))
|
||||
(is (nil? (utils.address/get-abbreviated-profile-url "https://status.app/u/abcdefg#012345678"))))
|
||||
|
||||
(testing "Ensure the function returns nil when given nil"
|
||||
(is (nil? (utils.address/get-abbreviated-profile-url nil)))))
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
(ns utils.vector)
|
||||
|
||||
(defn insert-element-at
|
||||
[data element index]
|
||||
(let [before (take index data)
|
||||
after (drop index data)]
|
||||
(vec (concat before [element] after))))
|
||||
@@ -0,0 +1,17 @@
|
||||
(ns utils.vector-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[utils.vector :as vector]))
|
||||
|
||||
(deftest test-insert-element-at
|
||||
(testing "Inserting into an empty vector"
|
||||
(is (= [42] (vector/insert-element-at [] 42 0))))
|
||||
|
||||
(testing "Inserting at the beginning of a vector"
|
||||
(is (= [42 1 2 3] (vector/insert-element-at [1 2 3] 42 0))))
|
||||
|
||||
(testing "Inserting in the middle of a vector"
|
||||
(is (= [1 42 2 3] (vector/insert-element-at [1 2 3] 42 1))))
|
||||
|
||||
(testing "Inserting at the end of a vector"
|
||||
(is (= [1 2 3 42] (vector/insert-element-at [1 2 3] 42 3)))))
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.179.3",
|
||||
"commit-sha1": "b744ff4386751bd3e7cb8e30164678a8d557fbc2",
|
||||
"src-sha256": "1yj76khas4g8xbgp2ymr1hwga662hsjmzpgb95x34vl42hdpirns"
|
||||
"version": "v0.179.4",
|
||||
"commit-sha1": "d246699c5e1c19b3f905a6c10c3526d2004de273",
|
||||
"src-sha256": "0gnnx70g8g8yhn29qj58if91fflgl0q2ry0wipzvvpdxd07hpxin"
|
||||
}
|
||||
|
||||
@@ -404,6 +404,8 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(703495)
|
||||
@marks.xfail(
|
||||
reason="Chat is not unmuted after expected time: https://github.com/status-im/status-mobile/issues/19627")
|
||||
def test_group_chat_mute_chat(self):
|
||||
[self.homes[i].navigate_back_to_home_view() for i in range(3)]
|
||||
|
||||
|
||||
@@ -782,7 +782,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.just_fyi("Receiver is checking if initial messages were delivered")
|
||||
for message in message_to_edit, message_to_delete:
|
||||
if not self.channel_1.chat_element_by_text(message).is_element_displayed(30):
|
||||
self.channel_1.driver.fail("Message '%s' was not received")
|
||||
self.channel_1.driver.fail("Message '%s' was not received" % message)
|
||||
|
||||
self.channel_2.just_fyi("Turning on airplane mode and editing/deleting messages")
|
||||
self.channel_2.driver.set_network_connection(ConnectionType.AIRPLANE_MODE)
|
||||
|
||||
@@ -52,8 +52,8 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
"Status mobile QA community max",
|
||||
"https://status.app/c/G1AAAGR0G-IRb2YJD4lRXwLusAFnGrDHGNl6Wt55MIARwVYvarnO873011-fdVSz1kHSan-qq0G96vOaMqyTRhJnQV74KCUr#zQ3shb9irJR66rhG1E8sQZX8pDU3dpGm4daYSmPVDd2e73ewE":
|
||||
"Open community for e2e",
|
||||
"https://status.app/c/G00AAGS9TbI9mSR-ZNmFrhRjNuEeXAAbcAIUaLLJyjMOG3ACJQ12oIHD78QhzO9s_T5bUeU7rnATWJg3mGgTUemrAg==#zQ3shspPKCZ1VPVQ9dLXGufUGvGphjxVwrcZ6rkZc7S39T4b3":
|
||||
"closed community"
|
||||
"https://status.app/c/GzAAAORtwyW4xNWM4td0F7hOnYZ1apSqCCRUUR0qxD19n3Ec97fX_aIVIGFWbdUM#zQ3shk6dgK8dYWWSC4m8Jj5c91zyfhfj1fFkgypS8D9gsXkrK":
|
||||
"Closed community"
|
||||
}
|
||||
for url, text in closed_community_urls.items():
|
||||
self.channel.just_fyi("Opening community '%s' by the url %s" % (text, url))
|
||||
@@ -97,8 +97,8 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
"Status mobile QA community max",
|
||||
"status.app://c/G1AAAGR0G-IRb2YJD4lRXwLusAFnGrDHGNl6Wt55MIARwVYvarnO873011-fdVSz1kHSan-qq0G96vOaMqyTRhJnQV74KCUr#zQ3shb9irJR66rhG1E8sQZX8pDU3dpGm4daYSmPVDd2e73ewE":
|
||||
"Open community for e2e",
|
||||
"status.app://c/G00AAGS9TbI9mSR-ZNmFrhRjNuEeXAAbcAIUaLLJyjMOG3ACJQ12oIHD78QhzO9s_T5bUeU7rnATWJg3mGgTUemrAg==#zQ3shspPKCZ1VPVQ9dLXGufUGvGphjxVwrcZ6rkZc7S39T4b3":
|
||||
"closed community"
|
||||
"status.app://c/GzAAAORtwyW4xNWM4td0F7hOnYZ1apSqCCRUUR0qxD19n3Ec97fX_aIVIGFWbdUM#zQ3shk6dgK8dYWWSC4m8Jj5c91zyfhfj1fFkgypS8D9gsXkrK":
|
||||
"Closed community"
|
||||
}
|
||||
for link, text in community_links.items():
|
||||
self.channel.just_fyi("Opening community '%s' by the link %s" % (text, link))
|
||||
|
||||
@@ -386,7 +386,6 @@ class CommunityView(HomeView):
|
||||
self.leave_community_button = Button(self.driver, translation_id="leave-community")
|
||||
self.edit_community_button = Button(self.driver, translation_id="edit-community")
|
||||
self.share_community_button = Button(self.driver, accessibility_id="share-community")
|
||||
self.share_community_link_button = Button(self.driver, accessibility_id="share-community-link")
|
||||
|
||||
# Members
|
||||
self.invite_people_button = Button(self.driver, accessibility_id="community-invite-people")
|
||||
@@ -500,8 +499,9 @@ class CommunityView(HomeView):
|
||||
community_element.long_press_until_element_is_shown(self.share_community_button)
|
||||
self.share_community_button.click()
|
||||
for user_name in user_names_to_share:
|
||||
Button(self.driver, xpath="//*[@content-desc='author-primary-name'][@text='%s']" % user_name).click()
|
||||
self.setup_chat_button.click()
|
||||
xpath = "//*[@content-desc='user-avatar']/following-sibling::android.widget.TextView[@text='%s']" % user_name
|
||||
Button(self.driver, xpath=xpath).click()
|
||||
self.share_invite_button.click()
|
||||
|
||||
|
||||
class PreviewMessage(ChatElementByText):
|
||||
|
||||
Reference in New Issue
Block a user