Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e8db12b64 | ||
|
|
8a3e53690c | ||
|
|
ecd7147113 | ||
|
|
f87fbf8b1a | ||
|
|
1fde6476f4 | ||
|
|
312ad42fa6 | ||
|
|
f254c312d4 | ||
|
|
7103a26f16 | ||
|
|
4574df2f8a | ||
|
|
591047de2a | ||
|
|
6fc8d08733 | ||
|
|
5af5e57795 | ||
|
|
7efa0d1ae8 | ||
|
|
bce33b2138 | ||
|
|
60bd74c234 | ||
|
|
794152d99c | ||
|
|
00124db899 | ||
|
|
3331a31e2d | ||
|
|
278af1c51f | ||
|
|
829f26cc1e | ||
|
|
30dc7518bd | ||
|
|
9cec67059a | ||
|
|
25e40df72d | ||
|
|
8ac44f9ae5 | ||
|
|
073d486aed | ||
|
|
c1ff618cde |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' : ''
|
||||
}
|
||||
|
||||
-44
@@ -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);
|
||||
}
|
||||
}
|
||||
+47
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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})))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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}))))
|
||||
|
||||
@@ -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)]]]))
|
||||
|
||||
@@ -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!"))]]))))
|
||||
@@ -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]}
|
||||
|
||||
@@ -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}]]))))
|
||||
|
||||
@@ -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])]))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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")}]})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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?)
|
||||
|
||||
|
||||
@@ -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)))))
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))))
|
||||
|
||||
@@ -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,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"
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user