Compare commits

...
Author SHA1 Message Date
Brian Sztamfater 0e8db12b64 feat: prepare events for sending collectible
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-01-11 12:18:08 -03:00
Ulises M 8a3e53690c Show collectibles to send and add filter capabilities
Additionally,
- Replace the sub `:wallet/collectibles-per-account` by `:wallet/current-viewing-account-collectibles` since
  it was only used for the current viewing account and simplified the code.
- Refactor the select-asset view.
2024-01-11 12:18:05 -03:00
Siddarth Kumar ecd7147113 fix: random local make-run ios failures (#18446)
In this commit we build iOS `status-go` for both targets `amd64` and for `arm64` otherwise we get random failures when running `make run-ios`.
Maybe this was an impact of Xcode Upgrade Or RN Upgrade or MacOS Upgrade, it is not clear at the moment.
This will increase the time it took for iOS to be built locally, but it is better to be slow rather than have random build failures.
2024-01-11 12:14:48 -03:00
Brian Sztamfater f87fbf8b1a fix: route not found when attempting to transfer assets to additional eth account (#18325)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-01-11 12:14:48 -03:00
mmilad75andJamie Caprani 1fde6476f4 Implement about tab on collectible page (#18269)
* add basics

* finalize component

* fix lint issues

* move color to props

* move variants to props

* change file structure

* working

* finalize loader

* fix lint issues

* fix style issues

* add tabs structure

* add basics

* draft codes

* draft

* make codes work after rebase

* fix lint issues

* remove Permissions tab

* revert codes

* finalize code

* fix lint issues

* revert podfile.lock

* create new reg-sub for traits and chain-id

* add real title and description for about tab

* resolve comments

* fix overview tab

* add tests

* resolve comments

---------

Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
2024-01-11 12:14:38 -03:00
Yevheniia Berdnyk 312ad42fa6 e2e: fixes 10.01 2024-01-11 12:13:04 -03:00
Mohamed Javid f254c312d4 Wallet - Initialize event, refactor networks data and bug fix (#18374)
This commit:

- Introduces new event ":wallet/initialize" to group events that need to be called on login
- Refactors wallet networks to use the nested structure in re-frame
- Fixes a bug when updating the testnet network preferences of an account the production network preferences update

---------

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-01-11 12:13:03 -03:00
jakub 7103a26f16 ci: fix handling of Android builds on Apple ARM64
Now that this PR has been merged:

* https://github.com/status-im/status-mobile/pull/16237

We need to handle ARM using an override.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2024-01-11 12:13:02 -03:00
jakub 4574df2f8a nix: fix regex in clean.sh script
Repo used to be called `status-react`.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2024-01-11 12:13:02 -03:00
Parvesh Monu 591047de2a Refactor compose (#18339)
- Removed show-floating-scroll-down-button? reagent atom
- Created event for scroll-to-bottom-fn
- Renamed chat.ui/close-chat
2024-01-11 12:13:01 -03:00
Omar Basem 6fc8d08733 refactor: kotlinify log (#18337)
refactor: kotlinify log
2024-01-11 12:13:01 -03:00
Ajay Sivan 5af5e57795 Move selected addresses for permissions to app db (#18430) 2024-01-11 12:13:00 -03:00
yqrashawn 7efa0d1ae8 fix: profile screen initial avatar alignment (#18426)
https://github.com/status-im/status-go/compare/debfe1ca...debfe1ca

Signed-off-by: yqrashawn <namy.19@gmail.com>
2024-01-11 12:13:00 -03:00
frank bce33b2138 fix: mark all notifications as read not work (#18107)
https://github.com/status-im/status-go/compare/5cb19722...5cb19722
2024-01-11 12:13:00 -03:00
Ibrahem Khalil 60bd74c234 Add internal-link component for #17116 (#18109) 2024-01-11 12:12:59 -03:00
Ibrahem Khalil 794152d99c Drop clj-kondo dir from linting (#18328) 2024-01-11 12:12:59 -03:00
Omar Basem 00124db899 Wallet: suggested routes list (#18388)
* wallet: suggested routes list
2024-01-11 12:12:59 -03:00
Omar Basem 3331a31e2d kotlinify thread pool (#18366)
chore: Kotlinify thread pool
2024-01-11 12:12:59 -03:00
Lungu Cristian 278af1c51f Biometrics in new settings (#18258)
* feat: added biometrics setting to new-settings

* fix: fix renaming issues from status-im2

* ref: addressed @cammellos' review comments

* fix: open password settings in a modal

* ref: addressed review comments

* fix: disabling biometric clears auth-method from keychain

* chore: quo/overlay seqs the childrend so need to add keys

* fix: don't pass the password unmasked between events to avoid leaks
2024-01-11 12:12:58 -03:00
Ulises M 829f26cc1e Lint fix 2024-01-08 19:16:02 -06:00
Ulises M 30dc7518bd Add empty state image 2024-01-08 19:16:02 -06:00
Ulises M 9cec67059a Add translations for not found state 2024-01-08 19:16:02 -06:00
Ulises M 25e40df72d Lint fix 2024-01-08 19:16:01 -06:00
Ulises M 8ac44f9ae5 Generalize collectibles-tab view 2024-01-08 19:16:01 -06:00
Ulises M 073d486aed Show collectibles to send and add filter capabilities
Additionally,
- Replace the sub `:wallet/collectibles-per-account` by `:wallet/current-viewing-account-collectibles` since
  it was only used for the current viewing account and simplified the code.
- Refactor the select-asset view.
2024-01-08 19:16:01 -06:00
Ulises M c1ff618cde Code style 2024-01-08 19:16:00 -06:00
99 changed files with 2060 additions and 781 deletions
-5
View File
@@ -194,8 +194,3 @@ test/appium/tests/users.py
## git hooks
lefthook.yml
## clj-kondo
/.clj-kondo/taoensso/*
/.clj-kondo/babashka/*
/.clj-kondo/rewrite-clj/rewrite-clj/config.edn
+5 -3
View File
@@ -279,8 +279,9 @@ run-android: ##@run Build Android APK and start it on the device
npx react-native run-android --appIdSuffix debug
SIMULATOR=iPhone 13
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios: export TARGET := ios
run-ios: export IOS_STATUS_GO_TARGETS := iossimulator/amd64
run-ios: export IOS_STATUS_GO_TARGETS := ios/arm64,iossimulator/amd64
run-ios: ##@run Build iOS app and start it in a simulator/device
ifneq ("$(SIMULATOR)", "")
npx react-native run-ios --simulator="$(SIMULATOR)" | xcbeautify
@@ -291,8 +292,9 @@ endif
show-ios-devices: ##@other shows connected ios device and its name
xcrun xctrace list devices
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios-device: export TARGET := ios
run-ios-device: export IOS_STATUS_GO_TARGETS := ios/arm64
run-ios-device: export IOS_STATUS_GO_TARGETS := ios/arm64,iossimulator/amd64
run-ios-device: ##@run iOS app and start it on a connected device by its name
ifndef DEVICE_NAME
$(error Usage: make run-ios-device DEVICE_NAME=your-device-name)
@@ -305,7 +307,7 @@ endif
# Get all clojure files, including untracked, excluding removed
define find_all_clojure_files
$$(comm -23 <(sort <(git ls-files --cached --others --exclude-standard)) <(sort <(git ls-files --deleted)) | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn)
$$(comm -23 <(sort <(git ls-files --cached --others --exclude-standard)) <(sort <(git ls-files --deleted)) | grep -E '((\.clj-kondo\/status-im)|(src).*\.clj[sc]?$$)|((\.clj-kondo\/(status-im|config))|(src).*\.edn$$)|shadow-cljs\.edn')
endef
lint: export TARGET := clojure
+26 -9
View File
@@ -21,8 +21,10 @@ pipeline {
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
/* we source .bash_profile to be able to use nix-store */
NIX_SSHOPTS = "-o StrictHostKeyChecking=no source .profile;"
NIX_SSHOPTS = "-oStrictHostKeyChecking=no"
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
NIX_STORE_CMD = '/nix/var/nix/profiles/default/bin/nix-store'
NIX_SSH_REMOTE = "ssh://${params.NIX_CACHE_USER}@${params.NIX_CACHE_HOST}?remote-program=${env.NIX_STORE_CMD}"
}
options {
@@ -42,19 +44,21 @@ pipeline {
steps { script {
nix.shell('nix-env -i openssh', sandbox: false, pure: false)
/* some build targets don't build on MacOS */
os = sh(script: 'uname', returnStdout: true)
arch = sh(script: 'arch', returnStdout: true)
os = sh(script: 'uname', returnStdout: true).trim()
arch = sh(script: 'arch', returnStdout: true).trim()
} }
}
stage('Build status-go') {
steps { script {
def platforms = ['mobile.android', 'mobile.ios', 'library']
if (os != 'Darwin') { platforms.removeAll { it == 'mobile.ios' } }
/* FIXME: Remove this when #16237 is merged. */
/* FIXME: "'x86_64-darwin' with features {} is required to build" */
if (arch == 'arm64') { platforms.removeAll { it == 'mobile.android' } }
platforms.each { os ->
platforms.each { platform ->
/* Allow for Android builds on Apple ARM. */
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, platform)
nix.build(
attr: "targets.status-go.${os}",
attr: "targets.status-go.${platform}",
sandbox: false,
link: false
)
@@ -74,6 +78,8 @@ pipeline {
}
stage('Build android deps') {
steps { script {
/* Allow for Android builds on Apple ARM. */
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, 'android')
/* Build/fetch deps required to build android release. */
nix.build(
attr: 'targets.mobile.android.release.buildInputs',
@@ -86,9 +92,13 @@ pipeline {
stage('Build nix shell deps') {
steps { script {
def shells = ['android', 'ios', 'fastlane', 'keytool', 'clojure', 'gradle']
if (os != "Darwin") { shells.removeAll { it == 'ios' } }
if (os != 'Darwin') { shells.removeAll { it == 'ios' } }
/* FIXME: "'x86_64-darwin' with features {} is required to build" */
if (arch == 'arm64') { shells.removeAll { it == 'android' } }
/* Build/fetch deps required to start default Nix shell. */
shells.each { shell ->
/* Allow for Android builds on Apple ARM. */
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, shell)
nix.build(
attr: "shells.${shell}.buildInputs",
sandbox: false,
@@ -103,8 +113,7 @@ pipeline {
nix.shell("""
find /nix/store/ -mindepth 1 -maxdepth 1 -type d \
-not -name '*.links' -and -not -name '*-status-mobile-*' \
| xargs nix copy \
--to ssh-ng://${params.NIX_CACHE_USER}@${params.NIX_CACHE_HOST}
| xargs nix copy --to ${NIX_SSH_REMOTE}
""",
pure: false
)
@@ -119,3 +128,11 @@ pipeline {
} }
}
}
def nixSysOverride(os, arch, target='android') {
return (
os == 'Darwin' &&
arch == 'arm64' &&
target =~ /.*android$/
) ? 'x86_64-darwin' : ''
}
@@ -1,44 +0,0 @@
package im.status.ethereum.module;
import java.util.concurrent.*;
/** Uses an unbounded queue, but allows timeout of core threads
* (modified case 2 in
* https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html ) */
public class StatusThreadPoolExecutor {
private static final int NUMBER_OF_CORES =
Runtime.getRuntime().availableProcessors();
private static final int THREADS_TO_CORES_RATIO = 100;
private static final int KEEP_ALIVE_TIME = 1;
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
private final BlockingQueue<Runnable> mQueue;
private final ThreadPoolExecutor mThreadPool;
private StatusThreadPoolExecutor() {
mQueue = new LinkedBlockingQueue<>();
mThreadPool = new ThreadPoolExecutor(
THREADS_TO_CORES_RATIO * NUMBER_OF_CORES,
THREADS_TO_CORES_RATIO * NUMBER_OF_CORES,
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
mQueue);
// Allow pool to drain
mThreadPool.allowCoreThreadTimeOut(true);
}
/** Pugh singleton */
private static class Holder {
private static StatusThreadPoolExecutor instance = new StatusThreadPoolExecutor();
}
public static StatusThreadPoolExecutor getInstance() {
return Holder.instance;
}
public void execute(final Runnable r) {
mThreadPool.execute(r);
}
}
@@ -0,0 +1,47 @@
package im.status.ethereum.module
import java.util.concurrent.*
/**
* Uses an unbounded queue but allows timeout of core threads
* (modified case 2 in
* https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html )
*/
class StatusThreadPoolExecutor private constructor() {
private val NUMBER_OF_CORES: Int = Runtime.getRuntime().availableProcessors()
private val THREADS_TO_CORES_RATIO: Int = 100
private val KEEP_ALIVE_TIME: Int = 1
private val KEEP_ALIVE_TIME_UNIT: TimeUnit = TimeUnit.SECONDS
private val mQueue: BlockingQueue<Runnable> = LinkedBlockingQueue()
private val mThreadPool: ThreadPoolExecutor
init {
mThreadPool = ThreadPoolExecutor(
THREADS_TO_CORES_RATIO * NUMBER_OF_CORES,
THREADS_TO_CORES_RATIO * NUMBER_OF_CORES,
KEEP_ALIVE_TIME.toLong(),
KEEP_ALIVE_TIME_UNIT,
mQueue
)
// Allow pool to drain
mThreadPool.allowCoreThreadTimeOut(true)
}
/** Singleton holder */
private object Holder {
val instance = StatusThreadPoolExecutor()
}
companion object {
@JvmStatic
fun getInstance(): StatusThreadPoolExecutor {
return Holder.instance
}
}
fun execute(r: Runnable) {
mThreadPool.execute(r)
}
}
@@ -1,23 +0,0 @@
package android.util;
public class Log {
public static int d(String tag, String msg) {
System.out.println("DEBUG: " + tag + ": " + msg);
return 0;
}
public static int i(String tag, String msg) {
System.out.println("INFO: " + tag + ": " + msg);
return 0;
}
public static int w(String tag, String msg) {
System.out.println("WARN: " + tag + ": " + msg);
return 0;
}
public static int e(String tag, String msg) {
System.out.println("ERROR: " + tag + ": " + msg);
return 0;
}
}
@@ -0,0 +1,27 @@
package android.util
object Log {
@JvmStatic
fun d(tag: String, msg: String): Int {
println("DEBUG: $tag: $msg")
return 0
}
@JvmStatic
fun i(tag: String, msg: String): Int {
println("INFO: $tag: $msg")
return 0
}
@JvmStatic
fun w(tag: String, msg: String): Int {
println("WARN: $tag: $msg")
return 0
}
@JvmStatic
fun e(tag: String, msg: String): Int {
println("ERROR: $tag: $msg")
return 0
}
}
+1 -1
View File
@@ -89,7 +89,7 @@ if [[ -n "${nixResultPath}" ]]; then
toDelete=$(findByResult "${nixResultPath}")
else
# use regular expression that should match all status-mobile build artifacts
toDelete=$(findByRegex '.*-status-(react|go)-(shell|source|build|patched-npm-gradle-modules).*')
toDelete=$(findByRegex '.*-status-(mobile|go)-(shell|source|build|patched-npm-gradle-modules).*')
fi
# remove duplicates and return
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

+28 -2
View File
@@ -39,7 +39,7 @@ export function interpolateNavigationViewOpacity(props) {
});
}
export function messagesListOnScroll(distanceFromListTop, callback) {
export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callback) {
return function (event) {
'worklet';
const currentY = event.contentOffset.y;
@@ -47,7 +47,8 @@ export function messagesListOnScroll(distanceFromListTop, callback) {
const contentSizeY = event.contentSize.height - layoutHeight;
const newDistance = contentSizeY - currentY;
distanceFromListTop.value = newDistance;
runOnJS(callback)(currentY, layoutHeight, newDistance);
chatListScrollY.value = currentY;
runOnJS(callback)(layoutHeight, newDistance);
};
}
@@ -64,3 +65,28 @@ export function placeholderZIndex(isCalculationsComplete) {
return isCalculationsComplete.value ? 0 : 2;
});
}
export function scrollDownButtonOpacity(chatListScrollY, isComposerFocused, windowHeight) {
return useDerivedValue(function () {
'worklet';
if (isComposerFocused.value) {
return 0;
} else {
return chatListScrollY.value > windowHeight * 0.75 ? 1 : 0;
}
});
}
export function jumpToButtonOpacity(scrollDownButtonOpacity, isComposerFocused) {
return useDerivedValue(function () {
'worklet';
return withTiming(scrollDownButtonOpacity.value == 1 || isComposerFocused.value ? 0 : 1);
});
}
export function jumpToButtonPosition(scrollDownButtonOpacity, isComposerFocused) {
return useDerivedValue(function () {
'worklet';
return withTiming(scrollDownButtonOpacity.value == 1 || isComposerFocused.value ? 35 : 0);
});
}
@@ -8,7 +8,7 @@
utils.money))
(defn view-internal
[{:keys [value icon theme style accessibility-label]}]
[{:keys [value icon theme style accessibility-label text-size]}]
[rn/view
{:style (merge style/container style)
:accessibility-label accessibility-label}
@@ -19,7 +19,7 @@
:resize-mode :center
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}]
[quo.text/text
{:size :paragraph-1
{:size (or text-size :paragraph-1)
:weight :regular
:style (style/text theme)} (utils.money/format-amount value)]])
@@ -0,0 +1,72 @@
(ns quo.components.links.internal-link-card.channel.style
(:require [quo.foundations.colors :as colors]))
(defn loading-circle
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:margin-right 4
:width 16
:height 16
:border-radius 16})
(defn loading-first-line-bar
[theme margin-right?]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 72
:margin-right (when margin-right? 4)
:height 16
:border-radius 6})
(defn loading-second-line-bar
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 112
:height 8
:border-radius 6
:margin-bottom 17})
(defn loading-thumbnail-box
[theme size]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:height (if (= :message size) 139 160)
:border-radius 12})
(defn thumbnail
[size]
{:width "100%"
:height (if (= :message size) 139 160)
:margin-top 8
:border-radius 12})
(defn container
[size theme]
{:border-width 1
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:background-color (colors/theme-colors colors/white colors/neutral-80-opa-40 theme)
:border-radius 16
:padding-horizontal 12
:padding-top 10
:padding-bottom 12
:height (if (= :message size) 215 236)
:width (if (= :message size) 295 335)})
(def header-container
{:flex-direction :row
:align-items :center})
(def title
{:margin-bottom 2})
(def logo
{:margin-right 6
:width 16
:height 16
:border-radius 8})
(defn channel-chevron-props
[theme]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
(def row-spacing
{:flex-direction :row
:margin-bottom 13})
@@ -0,0 +1,92 @@
(ns quo.components.links.internal-link-card.channel.view
(:require
[quo.components.icon :as icon]
[quo.components.links.internal-link-card.channel.style :as style]
[quo.components.links.internal-link-card.schema :as component-schema]
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]))
(defn- description-comp
[description]
[rn/view {:style {:margin-bottom 4}}
[text/text
{:size :paragraph-2
:number-of-lines 3
:accessibility-label :description}
description]])
(defn- title-comp
[title channel-name theme]
[rn/view
{:style {:flex-direction :row
:align-items :center}}
[text/text
{:size :paragraph-1
:number-of-lines 1
:weight :semi-bold
:style style/title
:accessibility-label :title}
title]
[icon/icon :i/chevron-right (style/channel-chevron-props theme)]
[text/text
{:size :paragraph-1
:number-of-lines 1
:weight :semi-bold
:style style/title
:accessibility-label :title}
channel-name]])
(defn- banner-comp
[thumbnail size]
[rn/image
{:style (style/thumbnail size)
:source thumbnail
:accessibility-label :banner}])
(defn- logo-comp
[logo]
[rn/image
{:accessibility-label :logo
:source logo
:style (assoc style/logo :margin-bottom 2)}])
(defn- loading-view
[theme size]
[rn/view
{:accessibility-label :loading-channel-link-view
:style {:height 215}}
[rn/view {:style {:flex-direction :row}}
[rn/view {:style style/row-spacing}
[rn/view {:style (style/loading-circle theme)}]
[rn/view {:style (style/loading-first-line-bar theme true)}]]
[rn/view {:style style/row-spacing}
[rn/view {:style (style/loading-circle theme)}]
[rn/view {:style (style/loading-first-line-bar theme false)}]]]
[rn/view {:style (style/loading-second-line-bar theme)}]
[rn/view {:style (style/loading-thumbnail-box theme size)}]])
(defn view-internal
[{:keys [title description loading? icon banner
theme on-press channel-name size]
:or {channel-name "empty name"}}]
[rn/pressable
{:style (style/container size theme)
:accessibility-label :internal-link-card
:on-press on-press}
(if loading?
[loading-view theme size]
[:<>
[rn/view {:style style/header-container}
(when icon
[logo-comp icon])
[title-comp title channel-name theme]]
(when description
[description-comp description])
(when banner
[banner-comp banner size])])])
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,87 @@
(ns quo.components.links.internal-link-card.community.style
(:require [quo.foundations.colors :as colors]))
(defn loading-circle
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:margin-right 4
:width 16
:height 16
:border-radius 16})
(defn loading-stat
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:margin-right 4
:width 32
:height 8
:border-radius 16})
(def loading-stat-container
{:flex-direction :row
:align-items :center
:margin-right 12
:margin-bottom -6})
(defn loading-first-line-bar
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 145
:height 16
:border-radius 6})
(defn loading-second-line-bar
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 112
:height 8
:border-radius 6
:margin-bottom 17})
(defn loading-thumbnail-box
[theme size]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:height (if (= :message size) 139 160)
:border-radius 12})
(defn thumbnail
[size]
{:width "100%"
:height (if (= :message size) 139 160)
:margin-top 6
:border-radius 12})
(defn container
[size theme]
{:border-width 1
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:background-color (colors/theme-colors colors/white colors/neutral-80-opa-40 theme)
:border-radius 16
:padding-horizontal 12
:padding-top 10
:padding-bottom 12
:height (if (= :message size) 245 266)
:width (if (= :message size) 295 335)})
(def header-container
{:flex-direction :row
:align-items :center})
(def title
{:margin-bottom 2})
(def logo
{:width 16
:height 16
:border-radius 8
:margin-right 4
:margin-bottom 2})
(def row-spacing
{:flex-direction :row
:margin-bottom 12
:margin-top 4})
(def stat-container
{:flex-direction :row
:margin-top 12})
@@ -0,0 +1,96 @@
(ns quo.components.links.internal-link-card.community.view
(:require
[quo.components.community.community-stat.view :as community-stat]
[quo.components.links.internal-link-card.community.style :as style]
[quo.components.links.internal-link-card.schema :as component-schema]
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]))
(defn- description-comp
[description members-count active-members-count]
[rn/view
[text/text
{:size :paragraph-2
:number-of-lines 3
:accessibility-label :description}
description]
[rn/view {:style style/stat-container}
[community-stat/view
{:value members-count
:icon :i/members
:accessibility-label :members-count
:style {:margin-right 12}
:text-size :paragraph-2}]
(when active-members-count
[community-stat/view
{:value active-members-count
:icon :i/active-members
:accessibility-label :active-members-count
:text-size :paragraph-2}])]])
(defn- title-comp
[title]
[text/text
{:size :paragraph-1
:number-of-lines 1
:weight :semi-bold
:style style/title
:accessibility-label :title}
title])
(defn- thumbnail-comp
[thumbnail size]
[rn/image
{:style (style/thumbnail size)
:source thumbnail
:accessibility-label :thumbnail}])
(defn- logo-comp
[logo]
[rn/image
{:accessibility-label :logo
:source logo
:style style/logo}])
(defn- stat-loading
[theme]
[rn/view {:style style/loading-stat-container}
[rn/view {:style (style/loading-circle theme)}]
[rn/view {:style (style/loading-stat theme)}]])
(defn- loading-view
[theme size]
[rn/view {:accessibility-label :loading-community-link-view}
[rn/view {:style style/row-spacing}
[rn/view {:style (style/loading-circle theme)}]
[rn/view {:style (style/loading-first-line-bar theme)}]]
[rn/view {:style (style/loading-second-line-bar theme)}]
[rn/view {:style style/row-spacing}
[stat-loading theme]
[stat-loading theme]]
[rn/view {:style (style/loading-thumbnail-box theme size)}]])
(defn- view-internal
[{:keys [title description loading? icon banner members-count active-members-count
theme on-press size]}]
[rn/pressable
{:style (style/container size theme)
:accessibility-label :internal-link-card
:on-press on-press}
(if loading?
[loading-view theme size]
[:<>
[rn/view {:style style/header-container}
(when icon
[logo-comp icon])
[title-comp title]]
(when description
[description-comp description members-count active-members-count])
(when banner
[thumbnail-comp banner size])])])
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,81 @@
(ns quo.components.links.internal-link-card.component-spec
(:require
[quo.components.links.internal-link-card.view :as view]
[test-helpers.component :as h]))
(defn- render
[component]
(h/render-with-theme-provider component :light))
(def user-props
{:title "Some title"
:subtitle "Some description"
:loading? false
:icon "data:image/png,logo-x"
:type :user
:customization-color "#ff0000"
:emoji-hash "🌟🚀🐠🌈🏰🔮🦉🐼🍉🎨🚲🌙🍔🌵"})
(h/describe "Internal link card - User"
(h/test "renders with most common props"
(render [view/view user-props])
(h/is-truthy (h/query-by-text (:title user-props)))
(h/is-truthy (h/query-by-text (:subtitle user-props))))
(h/test "does not render logo if prop is not present"
(render [view/view (dissoc user-props :icon)])
(h/is-null (h/query-by-label-text :logo))))
(def community-props
{:title "Some title"
:description "Some description"
:icon "data:image/png,logo-x"
:banner "data:image/png,whatever"
:members-count "20"
:loading? false
:active-members-count "15"
:type :community})
(h/describe "Internal link card - Community"
(h/test "renders with most common props"
(render [view/view community-props])
(h/is-truthy (h/query-by-text (:title community-props)))
(h/is-truthy (h/query-by-text (:description community-props)))
(h/is-truthy (h/query-by-text (:members-count community-props)))
(h/is-truthy (h/query-by-text (:active-members-count community-props)))
(h/is-truthy (h/query-by-label-text :logo))
(h/is-truthy (h/query-by-label-text :thumbnail)))
(h/test "does not render thumbnail if prop is not present"
(render [view/view (dissoc community-props :banner)])
(h/is-null (h/query-by-label-text :thumbnail)))
(h/test "does not render logo if prop is not present"
(render [view/view (dissoc community-props :icon)])
(h/is-null (h/query-by-label-text :logo))))
(def channel-props
{:title "Doodles"
:description "Coloring the world with joy • ᴗ •"
:icon "data:image/png,logo-x"
:banner "data:image/png,whatever"
:loading? false
:channel-name "#general"
:type :channel})
(h/describe "Internal link card - Channel"
(h/test "renders with most common props"
(render [view/view channel-props])
(h/is-truthy (h/query-by-text (:title channel-props)))
(h/is-truthy (h/query-by-text (:description channel-props)))
(h/is-truthy (h/query-by-text (:channel-name channel-props)))
(h/is-truthy (h/query-by-label-text :logo))
(h/is-truthy (h/query-by-label-text :banner)))
(h/test "does not render banner if prop is not present"
(render [view/view (dissoc channel-props :banner)])
(h/is-null (h/query-by-label-text :banner)))
(h/test "does not render logo if prop is not present"
(render [view/view (dissoc channel-props :icon)])
(h/is-null (h/query-by-label-text :logo))))
@@ -0,0 +1,23 @@
(ns quo.components.links.internal-link-card.schema)
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:title {:optional true} [:maybe :string]]
[:description {:optional true} [:maybe :string]]
[:channel-name {:optional true} [:maybe :string]]
[:loading? {:optional true} [:maybe :boolean]]
[:subtitle {:optional true} [:maybe :string]]
[:icon {:optional true} [:maybe [:or :string :int]]]
[:banner {:optional true} [:maybe [:or :string :int]]]
[:type {:optional true} [:maybe :keyword]]
[:on-press {:optional true} [:maybe fn?]]
[:members-count {:optional true} [:maybe [:or :int :string]]]
[:active-members-count {:optional true} [:maybe [:or :int :string]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:emoji-hash {:optional true} [:maybe :string]]
[:size {:optional true} [:maybe :keyword]]
[:theme :schema.common/theme]]]]
:any])
@@ -0,0 +1,66 @@
(ns quo.components.links.internal-link-card.user.style
(:require [quo.foundations.colors :as colors]))
(defn loading-circle
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:margin-right 4
:width 16
:height 16
:border-radius 16})
(defn loading-first-line-bar
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 145
:height 16
:border-radius 6})
(defn loading-second-line-bar
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 112
:height 8
:border-radius 6
:margin-bottom 17})
(defn last-bar-line-bar
[theme]
{:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80 theme)
:width 271
:height 16
:border-radius 6})
(defn gradient-start-color
[customization-color theme]
(colors/theme-colors (colors/resolve-color customization-color theme 10)
(colors/resolve-color customization-color theme 20)
theme))
(defn container
[loading? theme size]
{:border-width 1
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:background-color (colors/theme-colors colors/white colors/neutral-80-opa-40 theme)
:border-radius 16
:padding-horizontal 12
:padding-top 10
:padding-bottom 12
:height (if loading? 92 110)
:width (if (= :message size) 295 335)})
(def header-container
{:flex-direction :row
:align-items :center})
(def title
{:margin-bottom 2})
(def logo
{:margin-right 6
:width 16
:height 16
:border-radius 8
:margin-bottom 2})
(def row-spacing {:flex-direction :row :margin-bottom 12})
@@ -0,0 +1,83 @@
(ns quo.components.links.internal-link-card.user.view
(:require
[quo.components.links.internal-link-card.schema :as component-schema]
[quo.components.links.internal-link-card.user.style :as style]
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[schema.core :as schema]))
(defn- subtitle-comp
[subtitle emoji-hash]
[rn/view
[text/text
{:size :paragraph-2
:number-of-lines 2
:accessibility-label :subtitle
:style {:margin-bottom 12}}
subtitle]
[rn/view {:style {:flex-direction :row}}
[text/text
{:size :paragraph-2
:number-of-lines 1
:weight :regular
:accessibility-label :emoji-hash}
emoji-hash]]])
(defn- title-comp
[title]
[text/text
{:size :paragraph-1
:number-of-lines 1
:weight :semi-bold
:style style/title
:accessibility-label :title}
title])
(defn- logo-comp
[logo]
[rn/image
{:accessibility-label :logo
:source logo
:style style/logo}])
(defn- loading-view
[theme]
[rn/view {:accessibility-label :loading-user-link-view}
[rn/view {:style style/row-spacing}
[rn/view {:style (style/loading-circle theme)}]
[rn/view {:style (style/loading-first-line-bar theme)}]]
[rn/view {:style (style/loading-second-line-bar theme)}]
[rn/view {:style (style/last-bar-line-bar theme)}]])
(defn- linear-gradient-props
[theme customization-color]
[(style/gradient-start-color customization-color theme) :transparent])
(defn view-internal
[{:keys [title loading? icon
theme on-press subtitle emoji-hash customization-color size]}]
(if loading?
[rn/pressable
{:accessibility-label :internal-link-card
:on-press on-press
:style (style/container loading? theme size)}
[loading-view theme]]
[linear-gradient/linear-gradient
(assoc {:style (style/container loading? theme size)}
:colors
(linear-gradient-props theme customization-color))
[rn/pressable
{:accessibility-label :internal-link-card
:on-press on-press}
[rn/view {:style style/header-container}
(when icon
[logo-comp icon])
[title-comp title]]
(when subtitle
[subtitle-comp subtitle emoji-hash])]]))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
@@ -0,0 +1,11 @@
(ns quo.components.links.internal-link-card.view
(:require [quo.components.links.internal-link-card.channel.view :as channel.view]
[quo.components.links.internal-link-card.community.view :as community.view]
[quo.components.links.internal-link-card.user.view :as user.view]))
(defn view
[{card-type :type :as props}]
(case card-type
:community [community.view/view props]
:channel [channel.view/view props]
:user [user.view/view props]))
@@ -8,7 +8,7 @@
[react-native.linear-gradient :as linear-gradient]))
(defn- view-internal
[{:keys [address theme on-press icon title customization-color]}]
[{:keys [address theme on-press icon title customization-color container-style]}]
[rn/pressable
{:accessibility-label :link-card
:on-press on-press}
@@ -17,7 +17,7 @@
(properties/gradient-end-color theme customization-color)]
:start {:x 0 :y 1}
:end {:x 1 :y 1}
:style (style/container theme)}
:style (merge (style/container theme) container-style)}
[rn/view {:style style/icon-container}
[social/view
{:accessibility-label :social-icon
@@ -33,22 +33,22 @@
[rn/view
{:style style/networks-container
:accessibility-label :networks}
(when (pos? ethereum)
(when (and ethereum (pos? (:amount ethereum)))
[network-amount
{:network :ethereum
:amount (str ethereum " ETH")
:amount (str (:amount ethereum) " " (or (:token-symbol ethereum) "ETH"))
:divider? (or show-arbitrum? show-optimism?)
:theme theme}])
(when show-optimism?
[network-amount
{:network :optimism
:amount (str optimism " OPT")
:amount (str (:amount optimism) " " (or (:token-symbol optimism) "OPT"))
:divider? show-arbitrum?
:theme theme}])
(when show-arbitrum?
[network-amount
{:network :arbitrum
:amount (str arbitrum " ARB")
:amount (str (:amount arbitrum) " " (or (:token-symbol arbitrum) "ARB"))
:theme theme}])]))
(defn- view-internal
+2
View File
@@ -69,6 +69,7 @@
quo.components.inputs.title-input.view
quo.components.ios.drawer-bar.view
quo.components.keycard.view
quo.components.links.internal-link-card.view
quo.components.links.link-preview.view
quo.components.links.url-preview-list.view
quo.components.links.url-preview.view
@@ -288,6 +289,7 @@
(def numbered-keyboard quo.components.numbered-keyboard.numbered-keyboard.view/view)
;;;; Links
(def internal-link-card quo.components.links.internal-link-card.view/view)
(def link-preview quo.components.links.link-preview.view/view)
(def url-preview quo.components.links.url-preview.view/view)
(def url-preview-list quo.components.links.url-preview-list.view/view)
+1
View File
@@ -39,6 +39,7 @@
quo.components.inputs.recovery-phrase.component-spec
quo.components.inputs.title-input.component-spec
quo.components.keycard.component-spec
quo.components.links.internal-link-card.component-spec
quo.components.links.link-preview.component-spec
quo.components.links.url-preview-list.component-spec
quo.components.links.url-preview.component-spec
+30 -1
View File
@@ -24,11 +24,17 @@
(defn get-label-by-type
[biometric-type]
(case biometric-type
(condp = biometric-type
:fingerprint (i18n/label :t/biometric-fingerprint)
:FaceID (i18n/label :t/biometric-faceid)
(i18n/label :t/biometric-touchid)))
(defn get-icon-by-type
[biometric-type]
(condp = biometric-type
:FaceID :i/face-id
:i/touch-id))
(re-frame/reg-fx
:biometric/get-supported-biometric-type
(fn []
@@ -126,3 +132,26 @@
{:events [:biometric/authenticate]}
[_ opts]
{:biometric/authenticate opts})
(rf/reg-event-fx
:biometric/on-enable-success
(fn [{:keys [db]} [password]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (assoc db :auth-method constants/auth-method-biometric)
:dispatch [:keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password password}]})))
(rf/reg-event-fx
:biometric/enable
(fn [_ [password]]
{:dispatch [:biometric/authenticate
{:on-success #(rf/dispatch [:biometric/on-enable-success password])
:on-fail #(rf/dispatch [:biometric/show-message %])}]}))
(rf/reg-event-fx
:biometric/disable
(fn [{:keys [db]}]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (assoc db :auth-method constants/auth-method-none)
:keychain/clear-user-password key-uid})))
+2 -1
View File
@@ -95,7 +95,8 @@
:button-text (i18n/label :t/confirm)
:close-button-text (i18n/label :t/cancel)
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/close-chat chat-id])
(hide-sheet-and-dispatch [:chat.ui/close-and-remove-chat
chat-id])
(when inside-chat?
(rf/dispatch [:navigate-back])))}])}]))
@@ -131,6 +131,7 @@
:keychain/clear-user-password
(fn [key-uid]
(keychain/reset-credentials (password-migration-key-name key-uid))
(keychain/reset-credentials (str key-uid "-auth"))
(keychain/reset-credentials key-uid)))
(re-frame/reg-fx
@@ -142,6 +143,11 @@
(.then #(when on-success (on-success)))
(.catch #(when on-error (on-error %))))))
(re-frame/reg-event-fx
:keychain/save-password-and-auth-method
(fn [_ [opts]]
{:keychain/save-password-and-auth-method opts}))
;; NOTE: migrating the plaintext password in the keychain
;; with the hashed one. Added due to the sync onboarding
;; flow, where the password arrives already hashed.
@@ -6,3 +6,8 @@
(fn [{:keys [db]} [callback]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:keychain/get-user-password [key-uid callback]]]})))
(rf/reg-event-fx
:standard-auth/reset-login-password
(fn [{:keys [db]}]
{:db (update db :profile/login dissoc :password :error)}))
@@ -1,6 +1,5 @@
(ns status-im.common.standard-authentication.standard-auth.authorize
(:require
[native-module.core :as native-module]
[react-native.touch-id :as biometric]
[status-im.common.standard-authentication.enter-password.view :as enter-password]
[taoensso.timbre :as log]
@@ -18,11 +17,11 @@
auth-button-label theme blur? auth-button-icon-left]}]
(let [handle-auth-success (fn [biometric?]
(fn [entered-password]
(let [sha3-pwd (if biometric?
(str (security/safe-unmask-data entered-password))
(native-module/sha3 (str (security/safe-unmask-data
entered-password))))]
(on-auth-success sha3-pwd))))
(let [sha3-masked-password (if biometric?
entered-password
(security/hash-masked-password
entered-password))]
(on-auth-success sha3-masked-password))))
password-login (fn [{:keys [on-press-biometrics]}]
(rf/dispatch [:show-bottom-sheet
{:on-close on-close
@@ -53,10 +52,12 @@
(password-login {:on-press-biometrics
#(on-press-biometrics
on-press-biometrics)}))}))]
(biometric/get-supported-type
(fn [biometric-type]
(if (and biometric-auth? biometric-type)
(biometrics-login biometrics-login)
(do
(reset-password)
(password-login {})))))))
(if biometric-auth?
(biometric/get-supported-type
(fn [biometric-type]
(if biometric-type
(biometrics-login biometrics-login)
(do
(reset-password)
(password-login {})))))
(password-login {}))))
@@ -5,6 +5,7 @@
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.standard-authentication.standard-auth.authorize :as authorize]
[status-im.constants :as constants]
[utils.re-frame :as rf]))
(defn- view-internal
@@ -15,7 +16,7 @@
#(reset! reset-slider? true)
200))
auth-method (rf/sub [:auth-method])
biometric-auth? (= auth-method "biometric")]
biometric-auth? (= auth-method constants/auth-method-biometric)]
(fn [{:keys [track-text
customization-color
auth-button-label
+2
View File
@@ -437,3 +437,5 @@
(def ^:const send-type-stickers-buy 4)
(def ^:const send-type-bridge 5)
(def ^:const send-type-erc-721-transfer 6)
(def ^:const bridge-name-erc-721-transfer "ERC721Transfer")
+7
View File
@@ -1,6 +1,7 @@
(ns status-im.contexts.chat.effects
(:require
[react-native.async-storage :as async-storage]
[status-im.contexts.chat.messenger.messages.list.state :as chat.state]
[status-im.contexts.shell.jump-to.constants :as shell.constants]
[utils.re-frame :as rf]))
@@ -16,3 +17,9 @@
(when (= stored-key-uid key-uid)
(rf/dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id
shell.constants/open-screen-without-animation])))))))))
(rf/reg-fx :effects.chat/scroll-to-bottom
(fn []
(some-> ^js @chat.state/messages-list-ref
(.scrollToOffset #js
{:animated true}))))
+7 -2
View File
@@ -281,7 +281,7 @@
(rf/defn close-and-remove-chat
"Closes the chat and removes it from chat list while retaining history, producing all necessary effects for that"
{:events [:chat.ui/close-chat]}
{:events [:chat.ui/close-and-remove-chat]}
[{:keys [db now] :as cofx} chat-id]
(rf/merge cofx
{:effects/push-notifications-clear-message-notifications [chat-id]
@@ -386,7 +386,7 @@
:confirm-button-text (i18n/label :t/delete)
:on-accept #(do
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:chat.ui/close-chat chat-id]))}})
(rf/dispatch [:chat.ui/close-and-remove-chat chat-id]))}})
(rf/defn navigate-to-user-pinned-messages
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
@@ -447,3 +447,8 @@
:params [{:id chat-id}]
:on-success #()
:on-error #(log/error "failed to fetch messages for chat" chat-id %)}]})
(rf/defn scroll-to-bottom
{:events [:chat.ui/scroll-to-bottom]}
[_]
{:effects.chat/scroll-to-bottom nil})
@@ -20,8 +20,7 @@
{:keys [text-value focused? maximized?]}
{:keys [height saved-height last-height opacity background-y container-opacity]}
window-height
edit
scroll-to-bottom-fn]
edit]
(reanimated/animate height comp-constants/input-height)
(reanimated/set-shared-value saved-height comp-constants/input-height)
(reanimated/set-shared-value last-height comp-constants/input-height)
@@ -39,11 +38,11 @@
(reset! text-value "")
(reset! sending-links? false)
(reset! sending-images? false)
(when (and (not (some? edit)) scroll-to-bottom-fn)
(scroll-to-bottom-fn)))
(when-not (some? edit)
(rf/dispatch [:chat.ui/scroll-to-bottom])))
(defn f-send-button
[props state animations window-height images? btn-opacity scroll-to-bottom-fn z-index edit]
[props state animations window-height images? btn-opacity z-index edit]
(let [{:keys [text-value]} state
customization-color (rf/sub [:profile/customization-color])]
(rn/use-effect (fn []
@@ -61,19 +60,17 @@
[reanimated/view
{:style (style/send-button btn-opacity @z-index)}
[quo/button
{:icon-only? true
:size 32
{:icon-only? true
:size 32
:customization-color customization-color
:accessibility-label :send-message-button
:on-press #(send-message props state animations window-height edit scroll-to-bottom-fn)}
:on-press #(send-message props state animations window-height edit)}
:i/arrow-up]]))
(defn send-button
[props {:keys [text-value] :as state} animations window-height images? edit btn-opacity
scroll-to-bottom-fn]
[props {:keys [text-value] :as state} animations window-height images? edit btn-opacity]
(let [z-index (reagent/atom (if (and (empty? @text-value) (not images?)) 0 1))]
[:f> f-send-button props state animations window-height images? btn-opacity scroll-to-bottom-fn
z-index edit]))
[:f> f-send-button props state animations window-height images? btn-opacity z-index edit]))
(defn disabled-audio-button
[opacity]
@@ -231,7 +228,7 @@
:icon :i/format}])
(defn view
[props state animations window-height insets scroll-to-bottom-fn {:keys [edit images]}]
[props state animations window-height insets {:keys [edit images]}]
(let [send-btn-opacity (reanimated/use-shared-value 0)
audio-btn-opacity (reanimated/interpolate send-btn-opacity [0 1] [1 0])]
[rn/view {:style style/actions-container}
@@ -242,8 +239,7 @@
[image-button props animations insets edit]
[reaction-button]
[format-button]]
[:f> send-button props state animations window-height images edit send-btn-opacity
scroll-to-bottom-fn]
[:f> send-button props state animations window-height images edit send-btn-opacity]
(when (and (not edit) (not images))
;; TODO(alwx): needs to be replaced with an `audio-button` later. See
;; https://github.com/status-im/status-mobile/issues/16084 for more details.
@@ -16,11 +16,11 @@
(defn focus
"Animate to the `saved-height`, display background-overlay if needed, and set cursor position"
[{:keys [input-ref] :as props}
{:keys [text-value focused? lock-selection? saved-cursor-position]}
{:keys [text-value focused? lock-selection? saved-cursor-position composer-focused?]}
{:keys [height saved-height last-height opacity background-y container-opacity]
:as animations}
{:keys [max-height] :as dimensions}
show-floating-scroll-down-button?]
{:keys [max-height] :as dimensions}]
(reanimated/set-shared-value composer-focused? true)
(reset! focused? true)
(rf/dispatch [:chat.ui/set-input-focused true])
(let [last-height-value (reanimated/get-shared-value last-height)]
@@ -35,13 +35,12 @@
(when (and (not-empty @text-value) @input-ref)
(.setNativeProps ^js @input-ref
(clj->js {:selection {:start @saved-cursor-position :end @saved-cursor-position}})))
(kb/handle-refocus-emoji-kb-ios props animations dimensions)
(reset! show-floating-scroll-down-button? false))
(kb/handle-refocus-emoji-kb-ios props animations dimensions))
(defn blur
"Save the current height, minimize the composer, animate-out the background, and save cursor position"
[{:keys [text-value focused? lock-selection? cursor-position saved-cursor-position gradient-z-index
maximized? recording?]}
maximized? recording? composer-focused?]}
{:keys [height saved-height last-height gradient-opacity container-opacity opacity background-y]}
{:keys [content-height max-height window-height]}
{:keys [images link-previews? reply]}]
@@ -53,6 +52,7 @@
max-height
content-height
saved-height)]
(reanimated/set-shared-value composer-focused? false)
(reset! focused? false)
(rf/dispatch [:chat.ui/set-input-focused false])
(reanimated/set-shared-value last-height reopen-height)
@@ -6,7 +6,8 @@
[react-native.reanimated :as reanimated]
[status-im.contexts.chat.messenger.composer.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.worklets.chat.messages :as worklets]))
(defn bar
[theme]
@@ -23,33 +24,33 @@
[:f> f-blur-view props])
(defn- f-shell-button
[{:keys [focused?]} scroll-to-bottom-fn show-floating-scroll-down-button?]
(let [customization-color (rf/sub [:profile/customization-color])
hide-shell? (or @focused? @show-floating-scroll-down-button?)
y-shell (reanimated/use-shared-value (if hide-shell? 35 0))
opacity (reanimated/use-shared-value (if hide-shell? 0 1))]
(rn/use-effect
(fn []
(reanimated/animate opacity (if hide-shell? 0 1))
(reanimated/animate y-shell (if hide-shell? 35 0)))
[@focused? @show-floating-scroll-down-button?])
[{:keys [composer-focused?]} chat-list-scroll-y window-height]
(let [customization-color (rf/sub [:profile/customization-color])
scroll-down-button-opacity (worklets/scroll-down-button-opacity
chat-list-scroll-y
composer-focused?
window-height)
jump-to-button-opacity (worklets/jump-to-button-opacity
scroll-down-button-opacity
composer-focused?)
jump-to-button-position (worklets/jump-to-button-position
scroll-down-button-opacity
composer-focused?)]
[:<>
[reanimated/view
{:style (style/shell-button y-shell opacity)}
{:style (style/shell-button jump-to-button-position jump-to-button-opacity)}
[quo/floating-shell-button
{:jump-to
{:on-press (fn []
(rf/dispatch [:shell/navigate-to-jump-to]))
{:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:customization-color customization-color
:label (i18n/label :t/jump-to)
:style {:align-self :center}}}
{}]]
(when (and (not @focused?)
@show-floating-scroll-down-button?)
[quo/floating-shell-button
{:scroll-to-bottom {:on-press scroll-to-bottom-fn}}
style/scroll-to-bottom-button])]))
[quo/floating-shell-button
{:scroll-to-bottom {:on-press #(rf/dispatch [:chat.ui/scroll-to-bottom])}}
style/scroll-to-bottom-button
scroll-down-button-opacity]]))
(defn shell-button
[state scroll-to-bottom-fn show-floating-scroll-down-button?]
[:f> f-shell-button state scroll-to-bottom-fn show-floating-scroll-down-button?])
[state chat-list-scroll-y window-height]
[:f> f-shell-button state chat-list-scroll-y window-height])
@@ -193,7 +193,8 @@
:record-permission? (reagent/atom true)
:recording? (reagent/atom false)
:first-level? (reagent/atom true)
:menu-items (reagent/atom selection/first-level-menu-items)})
:menu-items (reagent/atom selection/first-level-menu-items)
:composer-focused? (reanimated/use-shared-value false)})
(defn init-subs
[]
@@ -30,8 +30,7 @@
(defn sheet-component
[{:keys [insets
scroll-to-bottom-fn
show-floating-scroll-down-button?
chat-list-scroll-y
window-height
blur-height
opacity
@@ -89,7 +88,7 @@
(:edit subscriptions)]
[rn/view
{:style style/composer-sheet-and-jump-to-container}
[sub-view/shell-button state scroll-to-bottom-fn show-floating-scroll-down-button?]
[sub-view/shell-button state chat-list-scroll-y window-height]
[gesture/gesture-detector
{:gesture
(drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
@@ -114,42 +113,39 @@
:menu-items @(:menu-items state)
:style (style/input-view state)}
[rn/text-input
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus
#(handler/focus props state animations dimensions show-floating-scroll-down-button?)
:on-blur #(handler/blur state animations dimensions subscriptions)
:on-content-size-change #(handler/content-size-change %
state
animations
dimensions
(or keyboard-shown
(:edit subscriptions)))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % props state)
:on-selection #(selection/on-selection % props state)
:keyboard-appearance (quo.theme/theme-value :light :dark)
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus #(handler/focus props state animations dimensions)
:on-blur #(handler/blur state animations dimensions subscriptions)
:on-content-size-change #(handler/content-size-change %
state
animations
dimensions
(or keyboard-shown
(:edit subscriptions)))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % props state)
:on-selection #(selection/on-selection % props state)
:keyboard-appearance (quo.theme/theme-value :light :dark)
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input-text props
state
{:max-height max-height
:theme theme})
:max-length constants/max-text-size
:accessibility-label :chat-message-input}]]]
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input-text props
state
{:max-height max-height
:theme theme})
:max-length constants/max-text-size
:accessibility-label :chat-message-input}]]]
[:<>
[gradients/view props state animations show-bottom-gradient?]
[link-preview/view]
[images/images-list]]
[:f> actions/view props state animations window-height insets scroll-to-bottom-fn
subscriptions]]]]]))
[:f> actions/view props state animations window-height insets subscriptions]]]]]))
(defn f-composer
[{:keys [insets scroll-to-bottom-fn show-floating-scroll-down-button?
messages-list-on-layout-finished?]}]
[{:keys [insets chat-list-scroll-y messages-list-on-layout-finished?]}]
(let [window-height (:height (rn/get-window))
theme (quo.theme/use-theme-value)
opacity (reanimated/use-shared-value 0)
@@ -159,8 +155,7 @@
(:bottom insets)))
extra-params {:insets insets
:window-height window-height
:scroll-to-bottom-fn scroll-to-bottom-fn
:show-floating-scroll-down-button? show-floating-scroll-down-button?
:chat-list-scroll-y chat-list-scroll-y
:blur-height blur-height
:opacity opacity
:background-y background-y
@@ -1,5 +1,6 @@
(ns status-im.contexts.chat.messenger.messages.list.state)
(defonce messages-list-ref (atom nil))
(defonce first-not-visible-item (atom nil))
(defonce scrolling (atom nil))
@@ -23,37 +23,16 @@
[utils.re-frame :as rf]
[utils.worklets.chat.messages :as worklets]))
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
(defonce ^:const loading-indicator-extra-spacing 250)
(defonce ^:const loading-indicator-page-loading-height 100)
(defonce ^:const min-message-height 32)
(defonce messages-list-ref (atom nil))
(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
(defn list-ref [ref] (reset! messages-list-ref ref))
(defn scroll-to-bottom
[]
(some-> ^js @messages-list-ref
(.scrollToOffset #js
{:animated true})))
(defn on-scroll-fn
[show-floating-scroll-down-button? distance-atom layout-height-atom]
(fn [y layout-height new-distance]
(let [threshold-height (* (/ layout-height 100)
threshold-percentage-to-show-floating-scroll-down-button)
reached-threshold? (> y threshold-height)]
(when (not= layout-height @layout-height-atom)
(reset! layout-height-atom layout-height))
(reset! distance-atom new-distance)
(when (not= reached-threshold? @show-floating-scroll-down-button?)
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets))
(reset! show-floating-scroll-down-button? reached-threshold?)))))
(defn list-ref [ref] (reset! state/messages-list-ref ref))
(defn on-viewable-items-changed
[e]
(when @messages-list-ref
(when @state/messages-list-ref
(reset! state/first-not-visible-item
(when-let [last-visible-element (aget (oops/oget e "viewableItems")
(dec (oops/oget e "viewableItems.length")))]
@@ -61,7 +40,7 @@
;; Get first not visible element, if it's a datemark/gap
;; we might add messages on receiving as they do not have
;; a clock value, but usually it will be a message
first-not-visible (aget (oops/oget @messages-list-ref "props.data") (inc index))]
first-not-visible (aget (oops/oget @state/messages-list-ref "props.data") (inc index))]
(when (and first-not-visible
(= :message (:type first-not-visible)))
first-not-visible))))))
@@ -300,9 +279,16 @@
(reanimated/set-shared-value calculations-complete? true))
(js/setTimeout #(reset! messages-list-on-layout-finished? true) 1000)))
(defn on-scroll-fn
[distance-atom layout-height-atom]
(fn [layout-height new-distance]
(when (not= layout-height @layout-height-atom)
(reset! layout-height-atom layout-height))
(reset! distance-atom new-distance)))
(defn f-messages-list-content
[{:keys [insets distance-from-list-top content-height layout-height cover-bg-color distance-atom
show-floating-scroll-down-button? calculations-complete? messages-list-on-layout-finished?]}]
calculations-complete? messages-list-on-layout-finished? chat-list-scroll-y]}]
(let [theme (quo.theme/use-theme-value)
chat (rf/sub [:chats/current-chat-chat-view])
{:keys [keyboard-shown]} (hooks/use-keyboard)
@@ -354,9 +340,8 @@
:on-scroll (reanimated/use-animated-scroll-handler
(worklets/messages-list-on-scroll
distance-from-list-top
(on-scroll-fn show-floating-scroll-down-button?
distance-atom
layout-height)))
chat-list-scroll-y
(on-scroll-fn distance-atom layout-height)))
:style {:background-color (colors/theme-colors colors/white
colors/neutral-95
theme)}
@@ -20,9 +20,9 @@
content-height (atom 0)
layout-height (atom 0)
distance-atom (atom 0)
show-floating-scroll-down-button? (reagent/atom false)
messages-list-on-layout-finished? (reagent/atom false)
distance-from-list-top (reanimated/use-shared-value 0)]
distance-from-list-top (reanimated/use-shared-value 0)
chat-list-scroll-y (reanimated/use-shared-value 0)]
[rn/keyboard-avoiding-view
{:style style/keyboard-avoiding-container
:keyboard-vertical-offset (- (:bottom insets))}
@@ -36,14 +36,13 @@
:distance-atom distance-atom
:calculations-complete? calculations-complete?
:distance-from-list-top distance-from-list-top
:chat-list-scroll-y chat-list-scroll-y
:messages-list-on-layout-finished? messages-list-on-layout-finished?
:cover-bg-color :turquoise
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]
:cover-bg-color :turquoise}]
[composer.view/composer
{:insets insets
:scroll-to-bottom-fn list.view/scroll-to-bottom
:messages-list-on-layout-finished? messages-list-on-layout-finished?
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]]))
:chat-list-scroll-y chat-list-scroll-y
:messages-list-on-layout-finished? messages-list-on-layout-finished?}]]))
(defn lazy-chat-screen
[calculations-complete?]
@@ -22,16 +22,15 @@
(defn f-view-internal
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
addresses-for-permissions (rf/sub [:communities/addresses-for-permissions])
selected-accounts (filter #(contains? addresses-for-permissions
(:address %))
accounts)]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-permission-addresses (rf/sub [:communities/selected-permission-addresses])
selected-accounts (filter #(contains? selected-permission-addresses
(:address %))
accounts)]
(rn/use-effect (fn []
(rf/dispatch [:communities/set-addresses-for-permissions
(set (map :address accounts))]))
(rf/dispatch [:communities/initialize-permission-addresses]))
[])
[rn/view {:style style/container}
[quo/page-nav
@@ -87,7 +86,7 @@
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete #(join-community-and-navigate-back id addresses-for-permissions)}]]]))
:on-complete #(join-community-and-navigate-back id selected-permission-addresses)}]]]))
(defn view
[]
@@ -2,7 +2,6 @@
(:require [quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.not-implemented :as not-implemented]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[utils.i18n :as i18n]
@@ -16,11 +15,9 @@
:emoji (:emoji item)
:customization-color (:customization-color item)}
:token-details []
:checked? (contains? @selected-addresses (:address item))
:on-change (fn [checked?]
(if checked?
(swap! selected-addresses conj (:address item))
(swap! selected-addresses disj (:address item))))
:checked? (contains? selected-addresses (:address item))
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
(:address item)])
:container-style {:margin-bottom 8}}])
(defn view
@@ -28,49 +25,49 @@
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (reagent/atom (rf/sub [:communities/addresses-for-permissions]))]
(fn []
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
selected-addresses (rf/sub [:communities/selected-permission-addresses])]
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
[rn/flat-list
{:render-fn account-item
:render-data selected-addresses
:content-container-style {:padding 20}
:key-fn :address
:data accounts}]
[rn/flat-list
{:render-fn account-item
:render-data selected-addresses
:content-container-style {:padding 20}
:key-fn :address
:data accounts}]
(when (empty? @selected-addresses)
[rn/view
{:style style/error-message}
[quo/icon
:i/info
{:color colors/danger-50
:size 16}]
[quo/text
{:size :paragraph-2
:style {:color colors/danger-50}}
(i18n/label :t/no-addresses-selected)]])
(when (empty? selected-addresses)
[rn/view
{:style style/error-message}
[quo/icon
:i/info
{:color colors/danger-50
:size 16}]
[quo/text
{:size :paragraph-2
:style {:color colors/danger-50}}
(i18n/label :t/no-addresses-selected)]])
[rn/view {:style style/buttons}
[quo/button
{:type :grey
:container-style {:flex 1}
:on-press #(rf/dispatch [:navigate-back])}
(i18n/label :t/cancel)]
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? @selected-addresses)
:on-press (fn []
(rf/dispatch [:communities/set-addresses-for-permissions
@selected-addresses])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/confirm-changes)]]])))
[rn/view {:style style/buttons}
[quo/button
{:type :grey
:container-style {:flex 1}
:on-press (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/cancel)]
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? selected-addresses)
:on-press (fn []
(rf/dispatch [:communities/update-previous-permission-addresses])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/confirm-changes)]]]))
+34 -3
View File
@@ -185,6 +185,37 @@
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))
(rf/reg-event-fx :communities/set-addresses-for-permissions
(fn [{:keys [db]} [addresses]]
{:db (assoc-in db [:communities/addresses-for-permissions] addresses)}))
(defn initialize-permission-addresses
[{:keys [db]}]
(let [accounts (get-in db [:wallet :accounts])
addresses (set (map :address (vals accounts)))]
{:db (assoc db
:communities/previous-permission-addresses addresses
:communities/selected-permission-addresses addresses)}))
(rf/reg-event-fx :communities/initialize-permission-addresses
initialize-permission-addresses)
(rf/reg-event-fx :communities/update-previous-permission-addresses
(fn [{:keys [db]}]
{:db (assoc db
:communities/previous-permission-addresses
(get-in db [:communities/selected-permission-addresses]))}))
(defn toggle-selected-permission-address
[{:keys [db]} [address]]
{:db (update db
:communities/selected-permission-addresses
(fn [selected-addresses]
(if (contains? selected-addresses address)
(disj selected-addresses address)
(conj selected-addresses address))))})
(rf/reg-event-fx :communities/toggle-selected-permission-address
toggle-selected-permission-address)
(rf/reg-event-fx :communities/reset-selected-permission-addresses
(fn [{:keys [db]}]
{:db (assoc db
:communities/selected-permission-addresses
(get-in db [:communities/previous-permission-addresses]))}))
@@ -0,0 +1,19 @@
(ns status-im.contexts.communities.events-test
(:require [cljs.test :refer [deftest is]]
matcher-combinators.test
[status-im.contexts.communities.events :as events]))
(deftest initialize-permission-addresses-test
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"}
"0x2" {:address "0x2"}}}}}
expected-db {:db (assoc (:db initial-db)
:communities/previous-permission-addresses #{"0x1" "0x2"}
:communities/selected-permission-addresses #{"0x1" "0x2"})}]
(is (match? expected-db (events/initialize-permission-addresses initial-db)))))
(deftest toggle-selected-permission-address-test
(let [initial-db {:db {:communities/selected-permission-addresses #{"0x1" "0x2"}}}]
(is (match? {:db {:communities/selected-permission-addresses #{"0x1"}}}
(events/toggle-selected-permission-address initial-db ["0x2"])))
(is (match? {:db {:communities/selected-permission-addresses #{"0x1" "0x2" "0x3"}}}
(events/toggle-selected-permission-address initial-db ["0x3"])))))
@@ -0,0 +1,60 @@
(ns status-im.contexts.preview.quo.links.internal-link-card
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :size
:type :select
:options [{:key :message}
{:key :full-page}]}
{:type :text
:key :title}
{:type :text
:key :subtitle}
{:type :text
:key :description}
{:type :text
:key :emoji-hash}
{:type :boolean
:key :loading?}
{:type :number
:key :members-count}
{:type :number
:key :active-members-count}
{:key :type
:type :select
:options [{:key :community}
{:key :channel}
{:key :user}]}
{:key :banner
:type :select
:options (mapv (fn [k] {:key k})
(keys resources/mock-images))}
(preview/customization-color-option)])
(defn view
[]
(let [state (reagent/atom
{:title "Doodles"
:description "Coloring the world with joy • ᴗ •"
:members-count 24
:emoji-hash "🌟🚀🐠🌈🏰🔮🦉🐼🍉🎨🚲🌙🍔🌵"
:active-members-count 12
:loading? false
:customization-color :purple
:banner :light-blur-background
:type :user
:subtitle "Web 3.0 Designer @ethstatus - DJ, Producer - Dad - YouTuber"})]
(fn []
(let [banner (get resources/mock-images (:banner @state) :bored-ape)]
[preview/preview-container
{:state state
:descriptor descriptor}
[quo/internal-link-card
(assoc @state
:banner banner
:icon (resources/get-mock-image :status-logo)
:on-press #(js/alert "You clicked me!"))]]))))
+5 -1
View File
@@ -81,6 +81,7 @@
[status-im.contexts.preview.quo.inputs.title-input :as title-input]
[status-im.contexts.preview.quo.ios.drawer-bar :as drawer-bar]
[status-im.contexts.preview.quo.keycard.keycard :as keycard]
[status-im.contexts.preview.quo.links.internal-link-card :as internal-link-card]
[status-im.contexts.preview.quo.links.link-preview :as link-preview]
[status-im.contexts.preview.quo.links.url-preview :as url-preview]
[status-im.contexts.preview.quo.links.url-preview-list :as
@@ -326,7 +327,10 @@
:component keyboard-key/view}
{:name :numbered-keyboard
:component numbered-keyboard/view}]
:links [{:name :url-preview
:links [{:name :internal-link-card
:options {:insets {:top true}}
:component internal-link-card/view}
{:name :url-preview
:options {:insets {:top? true}}
:component url-preview/view}
{:name :url-preview-list
@@ -20,9 +20,9 @@
[]
(let [state (reagent/atom {:type :status-account
:networks? true
:values {:ethereum 150
:optimism 50
:arbitrum 25}})
:values {:ethereum {:amount 150}
:optimism {:amount 50}
:arbitrum {:amount 25}}})
status-account-props {:customization-color :purple
:size 32
:emoji "🍑"
@@ -90,11 +90,10 @@
(assoc :chats/loading? true
:networks/current-network current-network
:networks/networks (merge networks config/default-networks-by-id)
:profile/profile (merge profile-overview settings))
(assoc-in [:wallet :ui :tokens-loading?] true))
:fx [[:dispatch [:wallet/get-ethereum-chains]]
[:dispatch [:universal-links/generate-profile-url]]
[:dispatch [:community/fetch]]]}
:profile/profile (merge profile-overview settings)))
:fx [[:dispatch [:universal-links/generate-profile-url]]
[:dispatch [:community/fetch]]
[:dispatch [:wallet/initialize]]]}
(notifications/load-preferences)
(data-store.chats/fetch-chats-preview
{:on-success
@@ -125,8 +124,7 @@
:on-error #(log/error
"failed to start messenger")}]
:check-eip1559-activation {:network-id network-id}
:effects.profile/enable-local-notifications nil
:dispatch-n [[:wallet/get-accounts]]}
:effects.profile/enable-local-notifications nil}
(not (:universal-links/handling db))
(assoc :effects.chat/open-last-chat (get-in db [:profile/profile :key-uid]))
notifications-enabled?
@@ -11,7 +11,7 @@
:blur? true
:action :arrow}
{:title (i18n/label :t/password)
:on-press not-implemented/alert
:on-press #(rf/dispatch [:open-modal :settings-password])
:image-props :i/password
:image :icon
:blur? true
@@ -0,0 +1,10 @@
(ns status-im.contexts.profile.settings.screens.password.style)
(defn navigation
[top-inset]
{:padding-top top-inset})
(def header
{:padding-horizontal 20
:padding-bottom 8
:padding-top 12})
@@ -0,0 +1,86 @@
(ns status-im.contexts.profile.settings.screens.password.view
(:require [quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.biometric.events :as biometric]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.standard-authentication.standard-auth.authorize :as authorize]
[status-im.constants :as constants]
[status-im.contexts.profile.settings.screens.password.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- on-press-biometric-enable
[button-label theme]
(fn []
(authorize/authorize
{:biometric-auth? false
:blur? true
:theme theme
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
:on-close (fn [] (rf/dispatch [:standard-auth/reset-login-password]))
:on-auth-success (fn [password]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:standard-auth/reset-login-password])
(rf/dispatch [:biometric/enable password]))})))
(defn- get-biometric-item
[theme]
(let [auth-method (rf/sub [:auth-method])
biometric-type (rf/sub [:biometric/supported-type])
label (biometric/get-label-by-type biometric-type)
icon (biometric/get-icon-by-type biometric-type)
supported? (boolean biometric-type)
enabled? (= auth-method constants/auth-method-biometric)
biometric-on? (and supported? enabled?)
press-handler (if biometric-on?
(fn [] (rf/dispatch [:biometric/disable]))
(on-press-biometric-enable label theme))]
{:title label
:image-props icon
:image :icon
:blur? true
:action :selector
:action-props {:disabled? (not supported?)
:on-change press-handler
:checked? biometric-on?}
:on-press press-handler}))
(defn- get-change-password-item
[]
{:title (i18n/label :t/change-password)
:on-press not-implemented/alert
:blur? true
:image :icon
:image-props :i/password
:action :arrow})
(defn- view-internal
[{:keys [theme]}]
(let [insets (safe-area/get-insets)]
[quo/overlay {:type :shell}
[rn/view
{:key :navigation
:style (style/navigation (:top insets))}
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]]
[rn/view
{:key :header
:style style/header}
[quo/text
{:accessibility-label :password-settings-label
:weight :semi-bold
:number-of-lines 1
:size :heading-1}
(i18n/label :t/password)]]
[quo/category
{:key :category
:data [(get-biometric-item theme)
(get-change-password-item)]
:blur? true
:list-type :settings}]]))
(def view (quo.theme/with-theme view-internal))
@@ -156,14 +156,20 @@
:on-error [:activity-center/process-notification-failure nil
:notification/mark-all-as-read]}]})))
(rf/defn mark-all-as-read-success
{:events [:activity-center.notifications/mark-all-as-read-success]}
[{:keys [db]}]
(defn merge-chats
[db chats]
(update db :chats merge (collection/index-by :chat-id chats)))
(defn mark-all-as-read-success
[{:keys [db]} [{:keys [chats] :as _messenger-response}]]
{:db (-> (reduce (fn [acc notification-type]
(assoc-in acc [:activity-center :unread-counts-by-type notification-type] 0))
db
types/all-supported)
(update :activity-center dissoc :mark-all-as-read-undoable-till))})
(update :activity-center dissoc :mark-all-as-read-undoable-till)
(merge-chats (map data-store.chats/<-rpc chats)))})
(rf/reg-event-fx :activity-center.notifications/mark-all-as-read-success mark-all-as-read-success)
(rf/defn undo-mark-all-as-read
{:events [:activity-center.notifications/undo-mark-all-as-read-locally]}
+3 -1
View File
@@ -11,6 +11,7 @@
[status-im.contexts.syncing.utils :as sync-utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]
[utils.transforms :as transforms]))
(rf/defn local-pairing-update-role
@@ -106,7 +107,8 @@
config-map (.stringify js/JSON
(clj->js {:senderConfig {:keyUID key-uid
:keystorePath ""
:password sha3-pwd
:password (security/safe-unmask-data
sha3-pwd)
:deviceType platform/os}
:serverConfig {:timeout 0}}))]
(native-module/get-connection-string-for-bootstrapping-another-device
@@ -7,18 +7,24 @@
[status-im.contexts.wallet.common.activity-tab.view :as activity]
[status-im.contexts.wallet.common.collectibles-tab.view :as collectibles]
[status-im.contexts.wallet.common.empty-tab.view :as empty-tab]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[{:keys [selected-tab]}]
[rn/view {:style {:flex 1}}
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view]
:activity [activity/view]
:permissions [empty-tab/view
{:title (i18n/label :t/no-permissions)
:description (i18n/label :t/no-collectibles-description)
:placeholder? true}]
:dapps [dapps/view]
[about/view])])
(let [collectible-list (rf/sub [:wallet/current-viewing-account-collectibles])]
[rn/view {:style {:flex 1}}
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view
{:collectibles collectible-list
:on-collectible-press (fn [id]
(rf/dispatch [:wallet/get-collectible-details id])
(rf/dispatch [:navigate-to :wallet-collectible]))}]
:activity [activity/view]
:permissions [empty-tab/view
{:title (i18n/label :t/no-permissions)
:description (i18n/label :t/no-collectibles-description)
:placeholder? true}]
:dapps [dapps/view]
[about/view])]))
@@ -43,29 +43,3 @@
(def opensea-button
{:flex 1
:margin-left 6})
(def info-container
{:flex-direction :row
:margin-horizontal 20
:margin-top 8
:margin-bottom 12})
(def account
{:margin-right 6
:flex 1})
(def network
{:margin-left 6
:flex 1})
(def traits-title-container
{:margin-left 20
:margin-top 8})
(def traits-item
{:margin 6
:flex 1})
(def traits-container
{:margin-horizontal 14
:margin-vertical 12})
@@ -0,0 +1,27 @@
(ns status-im.contexts.wallet.collectible.tabs.about.style)
(def title
{:padding-horizontal 20
:padding-top 8
:padding-bottom 4})
(def description
{:padding-horizontal 20
:padding-top 4
:padding-bottom 12})
(def section-label
{:margin-horizontal 20
:margin-top 12})
(def link-cards-container
{:margin-horizontal 20
:margin-top 12
:flex-direction :row
:justify-content :space-between
:flex-wrap :wrap})
(defn link-card
[item-width]
{:margin-bottom 16
:width item-width})
@@ -0,0 +1,36 @@
(ns status-im.contexts.wallet.collectible.tabs.about.view
(:require [quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.collectible.tabs.about.style :as style]
[status-im.contexts.wallet.temp :as temp]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def ^:private link-card-space 28)
(defn- view-internal
[]
(let [window-width (rf/sub [:dimensions/window-width])
item-width (- (/ window-width 2) link-card-space)
{:keys [collectible-data]} (rf/sub [:wallet/last-collectible-details])
link-card-container-style (style/link-card item-width)]
[:<>
[rn/view {:style style/title}
[quo/text
{:size :heading-2
:weight :semi-bold}
(:name collectible-data)]]
[rn/view {:style style/description}
[quo/text
{:size :paragraph-2}
(:description collectible-data)]]
[quo/section-label
{:container-style style/section-label
:section (i18n/label :t/on-the-web)}]
[rn/view {:style style/link-cards-container}
(for [item (:cards temp/collectible-about)]
^{:key (:title item)}
[quo/link-card (assoc item :container-style link-card-container-style)])]]))
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,17 @@
(ns status-im.contexts.wallet.collectible.tabs.activity.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.wallet.temp :as temp]))
(defn activity-item
[item]
[:<>
[quo/divider-date (:timestamp item)]
[quo/wallet-activity item]])
(defn view
[]
[rn/flat-list
{:data temp/collectible-activities
:style {:flex 1}
:render-fn activity-item}])
@@ -0,0 +1,27 @@
(ns status-im.contexts.wallet.collectible.tabs.overview.style)
(def info-container
{:flex-direction :row
:margin-horizontal 20
:margin-top 8
:margin-bottom 12})
(def account
{:margin-right 6
:flex 1})
(def network
{:margin-left 6
:flex 1})
(def traits-title-container
{:margin-left 20
:margin-top 8})
(def traits-item
{:margin 6
:flex 1})
(def traits-container
{:margin-horizontal 14
:margin-vertical 12})
@@ -0,0 +1,72 @@
(ns status-im.contexts.wallet.collectible.tabs.overview.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.collectible.tabs.overview.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- trait-item
[{:keys [trait-type value]}]
[quo/data-item
{:subtitle-type :default
:card? true
:status :default
:size :default
:title trait-type
:subtitle value
:container-style style/traits-item}])
(defn- traits-section
[]
(let [traits (rf/sub [:wallet/last-collectible-details-traits])]
(when (pos? (count traits))
[rn/view
[quo/section-label
{:section (i18n/label :t/traits)
:container-style style/traits-title-container}]
[rn/flat-list
{:render-fn trait-item
:data traits
:key :collectibles-list
:key-fn :id
:num-columns 2
:content-container-style style/traits-container}]])))
(defn- info
[]
(let [chain-id (rf/sub [:wallet/last-collectible-details-chain-id])
{:keys [network-name]} (rf/sub [:wallet/network-details-by-chain-id chain-id])
subtitle (string/capitalize (name (or network-name "")))
{:keys [name emoji color]} (rf/sub [:wallet/last-collectible-details-owner])]
[rn/view {:style style/info-container}
[rn/view {:style style/account}
[quo/data-item
{:card? true
:status :default
:size :default
:title (i18n/label :t/account-title)
:subtitle name
:emoji emoji
:subtitle-type :account
:customization-color color}]]
[rn/view {:style style/network}
[quo/data-item
{:subtitle-type :network
:card? true
:status :default
:size :default
:title (i18n/label :t/network)
:network-image (quo.resources/get-network network-name)
:subtitle subtitle}]]]))
(defn- view-internal
[]
[:<>
[info]
[traits-section]])
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,15 @@
(ns status-im.contexts.wallet.collectible.tabs.view
(:require [quo.theme]
[status-im.contexts.wallet.collectible.tabs.about.view :as about]
[status-im.contexts.wallet.collectible.tabs.activity.view :as activity]
[status-im.contexts.wallet.collectible.tabs.overview.view :as overview]))
(defn- view-internal
[{:keys [selected-tab]}]
(case selected-tab
:overview [overview/view]
:about [about/view]
:activity [activity/view]
nil))
(def view (quo.theme/with-theme view-internal))
@@ -1,14 +1,12 @@
(ns status-im.contexts.wallet.collectible.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.contexts.wallet.collectible.style :as style]
[status-im.contexts.wallet.temp :as temp]
[status-im.contexts.wallet.collectible.tabs.view :as tabs]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -42,105 +40,17 @@
:icon-left :i/opensea}
(i18n/label :t/opensea)]])
(def activity-tabs-data
(def tabs-data
[{:id :overview
:label (i18n/label :t/overview)
:accessibility-label :overview-tab}
{:id :activity
:label (i18n/label :t/activity)
:accessibility-label :activity-tab}
{:id :permissions
:label (i18n/label :t/permissions)
:accessibility-label :permissions-tab}
{:id :about
:label (i18n/label :t/about)
:accessibility-label :about-tab}])
(defn traits-section
[traits]
(when (pos? (count traits))
[rn/view
[quo/section-label
{:section (i18n/label :t/traits)
:container-style style/traits-title-container}]
[rn/flat-list
{:render-fn (fn [{:keys [trait-type value]}]
[quo/data-item
{:card? true
:status :default
:size :default
:title trait-type
:subtitle value
:subtitle-type :default
:container-style style/traits-item}])
:data traits
:key :collectibles-list
:key-fn :id
:num-columns 2
:content-container-style style/traits-container}]]))
(defn activity-item
[item]
[:<>
[quo/divider-date (:timestamp item)]
[quo/wallet-activity item]])
(defn activity-section
[]
[rn/flat-list
{:data temp/collectible-activities
:style {:flex 1}
:render-fn activity-item}])
(defn info
[chain-id]
(let [network (rf/sub [:wallet/network-details-by-chain-id
chain-id])
network-keyword (get network :network-name)
network-name (when network-keyword
(string/capitalize (name network-keyword)))]
[rn/view
{:style style/info-container}
[rn/view {:style style/account}
[quo/data-item
{:card? true
:status :default
:size :default
:title (i18n/label :t/account-title)
:subtitle "Collectibles vault"
:subtitle-type :account
:emoji "🎮"
:customization-color :yellow}]]
[rn/view {:style style/network}
[quo/data-item
{:card? true
:status :default
:size :default
:title (i18n/label :t/network)
:network-image (quo.resources/get-network network-keyword)
:subtitle network-name
:subtitle-type :network}]]]))
(defn tabs
[_]
(let [selected-tab (reagent/atom (:id (first activity-tabs-data)))]
(fn [{:keys [traits chain-id] :as _props}]
[:<>
[quo/tabs
{:size 32
:style style/tabs
:scrollable? true
:default-active @selected-tab
:data activity-tabs-data
:on-change #(reset! selected-tab %)}]
(condp = @selected-tab
:overview [:<>
[info chain-id]
[traits-section traits]]
:activity [activity-section]
nil)])))
(defn collectible-actions-sheet
[]
[quo/action-drawer
@@ -162,35 +72,41 @@
(defn view-internal
[{:keys [theme] :as _props}]
(let [collectible (rf/sub [:wallet/last-collectible-details])
{:keys [collectible-data preview-url
collection-data]} collectible
{traits :traits
collectible-name :name} collectible-data
{collection-image :image-url
collection-name :name} collection-data
chain-id (rf/sub [:wallet/last-collectible-chain-id])]
[scroll-page/scroll-page
{:navigate-back? true
:height 148
:page-nav-props {:type :title-description
:title collectible-name
:description collection-name
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch
[:show-bottom-sheet
{:content collectible-actions-sheet
:theme theme}])}]
:picture preview-url}}
[rn/view {:style style/container}
[rn/view {:style style/preview-container}
[rn/image
{:source preview-url
:style style/preview}]]
[header collectible-name collection-name collection-image]
[cta-buttons]
[tabs
{:traits traits
:chain-id chain-id}]]]))
(let [selected-tab (reagent/atom :overview)
on-tab-change #(reset! selected-tab %)]
(fn []
(let [collectible (rf/sub [:wallet/last-collectible-details])
{:keys [collectible-data preview-url
collection-data]} collectible
{collection-image :image-url
collection-name :name} collection-data
{collectible-name :name} collectible-data]
[scroll-page/scroll-page
{:navigate-back? true
:height 148
:page-nav-props {:type :title-description
:title collectible-name
:description collection-name
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch
[:show-bottom-sheet
{:content collectible-actions-sheet
:theme theme}])}]
:picture preview-url}}
[rn/view {:style style/container}
[rn/view {:style style/preview-container}
[rn/image
{:source preview-url
:style style/preview}]]
[header collectible-name collection-name collection-image]
[cta-buttons]
[quo/tabs
{:size 32
:style style/tabs
:scrollable? true
:default-active @selected-tab
:on-change on-tab-change
:data tabs-data}]
[tabs/view {:selected-tab @selected-tab}]]]))))
(def view (quo.theme/with-theme view-internal))
@@ -13,7 +13,7 @@
nil))
(defn view
[{:keys [on-press accessibility-label icon-name switcher-type]
[{:keys [on-press accessibility-label icon-name switcher-type margin-top]
:or {icon-name :i/close
accessibility-label :top-bar
switcher-type :account-options}}]
@@ -21,6 +21,7 @@
networks (rf/sub [:wallet/network-details])]
[quo/page-nav
{:icon-name icon-name
:margin-top margin-top
:background :blur
:on-press on-press
:accessibility-label accessibility-label
@@ -5,32 +5,34 @@
[react-native.core :as rn]
[status-im.common.resources :as resources]
[status-im.contexts.wallet.common.empty-tab.view :as empty-tab]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.i18n :as i18n]))
(defn- view-internal
[{:keys [theme]}]
(let [specific-address (rf/sub [:wallet/current-viewing-account-address])
collectible-list (if specific-address
(rf/sub [:wallet/collectibles-per-account specific-address])
(rf/sub [:wallet/all-collectibles]))]
(if (empty? collectible-list)
[{:keys [theme collectibles filtered? on-collectible-press]}]
(let [no-results-match-query? (and filtered? (empty? collectibles))]
(cond
no-results-match-query?
[rn/view {:style {:flex 1 :justify-content :center}}
[quo/empty-state
{:title (i18n/label :t/nothing-found)
:description (i18n/label :t/try-to-search-something-else)
:image (resources/get-themed-image :no-collectibles theme)}]]
(empty? collectibles)
[empty-tab/view
{:title (i18n/label :t/no-collectibles)
:description (i18n/label :t/no-collectibles-description)
:image (resources/get-themed-image :no-collectibles theme)}]
:else
[rn/flat-list
{:data collectible-list
{:data collectibles
:style {:flex 1}
:content-container-style {:align-items :center}
:num-columns 2
:render-fn (fn [{:keys [preview-url id]}]
:render-fn (fn [{:keys [preview-url] :as collectible}]
[quo/collectible
{:images [preview-url]
:on-press (fn []
(rf/dispatch [:wallet/get-collectible-details id])
(rf/dispatch
[:navigate-to
:wallet-collectible]))}])}])))
:on-press #(on-collectible-press collectible)}])}])))
(def view (quo.theme/with-theme view-internal))
@@ -15,6 +15,7 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.responsiveness :refer [iphone-11-Pro-20-pixel-from-width]]
[utils.security.core :as security]
[utils.string]))
(defn keypair-string
@@ -119,9 +120,8 @@
:track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color
:on-auth-success (fn [entered-password]
(prn entered-password)
(rf/dispatch [:wallet/derive-address-and-add-account
{:sha3-pwd entered-password
{:sha3-pwd (security/safe-unmask-data entered-password)
:emoji @emoji
:color @account-color
:path @derivation-path
@@ -64,7 +64,7 @@
(update-vals #(cske/transform-keys csk/->kebab-case %))
(update-vals #(mapv rpc->balances-per-chain %))))
(defn <-rpc
(defn rpc->network
[network]
(-> network
(set/rename-keys
@@ -13,10 +13,11 @@
(defn- show-save-account-toast
[updated-key]
(let [message (case updated-key
:name :t/edit-wallet-account-name-updated-message
:color :t/edit-wallet-account-colour-updated-message
:emoji :t/edit-wallet-account-emoji-updated-message
:prod-preferred-chain-ids :t/edit-wallet-network-preferences-updated-message
:name :t/edit-wallet-account-name-updated-message
:color :t/edit-wallet-account-colour-updated-message
:emoji :t/edit-wallet-account-emoji-updated-message
(:prod-preferred-chain-ids
:test-preferred-chain-ids) :t/edit-wallet-network-preferences-updated-message
nil)]
(rf/dispatch [:toasts/upsert
{:id :edit-account
@@ -50,11 +51,15 @@
:new-value @edited-account-name}))]
(fn []
(let [{:keys [name emoji address color watch-only?]
:as account} (rf/sub [:wallet/current-viewing-account])
network-details (rf/sub [:wallet/network-preference-details])
account-name (or @edited-account-name name)
button-disabled? (or (nil? @edited-account-name)
(= name @edited-account-name))]
:as account} (rf/sub [:wallet/current-viewing-account])
network-details (rf/sub [:wallet/network-preference-details])
test-networks-enabled? (rf/sub [:profile/test-networks-enabled?])
network-preferences-key (if test-networks-enabled?
:test-preferred-chain-ids
:prod-preferred-chain-ids)
account-name (or @edited-account-name name)
button-disabled? (or (nil? @edited-account-name)
(= name @edited-account-name))]
[create-or-edit-account/view
{:page-nav-right-side [{:icon-name :i/delete
:on-press #(js/alert "Delete account: to be implemented")}]
@@ -95,7 +100,7 @@
(rf/dispatch [:hide-bottom-sheet])
(save-account
{:account account
:updated-key :prod-preferred-chain-ids
:updated-key network-preferences-key
:new-value chain-ids}))
:watch-only? watch-only?}])}]))
:container-style style/data-item}]]))))
+11 -3
View File
@@ -195,13 +195,13 @@
(let [network-data
{:test (map #(->> %
:Test
data-store/<-rpc)
data-store/rpc->network)
data)
:prod (map #(->> %
:Prod
data-store/<-rpc)
data-store/rpc->network)
data)}]
{:db (assoc db :wallet/networks network-data)})))
{:db (assoc-in db [:wallet :networks] network-data)})))
(rf/reg-event-fx :wallet/find-ens
(fn [{:keys [db]} [input contacts chain-id cb]]
@@ -301,6 +301,10 @@
(background-timer/clear-timeout current-timeout)
{:db (assoc db :wallet/local-suggestions [] :wallet/valid-ens-or-address? false)})))
(rf/reg-event-fx :wallet/clean-account-selection
(fn [{:keys [db]}]
{:db (update-in db [:wallet :ui :send] dissoc :send-account-address)}))
(rf/reg-event-fx :wallet/get-address-details-success
(fn [{:keys [db]} [{:keys [hasActivity]}]]
{:db (assoc-in db
@@ -327,3 +331,7 @@
(fn [_ [explorer-link address]]
{:fx [[:dispatch [:hide-bottom-sheet]]
[:dispatch [:browser.ui/open-url (str explorer-link "/" address)]]]}))
(rf/reg-event-fx :wallet/initialize
(fn []
{:fx [[:dispatch-n [[:wallet/get-ethereum-chains] [:wallet/get-accounts]]]]}))
@@ -4,12 +4,18 @@
[status-im.contexts.wallet.common.activity-tab.view :as activity]
[status-im.contexts.wallet.common.collectibles-tab.view :as collectibles]
[status-im.contexts.wallet.home.tabs.assets.view :as assets]
[status-im.contexts.wallet.home.tabs.style :as style]))
[status-im.contexts.wallet.home.tabs.style :as style]
[utils.re-frame :as rf]))
(defn view
[{:keys [selected-tab]}]
[rn/view {:style style/container}
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view]
[activity/view])])
(let [collectible-list (rf/sub [:wallet/all-collectibles])]
[rn/view {:style style/container}
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view
{:collectibles collectible-list
:on-collectible-press (fn [id]
(rf/dispatch [:wallet/get-collectible-details id])
(rf/dispatch [:navigate-to :wallet-collectible]))}]
[activity/view])]))
+94 -37
View File
@@ -14,10 +14,6 @@
{:db (assoc-in db [:wallet :ui :send :select-address-tab] tab)}))
(rf/reg-event-fx :wallet/select-send-account-address
(fn [{:keys [db]} [address]]
{:db (assoc db [:wallet :ui :send :send-account-address] address)}))
(rf/reg-event-fx :wallet/suggested-routes-success
(fn [{:keys [db]} [suggested-routes timestamp]]
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
@@ -44,16 +40,36 @@
(update-in [:wallet :ui :send] dissoc :route)
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
(rf/reg-event-fx :wallet/select-send-account-address
(fn [{:keys [db]} [{:keys [address stack-id]}]]
{:db (-> db
(assoc-in [:wallet :ui :send :send-account-address] address)
(update-in [:wallet :ui :send] dissoc :to-address))
:fx [[:navigate-to-within-stack [:wallet-select-asset stack-id]]]}))
(rf/reg-event-fx :wallet/select-send-address
(fn [{:keys [db]} [{:keys [address stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :to-address] address)
{:db (-> db
(assoc-in [:wallet :ui :send :to-address] address)
(update-in [:wallet :ui :send] dissoc :send-account-address))
:fx [[:navigate-to-within-stack [:wallet-select-asset stack-id]]]}))
(rf/reg-event-fx :wallet/send-select-token
(fn [{:keys [db]} [{:keys [token stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :token] token)
{:db (-> db
(update-in [:wallet :ui :send] dissoc :collectible)
(assoc-in [:wallet :ui :send :token] token))
:fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]}))
(rf/reg-event-fx :wallet/send-select-collectible
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :token)
(assoc-in [:wallet :ui :send :collectible] collectible)
(assoc-in [:wallet :ui :send :amount] 1))
:fx [[:dispatch [:wallet/get-suggested-routes 1]]
[:navigate-to-within-stack [:wallet-transaction-confirmation stack-id]]]}))
(rf/reg-event-fx :wallet/send-select-amount
(fn [{:keys [db]} [{:keys [amount stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :amount] amount)
@@ -63,17 +79,26 @@
(fn [{:keys [db now]} [amount]]
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
token (get-in db [:wallet :ui :send :token])
to-address (get-in db [:wallet :ui :send :to-address])
token-decimal (:decimals token)
token-id (:symbol token)
network-preferences []
collectible (get-in db [:wallet :ui :send :collectible])
account-address (get-in db [:wallet :ui :send :send-account-address])
to-address (or account-address (get-in db [:wallet :ui :send :to-address]))
token-decimal (when token (:decimals token))
token-id (if token
(:symbol token)
(str (get-in collectible [:id :contract-id :address])
":"
(get-in collectible [:id :token-id])))
network-preferences (if token [] [(get-in collectible [:id :contract-id :chain-id])])
gas-rates constants/gas-rate-medium
amount-in (send-utils/amount-in-hex amount token-decimal)
amount-in (send-utils/amount-in-hex amount (if token token-decimal 0))
from-address wallet-address
disabled-from-chain-ids []
disabled-to-chain-ids []
from-locked-amount {}
request-params [constants/send-type-transfer
transaction-type (if token
constants/send-type-transfer
constants/send-type-erc-721-transfer)
request-params [transaction-type
from-address
to-address
amount-in
@@ -110,21 +135,43 @@
:fx [[:dispatch [:navigate-to :wallet-transaction-progress]]]})))
(defn- transaction-bridge
[{:keys [from-address to-address route]}]
(let [{:keys [from bridge-name amount-out gas-amount gas-fees]} route
{:keys [gas-price max-fee-per-gas-medium max-priority-fee-per-gas]} gas-fees]
[{:BridgeName bridge-name
:ChainID (:chain-id from)
:TransferTx {:From from-address
:To to-address
:Gas (money/to-hex gas-amount)
:GasPrice (money/to-hex (money/->wei :gwei gas-price))
:Value amount-out
:Nonce nil
:MaxFeePerGas (money/to-hex (money/->wei :gwei max-fee-per-gas-medium))
:MaxPriorityFeePerGas (money/to-hex (money/->wei :gwei max-priority-fee-per-gas))
:Input ""
:Data "0x"}}]))
[{:keys [from-address to-address token-id token-address route]}]
(let [{:keys [from bridge-name amount-out gas-amount
gas-fees]} route
eip-1559-enabled? (:eip-1559-enabled gas-fees)
{:keys [gas-price max-fee-per-gas-medium
max-priority-fee-per-gas]} gas-fees
transfer-tx (merge
(if eip-1559-enabled?
{:TxType "0x02"
:MaxFeePerGas (money/to-hex
(money/->wei
:gwei
max-fee-per-gas-medium))
:MaxPriorityFeePerGas (money/to-hex
(money/->wei
:gwei
max-priority-fee-per-gas))}
{:TxType "0x00"
:GasPrice (money/to-hex (money/->wei :gwei
gas-price))})
{:From from-address
:To (or token-address to-address)
:Gas (money/to-hex gas-amount)
:Value amount-out
:Nonce nil
:Input ""
:Data "0x"})]
[(merge
{:BridgeName bridge-name
:ChainID (:chain-id from)}
(if (= bridge-name constants/bridge-name-erc-721-transfer)
{:ERC721TransferTx
(merge
{:Recipient to-address
:TokenID token-id}
transfer-tx)}
{:TransferTx transfer-tx}))]))
(defn- multi-transaction-command
[{:keys [from-address to-address from-asset to-asset amount-out transfer-type]
@@ -140,17 +187,27 @@
(fn [{:keys [db]} [sha3-pwd]]
(let [route (get-in db [:wallet :ui :send :route])
from-address (get-in db [:wallet :current-viewing-account-address])
to-address (get-in db [:wallet :ui :send :to-address])
token (get-in db [:wallet :ui :send :token])
token-id (:symbol token)
request-params [(multi-transaction-command {:from-address from-address
:to-address to-address
:from-asset token-id
:to-asset token-id
:amount-out (:amount-out route)})
(transaction-bridge {:to-address to-address
:from-address from-address
:route route})
collectible (get-in db [:wallet :ui :send :collectible])
token-address (when collectible
(get-in collectible
[:id :contract-id :address]))
to-address (get-in db [:wallet :ui :send :to-address])
token-id (if token
(:symbol token)
(get-in collectible [:id :token-id]))
request-params [(multi-transaction-command
{:from-address from-address
:to-address to-address
:from-asset token-id
:to-asset token-id
:amount-out (:amount-out route)})
(transaction-bridge {:to-address to-address
:from-address from-address
:route route
:token-address token-address
:token-id (when collectible
(money/to-hex (js/parseInt token-id)))})
sha3-pwd]]
{:json-rpc/call [{:method "wallet_createMultiTransaction"
:params request-params
@@ -41,7 +41,8 @@
:removed false}
:wallet/wallet-send-token {:symbol :eth}
:wallet/wallet-send-loading-suggested-routes? false
:wallet/wallet-send-route {:route []}})
:wallet/wallet-send-route {:route []}
:wallet/wallet-send-suggested-routes {:candidates []}})
(h/describe "Send > input amount screen"
(h/setup-restorable-re-frame)
@@ -7,7 +7,6 @@
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.input-amount.style :as style]
[status-im.contexts.wallet.send.routes.view :as routes]
[utils.debounce :as debounce]
@@ -58,7 +57,6 @@
[{:keys [rate limit]}]
(let [bottom (safe-area/get-bottom)
{:keys [currency]} (rf/sub [:profile/profile])
networks (rf/sub [:wallet/network-details])
token (rf/sub [:wallet/wallet-send-token])
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
token-symbol (:symbol token)
@@ -101,18 +99,16 @@
:or {on-confirm #(rf/dispatch [:wallet/send-select-amount
{:amount @input-value
:stack-id :wallet-send-input-amount}])}}]
(let [limit-label (make-limit-label @current-limit)
input-num-value (parse-double @input-value)
route (rf/sub [:wallet/wallet-send-route])
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
confirm-disabled? (or
(nil? route)
(empty? @input-value)
(<= input-num-value 0)
(> input-num-value (:amount @current-limit)))
from-network (utils/id->network (get-in route [:From :chainId]))
to-network (utils/id->network (get-in route [:To :chainId]))
amount (str @input-value " " token-symbol)]
(let [limit-label (make-limit-label @current-limit)
input-num-value (parse-double @input-value)
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
route (rf/sub [:wallet/wallet-send-route])
confirm-disabled? (or
(nil? route)
(empty? @input-value)
(<= input-num-value 0)
(> input-num-value (:amount @current-limit)))
amount (str @input-value " " token-symbol)]
(rn/use-effect
(fn []
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
@@ -137,7 +133,7 @@
{:container-style style/input-container
:token token-symbol
:currency currency
:networks networks
:networks (:networks token)
:title (i18n/label :t/send-limit {:limit limit-label})
:conversion conversion-rate
:show-keyboard? false
@@ -145,20 +141,10 @@
:on-swap handle-swap
:on-change-text (fn [text]
(handle-on-change text))}]
;; Network routing content to be added
[rn/scroll-view
{:content-container-style {:flex-grow 1
:align-items :center
:justify-content :center}}
(cond loading-suggested-routes?
[quo/text "Loading routes"]
(and (not loading-suggested-routes?) route)
[routes/view
{:amount amount
:from-network from-network
:to-network to-network}]
(and (not loading-suggested-routes?) (nil? route))
[quo/text "Route not found"])]
[routes/view
{:amount amount
:routes suggested-routes
:networks (:networks token)}]
[quo/bottom-actions
{:actions :1-action
:button-one-label (i18n/label :t/confirm)
@@ -2,6 +2,7 @@
(def routes-container
{:padding-horizontal 20
:flex 1
:padding-vertical 16
:width "100%"
:height "100%"})
@@ -24,3 +25,8 @@
(def network-link
{:right 6
:z-index 1})
(def empty-container
{:flex-grow 1
:align-items :center
:justify-content :center})
@@ -2,31 +2,53 @@
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.routes.style :as style]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn route-item
[{:keys [amount from-network to-network status]}]
[rn/view {:style style/routes-inner-container}
[quo/network-bridge
{:amount amount
:network from-network
:status status}]
[quo/network-link
{:shape :linear
:source from-network
:destination to-network
:container-style style/network-link}]
[quo/network-bridge
{:amount amount
:network to-network
:status status
:container-style {:right 12}}]])
(defn view
[{:keys [amount from-network to-network]}]
[rn/view {:style style/routes-container}
[rn/view {:style style/routes-header-container}
[quo/section-label
{:section (i18n/label :t/from-label)
:container-style (style/section-label 0)}]
[quo/section-label
{:section (i18n/label :t/to-label)
:container-style (style/section-label 64)}]]
[rn/view {:style style/routes-inner-container}
[quo/network-bridge
{:amount amount
:network from-network
:status :default}]
[quo/network-link
{:shape :linear
:source from-network
:destination to-network
:container-style style/network-link}]
[quo/network-bridge
{:amount amount
:network to-network
:status :default
:container-style {:right 12}}]]])
[{:keys [amount routes]}]
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
candidates (:candidates routes)]
(if (and (not loading-suggested-routes?) (not-empty candidates))
[rn/flat-list
{:data candidates
:content-container-style style/routes-container
:header [rn/view {:style style/routes-header-container}
[quo/section-label
{:section (i18n/label :t/from-label)
:container-style (style/section-label 0)}]
[quo/section-label
{:section (i18n/label :t/to-label)
:container-style (style/section-label 64)}]]
:render-fn (fn [route]
[route-item
{:amount amount
:status :default
:from-network (utils/id->network (get-in route [:from :chain-id]))
:to-network (utils/id->network (get-in route
[:to :chain-id]))}])}]
[rn/view {:style style/empty-container}
(if loading-suggested-routes?
[rn/activity-indicator]
(when (not (nil? candidates))
[quo/text (i18n/label :t/no-routes-found)]))])))
@@ -17,5 +17,5 @@
(def button
{:justify-self :flex-end
:margin-bottom 46
:margin-bottom 20
:margin-horizontal 20})
@@ -12,10 +12,9 @@
[{:keys [color address] :as account}]
[quo/account-item
{:account-props (assoc account :customization-color color)
:on-press (fn []
(rf/dispatch [:wallet/select-send-account-address address])
(rf/dispatch [:navigate-to-within-stack
[:wallet-select-asset :wallet-select-address]]))}])
:on-press #(rf/dispatch [:wallet/select-send-account-address
{:address address
:stack-id :wallet-select-address}])}])
(defn my-accounts
[theme]
@@ -3,7 +3,9 @@
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.floating-button-page.view :as floating-button-page]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.item-types :as types]
@@ -115,6 +117,7 @@
(let [on-close (fn []
(rf/dispatch [:wallet/clean-scanned-address])
(rf/dispatch [:wallet/clean-local-suggestions])
(rf/dispatch [:wallet/clean-account-selection])
(rf/dispatch [:wallet/select-address-tab nil])
(rf/dispatch [:navigate-back]))
on-change-tab #(rf/dispatch [:wallet/select-address-tab %])
@@ -126,14 +129,22 @@
(rn/use-effect (fn []
(fn []
(rf/dispatch [:wallet/clean-scanned-address])
(rf/dispatch [:wallet/clean-local-suggestions]))))
[rn/scroll-view
{:content-container-style style/container
:keyboard-should-persist-taps :handled
:scroll-enabled false}
[account-switcher/view
{:on-press on-close
:switcher-type :select-account}]
(rf/dispatch [:wallet/clean-local-suggestions])
(rf/dispatch [:wallet/clean-account-selection]))))
[floating-button-page/view
{:header [account-switcher/view
{:on-press on-close
:margin-top (safe-area/get-top)
:switcher-type :select-account}]
:footer (when (> (count @input-value) 0)
[quo/button
{:accessibility-label :continue-button
:type :primary
:disabled? (not valid-ens-or-address?)
:on-press #(rf/dispatch [:wallet/select-send-address
{:address @input-value
:stack-id :wallet-select-address}])}
(i18n/label :t/continue)])}
[quo/text-combinations
{:title (i18n/label :t/send-to)
:container-style style/title-container
@@ -147,17 +158,7 @@
[rn/view
{:style {:flex 1
:padding 8}}
[local-suggestions-list]]
(when (> (count @input-value) 0)
[quo/button
{:accessibility-label :continue-button
:type :primary
:disabled? (not valid-ens-or-address?)
:container-style style/button
:on-press #(rf/dispatch [:wallet/select-send-address
{:address @input-value
:stack-id :wallet-select-address}])}
(i18n/label :t/continue)])]
[local-suggestions-list]]]
[:<>
[quo/tabs
{:style style/tabs
@@ -173,4 +174,3 @@
(defn view
[]
[:f> f-view])
@@ -1,11 +1,12 @@
(ns status-im.contexts.wallet.send.select-asset.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.collectibles-tab.view :as collectibles-tab]
[status-im.contexts.wallet.send.select-asset.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -17,13 +18,12 @@
(defn- asset-component
[]
(fn [token _ _ _]
(let [on-press
#(rf/dispatch [:wallet/send-select-token
{:token token
:stack-id :wallet-select-asset}])
(let [on-press #(rf/dispatch [:wallet/send-select-token
{:token token
:stack-id :wallet-select-asset}])
total-balance-formatted (.toFixed (:total-balance token) 2)
balance-fiat-formatted (.toFixed (:total-balance-fiat token) 2)
currency-symbol (rf/sub [:profile/currency-symbol])]
balance-fiat-formatted (.toFixed (:total-balance-fiat token) 2)
currency-symbol (rf/sub [:profile/currency-symbol])]
[quo/token-network
{:token (:symbol token)
:label (:name token)
@@ -44,34 +44,48 @@
:on-scroll-to-index-failed identity
:render-fn asset-component}]))
(defn- tab-view
[search-text selected-tab]
(case selected-tab
:tab/assets [asset-list search-text]
:tab/collectibles [quo/empty-state
{:title (i18n/label :t/no-collectibles)
:description (i18n/label :t/no-collectibles-description)
:placeholder? true
:container-style (style/empty-container-style (safe-area/get-top))}]))
(defn- search-input
[search-text on-change-text]
[rn/view {:style style/search-input-container}
[quo/input
{:small? true
:placeholder (i18n/label :t/search-assets)
:icon-name :i/search
:value search-text
:on-change-text on-change-text}]])
(defn collectibles-grid
[search-text]
(let [on-change-text #(reset! search-text %)]
(fn []
[rn/view {:style style/search-input-container}
[quo/input
{:small? true
:placeholder (i18n/label :t/search-assets)
:icon-name :i/search
:value @search-text
:on-change-text on-change-text}]])))
(let [collectibles (rf/sub [:wallet/current-viewing-account-collectibles-filtered search-text])
search-performed? (not (string/blank? search-text))]
[collectibles-tab/view
{:collectibles collectibles
:filtered? search-performed?
:on-collectible-press #(rf/dispatch [:wallet/send-select-collectible
{:collectible %
:stack-id :wallet-select-asset}])}]))
(defn- tab-view
[search-text selected-tab on-change-text]
(let [unfiltered-collectibles (rf/sub [:wallet/current-viewing-account-collectibles])
show-search-input? (or (= selected-tab :tab/assets)
(and (= selected-tab :tab/collectibles)
(seq unfiltered-collectibles)))]
[:<>
(when show-search-input?
[search-input search-text on-change-text])
(case selected-tab
:tab/assets [asset-list search-text]
:tab/collectibles [collectibles-grid search-text])]))
(defn- f-view-internal
[]
(let [selected-tab (reagent/atom (:id (first tabs-data)))
search-text (reagent/atom "")
on-close #(rf/dispatch [:navigate-back-within-stack
:wallet-select-asset])]
(let [selected-tab (reagent/atom (:id (first tabs-data)))
search-text (reagent/atom "")
on-change-text #(reset! search-text %)
on-change-tab #(reset! selected-tab %)
on-close #(rf/dispatch [:navigate-back-within-stack :wallet-select-asset])]
(fn []
[rn/safe-area-view {:style style/container}
[rn/scroll-view
@@ -94,9 +108,8 @@
:container-style {:margin-horizontal 20
:margin-vertical 8}
:data tabs-data
:on-change #(reset! selected-tab %)}]
[search-input search-text]
[tab-view @search-text @selected-tab]]])))
:on-change on-change-tab}]
[tab-view @search-text @selected-tab on-change-text]]])))
(defn- view-internal
[]
@@ -1,5 +1,6 @@
(ns status-im.contexts.wallet.send.transaction-confirmation.view
(:require
[clojure.string :as string]
[legacy.status-im.utils.utils :as utils]
[quo.core :as quo]
[quo.theme :as quo.theme]
@@ -9,10 +10,11 @@
[status-im.common.standard-authentication.core :as standard-auth]
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn- transaction-title
[{:keys [token-symbol amount account to-address]}]
[{:keys [token-symbol amount account to-address image-url collectible?]}]
[rn/view {:style style/content-container}
[rn/view {:style {:flex-direction :row}}
[quo/text
@@ -22,10 +24,10 @@
:accessibility-label :send-label}
(i18n/label :t/send)]
[quo/summary-tag
{:token token-symbol
{:token (if collectible? "" token-symbol)
:label (str amount " " token-symbol)
:type :token
:image-source :eth}]]
:type (if collectible? :collectible :token)
:image-source (if collectible? image-url :eth)}]]
[rn/view
{:style {:flex-direction :row
:margin-top 4}}
@@ -54,7 +56,7 @@
:label (utils/get-shortened-address to-address)}]]])
(defn- user-summary
[{:keys [amount account-props theme label accessibility-label summary-type]}]
[{:keys [amount token-symbol account-props theme label accessibility-label summary-type]}]
[rn/view
{:style {:padding-horizontal 20
:padding-bottom 16}}
@@ -67,7 +69,8 @@
[quo/summary-info
{:type summary-type
:networks? true
:values {:ethereum amount}
:values {:ethereum {:amount amount
:token-symbol token-symbol}}
:account-props account-props}]])
(defn- transaction-details
@@ -124,72 +127,85 @@
(let [on-close #(rf/dispatch [:navigate-back-within-stack :wallet-select-asset])
send-transaction-data (rf/sub [:wallet/wallet-send])
token (:token send-transaction-data)
token-symbol (:symbol token)
amount (:amount send-transaction-data)
route (:route send-transaction-data)
estimated-time-min (:estimated-time route)
max-fees "-"
to-address (:to-address send-transaction-data)
account (rf/sub [:wallet/current-viewing-account])
account-color (:color account)
from-account-props {:customization-color account-color
:size 32
:emoji (:emoji account)
:type :default
:name (:name account)
:address (utils/get-shortened-address (:address account))}
user-props {:full-name to-address
:address (utils/get-shortened-address to-address)}]
(prn route)
collectible (:collectible send-transaction-data)
collection-data (:collection-data collectible)
collectible-data (:collectible-data collectible)
collectible-id (get-in collectible [:id :token-id])
token-symbol (if collectible
(first (remove string/blank?
[(:name collectible-data)
(str (:name collection-data) " #" collectible-id)]))
(:symbol token))
image-url (when collectible (:image-url collectible-data))
amount (:amount send-transaction-data)]
(fn [{:keys [theme]}]
[rn/view {:style {:flex 1}}
[floating-button-page/view
{:header [quo/page-nav
{:icon-name :i/arrow-left
:on-press on-close
:margin-top (safe-area/get-top)
:background :blur
:accessibility-label :top-bar
:right-side [{:icon-name :i/advanced
:on-press #(js/alert
"to be implemented")
:accessibility-label :advanced-options}]}]
:footer [standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-send)
:container-style {:z-index 2}
:customization-color account-color
:on-auth-success #(rf/dispatch [:wallet/send-transaction %])
:auth-button-label (i18n/label :t/confirm)}]
:gradient-cover? true
:customization-color (:color account)}
[rn/view
[transaction-title
{:token-symbol token-symbol
:amount amount
:account account
:to-address to-address}]
[user-summary
{:amount amount
:summary-type :status-account
:accessibility-label :summary-from-label
:label (i18n/label :t/from-capitalized)
:account-props from-account-props
:theme theme}]
[user-summary
{:amount amount
:summary-type :account
:accessibility-label :summary-to-label
:label (i18n/label :t/to-capitalized)
:account-props user-props
:theme theme}]
[transaction-details
{:estimated-time-min estimated-time-min
:max-fees max-fees
:token token
:amount amount
:to-address to-address
:theme theme}]]]])))
(let [route (:route send-transaction-data)
estimated-time-min (:estimated-time route)
max-fees "-"
to-address (:to-address send-transaction-data)
account (rf/sub [:wallet/current-viewing-account])
account-color (:color account)
from-account-props {:customization-color account-color
:size 32
:emoji (:emoji account)
:type :default
:name (:name account)
:address (utils/get-shortened-address (:address account))}
user-props {:full-name to-address
:address (utils/get-shortened-address to-address)}]
[rn/view {:style {:flex 1}}
[floating-button-page/view
{:header [quo/page-nav
{:icon-name :i/arrow-left
:on-press on-close
:margin-top (safe-area/get-top)
:background :blur
:accessibility-label :top-bar
:right-side [{:icon-name :i/advanced
:on-press #(js/alert
"to be implemented")
:accessibility-label :advanced-options}]}]
:footer [standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-send)
:container-style {:z-index 2}
:customization-color account-color
:on-auth-success #(rf/dispatch [:wallet/send-transaction
(security/safe-unmask-data %)])
:auth-button-label (i18n/label :t/confirm)}]
:gradient-cover? true
:customization-color (:color account)}
[rn/view
[transaction-title
{:token-symbol token-symbol
:amount amount
:account account
:to-address to-address
:image-url image-url
:collectible? (some? collectible)}]
[user-summary
{:amount amount
:token-symbol token-symbol
:summary-type :status-account
:accessibility-label :summary-from-label
:label (i18n/label :t/from-capitalized)
:account-props from-account-props
:theme theme}]
[user-summary
{:amount amount
:token-symbol token-symbol
:summary-type :account
:accessibility-label :summary-to-label
:label (i18n/label :t/to-capitalized)
:account-props user-props
:theme theme}]
[transaction-details
{:estimated-time-min estimated-time-min
:max-fees max-fees
:token token
:amount amount
:to-address to-address
:theme theme}]]]]))))
(def view (quo.theme/with-theme view-internal))
+17
View File
@@ -105,3 +105,20 @@
:type :network
:network-logo (quo.resources/get-network :ethereum)
:network-name "Mainnet"}}])
(def collectible-about
{:cards [{:title "BAYC"
:icon :social/link
:address "boredapeyachtclub"
:customization-color :social/link
:on-press #(js/alert "pressed")}
{:title "Twitter"
:icon :social/twitter
:address "@BoredApeYC"
:customization-color :social/twitter
:on-press #(js/alert "pressed")}
{:title "Opensea"
:icon :social/opensea
:address "Bored Ape Yacht Club"
:customization-color :social/opensea
:on-press #(js/alert "pressed")}]})
+10 -2
View File
@@ -37,6 +37,7 @@
[status-im.contexts.profile.edit.name.view :as edit-name]
[status-im.contexts.profile.edit.view :as edit-profile]
[status-im.contexts.profile.profiles.view :as profiles]
[status-im.contexts.profile.settings.screens.password.view :as settings-password]
[status-im.contexts.profile.settings.view :as settings]
[status-im.contexts.shell.activity-center.view :as activity-center]
[status-im.contexts.shell.jump-to.view :as shell]
@@ -338,7 +339,8 @@
{:name :wallet-send-input-amount
:options {:modalPresentationStyle :overCurrentContext
:insets {:top? true}}
:insets {:top? true
:bottom? true}}
:component wallet-send-input-amount/view}
{:name :wallet-select-address
@@ -367,7 +369,13 @@
:options (merge
options/dark-screen
{:modalPresentationStyle :overCurrentContext})
:component scan-profile-qr-page/view}]
:component scan-profile-qr-page/view}
;; Settings
{:name :settings-password
:options options/transparent-screen-options
:component settings-password/view}]
(when js/goog.DEBUG
[{:name :dev-component-preview
+8 -7
View File
@@ -73,12 +73,14 @@
:key-uid target-key-uid
:theme (theme/get-theme)
:override-ring? override-ring?})
(image-server/get-initials-avatar-uri-fn {:port port
:ratio pixel-ratio/ratio
:key-uid target-key-uid
:theme (theme/get-theme)
:override-ring? override-ring?
:font-file font-file}))}))))
(image-server/get-initials-avatar-uri-fn
{:port port
:ratio pixel-ratio/ratio
:key-uid target-key-uid
:theme (theme/get-theme)
:uppercase-ratio (:uppercase-ratio constants/initials-avatar-font-conf)
:override-ring? override-ring?
:font-file font-file}))}))))
(re-frame/reg-sub
:multiaccount/public-key
@@ -104,7 +106,6 @@
(fn [profile]
(:test-networks-enabled? profile)))
(re-frame/reg-sub
:multiaccount/contact
:<- [:profile/profile]
+1 -2
View File
@@ -145,7 +145,7 @@
(reg-root-key-sub :communities/collapsed-categories :communities/collapsed-categories)
(reg-root-key-sub :communities/selected-tab :communities/selected-tab)
(reg-root-key-sub :contract-communities :contract-communities)
(reg-root-key-sub :communities/addresses-for-permissions :communities/addresses-for-permissions)
(reg-root-key-sub :communities/selected-permission-addresses :communities/selected-permission-addresses)
;;activity center
(reg-root-key-sub :activity-center :activity-center)
@@ -154,7 +154,6 @@
(reg-root-key-sub :wallet :wallet)
(reg-root-key-sub :wallet/scanned-address :wallet/scanned-address)
(reg-root-key-sub :wallet/create-account :wallet/create-account)
(reg-root-key-sub :wallet/networks :wallet/networks)
(reg-root-key-sub :wallet/local-suggestions :wallet/local-suggestions)
(reg-root-key-sub :wallet/valid-ens-or-address? :wallet/valid-ens-or-address?)
+49 -11
View File
@@ -10,15 +10,17 @@
animation-url
image-url))
(defn add-collectibles-preview-url
[collectibles]
(map (fn [{:keys [collectible-data] :as collectible}]
(assoc collectible :preview-url (preview-url collectible-data)))
collectibles))
(re-frame/reg-sub
:wallet/collectibles-per-account
:<- [:wallet]
(fn [wallet [_ address]]
(as-> wallet $
(get-in $ [:accounts address :collectibles])
(map (fn [{:keys [collectible-data] :as collectible}]
(assoc collectible :preview-url (preview-url collectible-data)))
$))))
:wallet/current-viewing-account-collectibles
:<- [:wallet/current-viewing-account]
(fn [current-account]
(-> current-account :collectibles add-collectibles-preview-url)))
(re-frame/reg-sub
:wallet/all-collectibles
@@ -27,8 +29,7 @@
(->> wallet
:accounts
(mapcat (comp :collectibles val))
(map (fn [{:keys [collectible-data] :as collectible}]
(assoc collectible :preview-url (preview-url collectible-data)))))))
(add-collectibles-preview-url))))
(re-frame/reg-sub
:wallet/last-collectible-details
@@ -38,7 +39,44 @@
(assoc last-collectible :preview-url (preview-url (:collectible-data last-collectible))))))
(re-frame/reg-sub
:wallet/last-collectible-chain-id
:wallet/last-collectible-details-chain-id
:<- [:wallet/last-collectible-details]
(fn [collectible]
(get-in collectible [:id :contract-id :chain-id])))
(re-frame/reg-sub
:wallet/current-viewing-account-collectibles-filtered
:<- [:wallet/current-viewing-account-collectibles]
(fn [current-account-collectibles [_ search-text]]
(let [search-text-lower-case (string/lower-case search-text)]
(filter (fn [{{collection-name :name} :collection-data
{collectible-name :name} :collectible-data}]
(or (string/includes? (string/lower-case collection-name) search-text-lower-case)
(string/includes? (string/lower-case collectible-name) search-text-lower-case)))
current-account-collectibles))))
(re-frame/reg-sub
:wallet/last-collectible-details-traits
:<- [:wallet/last-collectible-details]
(fn [collectible]
(get-in collectible [:collectible-data :traits])))
(re-frame/reg-sub
:wallet/last-collectible-details-owner
:<- [:wallet/last-collectible-details]
:<- [:wallet]
(fn [[collectible wallet]]
(let [address (:address (first (:ownership collectible)))
account (get-in wallet [:accounts address])]
account)))
(re-frame/reg-sub
:wallet/current-viewing-account-collectibles-filtered
:<- [:wallet/current-viewing-account-collectibles]
(fn [current-account-collectibles [_ search-text]]
(let [search-text-lower-case (string/lower-case search-text)]
(filter (fn [{{collection-name :name} :collection-data
{collectible-name :name} :collectible-data}]
(or (string/includes? (string/lower-case collection-name) search-text-lower-case)
(string/includes? (string/lower-case collectible-name) search-text-lower-case)))
current-account-collectibles))))
@@ -0,0 +1,50 @@
(ns status-im.subs.wallet.collectibles-test
(:require
[cljs.test :refer [is testing]]
[re-frame.db :as rf-db]
status-im.subs.root
status-im.subs.wallet.collectibles
[test-helpers.unit :as h]
[utils.re-frame :as rf]))
(def ^:private traits
[{:trait-type "Background"
:value "Gradient 5"
:display-type ""
:max-value ""}
{:trait-type "Skin"
:value "Pale"
:display-type ""
:max-value ""}
{:trait-type "Clothes"
:value "Naked"
:display-type ""
:max-value ""}])
(def ^:private collectible-owner-wallet
{:last-collectible-details {:ownership [{:address "0x1"}]}
:accounts {"0x1" {:name "account 1"
:color "army"}}})
(h/deftest-sub :wallet/last-collectible-details-chain-id
[sub-name]
(testing "correct chain-id of the last collectible should be returned"
(swap! rf-db/app-db assoc-in [:wallet :last-collectible-details :id :contract-id :chain-id] "1")
(let [result (rf/sub [sub-name])]
(is (= "1" result)))))
(h/deftest-sub :wallet/last-collectible-details-traits
[sub-name]
(testing "correct traits of the last collectible should be returned"
(swap! rf-db/app-db assoc-in [:wallet :last-collectible-details :collectible-data :traits] traits)
(let [result (rf/sub [sub-name])]
(is (= traits result)))))
(h/deftest-sub :wallet/last-collectible-details-owner
[sub-name]
(testing "correct owner of the last collectible should be returned"
(swap! rf-db/app-db assoc-in [:wallet] collectible-owner-wallet)
(let [result (rf/sub [sub-name])]
(is (= {:name "account 1"
:color "army"}
result)))))
+10 -4
View File
@@ -4,10 +4,16 @@
[status-im.constants :as constants]))
(re-frame/reg-sub
:wallet/filtered-networks-by-mode
:wallet/networks
:<- [:wallet]
:-> :networks)
(re-frame/reg-sub
:wallet/networks-by-mode
:<- [:wallet/networks]
(fn [networks [_ test?]]
(get networks (if test? :test :prod))))
:<- [:profile/test-networks-enabled?]
(fn [[networks test-networks-enabled?]]
(get networks (if test-networks-enabled? :test :prod))))
(def mainnet-network-details
{:source (resources/get-network constants/mainnet-network-name)
@@ -32,7 +38,7 @@
(re-frame/reg-sub
:wallet/network-details
:<- [:wallet/filtered-networks-by-mode false]
:<- [:wallet/networks-by-mode]
(fn [networks]
(->> networks
(keep
+1 -1
View File
@@ -37,7 +37,7 @@
(h/deftest-sub :wallet/network-details
[sub-name]
(testing "returns data with prod"
(swap! rf-db/app-db assoc :wallet/networks network-data)
(swap! rf-db/app-db assoc-in [:wallet :networks] network-data)
(is (= [{:network-name :ethereum
:short-name "eth"
:chain-id 1
+16 -13
View File
@@ -63,6 +63,11 @@
:<- [:wallet/wallet-send]
:-> :loading-suggested-routes?)
(rf/reg-sub
:wallet/wallet-send-suggested-routes
:<- [:wallet/wallet-send]
:-> :suggested-routes)
(rf/reg-sub
:wallet/watch-address-activity-state
:<- [:wallet/ui]
@@ -72,15 +77,13 @@
:wallet/accounts
:<- [:wallet]
:<- [:wallet/network-details]
(fn [[wallet network-details]]
;; TODO(@rende11): `testnet?` value would be relevant after this implementation,
;; https://github.com/status-im/status-mobile/issues/17826
(let [testnet? false]
(->> wallet
:accounts
vals
(map #(assoc-network-preferences-names network-details % testnet?))
(sort-by :position)))))
:<- [:profile/test-networks-enabled?]
(fn [[wallet network-details test-networks-enabled?]]
(->> wallet
:accounts
vals
(map #(assoc-network-preferences-names network-details % test-networks-enabled?))
(sort-by :position))))
(rf/reg-sub
:wallet/addresses
@@ -121,10 +124,10 @@
:<- [:wallet/balances]
:<- [:profile/currency-symbol]
(fn [[accounts current-viewing-account-address balances currency-symbol]]
(let [current-viewing-account (utils/get-account-by-address accounts current-viewing-account-address)
balance (get balances current-viewing-account-address)
formatted-balance (utils/prettify-balance currency-symbol balance)]
(-> current-viewing-account
(let [balance (get balances current-viewing-account-address)
formatted-balance (utils/prettify-balance currency-symbol balance)]
(-> accounts
(utils/get-account-by-address current-viewing-account-address)
(assoc :balance balance
:formatted-balance formatted-balance)))))
+5 -5
View File
@@ -167,7 +167,7 @@
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc :wallet/networks network-data)))
(assoc-in [:wallet :networks] network-data)))
(is
(=
(list {:path "m/44'/60'/0'/0/0"
@@ -252,7 +252,7 @@
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :current-viewing-account-address] "0x1")
(assoc :wallet/networks network-data)))
(assoc-in [:wallet :networks] network-data)))
(let [result (rf/sub [sub-name])]
(is
@@ -310,7 +310,7 @@
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :current-viewing-account-address] "0x2")
(assoc :wallet/networks network-data)))
(assoc-in [:wallet :networks] network-data)))
(is
(= (list
{:path "m/44'/60'/0'/0/0"
@@ -365,7 +365,7 @@
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc :wallet/networks network-data)))
(assoc-in [:wallet :networks] network-data)))
(is
(= (list
{:path "m/44'/60'/0'/0/0"
@@ -421,7 +421,7 @@
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :current-viewing-account-address] "0x1")
(assoc :wallet/networks network-data)))
(assoc-in [:wallet :networks] network-data)))
(is
(match? [{:short-name "eth"
:network-name :ethereum
+14
View File
@@ -2,6 +2,7 @@
(:require
[react-native.fs :as utils.fs]
[react-native.platform :as platform]
[schema.core :as schema]
[utils.datetime :as datetime]))
(def ^:const image-server-uri-prefix "https://localhost:")
@@ -182,6 +183,19 @@
"&ringWidth="
(* ring-width ratio)))
(schema/=> get-initials-avatar-uri
[:=>
[:cat
[:map
[:color string?]
[:background-color string?]
[:size number?]
[:ratio float?]
[:uppercase-ratio number?]
[:font-size number?]
[:font-file string?]]]
[:string]])
(defn get-initials-avatar-uri-fn
"return a fn that calls `get-account-initials-uri`
pass the fn to user-avatar component to fill the style related options
+2 -2
View File
@@ -42,9 +42,9 @@
:color "#0E162000"
:font-size 12
:font-file "/font/Inter Medium.otf"
:uppercase-ratio "uppercase-ratio"
:uppercase-ratio 0.6
:indicator-size 2
:indicator-center-to-edge 6
:indicator-color "#0E1620"
:ring-width 4})
"https://localhost:port/accountInitials?publicKey=public-key&keyUid=key-uid&length=length&size=96&bgColor=background-color&color=%230E162000&fontSize=24&fontFile=%2Ffont%2FInter%20Medium.otf&uppercaseRatio=uppercase-ratio&theme=:light&clock=&name=full-nametimestamp&indicatorColor=%230E1620&indicatorSize=4&indicatorBorder=0&indicatorCenterToEdge=12&addRing=1&ringWidth=8"))))
"https://localhost:port/accountInitials?publicKey=public-key&keyUid=key-uid&length=length&size=96&bgColor=background-color&color=%230E162000&fontSize=24&fontFile=%2Ffont%2FInter%20Medium.otf&uppercaseRatio=0.6&theme=:light&clock=&name=full-nametimestamp&indicatorColor=%230E1620&indicatorSize=4&indicatorBorder=0&indicatorCenterToEdge=12&addRing=1&ringWidth=8"))))
+16 -2
View File
@@ -23,9 +23,10 @@
[props]
(.interpolateNavigationViewOpacity ^js messages-worklets (clj->js props)))
;;;; Messages List
(defn messages-list-on-scroll
[distance-from-list-top callback]
(.messagesListOnScroll ^js messages-worklets distance-from-list-top callback))
[distance-from-list-top chat-list-scroll-y callback]
(.messagesListOnScroll ^js messages-worklets distance-from-list-top chat-list-scroll-y callback))
;;;; Placeholder
(defn placeholder-opacity
@@ -35,3 +36,16 @@
(defn placeholder-z-index
[calculations-complete?]
(.placeholderZIndex ^js messages-worklets calculations-complete?))
;;;; Common
(defn scroll-down-button-opacity
[chat-list-scroll-y composer-focused? window-height]
(.scrollDownButtonOpacity ^js messages-worklets chat-list-scroll-y composer-focused? window-height))
(defn jump-to-button-opacity
[scroll-down-button-opacity-sv composer-focused?]
(.jumpToButtonOpacity ^js messages-worklets scroll-down-button-opacity-sv composer-focused?))
(defn jump-to-button-position
[scroll-down-button-opacity-sv composer-focused?]
(.jumpToButtonPosition ^js messages-worklets scroll-down-button-opacity-sv composer-focused?))
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.171.39",
"commit-sha1": "debfe1cab368140b16d2383efc68007d3c28a4ef",
"src-sha256": "0cbj3796qz69ylwcvdw5jsl1cdyrcfk81d7shjkakvjh59rv5sjk"
"version": "v0.172.2",
"commit-sha1": "5cb1972261de90fee1469ae60ffb7f25900a9850",
"src-sha256": "1z37yinlxwpzprd10h2f4vzs5k2a1k85ks9lvl067lb4rqflcwny"
}
+1 -1
View File
@@ -196,7 +196,7 @@ def _upload_and_check_response_with_retries(apk_file_path, retries=3):
try:
_upload_and_check_response(apk_file_path)
break
except (ConnectionError, RemoteDisconnected):
except (ConnectionError, RemoteDisconnected, c_er):
time.sleep(10)
@@ -655,6 +655,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
self.home_2.navigate_back_to_home_view()
self.home_2.chats_tab.click()
self.home_2.get_chat(self.username_1).click()
self.chat_2.chat_message_input.wait_for_visibility_of_element()
self.home_2.just_fyi("Getting chat history")
chat_history = list()
for element in self.chat_2.chat_element_by_text(text='').message_text_content.find_elements():
@@ -5,7 +5,7 @@ import emoji
import pytest
from _pytest.outcomes import Failed
from appium.webdriver.connectiontype import ConnectionType
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.common.exceptions import NoSuchElementException, TimeoutException, StaleElementReferenceException
from tests import marks, run_in_parallel, pytest_config_global, transl
from tests.base_test_case import create_shared_drivers, MultipleSharedDeviceTestCase
@@ -108,7 +108,10 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
message_to_delete = "message to delete and undo"
self.channel.send_message(message_to_delete)
self.channel.delete_message_in_chat(message_to_delete)
self.channel.element_by_text("Undo").click()
try:
self.channel.element_by_text("Undo").click()
except StaleElementReferenceException:
pytest.fail("Can't press Undo button, not enough time")
try:
self.channel.chat_element_by_text(message_to_delete).wait_for_visibility_of_element()
except TimeoutException:
+7 -2
View File
@@ -139,7 +139,7 @@
"change-log-level": "Confirm and restart the app to change log level to {{log-level}}",
"change-logging-enabled": "Are you sure you want to {{enable}} logging?",
"change-passcode": "Change Passcode",
"change-password": "Change Password",
"change-password": "Change password",
"change-pin": "Change 6-digit passcode",
"change-puk": "Change 12-digit PUK",
"change-pairing": "Change pairing code",
@@ -1793,6 +1793,8 @@
"community-info-not-found": "Community information not found",
"community-info": "Community info",
"not-found": "Not found",
"nothing-found": "Nothing found",
"try-to-search-something-else": "Try to search something else",
"activity": "Activity",
"reject-and-delete": "Reject and delete",
"accept-and-add": "Accept and add",
@@ -2449,6 +2451,8 @@
"copy-all-details": "Copy all details",
"share-details": "Share details",
"what-are-you-waiting-for": "What are you waiting for?",
"no-relevant-tokens": "No relevant tokens",
"on-the-web": "On the web",
"sending-with-elipsis": "Sending...",
"transaction-confirmed": "Transaction confirmed!",
"transacation-finalised": "Transaction finalised!",
@@ -2457,5 +2461,6 @@
"to-label": "To",
"oops-wrong-word": "Oops! Wrong word",
"time-in-mins": "{{minutes}} min",
"amount-with-currency-symbol": "{{symbol}} {{amount}}"
"amount-with-currency-symbol": "{{symbol}} {{amount}}",
"no-routes-found": "No routes found"
}