Compare commits

...
Author SHA1 Message Date
Ibrahem Khalil fc3e398061 Merge branch 'develop' into remove-warning-when-theres-multiple-internal-link-cards 2024-04-17 10:07:26 +02:00
Icaro Motta c81dd8e3e3 Don't treat dynamic data as a function (#19672)
Sometimes an integration test was throwing "TypeError: Cannot read properties of
null (reading 'call')" because a value was nil in the app-db, but the code was
treating it as if it was always a map and could be called as a function.

The original code wasn't respecting Clojure's nil punning good practices. In
Clojure, it's often recommended to not use dynamic data as functions, because if
they're nil, in CLJS we'll get an exception and as usual in CLJS, the stacktrace
won't be very readable.

We should prefer contains? or get, which will work just fine with nil values,
and only use data as a function if it's static, e.g. a map defined in a def.
2024-04-16 14:48:28 -03:00
Omar Basem 24f4c4a07e Remove watch-only accounts from bridging (#19569)
Remove watch-only accounts from bridging (#19569)
2024-04-16 20:33:03 +04:00
Ajay Sivan 98762c74f1 Community detail token gating component (#19532) 2024-04-16 09:11:18 -07:00
Ibrahem Khalil f3aeddb53a Update doc/troubleshooting.md (#19673) 2024-04-16 17:46:14 +02:00
mmilad75 f5fcc9f45e Wallet: Token Options should be specific to watch only account #18543 (#19583) 2024-04-16 19:02:50 +03:30
ibrkhalil f549f9949c Removes metro warning when there's multiple internal link cards 2024-04-16 17:06:37 +02:00
Parvesh Monu 9aa9dc1b4c Redirect to community channel when following universal link (#19566) 2024-04-16 20:30:24 +05:30
Sean Hagstrom 61974dae4d Implement share button inside profile settings (#19559)
* tweak: implement the share button inside the profile settings page

* chore: define event and effect handler for opening share sheet

* tidy: refactor share buttons to use open-share event

* tidy: refactor open-share effect to use react-native-share bindings

* tidy: remove unused code for old bindings to react share sheet

* tidy: move effects.share/open definition to navigation effects

* tweak: ensure navigation effects are loaded

* tidy: use open-share dispatch in ui

* tidy: use open-share dispatch instead of calling open function directly

* tidy: refactor react-native.share/open to only receive options and return promise

* tidy: refactor open-share effect to receive map of content and handlers

* tidy: replace strings with keywords

* tweak: always handle failure case when opening share-sheet

* tweak: rename :content to :options

* fix: conditionally call on-error

* tweak: add extra information when logging error from attempting to share-sheet
2024-04-16 13:26:52 +02:00
Parvesh Monu 8b3e639abd fix error on long tap on token-gated channel from the join community screen (#19652) 2024-04-16 16:33:09 +05:30
jakub 7c901fa045 ci: use virtualenv to avoid race conditions
Desktop QA tests also use Pytest packages and their versions are
different, so we can't install them globally, it needs to be done per
build using `WORKSPACE_TMP` as destination.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2024-04-16 13:13:53 +03:00
frank 8a12ad3510 fix_: logout deadlock (#19640) 2024-04-16 17:50:47 +08:00
Brian Sztamfater c8044cd2f2 fix: wallet header spacing to match other tabs (#19632) 2024-04-16 06:31:09 -03:00
Sean Hagstrom 6872d1a857 fix: do not throw exception when passing nil to utils.address/get-abbreviated-profile-url (#19593) 2024-04-16 09:51:35 +02:00
Brian Sztamfater 98d4969ca5 feat: add ability to tap to disable from networks (#19392) 2024-04-15 12:04:44 -03:00
Parvesh Monu 5412092ca1 fix zero addresses are selected by default when joining a community (#19626) 2024-04-15 17:30:31 +05:30
Parvesh Monu a8695116e2 fix error is shown after scan button is tapped on the browser page (#19601) 2024-04-15 15:24:09 +05:30
Yevheniia Berdnyk 76773a4165 e2e: fix for sharing community flow 2024-04-15 12:11:24 +03:00
yqrashawn 32fc7b14e8 fix: add/rename missing sub :current-chat/one-to-one-chat? (#19628)
Signed-off-by: yqrashawn <namy.19@gmail.com>
2024-04-15 17:10:12 +08:00
Sean Hagstrom 82a8f9f44d fix: rewire legacy community share button to send invites (#19622) 2024-04-15 10:52:18 +02:00
John Ngei 8df72d0c29 updated standard auth drawer title size and weight 2024-04-13 23:04:49 +02:00
Mohsen 794cd57961 [#19299] fix: design feedback for settings screen (#19609) 2024-04-12 19:37:07 +03:00
John Ngei 6bc29088ab fix: community spacing issues in token gating community page
* fix: community spacing issues in token gating community page

* fix: spacing issues between token rows
2024-04-12 17:35:03 +02:00
90 changed files with 1604 additions and 744 deletions
+8 -1
View File
@@ -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'
}
} }
}
+8 -1
View File
@@ -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'
}
} }
}
+7 -1
View File
@@ -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'
}
} }
}
+16
View File
@@ -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)])
+7 -6
View File
@@ -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})
+134 -65
View File
@@ -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}]
+2
View File
@@ -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)
+1
View File
@@ -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
-4
View File
@@ -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)))
+1 -5
View File
@@ -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)))))
+6 -5
View File
@@ -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]]
+16 -4
View File
@@ -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)
+2
View File
@@ -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
+7 -5
View File
@@ -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"
+2
View File
@@ -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.")
+1 -2
View File
@@ -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
@@ -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}]
]))
+30 -40
View File
@@ -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))))))
+1 -6
View File
@@ -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
+11 -11
View File
@@ -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})
+77 -27
View File
@@ -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
+28 -1
View File
@@ -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}]])
+2
View File
@@ -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]))
+7 -4
View File
@@ -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)
+14
View File
@@ -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
+6
View File
@@ -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)
+6
View File
@@ -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]
+8 -5
View File
@@ -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
+23 -19
View File
@@ -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"
+15
View File
@@ -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]
+1 -1
View File
@@ -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)
+4 -1
View File
@@ -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)))))
+7
View File
@@ -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))))
+17
View File
@@ -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 -3
View File
@@ -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))
+3 -3
View File
@@ -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):