mirror of
https://github.com/status-im/status-mobile.git
synced 2025-02-20 12:28:31 +00:00
Update release branch 2.30.x (#20903)
Revisions from develop: - 59ceddbaa develop origin/develop fix(wallet): fix bridge transactions (#20902) - 99ccbc338 Cover wallet send events with tests Part 2 #20411 #20533 (#20721) - 8c2d5398b Enabling WalletConnect feature flag (#20906) - 67c83b13e fix(wallet): remove edit routes button in bridging (#20874) - 11a84ba14 feat(wallet): disable complex routing (#20901) - 1f5bb579c chore(wallet): disable bridging on unsupported tokens (#20846) - 4586f8007 Add toggle in advanced settings for mobile data - 55c620e59 fix: create password for small screen (#20645) - 525609f0a Wallet Activity: transactions are not sorted by time #20808 (#20862) - 90653955a chore(settings): Disable telemetry option (#20881) - d27ab756d fix_:display group message using the new ui (#20787) - c6a1db633 ci: enable split apks & build only for arm64-v8a (#20683) - 73777e052 Ensure keycard account can send transaction after upgrading from v1 to v2 #20552 (#20845) - a6d3fc374 [#20524] fix: the missed keypairs are shown in the key pair list screen (#20888) - a671c7083 fix broken screen and navigation when syncing fails (#20887) - a45991b6d 🥅 Filter connected dapps based on testnet mode, reject proposals and requests gracefully (#20799) - 2e9fa22e4 feat: wallet router v2 (#20631) - 737d8c4d5 rename sub to fix error when requesting to join community (#20868) - 3aa7e103f Sync process is blocked on Enabled notifications screen (#20883) - c1d2d44da perf: Fix app freeze after login (#20729) - 0fed8113d e2e: updated testnet switching and added one test into smoke - 53c35cb55 fix(wallet): Linear gradient exception on invalid colors for watched account cards (#20854) - be8236554 chore(settings)_: Remove testnet toggle from legacy advanced settings (#20875) - eae8a6559 feat(wallet)_: Add beta info box in activity tab (#20873) - fe54a25a3 fix: not clearing network & web3-wallet on logout (#20886) - 15a4219ef Reject wallet-connect request by dragging the modal down (#20763) (#20836) - 2ffbdac89 WalletConnect show expired toast (#20857) - 402eb8397 fix Issue with scrolling WalletConnect transaction on Android (#20867) - ff88049a0 Fix WalletConnect header alignment on Android (#20860) - cee21241d WalletConnect no internet edge-cases (#20826) - 60ad7c8a2 chore(tests): New match-strict? cljs.test directive (#20825) - 4989c9278 fix_: Adding own address as saved addresses (#20839)
This commit is contained in:
parent
a1784c5e1f
commit
0f15c0192d
@ -74,7 +74,8 @@
|
||||
;; https://github.com/borkdude/clj-kondo/issues/867
|
||||
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
|
||||
number
|
||||
legacy.status-im.test-helpers/restore-app-db]}
|
||||
legacy.status-im.test-helpers/restore-app-db
|
||||
(cljs.test/is [match-strict?])]}
|
||||
:unresolved-var {:level :error}
|
||||
:unsorted-required-namespaces {:level :error}
|
||||
:unused-alias {:level :warning}
|
||||
|
1
.env
1
.env
@ -35,3 +35,4 @@ FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=0
|
||||
ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
|
2
.env.e2e
2
.env.e2e
@ -38,3 +38,5 @@ SHOW_NOT_IMPLEMENTED_FEATURES=1
|
||||
DELETE_MESSAGE_FOR_ME_UNDO_TIME_LIMIT=10000
|
||||
DELETE_MESSAGE_UNDO_TIME_LIMIT=10000
|
||||
ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
MOBILE_DATA_SYNCING_TOGGLE_ENABLE=0
|
||||
|
@ -36,3 +36,4 @@ LOCAL_PAIRING_ENABLED=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
|
@ -23,3 +23,4 @@ DELETE_MESSAGE_ENABLED=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=0
|
||||
TEST_NETWORKS_ENABLED=0
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
|
@ -19,3 +19,4 @@ MAX_IMAGES_BATCH=1
|
||||
DELETE_MESSAGE_ENABLED=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=0
|
||||
TEST_NETWORKS_ENABLED=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
|
4
Makefile
4
Makefile
@ -215,15 +215,13 @@ build-fdroid: ##@build Build release for F-Droid
|
||||
build-android: export BUILD_ENV ?= prod
|
||||
build-android: export BUILD_TYPE ?= nightly
|
||||
build-android: export ORG_GRADLE_PROJECT_versionCode ?= $(TMP_BUILD_NUMBER)
|
||||
build-android: export ANDROID_ABI_SPLIT ?= false
|
||||
build-android: export ANDROID_ABI_INCLUDE ?= armeabi-v7a;arm64-v8a;x86
|
||||
build-android: ##@build Build unsigned Android APK
|
||||
@scripts/build-android.sh
|
||||
|
||||
release-android: export TARGET := keytool
|
||||
release-android: export KEYSTORE_PATH ?= $(HOME)/.gradle/status-im.keystore
|
||||
release-android: keystore build-android ##@build Build signed Android APK
|
||||
@scripts/sign-android.sh result/app-release-unsigned.apk
|
||||
@scripts/sign-android.sh result/app-arm64-v8a-release-unsigned.apk
|
||||
|
||||
release-ios: export TARGET := ios
|
||||
release-ios: export IOS_STATUS_GO_TARGETS := ios/arm64
|
||||
|
@ -211,7 +211,7 @@ android {
|
||||
reset()
|
||||
enable getEnvOrConfig('ANDROID_ABI_SPLIT').toBoolean()
|
||||
include getEnvOrConfig('ANDROID_ABI_INCLUDE').split(";")
|
||||
universalApk true
|
||||
universalApk false
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
@ -38,10 +38,10 @@ KEYSTORE_PASSWORD=password
|
||||
KEYSTORE_ALIAS=status
|
||||
KEYSTORE_KEY_PASSWORD=password
|
||||
|
||||
# By default we build a mostly universal APK
|
||||
ANDROID_ABI_SPLIT=false
|
||||
# Some platforms are excluded though
|
||||
ANDROID_ABI_INCLUDE=armeabi-v7a;arm64-v8a;x86;x86_64
|
||||
# Splitting by CPU Architecture produces smaller APKs.
|
||||
ANDROID_ABI_SPLIT=true
|
||||
# By default its better to only build apk for most recent devices.
|
||||
ANDROID_ABI_INCLUDE=arm64-v8a
|
||||
|
||||
org.gradle.jvmargs=-Xmx8704M -XX:+UseParallelGC
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@ -72,11 +72,7 @@ pipeline {
|
||||
stage('Upload') {
|
||||
steps { script {
|
||||
def urls = apks.collect { s5cmd.upload(it) }
|
||||
if (urls.size() > 1) { /* Return only the universal APK. */
|
||||
env.PKG_URL = urls.find { it.contains('universal') }
|
||||
} else { /* If no universal is available pick first. */
|
||||
env.PKG_URL = urls.first()
|
||||
}
|
||||
env.PKG_URL = urls.first()
|
||||
jenkins.setBuildDesc(APK: env.PKG_URL)
|
||||
} }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.1'
|
||||
library 'status-jenkins-lib@v1.9.3'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
|
@ -711,11 +711,11 @@
|
||||
},
|
||||
|
||||
{
|
||||
"path": "nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8",
|
||||
"path": "nubank/matcher-combinators/3.9.1/matcher-combinators-3.9.1",
|
||||
"host": "https://repo.clojars.org",
|
||||
"jar": {
|
||||
"sha1": "4c94bd510f0c18a20191e46dd6becedebc640bbd",
|
||||
"sha256": "0wpla2hx0s4mda58ndyd8938zmnz1gyhgfr6pzfphy27xfbvsssl"
|
||||
"sha1": "f0830a112cae8ee931a90d9f39214a0ed4d44150",
|
||||
"sha256": "1rjcgqhms84xmnhs7sqcd3b2dpa37mmzgz2yz33yz2rdb9skl96g"
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -77,7 +77,7 @@ net/cgrand/macrovich/0.2.1/macrovich-0.2.1.jar
|
||||
net/java/dev/jna/jna/5.12.1/jna-5.12.1.jar
|
||||
nrepl/bencode/1.1.0/bencode-1.1.0.jar
|
||||
nrepl/nrepl/1.0.0/nrepl-1.0.0.jar
|
||||
nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8.jar
|
||||
nubank/matcher-combinators/3.9.1/matcher-combinators-3.9.1.jar
|
||||
org/apache/ant/ant/1.10.11/ant-1.10.11.jar
|
||||
org/apache/ant/ant-launcher/1.10.11/ant-launcher-1.10.11.jar
|
||||
org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar
|
||||
|
@ -18,10 +18,10 @@
|
||||
buildUrl ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_buildUrl" null,
|
||||
statusGoSrcOverride ? lib.getEnvWithDefault "STATUS_GO_SRC_OVERRIDE" null,
|
||||
# If APKs should be split based on architectures
|
||||
androidAbiSplit ? lib.getEnvWithDefault "ANDROID_ABI_SPLIT" "false",
|
||||
androidAbiSplit ? lib.getEnvWithDefault "ANDROID_ABI_SPLIT" "true",
|
||||
# Android architectures to build for
|
||||
# Used to detect end-to-end builds
|
||||
androidAbiInclude ? lib.getEnvWithDefault "ANDROID_ABI_INCLUDE" "armeabi-v7a;arm64-v8a;x86",
|
||||
androidAbiInclude ? lib.getEnvWithDefault "ANDROID_ABI_INCLUDE" "arm64-v8a",
|
||||
}:
|
||||
|
||||
let
|
||||
|
BIN
resources/images/ui2/syncing_devices@2x.png
Normal file
BIN
resources/images/ui2/syncing_devices@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 424 KiB |
BIN
resources/images/ui2/syncing_devices@3x.png
Normal file
BIN
resources/images/ui2/syncing_devices@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 752 KiB |
BIN
resources/images/ui2/syncing_wrong@2x.png
Normal file
BIN
resources/images/ui2/syncing_wrong@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 547 KiB |
BIN
resources/images/ui2/syncing_wrong@3x.png
Normal file
BIN
resources/images/ui2/syncing_wrong@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
@ -13,7 +13,7 @@ export BUILD_TYPE=debug
|
||||
|
||||
# Install the APK on running emulator or android device.
|
||||
installAndLaunchApp() {
|
||||
adb install -r ./result/app-debug.apk > "${ADB_INSTALL_LOG_FILE}" 2>&1
|
||||
adb install -r ./result/app-arm64-v8a-debug.apk > "${ADB_INSTALL_LOG_FILE}" 2>&1
|
||||
"${GIT_ROOT}/scripts/wait-for-metro-port.sh" 2>&1
|
||||
# connected android devices need this port to be exposed for metro
|
||||
adb reverse "tcp:${RCT_METRO_PORT}" "tcp:${RCT_METRO_PORT}"
|
||||
|
@ -19,7 +19,7 @@
|
||||
[cider/piggieback "0.4.1"]
|
||||
[org.slf4j/slf4j-nop "2.0.9"]
|
||||
[re-frisk-remote "1.6.0"]
|
||||
[nubank/matcher-combinators "3.8.8"]
|
||||
[nubank/matcher-combinators "3.9.1"]
|
||||
|
||||
;; Use the same version specified in the Nix dependency.
|
||||
[clj-kondo/clj-kondo "2024.03.13"]
|
||||
|
@ -1,8 +1,8 @@
|
||||
(ns legacy.status-im.data-store.communities
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[clojure.walk :as walk]
|
||||
[status-im.constants :as constants]))
|
||||
[status-im.constants :as constants]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn <-revealed-accounts-rpc
|
||||
[accounts]
|
||||
@ -22,19 +22,26 @@
|
||||
(reduce #(assoc %1 (key-fn %2) (<-request-to-join-community-rpc %2)) {} requests))
|
||||
|
||||
(defn <-chats-rpc
|
||||
[chats]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc
|
||||
(name k)
|
||||
(-> v
|
||||
(assoc :token-gated? (:tokenGated v)
|
||||
:can-post? (:canPost v)
|
||||
:can-view? (:canView v)
|
||||
:hide-if-permissions-not-met? (:hideIfPermissionsNotMet v))
|
||||
(dissoc :canPost :tokenGated :canView :hideIfPermissionsNotMet)
|
||||
(update :members walk/stringify-keys))))
|
||||
{}
|
||||
chats))
|
||||
"This transformation from RPC is optimized differently because there can be
|
||||
thousands of members in all chats and we don't want to transform them from JS
|
||||
to CLJS because they will only be used to list community members or community
|
||||
chat members."
|
||||
[chats-js]
|
||||
(let [chat-key-fn (fn [k]
|
||||
(case k
|
||||
"tokenGated" :token-gated?
|
||||
"canPost" :can-post?
|
||||
"can-view" :can-view?
|
||||
"hideIfPermissionsNotMet" :hide-if-permissions-not-met?
|
||||
(keyword k)))
|
||||
chat-val-fn (fn [k v]
|
||||
(if (= "members" k)
|
||||
v
|
||||
(transforms/js->clj v)))]
|
||||
(transforms/<-js-map
|
||||
chats-js
|
||||
{:val-fn (fn [_ v]
|
||||
(transforms/<-js-map v {:key-fn chat-key-fn :val-fn chat-val-fn}))})))
|
||||
|
||||
(defn <-categories-rpc
|
||||
[categ]
|
||||
@ -48,49 +55,59 @@
|
||||
[token-permission]
|
||||
(= (:type token-permission) constants/community-token-permission-become-member))
|
||||
|
||||
(defn- rename-community-key
|
||||
[k]
|
||||
(case k
|
||||
"canRequestAccess" :can-request-access?
|
||||
"canManageUsers" :can-manage-users?
|
||||
"canDeleteMessageForEveryone" :can-delete-message-for-everyone?
|
||||
;; This flag is misleading based on its name alone
|
||||
;; because it should not be used to decide if the user
|
||||
;; is *allowed* to join. Allowance is based on token
|
||||
;; permissions. Still, the flag can be used to know
|
||||
;; whether or not the user will have to wait until an
|
||||
;; admin approves a join request.
|
||||
"canJoin" :can-join?
|
||||
"requestedToJoinAt" :requested-to-join-at
|
||||
"isMember" :is-member?
|
||||
"outroMessage" :outro-message
|
||||
"adminSettings" :admin-settings
|
||||
"tokenPermissions" :token-permissions
|
||||
"communityTokensMetadata" :tokens-metadata
|
||||
"introMessage" :intro-message
|
||||
"muteTill" :muted-till
|
||||
"lastOpenedAt" :last-opened-at
|
||||
"joinedAt" :joined-at
|
||||
(keyword k)))
|
||||
|
||||
(defn <-rpc
|
||||
[c]
|
||||
(-> c
|
||||
(set/rename-keys
|
||||
{:canRequestAccess :can-request-access?
|
||||
:canManageUsers :can-manage-users?
|
||||
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
|
||||
;; This flag is misleading based on its name alone
|
||||
;; because it should not be used to decide if the user
|
||||
;; is *allowed* to join. Allowance is based on token
|
||||
;; permissions. Still, the flag can be used to know
|
||||
;; whether or not the user will have to wait until an
|
||||
;; admin approves a join request.
|
||||
:canJoin :can-join?
|
||||
:requestedToJoinAt :requested-to-join-at
|
||||
:isMember :is-member?
|
||||
:outroMessage :outro-message
|
||||
:adminSettings :admin-settings
|
||||
:tokenPermissions :token-permissions
|
||||
:communityTokensMetadata :tokens-metadata
|
||||
:introMessage :intro-message
|
||||
:muteTill :muted-till
|
||||
:lastOpenedAt :last-opened-at
|
||||
:joinedAt :joined-at})
|
||||
(update :admin-settings
|
||||
set/rename-keys
|
||||
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
|
||||
(update :members walk/stringify-keys)
|
||||
(update :chats <-chats-rpc)
|
||||
(update :token-permissions seq)
|
||||
(update :categories <-categories-rpc)
|
||||
(assoc :role-permissions?
|
||||
(->> c
|
||||
:tokenPermissions
|
||||
vals
|
||||
(some role-permission?)))
|
||||
(assoc :membership-permissions?
|
||||
(->> c
|
||||
:tokenPermissions
|
||||
vals
|
||||
(some membership-permission?)))
|
||||
(assoc :token-images
|
||||
(reduce (fn [acc {sym :symbol image :image}]
|
||||
(assoc acc sym image))
|
||||
{}
|
||||
(:communityTokensMetadata c)))))
|
||||
[c-js]
|
||||
(let [community (transforms/<-js-map
|
||||
c-js
|
||||
{:key-fn rename-community-key
|
||||
:val-fn (fn [k v]
|
||||
(case k
|
||||
"members" v
|
||||
"chats" (<-chats-rpc v)
|
||||
(transforms/js->clj v)))})]
|
||||
(-> community
|
||||
(update :admin-settings
|
||||
set/rename-keys
|
||||
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
|
||||
(update :token-permissions seq)
|
||||
(update :categories <-categories-rpc)
|
||||
(assoc :role-permissions?
|
||||
(->> community
|
||||
:tokenPermissions
|
||||
vals
|
||||
(some role-permission?)))
|
||||
(assoc :membership-permissions?
|
||||
(->> community
|
||||
:tokenPermissions
|
||||
vals
|
||||
(some membership-permission?)))
|
||||
(assoc :token-images
|
||||
(reduce (fn [acc {sym :symbol image :image}]
|
||||
(assoc acc sym image))
|
||||
{}
|
||||
(:communityTokensMetadata community))))))
|
||||
|
@ -11,14 +11,10 @@
|
||||
legacy.status-im.fleet.core
|
||||
legacy.status-im.group-chats.core
|
||||
legacy.status-im.log-level.core
|
||||
legacy.status-im.mailserver.constants
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
legacy.status-im.mobile-sync-settings.core
|
||||
legacy.status-im.multiaccounts.login.core
|
||||
legacy.status-im.multiaccounts.logout.core
|
||||
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
|
||||
legacy.status-im.multiaccounts.update.core
|
||||
legacy.status-im.network.net-info
|
||||
legacy.status-im.pairing.core
|
||||
legacy.status-im.profile.core
|
||||
legacy.status-im.search.core
|
||||
@ -135,7 +131,6 @@
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :app-in-background-since)
|
||||
:effects.biometric/get-supported-type nil}
|
||||
(mailserver/process-next-messages-request)
|
||||
(when-not new-account?
|
||||
(universal-links/process-stored-event))
|
||||
#(when-let [chat-id (:current-chat-id db)]
|
||||
|
@ -1,437 +0,0 @@
|
||||
(ns ^{:doc "Mailserver events and API"} legacy.status-im.mailserver.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.node.core :as node]
|
||||
[legacy.status-im.utils.mobile-sync :as mobile-network-utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
;; How do mailserver work ?
|
||||
;;
|
||||
;; - We send a request to the mailserver, we are only interested in the
|
||||
;; messages since `last-request` up to the last seven days
|
||||
;; and the last 24 hours for topics that were just joined
|
||||
;; - The mailserver doesn't directly respond to the request and
|
||||
;; instead we start receiving messages in the filters for the requested
|
||||
;; topics.
|
||||
;; - If the mailserver was not ready when we tried for instance to request
|
||||
;; the history of a topic after joining a chat, the request will be done
|
||||
;; as soon as the mailserver becomes available
|
||||
|
||||
|
||||
(defn connected?
|
||||
[db id]
|
||||
(= (:mailserver/current-id db) id))
|
||||
|
||||
(defn fetch
|
||||
[db id]
|
||||
(get-in db [:mailserver/mailservers (node/current-fleet-key db) id]))
|
||||
|
||||
(defn fetch-current
|
||||
[db]
|
||||
(fetch db (:mailserver/current-id db)))
|
||||
|
||||
(defn preferred-mailserver-id
|
||||
[db]
|
||||
(get-in db [:profile/profile :pinned-mailservers (node/current-fleet-key db)]))
|
||||
|
||||
(defn connection-error-dismissed
|
||||
[db]
|
||||
(get-in db [:mailserver/connection-error-dismissed]))
|
||||
|
||||
(defn mailserver-address->id
|
||||
[db address]
|
||||
(let [current-fleet (node/current-fleet-key db)]
|
||||
(:id (some #(when (= address (:address %))
|
||||
%)
|
||||
(-> db
|
||||
:mailserver/mailservers
|
||||
current-fleet
|
||||
vals)))))
|
||||
|
||||
(rf/defn disconnect-from-mailserver
|
||||
{:events [::disconnect-from-mailserver]}
|
||||
[{:keys [db] :as cofx}]
|
||||
{:db (-> db
|
||||
(assoc :mailserver/state nil)
|
||||
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
|
||||
|
||||
(defn fetch-use-mailservers?
|
||||
[db]
|
||||
(get-in db [:profile/profile :use-mailservers?]))
|
||||
|
||||
(defonce showing-connection-error-popup? (atom false))
|
||||
|
||||
(defn cancel-connection-popup!
|
||||
[]
|
||||
(reset! showing-connection-error-popup? false)
|
||||
(re-frame/dispatch [:mailserver.ui/dismiss-connection-error true]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::cancel-connection-popup
|
||||
cancel-connection-popup!)
|
||||
|
||||
(rf/defn show-connection-error!
|
||||
[cofx current-fleet preferred-mailserver]
|
||||
(reset! showing-connection-error-popup? true)
|
||||
{:ui/show-confirmation
|
||||
{:title (i18n/label :t/mailserver-error-title)
|
||||
:content (i18n/label :t/mailserver-error-content)
|
||||
:confirm-button-text (i18n/label :t/mailserver-pick-another)
|
||||
:on-cancel cancel-connection-popup!
|
||||
:on-accept #(do
|
||||
(reset! showing-connection-error-popup? false)
|
||||
(re-frame/dispatch [:mailserver.ui/dismiss-connection-error true])
|
||||
(re-frame/dispatch [:navigate-to :offline-messaging-settings]))
|
||||
:extra-options [{:text (i18n/label :t/mailserver-retry)
|
||||
:onPress #(do
|
||||
(reset! showing-connection-error-popup? false)
|
||||
(re-frame/dispatch
|
||||
[:mailserver.ui/connect-confirmed
|
||||
current-fleet
|
||||
preferred-mailserver]))
|
||||
:style "default"}]}})
|
||||
|
||||
(rf/defn handle-successful-request
|
||||
{:events [::request-success]}
|
||||
[{:keys [db] :as cofx} response-js]
|
||||
{:db (dissoc db :mailserver/current-request)
|
||||
:dispatch [:sanitize-messages-and-process-response response-js]})
|
||||
|
||||
(rf/defn handle-mailserver-not-working
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [current-fleet (node/current-fleet-key db)
|
||||
error-dismissed? (connection-error-dismissed db)
|
||||
pinned-mailserver (get-in db [:profile/profile :pinned-mailservers current-fleet])]
|
||||
(when (and pinned-mailserver
|
||||
(not error-dismissed?)
|
||||
(not @showing-connection-error-popup?))
|
||||
(show-connection-error! cofx current-fleet pinned-mailserver))))
|
||||
|
||||
(rf/defn handle-request-error
|
||||
{:events [::request-error]}
|
||||
[{:keys [db] :as cofx}]
|
||||
{:db (dissoc db :mailserver/current-request)})
|
||||
|
||||
(defn needs-to-fetch-historic-messages?
|
||||
[db]
|
||||
(and
|
||||
(:messenger/started? db)
|
||||
(mobile-network-utils/syncing-allowed? db)
|
||||
(fetch-use-mailservers? db)
|
||||
(not (:mailserver/current-request db))))
|
||||
|
||||
(rf/defn process-next-messages-request
|
||||
{:events [::request-messages]}
|
||||
[{:keys [db]}]
|
||||
(when (needs-to-fetch-historic-messages? db)
|
||||
{:db (assoc db :mailserver/current-request true)
|
||||
:mailserver/request-all-historic-messages nil}))
|
||||
|
||||
(re-frame/reg-fx :mailserver/request-all-historic-messages
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_requestAllHistoricMessagesWithRetries"
|
||||
:params [false]
|
||||
:js-response true
|
||||
:on-success #(do
|
||||
(log/info "fetched historical messages")
|
||||
(re-frame/dispatch [::request-success %]))
|
||||
:on-error #(do
|
||||
(log/error "failed retrieve historical messages" %)
|
||||
(re-frame/dispatch [::request-error]))})))
|
||||
|
||||
(rf/defn handle-mailserver-changed
|
||||
[{:keys [db] :as cofx} ms]
|
||||
(if (seq ms)
|
||||
{:db (assoc db
|
||||
:mailserver/state :connecting
|
||||
:mailserver/current-id (keyword ms))}
|
||||
{:db (assoc db :mailserver/state nil)}))
|
||||
|
||||
(rf/defn handle-mailserver-available
|
||||
[{:keys [db] :as cofx} ms]
|
||||
{::cancel-connection-popup []
|
||||
:db (assoc db
|
||||
:mailserver/state :connected
|
||||
:mailserver/current-id (keyword ms))})
|
||||
|
||||
(rf/defn connected-to-mailserver
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [address]} (fetch-current db)]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:mailserver/update-mailservers [[address] #(re-frame/dispatch [::request-messages])]})))
|
||||
|
||||
(rf/defn handle-request-success
|
||||
{:events [:mailserver.callback/request-success]}
|
||||
[{{:keys [chats] :as db} :db} {:keys [request-id topics]}]
|
||||
(when (:mailserver/current-request db)
|
||||
{:db (assoc-in db
|
||||
[:mailserver/current-request :request-id]
|
||||
request-id)}))
|
||||
|
||||
(rf/defn toggle-use-mailservers
|
||||
[cofx value]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_toggleUseMailservers"
|
||||
:params [value]
|
||||
:on-success #(log/info "successfully toggled use-mailservers" value)
|
||||
:on-failure #(log/error "failed to toggle use-mailserver" value %)}]})
|
||||
|
||||
(rf/defn update-use-mailservers
|
||||
{:events [:mailserver.ui/use-history-switch-pressed]}
|
||||
[cofx use-mailservers?]
|
||||
(rf/merge cofx
|
||||
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
|
||||
(toggle-use-mailservers use-mailservers?)
|
||||
(when use-mailservers?
|
||||
(disconnect-from-mailserver))))
|
||||
|
||||
(rf/defn retry-next-messages-request
|
||||
{:events [:mailserver.ui/retry-request-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :mailserver/request-error)}
|
||||
(process-next-messages-request)))
|
||||
|
||||
(rf/defn show-request-error-popup
|
||||
{:events [:mailserver.ui/request-error-pressed]}
|
||||
[{:keys [db]}]
|
||||
(let [mailserver-error (:mailserver/request-error db)]
|
||||
{:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/mailserver-request-error-title)
|
||||
:content (i18n/label :t/mailserver-request-error-content
|
||||
{:error mailserver-error})
|
||||
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
|
||||
:confirm-button-text (i18n/label :t/mailserver-request-retry)}}))
|
||||
|
||||
(def enode-url-regex
|
||||
#"enode://[a-zA-Z0-9]+\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
|
||||
|
||||
(defn- extract-url-components
|
||||
[address]
|
||||
(rest (re-matches #"enode://(.*)@(.*)" address)))
|
||||
|
||||
(defn valid-enode-url?
|
||||
[address]
|
||||
(re-matches enode-url-regex address))
|
||||
|
||||
(defn build-url
|
||||
[address]
|
||||
(let [[initial host] (extract-url-components address)]
|
||||
(str "enode://" initial "@" host)))
|
||||
|
||||
(rf/defn set-input
|
||||
{:events [:mailserver.ui/input-changed]}
|
||||
[{:keys [db]} input-key value]
|
||||
{:db (update
|
||||
db
|
||||
:mailserver.edit/mailserver
|
||||
assoc
|
||||
input-key
|
||||
{:value value
|
||||
:error (case input-key
|
||||
:id false
|
||||
:name (string/blank? value)
|
||||
:url (not (valid-enode-url? value)))})})
|
||||
|
||||
(defn- address->mailserver
|
||||
[address]
|
||||
(let [[enode url :as response] (extract-url-components address)]
|
||||
{:address (if (seq response)
|
||||
(str "enode://" enode "@" url)
|
||||
address)
|
||||
:custom true}))
|
||||
|
||||
(defn- build
|
||||
[id mailserver-name address]
|
||||
(assoc (address->mailserver address)
|
||||
:id id
|
||||
:name mailserver-name))
|
||||
|
||||
(def default? (comp not :custom fetch))
|
||||
|
||||
(rf/defn edit
|
||||
{:events [:mailserver.ui/custom-mailserver-selected]}
|
||||
[{:keys [db] :as cofx} id]
|
||||
(let [{:keys [id address name]} (fetch db id)
|
||||
url (when address (build-url address))]
|
||||
(rf/merge cofx
|
||||
(set-input :id id)
|
||||
(set-input :url (str url))
|
||||
(set-input :name (str name))
|
||||
(navigation/navigate-to :edit-mailserver nil))))
|
||||
|
||||
(defn mailserver->rpc
|
||||
[mailserver current-fleet]
|
||||
(-> mailserver
|
||||
(assoc :fleet (name current-fleet))
|
||||
(update :id name)))
|
||||
|
||||
(rf/defn upsert
|
||||
{:events [:mailserver.ui/save-pressed]
|
||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||
[{{:mailserver.edit/keys [mailserver] :profile/keys [profile] :as db} :db
|
||||
random-id-generator :random-id-generator
|
||||
:as cofx}]
|
||||
|
||||
(let [{:keys [name url id]} mailserver
|
||||
current-fleet (node/current-fleet-key db)]
|
||||
(when (and (not (string/blank? (:value name)))
|
||||
(valid-enode-url? (:value url)))
|
||||
|
||||
(let [mailserver (build
|
||||
(or (:value id)
|
||||
(keyword (string/replace (random-id-generator) "-" "")))
|
||||
(:value name)
|
||||
(:value url))
|
||||
current (connected? db (:id mailserver))]
|
||||
{:db (-> db
|
||||
(dissoc :mailserver.edit/mailserver)
|
||||
(assoc-in [:mailserver/mailservers current-fleet (:id mailserver)]
|
||||
mailserver))
|
||||
:json-rpc/call
|
||||
[{:method "mailservers_addMailserver"
|
||||
:params [(mailserver->rpc mailserver current-fleet)]
|
||||
:on-success (fn []
|
||||
;; we naively logout if the user is connected to the edited mailserver
|
||||
(when current
|
||||
(re-frame/dispatch
|
||||
[:multiaccounts.logout.ui/logout-confirmed]))
|
||||
(log/debug "saved mailserver" id "successfuly"))
|
||||
:on-failure #(log/error "failed to save mailserver" id %)}]
|
||||
:dispatch [:navigate-back]}))))
|
||||
|
||||
(defn can-delete?
|
||||
[db id]
|
||||
(not (or (default? db id)
|
||||
(connected? db id))))
|
||||
|
||||
(rf/defn delete
|
||||
{:events [:mailserver.ui/delete-confirmed]}
|
||||
[{:keys [db] :as cofx} id]
|
||||
(if (can-delete? db id)
|
||||
{:db (-> db
|
||||
(update-in
|
||||
[:mailserver/mailservers (node/current-fleet-key db)]
|
||||
dissoc
|
||||
id)
|
||||
(dissoc :mailserver.edit/mailserver))
|
||||
:json-rpc/call
|
||||
[{:method "mailservers_deleteMailserver"
|
||||
:params [(name id)]
|
||||
:on-success #(log/debug "deleted mailserver" id)
|
||||
:on-failure #(log/error "failed to delete mailserver" id %)}]
|
||||
:dispatch [:navigate-back]}
|
||||
{:dispatch [:navigate-back]}))
|
||||
|
||||
(rf/defn show-connection-confirmation
|
||||
{:events [:mailserver.ui/default-mailserver-selected :mailserver.ui/connect-pressed]}
|
||||
[{:keys [db]} mailserver-id]
|
||||
(let [current-fleet (node/current-fleet-key db)]
|
||||
{:ui/show-confirmation
|
||||
{:title (i18n/label :t/close-app-title)
|
||||
:content
|
||||
(i18n/label :t/connect-mailserver-content
|
||||
{:name (get-in db
|
||||
[:mailserver/mailservers
|
||||
current-fleet mailserver-id :name])})
|
||||
:confirm-button-text (i18n/label :t/close-app-button)
|
||||
:on-accept
|
||||
#(re-frame/dispatch
|
||||
[:mailserver.ui/connect-confirmed current-fleet mailserver-id])
|
||||
:on-cancel nil}}))
|
||||
|
||||
(rf/defn show-delete-confirmation
|
||||
{:events [:mailserver.ui/delete-pressed]}
|
||||
[{:keys [db]} mailserver-id]
|
||||
{:ui/show-confirmation
|
||||
{:title (i18n/label :t/delete-mailserver-title)
|
||||
:content (i18n/label :t/delete-mailserver-are-you-sure)
|
||||
:confirm-button-text (i18n/label :t/delete-mailserver)
|
||||
:on-accept #(re-frame/dispatch
|
||||
[:mailserver.ui/delete-confirmed mailserver-id])}})
|
||||
|
||||
(rf/defn set-url-from-qr
|
||||
{:events [:mailserver.callback/qr-code-scanned]}
|
||||
[cofx url]
|
||||
(assoc (set-input cofx :url url)
|
||||
:dispatch
|
||||
[:navigate-back]))
|
||||
|
||||
(rf/defn dismiss-connection-error
|
||||
{:events [:mailserver.ui/dismiss-connection-error]}
|
||||
[{:keys [db]} new-state]
|
||||
{:db (assoc db :mailserver/connection-error-dismissed new-state)})
|
||||
|
||||
(rf/defn pin-mailserver
|
||||
{:events [:mailserver.ui/connect-confirmed]}
|
||||
[{:keys [db] :as cofx} current-fleet mailserver-id]
|
||||
(let [pinned-mailservers (-> db
|
||||
(get-in [:profile/profile :pinned-mailservers])
|
||||
(assoc current-fleet mailserver-id))]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :mailserver/current-id mailserver-id)
|
||||
:json-rpc/call [{:method "wakuext_setPinnedMailservers"
|
||||
:params [pinned-mailservers]
|
||||
:on-success #(log/info "successfully pinned mailserver")
|
||||
:on-error #(log/error "failed to pin mailserver" %)}]}
|
||||
(multiaccounts.update/optimistic :pinned-mailservers pinned-mailservers))))
|
||||
|
||||
(rf/defn unpin
|
||||
{:events [:mailserver.ui/unpin-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [current-fleet (node/current-fleet-key db)
|
||||
pinned-mailservers (-> db
|
||||
(get-in [:profile/profile :pinned-mailservers])
|
||||
(dissoc current-fleet))]
|
||||
(rf/merge cofx
|
||||
{:json-rpc/call [{:method "wakuext_setPinnedMailservers"
|
||||
:params [pinned-mailservers]
|
||||
:on-success #(log/info "successfully unpinned mailserver")
|
||||
:on-error #(log/error "failed to unpin mailserver" %)}]}
|
||||
(multiaccounts.update/optimistic
|
||||
:pinned-mailservers
|
||||
pinned-mailservers)
|
||||
(dismiss-connection-error false))))
|
||||
|
||||
(rf/defn pin
|
||||
{:events [:mailserver.ui/pin-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [current-fleet (node/current-fleet-key db)
|
||||
mailserver-id (:mailserver/current-id db)
|
||||
pinned-mailservers (get-in db [:profile/profile :pinned-mailservers])]
|
||||
(rf/merge cofx
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:pinned-mailservers
|
||||
(assoc pinned-mailservers
|
||||
current-fleet
|
||||
mailserver-id)
|
||||
{})
|
||||
(dismiss-connection-error false))))
|
||||
|
||||
(rf/defn mailserver-ui-add-pressed
|
||||
{:events [:mailserver.ui/add-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :mailserver.edit/mailserver)}
|
||||
(navigation/navigate-to :edit-mailserver nil)))
|
||||
|
||||
(defn add-mailservers
|
||||
[db mailservers]
|
||||
(reduce (fn [db {:keys [fleet id name] :as mailserver}]
|
||||
(let [updated-mailserver
|
||||
(-> mailserver
|
||||
(update :id keyword)
|
||||
(assoc :name (if (seq name) name id))
|
||||
(dissoc :fleet))]
|
||||
(assoc-in db
|
||||
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
||||
updated-mailserver)))
|
||||
db
|
||||
mailservers))
|
@ -1,109 +0,0 @@
|
||||
(ns legacy.status-im.mobile-sync-settings.core
|
||||
(:require
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.utils.mobile-sync :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn sheet-defaults
|
||||
[{:keys [db]}]
|
||||
(let [remember-choice? (get-in db [:profile/profile :remember-syncing-choice?])]
|
||||
{:db (assoc db
|
||||
:mobile-network/remember-choice?
|
||||
(or (nil? remember-choice?)
|
||||
remember-choice?))}))
|
||||
|
||||
(re-frame/reg-event-fx :mobile-network/on-network-status-change
|
||||
(fn [{:keys [db]}]
|
||||
(let [previously-initialized? (get db :network-status/initialized?)
|
||||
logged-in? (multiaccounts.model/logged-in? db)
|
||||
fetch-historic-messages? (mailserver/needs-to-fetch-historic-messages? db)]
|
||||
(if logged-in?
|
||||
{:db (cond-> (-> db
|
||||
(assoc :network-status/initialized? true)
|
||||
(assoc :bottom-sheet/show? false))
|
||||
fetch-historic-messages?
|
||||
(assoc :mailserver/current-request true))
|
||||
:fx [(when fetch-historic-messages?
|
||||
[:mailserver/request-all-historic-messages])
|
||||
[:dispatch [:hide-bottom-sheet]]
|
||||
(when previously-initialized?
|
||||
(let [new-identity-input (get-in db [:contacts/new-identity :input])]
|
||||
[:dispatch [:contacts/set-new-identity {:input new-identity-input}]]))]}
|
||||
{:db (assoc db :network-status/initialized? true)}))))
|
||||
|
||||
(defn apply-settings
|
||||
([sync?] (apply-settings sync? :default))
|
||||
([sync? remember?]
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(let [network (:network/type db)
|
||||
remember-choice?
|
||||
(if (not= :default remember?)
|
||||
remember?
|
||||
(:mobile-network/remember-choice? db))
|
||||
cellular? (utils/cellular? network)]
|
||||
(log/info "apply mobile network settings"
|
||||
"sunc?" sync?
|
||||
"remember?" remember?
|
||||
"cellular?" cellular?)
|
||||
(rf/merge
|
||||
cofx
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:syncing-on-mobile-network?
|
||||
(boolean sync?)
|
||||
{})
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:remember-syncing-choice?
|
||||
(boolean remember-choice?)
|
||||
{})
|
||||
(when (and cellular? sync?)
|
||||
(mailserver/process-next-messages-request)))))))
|
||||
|
||||
(rf/defn mobile-network-continue-syncing
|
||||
{:events [:mobile-network/continue-syncing]}
|
||||
[cofx]
|
||||
((apply-settings true) cofx))
|
||||
|
||||
(rf/defn mobile-network-stop-syncing
|
||||
{:events [:mobile-network/stop-syncing]}
|
||||
[cofx]
|
||||
((apply-settings false) cofx))
|
||||
|
||||
(rf/defn mobile-network-set-syncing
|
||||
{:events [:mobile-network/set-syncing]}
|
||||
[{:keys [db] :as cofx} syncing?]
|
||||
(let [{:keys [remember-syncing-choice?]} (:profile/profile db)]
|
||||
((apply-settings syncing? remember-syncing-choice?) cofx)))
|
||||
|
||||
(rf/defn mobile-network-ask-on-mobile-network?
|
||||
{:events [:mobile-network/ask-on-mobile-network?]}
|
||||
[{:keys [db] :as cofx} ask?]
|
||||
(let [{:keys [syncing-on-mobile-network?]} (:profile/profile db)]
|
||||
((apply-settings syncing-on-mobile-network? (not ask?)) cofx)))
|
||||
|
||||
(rf/defn mobile-network-restore-defaults
|
||||
{:events [:mobile-network/restore-defaults]}
|
||||
[cofx]
|
||||
((apply-settings false false) cofx))
|
||||
|
||||
(rf/defn mobile-network-remember-choice?
|
||||
{:events [:mobile-network/remember-choice?]}
|
||||
[{:keys [db]} remember-choice?]
|
||||
{:db (assoc db :mobile-network/remember-choice? remember-choice?)})
|
||||
|
||||
(rf/defn mobile-network-navigate-to-settings
|
||||
{:events [:mobile-network/navigate-to-settings]}
|
||||
[cofx]
|
||||
(rf/merge
|
||||
cofx
|
||||
(navigation/hide-bottom-sheet)
|
||||
(navigation/navigate-to :mobile-network-settings nil)))
|
||||
|
||||
(rf/defn mobile-network-show-offline-sheet
|
||||
{:events [:mobile-network/show-offline-sheet]}
|
||||
[cofx]
|
||||
(navigation/hide-bottom-sheet cofx))
|
@ -14,10 +14,12 @@
|
||||
|
||||
(rf/defn initialize-app-db
|
||||
[{{:keys [keycard initials-avatar-font-file biometrics]
|
||||
:network/keys [type]}
|
||||
:network/keys [type status expensive?]}
|
||||
:db}]
|
||||
{:db (assoc db/app-db
|
||||
:network/type type
|
||||
:network/status status
|
||||
:network/expensive? expensive?
|
||||
:initials-avatar-font-file initials-avatar-font-file
|
||||
:keycard (dissoc keycard :secrets :pin :application-info)
|
||||
:biometrics biometrics
|
||||
|
@ -1,56 +0,0 @@
|
||||
(ns legacy.status-im.network.net-info
|
||||
(:require
|
||||
["@react-native-community/netinfo" :default net-info]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn change-network-status
|
||||
[{:keys [db] :as cofx} is-connected?]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :network-status (if is-connected? :online :offline))}))
|
||||
|
||||
(rf/defn change-network-type
|
||||
[{:keys [db] :as cofx} network-type expensive?]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :network/type network-type)
|
||||
:network/notify-status-go [network-type expensive?]
|
||||
:dispatch [:mobile-network/on-network-status-change]}))
|
||||
|
||||
(rf/defn handle-network-info-change
|
||||
{:events [::network-info-changed]}
|
||||
[{:keys [db] :as cofx} {:keys [isConnected type details] :as state}]
|
||||
(let [old-network-status (:network-status db)
|
||||
old-network-type (:network/type db)
|
||||
connectivity-status (if isConnected :online :offline)
|
||||
status-changed? (= connectivity-status old-network-status)
|
||||
type-changed? (= type old-network-type)]
|
||||
(log/debug "[net-info]"
|
||||
"old-network-status" old-network-status
|
||||
"old-network-type" old-network-type
|
||||
"connectivity-status" connectivity-status
|
||||
"type" type
|
||||
"details" details)
|
||||
(rf/merge cofx
|
||||
(when-not status-changed?
|
||||
(change-network-status isConnected))
|
||||
(when-not type-changed?
|
||||
(change-network-type type (:is-connection-expensive details))))))
|
||||
|
||||
(defn add-net-info-listener
|
||||
[]
|
||||
(when net-info
|
||||
(.addEventListener ^js net-info
|
||||
#(re-frame/dispatch [::network-info-changed
|
||||
(js->clj % :keywordize-keys true)]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:network/listen-to-network-info
|
||||
(fn []
|
||||
(add-net-info-listener)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:network/notify-status-go
|
||||
(fn [[network-type expensive?]]
|
||||
(native-module/connection-change network-type expensive?)))
|
@ -15,8 +15,6 @@
|
||||
(reg-root-key-sub :visibility-status-updates :visibility-status-updates)
|
||||
(reg-root-key-sub :fleets/custom-fleets :custom-fleets)
|
||||
(reg-root-key-sub :ui/search :ui/search)
|
||||
(reg-root-key-sub :network/type :network/type)
|
||||
(reg-root-key-sub :network-status :network-status)
|
||||
(reg-root-key-sub :peer-stats/count :peer-stats/count)
|
||||
(reg-root-key-sub :peers-summary :peers-summary)
|
||||
(reg-root-key-sub :web3-node-version :web3-node-version)
|
||||
|
@ -5,6 +5,7 @@
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
@ -20,8 +21,6 @@
|
||||
light-client-enabled?
|
||||
store-confirmations-enabled?
|
||||
current-fleet
|
||||
test-networks-enabled?
|
||||
is-goerli-enabled?
|
||||
peer-syncing-enabled?]}]
|
||||
(keep
|
||||
identity
|
||||
@ -61,14 +60,14 @@
|
||||
:on-press
|
||||
#(re-frame/dispatch [:open-modal :peers-stats])
|
||||
:chevron true}
|
||||
{:size :small
|
||||
:title "Telemetry"
|
||||
:accessibility-label :telemetry-enabled
|
||||
:container-margin-bottom 8
|
||||
:on-press
|
||||
#(re-frame/dispatch [:profile.settings/toggle-telemetry])
|
||||
:accessory :switch
|
||||
:active telemetry-enabled?}
|
||||
(when (ff/enabled? ::ff/settings.telemetry)
|
||||
{:size :small
|
||||
:title "Telemetry"
|
||||
:accessibility-label :telemetry-enabled
|
||||
:container-margin-bottom 8
|
||||
:on-press #(re-frame/dispatch [:profile.settings/toggle-telemetry])
|
||||
:accessory :switch
|
||||
:active telemetry-enabled?})
|
||||
{:size :small
|
||||
:title (i18n/label :t/light-client-enabled)
|
||||
:accessibility-label :light-client-enabled
|
||||
@ -87,22 +86,6 @@
|
||||
[:wakuv2.ui/toggle-store-confirmations (not store-confirmations-enabled?)])
|
||||
:accessory :switch
|
||||
:active store-confirmations-enabled?}
|
||||
{:size :small
|
||||
:title "Testnet mode"
|
||||
:accessibility-label :test-networks-enabled
|
||||
:container-margin-bottom 8
|
||||
:on-press
|
||||
#(re-frame/dispatch [:profile.settings/toggle-test-networks])
|
||||
:accessory :switch
|
||||
:active test-networks-enabled?}
|
||||
{:size :small
|
||||
:title "Enable Goerli as test network"
|
||||
:accessibility-label :enable-sepolia-as-test-network
|
||||
:container-margin-bottom 8
|
||||
:on-press
|
||||
#(re-frame/dispatch [:profile.settings/toggle-goerli-test-network])
|
||||
:accessory :switch
|
||||
:active is-goerli-enabled?}
|
||||
{:size :small
|
||||
:title "Peer syncing"
|
||||
:accessibility-label :peer-syncing
|
||||
@ -124,9 +107,7 @@
|
||||
|
||||
(views/defview advanced-settings
|
||||
[]
|
||||
(views/letsubs [test-networks-enabled? [:profile/test-networks-enabled?]
|
||||
is-goerli-enabled? [:profile/is-goerli-enabled?]
|
||||
light-client-enabled? [:profile/light-client-enabled?]
|
||||
(views/letsubs [light-client-enabled? [:profile/light-client-enabled?]
|
||||
store-confirmations-enabled? [:profile/store-confirmations-enabled?]
|
||||
telemetry-enabled? [:profile/telemetry-enabled?]
|
||||
current-log-level [:log-level/current-log-level]
|
||||
@ -147,8 +128,6 @@
|
||||
:store-confirmations-enabled? store-confirmations-enabled?
|
||||
:current-fleet current-fleet
|
||||
:dev-mode? false
|
||||
:test-networks-enabled? test-networks-enabled?
|
||||
:is-goerli-enabled? is-goerli-enabled?
|
||||
:peer-syncing-enabled? peer-syncing-enabled?})
|
||||
:key-fn (fn [_ i] (str i))
|
||||
:render-fn render-item}]]))
|
||||
|
@ -127,7 +127,7 @@
|
||||
(when (and can-manage-users? (= constants/community-on-request-access (:access permissions)))
|
||||
[requests-to-join community-id])
|
||||
[rn/flat-list
|
||||
{:data (keys sorted-members)
|
||||
{:data sorted-members
|
||||
:render-data {:community-id community-id
|
||||
:my-public-key my-public-key
|
||||
:can-kick-users? (and can-manage-users?
|
||||
|
@ -1,51 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.mobile-network-settings.sheets
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require [legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.mobile-network-settings.sheets-styles :as styles]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn title
|
||||
[label]
|
||||
[react/view {:style styles/title}
|
||||
[react/text
|
||||
{:style styles/title-text}
|
||||
(i18n/label label)]])
|
||||
|
||||
(defn details
|
||||
[label]
|
||||
[react/view
|
||||
{:style styles/details}
|
||||
[react/text
|
||||
{:style styles/details-text}
|
||||
(i18n/label label)]])
|
||||
|
||||
(defn separator
|
||||
[]
|
||||
[react/view {:style styles/separator}])
|
||||
|
||||
(defn go-to-settings
|
||||
[]
|
||||
[react/view
|
||||
{:style styles/go-to-settings-container}
|
||||
[react/text
|
||||
{:style styles/go-to-settings
|
||||
:on-press #(re-frame/dispatch [:mobile-network/navigate-to-settings])}
|
||||
(i18n/label :t/mobile-network-go-to-settings)]])
|
||||
|
||||
(views/defview offline-sheet
|
||||
[]
|
||||
[react/view {:flex 1}
|
||||
[react/view {:align-items :center}
|
||||
[title :t/mobile-network-sheet-offline]
|
||||
[details :t/mobile-network-sheet-offline-details]]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/mobile-network-start-syncing)
|
||||
:subtitle (i18n/label :t/mobile-network-continue-syncing-details)
|
||||
:subtitle-max-lines 2
|
||||
:icon :main-icons/network
|
||||
:on-press #(re-frame/dispatch [:mobile-network/continue-syncing])}]
|
||||
[separator]
|
||||
[go-to-settings]])
|
@ -1,73 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.mobile-network-settings.sheets-styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def title
|
||||
{:height 21
|
||||
:margin-top 8})
|
||||
|
||||
(def title-text
|
||||
{:typography :title-bold})
|
||||
|
||||
(def details
|
||||
{:width 311
|
||||
:margin-left 32
|
||||
:margin-right 32
|
||||
:margin-top 6
|
||||
:margin-bottom 10})
|
||||
|
||||
(def details-text
|
||||
{:color colors/gray
|
||||
:text-align :center})
|
||||
|
||||
(def separator
|
||||
{:background-color colors/gray-lighter
|
||||
:margin-left 72
|
||||
:align-self :stretch
|
||||
:height 1
|
||||
:margin-top 8})
|
||||
|
||||
(def checkbox-line-container
|
||||
{:margin-left 71
|
||||
:margin-top 13
|
||||
:height 29
|
||||
:flex-direction :row
|
||||
:justify-content :center})
|
||||
|
||||
(def checkbox
|
||||
{:padding 0
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:width 18
|
||||
:height 18
|
||||
:border-radius 2
|
||||
:margin-top 6})
|
||||
|
||||
(def checkbox-icon
|
||||
{:tint-color colors/white})
|
||||
|
||||
(def checkbox-text-container
|
||||
{:justify-content :center
|
||||
:flex 1
|
||||
:margin-left 13})
|
||||
|
||||
(def settings-container
|
||||
{:margin-left 69
|
||||
:height 44
|
||||
:margin-top 6
|
||||
:align-items :flex-start})
|
||||
|
||||
(def settings-text
|
||||
{:color colors/gray})
|
||||
|
||||
(def settings-link
|
||||
{:color colors/blue})
|
||||
|
||||
(def go-to-settings-container
|
||||
{:height 52
|
||||
:margin-left 72
|
||||
:justify-content :center
|
||||
:align-self :stretch})
|
||||
|
||||
(def go-to-settings
|
||||
{:color colors/blue})
|
@ -1,32 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.mobile-network-settings.style
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
|
||||
(def switch-container
|
||||
{:height 52})
|
||||
|
||||
(def details
|
||||
{:margin-right 16
|
||||
:margin-left 16
|
||||
:margin-top 8
|
||||
:margin-bottom 16})
|
||||
|
||||
(def use-mobile-data-text
|
||||
{:color colors/gray})
|
||||
|
||||
(defn settings-separator
|
||||
[]
|
||||
{:align-self :stretch
|
||||
:height 1
|
||||
:background-color colors/gray-lighter})
|
||||
|
||||
(def defaults-container
|
||||
{:height 52
|
||||
:justify-content :center
|
||||
:padding-left 16})
|
||||
|
||||
(def defaults
|
||||
{:color colors/blue})
|
@ -1,57 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.mobile-network-settings.view
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
legacy.status-im.mobile-sync-settings.core
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.mobile-network-settings.sheets :as sheets]
|
||||
[legacy.status-im.ui.screens.mobile-network-settings.style :as styles]
|
||||
[legacy.status-im.ui.screens.profile.components.views :as profile.components]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(re-frame/dispatch [:bottom-sheet/hide-old])
|
||||
(re-frame/dispatch event))
|
||||
|
||||
(defn settings-separator
|
||||
[]
|
||||
[react/view
|
||||
{:style (styles/settings-separator)}])
|
||||
|
||||
;; TODO(Ferossgp): To refactor, uses outdated components
|
||||
(views/defview mobile-network-settings
|
||||
[]
|
||||
(views/letsubs
|
||||
[{:keys [syncing-on-mobile-network?
|
||||
remember-syncing-choice?]}
|
||||
[:profile/profile]]
|
||||
[:<>
|
||||
[react/view
|
||||
{:style styles/switch-container
|
||||
:accessibility-label "mobile-network-use-mobile"}
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/mobile-network-use-mobile
|
||||
:value syncing-on-mobile-network?
|
||||
:action-fn #(hide-sheet-and-dispatch [:mobile-network/set-syncing %])}]]
|
||||
[react/view {:style styles/details}
|
||||
[react/text {:style styles/use-mobile-data-text}
|
||||
(i18n/label :t/mobile-network-use-mobile-data)]]
|
||||
[react/view
|
||||
{:style styles/switch-container
|
||||
:accessibility-label "mobile-network-ask-me"}
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/mobile-network-ask-me
|
||||
:value (not remember-syncing-choice?)
|
||||
:action-fn #(hide-sheet-and-dispatch [:mobile-network/ask-on-mobile-network? %])}]]
|
||||
[settings-separator]
|
||||
[react/view
|
||||
{:style styles/defaults-container}
|
||||
[react/text
|
||||
{:style styles/defaults
|
||||
:accessibility-label "restore-defaults"
|
||||
:on-press #(hide-sheet-and-dispatch [:mobile-network/restore-defaults])}
|
||||
(i18n/label :t/restore-defaults)]]]))
|
||||
|
||||
(def offline-sheet
|
||||
{:content sheets/offline-sheet})
|
@ -13,7 +13,6 @@
|
||||
[legacy.status-im.ui.screens.glossary.view :as glossary]
|
||||
[legacy.status-im.ui.screens.help-center.views :as help-center]
|
||||
[legacy.status-im.ui.screens.log-level-settings.views :as log-level-settings]
|
||||
[legacy.status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings]
|
||||
[legacy.status-im.ui.screens.notifications-settings.views :as notifications-settings]
|
||||
[legacy.status-im.ui.screens.offline-messaging-settings.edit-mailserver.views :as edit-mailserver]
|
||||
[legacy.status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings]
|
||||
@ -145,10 +144,6 @@
|
||||
:options {:topBar (topbar-options :t/fleet-settings)
|
||||
:insets {:top? true}}
|
||||
:component fleet-settings/fleet-settings}
|
||||
{:name :mobile-network-settings
|
||||
:options {:topBar (topbar-options :t/mobile-network-settings)
|
||||
:insets {:top? true}}
|
||||
:component mobile-network-settings/mobile-network-settings}
|
||||
{:name :backup-settings
|
||||
:options {:topBar (topbar-options :t/backup-settings)
|
||||
:insets {:top? true}}
|
||||
|
@ -127,7 +127,7 @@
|
||||
[:app-state
|
||||
:current-chat-id
|
||||
:network
|
||||
:network-status
|
||||
:network/status
|
||||
:peers-summary
|
||||
:sync-state
|
||||
:view-id
|
||||
|
@ -171,7 +171,7 @@
|
||||
#js
|
||||
{:getEnforcing {}})
|
||||
|
||||
(def net-info #js {})
|
||||
(def net-info #js {:addEventListener identity})
|
||||
(def react-native-biometrics #js {:default {}})
|
||||
(def react-native-static-safe-area-insets #js {:default {}})
|
||||
|
||||
|
@ -332,7 +332,9 @@
|
||||
(defn set-blank-preview-flag
|
||||
[flag]
|
||||
(log/debug "[native-module] set-blank-preview-flag")
|
||||
(.setBlankPreviewFlag ^js (encryption) flag))
|
||||
;; Sometimes the app crashes during logout because `flag` is nil.
|
||||
(when flag
|
||||
(.setBlankPreviewFlag ^js (encryption) flag)))
|
||||
|
||||
(defn get-device-model-info
|
||||
[]
|
||||
@ -385,6 +387,11 @@
|
||||
(log/debug "[native-module] encode-transfer")
|
||||
(.encodeTransfer ^js (encryption) to-norm amount-hex))
|
||||
|
||||
(defn encode-function-call
|
||||
[method params]
|
||||
(log/debug "[native-module] encode-function-call")
|
||||
(.encodeFunctionCall ^js (encryption) method (types/clj->json params)))
|
||||
|
||||
(defn decode-parameters
|
||||
[bytes-string types]
|
||||
(log/debug "[native-module] decode-parameters")
|
||||
|
@ -60,7 +60,7 @@
|
||||
|
||||
(defn icon-color
|
||||
[{:keys [theme blur? type]}]
|
||||
(let [theme-with-blur (if blur? :blue theme)
|
||||
(let [theme-with-blur (if blur? :blur theme)
|
||||
matcher [theme-with-blur type]]
|
||||
(case matcher
|
||||
([:dark :main] [:light :main]) (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
|
||||
|
@ -65,9 +65,8 @@
|
||||
: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))
|
||||
{:style (style/container loading? theme size)
|
||||
:colors (linear-gradient-props theme customization-color)}
|
||||
[rn/pressable
|
||||
{:accessibility-label :internal-link-card
|
||||
:on-press on-press}
|
||||
|
@ -11,5 +11,5 @@
|
||||
[:networks [:* [:map [:source :schema.common/image-source]]]]
|
||||
[:on-press {:optional true} [:maybe fn?]]
|
||||
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
|
||||
[:state {:optional true} [:maybe [:enum :default :active :selected]]]]]
|
||||
[:state {:optional true} [:maybe [:enum :default :active :selected :disabled]]]]]
|
||||
:any])
|
||||
|
@ -18,6 +18,7 @@
|
||||
:padding-vertical 8
|
||||
:border-radius 12
|
||||
:height 56
|
||||
:opacity (when (= state :disabled) 0.3)
|
||||
:background-color (background-color state customization-color theme)})
|
||||
|
||||
(defn check-color
|
||||
|
@ -62,6 +62,7 @@
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out
|
||||
:on-press on-press
|
||||
:disabled (= state :disabled)
|
||||
:accessibility-label :token-network}
|
||||
[info props]
|
||||
[values props]]))
|
||||
|
@ -32,8 +32,7 @@
|
||||
|
||||
(def system-message-base-wrapper
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center})
|
||||
:flex 1})
|
||||
|
||||
(def system-message-base-content-wrapper
|
||||
{:align-self :center
|
||||
|
@ -127,6 +127,14 @@
|
||||
(when incoming? [split-text "sent you a contact request" theme true])
|
||||
[sm-timestamp timestamp theme]]]))
|
||||
|
||||
(defn system-message-group
|
||||
[{:keys [customization-color child]}]
|
||||
[system-message-base
|
||||
{:icon {:icon :i/add-user
|
||||
:color (or customization-color :primary)
|
||||
:opacity 5}}
|
||||
[rn/view child]])
|
||||
|
||||
(defn system-message-pinned
|
||||
[{:keys [pinned-by child customization-color timestamp]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
@ -183,6 +191,7 @@
|
||||
:contact-request [system-message-contact-request data]
|
||||
:added [system-message-added data]
|
||||
:removed [system-message-removed data]
|
||||
:group [system-message-group data]
|
||||
nil)]))
|
||||
|
||||
(defn system-message
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
(defn main
|
||||
[{:keys [type customization-color]} theme]
|
||||
{:justify-content :center
|
||||
{:justify-content :flex-start
|
||||
:align-items :center
|
||||
:height 32
|
||||
:padding-left 4
|
||||
@ -16,6 +16,7 @@
|
||||
(defn label
|
||||
[type theme]
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)
|
||||
:flex-shrink 1
|
||||
:margin-left (if (= type :address) 6 4)})
|
||||
|
||||
(def collectible-image
|
||||
|
@ -58,16 +58,19 @@
|
||||
- :emoji - string - emoji used for displaying account avatar
|
||||
- :image-source - resource - image to display on :network, :collectible and :user
|
||||
- :theme - :light / :dark"
|
||||
[{:keys [label customization-color type]
|
||||
[{:keys [label customization-color type container-style]
|
||||
:as props
|
||||
:or {customization-color colors/neutral-80-opa-5}}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view
|
||||
{:accessibility-label :container
|
||||
:style (style/main (assoc props :customization-color customization-color) theme)}
|
||||
:style (merge (style/main (assoc props :customization-color customization-color)
|
||||
theme)
|
||||
container-style)}
|
||||
[left-view props]
|
||||
[text/text
|
||||
{:style (style/label type theme)
|
||||
:weight :semi-bold
|
||||
:size :heading-1}
|
||||
{:style (style/label type theme)
|
||||
:weight :semi-bold
|
||||
:number-of-lines 1
|
||||
:size :heading-1}
|
||||
label]]))
|
||||
|
@ -21,3 +21,8 @@
|
||||
(if blur?
|
||||
(colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)))
|
||||
|
||||
(def text
|
||||
{:flex 1
|
||||
;; NOTE: assures the ellipses are not cut off when text is too long
|
||||
:padding-right 2})
|
||||
|
@ -59,7 +59,9 @@
|
||||
[rn/view {:style (merge style/container container-style)}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:number-of-lines 1
|
||||
:weight :semi-bold
|
||||
:style style/text
|
||||
:accessibility-label accessibility-label}
|
||||
title]
|
||||
(case right
|
||||
|
@ -5,7 +5,7 @@
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def account-colors
|
||||
[:blue :yellow :purple :turquoise :magenta :sky :orange :army :flamingo :camel :copper])
|
||||
[:blue :yellow :purple :turquoise :magenta :sky :orange :army :pink :camel :copper])
|
||||
|
||||
(defn alpha
|
||||
[value opacity]
|
||||
@ -44,6 +44,13 @@
|
||||
(alpha light-color light-opacity)
|
||||
(alpha dark-color dark-opacity))))))
|
||||
|
||||
(defn valid-color?
|
||||
[color]
|
||||
(or (keyword? color)
|
||||
(and (string? color)
|
||||
(or (string/starts-with? color "#")
|
||||
(string/starts-with? color "rgb")))))
|
||||
|
||||
|
||||
;;;;Neutral
|
||||
|
||||
@ -239,7 +246,7 @@
|
||||
60 "#CC6438"}
|
||||
:army {50 "#216266"
|
||||
60 "#1A4E52"}
|
||||
:flamingo {50 "#F66F8F"
|
||||
:pink {50 "#F66F8F"
|
||||
60 "#C55972"}
|
||||
:purple {50 "#7140FD"
|
||||
60 "#5A33CA"}
|
||||
@ -316,13 +323,14 @@
|
||||
[s]
|
||||
(and (string? s) (string/starts-with? s "#")))
|
||||
|
||||
(def fallback-color (customization :blue))
|
||||
|
||||
(defn- get-from-colors-map
|
||||
[color suffix]
|
||||
(let [color-without-suffix (get colors-map color)
|
||||
resolved-color? (hex-string? color-without-suffix)]
|
||||
(if resolved-color?
|
||||
(let [color-without-suffix (get colors-map color fallback-color)]
|
||||
(if (hex-string? color-without-suffix)
|
||||
color-without-suffix
|
||||
(get-in colors-map [color suffix]))))
|
||||
(get color-without-suffix suffix))))
|
||||
|
||||
(defn- resolve-color*
|
||||
([color theme]
|
||||
@ -356,11 +364,15 @@
|
||||
([color suffix]
|
||||
(custom-color color suffix nil))
|
||||
([color suffix opacity]
|
||||
(let [hex? (not (keyword? color))
|
||||
resolved-color (cond hex? color
|
||||
(hex-string? (get colors-map color)) (get colors-map color)
|
||||
:else (get-in colors-map
|
||||
[color suffix]))]
|
||||
(let [resolved-color (cond
|
||||
(not (keyword? color))
|
||||
color
|
||||
|
||||
(hex-string? (get colors-map color))
|
||||
(get colors-map color fallback-color)
|
||||
|
||||
:else
|
||||
(get-in colors-map [color suffix] (get fallback-color suffix)))]
|
||||
(if opacity
|
||||
(alpha resolved-color (/ opacity 100))
|
||||
resolved-color))))))
|
||||
|
@ -4,11 +4,37 @@
|
||||
[oops.core :as oops]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- add-keyboard-listener
|
||||
[listener callback]
|
||||
(oops/ocall rn/keyboard "addListener" listener callback))
|
||||
|
||||
(defn use-keyboard
|
||||
[]
|
||||
(let [kb (.useKeyboard hooks)]
|
||||
{:keyboard-shown (.-keyboardShown ^js kb)
|
||||
:keyboard-height (.-keyboardHeight ^js kb)}))
|
||||
(let [[keyboard-height set-keyboard-height] (rn/use-state 0)
|
||||
[did-show? set-did-show] (rn/use-state false)
|
||||
[will-show? set-will-show] (rn/use-state false)]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(let [will-show-listener (add-keyboard-listener "keyboardWillShow" #(set-will-show true))
|
||||
did-show-listener (add-keyboard-listener "keyboardDidShow"
|
||||
(fn [e]
|
||||
(set-did-show true)
|
||||
(set-keyboard-height
|
||||
(oops/oget e "endCoordinates.height"))))
|
||||
will-hide-listener (add-keyboard-listener "keyboardWillHide" #(set-will-show false))
|
||||
did-hide-listener (add-keyboard-listener "keyboardDidHide"
|
||||
(fn [e]
|
||||
(set-did-show false)
|
||||
(when e
|
||||
(oops/oget e "endCoordinates.height"))))]
|
||||
(fn []
|
||||
(oops/ocall will-show-listener "remove")
|
||||
(oops/ocall did-show-listener "remove")
|
||||
(oops/ocall will-hide-listener "remove")
|
||||
(oops/ocall did-hide-listener "remove")))))
|
||||
{:keyboard-shown did-show?
|
||||
:keyboard-will-show? will-show?
|
||||
:keyboard-height keyboard-height}))
|
||||
|
||||
(defn use-back-handler
|
||||
[handler]
|
||||
|
@ -1,6 +1,39 @@
|
||||
(ns react-native.linear-gradient
|
||||
(:require
|
||||
["react-native-linear-gradient" :default LinearGradient]
|
||||
[reagent.core :as reagent]))
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def linear-gradient (reagent/adapt-react-class LinearGradient))
|
||||
(def ^:private linear-gradient* (reagent/adapt-react-class LinearGradient))
|
||||
|
||||
(defn- split-valid-colors
|
||||
[acc idx color]
|
||||
(let [color? (colors/valid-color? color)]
|
||||
(cond-> acc
|
||||
:always (update :safe-colors conj (if color? color "transparent"))
|
||||
(not color?) (update :wrong-colors conj [idx color]))))
|
||||
|
||||
(defn- wrong-colors-str
|
||||
[colors]
|
||||
(reduce-kv (fn [s idx color]
|
||||
(str s "Index: " idx ", color: " (prn-str color)))
|
||||
"Invalid color values in vector passed to Linear Gradient:\n"
|
||||
colors))
|
||||
|
||||
(defn linear-gradient
|
||||
[props & children]
|
||||
(when ^boolean js/goog.DEBUG
|
||||
(assert (vector? (:colors props))))
|
||||
(let [{:keys [wrong-colors safe-colors]} (rn/use-memo
|
||||
(fn []
|
||||
(reduce-kv split-valid-colors
|
||||
{:safe-colors []
|
||||
:wrong-colors {}}
|
||||
(:colors props)))
|
||||
[(:colors props)])]
|
||||
(when (seq wrong-colors)
|
||||
(log/error (wrong-colors-str wrong-colors)))
|
||||
(into [linear-gradient* (assoc props :colors safe-colors)]
|
||||
children)))
|
||||
|
8
src/react_native/net_info.cljs
Normal file
8
src/react_native/net_info.cljs
Normal file
@ -0,0 +1,8 @@
|
||||
(ns react-native.net-info
|
||||
(:require
|
||||
["@react-native-community/netinfo" :default net-info]))
|
||||
|
||||
(defn add-net-info-listener
|
||||
[callback]
|
||||
(when net-info
|
||||
(.addEventListener ^js net-info callback)))
|
@ -23,7 +23,7 @@
|
||||
(oops/ocall wc-utils
|
||||
"buildApprovedNamespaces"
|
||||
(bean/->js {:proposal proposal
|
||||
:supportedNamespaces supported-namespaces})))
|
||||
:supportedNamespaces (clj->js supported-namespaces)})))
|
||||
|
||||
;; Get an error from this list:
|
||||
;; https://github.com/WalletConnect/walletconnect-monorepo/blob/c6e9529418a0c81d4efcc6ac4e61f242a50b56c5/packages/utils/src/errors.ts
|
||||
|
24
src/status_im/common/data_confirmation_sheet/style.cljs
Normal file
24
src/status_im/common/data_confirmation_sheet/style.cljs
Normal file
@ -0,0 +1,24 @@
|
||||
(ns status-im.common.data-confirmation-sheet.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def heading
|
||||
{:padding-left 20
|
||||
:padding-bottom 8})
|
||||
|
||||
(def message
|
||||
{:padding-horizontal 20
|
||||
:padding-top 4})
|
||||
|
||||
(def warning
|
||||
{:margin-horizontal 20
|
||||
:margin-top 10})
|
||||
|
||||
(def drawer-container
|
||||
{:padding-horizontal 13
|
||||
:padding-top 16})
|
||||
|
||||
(def settings-subtext
|
||||
{:color colors/white-opa-70
|
||||
:align-self :center
|
||||
:margin-bottom 12})
|
||||
|
73
src/status_im/common/data_confirmation_sheet/view.cljs
Normal file
73
src/status_im/common/data_confirmation_sheet/view.cljs
Normal file
@ -0,0 +1,73 @@
|
||||
(ns status-im.common.data-confirmation-sheet.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.data-confirmation-sheet.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.navigation :as navigation]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn on-choice-callback
|
||||
[syncing-on-mobile-network?]
|
||||
(rf/dispatch [:network/set-syncing-on-mobile-network syncing-on-mobile-network?])
|
||||
(navigation/hide-bottom-sheet))
|
||||
|
||||
(def on-wifi-only (partial on-choice-callback false))
|
||||
(def on-mobile-and-wifi (partial on-choice-callback true))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [settings-drawer? (= (rf/sub [:view-id]) :screen/settings.syncing)
|
||||
syncing-on-mobile-network? (rf/sub [:profile/syncing-on-mobile-network?])]
|
||||
(rn/use-mount navigation/dismiss-keyboard)
|
||||
[:<>
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:size :heading-2
|
||||
:accessibility-label :data-confirmation-sheet-heading
|
||||
:style style/heading}
|
||||
(i18n/label (if settings-drawer? :t/sync-and-backup :t/which-connection-to-use))]
|
||||
[quo/text
|
||||
{:weight :regular
|
||||
:size :paragraph-1
|
||||
:accessibility-label :data-confirmation-sheet-message
|
||||
:style style/message}
|
||||
(i18n/label :t/syncing-connection-message)]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:icon :i/info
|
||||
:blur? true
|
||||
:style style/warning}
|
||||
(i18n/label :t/syncing-wifi-connection-warning)]
|
||||
(if settings-drawer?
|
||||
[rn/view {:style style/drawer-container}
|
||||
[quo/drawer-action
|
||||
{:title (i18n/label :t/mobile-data-and-wifi)
|
||||
:state (when syncing-on-mobile-network? :selected)
|
||||
:blur? true
|
||||
:accessibility-label :mobile-data-and-wifi-action
|
||||
:icon :i/connection
|
||||
:on-press on-mobile-and-wifi}]
|
||||
[quo/drawer-action
|
||||
{:title (i18n/label :t/wifi-only)
|
||||
:state (when-not syncing-on-mobile-network? :selected)
|
||||
:blur? true
|
||||
:accessibility-label :wifi-only-action
|
||||
:icon :i/placeholder
|
||||
:on-press on-wifi-only}]]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:blur? true
|
||||
:container-style {:margin-top 12}
|
||||
:button-one-label (i18n/label :t/wifi-only)
|
||||
:button-one-props {:type :grey
|
||||
:on-press on-wifi-only}
|
||||
:button-two-label (i18n/label :t/mobile-and-wifi)
|
||||
:button-two-props {:on-press on-mobile-and-wifi}}])
|
||||
(if settings-drawer?
|
||||
[quo/divider-line {:container-style {:padding-vertical 8}}]
|
||||
[quo/text
|
||||
{:weight :regular
|
||||
:size :paragraph-2
|
||||
:style style/settings-subtext}
|
||||
(i18n/label :t/you-can-change-later-in-settings)])]))
|
@ -3,21 +3,23 @@
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(defn content-container
|
||||
[blur? keyboard-shown?]
|
||||
[blur? keyboard-shown? {:keys [padding-vertical padding-horizontal]}]
|
||||
(let [margin-bottom (if keyboard-shown? 0 (safe-area/get-bottom))]
|
||||
(cond-> {:margin-top :auto
|
||||
:overflow :hidden
|
||||
:margin-bottom margin-bottom
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20}
|
||||
:padding-vertical (or padding-vertical 12)
|
||||
:padding-horizontal (or padding-horizontal 20)}
|
||||
blur? (dissoc :padding-vertical :padding-horizontal))))
|
||||
|
||||
(defn blur-inner-container
|
||||
[theme shell-overlay?]
|
||||
{:background-color (colors/theme-colors colors/white-70-blur
|
||||
(if shell-overlay?
|
||||
colors/neutral-80-opa-80-blur
|
||||
colors/neutral-95-opa-70-blur)
|
||||
theme)
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20})
|
||||
[{:keys [theme shell-overlay? padding-vertical padding-horizontal background-color]}]
|
||||
{:background-color (or background-color
|
||||
(colors/theme-colors
|
||||
colors/white-70-blur
|
||||
(if shell-overlay?
|
||||
colors/neutral-80-opa-80-blur
|
||||
colors/neutral-95-opa-70-blur)
|
||||
theme))
|
||||
:padding-vertical (or padding-vertical 12)
|
||||
:padding-horizontal (or padding-horizontal 20)})
|
||||
|
@ -6,20 +6,25 @@
|
||||
[status-im.common.floating-button-page.floating-container.style :as style]))
|
||||
|
||||
(defn- blur-container
|
||||
[child shell-overlay?]
|
||||
[shell-overlay? blur-options child]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[quo/blur
|
||||
{:blur-amount 20
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent}
|
||||
[rn/view {:style (style/blur-inner-container theme shell-overlay?)}
|
||||
(or blur-options
|
||||
{:blur-amount 20
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent})
|
||||
[rn/view
|
||||
{:style (style/blur-inner-container (assoc
|
||||
blur-options
|
||||
:theme theme
|
||||
:shell-overlay? shell-overlay?))}
|
||||
child]]))
|
||||
|
||||
(defn view
|
||||
[{:keys [on-layout keyboard-shown? blur? shell-overlay?]} child]
|
||||
[{:keys [on-layout keyboard-shown? blur? shell-overlay? blur-options]} child]
|
||||
[rn/view
|
||||
{:style (style/content-container blur? keyboard-shown?)
|
||||
{:style (style/content-container blur? keyboard-shown? blur-options)
|
||||
:on-layout on-layout}
|
||||
(if blur?
|
||||
[blur-container child shell-overlay?]
|
||||
[blur-container shell-overlay? blur-options child]
|
||||
child)])
|
||||
|
@ -13,3 +13,13 @@
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(defn content-keyboard-avoiding-view
|
||||
[{:keys [top bottom]}]
|
||||
{:position :absolute
|
||||
:top top
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom bottom})
|
||||
|
||||
(def scroll-view-container {:flex 1})
|
||||
|
@ -30,13 +30,15 @@
|
||||
(reset! ratom height))))
|
||||
|
||||
(defn- init-keyboard-listeners
|
||||
[{:keys [on-did-show scroll-view-ref]}]
|
||||
[{:keys [on-did-show on-will-show scroll-view-ref]}]
|
||||
(let [keyboard-will-show? (reagent/atom false)
|
||||
keyboard-did-show? (reagent/atom false)
|
||||
add-listener (fn [listener callback]
|
||||
(oops/ocall rn/keyboard "addListener" listener callback))
|
||||
will-show-listener (add-listener "keyboardWillShow"
|
||||
#(reset! keyboard-will-show? true))
|
||||
(fn [e]
|
||||
(reset! keyboard-will-show? true)
|
||||
(when on-will-show (on-will-show e))))
|
||||
did-show-listener (add-listener "keyboardDidShow"
|
||||
(fn [e]
|
||||
(reset! keyboard-did-show? true)
|
||||
@ -58,7 +60,8 @@
|
||||
|
||||
(defn view
|
||||
[{:keys [header footer customization-color footer-container-padding header-container-style
|
||||
content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay?]
|
||||
content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay?
|
||||
blur-options content-avoid-keyboard?]
|
||||
:or {footer-container-padding (safe-area/get-top)}}
|
||||
& children]
|
||||
(reagent/with-let [scroll-view-ref (atom nil)
|
||||
@ -69,29 +72,34 @@
|
||||
content-container-height (reagent/atom 0)
|
||||
content-scroll-y (reagent/atom 0)
|
||||
keyboard-height (reagent/atom 0)
|
||||
reset-keyboard-height #(reset! keyboard-height (oops/oget
|
||||
%
|
||||
"endCoordinates.height"))
|
||||
{:keys [keyboard-will-show?
|
||||
keyboard-did-show?
|
||||
remove-listeners]} (init-keyboard-listeners
|
||||
{:scroll-view-ref scroll-view-ref
|
||||
:on-did-show
|
||||
(fn [e]
|
||||
(reset! keyboard-height
|
||||
(oops/oget e "endCoordinates.height")))})
|
||||
(cond-> {:scroll-view-ref scroll-view-ref}
|
||||
platform/ios?
|
||||
(assoc :on-will-show reset-keyboard-height)
|
||||
(not platform/ios?)
|
||||
(assoc :on-did-show reset-keyboard-height)))
|
||||
set-header-height (set-height-on-layout header-height)
|
||||
set-content-container-height (set-height-on-layout content-container-height)
|
||||
set-footer-container-height (set-height-on-layout footer-container-height)
|
||||
set-content-y-scroll (fn [event]
|
||||
(reset! content-scroll-y
|
||||
(oops/oget event "nativeEvent.contentOffset.y")))]
|
||||
(oops/oget event "nativeEvent.contentOffset.y")))
|
||||
bottom-safe-area (safe-area/get-bottom)]
|
||||
(let [keyboard-shown? (if platform/ios? @keyboard-will-show? @keyboard-did-show?)
|
||||
footer-container-padding (+ footer-container-padding (rf/sub [:alert-banners/top-margin]))
|
||||
show-background? (show-background {:window-height window-height
|
||||
:footer-container-height @footer-container-height
|
||||
:keyboard-height @keyboard-height
|
||||
:content-scroll-y @content-scroll-y
|
||||
:content-container-height @content-container-height
|
||||
:header-height @header-height
|
||||
:keyboard-shown? keyboard-shown?})]
|
||||
show-background? (show-background
|
||||
{:window-height window-height
|
||||
:footer-container-height @footer-container-height
|
||||
:keyboard-height @keyboard-height
|
||||
:content-scroll-y @content-scroll-y
|
||||
:content-container-height @content-container-height
|
||||
:header-height @header-height
|
||||
:keyboard-shown? keyboard-shown?})]
|
||||
[:<>
|
||||
(when gradient-cover?
|
||||
[quo/gradient-cover {:customization-color customization-color}])
|
||||
@ -100,20 +108,28 @@
|
||||
{:on-layout set-header-height
|
||||
:style header-container-style}
|
||||
header]
|
||||
[gesture/scroll-view
|
||||
{:ref set-scroll-ref
|
||||
:on-scroll set-content-y-scroll
|
||||
:scroll-event-throttle 64
|
||||
:content-container-style {:flex-grow 1
|
||||
:padding-bottom (when @keyboard-did-show?
|
||||
@footer-container-height)}
|
||||
:always-bounce-vertical @keyboard-did-show?
|
||||
:shows-vertical-scroll-indicator false
|
||||
:keyboard-should-persist-taps keyboard-should-persist-taps}
|
||||
(into [rn/view
|
||||
{:style content-container-style
|
||||
:on-layout set-content-container-height}]
|
||||
children)]
|
||||
[(if content-avoid-keyboard? rn/keyboard-avoiding-view rn/view)
|
||||
{:style
|
||||
(if content-avoid-keyboard?
|
||||
(style/content-keyboard-avoiding-view
|
||||
{:top @header-height
|
||||
:bottom (if keyboard-shown?
|
||||
@footer-container-height
|
||||
(+ bottom-safe-area @footer-container-height))})
|
||||
style/scroll-view-container)}
|
||||
[gesture/scroll-view
|
||||
{:ref set-scroll-ref
|
||||
:on-scroll set-content-y-scroll
|
||||
:scroll-event-throttle 64
|
||||
:content-container-style {:flex-grow 1}
|
||||
:always-bounce-vertical @keyboard-did-show?
|
||||
:automatically-adjust-keyboard-insets true
|
||||
:shows-vertical-scroll-indicator false
|
||||
:keyboard-should-persist-taps keyboard-should-persist-taps}
|
||||
(into [rn/view
|
||||
{:style content-container-style
|
||||
:on-layout set-content-container-height}]
|
||||
children)]]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style style/keyboard-avoiding-view
|
||||
:keyboard-vertical-offset (if platform/ios? footer-container-padding 0)
|
||||
@ -121,8 +137,9 @@
|
||||
[floating-container/view
|
||||
{:on-layout set-footer-container-height
|
||||
:keyboard-shown? keyboard-shown?
|
||||
:blur? show-background?
|
||||
:shell-overlay? shell-overlay?}
|
||||
:blur-options blur-options
|
||||
:shell-overlay? shell-overlay?
|
||||
:blur? show-background?}
|
||||
footer]]]])
|
||||
(finally
|
||||
(remove-listeners))))
|
||||
|
@ -55,7 +55,7 @@
|
||||
{:dispatch (if user-in-sign-in-intro-screen?
|
||||
[:navigate-to-within-stack
|
||||
[:screen/onboarding.syncing-progress-intro :screen/onboarding.sign-in-intro]]
|
||||
[:navigate-to :screen/onboarding.syncing-progress])}
|
||||
[:open-modal :screen/onboarding.syncing-progress])}
|
||||
|
||||
(and completed-pairing? sender?)
|
||||
{:dispatch [:syncing/clear-states]}
|
||||
|
@ -1,14 +1,14 @@
|
||||
(ns status-im.common.raw-data-block.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im.common.raw-data-block.style :as style]))
|
||||
|
||||
(defn view
|
||||
[data]
|
||||
[rn/scroll-view
|
||||
{:style style/container
|
||||
:content-container-style style/content}
|
||||
[gesture/scroll-view
|
||||
{:style style/container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/content
|
||||
:weight :code}
|
||||
data]])
|
||||
|
@ -27,7 +27,9 @@
|
||||
:welcome-illustration (js/require "../resources/images/ui2/welcome_illustration.png")
|
||||
:notifications (js/require "../resources/images/ui2/notifications.png")
|
||||
:nfc-prompt (js/require "../resources/images/ui2/nfc-prompt.png")
|
||||
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")})
|
||||
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")
|
||||
:syncing-devices (js/require "../resources/images/ui2/syncing_devices.png")
|
||||
:syncing-wrong (js/require "../resources/images/ui2/syncing_wrong.png")})
|
||||
|
||||
(def ui-themed
|
||||
{:angry-man
|
||||
|
@ -1,7 +1,6 @@
|
||||
(ns status-im.common.signals.events
|
||||
(:require
|
||||
[legacy.status-im.chat.models.message :as models.message]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[legacy.status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||
[oops.core :as oops]
|
||||
[status-im.common.pairing.events :as pairing]
|
||||
@ -38,6 +37,15 @@
|
||||
"wallet"
|
||||
{:fx [[:dispatch [:wallet/signal-received event-js]]]}
|
||||
|
||||
"wallet.sign.transactions"
|
||||
{:fx [[:dispatch
|
||||
[:standard-auth/authorize-with-keycard
|
||||
{:on-complete #(rf/dispatch [:keycard/sign-hash %
|
||||
(first (transforms/js->clj event-js))])}]]]}
|
||||
|
||||
"wallet.suggested.routes"
|
||||
{:fx [[:dispatch [:wallet/handle-suggested-routes (transforms/js->clj event-js)]]]}
|
||||
|
||||
"envelope.sent"
|
||||
(messages.transport/update-envelopes-status
|
||||
cofx
|
||||
@ -57,15 +65,6 @@
|
||||
"messages.new"
|
||||
(messages.transport/sanitize-messages-and-process-response cofx event-js true)
|
||||
|
||||
"mailserver.changed"
|
||||
(mailserver/handle-mailserver-changed cofx (oops/oget event-js :id))
|
||||
|
||||
"mailserver.available"
|
||||
(mailserver/handle-mailserver-available cofx (oops/oget event-js :id))
|
||||
|
||||
"mailserver.not.working"
|
||||
(mailserver/handle-mailserver-not-working cofx)
|
||||
|
||||
"discovery.summary"
|
||||
(summary cofx (transforms/js->clj event-js))
|
||||
|
||||
|
@ -3,21 +3,35 @@
|
||||
[schema.core :as schema]
|
||||
[status-im.common.standard-authentication.enter-password.view :as enter-password]
|
||||
[status-im.common.standard-authentication.events-schema :as events-schema]
|
||||
[status-im.contexts.keycard.pin.view :as keycard.pin]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-fx :effects.keycard/call-on-auth-success
|
||||
(fn [on-auth-success]
|
||||
(when on-auth-success (on-auth-success ""))))
|
||||
|
||||
(defn authorize
|
||||
[{:keys [db]} [args]]
|
||||
[{:keys [db]} [{:keys [on-auth-success keycard-supported?] :as args}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
keycard? (get-in db [:profile/profile :keycard-pairing])]
|
||||
{:fx [[:effects.biometric/check-if-available
|
||||
{:key-uid key-uid
|
||||
:on-success #(rf/dispatch [:standard-auth/authorize-with-biometric args])
|
||||
:on-fail (if keycard?
|
||||
#(rf/dispatch [:standard-auth/authorize-with-keycard args])
|
||||
#(rf/dispatch [:standard-auth/authorize-with-password args]))}]]}))
|
||||
{:fx
|
||||
[(if keycard?
|
||||
(if keycard-supported?
|
||||
[:effects.keycard/call-on-auth-success on-auth-success]
|
||||
[:effects.utils/show-popup
|
||||
{:title "This feature is not supported yet "
|
||||
:content
|
||||
"Keycard support is limited to logging in
|
||||
and signing the sending transaction.
|
||||
Use Status Desktop to access all functions."}])
|
||||
[:effects.biometric/check-if-available
|
||||
{:key-uid key-uid
|
||||
:on-success #(rf/dispatch [:standard-auth/authorize-with-biometric args])
|
||||
:on-fail #(rf/dispatch [:standard-auth/authorize-with-password args])}])]}))
|
||||
|
||||
(schema/=> authorize events-schema/?authorize)
|
||||
(rf/reg-event-fx :standard-auth/authorize authorize)
|
||||
@ -94,6 +108,16 @@
|
||||
:button-icon-left auth-button-icon-left
|
||||
:button-label auth-button-label}])))
|
||||
|
||||
(defn authorize-with-keycard
|
||||
[_ [{:keys [on-complete]}]]
|
||||
{:fx [[:dispatch
|
||||
[:show-bottom-sheet
|
||||
{:hide-on-background-press? false
|
||||
:on-close #(rf/dispatch [:standard-auth/reset-login-password])
|
||||
:content (fn []
|
||||
[keycard.pin/auth {:on-complete on-complete}])}]]]})
|
||||
(rf/reg-event-fx :standard-auth/authorize-with-keycard authorize-with-keycard)
|
||||
|
||||
(defn authorize-with-password
|
||||
[_ [{:keys [on-close theme blur?] :as args}]]
|
||||
{:fx [[:dispatch [:standard-auth/reset-login-password]]
|
||||
@ -110,7 +134,9 @@
|
||||
(rf/reg-event-fx
|
||||
:standard-auth/reset-login-password
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update db :profile/login dissoc :password :error)}))
|
||||
{:db (-> db
|
||||
(update :profile/login dissoc :password :error)
|
||||
(update :keycard dissoc :pin))}))
|
||||
|
||||
(rf/reg-fx
|
||||
:standard-auth/on-close
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
(defn view
|
||||
[{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail
|
||||
auth-button-icon-left size blur? container-style disabled? dependencies]
|
||||
auth-button-icon-left size blur? container-style disabled? dependencies keycard-supported?]
|
||||
:or {container-style {:flex 1}}}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
auth-method (rf/sub [:auth-method])
|
||||
@ -21,6 +21,7 @@
|
||||
:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:keycard-supported? keycard-supported?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
|
@ -125,6 +125,9 @@
|
||||
(def fetch-messages-enabled? (enabled? (get-config :FETCH_MESSAGES_ENABLED "1")))
|
||||
(def test-networks-enabled? (enabled? (get-config :TEST_NETWORKS_ENABLED "0")))
|
||||
|
||||
(def mobile-data-syncing-toggle-enabled?
|
||||
(enabled? (get-config :MOBILE_DATA_SYNCING_TOGGLE_ENABLE "1")))
|
||||
|
||||
;; Alert banners are disabled for debug builds because alert banners overlay
|
||||
;; interfere with react-native debug tools, such as inspector and Perf monitor
|
||||
(def enable-alert-banner? (enabled? (get-config :ENABLE_ALERT_BANNER "0")))
|
||||
|
@ -291,6 +291,7 @@
|
||||
(def ^:const wallet-connect-session-delete-event "session_delete")
|
||||
(def ^:const wallet-connect-user-rejected-error-key "USER_REJECTED")
|
||||
(def ^:const wallet-connect-user-disconnected-reason-key "USER_DISCONNECTED")
|
||||
(def ^:const wallet-connect-user-rejected-chains-error-key "USER_REJECTED_CHAINS")
|
||||
|
||||
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
|
||||
|
||||
@ -553,11 +554,21 @@
|
||||
(def ^:const send-type-erc-721-transfer 6)
|
||||
(def ^:const send-type-erc-1155-transfer 7)
|
||||
|
||||
(def ^:const multi-transaction-type-send 0)
|
||||
(def ^:const multi-transaction-type-approve 1)
|
||||
(def ^:const multi-transaction-type-bridge 2)
|
||||
(def ^:const multi-transaction-type-swap 3)
|
||||
(def ^:const multi-transaction-type-unknown 255)
|
||||
|
||||
(def ^:const contract-function-signature-erc20-approve "approve(address,uint256)")
|
||||
|
||||
(def ^:const bridge-name-transfer "Transfer")
|
||||
(def ^:const bridge-name-erc-721-transfer "ERC721Transfer")
|
||||
(def ^:const bridge-name-erc-1155-transfer "ERC1155Transfer")
|
||||
(def ^:const bridge-name-hop "Hop")
|
||||
|
||||
(def ^:const bridge-assets #{"ETH" "USDT" "USDC" "DAI"})
|
||||
|
||||
(def ^:const wallet-contract-type-uknown 0)
|
||||
(def ^:const wallet-contract-type-erc-20 1)
|
||||
(def ^:const wallet-contract-type-erc-721 2)
|
||||
|
@ -33,3 +33,7 @@
|
||||
(def drawer-message-container
|
||||
{:padding-top 4
|
||||
:padding-bottom 4})
|
||||
|
||||
(def group-member-mention
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
@ -126,14 +126,60 @@
|
||||
:photo-path photo-path
|
||||
:incoming? (not= public-key from)}]))
|
||||
|
||||
(defn group-member
|
||||
[literal]
|
||||
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity literal])
|
||||
photo-path (rf/sub [:chats/photo-path literal])]
|
||||
[rn/view {:style style/group-member-mention}
|
||||
[quo/user-avatar
|
||||
{:full-name primary-name
|
||||
:profile-picture photo-path
|
||||
:status-indicator? false
|
||||
:size :xxxs
|
||||
:ring? false}]
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:style {:margin-left 4}}
|
||||
primary-name]]))
|
||||
|
||||
|
||||
(defn resolve-group-system-message
|
||||
[{:keys [children]}]
|
||||
(reduce (fn [acc {:keys [type literal]}]
|
||||
(if (= type "mention")
|
||||
(conj acc [group-member literal])
|
||||
(conj acc
|
||||
[rn/view
|
||||
[quo/text literal]])))
|
||||
[:<>]
|
||||
children))
|
||||
|
||||
|
||||
(defn render-parsed-text
|
||||
[content]
|
||||
(reduce (fn [acc e]
|
||||
(conj acc (resolve-group-system-message e)))
|
||||
[quo/text]
|
||||
(:parsed-text content)))
|
||||
|
||||
(defn group-system-message
|
||||
[{:keys [chat-id timestamp-str content]} type]
|
||||
(let [{:keys [customization-color]} (rf/sub [:contacts/contact-by-address chat-id])]
|
||||
[quo/system-message
|
||||
{:type type
|
||||
:timestamp timestamp-str
|
||||
:customization-color customization-color
|
||||
:child (render-parsed-text content)}]))
|
||||
|
||||
(defn system-message-content
|
||||
[{:keys [content-type quoted-message] :as message-data}]
|
||||
|
||||
(if quoted-message
|
||||
[pin/pinned-message message-data]
|
||||
(condp = content-type
|
||||
|
||||
constants/content-type-system-text
|
||||
[system.text/text-content message-data]
|
||||
[group-system-message message-data :group]
|
||||
|
||||
constants/content-type-system-pinned-message
|
||||
[system.text/text-content message-data]
|
||||
|
@ -1,7 +1,5 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.link-preview.events
|
||||
(:require [camel-snake-kebab.core :as csk]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.collection]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@ -35,17 +33,6 @@
|
||||
{:fx [[:dispatch
|
||||
[:profile.settings/profile-update :link-preview-request-enabled (boolean enabled?)]]]}))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/link-preview-whitelist-received
|
||||
(fn [{:keys [db]} [whitelist]]
|
||||
{:db (assoc db :link-previews-whitelist whitelist)}))
|
||||
|
||||
(rf/reg-fx :chat.ui/request-link-preview-whitelist
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_getLinkPreviewWhitelist"
|
||||
:params []
|
||||
:on-success [:chat.ui/link-preview-whitelist-received]
|
||||
:on-error #(log/error "Failed to get link preview whitelist")})))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/enable-link-previews
|
||||
(fn [{{:profile/keys [profile]} :db} [site enabled?]]
|
||||
(let [enabled-sites (if enabled?
|
||||
|
@ -103,11 +103,11 @@
|
||||
(models.contact/process-js-contacts cofx response-js)
|
||||
|
||||
(seq communities)
|
||||
(let [communities-clj (types/js->clj communities)]
|
||||
(do
|
||||
(js-delete response-js "communities")
|
||||
(rf/merge cofx
|
||||
(process-next response-js sync-handler)
|
||||
(communities/handle-communities communities-clj)))
|
||||
(communities/handle-communities communities)))
|
||||
|
||||
(seq bookmarks)
|
||||
(let [bookmarks-clj (types/js->clj bookmarks)]
|
||||
|
@ -26,7 +26,7 @@
|
||||
"0xD" {:address "0xD"
|
||||
:operable? false
|
||||
:position 3
|
||||
:color :flamingo
|
||||
:color :pink
|
||||
:emoji "🦩"}})
|
||||
|
||||
(def permissioned-accounts
|
||||
|
@ -22,7 +22,7 @@
|
||||
airdrop-account (rf/sub [:communities/airdrop-account id])
|
||||
revealed-accounts (rf/sub [:communities/accounts-to-reveal id])
|
||||
revealed-accounts-count (count revealed-accounts)
|
||||
wallet-accounts-count (count (rf/sub [:wallet/operable-accounts-without-watched-accounts]))
|
||||
wallet-accounts-count (count (rf/sub [:wallet/operable-accounts]))
|
||||
addresses-shared-text (if (= revealed-accounts-count wallet-accounts-count)
|
||||
(i18n/label :t/all-addresses)
|
||||
(i18n/label-pluralize
|
||||
|
@ -57,19 +57,24 @@
|
||||
:index index})
|
||||
|
||||
(defn- members
|
||||
[items theme]
|
||||
[rn/section-list
|
||||
{:key-fn :public-key
|
||||
:content-container-style {:padding-bottom 20}
|
||||
:get-item-layout get-item-layout
|
||||
:content-inset-adjustment-behavior :never
|
||||
:sections items
|
||||
:sticky-section-headers-enabled false
|
||||
:render-section-header-fn contact-list/contacts-section-header
|
||||
:render-section-footer-fn footer
|
||||
:render-data {:theme theme}
|
||||
:render-fn contact-item
|
||||
:scroll-event-throttle 32}])
|
||||
[community-id chat-id theme]
|
||||
(let [online-members (rf/sub [:communities/chat-members-sorted community-id chat-id :online])
|
||||
offline-members (rf/sub [:communities/chat-members-sorted community-id chat-id :offline])]
|
||||
[rn/section-list
|
||||
{:key-fn :public-key
|
||||
:content-container-style {:padding-bottom 20}
|
||||
:get-item-layout get-item-layout
|
||||
:content-inset-adjustment-behavior :never
|
||||
:sections [{:title (i18n/label :t/online)
|
||||
:data online-members}
|
||||
{:title (i18n/label :t/offline)
|
||||
:data offline-members}]
|
||||
:sticky-section-headers-enabled false
|
||||
:render-section-header-fn contact-list/contacts-section-header
|
||||
:render-section-footer-fn footer
|
||||
:render-data {:theme theme}
|
||||
:render-fn contact-item
|
||||
:scroll-event-throttle 32}]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
@ -78,8 +83,6 @@
|
||||
{:keys [description chat-name emoji muted chat-type color]
|
||||
:as chat} (rf/sub [:chats/chat-by-id chat-id])
|
||||
pins-count (rf/sub [:chats/pin-messages-count chat-id])
|
||||
items (rf/sub [:communities/sorted-community-members-section-list
|
||||
community-id chat-id])
|
||||
theme (quo.theme/use-theme)]
|
||||
(rn/use-mount (fn []
|
||||
(rf/dispatch [:pin-message/load-pin-messages chat-id])))
|
||||
@ -133,4 +136,4 @@
|
||||
(if muted
|
||||
(home.actions/unmute-chat-action chat-id)
|
||||
(home.actions/mute-chat-action chat-id chat-type muted)))}]}]]]
|
||||
[members items theme]]))
|
||||
[members community-id chat-id theme]]))
|
||||
|
@ -54,7 +54,7 @@
|
||||
:as item}]
|
||||
(let [user-selected? (rf/sub [:is-contact-selected? public-key])
|
||||
{:keys [id]} (rf/sub [:get-screen-params])
|
||||
community-members-keys (set (keys (rf/sub [:communities/community-members id])))
|
||||
community-members-keys (set (rf/sub [:communities/community-members id]))
|
||||
community-member? (boolean (community-members-keys public-key))
|
||||
on-toggle (fn []
|
||||
(when-not community-member?
|
||||
|
@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.data-store.communities :as data-store.communities]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[schema.core :as schema]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
|
||||
@ -39,17 +38,6 @@
|
||||
|
||||
(rf/reg-event-fx :communities/handle-community handle-community)
|
||||
|
||||
(schema/=> handle-community
|
||||
[:=>
|
||||
[:catn
|
||||
[:cofx :schema.re-frame/cofx]
|
||||
[:args
|
||||
[:schema [:catn [:community-js map?]]]]]
|
||||
[:maybe
|
||||
[:map
|
||||
[:db [:map [:communities map?]]]
|
||||
[:fx vector?]]]])
|
||||
|
||||
(rf/defn handle-removed-chats
|
||||
[{:keys [db]} chat-ids]
|
||||
{:db (reduce (fn [db chat-id]
|
||||
@ -84,10 +72,9 @@
|
||||
|
||||
(rf/defn handle-communities
|
||||
{:events [:community/fetch-success]}
|
||||
[{:keys [db]} communities]
|
||||
{:fx
|
||||
(->> communities
|
||||
(map #(vector :dispatch [:communities/handle-community %])))})
|
||||
[{:keys [db]} communities-js]
|
||||
{:fx (map (fn [c] [:dispatch [:communities/handle-community c]])
|
||||
communities-js)})
|
||||
|
||||
(rf/reg-event-fx :communities/request-to-join-result
|
||||
(fn [{:keys [db]} [community-id request-id response-js]]
|
||||
@ -136,21 +123,30 @@
|
||||
{}
|
||||
categories))}))
|
||||
|
||||
(rf/reg-event-fx :community/fetch-low-priority
|
||||
(fn []
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_checkAndDeletePendingRequestToJoinCommunity"
|
||||
:params []
|
||||
:js-response true
|
||||
:on-success [:sanitize-messages-and-process-response]
|
||||
:on-error #(log/info "failed to fetch communities" %)}
|
||||
{:method "wakuext_collapsedCommunityCategories"
|
||||
:params []
|
||||
:on-success [:communities/fetched-collapsed-categories-success]
|
||||
:on-error #(log/error "failed to fetch collapsed community categories" %)}]]]}))
|
||||
|
||||
(rf/reg-event-fx :community/fetch
|
||||
(fn [_]
|
||||
{:json-rpc/call [{:method "wakuext_serializedCommunities"
|
||||
:params []
|
||||
:on-success #(rf/dispatch [:community/fetch-success %])
|
||||
:on-error #(log/error "failed to fetch communities" %)}
|
||||
{:method "wakuext_checkAndDeletePendingRequestToJoinCommunity"
|
||||
:params []
|
||||
:js-response true
|
||||
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
|
||||
:on-error #(log/info "failed to fetch communities" %)}
|
||||
{:method "wakuext_collapsedCommunityCategories"
|
||||
:params []
|
||||
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
|
||||
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_serializedCommunities"
|
||||
:params []
|
||||
:on-success [:community/fetch-success]
|
||||
:js-response true
|
||||
:on-error #(log/error "failed to fetch communities" %)}]]
|
||||
;; Dispatch a little after 1000ms because other higher-priority events
|
||||
;; after login are being processed at the 1000ms mark.
|
||||
[:dispatch-later [{:ms 1200 :dispatch [:community/fetch-low-priority]}]]]}))
|
||||
|
||||
(defn update-previous-permission-addresses
|
||||
[{:keys [db]} [community-id]]
|
||||
@ -291,8 +287,7 @@
|
||||
(when-let [community (first communities)]
|
||||
{:db (-> db
|
||||
(assoc-in [:communities (:id community) :spectated] true))
|
||||
:fx [[:dispatch [:communities/handle-community community]]
|
||||
[:dispatch [::mailserver/request-messages]]]}))
|
||||
:fx [[:dispatch [:communities/handle-community community]]]}))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/spectate-community-success spectate-community-success)
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
(ns status-im.contexts.communities.events-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
matcher-combinators.test
|
||||
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
|
||||
[status-im.contexts.communities.events :as events]))
|
||||
@ -112,7 +111,7 @@
|
||||
(testing "dispatch fxs for first community"
|
||||
(is (match?
|
||||
{:fx [[:dispatch [:communities/handle-community {:id community-id}]]
|
||||
[:dispatch [::mailserver/request-messages]]]}
|
||||
]}
|
||||
(events/spectate-community-success {} [{:communities [{:id community-id}]}])))))
|
||||
(testing "given empty community"
|
||||
(testing "do nothing"
|
||||
@ -151,7 +150,7 @@
|
||||
(-> effects :json-rpc/call first (select-keys [:method :params]))))))))
|
||||
|
||||
(deftest handle-community-test
|
||||
(let [community {:id community-id :clock 2}]
|
||||
(let [community #js {:id community-id :clock 2}]
|
||||
(testing "given a unjoined community"
|
||||
(let [effects (events/handle-community {} [community])]
|
||||
(is (match? community-id
|
||||
@ -163,7 +162,7 @@
|
||||
(filter some? (:fx effects))))))
|
||||
|
||||
(testing "given a joined community"
|
||||
(let [community (assoc community :joined true)
|
||||
(let [community #js {:id community-id :clock 2 :joined true}
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (match?
|
||||
[[:dispatch
|
||||
@ -172,16 +171,19 @@
|
||||
(filter some? (:fx effects))))))
|
||||
|
||||
(testing "given a community with token-permissions-check"
|
||||
(let [community (assoc community :token-permissions-check :fake-token-permissions-check)
|
||||
(let [community #js
|
||||
{:id community-id :clock 2 :token-permissions-check :fake-token-permissions-check}
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (match?
|
||||
[[:dispatch
|
||||
[:communities/check-permissions-to-join-community-with-all-addresses community-id]]]
|
||||
(filter some? (:fx effects))))))
|
||||
|
||||
(testing "given a community with lower clock"
|
||||
(let [effects (events/handle-community {:db {:communities {community-id {:clock 3}}}} [community])]
|
||||
(is (nil? effects))))
|
||||
|
||||
(testing "given a community without clock"
|
||||
(let [community (dissoc community :clock)
|
||||
(let [community #js {:id community-id}
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (nil? effects))))))
|
||||
|
@ -75,46 +75,51 @@
|
||||
:banner (resources/get-image :discover)
|
||||
:accessibility-label :communities-home-discover-card}})
|
||||
|
||||
(defn on-tab-change
|
||||
[tab]
|
||||
(rf/dispatch [:communities/select-tab tab]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [flat-list-ref (atom nil)
|
||||
set-flat-list-ref #(reset! flat-list-ref %)]
|
||||
(fn []
|
||||
(let [theme (quo.theme/use-theme)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
selected-tab (or (rf/sub [:communities/selected-tab]) :joined)
|
||||
{:keys [joined pending opened]} (rf/sub [:communities/grouped-by-status])
|
||||
selected-items (case selected-tab
|
||||
:joined joined
|
||||
:pending pending
|
||||
:opened opened)
|
||||
scroll-shared-value (reanimated/use-shared-value 0)]
|
||||
[:<>
|
||||
(if (empty? selected-items)
|
||||
[common.empty-state/view
|
||||
{:selected-tab selected-tab
|
||||
:tab->content (empty-state-content theme)}]
|
||||
[reanimated/flat-list
|
||||
{:ref set-flat-list-ref
|
||||
:key-fn :id
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [common.header-spacing/view]
|
||||
:render-fn item-render
|
||||
:style {:margin-top -1}
|
||||
:data selected-items
|
||||
:scroll-event-throttle 8
|
||||
:content-container-style {:padding-bottom
|
||||
jump-to.constants/floating-shell-button-height}
|
||||
:on-scroll #(common.banner/set-scroll-shared-value
|
||||
{:scroll-input (oops/oget
|
||||
%
|
||||
"nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})}])
|
||||
[:f> common.banner/animated-banner
|
||||
{:content banner-data
|
||||
:customization-color customization-color
|
||||
:scroll-ref flat-list-ref
|
||||
:tabs tabs-data
|
||||
:selected-tab selected-tab
|
||||
:on-tab-change (fn [tab] (rf/dispatch [:communities/select-tab tab]))
|
||||
:scroll-shared-value scroll-shared-value}]]))))
|
||||
(let [flat-list-ref (rn/use-ref-atom nil)
|
||||
set-flat-list-ref (rn/use-callback #(reset! flat-list-ref %))
|
||||
theme (quo.theme/use-theme)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
selected-tab (or (rf/sub [:communities/selected-tab]) :joined)
|
||||
{:keys [joined pending opened]} (rf/sub [:communities/grouped-by-status])
|
||||
selected-items (case selected-tab
|
||||
:joined joined
|
||||
:pending pending
|
||||
:opened opened)
|
||||
scroll-shared-value (reanimated/use-shared-value 0)
|
||||
on-scroll (rn/use-callback
|
||||
(fn [event]
|
||||
(common.banner/set-scroll-shared-value
|
||||
{:scroll-input (oops/oget event
|
||||
"nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})))]
|
||||
[:<>
|
||||
(if (empty? selected-items)
|
||||
[common.empty-state/view
|
||||
{:selected-tab selected-tab
|
||||
:tab->content (empty-state-content theme)}]
|
||||
[reanimated/flat-list
|
||||
{:ref set-flat-list-ref
|
||||
:key-fn :id
|
||||
:content-inset-adjustment-behavior :never
|
||||
:header [common.header-spacing/view]
|
||||
:render-fn item-render
|
||||
:style {:margin-top -1}
|
||||
:data selected-items
|
||||
:scroll-event-throttle 8
|
||||
:content-container-style {:padding-bottom
|
||||
jump-to.constants/floating-shell-button-height}
|
||||
:on-scroll on-scroll}])
|
||||
[common.banner/animated-banner
|
||||
{:content banner-data
|
||||
:customization-color customization-color
|
||||
:scroll-ref flat-list-ref
|
||||
:tabs tabs-data
|
||||
:selected-tab selected-tab
|
||||
:on-tab-change on-tab-change
|
||||
:scroll-shared-value scroll-shared-value}]]))
|
||||
|
@ -109,3 +109,22 @@
|
||||
[pairings]
|
||||
(keycard/set-pairings pairings))
|
||||
(rf/reg-fx :effects.keycard/set-pairing-to-keycard set-pairing-to-keycard)
|
||||
|
||||
(defn sign
|
||||
[{:keys [on-success on-failure] :as args}]
|
||||
(log/debug "[keycard] sign")
|
||||
(keycard/sign
|
||||
(assoc
|
||||
args
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] sign")
|
||||
(when on-success
|
||||
(on-success (transforms/js->clj response))))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/warn "[keycard response fail] sign"
|
||||
(error-object->map response))
|
||||
(when on-failure
|
||||
(on-failure (error-object->map response)))))))
|
||||
(rf/reg-fx :effects.keycard/sign sign)
|
||||
|
@ -3,6 +3,8 @@
|
||||
status-im.contexts.keycard.login.events
|
||||
status-im.contexts.keycard.pin.events
|
||||
status-im.contexts.keycard.sheet.events
|
||||
status-im.contexts.keycard.sign.events
|
||||
[status-im.contexts.keycard.utils :as keycard.utils]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-check-nfc-enabled-success
|
||||
@ -55,3 +57,19 @@
|
||||
(fn [{:keys [db]} [{:keys [on-cancel-event-vector]}]]
|
||||
(log/debug "[keycard] nfc started success")
|
||||
{:db (assoc-in db [:keycard :on-nfc-cancelled-event-vector] on-cancel-event-vector)}))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-action-with-pin-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
(log/debug "[keycard] get keys error: " error)
|
||||
(let [tag-was-lost? (keycard.utils/tag-lost? (:error error))
|
||||
pin-retries-count (keycard.utils/pin-retries (:error error))]
|
||||
(if tag-was-lost?
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(if (nil? pin-retries-count)
|
||||
{:effects.utils/show-popup {:title "wrong-keycard"}}
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||
(update-in [:keycard :pin] assoc :status :error))
|
||||
:fx [[:dispatch [:keycard/hide-connection-sheet]]
|
||||
(when (zero? pin-retries-count)
|
||||
[:effects.utils/show-popup {:title "frozen-keycard"}])]})))))
|
||||
|
@ -3,22 +3,6 @@
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :keycard.login/on-get-keys-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
(log/debug "[keycard] get keys error: " error)
|
||||
(let [tag-was-lost? (keycard.utils/tag-lost? (:error error))
|
||||
pin-retries-count (keycard.utils/pin-retries (:error error))]
|
||||
(if tag-was-lost?
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(if (nil? pin-retries-count)
|
||||
{:effects.utils/show-popup {:title "wrong-keycard"}}
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||
(update-in [:keycard :pin] assoc :status :error))
|
||||
:fx [[:dispatch [:keycard/hide-connection-sheet]]
|
||||
(when (zero? pin-retries-count)
|
||||
[:effects.utils/show-popup {:title "frozen-keycard"}])]})))))
|
||||
|
||||
(rf/reg-event-fx :keycard.login/on-get-keys-success
|
||||
(fn [{:keys [db]} [data]]
|
||||
(let [{:keys [key-uid encryption-public-key
|
||||
@ -56,28 +40,25 @@
|
||||
:key-uid key-uid}]]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard.login/on-get-application-info-success
|
||||
(fn [{:keys [db]} [application-info]]
|
||||
(let [profile (get-in db [:profile/profiles-overview (get-in db [:profile/login :key-uid])])
|
||||
pin (get-in db [:keycard :pin :text])
|
||||
error (keycard.utils/validate-application-info profile application-info)]
|
||||
(fn [{:keys [db]} [application-info {:keys [key-uid on-read-fx]}]]
|
||||
(let [error (keycard.utils/validate-application-info key-uid application-info)]
|
||||
(if error
|
||||
{:effects.utils/show-popup {:title (str error)}}
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info] application-info)
|
||||
(assoc-in [:keycard :pin :status] :verifying))
|
||||
:effects.keycard/get-keys {:pin pin
|
||||
:on-success #(rf/dispatch [:keycard.login/on-get-keys-success %])
|
||||
:on-failure #(rf/dispatch [:keycard.login/on-get-keys-error %])}}))))
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info] application-info)
|
||||
(assoc-in [:keycard :pin :status] :verifying))
|
||||
:fx on-read-fx}))))
|
||||
|
||||
(rf/reg-event-fx :keycard.login/cancel-reading-card
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :on-card-connected-event-vector] nil)}))
|
||||
|
||||
(rf/reg-event-fx :keycard/read-card-and-login
|
||||
(fn [{:keys [db]}]
|
||||
(rf/reg-event-fx :keycard/read-card
|
||||
(fn [{:keys [db]} [args]]
|
||||
(let [connected? (get-in db [:keycard :card-connected?])
|
||||
event-vector [:keycard/get-application-info
|
||||
{:on-success #(rf/dispatch [:keycard.login/on-get-application-info-success %])}]]
|
||||
{:on-success #(rf/dispatch [:keycard.login/on-get-application-info-success %
|
||||
args])}]]
|
||||
(log/debug "[keycard] proceed-to-login")
|
||||
{:db (assoc-in db [:keycard :on-card-connected-event-vector] event-vector)
|
||||
:fx [[:dispatch
|
||||
|
@ -9,13 +9,17 @@
|
||||
(assoc-in [:keycard :pin :text] (.slice pin 0 -1))
|
||||
(assoc-in [:keycard :pin :status] nil))}))))
|
||||
|
||||
(rf/reg-fx :effects.keycard.pin/dispatch-on-complete
|
||||
(fn [[on-complete new-pin]]
|
||||
(on-complete new-pin)))
|
||||
|
||||
(rf/reg-event-fx :keycard.pin/number-pressed
|
||||
(fn [{:keys [db]} [number max-numbers on-complete-event]]
|
||||
(fn [{:keys [db]} [number max-numbers on-complete]]
|
||||
(let [pin (get-in db [:keycard :pin :text])
|
||||
new-pin (str pin number)]
|
||||
(when (<= (count new-pin) max-numbers)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :text] new-pin)
|
||||
(assoc-in [:keycard :pin :status] nil))
|
||||
:fx [(when (= (dec max-numbers) (count pin))
|
||||
[:dispatch [on-complete-event]])]}))))
|
||||
:fx [(when (and on-complete (= (dec max-numbers) (count pin)))
|
||||
[:effects.keycard.pin/dispatch-on-complete [on-complete new-pin]])]}))))
|
||||
|
@ -6,7 +6,7 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn auth
|
||||
[callback-event-key]
|
||||
[{:keys [on-complete]}]
|
||||
(let [{:keys [text status]} (rf/sub [:keycard/pin])
|
||||
pin-retry-counter (rf/sub [:keycard/pin-retry-counter])
|
||||
error? (= status :error)]
|
||||
@ -23,4 +23,4 @@
|
||||
{:delete-key? true
|
||||
:on-delete #(rf/dispatch [:keycard.pin/delete-pressed])
|
||||
:on-press #(rf/dispatch [:keycard.pin/number-pressed % constants/pincode-length
|
||||
callback-event-key])}]]))
|
||||
on-complete])}]]))
|
||||
|
29
src/status_im/contexts/keycard/sign/events.cljs
Normal file
29
src/status_im/contexts/keycard/sign/events.cljs
Normal file
@ -0,0 +1,29 @@
|
||||
(ns status-im.contexts.keycard.sign.events
|
||||
(:require [utils.address]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn get-signature-map
|
||||
[tx-hash signature]
|
||||
{tx-hash {:r (subs signature 0 64)
|
||||
:s (subs signature 64 128)
|
||||
:v (str (js/parseInt (subs signature 128 130) 16))}})
|
||||
|
||||
(rf/reg-event-fx :keycard/sign-hash
|
||||
(fn [{:keys [db]} [pin-text tx-hash]]
|
||||
(let [current-address (get-in db [:wallet :current-viewing-account-address])
|
||||
path (get-in db [:wallet :accounts current-address :path])
|
||||
key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/read-card
|
||||
{:key-uid key-uid
|
||||
:on-read-fx [[:effects.keycard/sign
|
||||
{:pin pin-text
|
||||
:path path
|
||||
:hash (utils.address/naked-address tx-hash)
|
||||
:on-success
|
||||
#(do
|
||||
(rf/dispatch [:keycard/hide-connection-sheet])
|
||||
(rf/dispatch
|
||||
[:wallet/proceed-with-transactions-signatures
|
||||
(get-signature-map tx-hash %)]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}]]]})))
|
@ -16,8 +16,8 @@
|
||||
(re-matches #".*NFCError:100.*" error)))
|
||||
|
||||
(defn validate-application-info
|
||||
[profile {:keys [key-uid paired? pin-retry-counter puk-retry-counter] :as application-info}]
|
||||
(let [profile-mismatch? (or (nil? profile) (not= (:key-uid profile) key-uid))]
|
||||
[profile-key-uid {:keys [key-uid paired? pin-retry-counter puk-retry-counter] :as application-info}]
|
||||
(let [profile-mismatch? (or (nil? profile-key-uid) (not= profile-key-uid key-uid))]
|
||||
(log/debug "[keycard] login-with-keycard"
|
||||
"empty application info" (empty? application-info)
|
||||
"no key-uid" (empty? key-uid)
|
||||
|
17
src/status_im/contexts/network/effects.cljs
Normal file
17
src/status_im/contexts/network/effects.cljs
Normal file
@ -0,0 +1,17 @@
|
||||
(ns status-im.contexts.network.effects
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[react-native.net-info :as net-info]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.network/listen-to-network-info
|
||||
(fn []
|
||||
(net-info/add-net-info-listener
|
||||
#(rf/dispatch [:network/on-state-change
|
||||
(js->clj % :keywordize-keys true)]))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.network/notify-status-go
|
||||
(fn [network-type expensive?]
|
||||
(native-module/connection-change network-type expensive?)))
|
76
src/status_im/contexts/network/events.cljs
Normal file
76
src/status_im/contexts/network/events.cljs
Normal file
@ -0,0 +1,76 @@
|
||||
(ns status-im.contexts.network.events
|
||||
(:require
|
||||
[status-im.common.data-confirmation-sheet.view :as data-confirmation-sheet]
|
||||
[status-im.config :as config]
|
||||
[status-im.feature-flags :as ff]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :network/set-syncing-on-mobile-network
|
||||
(fn [{:keys [db]} [syncing-on-mobile-network?]]
|
||||
(when config/mobile-data-syncing-toggle-enabled?
|
||||
{:db (update db
|
||||
:profile/profile
|
||||
assoc
|
||||
:syncing-on-mobile-network?
|
||||
syncing-on-mobile-network?
|
||||
:remember-syncing-choice?
|
||||
true)
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setSyncingOnMobileNetwork"
|
||||
:params [{:enabled syncing-on-mobile-network?}]
|
||||
:on-success #(log/debug "successfully set syncing-on-mobile-network"
|
||||
syncing-on-mobile-network?)
|
||||
:on-error #(log/error "could not set syncing-on-mobile-network" %)}]]]})))
|
||||
|
||||
(rf/reg-event-fx :network/check-expensive-connection
|
||||
(fn [{:keys [db]}]
|
||||
(when
|
||||
(and (:network/expensive? db)
|
||||
config/mobile-data-syncing-toggle-enabled?
|
||||
(:profile/profile db)
|
||||
(not (get-in db [:profile/profile :remember-syncing-choice?])))
|
||||
;; Note here we are only updating :remember-syncing-choice? temporarily to avoid opening
|
||||
;; multiple bottom sheets and the user might again see the sheet on the next login. Unless the
|
||||
;; user makes a syncing choice that will persist this key in the status-go
|
||||
{:db (assoc-in db [:profile/profile :remember-syncing-choice?] true)
|
||||
:fx [[:dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn [] [data-confirmation-sheet/view])
|
||||
:shell? true
|
||||
:theme :dark}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:network/on-state-change
|
||||
(fn [{:keys [db]} [{:keys [isConnected type details]}]]
|
||||
(let [old-network-status (:network/status db)
|
||||
old-network-type (:network/type db)
|
||||
connectivity-status (if isConnected :online :offline)
|
||||
status-changed? (not= connectivity-status old-network-status)
|
||||
type-changed? (not= type old-network-type)
|
||||
expensive? (:isConnectionExpensive details)]
|
||||
(log/debug "[net-info]"
|
||||
"old-network-status" old-network-status
|
||||
"old-network-type" old-network-type
|
||||
"connectivity-status" connectivity-status
|
||||
"type" type
|
||||
"details" details)
|
||||
{:db (assoc db :network/expensive? expensive?)
|
||||
:fx [[:dispatch [:network/check-expensive-connection]]
|
||||
(when status-changed?
|
||||
[:dispatch [:network/on-network-status-change connectivity-status]])
|
||||
(when type-changed?
|
||||
[:dispatch [:network/on-network-type-change type expensive?]])]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:network/on-network-type-change
|
||||
(fn [{:keys [db]} [network-type expensive?]]
|
||||
{:db (assoc db :network/type network-type)
|
||||
:fx [[:effects.network/notify-status-go network-type expensive?]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:network/on-network-status-change
|
||||
(fn [{:keys [db]} [connectivity-status]]
|
||||
{:db (assoc db :network/status connectivity-status)
|
||||
:fx [(when (ff/enabled? ::ff/wallet.wallet-connect)
|
||||
[:dispatch [:wallet-connect/reload-on-network-change (= :online connectivity-status)]])]}))
|
@ -2,8 +2,6 @@
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(def flex-fill {:flex 1})
|
||||
|
||||
(def heading {:margin-bottom 20})
|
||||
(def heading-subtitle {:color colors/white})
|
||||
(def heading-title (assoc heading-subtitle :margin-bottom 8))
|
||||
@ -14,23 +12,15 @@
|
||||
(def space-between-inputs {:height 16})
|
||||
|
||||
(def password-tips
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 20})
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 20})
|
||||
|
||||
(def top-part
|
||||
{:margin-horizontal 20
|
||||
:margin-top 12})
|
||||
(def form-container
|
||||
{:justify-content :space-between
|
||||
:padding-top 12
|
||||
:padding-horizontal 20})
|
||||
|
||||
(def bottom-part
|
||||
{:flex 1
|
||||
:margin-top 12
|
||||
:justify-content :flex-end})
|
||||
|
||||
(def disclaimer-container
|
||||
{:margin-horizontal 20
|
||||
:margin-vertical 4})
|
||||
|
||||
(def button-container
|
||||
{:margin-horizontal 20
|
||||
:margin-vertical 12})
|
||||
(def disclaimer-container {:padding-horizontal 20})
|
||||
(def footer-container {:padding-bottom 12})
|
||||
(def footer-button-container {:margin-top 20 :padding-horizontal 20})
|
||||
|
@ -1,11 +1,11 @@
|
||||
(ns status-im.contexts.onboarding.create-password.view
|
||||
(:require
|
||||
[oops.core :refer [ocall]]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.floating-button-page.view :as floating-button]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.onboarding.create-password.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
@ -94,7 +94,7 @@
|
||||
[quo/tips {:completed? symbols?}
|
||||
(i18n/label :t/password-creation-tips-4)]]])
|
||||
|
||||
(defn password-validations
|
||||
(defn validate-password
|
||||
[password]
|
||||
(let [validations (juxt utils.string/has-lower-case?
|
||||
utils.string/has-upper-case?
|
||||
@ -111,68 +111,25 @@
|
||||
(filter true?)
|
||||
count))
|
||||
|
||||
(defn password-form
|
||||
[]
|
||||
(let [password (reagent/atom "")
|
||||
repeat-password (reagent/atom "")
|
||||
accepts-disclaimer? (reagent/atom false)
|
||||
focused-input (reagent/atom nil)
|
||||
show-password-validation? (reagent/atom false)
|
||||
same-password-length? #(and (seq @password)
|
||||
(= (count @password) (count @repeat-password)))]
|
||||
(fn []
|
||||
(let [{user-color :color} (rf/sub [:onboarding/profile])
|
||||
{:keys [long-enough?]
|
||||
:as validations} (password-validations @password)
|
||||
password-strength (calc-password-strength validations)
|
||||
empty-password? (empty? @password)
|
||||
same-passwords? (and (not empty-password?) (= @password @repeat-password))
|
||||
meet-requirements? (and (not empty-password?)
|
||||
(utils.string/at-least-n-chars? @password 10)
|
||||
same-passwords?
|
||||
@accepts-disclaimer?)]
|
||||
[:<>
|
||||
[rn/view {:style style/top-part}
|
||||
[header]
|
||||
[password-inputs
|
||||
{:password-long-enough? long-enough?
|
||||
:passwords-match? same-passwords?
|
||||
:empty-password? empty-password?
|
||||
:show-password-validation? @show-password-validation?
|
||||
:on-input-focus #(reset! focused-input :password)
|
||||
:on-change-password (fn [new-value]
|
||||
(reset! password new-value)
|
||||
(when (same-password-length?)
|
||||
(reset! show-password-validation? true)))
|
||||
:on-change-repeat-password (fn [new-value]
|
||||
(reset! repeat-password new-value)
|
||||
(when (same-password-length?)
|
||||
(reset! show-password-validation? true)))
|
||||
:on-blur-repeat-password #(if empty-password?
|
||||
(reset! show-password-validation? false)
|
||||
(reset! show-password-validation? true))}]]
|
||||
(defn- use-password-checks
|
||||
[password]
|
||||
(rn/use-memo
|
||||
(fn []
|
||||
(let [{:keys [long-enough?]
|
||||
:as validations} (validate-password password)]
|
||||
{:password-long-enough? long-enough?
|
||||
:password-validations validations
|
||||
:password-strength (calc-password-strength validations)
|
||||
:empty-password? (empty? password)}))
|
||||
[password]))
|
||||
|
||||
[rn/view {:style style/bottom-part}
|
||||
(when same-passwords?
|
||||
[rn/view {:style style/disclaimer-container}
|
||||
[quo/disclaimer
|
||||
{:blur? true
|
||||
:on-change #(swap! accepts-disclaimer? not)
|
||||
:checked? @accepts-disclaimer?}
|
||||
(i18n/label :t/password-creation-disclaimer)]])
|
||||
(when (and (= @focused-input :password) (not same-passwords?))
|
||||
[help
|
||||
{:validations validations
|
||||
:password-strength password-strength}])
|
||||
|
||||
[rn/view {:style style/button-container}
|
||||
[quo/button
|
||||
{:disabled? (not meet-requirements?)
|
||||
:customization-color user-color
|
||||
:on-press #(rf/dispatch
|
||||
[:onboarding/password-set
|
||||
(security/mask-data @password)])}
|
||||
(i18n/label :t/password-creation-confirm)]]]]))))
|
||||
(defn- use-repeat-password-checks
|
||||
[password repeat-password]
|
||||
(rn/use-memo
|
||||
(fn []
|
||||
{:same-password-length? (and (seq password) (= (count password) (count repeat-password)))
|
||||
:same-passwords? (and (seq password) (= password repeat-password))})
|
||||
[password repeat-password]))
|
||||
|
||||
(defn create-password-doc
|
||||
[]
|
||||
@ -183,38 +140,108 @@
|
||||
[quo/text {:size :paragraph-2}
|
||||
(i18n/label :t/create-profile-password-info-box-description)]]])
|
||||
|
||||
(defn- on-press-info
|
||||
[]
|
||||
(rn/dismiss-keyboard!)
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content create-password-doc
|
||||
:shell? true}]))
|
||||
|
||||
(defn- navigate-back
|
||||
[]
|
||||
(rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn- page-nav
|
||||
[]
|
||||
(let [{:keys [top]} (safe-area/get-insets)]
|
||||
[quo/page-nav
|
||||
{:margin-top top
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press navigate-back
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press on-press-info}]}]))
|
||||
|
||||
(defn create-password
|
||||
[]
|
||||
(reagent/with-let [keyboard-shown? (reagent/atom false)
|
||||
{:keys [top bottom]} (safe-area/get-insets)
|
||||
will-show-listener (ocall rn/keyboard
|
||||
"addListener"
|
||||
"keyboardWillShow"
|
||||
#(reset! keyboard-shown? true))
|
||||
will-hide-listener (ocall rn/keyboard
|
||||
"addListener"
|
||||
"keyboardWillHide"
|
||||
#(reset! keyboard-shown? false))
|
||||
on-press-info (fn []
|
||||
(rn/dismiss-keyboard!)
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content create-password-doc
|
||||
:shell? true}]))]
|
||||
[:<>
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press rn/dismiss-keyboard!
|
||||
:accessible false}
|
||||
[rn/view {:style style/flex-fill}
|
||||
[rn/keyboard-avoiding-view {:style style/flex-fill}
|
||||
[quo/page-nav
|
||||
{:margin-top top
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press on-press-info}]}]
|
||||
[password-form]
|
||||
[rn/view {:style {:height (if-not @keyboard-shown? bottom 0)}}]]]]]
|
||||
(finally
|
||||
(ocall will-show-listener "remove")
|
||||
(ocall will-hide-listener "remove"))))
|
||||
(let [[password set-password] (rn/use-state "")
|
||||
[repeat-password set-repeat-password] (rn/use-state "")
|
||||
[accepts-disclaimer? set-accepts-disclaimer?] (rn/use-state false)
|
||||
[focused-input set-focused-input] (rn/use-state nil)
|
||||
[show-password-validation?
|
||||
set-show-password-validation?] (rn/use-state false)
|
||||
{user-color :color} (rf/sub [:onboarding/profile])
|
||||
|
||||
|
||||
{:keys [password-long-enough?
|
||||
password-validations password-strength
|
||||
empty-password?]} (use-password-checks password)
|
||||
|
||||
{:keys [same-password-length? same-passwords?]} (use-repeat-password-checks password
|
||||
repeat-password)
|
||||
|
||||
meet-requirements? (rn/use-memo
|
||||
#(and (not empty-password?)
|
||||
(utils.string/at-least-n-chars? password
|
||||
10)
|
||||
same-passwords?
|
||||
accepts-disclaimer?)
|
||||
[password repeat-password
|
||||
accepts-disclaimer?])]
|
||||
|
||||
[floating-button/view
|
||||
{:header [page-nav]
|
||||
:keyboard-should-persist-taps :handled
|
||||
:content-avoid-keyboard? true
|
||||
:blur-options
|
||||
{:blur-amount 34
|
||||
:blur-radius 20
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur)
|
||||
:padding-vertical 0
|
||||
:padding-horizontal 0}
|
||||
:footer-container-padding 0
|
||||
:footer
|
||||
[rn/view
|
||||
{:style style/footer-container}
|
||||
(when same-passwords?
|
||||
[rn/view {:style style/disclaimer-container}
|
||||
[quo/disclaimer
|
||||
{:blur? true
|
||||
:on-change (partial set-accepts-disclaimer? not)
|
||||
:checked? accepts-disclaimer?}
|
||||
(i18n/label :t/password-creation-disclaimer)]])
|
||||
(when (and (= focused-input :password) (not same-passwords?))
|
||||
[help
|
||||
{:validations password-validations
|
||||
:password-strength password-strength}])
|
||||
[quo/button
|
||||
{:container-style style/footer-button-container
|
||||
:disabled? (not meet-requirements?)
|
||||
:customization-color user-color
|
||||
:on-press #(rf/dispatch
|
||||
[:onboarding/password-set
|
||||
(security/mask-data password)])}
|
||||
(i18n/label :t/password-creation-confirm)]]}
|
||||
|
||||
[rn/view {:style style/form-container}
|
||||
[header]
|
||||
[password-inputs
|
||||
{:password-long-enough? password-long-enough?
|
||||
:passwords-match? same-passwords?
|
||||
:empty-password? empty-password?
|
||||
:show-password-validation? show-password-validation?
|
||||
:on-input-focus #(set-focused-input :password)
|
||||
:on-change-password (fn [new-value]
|
||||
(set-password new-value)
|
||||
(when same-password-length?
|
||||
(set-show-password-validation? true)))
|
||||
|
||||
:on-change-repeat-password (fn [new-value]
|
||||
(set-repeat-password new-value)
|
||||
(when same-password-length?
|
||||
(set-show-password-validation? true)))
|
||||
:on-blur-repeat-password #(if empty-password?
|
||||
(set-show-password-validation? false)
|
||||
(set-show-password-validation? true))}]]]))
|
||||
|
@ -38,7 +38,7 @@
|
||||
(rf/dispatch [:push-notifications/switch true])
|
||||
(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/onboarding.welcome
|
||||
:screen/onboarding.generating-keys]]))
|
||||
:screen/onboarding.enable-notifications]]))
|
||||
:type :primary
|
||||
:icon-left :i/notifications
|
||||
:accessibility-label :enable-notifications-button
|
||||
@ -52,7 +52,7 @@
|
||||
nil)
|
||||
(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/onboarding.welcome
|
||||
:screen/onboarding.generating-keys]]))
|
||||
:screen/onboarding.enable-notifications]]))
|
||||
:accessibility-label :enable-notifications-later-button
|
||||
:type :grey
|
||||
:background :blur
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user