Compare commits

...
Author SHA1 Message Date
Ajay Sivan 3e563e7302 Implement Community Permissions Drawer
Fix bottom sheet bg color

Remove comment

Remove detail-token-view from screens

Show Permissions button on request to join screen

Community overview icon color fix

Replace dummy sheet on overview screen with permissions sheet

Passing community id properly to the bottomsheet

Show permission drawer button only when there is membership permission or user meets the requirements

Fix Permission Listing

Remove dead code

Remove anonymous functions

Empty member permission block - fix

Remove unused styles

Lint fix

New events to get all permission checks
2024-03-19 09:21:52 +05:30
Mohamed Javid 10c6bf7156 [Fix] Chain down toast shown for chains unrelated to current network (#19155)
This commit fixes chain down toast shown for chains unrelated to the current network.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-03-16 16:29:16 +05:30
Jamie Caprani d0d7310e82 feat(wallet): add ability to remove wallet account (#19121) 2024-03-15 14:20:28 -07:00
Jamie Caprani 219dd7cb46 chore(quo): add profile - collectibles list item component (#19125) 2024-03-15 13:58:04 -07:00
Parvesh Monu 9da0559b15 fix keycard crash (#19275) 2024-03-15 19:17:55 +05:30
Shivek Khurana aa7db8b883 💾 🗂️ [17653] wallet implement UI for save address bottom sheet (#19079)
* 🚧 Save address UI reached teenage years

* 🚧 Save point

* 📑 Use bottom sheet effect properly

* 📝 Can't get title input to work

* 🎨 Design in place

* 🗺️ Add address box and trigger for network prefs

* 💅 Pixel perfect UI and hide save address button

*  Upgrade to screen tech

* 🤚 Undo changes made to color picker during rebase

* 🧰 Fix screens I broke during rebase

* ❄️ Fix json indent

* ⚒️ Implement PR feedback

* ⛏️ Remove unrelated translations

* 🖼️ Remove container to fix margin issue

- Use rn/use-callback instead of defined functions

* 😶‍🌫️ Hide save address button

* 🔨 Fix lint

*  Remove bottom sheet screen updates

*  Remove empty lines between elements
2024-03-15 10:54:04 +00:00
Brian Sztamfater a06c5fdc02 fix: view-id not updating when navigating inside modals (#19163) 2024-03-14 13:56:30 -03:00
BalogunofAfrica 2a515a82ce fix: polish new chat (#19054) 2024-03-14 17:30:23 +01:00
flexsurfer 69294b196f Display discord bridged posts #19233 (#19248) 2024-03-14 13:46:00 +01:00
BalogunofAfrica 58606dc87c fix: handle limit event (#19066) 2024-03-14 13:13:29 +01:00
Parvesh Monu bccf0f8d11 re add progress root and popover overlay (#19241) 2024-03-14 16:48:08 +05:30
Lungu Cristian aab62dd19e Fix channel-action component (#19031)
* feat: added separate channel-action component & fixed pressed color

* feat: added channel-action preview screen

* fix: moved channel-action/s into separate dirs

* fix: channel-action style prop

* fix: renamed color prop to customization-color

* fix: small button width should be fixed

* fix: removed temp file

* style: formatting
2024-03-14 11:56:47 +02:00
Alexander fa9645d6dd Partial handlers update (re-frame/reg-event-fx instead of rf/defn) (#19005)
* Handlers update (re-frame/reg-event-fx instead of rf/defn)

* Fixes

* Fixes

* Fixes
2024-03-14 10:24:37 +01:00
yqrashawn 614b03d701 fix: duplicate sub key :communities/fetching-community (#18890) 2024-03-14 09:50:06 +08:00
flexsurfer e26d3a856d migrate reagent part 3 (#19165) 2024-03-13 16:46:44 +01:00
Mohsen 98cdf00276 [#19132] feat: block contact with remove contact checkbox (#19213) 2024-03-13 18:33:19 +03:00
flexsurfer eb379791c9 migrate reagent part4 (#19167) 2024-03-13 15:43:39 +01:00
Parvesh Monu 6bda54266b Refactor navigation files (#19068) 2024-03-13 19:09:09 +05:30
flexsurfer 1a8bca56e0 migrate reagent record audio component part5 (#19212) 2024-03-13 14:27:22 +01:00
codemaster 296d868797 fix: remove biometric button in the login screen when disabled biometrics (#19112) 2024-03-13 06:13:20 -07:00
Andrea Maria Piana e002fab376 cache processed description 2024-03-13 12:38:47 +00:00
Icaro Motta 4fa9a27cd9 Rewrite contract tests to use new promise-based API (#19208) 2024-03-13 09:38:32 -03:00
mmilad75 dbcdb18818 The wrong validation is applied for entered amount within send assets page #18751 (#18937) 2024-03-13 14:23:19 +03:30
Ibrahem Khalil 2009199c25 feat: Add internal link preview for communities (#18484) 2024-03-13 00:49:19 +02:00
Sean Hagstrom 103c4b4653 chore: decode emoji-hash and bio from contact payload (#19030) 2024-03-12 17:42:11 +00:00
Flavio Fraschetti 0828e9aa55 Fraschetti/18343 - Add contract test for wallet_getDerivedAddresses and move legacy code
Add contract test for wallet_getDerivedAddresses and move legacy code
2024-03-12 13:21:23 -03:00
Sean Hagstrom 0efdea6962 Feature: Ignore / Dismiss contact requests from contact profile (#19166)
* chore: add english translation for "contact request ignored"

* feature: integrate action to ignore contact request and display toast

* wip: default to showing "send contact request" after ignoring contact request
2024-03-12 13:48:21 +00:00
Sean Hagstrom d4c8e48441 Add action to remove contact inside contact action menu (#19168)
* chore: add english translation for "Remove contact"

* feature: integrate remove-contact acton in contact-profile action menu
2024-03-12 13:34:59 +00:00
Jamie Caprani 2931ae84ee chore(navigation): qualify wallet screen keywords (#18778) 2024-03-12 11:22:04 +00:00
Lungu Cristian 637efa24cf Clean up biometrics and standard-auth and add tests (#18756)
* ref(biometric): events using reg-event-fx & other

* test(biometric-events): show-message

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix(biometrics): removed unnecessary event

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* test(biometrics): tests & schemas for events

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref(standard-auth): refactored authorize

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* test(biometrics): fixed event tests

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref(standard-auth): authorize using events

* feat(standard-auth): schemas and removed old auth

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* test(standard-auth): added integration tests

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat(biometric): added missing schema

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref(biometrics): moved schemas to a separate file

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix(biometric): pressing biometric quickly errors

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: removed namespaced keywords for errors

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref: removed the use of vector cb for biometric fx

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: removed :maybe from fx schema

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref: remove event-fx schema

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: added nested biometrics db keys

* fix: using ExceptionInfo for the error schema

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* test: removed clearing fixture and small refactor

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: reset db password inside standard-authentication

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref: use naming convention for effects

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref: renamed not-canceled? to success?

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* rev: removed biometrics schemas :(

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: removed set-in & fix on-close bug

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: onboarding biometric not triggered

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: invalid props bug on onboarding welcome

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: moved side effect cb call into effect

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* test: moved integration test to new location

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: password input theme

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: disabled biometric not triggering fail when checking biometric

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

---------

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>
2024-03-12 12:14:56 +02:00
Jamie Caprani c57e5cd6db chore: improve share wallet test (#19107) 2024-03-12 08:44:59 +00:00
Parvesh Monu 604e232bda Implement alert banner (#19011) 2024-03-12 14:03:37 +05:30
Volodymyr Kozieiev e4997a2088 Root keys named :wallet/... moved as nested under :wallet root key (#19152) 2024-03-11 21:19:48 +00:00
Sean Hagstrom 459bf1621a Show toast after sending contact request (#19144)
* chore: add english translations for "Contact request sent"

* feature: add toast notification when sending a contact request
2024-03-11 10:10:50 +00:00
Sean Hagstrom ca9346a931 Implement reviewal of contact requests from contact profile (#19119)
* chore: add english translation for contact-request-review

* feature: integrate contact-request-review button

* tweak: render the locked-input label when provided

* tweak: allow locked-input component to grow in height

* chore: add english translation for "ignore"

* feature: add subscription for retrieving a pending contact-request by contact-id

* feature: integrate initial contact request review flow

* tweak: display send-message button on contact profile when contact-request-state is mutual

* tidy: refactor button-wrapper view to be button container-styles

* feature: add toast for accepting contact request
2024-03-11 09:43:18 +00:00
Mohsen 7065f4abd2 [#19101] feat: share contact profile (#19154) 2024-03-10 18:56:45 +03:00
Mohsen e283a72454 [#19048] feat: show contact QR code (#19139) 2024-03-09 00:36:24 +03:00
Ulises Manuel 3c6923963d [#18736] add address to watch using an ENS (#19043)
* Add capability to register an address based on an ENS

* update tests

* Check for existing addresses using an ENS
2024-03-08 12:20:41 -06:00
Mohsen 7a6714eeb2 [#18929] fix: no bottom space under the join button (#18987) 2024-03-08 19:24:02 +03:00
Alexander b3bebe1859 Update status-go version to fix the issue with peer syncing migration (#19127)
* Update `status-go` version to fix the issue with peer syncing migration

https://github.com/status-im/status-go/compare/8e8c1614...f9e7caa5

* Latest `commit-sha1`

* Fixes
2024-03-08 13:41:10 +01:00
Ulises Manuel ad546f9f14 [#18608] Immprove collectibles fetching performance (#18921)
* Add memoized versions to convert keys

* Add placeholder for SVG collectibles due to errors and warnings

* Add events to request collectibles per account

* Update subs to list all accounts collectibles evenly

* Update collectibles tab to pull new data when end is reached

* Use memoized version of key transformation
2024-03-07 12:05:45 -06:00
Mohsen 3145ecd6bf [#19037] feat: new design for manage nickname (#19085) 2024-03-07 15:23:07 +03:00
frank 669a232ad9 fix: peer exchange (#19082) 2024-03-07 18:10:17 +08:00
yqrashawn 29e69c54bd build: less node_modules recopy from nix (#19120) 2024-03-07 13:30:36 +08:00
flexsurfer 5fd0b27589 [#18985] Polish group details view (#19032) 2024-03-06 16:36:52 +01:00
Mohamed Javid 7d6b2ac87a [Feature] Wallet - Handle Blockchain Status (#18850)
This commit adds the feature to handle blockchain status signals from the status-go and shows a toast if the provider for any of the blockchains is down.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-03-06 20:59:52 +05:30
Jamie CapraniandYevheniia Berdnyk 93f488e61a chore(wallet): remove legacy network settings options (#18955)
* e2e: removed unused element

---------

Co-authored-by: Yevheniia Berdnyk <ie.berdnyk@gmail.com>
2024-03-06 07:05:05 -08:00
Sean Hagstrom f7498ef81f Implement Contact Request flow in Contact Profile (#19039)
* chore: add send-contact-request to i18n translations

* feature: add send-contact-request button on contact profile

* chore: prop drill full-name and profile-picture for the context-tag inside drawer-top component

* chore: add english translation for contact-request-message-prompt text

* feature: integrate contact-request sheet

* tidy: subscribe to contact data inside contact-request view

* tidy: wrap callback with use-callback

* tweak: hide contact-request button if contact-request is already sent
2024-03-06 12:57:02 +00:00
Ibrahem Khalil f1834c6a15 Sort communities by currently active tab (#18812) 2024-03-06 13:13:58 +02:00
Mohamed Javid ffcca1aea3 [Chore] Remove POKT Sepolia and Goerli RPC URL (#19040)
This commit removes the POKT (Grove) URL for Sepolia and Goerli as POKT dropped support.
Now, we will use Infura RPC for Sepolia and Goerli as default.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-03-06 15:50:36 +05:30
Ibrahem Khalil 0937da9e50 Fix usage of ratom to fix wallet share (#18883) 2024-03-06 10:46:48 +02:00
yqrashawn 33e637ff71 fix(style): :resize-method is not avaliable on ios (#18914) 2024-03-06 15:25:43 +08:00
Parvesh Monu a538e2896e fix Blink of shell screen occurs when the Scan sync button is tapped (#19104) 2024-03-06 10:16:58 +05:30
flexsurfer c02cc5d391 The wrong UI is applied for 'sync code' section when light mode is en… (#19110) 2024-03-05 18:59:02 +01:00
Parvesh Monu 613e48ece3 fix the mention highlighted area is only updated after reopening the chat (#19076) 2024-03-05 21:06:22 +05:30
298 changed files with 7201 additions and 5441 deletions
+31 -31
View File
@@ -22,37 +22,37 @@
:multi-lhs-hang]
:fn-map
{"reg-sub" :arg1-pair
"h/describe" :arg1-body
"h/describe-skip" :arg1-body
"h/describe-only" :arg1-body
"h/test" :arg1-body
"h/test-skip" :arg1-body
"h/test-only" :arg1-body
"test/async" :arg1-body
"test/use-fixtures" :arg1-body
"global.describe" :arg1-body
"global.test" :arg1-body
"list-comp" :binding
"defview" :arg1-body
"letsubs" :binding
"with-let" "let"
"reg-event-fx" :arg1-pair
"reg-fx" :arg1-pair
"testing" :arg1-body
"deftest-sub" :arg1-body
"h/integration-test" :arg1-body
"wait-for" :arg1-body
"with-deps-check" :arg1-body
"schema/=>" :arg1-body
"->" [:noarg1-body
{:list {:constant-pair? false :force-nl? false}
:next-inner-restore [[:list :constant-pair?]]}]
"set!" "reset!"
"assoc-when" "assoc"
"assoc-some" "assoc"
"conj-when" "conj"
"conj-some" "conj"}
{"reg-sub" :arg1-pair
"h/describe" :arg1-body
"h/describe-skip" :arg1-body
"h/describe-only" :arg1-body
"h/test" :arg1-body
"h/test-skip" :arg1-body
"h/test-only" :arg1-body
"test/async" :arg1-body
"test/use-fixtures" :arg1-body
"global.describe" :arg1-body
"global.test" :arg1-body
"list-comp" :binding
"defview" :arg1-body
"letsubs" :binding
"with-let" "let"
"reg-event-fx" :arg1-pair
"reg-fx" :arg1-pair
"testing" :arg1-body
"deftest-sub" :arg1-body
"test-async" :arg1-body
"wait-for" :arg1-body
"with-deps-check" :arg1-body
"schema/=>" :arg1-body
"->" [:noarg1-body
{:list {:constant-pair? false :force-nl? false}
:next-inner-restore [[:list :constant-pair?]]}]
"set!" "reset!"
"assoc-when" "assoc"
"assoc-some" "assoc"
"conj-when" "conj"
"conj-some" "conj"}
:style-map
{:no-comma {:map {:comma? false}}
+5 -3
View File
@@ -331,13 +331,14 @@ shadow-server:##@ Start shadow-cljs in server mode for watching
_test-clojure: export TARGET := clojure
_test-clojure: export WATCH ?= false
_test-clojure: status-go-library
_test-clojure:
ifeq ($(WATCH), true)
yarn install && \
yarn node-pre-gyp rebuild && \
yarn shadow-cljs compile mocks && \
nodemon --exec "yarn shadow-cljs compile test && node --require ./test-resources/override.js $$SHADOW_OUTPUT_TO" -e cljs
else
yarn install && \
yarn node-pre-gyp rebuild && \
yarn shadow-cljs compile mocks && \
yarn shadow-cljs compile test && \
node --require ./test-resources/override.js "$$SHADOW_OUTPUT_TO"
@@ -350,8 +351,9 @@ test: _test-clojure
test-watch-for-repl: export SHADOW_OUTPUT_TO := target/test/test.js
test-watch-for-repl: export SHADOW_NS_REGEXP := .*-test$$
test-watch-for-repl: status-go-library
test-watch-for-repl: ##@test Watch all Clojure tests and support REPL connections
yarn install
yarn node-pre-gyp rebuild
rm -f target/test/test.js
yarn shadow-cljs compile mocks && \
concurrently --kill-others --prefix-colors 'auto' --names 'build,repl' \
@@ -1888,6 +1888,36 @@ void _InitLogging(const FunctionCallbackInfo<Value>& args) {
delete c;
}
void _RestoreAccountAndLogin(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.Length() != 1) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8Literal(isolate, "Wrong number of arguments for RestoreAccountAndLogin")));
return;
}
// Check the argument types
if (!args[0]->IsString()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8Literal(isolate, "Wrong argument type for 'RestoreAccountAndLogin'")));
return;
}
String::Utf8Value arg0Obj(isolate, args[0]->ToString(context).ToLocalChecked());
char *arg0 = *arg0Obj;
// Call exported Go function, which returns a C string
char *c = RestoreAccountAndLogin(arg0);
Local<String> ret = String::NewFromUtf8(isolate, c).ToLocalChecked();
args.GetReturnValue().Set(ret);
delete c;
}
void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "multiAccountGenerateAndDeriveAddresses", _MultiAccountGenerateAndDeriveAddresses);
@@ -1945,6 +1975,7 @@ void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "connectionChange", _ConnectionChange);
NODE_SET_METHOD(exports, "pollSignal", _PollSignal);
NODE_SET_METHOD(exports, "initLogging", _InitLogging);
NODE_SET_METHOD(exports, "restoreAccountAndLogin", _RestoreAccountAndLogin);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, init)
+10
View File
@@ -53,6 +53,14 @@ copyNodeModules() {
# Find files that were modified and should cause a re-copying of node modules.
# Some files are generated/modified by build processes and should be ignored.
#
# react-native/ReactCommon/react/renderer/components/rncore/*
# generated at runtime by react-native
# related code https://github.com/facebook/react-native/blob/v0.72.5/packages/react-native/ReactCommon/React-rncore.podspec#L19
#
# react-native-config/ios/ReactNativeConfig/GeneratedDotEnv.m
# generated at runtime by react-native-config
# related code https://github.com/lugg/react-native-config/blob/v1.5.0/react-native-config.podspec#L52
findFilesNewerThan() {
local sentinel="${1}"
local dir="${2}"
@@ -61,6 +69,8 @@ findFilesNewerThan() {
-not -ipath "*/*android/build/*" -prune \
-not -ipath "*/xcuserdata/*" -prune \
-not -ipath "*/scripts/.packager.env" \
-not -path "*/node_modules/react-native/ReactCommon/react/renderer/components/rncore/*" \
-not -path "*/node_modules/react-native-config/ios/ReactNativeConfig/GeneratedDotEnv.m" \
-print
}
+9 -13
View File
@@ -3,7 +3,6 @@
["eth-phishing-detect" :as eth-phishing-detect]
[clojure.string :as string]
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
[legacy.status-im.browser.eip3085 :as eip3085]
[legacy.status-im.browser.eip3326 :as eip3326]
[legacy.status-im.browser.permissions :as browser.permissions]
[legacy.status-im.browser.webview-ref :as webview-ref]
@@ -16,6 +15,7 @@
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[react-native.platform :as platform]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.universal-links :as links]
[status-im.constants :as constants]
[status-im.contexts.chat.events :as chat.events]
@@ -443,9 +443,6 @@
(= method "wallet_switchEthereumChain")
(eip3326/handle-switch-ethereum-chain cofx dapp-name id message-id (first params))
(= method "wallet_addEthereumChain")
(eip3085/handle-add-ethereum-chain cofx dapp-name id message-id (first params))
:else
{:browser/call-rpc [payload
#(re-frame/dispatch [:browser.callback/call-rpc
@@ -658,12 +655,11 @@
stored-bookmarks)]
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
(rf/defn initialize-browser
[_]
{:json-rpc/call
[{:method "wakuext_getBrowsers"
:on-success #(re-frame/dispatch [::initialize-browsers %])}
{:method "browsers_getBookmarks"
:on-success #(re-frame/dispatch [::initialize-bookmarks %])}
{:method "permissions_getDappPermissions"
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
(re-frame/reg-fx :browser/initialize-browser
(fn []
(json-rpc/call {:method "wakuext_getBrowsers"
:on-success [::initialize-browsers]})
(json-rpc/call {:method "browsers_getBookmarks"
:on-success [::initialize-bookmarks]})
(json-rpc/call {:method "permissions_getDappPermissions"
:on-success [::initialize-dapp-permissions]})))
-38
View File
@@ -2,10 +2,6 @@
;(`wallet_addEthereumChain`)
(ns legacy.status-im.browser.eip3085
(:require
[clojure.string :as string]
[legacy.status-im.network.core :as network]
[legacy.status-im.ui.screens.browser.eip3085.sheet :as sheet]
[legacy.status-im.utils.random :as random]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[taoensso.timbre :as log]
@@ -40,37 +36,3 @@
:message "User rejected the request."}}
:dispatch [:bottom-sheet/hide-old]})
(rf/defn handle-add-ethereum-chain
{:events [:eip3085/handle-add-ethereum-chain]}
[{{:networks/keys [networks] :as db} :db :as cofx}
dapp-name id message-id
{:keys [chainId blockExplorerUrls chainName iconUrls nativeCurrency rpcUrls] :as params}]
(let [manage {:name {:value chainName}
:symbol {:value (:symbol nativeCurrency)}
:url {:value (first rpcUrls)}
:network-id {:value chainId}
:chain {:value :custom}}]
(if (network/valid-manage? manage)
(let [{:keys [name url chain network-id symbol]} manage
random-id (string/replace (random/id) "-" "")
network (network/new-network random-id
(:value name)
(:value symbol)
(:value url)
(:value chain)
(:value network-id))
new-networks (assoc networks random-id network)
params (assoc params
:new-networks new-networks
:id id
:new-network network)]
(if (network/chain-id-available? networks network)
{:dispatch [:bottom-sheet/show-sheet-old
{:content (fn []
[sheet/permissions-panel dapp-name message-id params])}]}
(send-success-call-to-bridge cofx id message-id)))
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId message-id
:error {:code -32602
:message "invalid network parameters"}}})))
+6 -8
View File
@@ -4,7 +4,6 @@
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
legacy.status-im.communities.e2e
[re-frame.core :as re-frame]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -84,13 +83,12 @@
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn member-banned
{:events [::member-banned]}
[cofx response-js]
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet-old)
(handle-response response-js)
(activity-center/notifications-fetch-unread-count)))
(re-frame/reg-event-fx ::member-banned
(fn [{:keys [db]} [response-js]]
{:db (assoc db :bottom-sheet/show? false)
:fx [[:dismiss-bottom-sheet-overlay-old]
[:sanitize-messages-and-process-response response-js]
[:activity-center.notifications/fetch-unread-count]]}))
(rf/defn member-ban
{:events [::member-ban]}
+10 -11
View File
@@ -6,7 +6,6 @@
[re-frame.core :as re-frame]
[status-im.contexts.chat.contacts.events :as contacts-store]
[status-im.contexts.chat.messenger.messages.list.events :as message-list]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.re-frame :as rf]))
@@ -45,16 +44,16 @@
(apply
rf/merge
cofx
{:db (->
db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key
:added?]
false))
:dispatch [:shell/close-switcher-card public-key]
:effects/push-notifications-clear-message-notifications [public-key]}
(activity-center/notifications-fetch-unread-count)
{:db (->
db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key
:added?]
false))
:fx [[:activity-center.notifications/fetch-unread-count]
[:effects/push-notifications-clear-message-notifications [public-key]]
[:dispatch [:shell/close-switcher-card public-key]]]}
fxs)))
(rf/defn block-contact
+3 -3
View File
@@ -45,12 +45,12 @@
(query-fn (comp participant-set :public-key) (vals all-contacts))))
(defn get-all-contacts-in-group-chat
[members admins contacts {:keys [public-key preferred-name name] :as current-account}]
[members admins contacts {:keys [public-key preferred-name name display-name] :as current-account}]
(let [current-contact (some->
current-account
(select-keys [:name :preferred-name :public-key :images])
(select-keys [:name :preferred-name :public-key :images :compressed-key])
(set/rename-keys {:name :alias :preferred-name :name})
(assoc :primary-name (or preferred-name name)))
(assoc :primary-name (or display-name preferred-name name)))
all-contacts (cond-> contacts
current-contact
(assoc public-key current-contact))]
@@ -29,37 +29,41 @@
(testing "transforms messages from RPC response"
(is
(= {:last-message {:quoted-message nil
:outgoing-status nil
:command-parameters nil
:link-previews []
:content {:sticker nil
:rtl? nil
:ens-name nil
:parsed-text nil
:response-to nil
:chat-id nil
:image nil
:line-count nil
:links nil
:text nil}
:outgoing false}
(= {:last-message {:quoted-message nil
:outgoing-status nil
:command-parameters nil
:link-previews []
:status-link-previews []
:content {:sticker nil
:rtl? nil
:ens-name nil
:parsed-text nil
:response-to nil
:chat-id nil
:image nil
:line-count nil
:links nil
:text nil}
:bridge-message nil
:outgoing false}
:message nil
:reply-message {:quoted-message nil
:outgoing-status nil
:command-parameters nil
:link-previews []
:content {:sticker nil
:rtl? nil
:ens-name nil
:parsed-text nil
:response-to nil
:chat-id nil
:image nil
:line-count nil
:links nil
:text nil}
:outgoing false}}
:reply-message {:quoted-message nil
:outgoing-status nil
:command-parameters nil
:link-previews []
:status-link-previews []
:content {:sticker nil
:rtl? nil
:ens-name nil
:parsed-text nil
:response-to nil
:chat-id nil
:image nil
:line-count nil
:links nil
:text nil}
:bridge-message nil
:outgoing false}}
(-> raw-notification
store/<-rpc
(select-keys [:last-message :message :reply-message])))))
+10 -9
View File
@@ -3,9 +3,10 @@
[clojure.set :as set]
[legacy.status-im.data-store.messages :as messages]
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[taoensso.timbre :as log]))
(defn rpc->type
[{:keys [chat-type name] :as chat}]
@@ -117,10 +118,10 @@
rpc->type
unmarshal-members))
(rf/defn fetch-chats-preview
[_ {:keys [on-success]}]
{:json-rpc/call [{:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
(re-frame/reg-fx :fetch-chats-preview
(fn [{:keys [on-success]}]
(json-rpc/call {:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)})))
@@ -4,13 +4,6 @@
[clojure.walk :as walk]
[status-im.constants :as constants]))
(defn rpc->channel-permissions
[rpc-channels-permissions]
(update-vals rpc-channels-permissions
(fn [{:keys [viewAndPostPermissions viewOnlyPermissions]}]
{:view-only (set/rename-keys viewOnlyPermissions {:satisfied :satisfied?})
:view-and-post (set/rename-keys viewAndPostPermissions {:satisfied :satisfied?})})))
(defn <-revealed-accounts-rpc
[accounts]
(mapv
@@ -34,8 +27,9 @@
(assoc acc
(name k)
(-> v
(assoc :can-post? (:canPost v))
(dissoc :canPost)
(assoc :token-gated? (:tokenGated v)
:can-post? (:canPost v))
(dissoc :canPost :tokenGated)
(update :members walk/stringify-keys))))
{}
chats))
@@ -1,23 +0,0 @@
(ns legacy.status-im.data-store.communities-test
(:require
[cljs.test :refer [deftest is]]
[legacy.status-im.data-store.communities :as sut]))
(def permissions
{"community-id-chat-1"
{:viewOnlyPermissions {:satisfied false
:permissions {:token-permission-id-01 {:criteria [false]}}}
:viewAndPostPermissions {:satisfied true :permissions {}}}
"community-id-chat-2"
{:viewOnlyPermissions {:satisfied true :permissions {}}
:viewAndPostPermissions {:satisfied true :permissions {}}}})
(deftest rpc->channel-permissions-test
(is (= {"community-id-chat-1"
{:view-only {:satisfied? false
:permissions {:token-permission-id-01 {:criteria [false]}}}
:view-and-post {:satisfied? true :permissions {}}}
"community-id-chat-2"
{:view-only {:satisfied? true :permissions {}}
:view-and-post {:satisfied? true :permissions {}}}}
(sut/rpc->channel-permissions permissions))))
+39 -3
View File
@@ -16,13 +16,41 @@
:community-id :communityId
:clock-value :clock})))
(defn- <-status-link-previews-rpc
[preview]
(-> preview
(update :community
set/rename-keys
{:communityId :community-id
:displayName :display-name
:membersCount :members-count
:activeMembersCount :active-members-count})
(update-in [:community :banner] set/rename-keys {:dataUri :data-uri})
(update-in [:community :icon] set/rename-keys {:dataUri :data-uri})))
(defn ->status-link-previews-rpc
[preview]
(-> preview
(update :community
set/rename-keys
{:community-id :communityId
:display-name :displayName
:members-count :membersCount
:active-members-count :activeMembersCount})
(update-in [:community :banner] set/rename-keys {:data-uri :dataUri})
(update-in [:community :icon] set/rename-keys {:data-uri :dataUri})))
(defn- <-link-preview-rpc
[preview]
(update preview :thumbnail set/rename-keys {:dataUri :data-uri}))
(-> preview
(update :thumbnail set/rename-keys {:dataUri :data-uri})
(update :favicon set/rename-keys {:dataUri :data-uri})))
(defn ->link-preview-rpc
[preview]
(update preview :thumbnail set/rename-keys {:data-uri :dataUri}))
(-> preview
(update :thumbnail set/rename-keys {:data-uri :dataUri})
(update :favicon set/rename-keys {:data-uri :dataUri})))
(defn <-rpc
[message]
@@ -53,8 +81,16 @@
:new :new?
:albumImagesCount :album-images-count
:displayName :display-name
:linkPreviews :link-previews})
:linkPreviews :link-previews
:statusLinkPreviews :status-link-previews
:bridgeMessage :bridge-message})
(update :bridge-message
set/rename-keys
{:bridgeName :bridge-name
:userName :user-name
:userAvatar :user-avatar})
(update :link-previews #(map <-link-preview-rpc %))
(update :status-link-previews #(map <-status-link-previews-rpc %))
(update :quoted-message
set/rename-keys
{:parsedText :parsed-text
@@ -21,6 +21,7 @@
:image nil
:response-to "a"
:links nil}
:bridge-message nil
:whisper-timestamp 1
:contact-verification-state 1
:contact-request-state 2
@@ -37,7 +38,19 @@
:compressed-key "c"
:timestamp 3
:link-previews [{:thumbnail {:url "http://localhost"
:data-uri "data:image/png"}}]}
:data-uri "data:image/png"}
:favicon nil}]
:status-link-previews [{:url "http://localhost"
:community {:community-id "0x01"
:display-name "Test Comm"
:members-count 12
:active-members-count 12
:banner
{:data-uri
"data:image/png"}
:icon
{:data-uri
"data:image/png"}}}]}
message {:id message-id
:whisperTimestamp 1
:parsedText "parsed-text"
@@ -61,5 +74,17 @@
:timestamp 3
:outgoingStatus "sending"
:linkPreviews [{:thumbnail {:url "http://localhost"
:dataUri "data:image/png"}}]}]
:dataUri "data:image/png"}
:favicon nil}]
:statusLinkPreviews [{:url "http://localhost"
:community {:communityId "0x01"
:displayName "Test Comm"
:membersCount 12
:activeMembersCount 12
:banner
{:dataUri
"data:image/png"}
:icon
{:dataUri
"data:image/png"}}}]}]
(is (= expected (m/<-rpc message))))))
@@ -2,6 +2,8 @@
(:require
[clojure.set :as set]
[clojure.walk :as walk]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -32,11 +34,11 @@
:on-success #()
:on-error #()}]})
(rf/defn fetch-switcher-cards-rpc
[_]
{:json-rpc/call [{:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)}]})
(re-frame/reg-fx :switcher-cards/fetch
(fn []
(json-rpc/call {:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)})))
@@ -2,8 +2,8 @@
(:require
[clojure.set :as set]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[status-im.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]))
(defn <-rpc
[visibility-status-update]
@@ -18,13 +18,13 @@
{:current-user-status :current-user-visibility-status})
(update :current-user-visibility-status <-rpc)))
(rf/defn fetch-visibility-status-updates-rpc
[_]
{:json-rpc/call [{:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)}]})
(re-frame/reg-fx :visibility-status-updates/fetch
(fn []
(json-rpc/call {:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)})))
@@ -239,7 +239,7 @@
(rf/defn tx-history-end-reached
[{:keys [db] :as cofx} address]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? db)]
{:db (assoc-in db
[:wallet-legacy :fetching address :all-fetched?]
(if syncing-allowed?
@@ -327,7 +327,7 @@
{:chain-tokens (:wallet-legacy/all-tokens db)
:addresses [address]
:before-block min-known-block
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
:fetch-more? (utils.mobile-sync/syncing-allowed? db)
;; Transfers are requested before and including `min-known-block` because there is no
;; guarantee that all transfers from that block are shown already. To make sure that we fetch
;; the whole `default-transfers-limit` of transfers the number of transfers already received
+7 -3
View File
@@ -8,11 +8,16 @@
legacy.status-im.chat.models.loading
legacy.status-im.contact.block
legacy.status-im.currency.core
legacy.status-im.data-store.chats
legacy.status-im.data-store.switcher-cards
legacy.status-im.data-store.visibility-status-updates
legacy.status-im.fleet.core
legacy.status-im.group-chats.core
[legacy.status-im.keycard.core :as keycard]
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]
@@ -37,7 +42,6 @@
[react-native.core :as rn]
[react-native.permissions :as permissions]
[react-native.platform :as platform]
[status-im.common.biometric.events :as biometric]
status-im.common.serialization
status-im.common.standard-authentication.events
[status-im.common.theme.core :as theme]
@@ -120,7 +124,7 @@
:content (i18n/label :t/biometric-auth-confirm-message)
:confirm-button-text (i18n/label :t/biometric-auth-confirm-try-again)
:cancel-button-text (i18n/label :t/biometric-auth-confirm-logout)
:on-accept #(biometric/authenticate nil {:on-fail on-biometric-auth-fail})
:on-accept #(rf/dispatch [:biometric/authenticate {:on-fail on-biometric-auth-fail}])
:on-cancel #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])})))
(rf/defn on-return-from-background
@@ -142,7 +146,7 @@
#(when-let [chat-id (:current-chat-id db)]
{:dispatch [:chat/mark-all-as-read chat-id]})
#(when requires-bio-auth
(biometric/authenticate % {:on-fail on-biometric-auth-fail})))))
{:dispatch [:biometric/authenticate {:on-fail on-biometric-auth-fail}]}))))
(rf/defn on-going-in-background
[{:keys [db now]}]
+12 -15
View File
@@ -6,9 +6,9 @@
[legacy.status-im.data-store.invitations :as data-store.invitations]
[oops.core :as oops]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[status-im.contexts.chat.events :as chat.events]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -19,15 +19,13 @@
(when (get-in cofx [:db :chats chat-id])
(chat.events/pop-to-root-and-navigate-to-chat cofx chat-id nil)))
(rf/defn handle-chat-removed
{:events [:chat-removed]}
[cofx response chat-id]
(rf/merge cofx
{:db (dissoc (:db cofx) :current-chat-id)
:dispatch-n [[:shell/close-switcher-card chat-id]
[:sanitize-messages-and-process-response response]
[:pop-to-root :shell-stack]]}
(activity-center/notifications-fetch-unread-count)))
(re-frame/reg-event-fx :chat-removed
(fn [{:keys [db]} [response chat-id]]
{:db (dissoc db :current-chat-id)
:fx [[:dispatch [:shell/close-switcher-card chat-id]]
[:dispatch [:sanitize-messages-and-process-response response]]
[:dispatch [:pop-to-root :shell-stack]]
[:activity-center.notifications/fetch-unread-count]]}))
(rf/defn handle-chat-update
{:events [:chat-updated]}
@@ -264,8 +262,7 @@
{}
invitations))})
(rf/defn get-group-chat-invitations
[_]
{:json-rpc/call
[{:method "wakuext_getGroupChatInvitations"
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
(re-frame/reg-fx :group-chats/get-group-chat-invitations
(fn []
(json-rpc/call {:method "wakuext_getGroupChatInvitations"
:on-success [::initialize-invitations]})))
+26 -17
View File
@@ -5,6 +5,7 @@
[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]
@@ -61,7 +62,7 @@
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
(defn fetch-use-mailservers?
[{:keys [db]}]
[db]
(get-in db [:profile/profile :use-mailservers?]))
(defonce showing-connection-error-popup? (atom false))
@@ -117,24 +118,32 @@
[{: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 now] :as cofx}]
(when (and
(:messenger/started? db)
(mobile-network-utils/syncing-allowed? cofx)
(fetch-use-mailservers? cofx)
(not (:mailserver/current-request db)))
{:db (assoc db :mailserver/current-request true)
: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]))}]}))
[{: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]
@@ -5,7 +5,7 @@
[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]
[status-im.contexts.chat.home.add-new-contact.events :as add-new-contact]
[re-frame.core :as re-frame]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -18,27 +18,24 @@
(or (nil? remember-choice?)
remember-choice?))}))
(rf/defn on-network-status-change
[{:keys [db] :as cofx}]
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
{:keys [remember-syncing-choice?]} (:profile/profile db)]
(apply
rf/merge
cofx
{:db (assoc db :network-status/initialized? true)}
(cond
;; NOTE(rasom): When we log into account on-network-status-change is
;; dispatched, but that doesn't mean there was a status change, thus
;; no reason to restart wallet.
(and logged-in? initialized?)
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)
#(add-new-contact/set-new-identity-reconnected %)]
logged-in?
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)]))))
(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])
[:dismiss-bottom-sheet-overlay-old]
(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))
@@ -13,15 +13,14 @@
(native-module/logout)))
(rf/defn initialize-app-db
[{{:keys [keycard initials-avatar-font-file]
:biometric/keys [supported-type]
:network/keys [type]}
[{{:keys [keycard initials-avatar-font-file biometrics]
:network/keys [type]}
:db}]
{:db (assoc db/app-db
:network/type type
:initials-avatar-font-file initials-avatar-font-file
:keycard (dissoc keycard :secrets :pin :application-info)
:biometric/supported-type supported-type
:biometrics biometrics
:syncing nil)})
(rf/defn logout-method
@@ -46,6 +45,7 @@
[_]
;; we need to disable notifications before starting the logout process
{:effects/push-notifications-disable nil
:dispatch [:alert-banners/remove-all]
:dispatch-later [{:ms 100
:dispatch [::logout-method
{:auth-method keychain/auth-method-none
+1 -132
View File
@@ -1,11 +1,6 @@
(ns legacy.status-im.network.core
(:require
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.navigation.events :as navigation]
[utils.ethereum.chain :as chain]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[clojure.string :as string]))
(def url-regex
#"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)")
@@ -14,12 +9,6 @@
[url]
(boolean (re-matches url-regex (str url))))
(def default-manage
{:name {:value ""}
:url {:value ""}
:symbol {:value ""}
:chain {:value :mainnet}})
(defn validate-string
[{:keys [value]}]
{:value value
@@ -56,123 +45,3 @@
[current-networks network]
(let [chain-id (get-in network [:config :NetworkId])]
(every? #(not= chain-id (get-in % [1 :config :NetworkId])) current-networks)))
(defn get-network
[{:keys [db]} network-id]
(get-in db [:networks/networks network-id]))
(rf/defn set-input
{:events [::input-changed]}
[{:keys [db]} input-key value]
{:db (-> db
(update-in [:networks/manage input-key] assoc :value value)
(update-in [:networks/manage] validate-manage))})
;; No edit functionality actually implemented
(rf/defn edit
{:events [::add-network-pressed]}
[{db :db}]
{:db (assoc db :networks/manage (validate-manage default-manage))
:dispatch [:navigate-to :edit-network]})
(rf/defn connect-success
{:events [::connect-success]}
[_ network-id]
{:ui/show-confirmation
{:title (i18n/label :t/close-app-title)
:content (i18n/label :t/logout-app-content)
:confirm-button-text (i18n/label :t/close-app-button)
:on-accept #(re-frame/dispatch [::save-network-settings-pressed network-id])
:on-cancel nil}})
(rf/defn connect-failure
{:events [::connect-failure]}
[_ reason]
{:effects.utils/show-popup
{:title (i18n/label :t/error)
:content (str reason)}})
(rf/defn connect
{:events [::connect-network-pressed]}
[{:keys [db] :as cofx} network-id]
(if (get-in db [:networks/networks network-id :config])
(connect-success cofx network-id)
(connect-failure cofx "A network with the specified id doesn't exist")))
(rf/defn delete
{:events [::delete-network-pressed]}
[{:keys [db]} network]
(let [current-network? (= (:networks/current-network db) network)]
(if (or current-network?
(not (get-in db [:networks/networks network])))
{:ui/show-error (i18n/label :t/delete-network-error)}
{:ui/show-confirmation {:title (i18n/label :t/delete-network-title)
:content (i18n/label :t/delete-network-confirmation)
:confirm-button-text (i18n/label :t/delete)
:on-accept #(re-frame/dispatch [::remove-network-confirmed
network])
:on-cancel nil}})))
(rf/defn save-network-settings
{:events [::save-network-settings-pressed]}
[{:keys [db] :as cofx} network]
{:db (assoc db :networks/current-network network)
:json-rpc/call [{:method "settings_saveSetting"
:params [:networks/current-network network]
:on-success #(re-frame/dispatch [:logout])}]})
(rf/defn remove-network
{:events [::remove-network-confirmed]}
[{:keys [db] :as cofx} network]
(let [networks (dissoc (:networks/networks db) network)]
{:db (assoc db :networks/networks networks)
:json-rpc/call [{:method "settings_saveSetting"
:params [:networks/networks (vals networks)]
:on-success #(re-frame/dispatch [:navigate-back])}]}))
(defn new-network
[random-id network-name sym upstream-url chain-type chain-id]
(let [data-dir (str "/ethereum/" (name chain-type) "_rpc")
config {:NetworkId (or (when chain-id (int chain-id))
(chain/chain-keyword->chain-id chain-type))
:DataDir data-dir
:UpstreamConfig {:Enabled true
:URL upstream-url}}]
{:id random-id
:name network-name
:symbol sym
:config config}))
(rf/defn save
{:events [::save-network-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:networks/keys [manage networks] :as db} :db
random-id-generator :random-id-generator
:as cofx}]
(if (valid-manage? manage)
;; rename network-id from UI to chain-id
(let [{:keys [name url chain network-id symbol]} manage
random-id (string/replace (random-id-generator) "-" "")
network (new-network random-id
(:value name)
(:value symbol)
(:value url)
(:value chain)
(:value network-id))
custom-chain-type? (= :custom (:value chain))
new-networks (assoc networks random-id network)]
(if (or (not custom-chain-type?)
(chain-id-available? networks network))
{:db (-> db
(dissoc :networks/manage)
(assoc :networks/networks new-networks))
:json-rpc/call [{:method "settings_saveSetting"
:params [:networks/networks (vals new-networks)]
:on-success #(re-frame/dispatch [:navigate-back])}]}
{:ui/show-error "chain-id already defined"}))
{:ui/show-error "invalid network parameters"}))
(rf/defn open-network-details
{:events [::network-entry-pressed]}
[cofx network]
(navigation/navigate-to cofx :network-details {:networks/selected-network network}))
-130
View File
@@ -31,38 +31,6 @@
(testing "an https url not on the default port"
(is (network.core/valid-rpc-url? "https://valid.something.else:65323"))))
(deftest new-network-test
(let [actual (network.core/new-network "randomid"
"network-name"
"network-symbol"
"upstream-url"
:mainnet
nil)]
(is (= {:id "randomid"
:name "network-name"
:symbol "network-symbol"
:config {:NetworkId 1
:DataDir "/ethereum/mainnet_rpc"
:UpstreamConfig {:Enabled true
:URL "upstream-url"}}}
actual))))
(deftest new-network-id-test
(let [actual (network.core/new-network "randomid"
"network-name"
"network-symbol"
"upstream-url"
:mainnet
"5777")]
(is (= {:id "randomid"
:name "network-name"
:symbol "network-symbol"
:config {:NetworkId 5777
:DataDir "/ethereum/mainnet_rpc"
:UpstreamConfig {:Enabled true
:URL "upstream-url"}}}
actual))))
(deftest valid-manage-test
(testing "a valid manage"
(is (network.core/valid-manage? {:url {:value "http://valid.com"}
@@ -92,101 +60,3 @@
:name {:value "valid"}
:symbol {:value ""}
:chain {:value "valid"}})))))
(deftest set-input-test
(testing "it updates and validate a field"
(is
(= {:db {:networks/manage {:url {:value "http://valid.com"
:error false}
:name {:value ""
:error true}
:symbol {:value "symbol"
:error false}
:chain {:value "mainnet"
:error false}
:network-id {:value nil
:error false}}}}
(network.core/set-input {:db {:networks/manage {:url {:value "something"
:error true}
:name {:value ""
:error false}
:symbol {:value "symbol"
:error false}
:chain {:value "mainnet"
:error false}}}}
:url
"http://valid.com")))))
(deftest not-save-invalid-url
(testing "it does not save a network with an invalid url"
(is
(:ui/show-error (network.core/save {:random-id-generator (constantly "random")
:db {:networks/manage {:url {:value "wrong"}
:chain {:value "1"}
:name {:value "empty"}}
:profile/profile {}}})))))
(deftest save-valid-network
(testing "save a valid network"
(let [fx (network.core/save
{:random-id-generator (constantly "random-id")
:db {:networks/manage {:url {:value "http://valid.com"}
:chain {:value :mainnet}
:symbol {:value "symbol"}
:name {:value "valid"}}
:profile/profile {}
:networks/networks {"random2"
{:id "random2"
:name "network-name"
:symbol "symbol"
:config {:NetworkId 1
:DataDir "/ethereum/mainnet_rpc"
:UpstreamConfig
{:Enabled true
:URL "upstream-url"}}}}}})]
(is (= "settings_saveSetting" (:method (first (:json-rpc/call fx)))))
(is (nil? (:networks/manage (:db fx))))
(testing "and check that it has an id with `-` and the correct mainnet NetworkId"
(is (= 1 (get-in fx [:db :networks/networks "randomid" :config :NetworkId])))))))
(deftest not-save-custom-chain-with-non-unique-id
(testing "it does not save a custom chain with network-id already defined"
(let [result (network.core/save
{:random-id-generator (constantly "already-defined")
:db {:networks/manage {:url {:value "http://valid.com"}
:chain {:value :custom}
:name {:value "valid"}
:network-id {:value 1}}
:profile/profile {}
:networks/networks {"random"
{:id "random"
:name "network-name"
:config {:NetworkId 1
:DataDir "/ethereum/mainnet_rpc"
:UpstreamConfig
{:Enabled true
:URL "upstream-url"}}}}}})]
(is (:ui/show-error result)))))
(deftest save-valid-network-with-unique-chain-id-check
(testing "save a valid network with chain-id not already defined"
(let [fx (network.core/save
{:random-id-generator (constantly "random")
:db {:networks/manage {:url {:value "http://valid.com"}
:chain {:value :mainnet}
:name {:value "valid"}
:symbol {:value "symbol"}
:network-id {:value 5}}
:profile/profile {}
:networks/networks {"randomid"
{:id "randomid"
:name "network-name"
:symbol "symbol"
:config {:NetworkId 3
:DataDir "/ethereum/mainnet_rpc"
:UpstreamConfig
{:Enabled true
:URL "upstream-url"}}}}}})]
(is (= "settings_saveSetting" (:method (first (:json-rpc/call fx)))))
(is (nil? (:networks/manage (:db fx))))
(is (get-in fx [:db :networks/networks "random"])))))
+4 -5
View File
@@ -1,7 +1,6 @@
(ns legacy.status-im.network.net-info
(:require
["@react-native-community/netinfo" :default net-info]
[legacy.status-im.mobile-sync-settings.core :as mobile-network]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
@@ -13,11 +12,11 @@
{:db (assoc db :network-status (if is-connected? :online :offline))}))
(rf/defn change-network-type
[{:keys [db] :as cofx} old-network-type network-type expensive?]
[{:keys [db] :as cofx} network-type expensive?]
(rf/merge cofx
{:db (assoc db :network/type network-type)
:network/notify-status-go [network-type expensive?]}
(mobile-network/on-network-status-change)))
:network/notify-status-go [network-type expensive?]
:dispatch [:mobile-network/on-network-status-change]}))
(rf/defn handle-network-info-change
{:events [::network-info-changed]}
@@ -37,7 +36,7 @@
(when-not status-changed?
(change-network-status isConnected))
(when-not type-changed?
(change-network-type old-network-type type (:is-connection-expensive details))))))
(change-network-type type (:is-connection-expensive details))))))
(defn add-net-info-listener
[]
+16
View File
@@ -2,6 +2,7 @@
(:require
[legacy.status-im.utils.utils :as utils]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.constants :as constants]
[utils.ethereum.chain :as chain]
[utils.re-frame :as rf]))
@@ -22,6 +23,21 @@
:params [(chain/chain-id db) id]
:on-success #()}]}))
(re-frame/reg-fx :stickers/load-packs
(fn [chain-id]
(json-rpc/call {:method "stickers_market"
:params [chain-id]
:on-success [:stickers/stickers-market-success]})
(json-rpc/call {:method "stickers_installed"
:params []
:on-success [:stickers/stickers-installed-success]})
(json-rpc/call {:method "stickers_pending"
:params []
:on-success [:stickers/stickers-pending-success]})
(json-rpc/call {:method "stickers_recent"
:params []
:on-success [:stickers/stickers-recent-success]})))
(rf/defn load-packs
{:events [:stickers/load-packs]}
[{:keys [db]}]
+1 -1
View File
@@ -61,7 +61,7 @@
(re-frame/reg-sub
:mailserver/use-status-nodes?
(fn [db _]
(boolean (mailserver/fetch-use-mailservers? {:db db}))))
(boolean (mailserver/fetch-use-mailservers? db))))
(re-frame/reg-sub
:mailserver.edit/validation-errors
-39
View File
@@ -1,39 +0,0 @@
(ns legacy.status-im.subs.networks
(:require
[re-frame.core :as re-frame]
[status-im.config :as config]
[utils.ethereum.chain :as chain]))
(defn- filter-networks
[network-type]
(fn [network]
(let [chain-id (chain/network->chain-id network)
testnet? (chain/testnet? chain-id)
custom? (:custom? network)]
(case network-type
:custom custom?
:mainnet (and (not custom?) (not testnet?))
:testnet (and (not custom?) testnet?)))))
(defn- label-networks
[default-networks]
(fn [network]
(let [custom? (not (default-networks (:id network)))]
(assoc network :custom? custom?))))
(re-frame/reg-sub
:get-networks
:<- [:networks/networks]
(fn [networks]
(let [networks (map (label-networks (into #{} (map :id config/default-networks)))
(sort-by :name (vals networks)))
types [:mainnet :testnet :custom]]
(zipmap
types
(map #(filter (filter-networks %) networks) types)))))
(re-frame/reg-sub
:manage-network-valid?
:<- [:networks/manage]
(fn [manage]
(not-any? :error (vals manage))))
+2 -1
View File
@@ -5,7 +5,6 @@
legacy.status-im.subs.ens
legacy.status-im.subs.keycard
legacy.status-im.subs.mailservers
legacy.status-im.subs.networks
legacy.status-im.subs.stickers
[re-frame.core :as re-frame]))
@@ -23,6 +22,7 @@
(reg-root-key-sub :peers-count :peers-count)
(reg-root-key-sub :peers-summary :peers-summary)
(reg-root-key-sub :web3-node-version :web3-node-version)
(reg-root-key-sub :alert-banners :alert-banners)
;;keycard
(reg-root-key-sub :keycard :keycard)
@@ -100,6 +100,7 @@
;;; Link previews
(reg-root-key-sub :link-previews-whitelist :link-previews-whitelist)
(reg-root-key-sub :chat/link-previews :chat/link-previews)
(reg-root-key-sub :chat/status-link-previews :chat/status-link-previews)
;;commands
(reg-root-key-sub :commands/select-account :commands/select-account)
@@ -13,8 +13,7 @@
(re-frame/dispatch event))
(defn- normal-mode-settings-data
[{:keys [network-name
current-log-level
[{:keys [current-log-level
light-client-enabled?
transactions-management-enabled?
current-fleet
@@ -25,22 +24,6 @@
(keep
identity
[{:size :small
:title (i18n/label :t/network)
:accessibility-label :network-button
:container-margin-top 8
:on-press
#(re-frame/dispatch [:open-modal :network-settings])
:accessory :text
:accessory-text network-name
:chevron true}
{:size :small
:title (i18n/label :t/network-info)
:accessibility-label :network-button
:container-margin-top 8
:on-press
#(re-frame/dispatch [:open-modal :network-info])
:chevron true}
{:size :small
:title (i18n/label :t/log-level)
:accessibility-label :log-level-settings-button
:on-press
@@ -151,15 +134,13 @@
is-goerli-enabled? [:profile/is-goerli-enabled?]
light-client-enabled? [:profile/light-client-enabled?]
webview-debug [:profile/webview-debug]
network-name [:network-name]
transactions-management-enabled? [:wallet-legacy/transactions-management-enabled?]
current-log-level [:log-level/current-log-level]
current-fleet [:fleets/current-fleet]
peer-syncing-enabled? [:profile/peer-syncing-enabled?]]
[list/flat-list
{:data (flat-list-data
{:network-name network-name
:current-log-level current-log-level
{:current-log-level current-log-level
:transactions-management-enabled? transactions-management-enabled?
:light-client-enabled? light-client-enabled?
:current-fleet current-fleet
@@ -85,9 +85,7 @@
:accessibility-label :share-community-link
:type :secondary
:on-press #(debounce/throttle-and-dispatch
[(if can-invite?
::communities/invite-people-confirmation-pressed
::communities/share-community-confirmation-pressed) @user-pk
[::communities/share-community-confirmation-pressed @user-pk
selected]
3000)}
(i18n/label (if can-invite? :t/invite :t/share))]}]]))))
@@ -21,7 +21,7 @@
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/update-value :default-sync-period id])}])
:on-press #(re-frame/dispatch [:profile.settings/profile-update :default-sync-period id])}])
(views/defview default-sync-period-settings
[]
@@ -1,12 +0,0 @@
(ns legacy.status-im.ui.screens.network.edit-network.styles)
(def edit-network-view
{:flex 1
:margin-horizontal 16
:margin-vertical 15})
(def bottom-container
{:flex-direction :row
:padding-vertical 4})
(def container {:flex 1})
@@ -1,72 +0,0 @@
(ns legacy.status-im.ui.screens.network.edit-network.views
(:require
[legacy.status-im.network.core :as network]
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.list.views :as list]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.screens.network.edit-network.styles :as styles]
[re-frame.core :as re-frame]
[utils.i18n :as i18n])
(:require-macros [legacy.status-im.utils.views :as views]))
(defn- render-network-type
[type _ _ manage-network]
(let [name (case type
:mainnet (i18n/label :t/mainnet-network)
:goerli (i18n/label :t/goerli-network)
:custom (i18n/label :t/custom))]
[list.item/list-item
{:title name
:accessory :radio
:active (= (get-in manage-network [:chain :value]) type)
:on-press #(re-frame/dispatch [::network/input-changed :chain type])}]))
(views/defview edit-network
[]
(views/letsubs [manage-network [:networks/manage]
is-valid? [:manage-network-valid?]]
(let [custom? (= (get-in manage-network [:chain :value]) :custom)]
[react/keyboard-avoiding-view {:flex 1}
[react/scroll-view
[react/view styles/edit-network-view
[react/view {:padding-vertical 8}
[quo/text-input
{:label (i18n/label :t/name)
:placeholder (i18n/label :t/specify-name)
:default-value (get-in manage-network [:name :value])
:on-change-text #(re-frame/dispatch [::network/input-changed :name %])
:auto-focus true}]]
[react/view {:padding-vertical 8}
[quo/text-input
{:label (i18n/label :t/symbol)
:placeholder (i18n/label :t/specify-symbol)
:default-value (get-in manage-network [:symbol :value])
:on-change-text #(re-frame/dispatch [::network/input-changed :symbol %])
:auto-focus true}]]
[react/view {:padding-vertical 8}
[quo/text-input
{:label (i18n/label :t/rpc-url)
:placeholder (i18n/label :t/specify-rpc-url)
:default-value (get-in manage-network [:url :value])
:on-change-text #(re-frame/dispatch [::network/input-changed :url %])}]]]
[quo/list-header (i18n/label :t/network-chain)]
[list/flat-list
{:data [:mainnet :goerli :custom]
:key-fn (fn [_ i] (str i))
:render-data manage-network
:render-fn render-network-type}]
(when custom?
[react/view styles/edit-network-view
[quo/text-input
{:label (i18n/label :t/network-id)
:placeholder (i18n/label :t/specify-network-id)
:on-change-text #(re-frame/dispatch [::network/input-changed :network-id %])}]])]
[react/view styles/bottom-container
[react/view {:flex 1}]
[quo/button
{:after :main-icons/next
:type :secondary
:disabled (not is-valid?)
:on-press #(re-frame/dispatch [::network/save-network-pressed])}
(i18n/label :t/save)]]])))
@@ -1,47 +0,0 @@
(ns legacy.status-im.ui.screens.network.network-details.views
(:require
[legacy.status-im.network.core :as network]
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.screens.network.styles :as st]
[legacy.status-im.ui.screens.network.views :as network-settings]
[re-frame.core :as re-frame]
[utils.debounce :refer [throttle-and-dispatch]]
[utils.i18n :as i18n])
(:require-macros [legacy.status-im.utils.views :as views]))
(views/defview network-details
[]
(views/letsubs [{:keys [networks/selected-network]} [:get-screen-params]
current-network [:networks/current-network]
networks [:get-networks]]
(let [{:keys [id name config]} selected-network
connected? (= id current-network)
custom? (seq (filter #(= (:id %) id) (:custom networks)))]
[:<>
[react/view {:flex 1}
[network-settings/network-badge
{:name name
:connected? connected?}]
(when-not connected?
[react/touchable-highlight
{:on-press #(throttle-and-dispatch [::network/connect-network-pressed id] 1000)}
[react/view st/connect-button-container
[react/view
{:style st/connect-button
:accessibility-label :network-connect-button}
[react/text {:style st/connect-button-label}
(i18n/label :t/connect)]]
[react/i18n-text
{:style st/connect-button-description
:key :connecting-requires-login}]]])
[react/view (st/network-config-container)
[react/text
{:style st/network-config-text
:accessibility-label :network-details-text}
config]]]
(when custom?
[react/view st/bottom-container
[react/view {:flex 1}
[quo/button {:on-press #(re-frame/dispatch [::network/delete-network-pressed id])}
(i18n/label :t/delete)]]])])))
@@ -1,90 +0,0 @@
(ns legacy.status-im.ui.screens.network.styles
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.utils.styles :as styles]))
(def wrapper
{:flex 1})
(def badge-name-text
{:font-size 17})
(styles/def badge-connected-text
{:color colors/gray
:ios {:margin-top 5}})
(def connect-button-container
{:margin-top 8
:margin-bottom 16
:margin-horizontal 16})
(def connect-button
{:height 52
:align-items :center
:justify-content :center
:background-color colors/blue
:border-radius 8
:ios {:opacity 0.9}})
(def connect-button-label
{:color colors/white-persist
:font-size 17})
(def connect-button-description
{:color colors/gray
:margin-top 8
:height 20})
(styles/defn network-config-container
[]
{:height 160
:margin-top 8
:padding-top 16
:padding-left 16
:margin-horizontal 16
:background-color colors/gray-lighter
:ios {:border-radius 9
:opacity 0.9}
:android {:border-radius 4}})
(styles/def network-config-text
{:font-size 17
:ios {:opacity 0.8}
:android {:opacity 0.4}})
(defn network-icon
[connected? size]
{:width size
:height size
:border-radius (/ size 2)
:background-color (if connected? colors/blue colors/gray-lighter)
:align-items :center
:justify-content :center})
(def network-badge
{:height 88
:padding-left 16
:flex-direction :row
:align-items :center})
(styles/def network-item
{:flex-direction :row
:align-items :center
:padding-horizontal 16
:ios {:height 64}
:android {:height 56}})
(def network-item-name-text
{:font-size 17})
(def network-item-connected-text
{:color colors/gray
:font-size 14
:margin-top 6})
(def bottom-container
{:flex-direction :row
:margin-horizontal 12
:margin-vertical 15})
(def container {:flex 1})
@@ -1,71 +0,0 @@
(ns legacy.status-im.ui.screens.network.views
(:require
[legacy.status-im.network.core :as network]
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.icons.icons :as icons]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.list.views :as list]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.components.topbar :as topbar]
[legacy.status-im.ui.screens.network.styles :as styles]
[re-frame.core :as re-frame]
[utils.i18n :as i18n])
(:require-macros [legacy.status-im.utils.views :as views]))
(defn- network-icon
[connected? size]
[react/view (styles/network-icon connected? size)
[icons/icon :main-icons/network {:color (if connected? colors/white-persist colors/gray)}]])
(defn network-badge
[& [{:keys [name connected?]}]]
[react/view styles/network-badge
[network-icon connected? 56]
[react/view {:padding-left 16}
[react/text {:style styles/badge-name-text}
(or name (i18n/label :t/new-network))]
(when connected?
[react/i18n-text
{:style styles/badge-connected-text
:key :connected}])]])
(def mainnet?
#{"mainnet" "mainnet_rpc"})
(defn render-network
[{:keys [id name] :as network} _ _ current-network]
(let [connected? (= id current-network)]
[list.item/list-item
{:on-press #(re-frame/dispatch [::network/network-entry-pressed network])
:icon :main-icons/network
:icon-bg-color (if connected? colors/blue colors/gray-lighter)
:icon-color (if connected? colors/white-persist colors/gray)
:title name
:subtitle (when connected? (i18n/label :t/connected))
:chevron true}]))
(views/defview network-settings
[]
(views/letsubs [current-network [:networks/current-network]
networks [:get-networks]]
[:<>
[topbar/topbar
{:title (i18n/label :t/network-settings)
:right-accessories
[{:icon :main-icons/add
:on-press #(re-frame/dispatch [::network/add-network-pressed])}]}]
[react/view styles/wrapper
[list/section-list
{:sections [{:title (i18n/label :t/main-networks)
:key :mainnet
:data (:mainnet networks)}
{:title (i18n/label :t/test-networks)
:key :testnet
:data (:testnet networks)}
{:title (i18n/label :t/custom-networks)
:key :custom
:data (:custom networks)}]
:key-fn :id
:default-separator? true
:render-data current-network
:render-fn render-network}]]]))
@@ -1,84 +0,0 @@
(ns legacy.status-im.ui.screens.network-info.views
(:require
[legacy.status-im.ethereum.decode :as decode]
[legacy.status-im.ui.components.react :as react]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.common.json-rpc.events :as json-rpc]
[utils.datetime :as datetime]))
(defn get-block
[block callback]
(json-rpc/call
{:method "eth_getBlockByNumber"
:params [block false]
:on-success callback
:on-error #(js/alert (str "can't fetch latest block" %))}))
(defn to-date
[timestamp]
(datetime/timestamp->long-date
(* 1000 timestamp)))
(defn check-lag
[]
(let [latest-block (reagent/atom nil)
last-loaded-block (reagent/atom nil)
on-press
(fn []
(get-block
"latest"
(fn [res]
(reset! latest-block res)
(get-block
(str "0x"
(native-module/number-to-hex
@(re-frame/subscribe [:ethereum/current-block])))
(fn [res]
(reset! last-loaded-block res))))))]
(fn []
[react/view
{:style {:flex 1
:margin-horizontal 16}}
(if-not @latest-block
[react/text
{:on-press on-press}
"PRESS TO REFRESH"]
[react/text
{:on-press on-press}
(let [latest-block-number
(decode/uint (:number @latest-block))
latest-block-timestamp
(decode/uint (:timestamp @latest-block))
last-loaded-block-number
(decode/uint (:number @last-loaded-block))
last-loaded-block-timestamp
(decode/uint (:timestamp @last-loaded-block))]
(str "Latest block number: "
latest-block-number
"\n"
"Latest block time: "
(to-date latest-block-timestamp)
"\n"
"Last loaded block: "
last-loaded-block-number
"\n"
"Last loaded block time: "
(to-date last-loaded-block-timestamp)
"\n"
"Seconds diff: "
(- latest-block-timestamp
last-loaded-block-timestamp)
"\n"
"Blocks diff: " (- latest-block-number
last-loaded-block-number)
"\n"
"PRESS TO REFRESH"))])])))
(defn network-info
[]
[check-lag])
@@ -111,7 +111,7 @@
:subtitle (i18n/label :t/webview-camera-permission-requests-subtitle)
:subtitle-max-lines 2
:on-press #(re-frame/dispatch
[:profile.settings/update-value
[:profile.settings/profile-update
:webview-allow-permission-requests?
((complement boolean) webview-allow-permission-requests?)])}])
[separator]
@@ -169,8 +169,7 @@
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/update-value :profile-pictures-visibility
id])}])
:on-press #(re-frame/dispatch [:profile.settings/profile-update :profile-pictures-visibility id])}])
(views/defview profile-pic
[]
@@ -51,4 +51,4 @@
:icon :main-icons/delete
:theme :accent
:title (i18n/label :t/profile-pic-remove)
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture nil])}])]))
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture])}])]))
+47 -60
View File
@@ -1,7 +1,6 @@
(ns legacy.status-im.ui.screens.screens
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.icons.icons :as icons]
[legacy.status-im.ui.screens.about-app.views :as about-app]
[legacy.status-im.ui.screens.advanced-settings.views :as advanced-settings]
[legacy.status-im.ui.screens.appearance.views :as appearance]
@@ -24,10 +23,6 @@
[legacy.status-im.ui.screens.link-previews-settings.views :as link-previews-settings]
[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.network-info.views :as network-info]
[legacy.status-im.ui.screens.network.edit-network.views :as edit-network]
[legacy.status-im.ui.screens.network.network-details.views :as network-details]
[legacy.status-im.ui.screens.network.views :as network]
[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]
@@ -52,10 +47,18 @@
[status-im.contexts.chat.group-details.view :as group-details]
[utils.i18n :as i18n]))
(defn right-button-options
[id icon]
{:id id
:icon (icons/icon-source icon)})
(defn topbar-options
[title]
{:elevation 0
:title {:color (if (colors/dark?) colors/white colors/black)
:text (i18n/label title)}
:rightButtonColor (if (colors/dark?) colors/white colors/black)
:background {:color (if (colors/dark?) colors/black colors/white)}
:backButton {:color (if (colors/dark?) colors/white colors/black)
:id :legacy-back-button
:testID :back-button
:visible true
:popStackOnPress false}})
(defn screens
[]
@@ -81,7 +84,7 @@
{:name :stickers
:options {:insets {:top? true}
:topBar {:title {:text (i18n/label :t/sticker-market)}}}
:topBar (topbar-options :t/sticker-market)}
:component stickers/packs}
{:name :stickers-pack
@@ -94,7 +97,7 @@
:component group-chat/new-group}
{:name :currency-settings
:options {:topBar {:title {:text (i18n/label :t/main-currency)}}
:options {:topBar (topbar-options :t/main-currency)
:insets {:top? true}}
:component currency-settings/currency-settings}
@@ -104,27 +107,27 @@
:options {:topBar {:visible false}}
:component profile.user/my-profile}
{:name :contacts-list
:options {:topBar {:title {:text (i18n/label :t/contacts)}}
:options {:topBar (topbar-options :t/contacts)
:insets {:top? true}}
:component contacts-list/contacts-list}
{:name :ens-main
:options {:topBar {:title {:text (i18n/label :t/ens-usernames)}}
:options {:topBar (topbar-options :t/ens-usernames)
:insets {:top? true}}
:component ens/main}
{:name :ens-search
:options {:topBar {:title {:text (i18n/label :t/ens-your-username)}}
:options {:topBar (topbar-options :t/ens-your-username)
:insets {:top? true}}
:component ens/search}
{:name :ens-checkout
:options {:topBar {:title {:text (i18n/label :t/ens-your-username)}}
:options {:topBar (topbar-options :t/ens-your-username)
:insets {:top? true}}
:component ens/checkout}
{:name :ens-confirmation
:options {:topBar {:title {:text (i18n/label :t/ens-your-username)}}
:options {:topBar (topbar-options :t/ens-your-username)
:insets {:top? true}}
:component ens/confirmation}
{:name :ens-terms
:options {:topBar {:title {:text (i18n/label :t/ens-terms-registration)}}
:options {:topBar (topbar-options :t/ens-terms-registration)
:insets {:top? true}}
:component ens/terms}
{:name :ens-name-details
@@ -132,7 +135,7 @@
:options {:insets {:top? true}}
:component ens/name-details}
{:name :blocked-users-list
:options {:topBar {:title {:text (i18n/label :t/blocked-users)}}
:options {:topBar (topbar-options :t/blocked-users)
:insets {:top? true}}
:component contacts-list/blocked-users-list}
{:name :wakuv2-settings
@@ -148,7 +151,7 @@
:options {:insets {:top? true}}
:component bootnodes-settings/bootnodes-settings}
{:name :installations
:options {:topBar {:title {:text (i18n/label :t/devices)}}
:options {:topBar (topbar-options (i18n/label :t/devices))
:insets {:top? true}}
:component pairing/installations}
{:name :edit-bootnode
@@ -164,107 +167,91 @@
:options {:insets {:top? true}}
:component edit-mailserver/edit-mailserver}
{:name :dapps-permissions
:options {:topBar {:title {:text (i18n/label :t/dapps-permissions)}}
:options {:topBar (topbar-options :t/dapps-permissions)
:insets {:top? true}}
:component dapps-permissions/dapps-permissions}
{:name :privacy-and-security
:options {:topBar {:title {:text (i18n/label :t/privacy-and-security)}}
:options {:topBar (topbar-options :t/privacy-and-security)
:insets {:top? true}}
:component privacy-and-security/privacy-and-security}
{:name :messages-from-contacts-only
:options {:topBar {:title {:text (i18n/label :t/accept-new-chats-from)}}
:options {:topBar (topbar-options :t/accept-new-chats-from)
:insets {:top? true}}
:component messages-from-contacts-only/messages-from-contacts-only-view}
{:name :appearance
:options {:topBar {:title {:text (i18n/label :t/appearance)}}
:options {:topBar (topbar-options :t/appearance)
:insets {:top? true}}
:component appearance/appearance-view}
{:name :privacy-and-security-profile-pic-show-to
:options {:topbar {:title {:text (i18n/label :t/show-profile-pictures-to)}}
:options {:topbar (topbar-options :t/show-profile-pictures-to)
:insets {:top? true}}
:component privacy-and-security/profile-pic-show-to}
{:name :privacy-and-security-profile-pic
:options {:topBar {:title {:text (i18n/label :t/show-profile-pictures)}}
:options {:topBar (topbar-options :t/show-profile-pictures)
:insets {:top? true}}
:component privacy-and-security/profile-pic}
{:name :notifications
:options {:topBar {:title {:text (i18n/label :t/notification-settings)}}
:options {:topBar (topbar-options :t/notification-settings)
:insets {:top? true}}
:component notifications-settings/notifications-settings}
{:name :sync-settings
:options {:topBar {:title {:text (i18n/label :t/sync-settings)}}
:options {:topBar (topbar-options :t/sync-settings)
:insets {:top? true}}
:component sync-settings/sync-settings}
{:name :advanced-settings
:options {:topBar {:title {:text (i18n/label :t/advanced)}}
:options {:topBar (topbar-options :t/advanced)
:insets {:top? true}}
:component advanced-settings/advanced-settings}
{:name :help-center
:options {:topBar {:title {:text (i18n/label :t/need-help)}}
:options {:topBar (topbar-options :t/need-help)
:insets {:top? true}}
:component help-center/help-center}
{:name :glossary
:options {:topBar {:title {:text (i18n/label :t/glossary)}}
:options {:topBar (topbar-options :t/glossary)
:insets {:top? true}}
:component glossary/glossary}
{:name :about-app
:options {:topBar {:title {:text (i18n/label :t/about-app)}}
:options {:topBar (topbar-options :t/about-app)
:insets {:top? true}}
:component about-app/about-app}
{:name :privacy-policy
:options {:topBar {:title {:text (i18n/label :t/privacy-policy)}}
:options {:topBar (topbar-options :t/privacy-policy)
:insets {:top? true}}
:component about-app/privacy-policy}
{:name :terms-of-service
:options {:topBar {:title {:text (i18n/label :t/terms-of-service)}}
:options {:topBar (topbar-options :t/terms-of-service)
:insets {:top? true}}
:component about-app/tos}
{:name :principles
:options {:topBar {:title {:text (i18n/label :t/principles)}}
:options {:topBar (topbar-options :t/principles)
:insets {:top? true}}
:component about-app/principles}
{:name :manage-dapps-permissions
;;TODO dynamic title
:options {:insets {:top? true}}
:component dapps-permissions/manage}
{:name :network-settings
;;TODO accessories
:options {:insets {:top? true}}
:component network/network-settings}
{:name :network-details
:options {:topBar {:title {:text (i18n/label :t/network-details)}}
:insets {:top? true}}
:component network-details/network-details}
{:name :network-info
:options {:topBar {:title {:text (i18n/label :t/network-info)}}
:insets {:top? true}}
:component network-info/network-info}
{:name :rpc-usage-info
:options {:topBar {:title {:text (i18n/label :t/rpc-usage-info)}}
:options {:topBar (topbar-options :t/rpc-usage-info)
:insets {:top? true}}
:component rpc-usage-info/usage-info}
{:name :peers-stats
:options {:topBar {:title {:text (i18n/label :t/peers-stats)}}
:options {:topBar (topbar-options :t/peers-stats)
:insets {:top? true}}
:component peers-stats/peers-stats}
{:name :edit-network
:options {:topBar {:title {:text (i18n/label :t/add-network)}}
:insets {:top? true}}
:component edit-network/edit-network}
{:name :log-level-settings
:options {:topBar {:title {:text (i18n/label :t/log-level-settings)}}
:options {:topBar (topbar-options :t/log-level-settings)
:insets {:top? true}}
:component log-level-settings/log-level-settings}
{:name :fleet-settings
:options {:topBar {:title {:text (i18n/label :t/fleet-settings)}}
:options {:topBar (topbar-options :t/fleet-settings)
:insets {:top? true}}
:component fleet-settings/fleet-settings}
{:name :mobile-network-settings
:options {:topBar {:title {:text (i18n/label :t/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 {:title {:text (i18n/label :t/backup-settings)}}
:options {:topBar (topbar-options :t/backup-settings)
:insets {:top? true}}
:component backup-settings/backup-settings}
{:name :backup-seed
@@ -272,14 +259,14 @@
:options {:insets {:top? true}}
:component profile.seed/backup-seed}
{:name :reset-password
:options {:topBar {:title {:text (i18n/label :t/reset-password)}}
:options {:topBar (topbar-options :t/reset-password)
:insets {:top? true}}
:component reset-password/reset-password}
{:name :delete-profile
:insets {:bottom? true}
:component delete-profile/delete-profile}
{:name :default-sync-period-settings
:options {:topBar {:title {:text (i18n/label :t/default-sync-period)}}
:options {:topBar (topbar-options :t/default-sync-period)
:insets {:top? true}}
:component default-sync-period-settings/default-sync-period-settings}
@@ -288,7 +275,7 @@
;[Chat] Link preview settings
{:name :link-previews-settings
:options {:topBar {:title {:text (i18n/label :t/chat-link-previews)}}
:options {:topBar (topbar-options :t/chat-link-previews)
:insets {:top? true}}
:component link-previews-settings/link-previews-settings}
@@ -328,7 +315,7 @@
;;TODO WHY MODAL?
;[Profile] Notifications settings
{:name :notifications-settings
:options {:topBar {:title {:text (i18n/label :t/notification-settings)}}
:options {:topBar (topbar-options :t/notification-settings)
:popGesture false
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false}
+5 -5
View File
@@ -10,6 +10,7 @@
[re-frame.core :as re-frame]
[react-native.mail :as react-native-mail]
[react-native.platform :as platform]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.log :as log]
[status-im.config :as config]
[utils.datetime :as datetime]
@@ -31,11 +32,10 @@
[{:keys [db]} node-version]
{:db (assoc db :web3-node-version node-version)})
(rf/defn initialize-web3-client-version
{:events [:logging/initialize-web3-client-version]}
[_]
{:json-rpc/call [{:method "web3_clientVersion"
:on-success #(re-frame/dispatch [:logging/store-web3-client-version %])}]})
(re-frame/reg-fx :logging/initialize-web3-client-version
(fn []
(json-rpc/call {:method "web3_clientVersion"
:on-success [:logging/store-web3-client-version]})))
(defn extract-url-components
[address]
+1 -1
View File
@@ -5,7 +5,7 @@
(= network-type "cellular"))
(defn syncing-allowed?
[{:keys [db]}]
[db]
(let [network (:network/type db)
{:keys [syncing-on-mobile-network?]} (:profile/profile db)]
(or (= network "wifi")
+1 -1
View File
@@ -2,7 +2,7 @@
(:require-macros [legacy.status-im.utils.slurp :refer [slurp]])
(:require
[legacy.status-im.fleet.default-fleet :refer (default-fleets)])
(:require [legacy.status-im.utils.test :as utils.test]))
(:require [tests.test-utils :as utils.test]))
;; to generate a js Proxy at js/__STATUS_MOBILE_JS_IDENTITY_PROXY__ that accept any (.xxx) call and
;; return itself
@@ -2,10 +2,17 @@
(:require
[quo.foundations.colors :as colors]))
(defn- get-dimensions
[size]
(case size
:size-24 24
:size-20 20
nil))
(defn collection-avatar
[theme]
{:width 24
:height 24
[theme size]
{:width (get-dimensions size)
:height (get-dimensions size)
:border-width 1
:border-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:border-radius 6})
@@ -9,10 +9,10 @@
:image - collection image
:theme - keyword -> :light/:dark"
[{:keys [image theme]}]
[{:keys [image theme size] :or {size :size-24}}]
[fast-image/fast-image
{:accessibility-label :collection-avatar
:source image
:style (style/collection-avatar theme)}])
:style (style/collection-avatar theme size)}])
(def view (quo.theme/with-theme view-internal))
@@ -1,7 +1,6 @@
(ns quo.components.colors.color-picker.component-spec
(:require
[quo.components.colors.color-picker.view :as color-picker]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(h/describe "color-picker"
@@ -12,7 +11,7 @@
(-> (h/expect event)
(.toHaveBeenCalled))))
(h/test "color picker color changed"
(let [selected (reagent/atom nil)]
(let [selected (atom nil)]
(h/render [color-picker/view {:on-change #(reset! selected %)}])
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
(-> (h/expect @selected)
@@ -0,0 +1,23 @@
(ns quo.components.community.channel-action.style
(:require
[quo.foundations.colors :as colors]))
(defn channel-action-container
[{:keys [big? disabled?]}]
(cond-> {}
disabled? (assoc :opacity 0.3)
big? (assoc :flex-grow 1)
(not big?) (assoc :width 104)))
(defn channel-action
[{:keys [color pressed? theme]}]
{:height 102
:padding 12
:border-radius 16
:background-color (colors/resolve-color color theme (if pressed? 20 10))
:justify-content :space-between})
(def channel-action-row
{:flex-direction :row
:justify-content :space-between
:align-items :center})
@@ -0,0 +1,39 @@
(ns quo.components.community.channel-action.view
(:require
[quo.components.community.channel-action.style :as style]
[quo.components.counter.counter.view :as counter]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.theme]
[react-native.core :as rn]))
(defn view
[{:keys [big? customization-color label counter-value icon on-press accessibility-label disabled?]}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/view
{:style (style/channel-action-container
{:big? big?
:disabled? disabled?})}
[rn/pressable
(cond-> {:style (style/channel-action
{:big? big?
:color customization-color
:pressed? pressed?
:theme theme
:disabled? disabled?})
:accessibility-label accessibility-label}
(not disabled?) (assoc :on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out))
[rn/view {:style style/channel-action-row}
[icons/icon icon]
(when counter-value
[counter/view {:type :secondary} counter-value])]
[text/text
{:size :paragraph-1
:weight :medium
:number-of-lines 2}
label]]]))
@@ -1,32 +0,0 @@
(ns quo.components.community.channel-actions
(:require
[quo.components.community.style :as style]
[quo.components.counter.counter.view :as counter]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[react-native.core :as rn]))
(defn channel-action
[{:keys [big? color label counter-value icon on-press accessibility-label]}]
[rn/touchable-opacity
{:on-press on-press
:style (style/channel-action-touch big?)
:accessibility-label accessibility-label}
[rn/view {:style (style/channel-action color)}
[rn/view {:style style/channel-action-row}
[icons/icon icon]
(when counter-value
[counter/view {:type :secondary} counter-value])]
[text/text {:size :paragraph-1 :weight :medium :number-of-lines 2} label]]])
(defn channel-actions
[{:keys [style actions]}]
[rn/view {:style (merge {:flex-direction :row :flex 1} style)}
(map-indexed
(fn [index action]
^{:key index}
[:<>
[channel-action action]
(when (not= action (last actions))
[rn/view {:width 16}])])
actions)])
@@ -0,0 +1,16 @@
(ns quo.components.community.channel-actions.view
(:require
[quo.components.community.channel-action.view :as channel-action]
[react-native.core :as rn]))
(defn view
[{:keys [container-style actions]}]
[rn/view {:style (assoc container-style :flex-direction :row)}
(map-indexed
(fn [index action]
^{:key index}
[:<>
[channel-action/view action]
(when (not= action (last actions))
[rn/view {:width 16}])])
actions)])
-19
View File
@@ -133,25 +133,6 @@
colors/neutral-80
theme)})
(defn channel-action-touch
[big?]
{:flex 1
:max-width (if big? 216 104)})
(defn channel-action
[color]
{:padding 12
:height 102
:flex 1
:border-radius 16
:background-color (colors/custom-color color 50 10)
:justify-content :space-between})
(def channel-action-row
{:flex-direction :row
:justify-content :space-between
:align-items :center})
(defn loading-card
[width theme]
(merge
@@ -11,6 +11,7 @@
[:catn
[:props
[:map {:closed true}
[:container-style {:optional true} [:maybe :map]]
[:value {:optional true} [:maybe [:or :string :int]]]
[:status {:optional true} [:maybe :keyword]]
[:size {:optional true} [:maybe [:enum :size-32 :size-24]]]
@@ -19,7 +20,7 @@
:any])
(defn- view-internal
[{:keys [value accessibility-label]
[{:keys [value accessibility-label container-style]
:as props}]
(let [default-props {:status :default
:size :size-32}
@@ -27,7 +28,7 @@
[rn/view
{:accessible true
:accessibility-label (or accessibility-label :collectible-counter)
:style (style/container props)}
:style (merge (style/container props) container-style)}
[text/text
{:weight :medium
:size (style/get-text-size props)
@@ -76,7 +76,8 @@
(str description " · " (i18n/label :t/on-device))])
(defn- context-tag-subtitle
[{:keys [context-tag-type community-logo community-name account-name emoji customization-color]}]
[{:keys [context-tag-type community-logo community-name account-name emoji customization-color
full-name profile-picture]}]
(let [tag-type (or context-tag-type :account)]
[rn/view
{:accessibility-label :context-tag-wrapper
@@ -88,7 +89,9 @@
:community-name community-name
:community-logo community-logo
:size 24
:customization-color customization-color}]]))
:customization-color customization-color
:profile-picture profile-picture
:full-name full-name}]]))
(defn- description-subtitle
[{:keys [theme blur? description]}]
@@ -100,7 +103,7 @@
(defn- subtitle
[{:keys [type theme blur? keycard? networks description community-name community-logo
context-tag-type account-name emoji customization-color]}]
context-tag-type account-name emoji customization-color full-name profile-picture]}]
(cond
(= :keypair type)
[keypair-subtitle
@@ -128,7 +131,9 @@
:community-name community-name
:account-name account-name
:emoji emoji
:customization-color customization-color}]
:customization-color customization-color
:profile-picture profile-picture
:full-name full-name}]
(and (not= :label type) description)
[description-subtitle
@@ -187,7 +192,7 @@
on-button-press
on-button-long-press
button-disabled? account-avatar-emoji account-avatar-type customization-color icon-avatar
profile-picture keycard? networks label]}]
profile-picture keycard? networks label full-name]}]
[rn/view {:style style/container}
(when (left-image-supported-types type)
[rn/view {:style style/left-container}
@@ -218,7 +223,9 @@
:context-tag-type context-tag-type
:customization-color customization-color
:account-name account-name
:emoji emoji}]]
:emoji emoji
:full-name full-name
:profile-picture profile-picture}]]
[right-icon
{:theme theme
:type type
@@ -2,5 +2,10 @@
(defn root-container
[opacity height]
{:height (or height 252)
:opacity opacity})
{:height (or height 252)
:opacity opacity
:position :absolute
:top 0
:left 0
:right 0
:z-index -1})
+76 -76
View File
@@ -6,8 +6,7 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]))
[react-native.reanimated :as reanimated]))
(def header-height 56)
@@ -57,7 +56,7 @@
:justify-content :center
:align-items :flex-end})
(defn title-style
(defn get-title-style
[{:keys [left right]} title-align]
(merge
absolute-fill
@@ -133,76 +132,77 @@
:size :large}
title])])
(defn- header-internal
[{:keys [left-width right-width]}]
(let [layout (reagent/atom {:left {:width (or left-width 8)
:height header-height}
:right {:width (or right-width 8)
:height header-height}
:title {:width 0
:height header-height}})
handle-layout (fn [el get-layout]
(fn [evt]
(let [width (oget evt "nativeEvent" "layout" "width")
height (oget evt "nativeEvent" "layout" "height")]
(when get-layout
(get-layout el
{:width width
:height height}))
(swap! layout assoc
el
{:width width
:height height}))))]
(fn
[{:keys [left-accessories left-component border-bottom
right-accessories right-component insets get-layout
title subtitle title-component style title-align
background theme]
:or {title-align :center
border-bottom false}}]
(let [status-bar-height (get insets :top 0)
height (+ header-height status-bar-height)]
[reanimated/view
{:style (header-wrapper-style {:height height
:background background
:border-bottom border-bottom
:theme theme})}
[rn/view
{:pointer-events :box-none
:height status-bar-height}]
[rn/view
{:style (merge {:height header-height}
style)
:pointer-events :box-none}
[rn/view
{:style absolute-fill
:pointer-events :box-none}
[rn/view
{:style content
:pointer-events :box-none}
[rn/view
{:style left-style
:on-layout (handle-layout :left get-layout)
:pointer-events :box-none}
[header-actions
{:accessories left-accessories
:component left-component}]]
[rn/view
{:style (title-style @layout title-align)
:on-layout (handle-layout :title get-layout)
:pointer-events :box-none}
[header-title
{:title title
:subtitle subtitle
:title-align title-align
:component title-component}]]
[rn/view
{:style right-style
:on-layout (handle-layout :right get-layout)
:pointer-events :box-none}
[header-actions
{:accessories right-accessories
:component right-component}]]]]]]))))
(def header (quo.theme/with-theme header-internal))
(defn header
[{:keys [left-accessories left-component border-bottom left-width right-width
right-accessories right-component insets get-layout
title subtitle title-component style title-align
background]
:or {title-align :center
border-bottom false}}]
(let [theme (quo.theme/use-theme-value)
[layout set-layout] (rn/use-state {:left {:width (or left-width 8)
:height header-height}
:right {:width (or right-width 8)
:height header-height}
:title {:width 0
:height header-height}})
handle-layout (rn/use-callback
(fn [el get-layout]
(fn [evt]
(let [width (oget evt "nativeEvent" "layout" "width")
height (oget evt "nativeEvent" "layout" "height")]
(when get-layout
(get-layout el
{:width width
:height height}))
(set-layout
(assoc layout
el
{:width width
:height height})))))
[layout])
status-bar-height (get insets :top 0)
height (+ header-height status-bar-height)
title-style (rn/use-memo (fn [] (get-title-style layout title-align))
[layout title-align])]
[reanimated/view
{:style (header-wrapper-style {:height height
:background background
:border-bottom border-bottom
:theme theme})}
[rn/view
{:pointer-events :box-none
:height status-bar-height}]
[rn/view
{:style (merge {:height header-height}
style)
:pointer-events :box-none}
[rn/view
{:style absolute-fill
:pointer-events :box-none}
[rn/view
{:style content
:pointer-events :box-none}
[rn/view
{:style left-style
:on-layout (handle-layout :left get-layout)
:pointer-events :box-none}
[header-actions
{:accessories left-accessories
:component left-component}]]
[rn/view
{:style title-style
:on-layout (handle-layout :title get-layout)
:pointer-events :box-none}
[header-title
{:title title
:subtitle subtitle
:title-align title-align
:component title-component}]]
[rn/view
{:style right-style
:on-layout (handle-layout :right get-layout)
:pointer-events :box-none}
[header-actions
{:accessories right-accessories
:component right-component}]]]]]]))
@@ -3,7 +3,7 @@
[quo.foundations.colors :as colors]))
(def ^:private themes
{:light {:default {:bg colors/white
{:light {:default {:bg colors/neutral-5
:border colors/neutral-20
:icon colors/neutral-50
:text colors/neutral-100}
+4 -3
View File
@@ -55,16 +55,17 @@
(def ^:private custom-props
"Custom properties that must be removed from properties map passed to InputText."
[:type :blur? :theme :error? :right-icon :left-icon :disabled? :small? :button
[:type :blur? :error? :right-icon :left-icon :disabled? :small? :button
:label :char-limit :on-char-limit-reach :icon-name :multiline? :on-focus :on-blur
:container-style])
(defn- base-input
[{:keys [blur? theme error? right-icon left-icon disabled? small? button
[{:keys [blur? error? right-icon left-icon disabled? small? button
label char-limit multiline? clearable? on-focus on-blur container-style
on-change-text on-char-limit-reach weight default-value]
:as props}]
(let [[status set-status] (rn/use-state :default)
(let [theme (quo.theme/use-theme-value)
[status set-status] (rn/use-state :default)
internal-on-focus (rn/use-callback #(set-status :focus))
internal-on-blur (rn/use-callback #(set-status :default))
[multiple-lines?
@@ -10,7 +10,7 @@
:background-color (colors/theme-colors colors/neutral-10
colors/neutral-80-opa-80
theme)
:height 40
:min-height 40
:padding-horizontal 12
:padding-vertical 9
:margin-top 4})
@@ -22,11 +22,12 @@
(defn- locked-input-internal
[{:keys [label icon container-style theme]} value]
[rn/view {:style container-style}
[text/text
{:size :paragraph-2
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
label]
(when label
[text/text
{:size :paragraph-2
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
label])
[info-box
{:theme theme
:icon icon
@@ -60,8 +60,8 @@
:padding-horizontal 12
:padding-top 10
:padding-bottom 12
:height (if (= :message size) 245 266)
:width (if (= :message size) 295 335)})
:width (if (= :message size) 295 335)
:flex 1})
(def header-container
{:flex-direction :row
@@ -7,7 +7,6 @@
{:title "Some title"
:description "Some description"
:link "status.im"
:logo "data:image/png,logo-x"
:thumbnail "data:image/png,whatever"})
(h/describe "Links - Link Preview"
@@ -21,17 +20,12 @@
(h/is-truthy (h/query-by-text (:title props)))
(h/is-truthy (h/query-by-text (:description props)))
(h/is-truthy (h/query-by-text (:link props)))
(h/is-truthy (h/query-by-label-text :logo))
(h/is-truthy (h/query-by-label-text :thumbnail)))
(h/test "does not render thumbnail if prop is not present"
(h/render [view/view (dissoc props :thumbnail)])
(h/is-null (h/query-by-label-text :thumbnail)))
(h/test "does not render logo if prop is not present"
(h/render [view/view (dissoc props :logo)])
(h/is-null (h/query-by-label-text :logo)))
(h/test "shows button to enable preview when preview is disabled"
(h/render [view/view
(assoc props
@@ -1,9 +1,14 @@
(ns quo.components.links.link-preview.view
(:require
["react-native-blob-util" :default ReactNativeBlobUtil]
[oops.core :as oops]
[quo.components.buttons.button.view :as button]
[quo.components.links.link-preview.style :as style]
[quo.components.markdown.text :as text]
[react-native.core :as rn]))
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.svg :as svg]
[taoensso.timbre :as log]))
(defn- button-disabled
[disabled-text on-enable]
@@ -51,14 +56,30 @@
thumbnail)
:accessibility-label :thumbnail}])
(defn- get-image-data
[logo set-is-svg on-success]
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?}))
(.fetch "GET" logo)
(.then (fn [imgObj]
(set-is-svg (= "image/svg"
(oops/oget imgObj
["respInfo" "headers" "Content-Type"])))
(on-success (oops/oget imgObj "data"))))
(.catch #(log/error "could not fetch favicon " logo))))
(defn- logo-comp
[logo]
[rn/image
{:accessibility-label :logo
:source (if (string? logo)
{:uri logo}
logo)
:style style/logo}])
(let [[image-data set-image-data] (rn/use-state nil)
[is-svg? set-is-svg] (rn/use-state nil)
on-success (fn [data-uri]
(set-image-data data-uri))
_get-image-data (get-image-data logo set-is-svg on-success)]
(if is-svg?
[svg/svg-xml (merge style/logo {:xml image-data})]
[rn/image
{:accessibility-label :logo
:source {:uri (str "data:image/png;base64," image-data)}
:style style/logo}])))
(defn view
[{:keys [title logo description link thumbnail
@@ -21,6 +21,7 @@
:border-radius 12
:border-style :dashed
:align-items :center
:flex-direction :row
:justify-content :center
:align-self :stretch
:padding horizontal-padding
+27 -8
View File
@@ -1,19 +1,31 @@
(ns quo.components.links.url-preview.view
(:require
[clojure.string :as string]
[quo.components.icon :as icon]
[quo.components.links.url-preview.style :as style]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[react-native.core :as rn]))
[react-native.core :as rn]
[react-native.svg :as svg]))
(def base64-svg-prefix "data:image/svg;base64,")
(defn- logo-comp
[{:keys [logo]}]
[rn/image
{:accessibility-label :logo
:source (if (string? logo)
{:uri logo}
logo)
:style style/logo}])
(if (and (string? logo)
(string/starts-with? logo base64-svg-prefix))
[svg/svg-xml
(merge style/logo
{:xml (-> logo
(string/replace base64-svg-prefix "")
js/atob)})]
[rn/image
{:accessibility-label :logo
:source (if (string? logo)
{:uri logo}
logo)
:style style/logo
:resize-mode :cover}]))
(defn- content
[{:keys [title body]}]
@@ -50,6 +62,10 @@
[rn/view
{:accessibility-label :url-preview-loading
:style (merge (style/loading-container) container-style)}
[icon/icon :i/loading
{:size 12
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:container-style {:margin-right 8}}]
[rn/text
{:size :paragraph-2
:weight :medium
@@ -60,6 +76,9 @@
{:accessibility-label :url-preview
:style (merge (style/container) container-style)}
(when logo
[logo-comp {:logo logo}])
[logo-comp
{:logo (if (map? logo)
(:data-uri logo)
logo)}])
[content {:title title :body body}]
[clear-button {:on-press on-clear}]]))
@@ -32,7 +32,7 @@
[rn/view {:style style/url-preview-separator}])
(defn- item-component
[{:keys [title body loading? logo]} _ _
[{:keys [title body loading? logo url]} _ _
{:keys [width on-clear loading-message container-style]}]
[url-preview/view
{:logo logo
@@ -41,7 +41,8 @@
:loading? loading?
:loading-message loading-message
:on-clear on-clear
:container-style (merge container-style {:width width})}])
:container-style (merge container-style {:width width})
:url url}])
(defn- f-view
[]
@@ -27,7 +27,6 @@
[:blur? {:optional true} [:maybe :boolean]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:on-press {:optional true} [:maybe fn?]]
[:theme :schema.common/theme]
[:title-icon {:optional true} [:maybe :keyword]]
[:account-props
[:map
+33 -35
View File
@@ -9,7 +9,6 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- account-view
@@ -97,41 +96,40 @@
(colors/resolve-color customization-color theme))}]])
(defn- internal-view
[_]
(let [pressed? (reagent/atom false)
on-press-in #(reset! pressed? true)
on-press-out #(reset! pressed? false)]
(fn [{:keys [type state blur? customization-color on-press]
:or {customization-color :blue
type :default
state :default
blur? false}
:as props}]
[rn/pressable
{:style (style/container
{:state state
:blur? blur?
:customization-color customization-color
:pressed? @pressed?})
:on-press-in on-press-in
:on-press on-press
:on-press-out on-press-out
:accessibility-label :container}
[account-view props]
[rn/view {:style (when (= type :tag) style/token-tag-container)}
(cond
(#{:balance-neutral :balance-negative :balance-positive} type)
[balance-view props]
[{:keys [type state blur? customization-color on-press]
:or {customization-color :blue
type :default
state :default
blur? false}
:as props}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))
props (assoc props :theme theme)]
[rn/pressable
{:style (style/container
{:state state
:blur? blur?
:customization-color customization-color
:pressed? pressed?})
:on-press-in on-press-in
:on-press on-press
:on-press-out on-press-out
:accessibility-label :container}
[account-view props]
[rn/view {:style (when (= type :tag) style/token-tag-container)}
(cond
(#{:balance-neutral :balance-negative :balance-positive} type)
[balance-view props]
(= type :tag)
[token-tag props]
(= type :tag)
[token-tag props]
(= type :action)
[options-button props]
(= type :action)
[options-button props]
(and (= type :default) (= state :selected))
[check-icon props])]])))
(and (= type :default) (= state :selected))
[check-icon props])]]))
(def view
(quo.theme/with-theme
(schema/instrument #'internal-view component-schema/?schema)))
(def view (schema/instrument #'internal-view component-schema/?schema))
@@ -5,7 +5,6 @@
[:action {:optional true} [:enum :icon :none]]
[:blur? {:optional true} [:maybe :boolean]]
[:on-press {:optional true} [:maybe fn?]]
[:theme :schema.common/theme]
[:account-props
[:map {:closed true}
[:type [:enum :default :watch-only]]
@@ -9,38 +9,37 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- internal-view
[]
(let [state (reagent/atom :default)]
(fn [{:keys [action blur? account-props networks on-press on-options-press theme]}]
[rn/pressable
{:style (style/container {:state @state :blur? blur? :theme theme})
:on-press-in #(reset! state :pressed)
:on-press-out #(reset! state :default)
:on-press on-press
:accessibility-label :container}
[rn/view {:style style/left-container}
[account-avatar/view account-props]
[rn/view {:style {:margin-left 8}}
[text/text
{:weight :semi-bold
:size :paragraph-2}
(:name account-props)]
[address-text/view
{:networks networks
:address (:address account-props)
:format :short}]]]
(when (= action :icon)
[rn/pressable {:on-press on-options-press}
[icon/icon :i/options
{:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))
:accessibility-label :icon}]])])))
[{:keys [action blur? account-props networks on-press on-options-press]}]
(let [theme (quo.theme/use-theme-value)
[state set-state] (rn/use-state :default)
on-press-in (rn/use-callback #(set-state :pressed))
on-press-out (rn/use-callback #(set-state :default))]
[rn/pressable
{:style (style/container {:state state :blur? blur? :theme theme})
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :container}
[rn/view {:style style/left-container}
[account-avatar/view account-props]
[rn/view {:style {:margin-left 8}}
[text/text
{:weight :semi-bold
:size :paragraph-2}
(:name account-props)]
[address-text/view
{:networks networks
:address (:address account-props)
:format :short}]]]
(when (= action :icon)
[rn/pressable {:on-press on-options-press}
[icon/icon :i/options
{:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))
:accessibility-label :icon}]])]))
(def view
(quo.theme/with-theme
(schema/instrument #'internal-view component-schema/?schema)))
(def view (schema/instrument #'internal-view component-schema/?schema))
@@ -9,6 +9,5 @@
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:on-press {:optional true} [:maybe fn?]]
[:blur? {:optional true} [:maybe :boolean]]
[:theme :schema.common/theme]
[:active-state? {:optional true} [:maybe :boolean]]]]
:any])
+32 -32
View File
@@ -1,13 +1,12 @@
(ns quo.components.list-items.address.view
(:require
[quo.components.avatars.wallet-user-avatar.view :as wallet-user-avatar]
(quo.components.list-items.address.schema :as component-schema)
[quo.components.list-items.address.schema :as component-schema]
[quo.components.list-items.address.style :as style]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]
[utils.address :as address]))
@@ -39,34 +38,35 @@
(address/get-shortened-key address)]]]])
(defn- internal-view
[]
(let [state (reagent/atom :default)
active? (atom false)
timer (atom nil)
on-press-in (fn []
(when-not (= @state :selected)
(reset! timer (js/setTimeout #(reset! state :pressed) 100))))]
(fn [{:keys [networks address customization-color on-press active-state? blur? theme]
:or {customization-color :blue}}]
(let [on-press-out (fn []
(let [new-state (if (or (not active-state?) @active?) :default :active)]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active? (= new-state :active))
(reset! state new-state)))]
[rn/pressable
{:style (style/container @state customization-color blur?)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :container}
[left-container
{:theme theme
:networks networks
:address address
:blur? blur?}]]))))
(def view
(quo.theme/with-theme
(schema/instrument #'internal-view component-schema/?schema)))
[{:keys [networks address customization-color on-press active-state? blur?]
:or {customization-color :blue}}]
(let [theme (quo.theme/use-theme-value)
[state set-state] (rn/use-state :default)
active? (rn/use-ref-atom false)
timer (rn/use-ref-atom nil)
on-press-in (rn/use-callback
(fn []
(when-not (= state :selected)
(reset! timer (js/setTimeout #(set-state :pressed) 100))))
[state])
on-press-out (rn/use-callback
(fn []
(let [new-state (if (or (not active-state?) @active?) :default :active)]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active? (= new-state :active))
(set-state new-state)))
[active-state?])]
[rn/pressable
{:style (style/container state customization-color blur?)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :container}
[left-container
{:theme theme
:networks networks
:address address
:blur? blur?}]]))
(def view (schema/instrument #'internal-view component-schema/?schema))
+37 -39
View File
@@ -5,11 +5,10 @@
[quo.components.icon :as quo.icons]
[quo.components.list-items.channel.style :as style]
[quo.components.markdown.text :as quo.text]
[quo.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[quo.theme]
[react-native.core :as rn]))
(defn- view-internal
(defn view
"Options:
- notification - (nil/:notification/:mention/:mute, default: nil):
- :notification - Display a grey dot.
@@ -27,38 +26,37 @@
- on-press - (function, default: nil) - Function called when the component is pressed.
- on-long-press - (function, default: nil) - Function called when the component is long pressed.
- theme - Theme value from with-theme HOC"
[]
(let [pressed? (reagent/atom false)]
(fn [{:keys [notification locked? mentions-count customization-color emoji name on-press
on-long-press theme]}]
[rn/pressable
{:style (style/container @pressed? customization-color theme)
:accessibility-label :channel-list-item
:on-press on-press
:on-long-press on-long-press
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)}
[channel-avatar/view
{:size :size-32
:locked? locked?
:full-name name
:customization-color customization-color
:emoji emoji}]
[quo.text/text
{:style (style/label notification theme)
:weight :medium
:size :paragraph-1} (str "# " name)]
(when-not locked?
(condp = notification
:mute [quo.icons/icon :i/muted
{:color (style/mute-notification-icon-color theme)}]
:mention [counter/view
{:customization-color customization-color
:container-style (style/counter mentions-count)}
mentions-count]
:notification [quo.icons/icon :i/notification
{:color (style/mute-notification-icon-color theme)
:accessibility-label :unviewed-messages-public}]
nil))])))
(def view (theme/with-theme view-internal))
[{:keys [notification locked? mentions-count customization-color emoji name on-press on-long-press]}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/pressable
{:style (style/container pressed? customization-color theme)
:accessibility-label :channel-list-item
:on-press on-press
:on-long-press on-long-press
:on-press-in on-press-in
:on-press-out on-press-out}
[channel-avatar/view
{:size :size-32
:locked? locked?
:full-name name
:customization-color customization-color
:emoji emoji}]
[quo.text/text
{:style (style/label notification theme)
:weight :medium
:size :paragraph-1} (str "# " name)]
(when-not locked?
(condp = notification
:mute [quo.icons/icon :i/muted
{:color (style/mute-notification-icon-color theme)}]
:mention [counter/view
{:customization-color customization-color
:container-style (style/counter mentions-count)}
mentions-count]
:notification [quo.icons/icon :i/notification
{:color (style/mute-notification-icon-color theme)
:accessibility-label :unviewed-messages-public}]
nil))]))
@@ -7,8 +7,7 @@
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.core :as rn]))
(defn- logo-component
[logo]
@@ -83,7 +82,7 @@
:style {:margin-left 10}}
component])))
(defn- view-internal
(defn view
"Options:
:type - :discover/engage/share
@@ -116,49 +115,48 @@
:unread-count - number - When the info is :mention, it will be used to show
the number of unread mentions.
"
[]
(let [pressed? (reagent/atom false)]
(fn [{:keys [members type info tokens locked? title subtitle
logo blur? customization-color
on-press on-long-press on-press-info
container-style unread-count theme]}]
[rn/pressable
{:accessibility-label :container
:on-press-in (fn [] (reset! pressed? true))
:on-press on-press
:on-long-press on-long-press
:on-press-out (fn [] (reset! pressed? false))
:style (merge (style/container {:blur? blur?
:customization-color customization-color
:info info
:type type
:pressed? @pressed?
:theme theme})
container-style)}
[logo-component logo]
[rn/view {:style {:flex 1}}
[title-component
{:blur? blur?
:info info
:theme theme
:title title
:type type}]
(when (and (= type :share) subtitle)
[subtitle-component subtitle blur? theme])
(when (and members (= type :discover))
[community-view/community-stats-column
{:type :list-view
:members-count (:members-count members)
:active-count (:active-count members)}])]
[info-component
{:blur? blur?
:customization-color customization-color
:info info
:type type
:locked? locked?
:on-press-info on-press-info
:theme theme
:tokens tokens
:unread-count unread-count}]])))
[{:keys [members type info tokens locked? title subtitle logo blur? customization-color
on-press on-long-press on-press-info container-style unread-count]}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/pressable
{:accessibility-label :container
(def view (quo.theme/with-theme view-internal))
:on-press on-press
:on-long-press on-long-press
:on-press-in on-press-in
:on-press-out on-press-out
:style (merge (style/container {:blur? blur?
:customization-color customization-color
:info info
:type type
:pressed? pressed?
:theme theme})
container-style)}
[logo-component logo]
[rn/view {:style {:flex 1}}
[title-component
{:blur? blur?
:info info
:theme theme
:title title
:type type}]
(when (and (= type :share) subtitle)
[subtitle-component subtitle blur? theme])
(when (and members (= type :discover))
[community-view/community-stats-column
{:type :list-view
:members-count (:members-count members)
:active-count (:active-count members)}])]
[info-component
{:blur? blur?
:customization-color customization-color
:info info
:type type
:locked? locked?
:on-press-info on-press-info
:theme theme
:tokens tokens
:unread-count unread-count}]]))
+37 -39
View File
@@ -6,43 +6,41 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[reagent.core :as reagent]))
[react-native.fast-image :as fast-image]))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)]
(fn [{:keys [dapp action on-press on-press-icon theme] :as props}]
[rn/pressable
{:style (style/container (assoc props :pressed? @pressed?))
:on-press on-press
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)}
[rn/view {:style style/container-info}
[fast-image/fast-image
{:source (:avatar dapp)
:style {:width 32 :height 32}}]
[rn/view {:style style/user-info}
[text/text
{:weight :semi-bold
:size :paragraph-1
:style (style/style-text-name theme)}
(:name dapp)]
[text/text
{:weight :regular
:size :paragraph-2
:style (style/style-text-value theme)}
(:value dapp)]]]
(when (= action :icon)
[rn/pressable
{:on-press on-press-icon
:testID "dapp-component-icon"}
[icons/icon :i/options
{:color (colors/theme-colors
colors/neutral-50
colors/neutral-40
theme)
:accessibility-label :icon}]])])))
(def view
(quo.theme/with-theme view-internal))
(defn view
[{:keys [dapp action on-press on-press-icon] :as props}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))]
[rn/pressable
{:style (style/container (assoc props :pressed? pressed?))
:on-press on-press
:on-press-in on-press-in
:on-press-out on-press-out}
[rn/view {:style style/container-info}
[fast-image/fast-image
{:source (:avatar dapp)
:style {:width 32 :height 32}}]
[rn/view {:style style/user-info}
[text/text
{:weight :semi-bold
:size :paragraph-1
:style (style/style-text-name theme)}
(:name dapp)]
[text/text
{:weight :regular
:size :paragraph-2
:style (style/style-text-value theme)}
(:value dapp)]]]
(when (= action :icon)
[rn/pressable
{:on-press on-press-icon
:testID "dapp-component-icon"}
[icons/icon :i/options
{:color (colors/theme-colors
colors/neutral-50
colors/neutral-40
theme)
:accessibility-label :icon}]])]))
@@ -5,7 +5,6 @@
[quo.components.markdown.text :as text]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- info
@@ -22,18 +21,19 @@
(if (string/blank? label) "-" label)]]])
(defn- values
[{:keys [token-value fiat-value theme]}]
[rn/view {:style style/values-container}
[text/text
{:weight :medium
:size :paragraph-2
:number-of-lines 1}
token-value]
[text/text
{:style (style/fiat-value theme)
:size :paragraph-2
:number-of-lines 1}
fiat-value]])
[{:keys [token-value fiat-value]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style style/values-container}
[text/text
{:weight :medium
:size :paragraph-2
:number-of-lines 1}
token-value]
[text/text
{:style (style/fiat-value theme)
:size :paragraph-2
:number-of-lines 1}
fiat-value]]))
(def ?schema
[:=>
@@ -51,26 +51,21 @@
:any])
(defn- view-internal
[]
(let [pressed? (reagent/atom false)
on-press-in #(reset! pressed? true)
on-press-out #(reset! pressed? false)]
(fn [{:keys [on-press state customization-color theme]
:as props
:or {customization-color :blue}}]
(let [internal-state (if @pressed?
:pressed
state)]
[{:keys [on-press state customization-color]
:as props
:or {customization-color :blue}}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))
internal-state (if pressed? :pressed state)]
[rn/pressable
{:style (style/container internal-state customization-color theme)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :network-list}
[info props]
[values props]]))
[rn/pressable
{:style (style/container internal-state customization-color theme)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :network-list}
[info props]
[values props]]))))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
(def view (schema/instrument #'view-internal ?schema))
@@ -76,12 +76,12 @@
:blur? overflow-label blur?}
items preview list items (only 4 items is required for preview)
"
[{:keys [type size number blur?]} items]
[{:keys [type size number blur? container-style]} items]
(let [size-key (if (contains? properties/sizes size) size :size-24)
number (or number (count items))
border-type (properties/border-type type)
margin-left (get-in properties/sizes [size-key :margin-left])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (assoc container-style :flex-direction :row)}
(for [index (range (if (> number 4) 3 number))]
^{:key (str index number)}
[list-item
@@ -7,70 +7,69 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.address :as address]))
(defn- left-container
[{:keys [blur? theme name ens address customization-color]}]
[rn/view {:style style/left-container}
[wallet-user-avatar/wallet-user-avatar
{:size :size-32
:full-name name
:customization-color customization-color}]
[rn/view {:style style/account-container}
[text/text
{:weight :semi-bold
:size :paragraph-1
:style style/name-text}
name]
[text/text {:size :paragraph-2}
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address blur? theme)}
(or ens (address/get-shortened-key address))]]]])
[{:keys [blur? name ens address customization-color]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style style/left-container}
[wallet-user-avatar/wallet-user-avatar
{:size :size-32
:full-name name
:customization-color customization-color}]
[rn/view {:style style/account-container}
[text/text
{:weight :semi-bold
:size :paragraph-1
:style style/name-text}
name]
[text/text {:size :paragraph-2}
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address blur? theme)}
(or ens (address/get-shortened-key address))]]]]))
(defn- internal-view
[]
(let [state (reagent/atom :default)
active? (atom false)
timer (atom nil)
on-press-in (fn []
(when-not (= @state :selected)
(reset! timer (js/setTimeout #(reset! state :pressed) 100))))]
(fn [{:keys [blur? user-props active-state? customization-color
on-press
on-options-press
theme]
:or {customization-color :blue
blur? false}}]
(let [on-press-out (fn []
(let [new-state (if (or (not active-state?) @active?) :default :active)]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active? (= new-state :active))
(reset! state new-state)))]
[rn/pressable
{:style (style/container
{:state @state :blur? blur? :customization-color customization-color})
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :container}
[left-container
{:blur? blur?
:theme theme
:name (:name user-props)
:ens (:ens user-props)
:address (:address user-props)
:customization-color (or (:customization-color user-props) :blue)}]
(when on-options-press
[rn/pressable
{:accessibility-label :options-button
:on-press on-options-press}
[icon/icon :i/options
{:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])]))))
(def view (quo.theme/with-theme internal-view))
(defn view
[{:keys [blur? user-props active-state? customization-color on-press on-options-press]
:or {customization-color :blue
blur? false}}]
(let [theme (quo.theme/use-theme-value)
[state set-state] (rn/use-state :default)
active? (rn/use-ref-atom false)
timer (rn/use-ref-atom nil)
on-press-in (rn/use-callback
(fn []
(when-not (= state :selected)
(reset! timer (js/setTimeout #(set-state :pressed) 100))))
[state])
on-press-out (rn/use-callback
(fn []
(let [new-state (if (or (not active-state?) @active?) :default :active)]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active? (= new-state :active))
(set-state new-state)))
[active-state?])]
[rn/pressable
{:style (style/container
{:state state :blur? blur? :customization-color customization-color})
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :container}
[left-container
{:blur? blur?
:theme theme
:name (:name user-props)
:ens (:ens user-props)
:address (:address user-props)
:customization-color (or (:customization-color user-props) :blue)}]
(when on-options-press
[rn/pressable
{:accessibility-label :options-button
:on-press on-options-press}
[icon/icon :i/options
{:color (if blur?
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])]))
@@ -23,7 +23,6 @@
[:contact-props ?contact]
[:accounts {:optional true} ?accounts]
[:on-press {:optional true} [:maybe fn?]]
[:theme :schema.common/theme]
[:active-state? {:optional true} [:maybe :boolean]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]]]
:any])
@@ -9,91 +9,89 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]
[utils.address :as address]
[utils.i18n :as i18n]))
(defn- account
[{:keys [emoji name address customization-color theme]}]
[rn/view
{:accessibility-label :account-container
:style style/account-container}
[account-avatar/view
{:emoji emoji
:size 16
:customization-color customization-color}]
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-name theme)}
name]
[rn/view {:style (style/dot-divider theme)}]
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address theme)}
(address/get-shortened-key address)]])
[{:keys [emoji name address customization-color]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view
{:accessibility-label :account-container
:style style/account-container}
[account-avatar/view
{:emoji emoji
:size 16
:customization-color customization-color}]
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-name theme)}
name]
[rn/view {:style (style/dot-divider theme)}]
[text/text
{:size :paragraph-2
:weight :monospace
:style (style/account-address theme)}
(address/get-shortened-key address)]]))
(defn- internal-view
[]
(let [state (reagent/atom :default)
active? (atom false)
timer (atom nil)
on-press-in (fn []
(when-not (= @state :selected)
(reset! timer (js/setTimeout #(reset! state :pressed) 100))))]
(fn [{:keys [contact-props accounts active-state? customization-color on-press theme]
:or {customization-color :blue
accounts []
active-state? true}}]
(let [accounts-count (count accounts)
account-props (when (= accounts-count 1)
(first accounts))
on-press-out (fn []
[{:keys [contact-props accounts active-state? customization-color on-press]
:or {customization-color :blue
accounts []
active-state? true}}]
(let [theme (quo.theme/use-theme-value)
[state set-state] (rn/use-state :default)
active? (rn/use-ref-atom false)
timer (rn/use-ref-atom nil)
on-press (rn/use-callback #(when on-press (on-press)))
on-press-in (rn/use-callback
(fn []
(when-not (= state :selected)
(reset! timer (js/setTimeout #(set-state :pressed) 100))))
[state])
accounts-count (count accounts)
account-props (when (= accounts-count 1) (first accounts))
on-press-out (rn/use-callback
(fn []
(let [new-state (if (or (not active-state?) @active?) :default :active)]
(when @timer (js/clearTimeout @timer))
(reset! timer nil)
(reset! active? (= new-state :active))
(reset! state new-state)))]
[rn/pressable
{:style (style/container
{:state @state :customization-color customization-color})
:on-press-in on-press-in
:on-press-out on-press-out
:on-press #(when on-press
(on-press))
:accessibility-label :container}
[rn/view {:style style/left-container}
[user-avatar/user-avatar (assoc contact-props :size :small)]
[rn/view {:style style/saved-contact-container}
[rn/view
{:style style/account-title-container}
[text/text
{:weight :semi-bold
:size :paragraph-1}
(:full-name contact-props)]
[icon/icon :i/contact
{:container-style style/contact-icon-container
:accessibility-label :contact-icon
:size 12
:color (colors/theme-colors colors/primary-50 colors/primary-60 theme)
:color-2 colors/white}]]
(if account-props
[account (assoc account-props :theme theme)]
[text/text
{:accessibility-label :accounts-count
:size :paragraph-2
:style (style/accounts-count theme)}
(i18n/label :t/accounts-count {:count accounts-count})])]]
(when (> accounts-count 1)
[icon/icon :i/chevron-right
{:accessibility-label :check-icon
:size 20
:color (colors/theme-colors colors/neutral-50
colors/neutral-40
theme)}])]))))
(set-state new-state)))
[active-state?])]
[rn/pressable
{:style (style/container {:state state :customization-color customization-color})
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :container}
[rn/view {:style style/left-container}
[user-avatar/user-avatar (assoc contact-props :size :small)]
[rn/view {:style style/saved-contact-container}
[rn/view
{:style style/account-title-container}
[text/text
{:weight :semi-bold
:size :paragraph-1}
(:full-name contact-props)]
[icon/icon :i/contact
{:container-style style/contact-icon-container
:accessibility-label :contact-icon
:size 12
:color (colors/theme-colors colors/primary-50 colors/primary-60 theme)
:color-2 colors/white}]]
(if account-props
[account (assoc account-props :theme theme)]
[text/text
{:accessibility-label :accounts-count
:size :paragraph-2
:style (style/accounts-count theme)}
(i18n/label :t/accounts-count {:count accounts-count})])]]
(when (> accounts-count 1)
[icon/icon :i/chevron-right
{:accessibility-label :check-icon
:size 20
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}])]))
(def view
(quo.theme/with-theme
(schema/instrument #'internal-view component-schema/?schema)))
(def view (schema/instrument #'internal-view component-schema/?schema))
@@ -11,6 +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} [:enum :default :active :selected]]
[:theme :schema.common/theme]]]
[:state {:optional true} [:enum :default :active :selected]]]]
:any])
@@ -8,7 +8,6 @@
[quo.components.utilities.token.view :as token]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- info
@@ -31,44 +30,40 @@
networks]]])
(defn- values
[{:keys [state token-value fiat-value customization-color theme]}]
(if (= state :selected)
[icon/icon :i/check
{:color (style/check-color customization-color theme)
:accessibility-label :check-icon}]
[rn/view {:style style/values-container}
[text/text
{:weight :medium
:size :paragraph-2
:number-of-lines 1}
token-value]
[text/text
{:style (style/fiat-value theme)
:size :paragraph-2
:number-of-lines 1}
fiat-value]]))
[{:keys [state token-value fiat-value customization-color]}]
(let [theme (quo.theme/use-theme-value)]
(if (= state :selected)
[icon/icon :i/check
{:color (style/check-color customization-color theme)
:accessibility-label :check-icon}]
[rn/view {:style style/values-container}
[text/text
{:weight :medium
:size :paragraph-2
:number-of-lines 1}
token-value]
[text/text
{:style (style/fiat-value theme)
:size :paragraph-2
:number-of-lines 1}
fiat-value]])))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)
on-press-in #(reset! pressed? true)
on-press-out #(reset! pressed? false)]
(fn [{:keys [on-press state customization-color
_token _networks _token-value _fiat-value theme]
:as props
:or {customization-color :blue}}]
(let [internal-state (if @pressed?
:pressed
state)]
[rn/pressable
{:style (style/container internal-state customization-color theme)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :token-network}
[info props]
[values props]]))))
[{:keys [on-press state customization-color _token _networks _token-value _fiat-value]
:as props
:or {customization-color :blue}}]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed] (rn/use-state false)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed false))
internal-state (if pressed? :pressed state)]
[rn/pressable
{:style (style/container internal-state customization-color theme)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:accessibility-label :token-network}
[info props]
[values props]]))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal component-schema/?schema)))
(def view (schema/instrument #'view-internal component-schema/?schema))
@@ -17,7 +17,6 @@
[:values ?values]
[:on-press {:optional true} [:maybe fn?]]
[:on-long-press {:optional true} [:maybe fn?]]
[:theme :schema.common/theme]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:metrics? {:optional true} [:maybe :boolean]]]]
:any])
@@ -9,64 +9,67 @@
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[schema.core :as schema]))
(defn- internal-view
[]
(let [state (reagent/atom :default)]
(fn [{:keys [theme customization-color status token metrics? values on-press on-long-press
token-name]}]
(let [bg-opacity (case @state
:active 10
:pressed 5
0)
{:keys [crypto-value fiat-value percentage-change fiat-change]} values]
[rn/pressable
{:style (style/container customization-color bg-opacity theme)
:on-press-in #(reset! state :pressed)
:on-press-out #(reset! state :default)
:on-press (fn []
(reset! state :active)
(js/setTimeout #(reset! state :default) 300)
on-press)
:on-long-press on-long-press
:accessibility-label :container}
[rn/view
{:style {:flex-direction :row
:align-items :center
:flex 1}}
[token/view {:token token :size :size-32}]
[rn/view {:style {:margin-left 8}}
[text/text {:weight :semi-bold} token-name]
[text/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(str crypto-value " " (if token (string/upper-case (clj->js token)) ""))]]]
[rn/view
{:style {:align-items :flex-end
:justify-content :space-between}}
[text/text
{:weight :medium
:size :paragraph-2} fiat-value]
(when metrics?
[rn/view
{:style {:flex-direction :row
:align-items :center}}
[text/text
{:size :paragraph-2
:style (style/metric-text status theme)} (str percentage-change "%")]
[rn/view {:style (style/dot-divider status theme)}]
[text/text
{:size :paragraph-2
:style (style/metric-text status theme)} fiat-change]
(when (not= status :empty)
[rn/view
{:style {:margin-left 4}
:accessibility-label :arrow-icon}
[icon/icon (if (= status :positive) :i/positive :i/negative)
(style/arrow-icon status theme)]])])]]))))
[{:keys [customization-color status token metrics? values on-press on-long-press token-name]}]
(let [theme (quo.theme/use-theme-value)
[state set-state] (rn/use-state :default)
bg-opacity (case state
:active 10
:pressed 5
0)
{:keys [crypto-value
fiat-value
percentage-change
fiat-change]} values
on-press-in (rn/use-callback #(set-state :pressed))
on-press-out (rn/use-callback #(set-state :default))
on-press (rn/use-callback
(fn []
(set-state :active)
(js/setTimeout #(set-state :default) 300)
on-press))]
[rn/pressable
{:style (style/container customization-color bg-opacity theme)
:on-press-in on-press-in
:on-press-out on-press-out
:on-press on-press
:on-long-press on-long-press
:accessibility-label :container}
[rn/view
{:style {:flex-direction :row
:align-items :center
:flex 1}}
[token/view {:token token :size :size-32}]
[rn/view {:style {:margin-left 8}}
[text/text {:weight :semi-bold} token-name]
[text/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(str crypto-value " " (if token (string/upper-case (clj->js token)) ""))]]]
[rn/view
{:style {:align-items :flex-end
:justify-content :space-between}}
[text/text
{:weight :medium
:size :paragraph-2} fiat-value]
(when metrics?
[rn/view
{:style {:flex-direction :row
:align-items :center}}
[text/text
{:size :paragraph-2
:style (style/metric-text status theme)} (str percentage-change "%")]
[rn/view {:style (style/dot-divider status theme)}]
[text/text
{:size :paragraph-2
:style (style/metric-text status theme)} fiat-change]
(when (not= status :empty)
[rn/view
{:style {:margin-left 4}
:accessibility-label :arrow-icon}
[icon/icon (if (= status :positive) :i/positive :i/negative)
(style/arrow-icon status theme)]])])]]))
(def view
(quo.theme/with-theme
(schema/instrument #'internal-view component-schema/?schema)))
(def view (schema/instrument #'internal-view component-schema/?schema))
+4 -3
View File
@@ -18,9 +18,9 @@
:align-items :center})
(defn action-icon
[{:keys [type on-press on-check disabled? checked?]} theme]
[{:keys [type on-press on-check disabled? checked?]} customization-color theme]
[rn/touchable-opacity
{:on-press (when on-press on-press)}
{:on-press on-press}
(case type
:options
[icons/icon :i/options
@@ -30,6 +30,7 @@
[selectors/view
{:type :checkbox
:checked? checked?
:customization-color customization-color
:accessibility-label :user-list-toggle-check
:disabled? disabled?
:on-change (when on-check on-check)}]
@@ -68,4 +69,4 @@
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
short-chat-key])]
(when accessory
[action-icon accessory theme])]])
[action-icon accessory customization-color theme])]])
+22 -22
View File
@@ -5,8 +5,7 @@
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.core :as rn]))
;;; helpers
(def themes
@@ -137,24 +136,25 @@
style
on-press
warning-label]}]
(let [body-height (reagent/atom nil)]
(fn []
[rn/view
{:on-layout #(reset! body-height (oget % "nativeEvent.layout.height"))
:overflow :hidden
:flex 1}
[hborder {:type :top}]
[hborder {:type :bottom}]
[rn/view
(merge {:width "100%"
:background-color (get-color :background)
:flex-direction :row
:padding 20
:padding-left 31
:margin-vertical 4}
style)
(let [[body-height set-body-height] (rn/use-state nil)
on-layout (rn/use-callback #(set-body-height
(oget % "nativeEvent.layout.height")))]
[rn/view
{:on-layout on-layout
:overflow :hidden
:flex 1}
[hborder {:type :top}]
[hborder {:type :bottom}]
[rn/view
(merge {:width "100%"
:background-color (get-color :background)
:flex-direction :row
:padding 20
:padding-left 31
:margin-vertical 4}
style)
[timeline]
[body timestamp-far timestamp-near on-info-button-pressed on-press warning-label]]
[vborder :left body-height]
[vborder :right body-height]])))
[timeline]
[body timestamp-far timestamp-near on-info-button-pressed on-press warning-label]]
[vborder :left body-height]
[vborder :right body-height]]))
@@ -35,7 +35,7 @@
:on-press on-press
:background (if behind-overlay?
:blur
(button-properties/backgrounds background))
(when (button-properties/backgrounds background) background))
:accessibility-label accessibility-label}
icon-name])]
children))
@@ -4,50 +4,48 @@
[quo.components.markdown.text :as text]
[quo.components.numbered-keyboard.keyboard-key.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.core :as rn]))
(defn- label->accessibility-label
[label]
(let [label-name (if (keyword? label) (name label) label)]
(keyword (str "keyboard-key-" label-name))))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)]
(fn [{:keys [disabled? theme blur? on-press on-long-press type]} label]
(let [label-color (style/get-label-color disabled? theme blur?)
background-color (style/toggle-background-color @pressed? blur? theme)]
[rn/pressable
{:accessibility-label (label->accessibility-label label)
:disabled (or disabled? (not label))
:on-press (fn []
(when on-press
(on-press label)))
:on-long-press (fn []
(when (fn? on-long-press)
(on-long-press label)))
:allow-multiple-presses? true
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)
:hit-slop {:top 8 :bottom 8 :left 25 :right 25}
:style (style/container background-color)}
(case type
:key [icons/icon
label
{:color label-color
:accessibility-label :icon-label}]
:digit [text/text
{:accessibility-label :text-label
:weight :regular
:size :heading-1
:style {:color label-color}}
label]
:derivation-path [icons/icon
:i/derivation-path
{:color label-color
:size 32
:accessibility-label :derivation-path-label}]
nil)]))))
(def view (quo.theme/with-theme view-internal))
(defn view
[{:keys [disabled? blur? on-press on-long-press type]} label]
(let [theme (quo.theme/use-theme-value)
[pressed? set-pressed?] (rn/use-state false)
on-press (rn/use-callback #(when on-press (on-press label)) [label])
on-long-press (rn/use-callback #(when (fn? on-long-press) (on-long-press label))
[label])
on-press-in (rn/use-callback #(set-pressed? true))
on-press-out (rn/use-callback #(set-pressed? false))
label-color (style/get-label-color disabled? theme blur?)
background-color (style/toggle-background-color pressed? blur? theme)]
[rn/pressable
{:accessibility-label (label->accessibility-label label)
:disabled (or disabled? (not label))
:on-press on-press
:on-long-press on-long-press
:allow-multiple-presses? true
:on-press-in on-press-in
:on-press-out on-press-out
:hit-slop {:top 8 :bottom 8 :left 25 :right 25}
:style (style/container background-color)}
(case type
:key [icons/icon
label
{:color label-color
:accessibility-label :icon-label}]
:digit [text/text
{:accessibility-label :text-label
:weight :regular
:size :heading-1
:style {:color label-color}}
label]
:derivation-path [icons/icon
:i/derivation-path
{:color label-color
:size 32
:accessibility-label :derivation-path-label}]
nil)]))
@@ -1,9 +1,9 @@
(ns quo.components.profile.collectible.view
(:require
[clojure.string :as string]
[quo.components.markdown.text :as text]
[quo.components.profile.collectible.style :as style]
[react-native.core :as rn]
[react-native.svg :as svg]))
[react-native.core :as rn]))
(defn remaining-tiles
[amount]
@@ -19,11 +19,28 @@
(let [svg? (and (map? resource) (:svg? resource))
image-style (style/tile-style-by-size size)]
[rn/view {:style style}
(if svg?
(cond
svg?
[rn/view
{:style {:border-radius (:border-radius image-style)
:overflow :hidden}}
[svg/svg-uri (assoc image-style :uri (:uri resource))]]
{:style (assoc image-style
:border-radius (:border-radius image-style)
:overflow :hidden
:justify-content :center
:align-items :center
:background-color :lightblue)}
[text/text "SVG Content"]]
(or (string/blank? resource) (string/blank? (:uri resource)))
[rn/view
{:style (assoc image-style
:border-radius (:border-radius image-style)
:overflow :hidden
:justify-content :center
:align-items :center
:background-color :lightgray)}
[text/text "Missing image"]]
:else
;; NOTE: using react-native-fast-image here causes a crash on devices when used inside a
;; large flatlist. The library seems to have issues with memory consumption when used with
;; large images/GIFs.
@@ -0,0 +1,116 @@
(ns quo.components.profile.collectible-list-item.component-spec
(:require
[quo.components.profile.collectible-list-item.view :as collectible-list-item]
[test-helpers.component :as h]))
(h/describe "Profile/ collectible list item tests"
(h/describe "type card"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders counter and collectible name"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:collectible-name "Doodle #6822"
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-text "Doodle #6822")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-translation-text :t/unsupported-file))))
(h/describe "type image"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported
:counter "x500"}])
(h/get-by-text "x500")
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
@@ -0,0 +1,90 @@
(ns quo.components.profile.collectible-list-item.style
(:require [quo.foundations.colors :as colors]
[quo.foundations.shadows :as shadows]))
(def container-border-radius 12)
(def card-image-padding-vertical 3)
(def card-image-padding-horizontal 3)
(defn fallback
[{:keys [theme]}]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius container-border-radius
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
(def collectible-counter
{:position :absolute
:top 12
:right 12})
(def avatar
{:position :absolute
:bottom 12
:left 12})
(def container
{:flex 1})
(defn card-view-container
[theme]
(merge
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:padding-top card-image-padding-vertical
:padding-left card-image-padding-horizontal
:padding-right card-image-padding-horizontal
:padding-bottom card-image-padding-vertical
:border-radius 14
:border-width 1
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)}
(shadows/get 2)))
(def image
{:width "100%"
:flex 1
:border-radius container-border-radius})
(def card-details-container
{:flex-direction :row
:height 27
:margin-top 3
:margin-bottom 2
:align-items :center
:padding-left 8
:padding-right 0
:padding-top 4})
(def card-detail-text
{:flex 1})
(def image-view-container
{:aspect-ratio 1
:border-radius container-border-radius})
(defn loading-square
[theme]
{:height 20
:width 20
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-message
[theme]
{:height 14
:width 72
:margin-left 8
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-image
[theme]
{:flex 1
:border-radius container-border-radius
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)})
@@ -0,0 +1,195 @@
(ns quo.components.profile.collectible-list-item.view
(:require
[quo.components.avatars.collection-avatar.view :as collection-avatar]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
[quo.components.list-items.preview-list.view :as preview-list]
[quo.components.markdown.text :as quo]
[quo.components.profile.collectible-list-item.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.gradients :as gradients]
[quo.theme]
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- fallback-view
[{:keys [label theme type]}]
[rn/view
{:style (style/fallback {:type type
:theme theme})}
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[rn/view {:style {:height 4}}]
[quo/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
label]])
(defn- loading-square
[theme]
[rn/view {:style (style/loading-square theme)}])
(defn- loading-message
[theme]
[rn/view {:style (style/loading-message theme)}])
(defn- loading-image
[{:keys [theme gradient-color-index]}]
[gradients/view
{:theme theme
:container-style (style/loading-image theme)
:color-index gradient-color-index}])
(defn- card-details
[{:keys [status community? avatar-image-src collectible-name theme]}]
[rn/view {:style style/card-details-container}
(cond (= :cant-fetch status)
[quo/text
{:size :paragraph-1
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(i18n/label :t/unknown)]
(= :loading status)
[rn/view {:style {:flex-direction :row}}
[loading-square theme]
[loading-message theme]]
community?
[:<>
[preview-list/view
{:type :communities
:size :size-20}
[avatar-image-src]]
[rn/view {:style {:width 8}}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style style/card-detail-text}
collectible-name]]
:else
[:<>
[collection-avatar/view
{:size :size-20
:image avatar-image-src}]
[rn/view {:style {:width 8}}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:ellipsize-mode :tail
:number-of-lines 1
:style style/card-detail-text}
collectible-name]])])
(defn- card-view
[{:keys [avatar-image-src collectible-name community? counter
gradient-color-index image-src status type]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style (style/card-view-container theme)}
[rn/view {:style {:aspect-ratio 1}}
(cond
(= :loading status)
[loading-image
{:theme theme
:gradient-color-index gradient-color-index}]
(= status :unsupported)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/cant-fetch-info)}]
:else
[rn/view {:style {:aspect-ratio 1}}
[rn/image
{:style style/image
:source image-src}]])]
(when (and (not= status :loading) (not= status :cant-fetch) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
:value counter}])
[card-details
{:status status
:community? community?
:avatar-image-src avatar-image-src
:collectible-name collectible-name
:theme theme}]]))
(defn- image-view
[{:keys [avatar-image-src community? counter
gradient-color-index image-src status]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style style/image-view-container}
(cond
(= :loading status)
[loading-image
{:theme theme
:gradient-color-index gradient-color-index}]
(= status :unsupported)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/cant-fetch-info)}]
:else [rn/view {:style {:aspect-ratio 1}}
[rn/image
{:style style/image
:source image-src}]])
(when (and (not= status :loading) (not= status :cant-fetch) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
:value counter}])
(when (and (not= status :loading) (not= status :cant-fetch) community?)
[preview-list/view
{:container-style style/avatar
:type :communities
:size :size-24}
[avatar-image-src]])]))
(defn- view-internal
[{:keys [container-style type on-press status]
:as props}]
[rn/pressable
{:on-press (when-not (= status :loading) on-press)
:accessibility-label :collectible-list-item
:style (merge container-style style/container)}
(if (= type :card)
[card-view props]
[image-view props])])
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:avatar-image-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-name {:optional true} [:maybe string?]]
[:community? {:optional true} [:maybe boolean?]]
[:counter {:optional true} [:maybe string?]]
[:gradient-color-index {:optional true}
[:maybe [:enum :gradient-1 :gradient-2 :gradient-3 :gradient-4 :gradient-5]]]
[:image-src {:optional true} [:maybe :schema.common/image-source]]
[:on-press {:optional true} [:maybe fn?]]
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
[:type [:enum :card :image]]]]]
:any])
(def view (schema/instrument #'view-internal ?schema))
@@ -3,48 +3,33 @@
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.markdown.text :as text]
[quo.components.profile.select-profile.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- on-change-handler
[selected? on-change]
(swap! selected? not)
(when on-change (on-change @selected?)))
[react-native.core :as rn]))
(defn view
"Options
- `default-selected?` The default selected state. Use when the component is not controlled.
- `selected?` Selected state. Use when the component is controlled.
- `name` Full name
- `profile-picture` Profile picture
- `customization-color` Customization color
- `(on-change selected?)` On change event handler
"
[{:keys [default-selected?]}]
(let [internal-selected? (reagent/atom (or default-selected? false))]
(fn [{:keys [selected?
profile-picture
name
customization-color
on-change]
:or {customization-color :turquoise}}]
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
(reset! internal-selected? selected?))
[rn/touchable-opacity
{:style (style/container customization-color @internal-selected?)
:on-press #(on-change-handler internal-selected? on-change)
:active-opacity 1
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
:profile-picture profile-picture}]
[rn/view {:style (style/select-radio @internal-selected?)}
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]])))
[{:keys [selected? profile-picture name customization-color on-change]
:or {customization-color :turquoise}}]
[rn/touchable-opacity
{:style (style/container customization-color selected?)
:on-press #(when on-change (on-change (not selected?)))
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
:profile-picture profile-picture}]
[rn/view {:style (style/select-radio selected?)}
(when selected?
[rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]])
@@ -1,7 +1,6 @@
(ns quo.components.profile.showcase-nav.component-spec
(:require
[quo.components.profile.showcase-nav.view :as view]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(def nav-data
@@ -35,7 +34,7 @@
(.toHaveBeenCalled))))
(h/test "active id updated"
(let [active-id (reagent/atom :recent)]
(let [active-id (atom :recent)]
(h/render [view/view
{:data nav-data
:on-press #(reset! active-id %)}])
@@ -4,10 +4,10 @@
[quo.components.record-audio.record-audio.helpers :as helpers]
[quo.components.record-audio.record-audio.style :as style]
[quo.foundations.colors :as colors]
[react-native.core :refer [use-effect]]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]))
(defn f-delete-button
(defn delete-button
[recording? ready-to-delete? reviewing-audio? force-show-controls?]
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
translate-x (reanimated/use-shared-value (if force-show-controls? 35 20))
@@ -17,62 +17,68 @@
connector-height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-animation (fn []
(helpers/animate-linear-with-delay translate-x 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay connector-width 56 83.33 80)
(helpers/animate-easing-with-delay connector-height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80))
reset-x-animation (fn []
(helpers/animate-linear translate-x 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-in-animation (fn []
(helpers/animate-linear translate-x 0 200)
(helpers/animate-linear opacity 1 200))
fade-out-animation (fn []
(helpers/animate-linear
translate-x
(if @reviewing-audio? 35 20)
200)
(if @reviewing-audio?
(helpers/animate-linear scale 0.75 200)
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-x 20 0 200)
(helpers/animate-linear-with-delay scale 1 0 200))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(when-not @reviewing-audio?
(fade-out-reset-animation)))
[@reviewing-audio?])
(use-effect (fn []
(cond
@ready-to-delete?
(start-x-animation)
@recording?
(reset-x-animation)))
[@ready-to-delete?])
start-x-animation (rn/use-callback
(fn []
(helpers/animate-linear-with-delay translate-x 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay connector-width 56 83.33 80)
(helpers/animate-easing-with-delay connector-height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80)))
reset-x-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-x 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16)))
fade-in-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-x 0 200)
(helpers/animate-linear opacity 1 200)))
fade-out-animation (rn/use-callback
(fn []
(helpers/animate-linear
translate-x
(if reviewing-audio? 35 20)
200)
(if reviewing-audio?
(helpers/animate-linear scale 0.75 200)
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value connector-width 24)
(helpers/set-value connector-height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
[reviewing-audio?])
fade-out-reset-animation (rn/use-callback
(fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-x 20 0 200)
(helpers/animate-linear-with-delay scale 1 0 200)))]
(rn/use-effect (fn []
(if recording?
(fade-in-animation)
(fade-out-animation)))
[recording?])
(rn/use-effect (fn []
(when-not reviewing-audio?
(fade-out-reset-animation)))
[reviewing-audio?])
(rn/use-effect (fn []
(cond
ready-to-delete?
(start-x-animation)
recording?
(reset-x-animation)))
[ready-to-delete?])
[:<>
[reanimated/view {:style (style/delete-button-container opacity)}
[reanimated/view
@@ -5,10 +5,10 @@
[quo.components.record-audio.record-audio.style :as style]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :refer [use-effect]]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]))
(defn f-lock-button
(defn lock-button
[recording? ready-to-lock? locked?]
(let [theme (quo.theme/use-theme-value)
translate-x-y (reanimated/use-shared-value 20)
@@ -18,54 +18,58 @@
height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-y-animation (fn []
(helpers/animate-linear-with-delay translate-x-y 8 50 116.66)
(helpers/animate-easing-with-delay connector-opacity 1 0 80)
(helpers/animate-easing-with-delay width 56 83.33 63.33)
(helpers/animate-easing-with-delay height 56 83.33 63.33)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
63.33)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
63.33))
reset-x-y-animation (fn []
(helpers/animate-linear translate-x-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-in-animation (fn []
(helpers/animate-linear translate-x-y 0 220)
(helpers/animate-linear opacity 1 220))
fade-out-animation (fn []
(helpers/animate-linear translate-x-y 20 200)
(helpers/animate-linear opacity 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(cond
@ready-to-lock?
(start-x-y-animation)
(and @recording? (not @locked?))
(reset-x-y-animation)))
[@ready-to-lock?])
(use-effect (fn []
(if @locked?
(fade-out-animation)
(reset-x-y-animation)))
[@locked?])
start-x-y-animation (rn/use-callback
(fn []
(helpers/animate-linear-with-delay translate-x-y 8 50 116.66)
(helpers/animate-easing-with-delay connector-opacity 1 0 80)
(helpers/animate-easing-with-delay width 56 83.33 63.33)
(helpers/animate-easing-with-delay height 56 83.33 63.33)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
63.33)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
63.33)))
reset-x-y-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-x-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16)))
fade-in-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-x-y 0 220)
(helpers/animate-linear opacity 1 220)))
fade-out-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-x-y 20 200)
(helpers/animate-linear opacity 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16)))]
(rn/use-effect (fn []
(if recording?
(fade-in-animation)
(fade-out-animation)))
[recording?])
(rn/use-effect (fn []
(cond
ready-to-lock?
(start-x-y-animation)
(and recording? (not locked?))
(reset-x-y-animation)))
[ready-to-lock?])
(rn/use-effect (fn []
(if locked?
(fade-out-animation)
(reset-x-y-animation)))
[locked?])
[:<>
[reanimated/view {:style (style/lock-button-container opacity)}
[reanimated/view
@@ -77,6 +81,6 @@
[reanimated/view
{:style (style/lock-button translate-x-y opacity)
:pointer-events :none}
[icons/icon (if @ready-to-lock? :i/locked :i/unlocked)
[icons/icon (if ready-to-lock? :i/locked :i/unlocked)
{:color (colors/theme-colors colors/black colors/white theme)
:size 20}]]]))
@@ -3,19 +3,17 @@
[quo.components.buttons.button.view :as button]
[quo.components.record-audio.record-audio.helpers :as helpers]
[quo.components.record-audio.record-audio.style :as style]
[react-native.core :as rn :refer [use-effect]]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]))
(defn f-record-button
(defn record-button
[recording? reviewing-audio?]
(let [opacity (reanimated/use-shared-value 1)
show-animation #(helpers/set-value opacity 1)
hide-animation #(helpers/set-value opacity 0)]
(use-effect (fn []
(if (or @recording? @reviewing-audio?)
(hide-animation)
(show-animation)))
[@recording? @reviewing-audio?])
(let [opacity (reanimated/use-shared-value 1)]
(rn/use-effect (fn []
(if (or recording? reviewing-audio?)
(helpers/set-value opacity 0)
(helpers/set-value opacity 1)))
[recording? reviewing-audio?])
[reanimated/view {:style (style/record-button-container opacity)}
[button/button
{:type :outline
@@ -5,8 +5,9 @@
[quo.components.record-audio.record-audio.helpers :as helpers]
[quo.components.record-audio.record-audio.style :as style]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.audio-toolkit :as audio]
[react-native.core :as rn :refer [use-effect]]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[taoensso.timbre :as log]
@@ -28,13 +29,16 @@
(reagent/as-element
[reanimated/view {:style (style/animated-circle scale opacity color)}]))))))
(defn f-record-button-big
[{:keys [recording? ready-to-send? ready-to-lock? ready-to-delete? record-button-is-animating?
record-button-at-initial-position? locked? reviewing-audio? recording-length-ms
clear-timeout touch-active? recorder-ref reload-recorder-fn idle? on-send on-cancel theme]}]
(let [scale (reanimated/use-shared-value 1)
(defn record-button-big
[{:keys [recording? set-recording ready-to-send? set-ready-to-send ready-to-lock? set-ready-to-lock
ready-to-delete? set-ready-to-delete record-button-is-animating?
record-button-at-initial-position? locked? set-locked reviewing-audio? recording-length-ms
set-recording-length-ms
clear-timeout touch-active? recorder-ref reload-recorder-fn idle? on-send on-cancel]}]
(let [theme (quo.theme/use-theme-value)
scale (reanimated/use-shared-value 1)
opacity (reanimated/use-shared-value 0)
opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default)
opacity-from (if ready-to-lock? opacity-from-lock opacity-from-default)
animations (map
(fn [index]
(let [ring-scale (worklets.record-audio/ring-scale scale
@@ -46,141 +50,155 @@
[opacity-from 0])}))
(range 0 5))
rings-color (cond
@ready-to-lock? (colors/theme-colors colors/neutral-80-opa-5-opaque
colors/neutral-80
theme)
@ready-to-delete? colors/danger-50
:else colors/primary-50)
ready-to-lock? (colors/theme-colors colors/neutral-80-opa-5-opaque
colors/neutral-80
theme)
ready-to-delete? colors/danger-50
:else colors/primary-50)
translate-y (reanimated/use-shared-value 0)
translate-x (reanimated/use-shared-value 0)
button-color colors/primary-50
icon-color (if (and (not (= :dark theme)) @ready-to-lock?) colors/black colors/white)
icon-color (if (and (not (= :dark theme)) ready-to-lock?) colors/black colors/white)
icon-opacity (reanimated/use-shared-value 1)
red-overlay-opacity (reanimated/use-shared-value 0)
gray-overlay-opacity (reanimated/use-shared-value 0)
complete-animation
(fn []
(cond
(and @ready-to-lock? (not @record-button-is-animating?))
(do
(reset! locked? true)
(reset! ready-to-lock? false))
(and (not @locked?) (not @reviewing-audio?))
(audio/stop-recording
@recorder-ref
(fn []
(cond
@ready-to-send?
(when on-send
(on-send {:file-path (audio/get-recorder-file-path @recorder-ref)
:duration @recording-length-ms}))
@ready-to-delete?
(when on-cancel
(on-cancel)))
(reload-recorder-fn)
(reset! recording? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(reset! ready-to-lock? false)
(reset! idle? true)
(js/setTimeout #(reset! idle? false) 1000)
(reset! recording-length-ms 0)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))))
start-animation (fn []
(helpers/set-value opacity 1)
(helpers/animate-linear scale 2.6 signal-anim-duration)
;; TODO: Research if we can implement this with withSequence method
;; from Reanimated 2
;; GitHub issue [#14561]:
;; https://github.com/status-im/status-mobile/issues/14561
(reset! clear-timeout
(js/setTimeout
(rn/use-callback
(fn []
(cond
(and ready-to-lock? (not @record-button-is-animating?))
(do
(set-locked true)
(set-ready-to-lock false))
(and (not locked?) (not reviewing-audio?))
(audio/stop-recording
@recorder-ref
(fn []
(cond
ready-to-send?
(when on-send
(on-send {:file-path (audio/get-recorder-file-path @recorder-ref)
:duration recording-length-ms}))
ready-to-delete?
(when on-cancel
(on-cancel)))
(reload-recorder-fn)
(set-recording false)
(set-ready-to-send false)
(set-ready-to-delete false)
(set-ready-to-lock false)
(reset! idle? true)
(js/setTimeout #(reset! idle? false) 1000)
(set-recording-length-ms 0)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))))
[ready-to-lock? locked? reviewing-audio? ready-to-send? recording-length-ms ready-to-delete?
idle?])
start-animation (rn/use-callback
(fn []
(helpers/set-value opacity 1)
(helpers/animate-linear scale 2.6 signal-anim-duration)
;; TODO: Research if we can implement this with withSequence method
;; from Reanimated 2
;; GitHub issue [#14561]:
;; https://github.com/status-im/status-mobile/issues/14561
(reset! clear-timeout
(js/setTimeout
(fn []
(helpers/set-value scale scale-to-each)
(helpers/animate-linear-with-delay-loop scale
scale-to-total
signal-anim-duration-2
0))
signal-anim-duration))))
stop-animation (rn/use-callback
(fn []
(helpers/set-value opacity 0)
(reanimated/cancel-animation scale)
(helpers/set-value scale 1)
(when @clear-timeout (js/clearTimeout @clear-timeout))))
start-y-animation (rn/use-callback
(fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
[complete-animation])
reset-y-animation (rn/use-callback
(fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-linear icon-opacity 1 500)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500)))
start-x-animation (rn/use-callback
(fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-x -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(helpers/animate-linear red-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
[complete-animation])
reset-x-animation (rn/use-callback
(fn []
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear red-overlay-opacity 0 100)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500)))
start-x-y-animation (rn/use-callback
(fn []
(helpers/set-value scale scale-to-each)
(helpers/animate-linear-with-delay-loop scale
scale-to-total
signal-anim-duration-2
0))
signal-anim-duration)))
stop-animation (fn []
(helpers/set-value opacity 0)
(reanimated/cancel-animation scale)
(helpers/set-value scale 1)
(when @clear-timeout (js/clearTimeout @clear-timeout)))
start-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-y-animation (fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-linear icon-opacity 1 500)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500))
start-x-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-x -64 250)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 76.66)
(helpers/animate-linear red-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-x-animation (fn []
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear red-overlay-opacity 0 100)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
500))
start-x-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -44 200)
(helpers/animate-easing translate-x -44 200)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 33.33)
(helpers/animate-linear gray-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
200))
reset-x-y-animation (fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear gray-overlay-opacity 0 800)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
800))]
(use-effect (fn []
(cond
@recording?
(start-animation)
(not @ready-to-lock?)
(stop-animation)))
[@recording?])
(use-effect (fn []
(if @ready-to-lock?
(start-x-y-animation)
(reset-x-y-animation)))
[@ready-to-lock?])
(use-effect (fn []
(if @ready-to-send?
(start-y-animation)
(reset-y-animation)))
[@ready-to-send?])
(use-effect (fn []
(if @ready-to-delete?
(start-x-animation)
(reset-x-animation)))
[@ready-to-delete?])
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(helpers/animate-easing translate-y -44 200)
(helpers/animate-easing translate-x -44 200)
(helpers/animate-linear-with-delay icon-opacity 0 33.33 33.33)
(helpers/animate-linear gray-overlay-opacity 1 33.33)
(js/setTimeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
200))
[complete-animation])
reset-x-y-animation (rn/use-callback
(fn []
(helpers/animate-easing translate-y 0 300)
(helpers/animate-easing translate-x 0 300)
(helpers/animate-linear icon-opacity 1 500)
(helpers/animate-linear gray-overlay-opacity 0 800)
(js/setTimeout (fn []
(reset! record-button-at-initial-position? true))
800)))]
(rn/use-effect (fn []
(cond
recording?
(start-animation)
(not ready-to-lock?)
(stop-animation)))
[recording?])
(rn/use-effect (fn []
(if ready-to-lock?
(start-x-y-animation)
(reset-x-y-animation)))
[ready-to-lock?])
(rn/use-effect (fn []
(if ready-to-send?
(start-y-animation)
(reset-y-animation)))
[ready-to-send?])
(rn/use-effect (fn []
(if ready-to-delete?
(start-x-animation)
(reset-x-animation)))
[ready-to-delete?])
[reanimated/view
{:style (style/record-button-big-container translate-x translate-y opacity)
:pointer-events :none}
@@ -197,6 +215,6 @@
[reanimated/view {:style (style/record-button-big-red-overlay red-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-gray-overlay gray-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-icon-container icon-opacity)}
(if @locked?
(if locked?
[rn/view {:style style/stop-icon}]
[icons/icon :i/audio {:color icon-color}])]]]))
@@ -4,10 +4,10 @@
[quo.components.record-audio.record-audio.helpers :as helpers]
[quo.components.record-audio.record-audio.style :as style]
[quo.foundations.colors :as colors]
[react-native.core :refer [use-effect]]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]))
(defn f-send-button
(defn send-button
[recording? ready-to-send? reviewing-audio? force-show-controls?]
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
translate-y (reanimated/use-shared-value (if force-show-controls? 76 20))
@@ -16,65 +16,71 @@
height (reanimated/use-shared-value 24)
border-radius-first-half (reanimated/use-shared-value 16)
border-radius-second-half (reanimated/use-shared-value 8)
start-y-animation (fn []
(helpers/animate-linear-with-delay translate-y 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay width 56 83.33 80)
(helpers/animate-easing-with-delay height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80))
reset-y-animation (fn []
(helpers/animate-linear translate-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 12)
(helpers/set-value height 24)
(helpers/set-value border-radius-first-half 16)
(helpers/set-value border-radius-second-half 8))
fade-in-animation (fn []
(helpers/animate-linear translate-y 0 200)
(helpers/animate-linear opacity 1 200))
fade-out-animation (fn []
(when-not force-show-controls?
(helpers/animate-linear
translate-y
(if @reviewing-audio? 76 20)
200))
(when-not @reviewing-audio?
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-y 20 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))]
(use-effect (fn []
(if @recording?
(fade-in-animation)
(fade-out-animation)))
[@recording?])
(use-effect (fn []
(when-not @reviewing-audio?
(fade-out-reset-animation)))
[@reviewing-audio?])
(use-effect (fn []
(cond
@ready-to-send?
(start-y-animation)
@recording? (reset-y-animation)))
[@ready-to-send?])
start-y-animation (rn/use-callback
(fn []
(helpers/animate-linear-with-delay translate-y 12 50 133.33)
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
(helpers/animate-easing-with-delay width 56 83.33 80)
(helpers/animate-easing-with-delay height 56 83.33 80)
(helpers/animate-easing-with-delay border-radius-first-half
28
83.33
80)
(helpers/animate-easing-with-delay border-radius-second-half
28
83.33
80)))
reset-y-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-y 0 100)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 12)
(helpers/set-value height 24)
(helpers/set-value border-radius-first-half 16)
(helpers/set-value border-radius-second-half 8)))
fade-in-animation (rn/use-callback
(fn []
(helpers/animate-linear translate-y 0 200)
(helpers/animate-linear opacity 1 200)))
fade-out-animation (rn/use-callback
(fn []
(when-not force-show-controls?
(helpers/animate-linear
translate-y
(if reviewing-audio? 76 20)
200))
(when-not reviewing-audio?
(helpers/animate-linear opacity 0 200))
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16))
[reviewing-audio? force-show-controls?])
fade-out-reset-animation (rn/use-callback
(fn []
(helpers/animate-linear opacity 0 200)
(helpers/animate-linear-with-delay translate-y 20 0 200)
(helpers/set-value connector-opacity 0)
(helpers/set-value width 24)
(helpers/set-value height 12)
(helpers/set-value border-radius-first-half 8)
(helpers/set-value border-radius-second-half 16)))]
(rn/use-effect (fn []
(if recording?
(fade-in-animation)
(fade-out-animation)))
[recording?])
(rn/use-effect (fn []
(when-not reviewing-audio?
(fade-out-reset-animation)))
[reviewing-audio?])
(rn/use-effect (fn []
(cond
ready-to-send?
(start-y-animation)
recording? (reset-y-animation)))
[ready-to-send?])
[:<>
[reanimated/view {:style (style/send-button-container opacity)}
[reanimated/view

Some files were not shown because too many files have changed in this diff Show More