Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2883ac177d | ||
|
|
16fba373c9 | ||
|
|
9c3ff8c88c | ||
|
|
2525620730 | ||
|
|
6dde1d7b74 | ||
|
|
1691e2fe34 | ||
|
|
b536d20713 | ||
|
|
ca3720be0a | ||
|
|
63d0aaca2a | ||
|
|
3a4b58f32f | ||
|
|
d748ccdef9 | ||
|
|
97aff27980 | ||
|
|
0c3e836272 | ||
|
|
60fc4f1b9a | ||
|
|
b97e2df2fb | ||
|
|
f539bb5ca2 |
@@ -19,5 +19,5 @@
|
||||
Make sure to compress images before using into project.
|
||||
```
|
||||
make shell
|
||||
./scrips/compress_image.sh image_path
|
||||
./scripts/compress_image.sh image_path
|
||||
```
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{ lib, stdenv, meta, source, buildGoPackage }:
|
||||
{ lib, stdenv, meta, source, buildGoPackage,
|
||||
go-bindata, mockgen, protoc-gen-go, protobuf3_20 }:
|
||||
|
||||
buildGoPackage {
|
||||
pname = source.repo;
|
||||
@@ -7,6 +8,10 @@ buildGoPackage {
|
||||
inherit meta;
|
||||
inherit (source) src goPackagePath;
|
||||
|
||||
nativeBuildInputs = [
|
||||
go-bindata mockgen protoc-gen-go protobuf3_20
|
||||
];
|
||||
|
||||
phases = ["unpackPhase" "configurePhase" "buildPhase"];
|
||||
|
||||
# https://pkg.go.dev/net#hdr-Name_Resolution
|
||||
@@ -22,6 +27,7 @@ buildGoPackage {
|
||||
preBuild = ''
|
||||
pushd go/src/$goPackagePath
|
||||
go run cmd/library/*.go > $NIX_BUILD_TOP/main.go
|
||||
make generate SHELL=$SHELL GO111MODULE=on GO_GENERATE_CMD='go generate'
|
||||
popd
|
||||
'';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{ callPackage, lib, buildGoPackage
|
||||
, androidPkgs, openjdk, gomobile, xcodeWrapper, removeReferencesTo
|
||||
, go-bindata, mockgen, protobuf3_20, protoc-gen-go
|
||||
, meta
|
||||
, source
|
||||
, platform ? "android"
|
||||
@@ -15,7 +16,7 @@ let
|
||||
isAndroid = platform == "android";
|
||||
enforceXCodeAvailable = callPackage ./enforceXCodeAvailable.nix { };
|
||||
|
||||
in buildGoPackage {
|
||||
in buildGoPackage rec {
|
||||
pname = source.repo;
|
||||
version = "${source.cleanVersion}-${source.shortRev}-${platform}";
|
||||
|
||||
@@ -27,8 +28,9 @@ in buildGoPackage {
|
||||
__noChroot = isIOS;
|
||||
|
||||
extraSrcPaths = [ gomobile ];
|
||||
nativeBuildInputs = [ gomobile removeReferencesTo ]
|
||||
++ optional isAndroid openjdk
|
||||
nativeBuildInputs = [
|
||||
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20
|
||||
] ++ optional isAndroid openjdk
|
||||
++ optional isIOS xcodeWrapper;
|
||||
|
||||
ldflags = goBuildLdFlags;
|
||||
@@ -44,6 +46,13 @@ in buildGoPackage {
|
||||
# TODO: try removing when go is upgraded to 1.22
|
||||
GODEBUG = "netdns=cgo+2";
|
||||
|
||||
preBuild = ''
|
||||
echo 'Generate static files'
|
||||
pushd go/src/$goPackagePath
|
||||
make generate SHELL=$SHELL GO111MODULE=on GO_GENERATE_CMD='go generate'
|
||||
popd
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
echo -e "\nBuilding $pname for: ${concatStringsSep "," targets}"
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { useDerivedValue, withTiming, interpolate } from 'react-native-reanimated';
|
||||
|
||||
export function navigationHeaderOpacity(distanceFromListTop, isAllLoaded, isCalculationsComplete, startPosition) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const isCalculationsCompleteValue = isCalculationsComplete.value;
|
||||
if (distanceFromListTop.value < startPosition && isAllLoaded.value) {
|
||||
return isCalculationsCompleteValue ? withTiming(0) : 0;
|
||||
} else {
|
||||
return isCalculationsCompleteValue ? withTiming(1) : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function navigationHeaderPosition(distanceFromListTop, isAllLoaded, topBarHeight, startPosition) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return distanceFromListTop.value < startPosition && isAllLoaded.value ? withTiming(topBarHeight) : withTiming(0);
|
||||
});
|
||||
}
|
||||
|
||||
export function navigationButtonsCompleteOpacity(isCalculationComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationComplete.value ? withTiming(1) : 0;
|
||||
});
|
||||
}
|
||||
|
||||
export function interpolateNavigationViewOpacity(props) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const {
|
||||
'all-loaded?': isAllLoaded,
|
||||
'end-position': endPosition,
|
||||
'start-position': startPosition,
|
||||
'distance-from-list-top': distanceFromListTop,
|
||||
} = props;
|
||||
if (isAllLoaded.value) {
|
||||
return interpolate(distanceFromListTop.value, [startPosition, endPosition], [0, 1], {
|
||||
extrapolateLeft: 'clamp',
|
||||
extrapolateRight: 'clamp',
|
||||
});
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { useDerivedValue } from 'react-native-reanimated';
|
||||
|
||||
export function placeholderOpacity(isCalculationsComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationsComplete.value ? 0 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
export function placeholderZIndex(isCalculationsComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationsComplete.value ? 0 : 2;
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
(ns quo.components.buttons.wallet-ctas.style)
|
||||
(ns quo.components.buttons.wallet-ctas.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def inner-container
|
||||
{:flex-direction :row
|
||||
@@ -10,3 +11,9 @@
|
||||
:width 77.75
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(defn action-button-text
|
||||
[theme disabled?]
|
||||
(cond-> {:margin-top 4
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}
|
||||
disabled? (assoc :opacity 0.5)))
|
||||
|
||||
@@ -3,28 +3,28 @@
|
||||
[quo.components.buttons.wallet-button.view :as wallet-button]
|
||||
[quo.components.buttons.wallet-ctas.style :as style]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
|
||||
(defn action-button
|
||||
[{:keys [icon text on-press theme accessibility-label]}]
|
||||
[{:keys [icon text on-press theme accessibility-label disabled?]}]
|
||||
[rn/view
|
||||
{:style style/button-container
|
||||
:accessibility-label accessibility-label}
|
||||
[wallet-button/view
|
||||
{:icon icon
|
||||
:on-press on-press}]
|
||||
{:icon icon
|
||||
:disabled? disabled?
|
||||
:on-press on-press}]
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style {:margin-top 4
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}} text]])
|
||||
:style (style/action-button-text theme disabled?)} text]])
|
||||
|
||||
(defn view
|
||||
[{:keys [buy-action send-action receive-action bridge-action swap-action container-style]}]
|
||||
[{:keys [buy-action send-action receive-action bridge-action swap-action bridge-disabled?
|
||||
swap-disabled? container-style]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view {:style container-style}
|
||||
[rn/view {:style style/inner-container}
|
||||
@@ -52,10 +52,12 @@
|
||||
:text (i18n/label :t/swap)
|
||||
:on-press swap-action
|
||||
:theme theme
|
||||
:disabled? swap-disabled?
|
||||
:accessibility-label :swap}])
|
||||
[action-button
|
||||
{:icon :i/bridge
|
||||
:text (i18n/label :t/bridge)
|
||||
:on-press bridge-action
|
||||
:theme theme
|
||||
:disabled? bridge-disabled?
|
||||
:accessibility-label :bridge}]]]))
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
[rn/pressable
|
||||
(when-not disabled?
|
||||
{:on-press on-press
|
||||
:allow-multiple-presses? true})
|
||||
:allow-multiple-presses? true
|
||||
:hit-slop 12})
|
||||
[rn/view
|
||||
{:style outer-styles
|
||||
:needs-offscreen-alpha-compositing true
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
(defn enabled? [v] (= "1" v))
|
||||
|
||||
(goog-define INFURA_TOKEN "62f3cee52dbb484198e7339837e263f3")
|
||||
(goog-define INFURA_TOKEN "")
|
||||
(goog-define POKT_TOKEN "3ef2018191814b7e1009b8d9")
|
||||
(goog-define STATUS_BUILD_PROXY_USER "")
|
||||
(goog-define STATUS_BUILD_PROXY_PASSWORD "")
|
||||
|
||||
@@ -619,3 +619,12 @@
|
||||
(def router-error-code-not-enough-liquidity "WPP-038")
|
||||
(def router-error-code-price-impact-too-high "WPP-039")
|
||||
(def router-error-code-not-enough-native-balance "WR-002")
|
||||
|
||||
(def ^:const wallet-transaction-estimation
|
||||
{:unknown 0
|
||||
:less-than-one-minute 1
|
||||
:less-than-three-minutes 2
|
||||
:less-than-five-minutes 3
|
||||
:more-than-five-minutes 4})
|
||||
|
||||
(def ^:const wallet-connect-transaction-refresh-interval-ms 10000)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
user])
|
||||
|
||||
(defn view
|
||||
[{:keys [layout-height]}]
|
||||
[layout-height]
|
||||
(let [suggestions (rf/sub [:chat/mention-suggestions])
|
||||
suggestions? (seq suggestions)
|
||||
theme (quo.theme/use-theme)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
:default-value default-value}])))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[layout-height]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
bottom (safe-area/get-bottom)
|
||||
input-ref (rn/use-ref-atom nil)
|
||||
@@ -43,7 +43,7 @@
|
||||
(rf/dispatch [:chat/set-input-ref value])
|
||||
(reset! input-ref value)))]
|
||||
[rn/view {:style {:margin-bottom bottom}}
|
||||
[mentions/view props]
|
||||
[mentions/view layout-height]
|
||||
[quo/separator]
|
||||
[rn/view {:style {:padding-horizontal 20 :padding-top 20}}
|
||||
[:<>
|
||||
|
||||
@@ -3,15 +3,4 @@
|
||||
;;;; Navigation
|
||||
(def ^:const top-bar-height 56)
|
||||
(def ^:const pinned-banner-height 40)
|
||||
(def ^:const header-container-top-margin 48)
|
||||
(def ^:const header-container-radius 20)
|
||||
(def ^:const header-animation-distance 20)
|
||||
(def ^:const content-animation-start-position-android 130)
|
||||
(def ^:const content-animation-start-position-ios 124)
|
||||
;; Note - We should also consider height of bio for banner animation starting position
|
||||
;; Todo - Should be updated once New-profile implemation is complete
|
||||
(def ^:const pinned-banner-animation-start-position 148)
|
||||
|
||||
(def ^:const default-extrapolation-option
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"})
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.list.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.screens.chat.group :as chat.group]
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
@@ -25,8 +24,8 @@
|
||||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.messages :as worklets]))
|
||||
|
||||
(defonce ^:const distance-from-last-message 4)
|
||||
(defonce ^:const loading-indicator-page-loading-height 100)
|
||||
(def ^:const distance-from-last-message 4)
|
||||
(def ^:const loading-indicator-page-loading-height 100)
|
||||
|
||||
(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
|
||||
(defn list-ref [ref] (reset! state/messages-list-ref ref))
|
||||
@@ -60,44 +59,17 @@
|
||||
on-loaded])
|
||||
(if platform/low-device? 700 100)))))
|
||||
|
||||
(defn- contact-icon
|
||||
[{:keys [ens-verified added?]} theme]
|
||||
(when (or ens-verified added?)
|
||||
[rn/view
|
||||
{:style {:margin-left 4}}
|
||||
(if ens-verified
|
||||
[quo/icon :i/verified
|
||||
{:no-color true
|
||||
:size 20
|
||||
:color (colors/theme-colors
|
||||
(colors/custom-color :success 50)
|
||||
(colors/custom-color :success 60)
|
||||
theme)}]
|
||||
(when added?
|
||||
[quo/icon :i/contact
|
||||
{:no-color true
|
||||
:size 20
|
||||
:color (colors/theme-colors colors/primary-50 colors/primary-60 theme)}]))]))
|
||||
|
||||
(defn- skeleton-list-props
|
||||
[content parent-height animated?]
|
||||
{:content content
|
||||
:parent-height parent-height
|
||||
:animated? animated?})
|
||||
|
||||
(defn loading-view
|
||||
[chat-id {:keys [window-height]}]
|
||||
[{:keys [chat-id window-height]}]
|
||||
(let [messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
loading-first-page? (= (count messages) 0)
|
||||
top-spacing (if loading-first-page?
|
||||
0
|
||||
(+ messages.constants/top-bar-height (safe-area/get-top)))
|
||||
parent-height (if loading-first-page?
|
||||
window-height
|
||||
loading-indicator-page-loading-height)]
|
||||
[rn/view {:padding-top top-spacing}
|
||||
;; Don't use animated loading skeleton https://github.com/status-im/status-mobile/issues/17426
|
||||
[quo/skeleton-list (skeleton-list-props :messages parent-height false)]]))
|
||||
[quo/skeleton-list
|
||||
{:content :messages
|
||||
:parent-height parent-height
|
||||
:animated? false}]))
|
||||
|
||||
(defn header-height
|
||||
[{:keys [insets able-to-send-message? images reply edit link-previews? input-content-height]}]
|
||||
@@ -125,84 +97,6 @@
|
||||
(+ (:bottom insets)))
|
||||
(- 70 (:bottom insets))))
|
||||
|
||||
(defn list-header
|
||||
[insets able-to-send-message?]
|
||||
(let [header-data {:insets insets
|
||||
:able-to-send-message? able-to-send-message?
|
||||
:input-content-height (:input-content-height (rf/sub [:chats/current-chat-input]))
|
||||
:images (rf/sub [:chats/sending-image])
|
||||
:reply (rf/sub [:chats/reply-message])
|
||||
:edit (rf/sub [:chats/edit-message])
|
||||
:link-previews? (or (rf/sub [:chats/link-previews?])
|
||||
(rf/sub [:chats/status-link-previews?]))}]
|
||||
[rn/view {:style {:height (header-height header-data)}}]))
|
||||
|
||||
(defn list-footer-avatar
|
||||
[{:keys [distance-from-list-top display-name online? profile-picture theme group-chat color
|
||||
emoji chat-type chat-name empty-chat?]}]
|
||||
(let [scale (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[1 0.4]
|
||||
messages.constants/default-extrapolation-option)
|
||||
top (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[-44 -12]
|
||||
messages.constants/default-extrapolation-option)
|
||||
left (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[16 -8]
|
||||
messages.constants/default-extrapolation-option)
|
||||
community-channel? (= chat-type constants/community-chat-type)]
|
||||
[reanimated/view
|
||||
{:style (style/header-image scale top left theme)}
|
||||
(cond
|
||||
community-channel?
|
||||
[quo/channel-avatar
|
||||
{:size :size-80
|
||||
:full-name chat-name
|
||||
:customization-color color
|
||||
:emoji (when-not (string/blank? emoji)
|
||||
(string/trim emoji))}]
|
||||
group-chat
|
||||
[quo/group-avatar
|
||||
{:customization-color color
|
||||
:size :size-80
|
||||
:picture profile-picture
|
||||
:chat-name chat-name}]
|
||||
:else
|
||||
[quo/user-avatar
|
||||
{:full-name display-name
|
||||
:online? online?
|
||||
:profile-picture profile-picture
|
||||
:size :big}])]))
|
||||
|
||||
(defn chat-display-name
|
||||
[{:keys [distance-from-list-top display-name contact theme empty-chat?]}]
|
||||
(let [top (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[0 -35]
|
||||
messages.constants/default-extrapolation-option)
|
||||
left (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[0 40]
|
||||
messages.constants/default-extrapolation-option)]
|
||||
[reanimated/view
|
||||
{:style (style/user-name-container top left)}
|
||||
[rn/view
|
||||
{:style style/user-name}
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:size :heading-1
|
||||
:style {:flex-shrink 1}
|
||||
:number-of-lines 1}
|
||||
display-name]
|
||||
[contact-icon contact theme]]]))
|
||||
|
||||
(defn actions
|
||||
[chat-id cover-bg-color]
|
||||
(let [latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id])
|
||||
@@ -236,101 +130,12 @@
|
||||
chat-type
|
||||
muted?)))}]}]))
|
||||
|
||||
(defn bio-and-actions
|
||||
[{:keys [distance-from-list-top bio chat-id customization-color empty-chat? description]}]
|
||||
(let [has-bio (seq (or bio description))
|
||||
top (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[(if has-bio 8 16) (if has-bio -28 -20)]
|
||||
messages.constants/default-extrapolation-option)]
|
||||
[reanimated/view
|
||||
{:style (style/bio-and-actions top)}
|
||||
(when has-bio
|
||||
[quo/text (or bio description)])
|
||||
[actions chat-id customization-color]]))
|
||||
|
||||
(defn footer-component
|
||||
[{:keys [chat distance-from-list-top customization-color]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [chat-id chat-name emoji chat-type
|
||||
group-chat color description
|
||||
empty-chat?]} chat
|
||||
display-name (cond
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
|
||||
(= chat-type constants/community-chat-type)
|
||||
(str "# " chat-name)
|
||||
:else (str emoji chat-name))
|
||||
{:keys [bio]} (rf/sub [:contacts/contact-by-identity chat-id])
|
||||
online? (rf/sub [:visibility-status-updates/online? chat-id])
|
||||
contact (when-not group-chat
|
||||
(rf/sub [:contacts/contact-by-address chat-id]))
|
||||
photo-path (if group-chat
|
||||
(rf/sub [:chats/group-chat-image chat-id])
|
||||
(rf/sub [:chats/photo-path chat-id]))
|
||||
top-margin (+ (safe-area/get-top)
|
||||
messages.constants/top-bar-height
|
||||
messages.constants/header-container-top-margin
|
||||
32)
|
||||
background-color (colors/theme-colors
|
||||
(colors/resolve-color customization-color theme 20)
|
||||
(colors/resolve-color customization-color theme 40)
|
||||
theme)
|
||||
bottom (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 messages.constants/header-container-top-margin]
|
||||
[32 -4]
|
||||
messages.constants/default-extrapolation-option)
|
||||
background-opacity (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[messages.constants/header-container-top-margin
|
||||
(+ messages.constants/header-animation-distance
|
||||
messages.constants/header-container-top-margin)]
|
||||
[1 0]
|
||||
messages.constants/default-extrapolation-option)]
|
||||
[:<>
|
||||
[reanimated/view
|
||||
{:style (style/background-container background-color background-opacity top-margin)}]
|
||||
[reanimated/view {:style (style/header-bottom-container bottom top-margin)}
|
||||
[rn/view {:style (style/header-bottom-shadow theme)}]
|
||||
[rn/view {:style (style/header-bottom-part theme)}
|
||||
[list-footer-avatar
|
||||
{:distance-from-list-top distance-from-list-top
|
||||
:display-name display-name
|
||||
:online? online?
|
||||
:theme theme
|
||||
:profile-picture photo-path
|
||||
:group-chat group-chat
|
||||
:color color
|
||||
:emoji emoji
|
||||
:chat-type chat-type
|
||||
:chat-name chat-name
|
||||
:empty-chat? empty-chat?}]
|
||||
[chat-display-name
|
||||
{:distance-from-list-top distance-from-list-top
|
||||
:display-name display-name
|
||||
:theme theme
|
||||
:contact contact
|
||||
:group-chat group-chat
|
||||
:empty-chat? empty-chat?}]
|
||||
[bio-and-actions
|
||||
{:distance-from-list-top distance-from-list-top
|
||||
:bio bio
|
||||
:chat-id chat-id
|
||||
:customization-color customization-color
|
||||
:description description
|
||||
:empty-chat? empty-chat?}]]]]))
|
||||
|
||||
(defn list-footer
|
||||
[props]
|
||||
(let [chat-id (get-in props [:chat :chat-id])
|
||||
loading-messages? (rf/sub [:chats/loading-messages? chat-id])
|
||||
(defn more-messages-loader
|
||||
[{:keys [chat-id] :as props}]
|
||||
(let [loading-messages? (rf/sub [:chats/loading-messages? chat-id])
|
||||
all-loaded? (rf/sub [:chats/all-loaded? chat-id])]
|
||||
[:<>
|
||||
(if (or loading-messages? (not all-loaded?))
|
||||
[loading-view chat-id props]
|
||||
[footer-component props])]))
|
||||
(when (or loading-messages? (not all-loaded?))
|
||||
[loading-view props])))
|
||||
|
||||
(defn list-group-chat-header
|
||||
[{:keys [chat-id invitation-admin]}]
|
||||
@@ -359,8 +164,7 @@
|
||||
(reset! content-height content-height-new)))))
|
||||
|
||||
(defn on-layout
|
||||
[{:keys [event layout-height distance-atom distance-from-list-top
|
||||
chat-screen-layout-calculations-complete?]}]
|
||||
[{:keys [event layout-height distance-atom distance-from-list-top on-layout-done?]}]
|
||||
(let [layout-height-new (oops/oget event "nativeEvent.layout.height")
|
||||
change (- layout-height-new @layout-height)
|
||||
new-distance (- @distance-atom change)]
|
||||
@@ -368,8 +172,7 @@
|
||||
(reanimated/set-shared-value distance-from-list-top new-distance)
|
||||
(reset! distance-atom new-distance)
|
||||
(reset! layout-height layout-height-new))
|
||||
(when-not (reanimated/get-shared-value chat-screen-layout-calculations-complete?)
|
||||
(reanimated/set-shared-value chat-screen-layout-calculations-complete? true))))
|
||||
(reset! on-layout-done? true)))
|
||||
|
||||
(defn on-scroll-fn
|
||||
[distance-atom layout-height-atom]
|
||||
@@ -379,28 +182,21 @@
|
||||
(reset! distance-atom new-distance)))
|
||||
|
||||
(defn messages-list-content
|
||||
[{:keys [insets distance-from-list-top content-height layout-height distance-atom
|
||||
chat-screen-layout-calculations-complete? chat-list-scroll-y]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [chat-type chat-id] :as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
one-to-one-chat? (= chat-type constants/one-to-one-chat-type)
|
||||
community-channel? (= constants/community-chat-type chat-type)
|
||||
{contact-customization-color
|
||||
:customization-color} (when one-to-one-chat?
|
||||
(rf/sub [:contacts/contact-by-identity chat-id]))
|
||||
customization-color (cond community-channel?
|
||||
(or (:color chat)
|
||||
(rf/sub [:communities/community-color
|
||||
(:community-id chat)]))
|
||||
one-to-one-chat? contact-customization-color
|
||||
:else (or (:color chat) :turquoise))
|
||||
{:keys [keyboard-shown]} (hooks/use-keyboard)
|
||||
{window-height :height} (rn/get-window)
|
||||
context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
able-to-send-message? (:able-to-send-message? context)
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
margin-bottom? (and community-channel? (not able-to-send-message?))
|
||||
recording? (rf/sub [:chats/recording?])]
|
||||
[{:keys [insets distance-from-list-top layout-height chat-list-scroll-y on-layout-done?]}]
|
||||
(let [content-height (rn/use-ref-atom 0)
|
||||
distance-atom (rn/use-ref-atom 0)
|
||||
theme (quo.theme/use-theme)
|
||||
{:keys [keyboard-shown]} (hooks/use-keyboard)
|
||||
{:keys [chat-type chat-id]
|
||||
:as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
community-channel? (= constants/community-chat-type chat-type)
|
||||
{window-height :height} (rn/get-window)
|
||||
context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
able-to-send-message? (:able-to-send-message? context)
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
margin-bottom? (and community-channel? (not able-to-send-message?))
|
||||
recording? (rf/sub [:chats/recording?])
|
||||
top-margin (+ (safe-area/get-top) messages.constants/top-bar-height)]
|
||||
[rn/view {:style (style/permission-context-sheet margin-bottom?)}
|
||||
[rn/view {:style {:flex-shrink 1}} ;; Keeps flat list on top
|
||||
[reanimated/flat-list
|
||||
@@ -409,12 +205,9 @@
|
||||
:bounces false
|
||||
:header (when (= (:chat-type chat) constants/private-group-chat-type)
|
||||
[list-group-chat-header chat])
|
||||
:footer [list-footer
|
||||
{:theme theme
|
||||
:chat chat
|
||||
:window-height window-height
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:customization-color customization-color}]
|
||||
:footer [more-messages-loader
|
||||
{:chat-id chat-id
|
||||
:window-height window-height}]
|
||||
:data messages
|
||||
:render-data {:theme theme
|
||||
:context context
|
||||
@@ -444,15 +237,15 @@
|
||||
:style {:background-color (colors/theme-colors colors/white
|
||||
colors/neutral-95
|
||||
theme)}
|
||||
:content-container-style {:padding-top distance-from-last-message}
|
||||
:content-container-style {:padding-top distance-from-last-message
|
||||
:padding-bottom top-margin}
|
||||
:inverted true
|
||||
:on-layout #(on-layout
|
||||
{:event %
|
||||
:layout-height layout-height
|
||||
:distance-atom distance-atom
|
||||
{:event %
|
||||
:layout-height layout-height
|
||||
:distance-atom distance-atom
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:chat-screen-layout-calculations-complete?
|
||||
chat-screen-layout-calculations-complete?})
|
||||
:on-layout-done? on-layout-done?})
|
||||
:scroll-enabled (not recording?)
|
||||
:content-inset-adjustment-behavior :never
|
||||
:scroll-indicator-insets {:right 1}}]]]))
|
||||
|
||||
@@ -1,56 +1,43 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.navigation.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]))
|
||||
|
||||
(defn navigation-view
|
||||
[navigation-view-height pinned-banner-height]
|
||||
[navigation-view-height]
|
||||
{:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:position :absolute
|
||||
:pointer-events :box-none
|
||||
:height (+ navigation-view-height pinned-banner-height)
|
||||
:height (+ navigation-view-height messages.constants/pinned-banner-height)
|
||||
:z-index 1})
|
||||
|
||||
(defn animated-background-view
|
||||
[background-opacity navigation-view-height]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity background-opacity}
|
||||
{:height navigation-view-height
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:overflow :hidden
|
||||
:position :absolute}))
|
||||
(defn background
|
||||
[navigation-view-height]
|
||||
{:height navigation-view-height
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:overflow :hidden
|
||||
:position :absolute})
|
||||
|
||||
(defn header-container
|
||||
[top-insets top-bar-height]
|
||||
[top-insets]
|
||||
{:margin-top top-insets
|
||||
:flex-direction :row
|
||||
:padding-horizontal 20
|
||||
:overflow :hidden
|
||||
:height top-bar-height
|
||||
:height messages.constants/top-bar-height
|
||||
:align-items :center})
|
||||
|
||||
(defn button-animation-container
|
||||
[opacity-value]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity-value}
|
||||
{}))
|
||||
|
||||
;;;; Content
|
||||
|
||||
(defn header-content-container
|
||||
[header-opacity header-position]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y header-position}]
|
||||
:opacity header-opacity}
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:flex 1
|
||||
:margin-horizontal 12
|
||||
:height 40}))
|
||||
(def header-content-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:flex 1
|
||||
:margin-horizontal 12
|
||||
:height 40})
|
||||
|
||||
(def header-text-container
|
||||
{:margin-left 8})
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[re-frame.db]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.home.actions.view :as actions]
|
||||
[status-im.constants :as constants]
|
||||
@@ -15,44 +14,26 @@
|
||||
[status-im.contexts.chat.messenger.messages.navigation.style :as style]
|
||||
[status-im.contexts.chat.messenger.messages.pin.banner.view :as pin.banner]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.messages :as messages.worklets]
|
||||
[utils.worklets.chat.messenger.navigation :as worklets]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn header-content-container
|
||||
[{:keys [chat distance-from-list-top all-loaded? chat-screen-layout-calculations-complete?]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [chat-id group-chat chat-type chat-name
|
||||
emoji color]} chat
|
||||
display-name (cond
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(first (rf/sub
|
||||
[:contacts/contact-two-names-by-identity
|
||||
chat-id]))
|
||||
(= chat-type constants/community-chat-type)
|
||||
(str "# " chat-name)
|
||||
:else (str emoji chat-name))
|
||||
online? (when-not group-chat (rf/sub [:visibility-status-updates/online? chat-id]))
|
||||
photo-path (if group-chat
|
||||
(rf/sub [:chats/group-chat-image chat-id])
|
||||
(rf/sub [:chats/photo-path chat-id]))
|
||||
header-opacity (worklets/navigation-header-opacity
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
chat-screen-layout-calculations-complete?
|
||||
(if platform/ios?
|
||||
messages.constants/content-animation-start-position-ios
|
||||
messages.constants/content-animation-start-position-android))
|
||||
header-position (worklets/navigation-header-position
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
messages.constants/top-bar-height
|
||||
(if platform/ios?
|
||||
messages.constants/content-animation-start-position-ios
|
||||
messages.constants/content-animation-start-position-android))
|
||||
community-channel? (= chat-type constants/community-chat-type)]
|
||||
[reanimated/view
|
||||
{:style (style/header-content-container header-opacity header-position)}
|
||||
[{:keys [chat-id group-chat chat-type chat-name emoji color] :as _chat}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
display-name (cond
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
|
||||
|
||||
(= chat-type constants/community-chat-type)
|
||||
(str "# " chat-name)
|
||||
|
||||
:else
|
||||
(str emoji chat-name))
|
||||
online? (when-not group-chat (rf/sub [:visibility-status-updates/online? chat-id]))
|
||||
photo-path (if group-chat
|
||||
(rf/sub [:chats/group-chat-image chat-id])
|
||||
(rf/sub [:chats/photo-path chat-id]))
|
||||
community-channel? (= chat-type constants/community-chat-type)]
|
||||
[rn/view {:style style/header-content-container}
|
||||
(cond
|
||||
community-channel?
|
||||
[quo/channel-avatar
|
||||
@@ -90,30 +71,11 @@
|
||||
(i18n/label
|
||||
(if online? :t/online :t/offline))])]]))
|
||||
|
||||
(defn animated-background-and-pinned-banner
|
||||
[{:keys [chat-id navigation-view-height distance-from-list-top all-loaded?]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
animation-distance messages.constants/header-animation-distance
|
||||
props {:distance-from-list-top distance-from-list-top
|
||||
:all-loaded? all-loaded?}
|
||||
background-opacity (worklets/interpolate-navigation-view-opacity
|
||||
(assoc props
|
||||
:start-position
|
||||
messages.constants/header-container-top-margin
|
||||
:end-position
|
||||
(+ animation-distance
|
||||
messages.constants/header-container-top-margin)))
|
||||
banner-opacity (worklets/interpolate-navigation-view-opacity
|
||||
(assoc props
|
||||
:start-position
|
||||
(+ navigation-view-height
|
||||
messages.constants/pinned-banner-animation-start-position)
|
||||
:end-position
|
||||
(+ animation-distance
|
||||
navigation-view-height
|
||||
messages.constants/pinned-banner-animation-start-position)))]
|
||||
(defn header-background
|
||||
[{:keys [chat-id navigation-view-height]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[:<>
|
||||
[reanimated/view {:style (style/animated-background-view background-opacity navigation-view-height)}
|
||||
[rn/view {:style (style/background navigation-view-height)}
|
||||
[quo/blur
|
||||
{:style {:flex 1}
|
||||
:blur-amount 20
|
||||
@@ -121,58 +83,37 @@
|
||||
:overlay-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)
|
||||
:blur-radius (if platform/ios? 20 10)}]]
|
||||
[pin.banner/banner
|
||||
{:chat-id chat-id
|
||||
:banner-opacity banner-opacity
|
||||
:top-offset navigation-view-height}]]))
|
||||
{:chat-id chat-id
|
||||
:top-offset navigation-view-height}]]))
|
||||
|
||||
(defn view
|
||||
[{:keys [distance-from-list-top chat-screen-layout-calculations-complete?]}]
|
||||
[]
|
||||
(let [{:keys [chat-id chat-type]
|
||||
:as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
all-loaded? (reanimated/use-shared-value false)
|
||||
all-loaded-sub (rf/sub [:chats/all-loaded? chat-id])
|
||||
top-insets (safe-area/get-top)
|
||||
top-bar-height messages.constants/top-bar-height
|
||||
navigation-view-height (+ top-bar-height top-insets)
|
||||
navigation-buttons-opacity (worklets/navigation-buttons-complete-opacity
|
||||
chat-screen-layout-calculations-complete?)
|
||||
reached-threshold? (messages.worklets/use-messages-scrolled-to-threshold
|
||||
distance-from-list-top
|
||||
top-bar-height)
|
||||
button-background (if reached-threshold? :photo :blur)]
|
||||
(rn/use-effect (fn [] (reanimated/set-shared-value all-loaded? all-loaded-sub))
|
||||
[all-loaded-sub])
|
||||
[rn/view
|
||||
{:style (style/navigation-view navigation-view-height messages.constants/pinned-banner-height)}
|
||||
[animated-background-and-pinned-banner
|
||||
:as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
top-insets (safe-area/get-top)
|
||||
navigation-view-height (+ top-insets messages.constants/top-bar-height)]
|
||||
[rn/view {:style (style/navigation-view navigation-view-height)}
|
||||
[header-background
|
||||
{:chat-id chat-id
|
||||
:navigation-view-height navigation-view-height
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:all-loaded? all-loaded?}]
|
||||
[rn/view {:style (style/header-container top-insets top-bar-height)}
|
||||
[reanimated/view {:style (style/button-animation-container navigation-buttons-opacity)}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background button-background
|
||||
:size 32
|
||||
:accessibility-label :back-button
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
(if (= chat-type constants/community-chat-type) :i/arrow-left :i/close)]]
|
||||
[header-content-container
|
||||
{:chat chat
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:all-loaded? all-loaded?
|
||||
:chat-screen-layout-calculations-complete? chat-screen-layout-calculations-complete?}]
|
||||
[reanimated/view {:style (style/button-animation-container navigation-buttons-opacity)}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background button-background
|
||||
:size 32
|
||||
:accessibility-label :options-button
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [actions/chat-actions chat true])}]))}
|
||||
:i/options]]]]))
|
||||
:navigation-view-height navigation-view-height}]
|
||||
[rn/view {:style (style/header-container top-insets)}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background :blur
|
||||
:size 32
|
||||
:accessibility-label :back-button
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
(if (= chat-type constants/community-chat-type) :i/arrow-left :i/close)]
|
||||
[header-content-container chat]
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background :blur
|
||||
:size 32
|
||||
:accessibility-label :options-button
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [actions/chat-actions chat true])}]))}
|
||||
:i/options]]]))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.pin.banner.style
|
||||
(:require
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]))
|
||||
|
||||
(def container
|
||||
@@ -10,8 +9,6 @@
|
||||
:right 0
|
||||
:height messages.constants/pinned-banner-height})
|
||||
|
||||
(defn container-animated-style
|
||||
[top-offset banner-opacity]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity banner-opacity}
|
||||
(assoc container :top top-offset)))
|
||||
(defn container-with-top-offset
|
||||
[top-offset]
|
||||
(assoc container :top top-offset))
|
||||
|
||||
@@ -2,30 +2,26 @@
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.contexts.chat.messenger.messages.pin.banner.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn f-banner
|
||||
[{:keys [chat-id banner-opacity top-offset]} latest-pin-text pins-count]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[reanimated/view {:style (style/container-animated-style top-offset banner-opacity)}
|
||||
[quo/blur
|
||||
{:style style/container
|
||||
:blur-radius (if platform/ios? 20 10)
|
||||
:blur-type theme
|
||||
:blur-amount 20}]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id]))}]]))
|
||||
|
||||
(defn banner
|
||||
[{:keys [chat-id] :as props}]
|
||||
(let [latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id])
|
||||
[{:keys [chat-id top-offset]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id])
|
||||
pins-count (rf/sub [:chats/pin-messages-count chat-id])]
|
||||
(when (> pins-count 0)
|
||||
[:f> f-banner props latest-pin-text pins-count])))
|
||||
[rn/view {:style (style/container-with-top-offset top-offset)}
|
||||
[quo/blur
|
||||
{:style style/container
|
||||
:blur-radius (if platform/ios? 20 10)
|
||||
:blur-type theme
|
||||
:blur-amount 20}]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id]))}]])))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[utils.worklets.chat.messenger.composer :as worklets]))
|
||||
|
||||
(defn button
|
||||
[{:keys [chat-list-scroll-y]}]
|
||||
[chat-list-scroll-y]
|
||||
(let [{window-height :height} (rn/get-window)
|
||||
scroll-down-button-opacity (worklets/scroll-down-button-opacity
|
||||
chat-list-scroll-y
|
||||
|
||||
@@ -19,57 +19,50 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- footer
|
||||
[props]
|
||||
[layout-height]
|
||||
(let [current-chat-id (rf/sub [:chats/current-chat-id])
|
||||
able-to-send-message? (rf/sub [:chats/able-to-send-message?])]
|
||||
(when-not (string/blank? current-chat-id)
|
||||
(if able-to-send-message?
|
||||
[composer/view props]
|
||||
[composer/view layout-height]
|
||||
[contact-requests.bottom-drawer/view {:contact-id current-chat-id}]))))
|
||||
|
||||
(defn- chat-screen
|
||||
[{:keys [insets] :as props}]
|
||||
[on-layout-done?]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
layout-height (rn/use-ref-atom 0)
|
||||
distance-from-list-top (reanimated/use-shared-value 0)
|
||||
chat-list-scroll-y (reanimated/use-shared-value 0)
|
||||
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
|
||||
chat-exist? (rf/sub [:chats/current-chat-exist?])]
|
||||
(when chat-exist?
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style (style/keyboard-avoiding-container theme)
|
||||
:keyboard-vertical-offset (- (if platform/ios? alert-banners-top-margin 0) (:bottom insets))}
|
||||
[:<>
|
||||
[list.view/messages-list-content props]
|
||||
[scroll-to-bottom/button props]]
|
||||
[messages.navigation/view props]
|
||||
[footer props]])))
|
||||
|
||||
(defn lazy-chat-screen
|
||||
[chat-screen-layout-calculations-complete? *screen-loaded?*]
|
||||
(let [screen-loaded? (rf/sub [:shell/chat-screen-loaded?])
|
||||
distance-from-list-top (reanimated/use-shared-value 0)
|
||||
chat-list-scroll-y (reanimated/use-shared-value 0)
|
||||
props {:insets (safe-area/get-insets)
|
||||
:content-height (atom 0)
|
||||
:layout-height (atom 0)
|
||||
:distance-atom (atom 0)
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:chat-list-scroll-y chat-list-scroll-y
|
||||
:chat-screen-layout-calculations-complete?
|
||||
chat-screen-layout-calculations-complete?}]
|
||||
(when *screen-loaded?*
|
||||
(rn/use-mount #(reset! *screen-loaded?* true)))
|
||||
(when-not (if *screen-loaded?* @*screen-loaded?* screen-loaded?)
|
||||
(reanimated/set-shared-value chat-screen-layout-calculations-complete? false)
|
||||
(reanimated/set-shared-value distance-from-list-top 0)
|
||||
(reanimated/set-shared-value chat-list-scroll-y 0))
|
||||
(when (if *screen-loaded?* @*screen-loaded?* screen-loaded?)
|
||||
[chat-screen props])))
|
||||
insets (safe-area/get-insets)]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style (style/keyboard-avoiding-container theme)
|
||||
:keyboard-vertical-offset (- (if platform/ios? alert-banners-top-margin 0)
|
||||
(:bottom insets))}
|
||||
[:<>
|
||||
[list.view/messages-list-content
|
||||
{:insets insets
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:chat-list-scroll-y chat-list-scroll-y
|
||||
:layout-height layout-height
|
||||
:on-layout-done? on-layout-done?}]
|
||||
[scroll-to-bottom/button chat-list-scroll-y]]
|
||||
[messages.navigation/view]
|
||||
[footer layout-height]]))
|
||||
|
||||
(defn chat
|
||||
[]
|
||||
(let [chat-screen-layout-calculations-complete? (reanimated/use-shared-value false)
|
||||
jump-to-enabled? (ff/enabled? ::ff/shell.jump-to)
|
||||
*screen-loaded?* (when-not jump-to-enabled?
|
||||
(reagent/atom false))]
|
||||
[:<>
|
||||
[lazy-chat-screen chat-screen-layout-calculations-complete? *screen-loaded?*]
|
||||
[placeholder.view/view chat-screen-layout-calculations-complete?]]))
|
||||
(let [on-layout-done? (reagent/atom false)
|
||||
first-render-done? (reagent/atom false)]
|
||||
(fn []
|
||||
(let [chat-exists? (rf/sub [:chats/current-chat-exist?])
|
||||
jump-to-enabled? (ff/enabled? ::ff/shell.jump-to)
|
||||
screen-loaded-for-jump-to? (rf/sub [:shell/chat-screen-loaded?])
|
||||
screen-loaded? (if jump-to-enabled?
|
||||
screen-loaded-for-jump-to?
|
||||
@first-render-done?)]
|
||||
(rn/use-mount #(reset! first-render-done? true))
|
||||
[:<>
|
||||
(when (and chat-exists? screen-loaded?)
|
||||
[chat-screen on-layout-done?])
|
||||
[placeholder.view/view on-layout-done?]]))))
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
(ns status-im.contexts.chat.messenger.placeholder.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(defn container
|
||||
[top opacity z-index theme]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity
|
||||
:z-index z-index}
|
||||
{:position :absolute
|
||||
:padding-top top
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}))
|
||||
[theme on-layout-done?]
|
||||
{:position :absolute
|
||||
:padding-top (safe-area/get-top)
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
|
||||
:opacity (if on-layout-done? 0 1)
|
||||
:z-index (if on-layout-done? 0 2)})
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
[quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.contexts.chat.messenger.placeholder.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.placeholder :as worklets]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- loading-skeleton
|
||||
[]
|
||||
@@ -17,13 +14,10 @@
|
||||
:animated? false}])
|
||||
|
||||
(defn view
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
[on-layout-done?]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
top (safe-area/get-top)
|
||||
chat-exist? (rf/sub [:chats/current-chat-exist?])
|
||||
opacity (worklets/placeholder-opacity chat-screen-layout-calculations-complete?)
|
||||
z-index (worklets/placeholder-z-index chat-screen-layout-calculations-complete?)]
|
||||
[reanimated/view {:style (style/container top opacity z-index theme)}
|
||||
chat-exist? (rf/sub [:chats/current-chat-exist?])]
|
||||
[rn/view {:style (style/container theme @on-layout-done?)}
|
||||
(when-not chat-exist?
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
|
||||
@@ -119,38 +119,29 @@
|
||||
:icon-left :i/communities}
|
||||
(i18n/label :t/request-to-join)])
|
||||
|
||||
(defn- info-button-handler
|
||||
(defn token-gated-communities-info
|
||||
[]
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[quo/documentation-drawers
|
||||
{:title (i18n/label :t/token-gated-communities)
|
||||
:show-button? true
|
||||
:button-label (i18n/label :t/read-more)
|
||||
:button-icon :info}
|
||||
[quo/text {:size :paragraph-2}
|
||||
(i18n/label :t/token-gated-communities-info)]])}]))
|
||||
[quo/documentation-drawers {:title (i18n/label :t/token-gated-communities)}
|
||||
[quo/text {:size :paragraph-2}
|
||||
(i18n/label :t/token-gated-communities-info)]])
|
||||
|
||||
(defn- token-requirements
|
||||
[{:keys [id color role-permissions?]}]
|
||||
(let [{:keys [can-request-access?
|
||||
no-member-permission?
|
||||
tokens
|
||||
networks-not-supported?
|
||||
highest-permission-role]} (rf/sub [:community/token-gated-overview id])
|
||||
highest-role-text
|
||||
(i18n/label
|
||||
(communities.utils/role->translation-key highest-permission-role :t/member))
|
||||
on-press (rn/use-callback (fn []
|
||||
(if config/community-accounts-selection-enabled?
|
||||
(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id id}])
|
||||
(rf/dispatch [:open-modal :community-requests-to-join
|
||||
{:id
|
||||
id}])))
|
||||
[id])]
|
||||
(let [{:keys [can-request-access? no-member-permission? networks-not-supported?
|
||||
highest-permission-role
|
||||
tokens]} (rf/sub [:community/token-gated-overview id])
|
||||
highest-role-text (i18n/label
|
||||
(communities.utils/role->translation-key highest-permission-role :t/member))
|
||||
on-press (rn/use-callback
|
||||
(fn []
|
||||
(if config/community-accounts-selection-enabled?
|
||||
(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id id}])
|
||||
(rf/dispatch [:open-modal :community-requests-to-join
|
||||
{:id id}])))
|
||||
[id])
|
||||
on-press-info #(rf/dispatch
|
||||
[:show-bottom-sheet {:content token-gated-communities-info}])]
|
||||
(cond
|
||||
networks-not-supported?
|
||||
[network-not-supported]
|
||||
@@ -160,13 +151,12 @@
|
||||
|
||||
:else
|
||||
[quo/community-token-gating
|
||||
{:role highest-role-text
|
||||
:tokens tokens
|
||||
{:role highest-role-text
|
||||
:tokens tokens
|
||||
:community-color color
|
||||
:satisfied? can-request-access?
|
||||
:on-press on-press
|
||||
:on-press-info
|
||||
info-button-handler}])))
|
||||
:satisfied? can-request-access?
|
||||
:on-press on-press
|
||||
:on-press-info on-press-info}])))
|
||||
|
||||
(defn- join-community
|
||||
[{:keys [id joined permissions] :as community}]
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
(reset! shell.state/screen-height height)
|
||||
(async-storage/set-item! :screen-height height))))
|
||||
|
||||
(defn f-view
|
||||
(defn view
|
||||
[dark-overlay?]
|
||||
(let [view-id (rf/sub [:view-id])
|
||||
animate? (not dark-overlay?)
|
||||
@@ -94,5 +94,3 @@
|
||||
:blur-radius (if platform/android? 25 10)
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent}])]))
|
||||
|
||||
(defn view [dark-overlay?] [:f> f-view dark-overlay?])
|
||||
|
||||
@@ -102,8 +102,6 @@
|
||||
[:dispatch-later [{:ms 1500 :dispatch [:profile.login/non-critical-initialization]}]]
|
||||
[:dispatch [:network/check-expensive-connection]]
|
||||
[:profile.settings/get-profile-picture key-uid]
|
||||
(when (ff/enabled? ::ff/wallet.wallet-connect)
|
||||
[:dispatch [:wallet-connect/init]])
|
||||
(when notifications-enabled?
|
||||
[:effects/push-notifications-enable])]})))
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
;; TODO: Replace with correct enum values once status-go implements them.
|
||||
(def ^:const tx 66612)
|
||||
(def ^:const system 66614)
|
||||
(def ^:const system
|
||||
#{new-installation-received new-installation-created})
|
||||
|
||||
(def ^:const membership
|
||||
"Membership is like a logical group of notifications with different types, i.e.
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
(let [selected-tab (or (rf/sub [:wallet/account-tab]) first-tab-id)
|
||||
{:keys [name color formatted-balance
|
||||
watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
testnet-mode? (rf/sub [:profile/test-networks-enabled?])]
|
||||
(hot-reload/use-safe-unmount (fn []
|
||||
(rf/dispatch [:wallet/close-account-page])
|
||||
(rf/dispatch [:wallet/clean-current-viewing-account])))
|
||||
@@ -46,23 +47,24 @@
|
||||
[quo/wallet-graph {:time-frame :empty}])
|
||||
(when (not watch-only?)
|
||||
[quo/wallet-ctas
|
||||
{:container-style style/cta-buttons
|
||||
:send-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/wizard-navigate-forward
|
||||
{:start-flow? true
|
||||
:flow-id :wallet-send-flow}]))
|
||||
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
|
||||
{:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:bridge-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/start-bridge]))
|
||||
:swap-action (when (ff/enabled? ::ff/wallet.swap)
|
||||
(fn []
|
||||
(rf/dispatch [:wallet.tokens/get-token-list])
|
||||
(rf/dispatch [:open-modal :screen/wallet.swap-select-asset-to-pay])))}])
|
||||
{:container-style style/cta-buttons
|
||||
:send-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/wizard-navigate-forward
|
||||
{:start-flow? true
|
||||
:flow-id :wallet-send-flow}]))
|
||||
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
|
||||
{:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:bridge-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/start-bridge]))
|
||||
:swap-action (fn []
|
||||
(rf/dispatch [:wallet.tokens/get-token-list])
|
||||
(rf/dispatch [:open-modal :screen/wallet.swap-select-asset-to-pay]))
|
||||
:bridge-disabled? testnet-mode?
|
||||
:swap-disabled? testnet-mode?}])
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im.contexts.wallet.common.token-value.view
|
||||
(:require [quo.core :as quo]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[status-im.feature-flags :as ff]
|
||||
@@ -18,15 +17,15 @@
|
||||
:right-icon :i/external})
|
||||
|
||||
(defn- action-send
|
||||
[send-params entry-point]
|
||||
[{:keys [disabled?] :as params} entry-point]
|
||||
{:icon :i/send
|
||||
:accessibility-label :send
|
||||
:label (i18n/label :t/send)
|
||||
:disabled? (:disabled? send-params)
|
||||
:disabled? disabled?
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/set-token-to-send send-params entry-point]))})
|
||||
(rf/dispatch [:wallet/set-token-to-send params entry-point]))})
|
||||
|
||||
(defn- action-receive
|
||||
[selected-account?]
|
||||
@@ -38,21 +37,26 @@
|
||||
#(rf/dispatch [:open-modal :screen/share-shell {:initial-tab :wallet}]))})
|
||||
|
||||
(defn- action-bridge
|
||||
[bridge-params]
|
||||
[{:keys [bridge-disabled? testnet-mode?] :as params}]
|
||||
{:icon :i/bridge
|
||||
:accessibility-label :bridge
|
||||
:label (i18n/label :t/bridge)
|
||||
:disabled? (:bridge-disabled? bridge-params)
|
||||
:disabled? (or testnet-mode? bridge-disabled?)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet/bridge-select-token bridge-params]))})
|
||||
(rf/dispatch [:wallet/bridge-select-token params]))})
|
||||
|
||||
(defn- action-swap
|
||||
[]
|
||||
[{:keys [token token-symbol testnet-mode?]}]
|
||||
{:icon :i/swap
|
||||
:accessibility-label :swap
|
||||
:label (i18n/label :t/swap)
|
||||
:on-press #(not-implemented/alert)})
|
||||
:disabled? testnet-mode?
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet.swap/start
|
||||
{:asset-to-pay (or token {:symbol token-symbol})
|
||||
:open-new-screen? true}]))})
|
||||
|
||||
(defn- action-manage-tokens
|
||||
[watch-only?]
|
||||
@@ -71,47 +75,38 @@
|
||||
|
||||
(defn token-value-drawer
|
||||
[token watch-only? entry-point]
|
||||
(let [token-symbol (:token token)
|
||||
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query token-symbol}]))
|
||||
fiat-unformatted-value (get-in token [:values :fiat-unformatted-value])
|
||||
has-balance? (money/greater-than fiat-unformatted-value (money/bignumber "0"))
|
||||
selected-account? (rf/sub [:wallet/current-viewing-account-address])
|
||||
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
|
||||
send-params (if selected-account?
|
||||
{:token token-data
|
||||
:stack-id :screen/wallet.accounts
|
||||
:disabled? (not has-balance?)
|
||||
:start-flow? true
|
||||
:owners token-owners}
|
||||
{:token-symbol token-symbol
|
||||
:stack-id :wallet-stack
|
||||
:start-flow? true
|
||||
:owners token-owners})
|
||||
bridge-params (if selected-account?
|
||||
{:token token-data
|
||||
:bridge-disabled? (or (not has-balance?)
|
||||
(send-utils/bridge-disabled? token-symbol))
|
||||
:stack-id :screen/wallet.accounts
|
||||
:start-flow? true
|
||||
:owners token-owners}
|
||||
{:token-symbol token-symbol
|
||||
:bridge-disabled? (send-utils/bridge-disabled? token-symbol)
|
||||
:stack-id :wallet-stack
|
||||
:start-flow? true
|
||||
:owners token-owners})]
|
||||
(let [token-symbol (:token token)
|
||||
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query token-symbol}]))
|
||||
selected-account (rf/sub [:wallet/current-viewing-account-address])
|
||||
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
|
||||
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
|
||||
params (cond-> {:start-flow? true
|
||||
:owners token-owners
|
||||
:testnet-mode? testnet-mode?}
|
||||
selected-account
|
||||
(assoc :token token-data
|
||||
:stack-id :screen/wallet.accounts
|
||||
:has-balance? (-> (get-in token [:values :fiat-unformatted-value])
|
||||
(money/greater-than (money/bignumber "0"))))
|
||||
(not selected-account)
|
||||
(assoc :token-symbol token-symbol
|
||||
:stack-id :wallet-stack))]
|
||||
[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)
|
||||
(when (seq token-owners)
|
||||
(action-send send-params entry-point))
|
||||
(action-receive selected-account?)
|
||||
(when (ff/enabled? ::ff/wallet.swap) (action-swap))
|
||||
(when (seq (seq token-owners))
|
||||
(action-bridge bridge-params))]))]]))
|
||||
(not watch-only?)
|
||||
(concat [(action-buy)
|
||||
(when (seq token-owners)
|
||||
(action-send params entry-point))
|
||||
(action-receive selected-account)
|
||||
(action-swap params)
|
||||
(when (seq token-owners)
|
||||
(action-bridge (assoc params
|
||||
:bridge-disabled?
|
||||
(send-utils/bridge-disabled? token-symbol))))]))]]))
|
||||
|
||||
(defn view
|
||||
[item _ _ {:keys [watch-only? entry-point]}]
|
||||
|
||||
@@ -493,3 +493,13 @@
|
||||
:available-balance (calculate-total-token-balance token)
|
||||
:total-balance (calculate-total-token-balance token chain-ids)))
|
||||
tokens))
|
||||
|
||||
(defn estimated-time-format
|
||||
"Formats the estimated time for a transaction"
|
||||
[estimated-time]
|
||||
(condp = estimated-time
|
||||
(:unknown constants/wallet-transaction-estimation) ">5"
|
||||
(:less-than-one-minute constants/wallet-transaction-estimation) "<1"
|
||||
(:less-than-three-minutes constants/wallet-transaction-estimation) "1-3"
|
||||
(:less-than-five-minutes constants/wallet-transaction-estimation) "3-5"
|
||||
">5"))
|
||||
|
||||
@@ -345,8 +345,7 @@
|
||||
:Prod
|
||||
data-store/rpc->network)
|
||||
data)}]
|
||||
{:fx [(when (ff/enabled? ::ff/wallet.swap)
|
||||
[:dispatch [:wallet.tokens/get-token-list]])]
|
||||
{:fx [[:dispatch [:wallet.tokens/get-token-list]]]
|
||||
:db (assoc-in db [:wallet :networks] network-data)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
@@ -478,7 +477,9 @@
|
||||
[:dispatch [:wallet/get-ethereum-chains]]
|
||||
[:dispatch [:wallet/get-accounts]]
|
||||
[:dispatch [:wallet/get-keypairs]]
|
||||
[:dispatch [:wallet/get-saved-addresses]]]}))
|
||||
[:dispatch [:wallet/get-saved-addresses]]
|
||||
(when (ff/enabled? ::ff/wallet.wallet-connect)
|
||||
[:dispatch-later [{:ms 500 :dispatch [:wallet-connect/init]}]])]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/share-account
|
||||
(fn [_ [{:keys [content title]}]]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns status-im.contexts.wallet.send.events-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [is testing run-tests]]
|
||||
[cljs.test :refer-macros [is testing]]
|
||||
matcher-combinators.test
|
||||
[re-frame.db :as rf-db]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
@@ -710,5 +710,3 @@
|
||||
:stack-id stack-id
|
||||
:start-flow? start-flow?
|
||||
:netork-details network-details}])))))))
|
||||
|
||||
(run-tests)
|
||||
|
||||
@@ -14,22 +14,36 @@
|
||||
[utils.number :as number]))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/start
|
||||
(fn [{:keys [db]} [{:keys [asset-to-pay asset-to-receive network]}]]
|
||||
(let [asset-to-receive' (or asset-to-receive
|
||||
(swap-utils/select-asset-to-receive
|
||||
(:wallet db)
|
||||
(:profile/profile db)
|
||||
asset-to-pay))
|
||||
network' (or network
|
||||
(swap-utils/select-network asset-to-pay))]
|
||||
(fn [{:keys [db]} [{:keys [network open-new-screen?] :as data}]]
|
||||
(let [{:keys [wallet]} db
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
account (swap-utils/wallet-account wallet)
|
||||
asset-to-pay (if (get-in data [:asset-to-pay :networks])
|
||||
(:asset-to-pay data)
|
||||
(swap-utils/select-asset-to-pay-by-symbol
|
||||
{:wallet wallet
|
||||
:account account
|
||||
:test-networks-enabled? test-networks-enabled?
|
||||
:token-symbol (get-in data [:asset-to-pay :symbol])}))
|
||||
asset-to-receive (or (:asset-to-receive data)
|
||||
(swap-utils/select-default-asset-to-receive
|
||||
{:wallet wallet
|
||||
:account account
|
||||
:test-networks-enabled? test-networks-enabled?
|
||||
:asset-to-pay asset-to-pay}))
|
||||
network' (or network
|
||||
(swap-utils/select-network asset-to-pay))]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :swap :asset-to-pay] asset-to-pay)
|
||||
(assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive')
|
||||
(assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive)
|
||||
(assoc-in [:wallet :ui :swap :network] network'))
|
||||
:fx (if network'
|
||||
[[:dispatch
|
||||
[:navigate-to-within-stack
|
||||
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]]]
|
||||
[[:dispatch [:wallet/switch-current-viewing-account (:address account)]]
|
||||
[:dispatch
|
||||
(if open-new-screen?
|
||||
[:navigate-to :screen/wallet.setup-swap]
|
||||
[:navigate-to-within-stack
|
||||
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]])]
|
||||
[:dispatch [:wallet.swap/set-default-slippage]]]
|
||||
[[:dispatch
|
||||
[:show-bottom-sheet
|
||||
@@ -41,8 +55,9 @@
|
||||
(rf/dispatch
|
||||
[:wallet.swap/start
|
||||
{:asset-to-pay asset-to-pay
|
||||
:asset-to-receive asset-to-receive'
|
||||
:network network}]))}])}]]])})))
|
||||
:asset-to-receive asset-to-receive
|
||||
:network network
|
||||
:open-new-screen? open-new-screen?}]))}])}]]])})))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/select-asset-to-pay
|
||||
(fn [{:keys [db]} [{:keys [token]}]]
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
(defn- assets-view
|
||||
[search-text on-change-text]
|
||||
(let [on-token-press (fn [token]
|
||||
(rf/dispatch [:wallet.swap/start {:asset-to-pay token}]))]
|
||||
(rf/dispatch [:wallet.swap/start
|
||||
{:asset-to-pay token
|
||||
:open-new-screen? false}]))]
|
||||
[:<>
|
||||
[search-input search-text on-change-text]
|
||||
[asset-list/view
|
||||
|
||||
@@ -30,22 +30,61 @@
|
||||
:else
|
||||
(i18n/label :t/something-went-wrong-please-try-again-later)))
|
||||
|
||||
(defn select-asset-to-receive
|
||||
[wallet profile asset-to-pay]
|
||||
(let [wallet-address (get-in wallet [:current-viewing-account-address])
|
||||
account (-> wallet
|
||||
:accounts
|
||||
vals
|
||||
(utils/get-account-by-address wallet-address))
|
||||
test-networks-enabled? (get profile :test-networks-enabled?)
|
||||
networks (-> (get-in wallet
|
||||
[:wallet :networks (if test-networks-enabled? :test :prod)])
|
||||
(network-utils/sorted-networks-with-details))]
|
||||
(defn- first-operable-account
|
||||
[accounts]
|
||||
(->> accounts
|
||||
vals
|
||||
(remove :watch-only?)
|
||||
(filter :operable?)
|
||||
(sort-by :position)
|
||||
first))
|
||||
|
||||
(defn wallet-account
|
||||
"Picks the account that's gonna be used for the swap operation.
|
||||
It's gonna be either the preselected account defined by
|
||||
`[:wallet :current-viewing-account-address]` in `db`
|
||||
or the first operable account."
|
||||
[wallet]
|
||||
(if-let [wallet-address (get wallet :current-viewing-account-address)]
|
||||
(-> wallet
|
||||
:accounts
|
||||
vals
|
||||
(utils/get-account-by-address wallet-address))
|
||||
(-> wallet :accounts first-operable-account)))
|
||||
|
||||
(defn select-asset-to-pay-by-symbol
|
||||
"Selects an asset to pay by token symbol.
|
||||
It's used for cases when only token symbol is available and the information
|
||||
about token needs to be extracted from the database.
|
||||
That happens when token is being selected on the home screen and
|
||||
it basically indicates that no account pre-selection was made."
|
||||
[{:keys [wallet account test-networks-enabled? token-symbol]}]
|
||||
(let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)])
|
||||
(network-utils/sorted-networks-with-details))
|
||||
token (->> account
|
||||
:tokens
|
||||
(filter #(= token-symbol (:symbol %)))
|
||||
first)]
|
||||
(assoc token :networks (network-utils/network-list token networks))))
|
||||
|
||||
(defn select-default-asset-to-receive
|
||||
"Selects an asset to receive if it was not provided explicitly.
|
||||
The principle of how the asset is being selected is simple: we get the
|
||||
whole list, remove the currently selected `asset-to-pay` from it, and choose
|
||||
the first one of what's left."
|
||||
[{:keys [wallet account test-networks-enabled? asset-to-pay]}]
|
||||
(let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)])
|
||||
(network-utils/sorted-networks-with-details))]
|
||||
(->> (utils/tokens-with-balance (:tokens account) networks nil)
|
||||
(remove #(= (:symbol %) (:symbol asset-to-pay)))
|
||||
first)))
|
||||
|
||||
(defn select-network
|
||||
"Chooses the network.
|
||||
Usually user needs to do the selection first and if the selection was done
|
||||
then the list of networks for the defined token will always contain
|
||||
one entry. Otherwise `nil` will be returned from here which will serve
|
||||
as an indicator that the network selector needs to be displayed."
|
||||
[{:keys [networks]}]
|
||||
(when (= (count networks) 1)
|
||||
(first networks)))
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
{:fx [[:effects.wallet-connect/init
|
||||
{:on-success #(rf/dispatch [:wallet-connect/on-init-success %])
|
||||
:on-fail #(rf/dispatch [:wallet-connect/on-init-fail %])}]]})
|
||||
;; NOTE: when offline, fetching persistent sessions only
|
||||
{:fx [[:dispatch [:wallet-connect/fetch-persisted-sessions]]]}))))
|
||||
;; NOTE: when offline, fetching persistent sessions without initializing WC
|
||||
{:fx [[:dispatch [:wallet-connect/get-sessions]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-init-success
|
||||
@@ -30,7 +30,7 @@
|
||||
(log/info "WalletConnect SDK initialisation successful")
|
||||
{:db (assoc db :wallet-connect/web3-wallet web3-wallet)
|
||||
:fx [[:dispatch [:wallet-connect/register-event-listeners]]
|
||||
[:dispatch [:wallet-connect/fetch-persisted-sessions]]]}))
|
||||
[:dispatch [:wallet-connect/get-sessions]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reload-on-network-change
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
@@ -41,35 +43,19 @@
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/disconnect
|
||||
(fn [{:keys [web3-wallet topic reason on-success on-fail]}]
|
||||
(-> (wallet-connect/disconnect-session {:web3-wallet web3-wallet
|
||||
:topic topic
|
||||
:reason reason})
|
||||
(fn [{:keys [web3-wallet topic on-success on-fail]}]
|
||||
(-> (sessions/disconnect web3-wallet topic)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-fail))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/approve-session
|
||||
(fn [{:keys [web3-wallet proposal networks accounts on-success on-fail]}]
|
||||
(let [{:keys [params id]} proposal
|
||||
approved-namespaces (->> {:eip155
|
||||
{:chains networks
|
||||
:accounts accounts
|
||||
:methods constants/wallet-connect-supported-methods
|
||||
:events constants/wallet-connect-supported-events}}
|
||||
(wallet-connect/build-approved-namespaces
|
||||
params))]
|
||||
(-> (wallet-connect/approve-session
|
||||
{:web3-wallet web3-wallet
|
||||
:id id
|
||||
:approved-namespaces approved-namespaces})
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-fail)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/fetch-active-sessions
|
||||
(fn [{:keys [web3-wallet on-success on-fail]}]
|
||||
(-> (wallet-connect/get-active-sessions web3-wallet)
|
||||
(fn [{:keys [web3-wallet proposal-request session-networks address on-success on-fail]}]
|
||||
(-> (sessions/approve
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal-request proposal-request
|
||||
:address address
|
||||
:session-networks session-networks})
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-fail))))
|
||||
|
||||
@@ -123,11 +109,11 @@
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/sign-typed-data
|
||||
(fn [{:keys [password address data version chain-id on-success on-error]}]
|
||||
(-> (signing/eth-sign-typed-data (security/safe-unmask-data password)
|
||||
address
|
||||
data
|
||||
chain-id
|
||||
version)
|
||||
(-> (typed-data/sign (security/safe-unmask-data password)
|
||||
address
|
||||
data
|
||||
chain-id
|
||||
version)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -155,3 +141,10 @@
|
||||
:reason reason})
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/get-sessions
|
||||
(fn [{:keys [web3-wallet addresses online? on-success on-error]}]
|
||||
(-> (sessions/get-sessions web3-wallet addresses online?)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :address] address)}))
|
||||
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/approve-session
|
||||
(fn [{:keys [db]}]
|
||||
@@ -119,33 +118,51 @@
|
||||
(map networks/chain-id->eip155)
|
||||
vec)
|
||||
current-address (get-in db [:wallet-connect/current-proposal :address])
|
||||
accounts (-> (partial networks/format-eip155-address current-address)
|
||||
(map session-networks))
|
||||
network-status (:network/status db)
|
||||
expiry (get-in current-proposal [:params :expiryTimestamp])]
|
||||
expired? (-> current-proposal
|
||||
(get-in [:params :expiryTimestamp])
|
||||
uri/timestamp-expired?)]
|
||||
(if (= network-status :online)
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :response-sent?] true)
|
||||
:fx [(if (uri/timestamp-expired? expiry)
|
||||
:fx [(if expired?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :wallet-connect-proposal-expired
|
||||
:type :negative
|
||||
:text (i18n/label :t/wallet-connect-proposal-expired)}]]
|
||||
[:effects.wallet-connect/approve-session
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal current-proposal
|
||||
:networks session-networks
|
||||
:accounts accounts
|
||||
:on-success (fn [approved-session]
|
||||
(log/info "Wallet Connect session approved")
|
||||
(rf/dispatch [:wallet-connect/reset-current-session-proposal])
|
||||
(rf/dispatch [:wallet-connect/persist-session
|
||||
approved-session]))
|
||||
:on-fail (fn [error]
|
||||
(log/error "Wallet Connect session approval failed"
|
||||
{:error error
|
||||
:event :wallet-connect/approve-session})
|
||||
(rf/dispatch
|
||||
[:wallet-connect/reset-current-session-proposal]))}])
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal-request current-proposal
|
||||
:session-networks session-networks
|
||||
:address current-address
|
||||
:on-success #(rf/dispatch [:wallet-connect/approve-session-success %])
|
||||
:on-fail #(rf/dispatch [:wallet-connect/approve-session-error %])}])
|
||||
[:dispatch [:dismiss-modal :screen/wallet.wallet-connect-session-proposal]]]}
|
||||
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
|
||||
|
||||
(rf/reg-event-fx :wallet-connect/approve-session-success
|
||||
(fn [_ [session]]
|
||||
(log/info "Wallet Connect session approved")
|
||||
{:fx [[:dispatch [:wallet-connect/on-new-session session]]
|
||||
[:dispatch [:wallet-connect/reset-current-session-proposal]]
|
||||
[:dispatch [:wallet-connect/redirect-to-dapp (data-store/get-dapp-redirect-url session)]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet-connect/approve-session-error
|
||||
(fn [_ [error]]
|
||||
(log/error "Wallet Connect session approval failed"
|
||||
{:error error
|
||||
:event :wallet-connect/approve-session})
|
||||
{:fx [[:dispatch [:wallet-connect/reset-current-session-proposal]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reject-session-proposal
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)
|
||||
{:keys [request response-sent?]} (:wallet-connect/current-proposal db)]
|
||||
{:fx [(when-not response-sent?
|
||||
[:effects.wallet-connect/reject-session-proposal
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal (or proposal request)
|
||||
:on-success #(log/info "Wallet Connect session proposal rejected")
|
||||
:on-error #(log/error "Wallet Connect unable to reject session proposal")}])
|
||||
[:dispatch [:wallet-connect/reset-current-session-proposal]]]})))
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
@@ -37,7 +37,9 @@
|
||||
(assoc-in [:wallet-connect/current-request :response-sent?] false))
|
||||
:fx [(condp = method
|
||||
constants/wallet-connect-eth-send-transaction-method
|
||||
[:dispatch [:wallet-connect/process-eth-send-transaction]]
|
||||
[:dispatch
|
||||
[:wallet-connect/process-eth-send-transaction
|
||||
{:on-success (fn [] (rf/dispatch [:wallet-connect/show-request-modal]))}]]
|
||||
|
||||
constants/wallet-connect-eth-sign-method
|
||||
[:dispatch [:wallet-connect/process-eth-sign]]
|
||||
@@ -94,22 +96,25 @@
|
||||
:raw-data prepared-tx
|
||||
:transaction tx
|
||||
:chain-id chain-id
|
||||
:display-data display-data)
|
||||
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
|
||||
:display-data display-data)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-send-transaction
|
||||
(fn [{:keys [db]}]
|
||||
(fn [{:keys [db]} [{:keys [on-success]}]]
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
tx (-> event data-store/get-request-params first)
|
||||
chain-id (-> event
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)]
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
:chain-id chain-id
|
||||
:on-success #(rf/dispatch [:wallet-connect/prepare-transaction-success % chain-id])
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]})))
|
||||
(when tx
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
:chain-id chain-id
|
||||
:on-success (fn [data]
|
||||
(rf/dispatch [:wallet-connect/prepare-transaction-success data chain-id])
|
||||
(when on-success
|
||||
(rf/call-continuation on-success)))
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-sign-transaction
|
||||
@@ -130,16 +135,13 @@
|
||||
(fn [{:keys [db]}]
|
||||
(try
|
||||
(let [[address raw-data] (data-store/get-db-current-request-params db)
|
||||
parsed-raw-data (transforms/js-parse raw-data)
|
||||
session-chain-id (-> (data-store/get-db-current-request-event db)
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)
|
||||
data-chain-id (-> parsed-raw-data
|
||||
transforms/js->clj
|
||||
signing/typed-data-chain-id)
|
||||
parsed-data (-> parsed-raw-data
|
||||
(transforms/js-dissoc :types :primaryType)
|
||||
(transforms/js-stringify 2))]
|
||||
typed-data (-> raw-data
|
||||
transforms/js-parse
|
||||
transforms/js->clj)
|
||||
data-chain-id (typed-data/get-chain-id typed-data)]
|
||||
(if (and data-chain-id
|
||||
(not= session-chain-id data-chain-id))
|
||||
{:fx [[:dispatch
|
||||
@@ -150,7 +152,7 @@
|
||||
[:wallet-connect/current-request]
|
||||
assoc
|
||||
:address (string/lower-case address)
|
||||
:display-data (or parsed-data raw-data)
|
||||
:display-data (typed-data/flatten-typed-data typed-data)
|
||||
:raw-data raw-data)
|
||||
:fx [[:dispatch [:wallet-connect/show-request-modal]]]}))
|
||||
(catch js/Error err
|
||||
|
||||
@@ -165,19 +165,6 @@
|
||||
{:fx [[:dispatch [:wallet-connect/send-response {:result result}]]
|
||||
[:dispatch [:wallet-connect/dismiss-request-modal]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reject-session-proposal
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)
|
||||
{:keys [request response-sent?]} (:wallet-connect/current-proposal db)]
|
||||
{:fx [(when-not response-sent?
|
||||
[:effects.wallet-connect/reject-session-proposal
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal (or proposal request)
|
||||
:on-success #(log/info "Wallet Connect session proposal rejected")
|
||||
:on-error #(log/error "Wallet Connect unable to reject session proposal")}])
|
||||
[:dispatch [:wallet-connect/reset-current-session-proposal]]]})))
|
||||
|
||||
;; NOTE: Currently we only reject a session if the user dismissed a modal
|
||||
;; without accepting the session first.
|
||||
;; But this needs to be solidified to ensure other cases:
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.sessions
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.transforms :as types]))
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-delete
|
||||
(fn [{:keys [db]} [{:keys [topic] :as event}]]
|
||||
(when (networks/event-should-be-handled? db event)
|
||||
(log/info "Received Wallet Connect session delete from the SDK: " event)
|
||||
{:fx [[:dispatch [:wallet-connect/disconnect-persisted-session topic]]]})))
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_disconnectWalletConnectSession"
|
||||
:params [topic]
|
||||
:on-success [:wallet-connect/delete-session topic]
|
||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/disconnect-dapp
|
||||
@@ -26,116 +26,64 @@
|
||||
{:fx [[:effects.wallet-connect/disconnect
|
||||
{:web3-wallet web3-wallet
|
||||
:topic topic
|
||||
:reason (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-disconnected-reason-key)
|
||||
:on-fail on-fail
|
||||
:on-success (fn []
|
||||
(rf/dispatch [:wallet-connect/disconnect-persisted-session topic])
|
||||
(log/info "Successfully disconnected dApp session" topic)
|
||||
(rf/dispatch [:wallet-connect/delete-session topic])
|
||||
(when on-success
|
||||
(on-success)))}]]}
|
||||
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
|
||||
|
||||
;; We first load sessions from database, then we initiate a call to Wallet Connect SDK and
|
||||
;; then replace the list we have stored in the database with the one that came from the SDK.
|
||||
;; In addition to that, we also update the backend state by marking sessions that are not
|
||||
;; active anymore by calling `:wallet-connect/disconnect-session`.
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-active-sessions-success
|
||||
(fn [{:keys [db now]} [sessions]]
|
||||
(let [persisted-sessions (:wallet-connect/sessions db)
|
||||
account-addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
sessions/filter-operable-accounts
|
||||
(map :address))
|
||||
sessions (->> (js->clj sessions :keywordize-keys true)
|
||||
vals
|
||||
(map sessions/sdk-session->db-session)
|
||||
(sessions/filter-sessions-for-account-addresses
|
||||
account-addresses))
|
||||
session-topics (set (map :topic sessions))
|
||||
expired-sessions (filter
|
||||
(fn [{:keys [expiry topic]}]
|
||||
(or (< expiry (/ now 1000))
|
||||
(not (contains? session-topics topic))))
|
||||
persisted-sessions)]
|
||||
(when (seq expired-sessions)
|
||||
(log/info "Updating WalletConnect persisted sessions due to expired/inactive sessions"
|
||||
{:expired expired-sessions}))
|
||||
{:fx (mapv (fn [{:keys [topic]}]
|
||||
[:dispatch [:wallet-connect/disconnect-persisted-session topic]])
|
||||
expired-sessions)
|
||||
:db (assoc db :wallet-connect/sessions sessions)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-active-sessions
|
||||
:wallet-connect/get-sessions
|
||||
(fn [{:keys [db]}]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/fetch-active-sessions
|
||||
{:web3-wallet web3-wallet
|
||||
:on-fail #(log/error "Failed to get active sessions" {:error %})
|
||||
:on-success #(rf/dispatch [:wallet-connect/fetch-active-sessions-success %])}]]})))
|
||||
(let [addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
sessions/filter-operable-accounts
|
||||
(map :address))]
|
||||
(if (not (seq addresses))
|
||||
;; NOTE: Re-trying to get active sessions if accounts weren't loaded yet during
|
||||
;; initialization
|
||||
((log/info "Re-trying to fetch active WalletConnect sessions")
|
||||
{:fx [[:dispatch-later [{:ms 500 :dispatch [:wallet-connect/get-sessions]}]]]})
|
||||
{:fx [[:effects.wallet-connect/get-sessions
|
||||
{:online? (-> db :network/status (= :online))
|
||||
:web3-wallet (get db :wallet-connect/web3-wallet)
|
||||
:addresses addresses
|
||||
:on-success #(rf/dispatch [:wallet-connect/get-sessions-success %])
|
||||
:on-error #(rf/dispatch [:wallet-connect/get-sessions-error %])}]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions-success
|
||||
:wallet-connect/get-sessions-success
|
||||
(fn [{:keys [db]} [sessions]]
|
||||
(let [network-status (:network/status db)
|
||||
sessions' (mapv (fn [{:keys [sessionJson] :as session}]
|
||||
(assoc session
|
||||
:accounts
|
||||
(-> sessionJson
|
||||
types/json->clj
|
||||
:namespaces
|
||||
:eip155
|
||||
:accounts)))
|
||||
sessions)]
|
||||
{:fx [(when (= network-status :online)
|
||||
[:dispatch [:wallet-connect/fetch-active-sessions]])]
|
||||
:db (assoc db :wallet-connect/sessions sessions')})))
|
||||
(log/info "WalletConnect sessions loaded successfully")
|
||||
{:db (assoc db :wallet-connect/sessions sessions)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions-fail
|
||||
:wallet-connect/get-sessions-error
|
||||
(fn [_ [error]]
|
||||
(log/info "Wallet Connect fetch persisted sessions failed" error)
|
||||
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]]}))
|
||||
(log/error "WalletConnect sessions failed to load" error)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:text (i18n/label :t/wallet-connect-connections-error)}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions
|
||||
(fn [{:keys [now]} _]
|
||||
(let [current-timestamp (quot now 1000)]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_getWalletConnectActiveSessions"
|
||||
;; NOTE: This is the activeSince timestamp to avoid expired sessions
|
||||
:params [current-timestamp]
|
||||
:on-success [:wallet-connect/fetch-persisted-sessions-success]
|
||||
:on-error [:wallet-connect/fetch-persisted-sessions-fail]}]]]})))
|
||||
:wallet-connect/on-new-session
|
||||
(fn [{:keys [db]} [new-session]]
|
||||
{:db (update db
|
||||
:wallet-connect/sessions
|
||||
(fn [sessions]
|
||||
(->> new-session
|
||||
sessions/sdk-session->db-session
|
||||
(conj sessions))))}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/persist-session
|
||||
(fn [_ [session-info]]
|
||||
(let [redirect-url (-> session-info
|
||||
(js->clj :keywordize-keys true)
|
||||
(data-store/get-dapp-redirect-url))]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_addWalletConnectSession"
|
||||
:params [(js/JSON.stringify session-info)]
|
||||
:on-success (fn []
|
||||
(log/info "Wallet Connect session persisted")
|
||||
(rf/dispatch [:wallet-connect/fetch-persisted-sessions])
|
||||
(rf/dispatch [:wallet-connect/redirect-to-dapp redirect-url]))
|
||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/disconnect-persisted-session
|
||||
:wallet-connect/delete-session
|
||||
(fn [{:keys [db]} [topic]]
|
||||
(log/info "Removing session from persistance and state" topic)
|
||||
{:db (update db
|
||||
:wallet-connect/sessions
|
||||
(fn [sessions]
|
||||
(->> sessions
|
||||
(remove #(= (:topic %) topic))
|
||||
(into []))))
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wallet_disconnectWalletConnectSession"
|
||||
:params [topic]
|
||||
:on-success #(log/info "Wallet Connect session disconnected")
|
||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]}))
|
||||
(into []))))}))
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.sessions-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [is are testing]]
|
||||
matcher-combinators.test
|
||||
[re-frame.db :as rf-db]
|
||||
status-im.contexts.wallet.wallet-connect.events.session-responses
|
||||
status-im.contexts.wallet.wallet-connect.events.sessions
|
||||
[test-helpers.unit :as h]))
|
||||
|
||||
(defn- find-fx
|
||||
[fx name]
|
||||
(some #(when (= name (first %)) %) fx))
|
||||
|
||||
(defn- get-fx-arg
|
||||
"Finds the arg value for an effect, if present in the fx vector"
|
||||
[fx fx-name arg-fn]
|
||||
(-> fx
|
||||
(find-fx fx-name)
|
||||
second
|
||||
arg-fn))
|
||||
|
||||
(h/deftest-event :wallet-connect/on-session-delete
|
||||
[event-id dispatch]
|
||||
(testing "successfully deletes the session"
|
||||
(reset! rf-db/app-db {:profile/profile {:test-networks-enabled? false}
|
||||
:wallet-connect/sessions [{:topic "topic"
|
||||
:chains ["eip155:1"]}]})
|
||||
(let [fx (:fx (dispatch [event-id
|
||||
{:topic "topic"
|
||||
:chains ["eip155:1"]}]))
|
||||
get-rpc-fx-arg (partial get-fx-arg fx :json-rpc/call)]
|
||||
(are [expected result] (match? expected result)
|
||||
:json-rpc/call (-> fx (find-fx :json-rpc/call) first)
|
||||
"wallet_disconnectWalletConnectSession" (get-rpc-fx-arg (comp :method first))
|
||||
["topic"] (get-rpc-fx-arg (comp :params first))
|
||||
[:wallet-connect/delete-session "topic"] (get-rpc-fx-arg (comp :on-success first)))))
|
||||
|
||||
(testing "ignore the deletion if session topic not found"
|
||||
(let [topic-1 "topic-1"
|
||||
topic-2 "topic-2"]
|
||||
(reset! rf-db/app-db {:profile/profile {:test-networks-enabled? false}
|
||||
:wallet-connect/sessions [{:topic topic-1
|
||||
:chains ["eip155:1"]}]})
|
||||
(is (match? nil
|
||||
(dispatch [event-id
|
||||
{:topic topic-2
|
||||
:chains ["eip155:1"]}])))))
|
||||
|
||||
(testing "ignore the deletion if the event is for the wrong network mode (testnet/mainnet)"
|
||||
(let [topic "topic"]
|
||||
(reset! rf-db/app-db {:profile/profile {:test-networks-enabled? true}
|
||||
:wallet-connect/sessions [{:topic topic
|
||||
:chains ["eip155:1"]}]})
|
||||
(is (match? nil
|
||||
(dispatch [event-id
|
||||
{:topic topic
|
||||
:chains ["eip155:11155111"]}]))))))
|
||||
|
||||
(h/deftest-event :wallet-connect/disconnect-dapp
|
||||
[event-id dispatch]
|
||||
(testing "disconnecting from dApp when online"
|
||||
(reset! rf-db/app-db {:network/status :online
|
||||
:wallet-connect/web3-wallet "mock"})
|
||||
(let [fx (:fx (dispatch [event-id {:topic "topic"}]))]
|
||||
(are [expected result] (match? expected result)
|
||||
:effects.wallet-connect/disconnect (ffirst fx)
|
||||
"topic" (-> fx first second :topic)
|
||||
"mock" (-> fx first second :web3-wallet))))
|
||||
|
||||
(testing "showing no-internet toast when offline"
|
||||
(reset! rf-db/app-db {:network/status :offline})
|
||||
(is (match? :wallet-connect/no-internet-toast
|
||||
(-> (dispatch [event-id {:topic "topic"}])
|
||||
:fx
|
||||
first
|
||||
second
|
||||
first)))))
|
||||
|
||||
(h/deftest-event :wallet-connect/get-sessions
|
||||
[event-id dispatch]
|
||||
(testing "the fx includes only for the available accounts"
|
||||
(reset! rf-db/app-db {:wallet {:accounts {"available" {:address "0x123"
|
||||
:operable? true}
|
||||
"watch-only" {:address "0x456"
|
||||
:operable? true
|
||||
:watch-only? true}
|
||||
"non-operable" {:address "0x789"
|
||||
:operable? false}}}
|
||||
:network/status :online
|
||||
:wallet-connect/web3-wallet "mock"})
|
||||
(let [fx (:fx (dispatch [event-id]))
|
||||
get-sessions-fx-arg (partial get-fx-arg fx :effects.wallet-connect/get-sessions)]
|
||||
(are [expected result] (match? expected result)
|
||||
:effects.wallet-connect/get-sessions (-> fx (find-fx :effects.wallet-connect/get-sessions) first)
|
||||
true (get-sessions-fx-arg :online?)
|
||||
'("0x123") (get-sessions-fx-arg :addresses)
|
||||
"mock" (get-sessions-fx-arg :web3-wallet)))))
|
||||
|
||||
(h/deftest-event :wallet-connect/get-sessions-success
|
||||
[event-id dispatch]
|
||||
(testing "sessions are stored in the db"
|
||||
(let [sessions '({:topic "123"} {:topic "456"})]
|
||||
(is (match? {:db {:wallet-connect/sessions sessions}}
|
||||
(dispatch [event-id sessions]))))))
|
||||
|
||||
(h/deftest-event :wallet-connect/on-new-session
|
||||
[event-id dispatch]
|
||||
(testing "new session is added to db"
|
||||
(let [sessions '({:topic "123"} {:topic "456"})
|
||||
new-session {:topic "789"}]
|
||||
(reset! rf-db/app-db {:wallet-connect/sessions sessions})
|
||||
(is (match? {:db {:wallet-connect/sessions (conj sessions new-session)}}
|
||||
(dispatch [event-id new-session]))))))
|
||||
|
||||
(h/deftest-event :wallet-connect/delete-session
|
||||
[event-id dispatch]
|
||||
(testing "session is deleted from db"
|
||||
(let [sessions '({:topic "123"} {:topic "456"})
|
||||
expected '({:topic "123"})]
|
||||
(reset! rf-db/app-db {:wallet-connect/sessions sessions})
|
||||
(is (match? {:db {:wallet-connect/sessions expected}}
|
||||
(dispatch [event-id "456"]))))))
|
||||
@@ -4,6 +4,7 @@
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.standard-authentication.core :as standard-authentication]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.footer.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -14,17 +15,25 @@
|
||||
(rf/dispatch [:wallet-connect/respond-current-session password]))
|
||||
|
||||
(defn view
|
||||
[{:keys [warning-label slide-button-text error-text]} & children]
|
||||
[{:keys [warning-label slide-button-text error-state]} & children]
|
||||
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])
|
||||
offline? (rf/sub [:network/offline?])
|
||||
theme (quo.theme/use-theme)]
|
||||
[:<>
|
||||
(when (or offline? error-text)
|
||||
(when (or offline? error-state)
|
||||
[quo/alert-banner
|
||||
{:action? false
|
||||
:text (if offline?
|
||||
(i18n/label :t/wallet-connect-no-internet-warning)
|
||||
error-text)}])
|
||||
{:action? (when error-state true)
|
||||
:text (if offline?
|
||||
(i18n/label :t/wallet-connect-no-internet-warning)
|
||||
(i18n/label (condp = error-state
|
||||
:not-enough-assets-to-pay-gas-fees
|
||||
:t/not-enough-assets-to-pay-gas-fees
|
||||
|
||||
:not-enough-assets
|
||||
:t/not-enough-assets-for-transaction)))
|
||||
:button-text (i18n/label :t/buy-eth)
|
||||
:on-button-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])}])
|
||||
[rn/view {:style style/content-container}
|
||||
(into [rn/view
|
||||
{:style style/data-items-container}]
|
||||
@@ -33,7 +42,7 @@
|
||||
[standard-authentication/slide-button
|
||||
{:size :size-48
|
||||
:track-text slide-button-text
|
||||
:disabled? (or offline? (seq error-text))
|
||||
:disabled? (or offline? error-state)
|
||||
:customization-color customization-color
|
||||
:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/confirm)}]]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.modals.common.style
|
||||
(:require [status-im.constants :as constants]))
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[status-im.constants :as constants]))
|
||||
|
||||
(defn container
|
||||
[bottom]
|
||||
@@ -21,3 +22,23 @@
|
||||
(def data-item
|
||||
{:flex 1
|
||||
:background-color :transparent})
|
||||
|
||||
(def typed-data-item
|
||||
(assoc data-item :margin-bottom 4))
|
||||
|
||||
(def data-border-container
|
||||
{:padding-horizontal 12
|
||||
:padding-top 8
|
||||
:margin-top 10.5
|
||||
:margin-bottom 0
|
||||
:border-width 1
|
||||
:border-color colors/neutral-10
|
||||
:border-radius 16})
|
||||
|
||||
(def data-item-container
|
||||
{:padding 10
|
||||
:margin-top 10.5
|
||||
:margin-bottom 0
|
||||
:border-width 1
|
||||
:border-color colors/neutral-10
|
||||
:border-radius 16})
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
(:require [quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.data-block.view :as data-block]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.fees-data-item.view :as
|
||||
fees-data-item]
|
||||
@@ -10,19 +12,71 @@
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.header.view :as header]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.page-nav.view :as page-nav]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transaction-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- refetch-transaction
|
||||
[]
|
||||
(rf/dispatch [:wallet-connect/process-eth-send-transaction]))
|
||||
|
||||
(def tabs-data
|
||||
[{:id :tab/data :label (i18n/label :t/data)}
|
||||
{:id :tab/hex :label (i18n/label :t/hex)}])
|
||||
|
||||
(defn- render-item
|
||||
[props]
|
||||
(let [[label value] props]
|
||||
[quo/data-item
|
||||
{:card? false
|
||||
:container-style style/data-item
|
||||
:title (str (name label) ":")
|
||||
:subtitle value}]))
|
||||
|
||||
(defn- tab-view
|
||||
[selected-tab]
|
||||
(let [{:keys [transaction]} (rf/sub [:wallet-connect/current-request])
|
||||
transaction-items (rn/use-memo #(-> transaction
|
||||
(transaction-utils/transaction-hex-values->number)
|
||||
(transaction-utils/transactions->display-array))
|
||||
[transaction])]
|
||||
[:<>
|
||||
(case selected-tab
|
||||
:tab/data [gesture/flat-list
|
||||
{:data transaction-items
|
||||
:content-container-style style/data-item-container
|
||||
:render-fn render-item
|
||||
:shows-vertical-scroll-indicator false}]
|
||||
:tab/hex [data-block/view])]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [bottom (safe-area/get-bottom)
|
||||
(let [bottom (safe-area/get-bottom)
|
||||
{:keys [customization-color]
|
||||
:as account} (rf/sub [:wallet-connect/current-request-account-details])
|
||||
dapp (rf/sub [:wallet-connect/current-request-dapp])
|
||||
network (rf/sub [:wallet-connect/current-request-network])
|
||||
:as account} (rf/sub [:wallet-connect/current-request-account-details])
|
||||
dapp (rf/sub [:wallet-connect/current-request-dapp])
|
||||
network (rf/sub [:wallet-connect/current-request-network])
|
||||
{:keys [max-fees-fiat-formatted
|
||||
error-state]} (rf/sub [:wallet-connect/current-request-transaction-information])]
|
||||
(rn/use-unmount #(rf/dispatch [:wallet-connect/on-request-modal-dismissed]))
|
||||
error-state estimated-time]} (rf/sub
|
||||
[:wallet-connect/current-request-transaction-information])
|
||||
[selected-tab set-selected-tab] (rn/use-state (:id (first tabs-data)))
|
||||
on-change-tab #(set-selected-tab %)
|
||||
refetch-interval-ref (rn/use-ref nil)
|
||||
clear-interval (rn/use-callback (fn []
|
||||
(when (.-current refetch-interval-ref)
|
||||
(js/clearInterval
|
||||
(.-current refetch-interval-ref))))
|
||||
[refetch-interval-ref])]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(clear-interval)
|
||||
(set! (.-current refetch-interval-ref)
|
||||
(js/setInterval refetch-transaction constants/wallet-connect-transaction-refresh-interval-ms))))
|
||||
|
||||
(rn/use-unmount (fn []
|
||||
(clear-interval)
|
||||
(rf/dispatch [:wallet-connect/on-request-modal-dismissed])))
|
||||
|
||||
[rn/view {:style (style/container bottom)}
|
||||
[quo/gradient-cover {:customization-color customization-color}]
|
||||
[page-nav/view
|
||||
@@ -33,17 +87,17 @@
|
||||
{:label (i18n/label :t/wallet-connect-send-transaction-header)
|
||||
:dapp dapp
|
||||
:account account}]
|
||||
[data-block/view]]
|
||||
[quo/segmented-control
|
||||
{:size 32
|
||||
:blur? false
|
||||
:default-active :tab/data
|
||||
:data tabs-data
|
||||
:on-change on-change-tab}]
|
||||
[tab-view selected-tab]]
|
||||
[footer/view
|
||||
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
|
||||
:slide-button-text (i18n/label :t/slide-to-send)
|
||||
:error-text (when error-state
|
||||
(i18n/label (condp = error-state
|
||||
:not-enough-assets-to-pay-gas-fees
|
||||
:t/not-enough-assets-to-pay-gas-fees
|
||||
|
||||
:not-enough-assets
|
||||
:t/not-enough-assets)))}
|
||||
:error-state error-state}
|
||||
[quo/data-item
|
||||
{:status :default
|
||||
:card? false
|
||||
@@ -54,5 +108,12 @@
|
||||
:subtitle (:full-name network)}]
|
||||
[fees-data-item/view
|
||||
{:fees max-fees-fiat-formatted
|
||||
:fees-error error-state}]]]]))
|
||||
:fees-error error-state}]
|
||||
[quo/data-item
|
||||
{:card? false
|
||||
:container-style style/data-item
|
||||
:title (i18n/label :t/est-time)
|
||||
:subtitle (if estimated-time
|
||||
(i18n/label :t/time-in-mins {:minutes estimated-time})
|
||||
(i18n/label :t/unknown))}]]]]))
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.modals.sign-message.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.data-block.view :as data-block]
|
||||
[status-im.common.raw-data-block.view :as data-block]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.fees-data-item.view :as
|
||||
fees-data-item]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.footer.view :as footer]
|
||||
@@ -12,6 +13,37 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn typed-data-field
|
||||
[{:keys [label value]}]
|
||||
[quo/data-item
|
||||
{:card? false
|
||||
:container-style style/typed-data-item
|
||||
:title label
|
||||
:subtitle value}])
|
||||
|
||||
(defn typed-data-view
|
||||
[]
|
||||
(let [display-data (rf/sub [:wallet-connect/current-request-display-data])]
|
||||
[gesture/flat-list
|
||||
{:data display-data
|
||||
:style style/data-border-container
|
||||
:over-scroll-mode :never
|
||||
:content-container-style {:padding-bottom 12}
|
||||
:render-fn typed-data-field
|
||||
:shows-vertical-scroll-indicator false}]))
|
||||
|
||||
(defn message-data-view
|
||||
[]
|
||||
(let [display-data (rf/sub [:wallet-connect/current-request-display-data])]
|
||||
[data-block/view display-data]))
|
||||
|
||||
(defn display-data-view
|
||||
[]
|
||||
(let [typed-data? (rf/sub [:wallet-connect/typed-data-request?])]
|
||||
(if typed-data?
|
||||
[typed-data-view]
|
||||
[message-data-view])))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [bottom (safe-area/get-bottom)
|
||||
@@ -29,7 +61,7 @@
|
||||
{:label (i18n/label :t/wallet-connect-sign-message-header)
|
||||
:dapp dapp
|
||||
:account account}]
|
||||
[data-block/view]]
|
||||
[display-data-view]]
|
||||
[footer/view
|
||||
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
|
||||
:slide-button-text (i18n/label :t/slide-to-sign)}
|
||||
|
||||
@@ -57,3 +57,25 @@
|
||||
[chain-id]
|
||||
(-> (rpc-events/call-async "wallet_getSuggestedFees" true chain-id)
|
||||
(promesa/then transforms/js->clj)))
|
||||
|
||||
(defn wallet-disconnect-persisted-session
|
||||
[topic]
|
||||
(rpc-events/call-async "wallet_disconnectWalletConnectSession" true topic))
|
||||
|
||||
(defn wallet-get-persisted-sessions
|
||||
([]
|
||||
(let [now (-> (js/Date.) .getTime (quot 1000))]
|
||||
(wallet-get-persisted-sessions now)))
|
||||
([expiry-timestamp]
|
||||
(rpc-events/call-async "wallet_getWalletConnectActiveSessions" false expiry-timestamp)))
|
||||
|
||||
(defn wallet-persist-session
|
||||
[session]
|
||||
(->> session
|
||||
transforms/clj->json
|
||||
(rpc-events/call-async "wallet_addWalletConnectSession" false)))
|
||||
|
||||
(defn wallet-get-transaction-estimated-time
|
||||
[chain-id max-fee-per-gas]
|
||||
(-> (rpc-events/call-async "wallet_getTransactionEstimatedTime" true chain-id max-fee-per-gas)
|
||||
(promesa/then transforms/js->clj)))
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.sessions
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[promesa.core :as promesa]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn sdk-session->db-session
|
||||
@@ -42,3 +48,102 @@
|
||||
first
|
||||
(string/split #":")
|
||||
last)))
|
||||
|
||||
(defn- parse-session-accounts
|
||||
[{:keys [sessionJson] :as session}]
|
||||
(assoc session
|
||||
:accounts
|
||||
(-> sessionJson
|
||||
:namespaces
|
||||
:eip155
|
||||
:accounts)))
|
||||
|
||||
(defn- find-inactive-sessions
|
||||
[active-sessions persisted-sessions]
|
||||
(->> persisted-sessions
|
||||
(filter #(->> %
|
||||
:topic
|
||||
(contains? (->> active-sessions
|
||||
(map :topic)
|
||||
set))
|
||||
not))))
|
||||
|
||||
(defn get-persisted-sessions
|
||||
[]
|
||||
(-> (rpc/wallet-get-persisted-sessions)
|
||||
(promesa/then #(map parse-session-accounts %))
|
||||
(promesa/catch (fn [err]
|
||||
(throw (ex-info "Failed to get persisted WalletConnect sessions"
|
||||
{:error err
|
||||
:code :error/wc-get-persisted-sessions}))))))
|
||||
|
||||
(defn get-active-sessions
|
||||
[web3-wallet addresses]
|
||||
(-> (wallet-connect/get-active-sessions web3-wallet)
|
||||
(promesa/then #(->>
|
||||
(transforms/js->clj %)
|
||||
vals
|
||||
(map sdk-session->db-session)
|
||||
(filter-sessions-for-account-addresses addresses)))
|
||||
(promesa/catch (fn [err]
|
||||
(throw (ex-info "Failed to get active WalletConnect sessions"
|
||||
{:error err
|
||||
:code :error/wc-get-active-sessions}))))))
|
||||
|
||||
(defn sync-persisted-sessions
|
||||
[active-sessions persisted-sessions]
|
||||
(-> (promesa/all
|
||||
(for [topic (find-inactive-sessions active-sessions
|
||||
persisted-sessions)]
|
||||
(do (log/info "Syncing disconnected session with persistance" topic)
|
||||
(rpc/wallet-disconnect-persisted-session topic))))
|
||||
(promesa/catch (fn [err]
|
||||
(throw (ex-info "Failed to synchronize persisted sessions"
|
||||
{:error err
|
||||
:code :error/wc-sync-persisted-sessions}))))))
|
||||
|
||||
(defn get-sessions
|
||||
[web3-wallet addresses online?]
|
||||
(promesa/let [persisted-sessions (get-persisted-sessions)]
|
||||
(if online?
|
||||
(promesa/let [active-sessions (get-active-sessions web3-wallet addresses)]
|
||||
(sync-persisted-sessions active-sessions persisted-sessions)
|
||||
active-sessions)
|
||||
persisted-sessions)))
|
||||
|
||||
(defn disconnect
|
||||
[web3-wallet topic]
|
||||
(let [reason (wallet-connect/get-sdk-error constants/wallet-connect-user-disconnected-reason-key)]
|
||||
(->
|
||||
(promesa/do
|
||||
(wallet-connect/disconnect-session {:web3-wallet web3-wallet
|
||||
:topic topic
|
||||
:reason reason})
|
||||
(rpc/wallet-disconnect-persisted-session topic))
|
||||
(promesa/catch (fn [err]
|
||||
(throw (ex-info "Failed to disconnect dapp"
|
||||
{:err err
|
||||
:code :error/wc-disconnect-dapp})))))))
|
||||
|
||||
(defn approve
|
||||
[{:keys [web3-wallet address session-networks proposal-request]}]
|
||||
(let [{:keys [params id]} proposal-request
|
||||
accounts (-> (partial networks/format-eip155-address address)
|
||||
(map session-networks))]
|
||||
(-> (promesa/let [session
|
||||
(wallet-connect/approve-session
|
||||
{:web3-wallet web3-wallet
|
||||
:id id
|
||||
:approved-namespaces (->>
|
||||
{:eip155
|
||||
{:chains session-networks
|
||||
:accounts accounts
|
||||
:methods constants/wallet-connect-supported-methods
|
||||
:events constants/wallet-connect-supported-events}}
|
||||
(wallet-connect/build-approved-namespaces params))})]
|
||||
(rpc/wallet-persist-session session)
|
||||
(transforms/js->clj session))
|
||||
(promesa/catch (fn [err]
|
||||
(throw (ex-info "Failed to approve session"
|
||||
{:err err
|
||||
:code :error/wc-approve})))))))
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.signing
|
||||
(:require [native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.hex :as hex]
|
||||
[utils.number :as number]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn typed-data-chain-id
|
||||
"Returns the `:chain-id` from typed data if it's present and if the EIP712 domain defines it. Without
|
||||
the `:chain-id` in the domain type, it will not be signed as part of the typed-data."
|
||||
[typed-data]
|
||||
(let [chain-id-type? (->> typed-data
|
||||
:types
|
||||
:EIP712Domain
|
||||
(some #(= "chainId" (:name %))))
|
||||
data-chain-id (-> typed-data
|
||||
:domain
|
||||
:chainId
|
||||
number/parse-int)]
|
||||
(when chain-id-type?
|
||||
data-chain-id)))
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.hex :as hex]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn eth-sign
|
||||
[password address data]
|
||||
@@ -38,13 +22,3 @@
|
||||
(-> (rpc/wallet-hash-message-eip-191 data)
|
||||
(promesa/then #(rpc/wallet-sign-message % address password))
|
||||
(promesa/then hex/prefix-hex)))
|
||||
|
||||
(defn eth-sign-typed-data
|
||||
[password address data chain-id-eip155 version]
|
||||
(let [legacy? (= version :v1)
|
||||
chain-id (networks/eip155->chain-id chain-id-eip155)]
|
||||
(rpc/wallet-safe-sign-typed-data data
|
||||
address
|
||||
password
|
||||
chain-id
|
||||
legacy?)))
|
||||
|
||||
@@ -51,12 +51,16 @@
|
||||
(transforms/js-stringify 0)))
|
||||
|
||||
(defn beautify-transaction
|
||||
[tx]
|
||||
(-> tx
|
||||
clj->js
|
||||
(js/JSON.stringify nil 2)))
|
||||
|
||||
(defn transaction-hex-values->number
|
||||
[tx]
|
||||
(let [hex->number #(-> % (subs 2) native-module/hex-to-number)]
|
||||
(-> tx
|
||||
(format-tx-hex-values hex->number)
|
||||
clj->js
|
||||
(js/JSON.stringify nil 2))))
|
||||
(format-tx-hex-values hex->number))))
|
||||
|
||||
(defn- gwei->hex
|
||||
[gwei]
|
||||
@@ -121,10 +125,14 @@
|
||||
tx-priority
|
||||
suggested-fees)
|
||||
prepare-transaction-for-rpc
|
||||
(rpc/wallet-build-transaction chain-id))]
|
||||
(rpc/wallet-build-transaction chain-id))
|
||||
estimated-time (rpc/wallet-get-transaction-estimated-time
|
||||
chain-id
|
||||
(:maxPriorityFeePerGas suggested-fees))]
|
||||
{:tx-args tx-args
|
||||
:tx-hash message-to-sign
|
||||
:suggested-fees suggested-fees}))
|
||||
:suggested-fees suggested-fees
|
||||
:estimated-time estimated-time}))
|
||||
|
||||
(defn sign-transaction
|
||||
[password address tx-hash tx-args chain-id]
|
||||
@@ -141,3 +149,11 @@
|
||||
tx-args
|
||||
signature)]
|
||||
tx))
|
||||
|
||||
(defn transactions->display-array
|
||||
[data]
|
||||
(remove (fn [[k v]]
|
||||
(or (= v "0x")
|
||||
(= k :MultiTransactionID)
|
||||
(= k :Symbol)))
|
||||
data))
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.typed-data
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.number :as number]))
|
||||
|
||||
(declare flatten-data)
|
||||
|
||||
(defn- format-flattened-key
|
||||
[k]
|
||||
(cond
|
||||
(keyword? k) (name k)
|
||||
(number? k) (str k)
|
||||
(string? k) k
|
||||
:else "unsupported-key"))
|
||||
|
||||
(defn- flatten-map
|
||||
[data path]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(->> (format-flattened-key k)
|
||||
(conj path)
|
||||
(flatten-data v acc)))
|
||||
[]
|
||||
data))
|
||||
|
||||
(defn- flatten-vec
|
||||
[data path]
|
||||
(->> data
|
||||
(map-indexed vector)
|
||||
(reduce (fn [acc [idx v]]
|
||||
(->> (str idx)
|
||||
(conj path)
|
||||
(flatten-data v acc)))
|
||||
[])))
|
||||
|
||||
(defn flatten-data
|
||||
"Recursively flatten a map or vector into a flat vector.
|
||||
|
||||
e.g. `[[[\"person\" \"first-name\"] \"Rich\"]
|
||||
[[[\"person\" \"last-name\"] \"Hickey\"]]]`"
|
||||
([value]
|
||||
(flatten-data value [] []))
|
||||
([value acc path]
|
||||
(cond
|
||||
(map? value) (into acc (flatten-map value path))
|
||||
(vector? value) (into acc (flatten-vec value path))
|
||||
:else (conj acc [path value]))))
|
||||
|
||||
(defn format-fields
|
||||
"Format the fields into maps with `:label` & `:value`, where the label
|
||||
is the flattened keys joined with a separator
|
||||
|
||||
e.g. `{:label \"person: first-name:\" :value \"Rich\"}`"
|
||||
[data separator]
|
||||
(mapv (fn [[kv v]]
|
||||
{:label (-> separator
|
||||
(string/join kv)
|
||||
(str separator)
|
||||
string/trim)
|
||||
:value v})
|
||||
data))
|
||||
|
||||
(defn flatten-typed-data
|
||||
"Flatten typed data and prepare it for UI"
|
||||
[typed-data]
|
||||
(-> typed-data
|
||||
(select-keys [:domain :message])
|
||||
flatten-data
|
||||
(format-fields ": ")))
|
||||
|
||||
(defn get-chain-id
|
||||
"Returns the `:chain-id` from typed data if it's present and if the EIP712 domain defines it. Without
|
||||
the `:chain-id` in the domain type, it will not be signed as part of the typed-data."
|
||||
[typed-data]
|
||||
(let [chain-id-type? (->> typed-data
|
||||
:types
|
||||
:EIP712Domain
|
||||
(some #(= "chainId" (:name %))))
|
||||
data-chain-id (-> typed-data
|
||||
:domain
|
||||
:chainId
|
||||
number/parse-int)]
|
||||
(when chain-id-type?
|
||||
data-chain-id)))
|
||||
|
||||
(defn sign
|
||||
[password address data chain-id-eip155 version]
|
||||
(let [legacy? (= version :v1)
|
||||
chain-id (networks/eip155->chain-id chain-id-eip155)]
|
||||
(rpc/wallet-safe-sign-typed-data data
|
||||
address
|
||||
password
|
||||
chain-id
|
||||
legacy?)))
|
||||
|
||||
(defn typed-data-request?
|
||||
[method]
|
||||
(contains?
|
||||
#{constants/wallet-connect-eth-sign-typed-v4-method
|
||||
constants/wallet-connect-eth-sign-typed-method}
|
||||
method))
|
||||
@@ -0,0 +1,52 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.typed-data-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as sut]))
|
||||
|
||||
(deftest flatten-data-test
|
||||
(testing "correctly returns the fallback when key is not string/keyword/number"
|
||||
(is (match? [[["unsupported-key"] "value"]]
|
||||
(sut/flatten-data {[1 2] "value"}))))
|
||||
|
||||
(testing "correctly flattens a simple map"
|
||||
(is (match? [[["zero"] 0]
|
||||
[["one"] 1]
|
||||
[["2"] 2]]
|
||||
(sut/flatten-data {:zero 0
|
||||
"one" 1
|
||||
2 2}))))
|
||||
|
||||
(testing "correctly flattens a simple vec"
|
||||
(is (match? [[["0"] "zero"] [["1"] "one"]]
|
||||
(sut/flatten-data ["zero" "one"]))))
|
||||
|
||||
(testing "correctly flattens a nested map"
|
||||
(is (match? [[["nested" "child"] "child value"]
|
||||
[["nested" "nested" "0"] "child one"]
|
||||
[["nested" "nested" "1"] "child two"]
|
||||
[["flat"] "child value"]]
|
||||
(sut/flatten-data {:nested {:child "child value"
|
||||
:nested ["child one" "child two"]}
|
||||
:flat "child value"}))))
|
||||
|
||||
(testing "correctly flattens a nested vector"
|
||||
(is (match? [[["0" "flat"] 1]
|
||||
[["0" "nested-vector" "0"] 1]
|
||||
[["0" "nested-vector" "1"] 2]
|
||||
[["0" "nested-map" "one"] 1]]
|
||||
(sut/flatten-data [{:flat 1
|
||||
:nested-vector [1 2]
|
||||
:nested-map {:one 1}}])))))
|
||||
|
||||
(deftest flatten-typed-data-test
|
||||
(testing "successfully extracts, flattens and formats the typed data"
|
||||
(is (match? [{:label "domain: chain-id:" :value 1}
|
||||
{:label "message: to: address:" :value "0x"}
|
||||
{:label "message: from: address:" :value "0x"}
|
||||
{:label "message: amount:" :value "0x"}]
|
||||
(sut/flatten-typed-data {:domain {:chain-id 1}
|
||||
:types {:Tx [{:name "to"
|
||||
:type "address"}]}
|
||||
:message {:to {:address "0x"}
|
||||
:from {:address "0x"}
|
||||
:amount "0x"}})))))
|
||||
@@ -31,7 +31,6 @@
|
||||
::wallet.import-private-key (enabled-in-env? :FLAG_IMPORT_PRIVATE_KEY_ENABLED)
|
||||
::wallet.long-press-watch-only-asset (enabled-in-env? :FLAG_LONG_PRESS_WATCH_ONLY_ASSET_ENABLED)
|
||||
::wallet.saved-addresses (enabled-in-env? :WALLET_SAVED_ADDRESSES)
|
||||
::wallet.swap (enabled-in-env? :FLAG_SWAP_ENABLED)
|
||||
::wallet.wallet-connect (enabled-in-env? :FLAG_WALLET_CONNECT_ENABLED)
|
||||
::wallet.custom-network-amounts (enabled-in-env? :FLAG_WALLET_CUSTOM_NETWORK_AMOUNTS_ENABLED)})
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
@@ -16,6 +17,14 @@
|
||||
:<- [:wallet-connect/current-request]
|
||||
:-> :display-data)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-method
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [request]
|
||||
(-> request
|
||||
:event
|
||||
data-store/get-request-method)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-account-details
|
||||
:<- [:wallet-connect/current-request-address]
|
||||
@@ -45,3 +54,8 @@
|
||||
:wallet-connect/current-request-network
|
||||
:<- [:wallet-connect/chain-id]
|
||||
networks/chain-id->network-details)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/typed-data-request?
|
||||
:<- [:wallet-connect/current-request-method]
|
||||
typed-data/typed-data-request?)
|
||||
|
||||
@@ -54,20 +54,23 @@
|
||||
:<- [:profile/currency-symbol]
|
||||
(fn [[chain-id max-fees-wei transaction eth-token currency currency-symbol]]
|
||||
(when transaction
|
||||
(let [max-fees-ether (money/wei->ether max-fees-wei)
|
||||
max-fees-fiat (wallet-utils/calculate-token-fiat-value {:currency currency
|
||||
:balance max-fees-ether
|
||||
:token eth-token})
|
||||
max-fees-fiat-formatted (-> (wallet-utils/get-standard-crypto-format eth-token max-fees-ether)
|
||||
(wallet-utils/get-standard-fiat-format currency-symbol
|
||||
max-fees-fiat))
|
||||
balance (-> eth-token
|
||||
(get-in [:balances-per-chain chain-id :raw-balance])
|
||||
money/bignumber)
|
||||
tx-value (money/bignumber (:value transaction))
|
||||
total-transaction-value (money/add max-fees-wei tx-value)]
|
||||
(let [max-fees-ether (money/wei->ether max-fees-wei)
|
||||
max-fees-fiat (wallet-utils/calculate-token-fiat-value {:currency currency
|
||||
:balance max-fees-ether
|
||||
:token eth-token})
|
||||
max-fees-fiat-formatted (-> (wallet-utils/get-standard-crypto-format eth-token
|
||||
max-fees-ether)
|
||||
(wallet-utils/get-standard-fiat-format currency-symbol
|
||||
max-fees-fiat))
|
||||
balance (-> eth-token
|
||||
(get-in [:balances-per-chain chain-id :raw-balance])
|
||||
money/bignumber)
|
||||
tx-value (money/bignumber (:value transaction))
|
||||
total-transaction-value (money/add max-fees-wei tx-value)
|
||||
estimated-time-formatted (wallet-utils/estimated-time-format (:estimated-time transaction))]
|
||||
{:total-transaction-value total-transaction-value
|
||||
:balance balance
|
||||
:estimated-time estimated-time-formatted
|
||||
:max-fees max-fees-wei
|
||||
:max-fees-fiat-value max-fees-fiat
|
||||
:max-fees-fiat-formatted max-fees-fiat-formatted
|
||||
|
||||
@@ -6,8 +6,3 @@
|
||||
[distance-from-list-top chat-list-scroll-y callback]
|
||||
(.messagesListOnScroll ^js worklets distance-from-list-top chat-list-scroll-y callback))
|
||||
|
||||
(defn use-messages-scrolled-to-threshold
|
||||
[distance-from-list-top threshold]
|
||||
(.useMessagesScrolledToThreshold ^js worklets
|
||||
distance-from-list-top
|
||||
threshold))
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
(ns utils.worklets.chat.messenger.navigation)
|
||||
|
||||
(def ^:private worklets (js/require "../src/js/worklets/chat/messenger/navigation.js"))
|
||||
|
||||
(defn navigation-header-opacity
|
||||
[distance-from-list-top all-loaded? chat-screen-layout-calculations-complete? start-position]
|
||||
(.navigationHeaderOpacity ^js worklets
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
chat-screen-layout-calculations-complete?
|
||||
start-position))
|
||||
|
||||
(defn navigation-header-position
|
||||
[distance-from-list-top all-loaded? top-bar-height start-position]
|
||||
(.navigationHeaderPosition ^js worklets
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
top-bar-height
|
||||
start-position))
|
||||
|
||||
(defn navigation-buttons-complete-opacity
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
(.navigationButtonsCompleteOpacity ^js worklets chat-screen-layout-calculations-complete?))
|
||||
|
||||
(defn interpolate-navigation-view-opacity
|
||||
[props]
|
||||
(.interpolateNavigationViewOpacity ^js worklets (clj->js props)))
|
||||
@@ -1,11 +0,0 @@
|
||||
(ns utils.worklets.chat.messenger.placeholder)
|
||||
|
||||
(def ^:private worklets (js/require "../src/js/worklets/chat/messenger/placeholder.js"))
|
||||
|
||||
(defn placeholder-opacity
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
(.placeholderOpacity ^js worklets chat-screen-layout-calculations-complete?))
|
||||
|
||||
(defn placeholder-z-index
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
(.placeholderZIndex ^js worklets chat-screen-layout-calculations-complete?))
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v2.3.0",
|
||||
"commit-sha1": "effde33d493ff52b66c8013067c9aa6444d84473",
|
||||
"src-sha256": "1rd0mczdkvjm9pbmza234v1jy1bvqh3ni2xck1l42ha4sld2aqjl"
|
||||
"version": "hop-path-processor-update",
|
||||
"commit-sha1": "0af7eec514bbcd105461f779d8d794b037c37279",
|
||||
"src-sha256": "1wfm28afb1mqn8vd1w426xvkg0nj9cycwc35swqdcqj6ga40cm1b"
|
||||
}
|
||||
|
||||
@@ -374,6 +374,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
def test_community_message_edit(self):
|
||||
message_before_edit, message_after_edit = 'Message BEFORE edit', "Message AFTER edit 2"
|
||||
self.channel_1.send_message(message_before_edit)
|
||||
self.channel_1.chat_element_by_text(message_before_edit).wait_for_sent_state()
|
||||
self.channel_1.edit_message_in_chat(message_before_edit, message_after_edit)
|
||||
for channel in (self.channel_1, self.channel_2):
|
||||
if not channel.element_by_text_part(message_after_edit).is_element_displayed(60):
|
||||
@@ -391,6 +392,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
message_to_delete_everyone = 'delete for everyone'
|
||||
message_to_delete_for_me = 'delete for me'
|
||||
self.channel_2.send_message(message_to_delete_everyone)
|
||||
self.channel_2.chat_element_by_text(message_to_delete_everyone).wait_for_sent_state()
|
||||
self.home_2.just_fyi('Delete for message everyone. Checking that message is deleted for all members')
|
||||
self.channel_2.delete_message_in_chat(message_to_delete_everyone)
|
||||
for channel in (self.channel_1, self.channel_2):
|
||||
|
||||
@@ -1016,9 +1016,8 @@ class ChatView(BaseView):
|
||||
|
||||
def edit_message_in_chat(self, message_to_edit, message_to_update):
|
||||
self.driver.info("Looking for message '%s' to edit it" % message_to_edit)
|
||||
element = self.element_by_translation_id("edit-message")
|
||||
self.chat_element_by_text(message_to_edit).message_body.long_press_until_element_is_shown(element)
|
||||
element.click()
|
||||
self.chat_element_by_text(message_to_edit).message_body.long_press_element()
|
||||
self.element_by_translation_id("edit-message").click()
|
||||
self.chat_message_input.clear()
|
||||
self.chat_message_input.send_keys(message_to_update)
|
||||
self.send_message_button.click()
|
||||
@@ -1029,7 +1028,6 @@ class ChatView(BaseView):
|
||||
delete_button = self.element_by_translation_id("delete-for-everyone")
|
||||
else:
|
||||
delete_button = self.element_by_translation_id("delete-for-me")
|
||||
# self.chat_element_by_text(message).message_body.long_press_until_element_is_shown(delete_button)
|
||||
self.chat_element_by_text(message).message_body.long_press_element()
|
||||
delete_button.click()
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ class HomeView(BaseView):
|
||||
if self.toast_content_element.is_element_displayed(10):
|
||||
self.toast_content_element.wait_for_invisibility_of_element()
|
||||
try:
|
||||
self.notifications_unread_badge.wait_for_visibility_of_element(30)
|
||||
self.notifications_unread_badge.wait_for_visibility_of_element(60)
|
||||
except TimeoutException:
|
||||
pass
|
||||
self.open_activity_center_button.click_until_presence_of_element(self.close_activity_centre)
|
||||
|
||||
@@ -1124,6 +1124,7 @@
|
||||
"help-improve-status": "Help improve Status",
|
||||
"help-us-improve-status": "Help us improve Status",
|
||||
"here-is-a-cat-in-a-box-instead": "Here’s a cat in a box instead",
|
||||
"hex": "Hex",
|
||||
"hide": "Hide",
|
||||
"hide-content-when-switching-apps": "Block screenshots",
|
||||
"hide-content-when-switching-apps-ios": "Hide preview",
|
||||
@@ -1737,6 +1738,7 @@
|
||||
"not-connected-nodes": "Not connected to a status node",
|
||||
"not-connected-to-peers": "Not connected to any peers",
|
||||
"not-enough-assets": "Not enough assets to complete transaction",
|
||||
"not-enough-assets-for-transaction": "Not enough assets for transaction",
|
||||
"not-enough-assets-to-pay-gas-fees": "Not enough assets to pay gas fees",
|
||||
"not-enough-liquidity": "Not enough liquidity. Lower token amount or try again later.",
|
||||
"not-enough-snt": "Not enough SNT",
|
||||
@@ -2484,8 +2486,8 @@
|
||||
"token-auto-validate-name-error": "Wrong name for token {{symbol}} at address {{address}} - set to {{expected}} but detected as {{actual}}",
|
||||
"token-auto-validate-symbol-error": "Wrong symbol for token {{symbol}} at address {{address}} - set to {{expected}} but detected as {{actual}}",
|
||||
"token-details": "Token details",
|
||||
"token-gated-communities": "Token gated communities",
|
||||
"token-gated-communities-info": "Here will be something relevant about this topic. This will help the user get more context and therefore have a better understanding of it.",
|
||||
"token-gated-communities": "Token-gated communities",
|
||||
"token-gated-communities-info": "If you want to join a token-gated community, you need to meet the token requirements set by the community Owner.\n\nThe Status app automatically checks if you meet the community requirements. If you meet the requirements, the option to join the community is available.",
|
||||
"token-master": "Token Master",
|
||||
"token-not-available-on-networks": "{{token-symbol}} is not available on {{networks}}.",
|
||||
"token-not-available-on-receiver-networks": "{{token-symbol}} is not available on the recipient’s desired networks. Proceed with caution.",
|
||||
@@ -2696,6 +2698,7 @@
|
||||
"wallet-connect": "Wallet Connect",
|
||||
"wallet-connect-2.0": "Wallet Connect 2.0",
|
||||
"wallet-connect-app-connected": "is connected",
|
||||
"wallet-connect-connections-error": "Failed to get dApps connections",
|
||||
"wallet-connect-go-back": "Go back to your browser or dapp",
|
||||
"wallet-connect-label": "WalletConnect",
|
||||
"wallet-connect-networks-not-supported": "{{dapp}} requires an unsupported network.",
|
||||
|
||||
Reference in New Issue
Block a user