Compare commits

...
Author SHA1 Message Date
Ibrkhalil 70f99407fc add initial support for channel and contact 2024-03-11 16:04:59 +02:00
Ibrahem Khalil bf9fc03670 Merge branch 'develop' into add-internal-link-preview 2024-03-08 19:29:36 +02:00
Mohsen 7a6714eeb2 [#18929] fix: no bottom space under the join button (#18987) 2024-03-08 19:24:02 +03:00
Ibrkhalil a3b04f8ce0 Remove logo tests, Because we cannot get mediaserver URLs 2024-03-08 15:00:05 +02:00
Ibrkhalil c2db5ec102 Fix tests 2024-03-08 14:43:14 +02:00
Ibrkhalil ab880b11cd clean 2024-03-08 14:43:14 +02:00
Ibrkhalil f72f3ad1c8 Bump go 2024-03-08 14:43:14 +02:00
Ibrkhalil aaef05a3c0 improvements 2024-03-08 14:43:14 +02:00
Ibrkhalil 3bf8734a7e Bump go and type check 2024-03-08 14:43:14 +02:00
Ibrkhalil 43493f82c0 Improvements 2024-03-08 14:43:13 +02:00
Ibrkhalil a80f16f632 SVG working with a single trip to image URI 2024-03-08 14:43:13 +02:00
Ibrkhalil 109ab6b2ff Improvements and bump go 2024-03-08 14:43:13 +02:00
Ibrkhalil cfa893c746 Better support for SVGs 2024-03-08 14:43:13 +02:00
Ibrkhalil 8f76fb9f97 Support SVGs 2024-03-08 14:43:12 +02:00
Ibrkhalil 5b5d602511 cleamn 2024-03-08 14:43:12 +02:00
Ibrkhalil 5e32ba8e6c Improvements 2024-03-08 14:43:12 +02:00
Ibrkhalil d63c73b6bf Improvements and support status-link-previews icon 2024-03-08 14:43:12 +02:00
Ibrkhalil f079f52941 Bump go 2024-03-08 14:43:10 +02:00
Ibrkhalil 545abee7d1 clean extra lines 2024-03-08 14:42:40 +02:00
Ibrkhalil fe6beef442 Use dynamic height 2024-03-08 14:42:40 +02:00
Ibrkhalil 5f44d2b319 Refactors 2024-03-08 14:42:40 +02:00
Ibrkhalil 8f0c4087c2 lint 2024-03-08 14:42:39 +02:00
Ibrkhalil 690aab3185 Fix typo 2024-03-08 14:42:39 +02:00
Ibrahem KhalilandLungu Cristian 843b1b57d7 Update src/status_im/subs/chats.cljs
Co-authored-by: Lungu Cristian <lungucristian95@gmail.com>
2024-03-08 14:42:39 +02:00
Ibrkhalil 160d4e6d71 Review comments 2024-03-08 14:42:39 +02:00
Ibrkhalil d7e8d3c5c2 clean 2024-03-08 14:42:39 +02:00
Ibrkhalil 962ba6ccd0 clean 2024-03-08 14:42:38 +02:00
Ibrkhalil 928a87a368 Bump tests 2024-03-08 14:42:38 +02:00
Ibrkhalil e4c2bd0683 Bump 2024-03-08 14:42:38 +02:00
Ibrkhalil 66f1de8d6b Bump tests 2024-03-08 14:42:38 +02:00
Ibrkhalil 3455f9f1ef clean 2024-03-08 14:42:38 +02:00
Ibrkhalil 26acf1dd38 clean 2024-03-08 14:42:37 +02:00
Ibrkhalil b1cb5221f1 Edit message 2024-03-08 14:42:37 +02:00
Ibrkhalil 00ea2f9f71 Improvements 2024-03-08 14:42:37 +02:00
Ibrkhalil 6be6c39bae clean 2024-03-08 14:42:37 +02:00
Ibrkhalil c3df5139df Add internal link preview 2024-03-08 14:42:36 +02: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
95 changed files with 1139 additions and 1319 deletions
+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' \
+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
}
-4
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]
@@ -443,9 +442,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
-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"}}})))
+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,39 @@
(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}
: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}
:outgoing false}}
(-> raw-notification
store/<-rpc
(select-keys [:last-message :message :reply-message])))))
+43 -3
View File
@@ -16,13 +16,51 @@
: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})
(update-in [:contact :icon] set/rename-keys {:dataUri :data-uri})
(update :contact
set/rename-keys
{:publicKey :public-key
:displayName :display-name})))
(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})
(update :contact
set/rename-keys
{:public-key :publicKey
:display-name :displayName})
(update-in [:contact :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 +91,10 @@
:new :new?
:albumImagesCount :album-images-count
:displayName :display-name
:linkPreviews :link-previews})
:linkPreviews :link-previews
:statusLinkPreviews :status-link-previews})
(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
@@ -37,7 +37,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 +73,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))))))
+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"])))))
-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))))
+1 -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]))
@@ -100,6 +99,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))]}]]))))
@@ -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])
@@ -24,10 +24,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]
@@ -227,18 +223,6 @@
;;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)}}
:insets {:top? true}}
@@ -247,10 +231,6 @@
:options {:topBar {:title {:text (i18n/label :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)}}
:insets {:top? true}}
@@ -20,8 +20,8 @@
[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)}
[{:keys [container-style actions]}]
[rn/view {:style (assoc container-style :flex-direction :row)}
(map-indexed
(fn [index action]
^{:key index}
-1
View File
@@ -142,7 +142,6 @@
[color]
{:padding 12
:height 102
:flex 1
:border-radius 16
:background-color (colors/custom-color color 50 10)
:justify-content :space-between})
@@ -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})
+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?
@@ -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,15 @@
(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]
[reagent.core :as reagent]
[taoensso.timbre :as log]))
(defn- button-disabled
[disabled-text on-enable]
@@ -53,12 +59,25 @@
(defn- logo-comp
[logo]
[rn/image
{:accessibility-label :logo
:source (if (string? logo)
{:uri logo}
logo)
:style style/logo}])
(let [image-data (reagent/atom nil)
is-svg? (reagent/atom nil)
on-success (fn [data-uri]
(reset! image-data data-uri))
_get-svg (-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?}))
(.fetch "GET" logo)
(.then (fn [imgObj]
(reset! 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)))]
(fn []
(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
[]
@@ -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))
@@ -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.
@@ -150,8 +150,7 @@
profile-picture emoji on-share-press address]
:as props}]
[:<>
[rn/view {:style style/gradient-bg}
[gradient-cover/view {:customization-color customization-color :height 463}]]
[gradient-cover/view {:customization-color customization-color :height 463}]
[rn/view {:style style/content-container}
[rn/view {:style style/share-qr-container}
[rn/view {:style style/share-qr-inner-container}
+9 -4
View File
@@ -25,10 +25,15 @@
(defn image
[{:keys [source] :as props}]
[image-native
(if (string? source)
(assoc props :source {:uri source})
props)])
(let [props (cond-> props
platform/ios?
(dissoc :resize-method)
(and (:style props) platform/ios?)
(update :style dissoc :resize-method))]
[image-native
(if (string? source)
(assoc props :source {:uri source})
props)]))
(defn image-get-size
[uri]
+3 -4
View File
@@ -132,10 +132,9 @@
:shell? shell?
:padding-bottom content-padding-bottom})}
(when (and gradient-cover? customization-color)
[rn/view {:style style/gradient-bg}
[quo/gradient-cover
{:customization-color customization-color
:opacity 0.4}]])
[quo/gradient-cover
{:customization-color customization-color
:opacity 0.4}])
(when-not hide-handle?
[quo/drawer-bar])
[content]]]]]))
+11 -2
View File
@@ -29,7 +29,7 @@
(defn validation-name
[s]
(cond
(or (= s nil) (= s "")) nil
(string/blank? s) nil
(string/ends-with? s "-eth") (i18n/label :t/ending-not-allowed {:ending "-eth"})
(string/ends-with? s "_eth") (i18n/label :t/ending-not-allowed {:ending "_eth"})
(string/ends-with? s ".eth") (i18n/label :t/ending-not-allowed {:ending ".eth"})
@@ -45,8 +45,17 @@
(defn validation-bio
[s]
(cond
(or (= s nil) (= s "")) nil
(string/blank? s) nil
(has-emojis? s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/emojis)})
(has-special-characters? s) (i18n/label :t/are-not-allowed
{:check (i18n/label :t/special-characters)})
(bio-too-long? s) (i18n/label :t/bio-is-too-long)))
(defn validation-nickname
[s]
(cond
(string/blank? s) nil
(has-emojis? s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/emojis)})
(has-special-characters? s) (i18n/label :t/are-not-allowed
{:check (i18n/label :t/special-characters)})
(name-too-long? s) (i18n/label :t/nickname-is-too-long)))
+5
View File
@@ -425,6 +425,9 @@
(def ^:const optimism-goerli-chain-id 420)
(def ^:const optimism-sepolia-chain-id 11155420)
(def ^:const mainnet-chain-ids
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id})
(def ^:const mainnet-short-name "eth")
(def ^:const optimism-short-name "opt")
(def ^:const arbitrum-short-name "arb1")
@@ -462,3 +465,5 @@
(def ^:const bridge-name-transfer "Transfer")
(def ^:const bridge-name-erc-721-transfer "ERC721Transfer")
(def ^:const status-hostname "status.app")
@@ -2,11 +2,9 @@
(:require
[quo.foundations.colors :as colors]))
(defn actions-view
[]
{:flex-direction :row
:justify-content :space-between
:margin-vertical 20
(def actions-view
{:margin-top 8
:margin-bottom 20
:padding-horizontal 20})
(defn action-container
@@ -12,53 +12,6 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn back-button
[]
[quo/button
{:type :grey
:size 32
:icon-only? true
:container-style {:margin-left 20}
:accessibility-label :back-button
:on-press #(rf/dispatch [:navigate-back])}
:i/arrow-left])
(defn options-button
[group]
[quo/button
{:type :grey
:size 32
:icon-only? true
:container-style {:margin-right 20}
:accessibility-label :options-button
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [actions/group-details-actions group])}])}
:i/options])
(defn count-container
[amount accessibility-label]
[rn/view
{:style (style/count-container)
:accessibility-label accessibility-label}
[quo/text
{:size :label
:weight :medium
:style {:text-align :center}}
amount]])
(defn contacts-section-header
[{:keys [title]}]
[rn/view
{:style {:padding-horizontal 20
:border-top-width 1
:border-top-color colors/neutral-20
:padding-vertical 8
:margin-top 8}}
[quo/text
{:size :paragraph-2
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}} title]])
(defn group-chat-member-toggle
[member? selected? public-key]
(if-not member?
@@ -143,79 +96,74 @@
:on-press show-profile-actions}})
item]))
(defn contacts-section-header
[{:keys [title]}]
[quo/divider-label {:tight? true} title])
(defn contacts-section-footer
[_]
[rn/view {:style {:height 8}}])
(defn group-details
[]
(let [chat-id (rf/sub [:get-screen-params :group-chat-profile])
{:keys [admins chat-id chat-name color public?
muted contacts]
{:keys [admins chat-id chat-name color muted contacts]
:as group} (rf/sub [:chats/chat-by-id chat-id])
members (rf/sub [:contacts/group-members-sections chat-id])
pinned-messages (rf/sub [:chats/pinned chat-id])
current-pk (rf/sub [:multiaccount/public-key])
admin? (get admins current-pk)]
[rn/view
{:style {:flex 1
:background-color (colors/theme-colors colors/white colors/neutral-95)}}
[quo/header
{:left-component [back-button]
:right-component [options-button group]
:background (colors/theme-colors colors/white colors/neutral-95)}]
[rn/view
{:style {:flex-direction :row
:margin-top 24
:padding-horizontal 20}}
[quo/group-avatar
{:customization-color color
:size :size-32}]
[quo/text
{:weight :semi-bold
:size :heading-1
:style {:margin-horizontal 8}} chat-name]
[rn/view {:style {:margin-top 8}}
[quo/icon (if public? :i/world :i/privacy)
{:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]]
[rn/view {:style (style/actions-view)}
[rn/touchable-opacity
{:style (style/action-container color)
:accessibility-label :pinned-messages
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id]))}
[rn/view
{:style {:flex-direction :row
:justify-content :space-between}}
[quo/icon :i/pin {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}]
[count-container (count pinned-messages) :pinned-count]]
[quo/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium}
(i18n/label :t/pinned-messages)]]
[rn/touchable-opacity
{:style (style/action-container color)
:accessibility-label :toggle-mute
:on-press #(rf/dispatch [:chat.ui/mute chat-id (not muted)
(when-not muted constants/mute-till-unmuted)])}
[quo/icon (if muted :i/muted :i/activity-center)
{:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}]
[quo/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium}
(i18n/label (if muted :unmute-group :mute-group))]]
[rn/touchable-opacity
{:style (style/action-container color)
:accessibility-label :manage-members
:on-press (fn []
(rf/dispatch [:group/clear-added-participants])
(rf/dispatch [:group/clear-removed-members])
(rf/dispatch [:open-modal :group-add-manage-members chat-id]))}
[rn/view
{:style {:flex-direction :row
:justify-content :space-between}}
[quo/icon :i/add-user {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}]
[count-container (count contacts) :members-count]]
[quo/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium}
(i18n/label (if admin? :t/manage-members :t/add-members))]]]
[:<>
[quo/gradient-cover
{:height 286
:customization-color color}]
[quo/page-nav
{:type :no-title
:background :photo
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [actions/group-details-actions
group])}])}]
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
[quo/page-top
{:title chat-name
:avatar {:customization-color color}}]
[quo/channel-actions
{:container-style style/actions-view
:actions [{:accessibility-label :pinned-messages
:label (i18n/label :t/pinned-messages)
:color color
:icon :i/pin
:counter-value (count pinned-messages)
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:accessibility-label :toggle-mute
:color color
:icon (if muted :i/muted :i/activity-center)
:label (i18n/label (if muted :unmute-group :mute-group))
:on-press #(rf/dispatch [:chat.ui/mute chat-id (not muted)
(when-not muted
constants/mute-till-unmuted)])}
{:accessibility-label :manage-members
:color color
:icon :i/add-user
:label (i18n/label (if admin? :t/manage-members :t/add-members))
:counter-value (count contacts)
:on-press (fn []
(rf/dispatch [:group/clear-added-participants])
(rf/dispatch [:group/clear-removed-members])
(rf/dispatch [:open-modal :group-add-manage-members
chat-id]))}]}]
[rn/section-list
{:key-fn :title
:sticky-section-headers-enabled false
:sections members
:render-section-header-fn contacts-section-header
:render-section-footer-fn contacts-section-footer
:render-data {:chat-id chat-id
:admin? admin?}
:render-fn contact-item-render}]]))
@@ -1,7 +1,7 @@
(ns status-im.contexts.chat.messenger.composer.events
(:require [clojure.string :as string]
[legacy.status-im.chat.models.mentions :as mentions]
[legacy.status-im.data-store.messages :as data-store-messages]
[legacy.status-im.data-store.messages :as data-store.messages]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.composer.link-preview.events :as link-preview]
[status-im.contexts.chat.messenger.messages.transport.events :as messages.transport]
@@ -132,6 +132,43 @@
:response-to message-id})
images)))
(defn- build-status-link-previews
[status-link-previews]
(map (fn [{{:keys [community-id color description display-name
members-count active-members-count icon banner]} :community
url :url
{contact-description :description
contact-icon :icon
contact-display-name :display-name
pk :public-key} :contact}]
{:url url
:community {:community-id community-id
:color color
:description description
:display-name display-name
:members-count members-count
:active-members-count active-members-count
:icon {:data-uri (:data-uri icon)
:width (:width icon)
:height (:height icon)}
:banner {:data-uri (:data-uri banner)
:width (:width banner)
:height (:height banner)}}
:contact {:public-key pk
:display-name contact-display-name
:description contact-description
:icon {:data-uri (:data-uri contact-icon)}}})
status-link-previews))
(defn- build-link-previews
[link-previews]
(->> link-previews
(map #(select-keys %
[:url :title :description :thumbnail
:status-link-preview? :favicon]))
(filter (fn [{:keys [status-link-preview?]}]
(not status-link-preview?)))))
(defn build-text-message
[{:keys [db]} input-text current-chat-id]
(when-not (string/blank? input-text)
@@ -140,15 +177,16 @@
preferred-name (get-in db [:profile/profile :preferred-name])
emoji? (emoji-only-content? {:text input-text
:response-to message-id})]
{:chat-id current-chat-id
:content-type (if emoji?
constants/content-type-emoji
constants/content-type-text)
:text input-text
:response-to message-id
:ens-name preferred-name
:link-previews (map #(select-keys % [:url :title :description :thumbnail])
(get-in db [:chat/link-previews :unfurled]))})))
{:chat-id current-chat-id
:content-type (if emoji?
constants/content-type-emoji
constants/content-type-text)
:text input-text
:response-to message-id
:ens-name preferred-name
:link-previews (build-link-previews (get-in db [:chat/link-previews :unfurled]))
:status-link-previews (build-status-link-previews
(get-in db [:chat/status-link-previews :unfurled]))})))
(rf/defn send-messages
[{:keys [db] :as cofx} input-text current-chat-id]
@@ -181,29 +219,41 @@
(when message-id
{:response-to message-id}))])))))
(defn- process-link-previews
[link-previews]
(->> link-previews
(map #(select-keys %
[:url :title :description :thumbnail
:status-link-preview? :favicon]))
(map data-store.messages/->link-preview-rpc)
(filter (fn [{:keys [status-link-preview?]}]
(not status-link-preview?)))))
(rf/defn send-edited-message
[{:keys [db]
:as cofx} text {:keys [message-id quoted-message chat-id]}]
(rf/merge
cofx
{:json-rpc/call [{:method "wakuext_editMessage"
:params [{:id message-id
:text text
:content-type (if (emoji-only-content?
{:text text
:response-to quoted-message})
constants/content-type-emoji
constants/content-type-text)
:linkPreviews (map #(-> %
(select-keys [:url :title :description
:thumbnail])
data-store-messages/->link-preview-rpc)
(get-in db [:chat/link-previews :unfurled]))}]
:js-response true
:on-error #(log/error "failed to edit message " %)
:on-success (fn [result]
(rf/dispatch [:sanitize-messages-and-process-response
result]))}]}
{:json-rpc/call
[{:method "wakuext_editMessage"
:params [{:id message-id
:text text
:content-type (if (emoji-only-content?
{:text text
:response-to quoted-message})
constants/content-type-emoji
constants/content-type-text)
:linkPreviews (process-link-previews (get-in db
[:chat/link-previews :unfurled]))
:statusLinkPreviews (map data-store.messages/->status-link-previews-rpc
(get-in db
[:chat/status-link-previews
:unfurled]))}]
:js-response true
:on-error #(log/error "failed to edit message " %)
:on-success (fn [result]
(rf/dispatch [:sanitize-messages-and-process-response
result]))}]}
(link-preview/reset-unfurled)
(cancel-message-edit)))
@@ -80,24 +80,53 @@
[]
curr-previews))
(defn- merge-preview-types
[new-previews new-status-link-previews]
(-> (map
(fn [{{:keys [display-name members-count banner icon
description]} :community
{contact-display-name :display-name
contact-icon :icon} :contact
url :url}]
;; Other types of previews need to be done here too
;; Like User link preview and Channel link preview
{:url url
:display-name (or contact-display-name display-name)
:members-count members-count
:banner banner
:icon (or (:data-uri contact-icon) icon)
:description description
;; Need to set status-link-preview?
;; to true to not send status-link-previews
;; with normal link-previews
:status-link-preview? true})
new-status-link-previews)
(concat new-previews)))
(rf/defn unfurl-parsed-urls-success
{:events [:link-preview/unfurl-parsed-urls-success]}
[{:keys [db]} request-id {new-previews :linkPreviews}]
[{:keys [db]} request-id {new-previews :linkPreviews status-link-previews :statusLinkPreviews}]
(when (= request-id (get-in db [:chat/link-previews :request-id]))
(let [new-previews (map data-store.messages/<-link-preview-rpc new-previews)
curr-previews (get-in db [:chat/link-previews :unfurled])
indexed-new-previews (utils.collection/index-by :url new-previews)]
(let [new-previews (map data-store.messages/<-link-preview-rpc new-previews)
new-status-link-previews (map data-store.messages/<-status-link-previews-rpc
status-link-previews)
merged-preview-types (merge-preview-types new-previews new-status-link-previews)
curr-previews (get-in db [:chat/link-previews :unfurled])
indexed-new-previews (utils.collection/index-by :url merged-preview-types)]
(log/debug "URLs unfurled"
:chat/link-previews
{:event :link-preview/unfurl-parsed-urls-success
:previews (map #(update % :thumbnail dissoc :data-uri) new-previews)
:previews (map #(update % :thumbnail dissoc :data-uri) merged-preview-types)
:request-id request-id})
{:db (-> db
(assoc-in [:chat/status-link-previews :unfurled] new-status-link-previews)
(update-in [:chat/link-previews :unfurled] reconcile-unfurled indexed-new-previews)
(update-in [:chat/link-previews :cache]
merge
indexed-new-previews
(utils.collection/index-by :url
(failed-previews curr-previews new-previews))))})))
(failed-previews curr-previews
merged-preview-types))))})))
(rf/defn unfurl-parsed-urls-error
{:events [:link-preview/unfurl-parsed-urls-error]}
@@ -6,6 +6,8 @@
(def url-github "https://github.com")
(def url-gitlab "https://gitlab.com")
(def url-community
"https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11")
(def preview-github {:url url-github :thumbnail nil})
(def preview-gitlab {:url url-gitlab :thumbnail nil})
(def request-id "abc123")
@@ -31,7 +33,15 @@
(is (match? {:json-rpc/call [{:method "wakuext_getTextURLs"
:params [url-github]}]}
(remove-rpc-callbacks
(events/unfurl-urls cofx url-github)))))))
(events/unfurl-urls cofx url-github))))))
(testing "fetches status community URLs"
(let [cofx {:db {:chat/link-previews {:unfurled {}
:cache {}
:request-id "123"}}}]
(is (match? {:json-rpc/call [{:method "wakuext_getTextURLs"
:params [url-community]}]}
(remove-rpc-callbacks
(events/unfurl-urls cofx url-community)))))))
(deftest unfurl-parsed-urls-test
(with-redefs [events/new-request-id (constantly request-id)]
@@ -1,8 +1,11 @@
(ns status-im.contexts.chat.messenger.composer.link-preview.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im.common.resources :as resources]
[status-im.constants]
[status-im.contexts.chat.messenger.composer.constants :as constants]
[status-im.contexts.chat.messenger.composer.link-preview.events]
[status-im.contexts.chat.messenger.composer.link-preview.style :as style]
@@ -33,13 +36,19 @@
:horizontal-spacing style/padding-horizontal
:loading-message (i18n/label :t/link-preview-loading-message)
:on-clear #(rf/dispatch [:link-preview/clear])
:data (map (fn [{:keys [title thumbnail hostname loading? url]}]
{:title title
:body hostname
:loading? loading?
:thumbnail (:data-uri thumbnail)
:url url})
previews)}]]))
:data (map
(fn [{:keys [title display-name thumbnail hostname loading? url favicon
icon]}]
{:title (or display-name title)
:body (or (when-not display-name hostname)
status-im.constants/status-hostname)
:logo (if (string/starts-with? url "https://status.app/c")
(resources/get-mock-image :status-logo)
(or icon favicon))
:loading? loading?
:thumbnail (:data-uri thumbnail)
:url url})
previews)}]]))
(defn view
[]
@@ -16,12 +16,13 @@
(let [previews (rf/sub [:chats/message-link-previews chat-id message-id])]
(when (seq previews)
[:<>
(for [{:keys [url title description thumbnail hostname]} previews]
(for [{:keys [url title description thumbnail hostname favicon]} previews]
^{:key url}
[quo/link-preview
{:title title
:description description
:link hostname
:logo (:url favicon)
:thumbnail (:url thumbnail)
:thumbnail-size (when (nearly-square? thumbnail) :large)
:container-style {:margin-top 8}}])])))
@@ -0,0 +1,28 @@
(ns status-im.contexts.chat.messenger.messages.content.status-link-preview.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[utils.re-frame :as rf]))
(defn view
[{:keys [chat-id message-id]}]
(let [status-link-previews (rf/sub [:chats/message-status-link-previews chat-id message-id])
link-previews? (rf/sub [:chats/message-link-previews? chat-id message-id])]
(when (seq status-link-previews)
[rn/view {:style {:margin-top (when link-previews? 8)}}
(for [{:keys [url community]} status-link-previews]
(when community
(let [{community-description :description
community-icon :icon
community-banner :banner
community-name :display-name
members-count :members-count} community]
^{:key url}
[quo/internal-link-card
{:type :community
:size :message
:description community-description
:members-count members-count
:title community-name
:banner (:url community-banner)
:icon (:url community-icon)
:on-press #(rf/dispatch [:universal-links/handle-url url])}])))])))
@@ -14,18 +14,18 @@
(defn mention-tag-wrapper
[first-child-mention]
{:flex-direction :row
:align-items :center
:height (if platform/ios? 22 21)
:background-color colors/primary-50-opa-10
:padding-horizontal 3
:border-radius 6
:transform [{:translateY (if platform/ios? (if first-child-mention 4.5 3) 4.5)}]})
{:flex-direction :row
:align-items :center
:height (if platform/ios? 22 21)
:border-radius 6
:transform [{:translateY (if platform/ios? (if first-child-mention 4.5 3) 4.5)}]})
(def mention-tag-text
{:color (colors/theme-colors colors/primary-50
colors/primary-60)
:selection-color :transparent
:background-color colors/primary-50-opa-10
:padding-horizontal 3
:suppress-highlighting true})
(defn code
@@ -5,6 +5,7 @@
[react-native.core :as rn]
[react-native.platform :as platform]
[status-im.contexts.chat.messenger.messages.content.link-preview.view :as link-preview]
[status-im.contexts.chat.messenger.messages.content.status-link-preview.view :as status-link-preview]
[status-im.contexts.chat.messenger.messages.content.text.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -56,14 +57,16 @@
:mention
(conj
units
[rn/pressable
{:on-press #(rf/dispatch [:chat.ui/show-profile literal])
:style (style/mention-tag-wrapper first-child-mention)}
[quo/text
{:weight :medium
:style style/mention-tag-text
:size :paragraph-1}
(rf/sub [:messages/resolve-mention literal])]])
(let [resolved-mention (rf/sub [:messages/resolve-mention literal])]
[rn/pressable
{:on-press #(rf/dispatch [:chat.ui/show-profile literal])
:key resolved-mention
:style (style/mention-tag-wrapper first-child-mention)}
[quo/text
{:weight :medium
:style style/mention-tag-text
:size :paragraph-1}
resolved-mention]]))
:edited
(conj units
@@ -163,4 +166,5 @@
[message-data]
[:<>
[render-parsed-text message-data]
[link-preview/view message-data]])
[link-preview/view message-data]
[status-link-preview/view message-data]])
@@ -81,7 +81,9 @@
(fn []
(when-not cached-preview-data
(let [community-id (community-id-from-link community-link)]
(rf/dispatch [:communities/fetch-community community-id]))))
(rf/dispatch [:communities/fetch-community
{:community-id community-id
:update-last-opened-at? false}]))))
:reagent-render
(fn []
(when cached-preview-data
@@ -143,28 +143,28 @@
mute-chat-label (if community-channel? :t/mute-channel :t/mute-chat)
unmute-chat-label (if community-channel? :t/unmute-channel :t/unmute-chat)]
[quo/channel-actions
{:style {:margin-top 16}
:actions [{:accessibility-label :action-button-pinned
:big? true
:label (or latest-pin-text (i18n/label :t/no-pinned-messages))
:color cover-bg-color
:icon :i/pin
:counter-value pins-count
:on-press (fn []
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:accessibility-label :action-button-mute
:label (i18n/label (if muted
unmute-chat-label
mute-chat-label))
:color cover-bg-color
:icon (if muted? :i/activity-center :i/muted)
:on-press (fn []
(if muted?
(home.actions/unmute-chat-action chat-id)
(home.actions/mute-chat-action chat-id
chat-type
muted?)))}]}]))
{:container-style {:margin-top 16}
:actions [{:accessibility-label :action-button-pinned
:big? true
:label (or latest-pin-text (i18n/label :t/no-pinned-messages))
:color cover-bg-color
:icon :i/pin
:counter-value pins-count
:on-press (fn []
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:accessibility-label :action-button-mute
:label (i18n/label (if muted
unmute-chat-label
mute-chat-label))
:color cover-bg-color
:icon (if muted? :i/activity-center :i/muted)
:on-press (fn []
(if muted?
(home.actions/unmute-chat-action chat-id)
(home.actions/mute-chat-action chat-id
chat-type
muted?)))}]}]))
(defn f-list-footer
[{:keys [chat distance-from-list-top theme customization-color]}]
@@ -8,6 +8,7 @@
[legacy.status-im.data-store.chats :as data-store.chats]
[legacy.status-im.data-store.communities :as data-store.communities]
[legacy.status-im.data-store.invitations :as data-store.invitations]
[legacy.status-im.data-store.messages :as data-store.messages]
[legacy.status-im.group-chats.core :as models.group]
[legacy.status-im.multiaccounts.update.core :as update.core]
[legacy.status-im.pairing.core :as models.pairing]
@@ -356,32 +357,35 @@
(conj set-hash-fxs
#(sanitize-messages-and-process-response % response-js false)))))
(defn- image->rpc [image] (set/rename-keys image {:data-uri :dataUri}))
(defn- link-preview->rpc
[preview]
(update preview
:thumbnail
(fn [thumbnail]
(set/rename-keys thumbnail {:data-uri :dataUri}))))
(-> preview
(update :thumbnail image->rpc)
(update :favicon image->rpc)))
(defn build-message
[msg]
(-> msg
(update :link-previews #(map link-preview->rpc %))
(update :status-link-previews #(set (map data-store.messages/->status-link-previews-rpc %)))
(set/rename-keys
{:album-id :albumId
:audio-duration-ms :audioDurationMs
:audio-path :audioPath
:chat-id :chatId
:community-id :communityId
:content-type :contentType
:ens-name :ensName
:image-height :imageHeight
:image-path :imagePath
:image-width :imageWidth
:link-previews :linkPreviews
:response-to :responseTo
:sticker :sticker
:text :text})))
{:album-id :albumId
:audio-duration-ms :audioDurationMs
:audio-path :audioPath
:chat-id :chatId
:community-id :communityId
:content-type :contentType
:ens-name :ensName
:image-height :imageHeight
:image-path :imagePath
:image-width :imageWidth
:link-previews :linkPreviews
:status-link-previews :statusLinkPreviews
:response-to :responseTo
:sticker :sticker
:text :text})))
(rf/defn send-chat-messages
[_ messages]
@@ -14,6 +14,6 @@
(defn bottom-actions
[]
{:padding-top 12
{:padding-vertical 12
:padding-horizontal screen-horizontal-padding
:background-color (colors/theme-colors colors/white colors/neutral-95)})
@@ -30,6 +30,4 @@
(defn gradient-cover-wrapper
[width]
{:width (gradient-cover-size width)
:position :absolute
:border-radius 12
:z-index -1})
:border-radius 12})
+24 -10
View File
@@ -22,15 +22,18 @@
[{:keys [db]} [community-js]]
(when community-js
(let [{:keys [token-permissions
token-permissions-check joined id]
token-permissions-check joined id last-opened-at]
:as community} (data-store.communities/<-rpc community-js)
has-channel-perm? (fn [id-perm-tuple]
(let [{:keys [type]} (second id-perm-tuple)]
(or (= type constants/community-token-permission-can-view-channel)
(=
type
constants/community-token-permission-can-view-and-post-channel))))]
{:db (assoc-in db [:communities id] community)
constants/community-token-permission-can-view-and-post-channel))))
previous-last-opened-at (get-in db [:communities id :last-opened-at])]
{:db (assoc-in db
[:communities id]
(assoc community :last-opened-at (max last-opened-at previous-last-opened-at)))
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
(when (not joined)
[:dispatch [:chat.ui/spectate-community id]])
@@ -299,6 +302,7 @@
(when community
{:db (update db :communities/fetching-community dissoc community-id)
:fx [[:dispatch [:communities/handle-community community]]
[:dispatch [:communities/update-last-opened-at community-id]]
[:dispatch
[:chat.ui/cache-link-preview-data (link-preview.events/community-link community-id)
community]]]}))
@@ -312,7 +316,7 @@
(rf/reg-event-fx :chat.ui/community-failed-to-fetch community-failed-to-fetch)
(defn fetch-community
[{:keys [db]} [community-id]]
[{:keys [db]} [{:keys [community-id update-last-opened-at?]}]]
(when (and community-id (not (get-in db [:communities/fetching-community community-id])))
{:db (assoc-in db [:communities/fetching-community community-id] true)
:json-rpc/call [{:method "wakuext_fetchCommunity"
@@ -320,6 +324,8 @@
:TryDatabase true
:WaitForResponse true}]
:on-success (fn [community]
(when update-last-opened-at?
(rf/dispatch [:communities/update-last-opened-at community-id]))
(rf/dispatch [:chat.ui/community-fetched community-id community]))
:on-error (fn [err]
(rf/dispatch [:chat.ui/community-failed-to-fetch community-id])
@@ -332,7 +338,11 @@
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema [:catn [:community-id [:? :string]]]]]]
[:schema
[:catn
[:map
[:community-id [:? :string]]
[:update-last-opened-at? [:? :boolean]]]]]]]
[:maybe
[:map
[:db map?]
@@ -400,17 +410,21 @@
(navigate-to-serialized-community cofx deserialized-key)
(rf/merge
cofx
{:fx [[:dispatch [:communities/fetch-community deserialized-key]]
[:dispatch [:navigate-to :community-overview deserialized-key]]
[:dispatch [:communities/update-last-opened-at deserialized-key]]]}
{:fx [[:dispatch
[:communities/fetch-community
{:community-id deserialized-key
:update-last-opened-at? true}]]
[:dispatch [:navigate-to :community-overview deserialized-key]]]}
(navigation/pop-to-root :shell-stack)))))
(rf/reg-event-fx :communities/navigate-to-community-chat
(fn [{:keys [db]} [chat-id pop-to-root?]]
(let [{:keys [community-id]} (get-in db [:chats chat-id])]
{:fx [(when community-id
[:dispatch [:communities/fetch-community community-id]]
[:dispatch [:communities/update-last-opened-at community-id]])
[:dispatch
[:communities/fetch-community
{:community-id community-id
:update-last-opened-at? true}]])
(if pop-to-root?
[:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]]
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
@@ -106,14 +106,14 @@
(testing "update fetching indicator in db"
(is (match?
{:db {:communities/fetching-community {community-id true}}}
(events/fetch-community {} [community-id]))))
(events/fetch-community {} [{:community-id community-id}]))))
(testing "call the fetch community rpc method with correct community id"
(is (match?
{:json-rpc/call [{:method "wakuext_fetchCommunity"
:params [{:CommunityKey community-id
:TryDatabase true
:WaitForResponse true}]}]}
(events/fetch-community {} [community-id])))))
(events/fetch-community {} [{:community-id community-id}])))))
(testing "with no community id"
(testing "do nothing"
(is (match?
@@ -143,6 +143,7 @@
(testing "dispatch fxs"
(is (match?
{:fx [[:dispatch [:communities/handle-community {:id community-id}]]
[:dispatch [:communities/update-last-opened-at community-id]]
[:dispatch
[:chat.ui/cache-link-preview-data "community-link+community-id"
{:id community-id}]]]}
@@ -153,6 +154,7 @@
(testing "dispatch fxs, do not spectate community"
(is (match?
{:fx [[:dispatch [:communities/handle-community {:id community-id}]]
[:dispatch [:communities/update-last-opened-at community-id]]
[:dispatch
[:chat.ui/cache-link-preview-data "community-link+community-id"
{:id community-id}]]]}
@@ -163,6 +165,7 @@
(testing "dispatch fxs, do not spectate community"
(is (match?
{:fx [[:dispatch [:communities/handle-community {:id community-id}]]
[:dispatch [:communities/update-last-opened-at community-id]]
[:dispatch
[:chat.ui/cache-link-preview-data "community-link+community-id"
{:id community-id}]]]}
@@ -66,11 +66,6 @@
:source (resources/get-mock-image :dark-blur-bg)}])
[(if @blur? blur/view rn/view)
{:style {:height 332
:position :absolute
:top 0
:left 0
:right 0
:bottom 0
:padding-vertical 40}
:blur-type :dark}
[quo/gradient-cover @state]]]
@@ -1,6 +1,7 @@
(ns status-im.contexts.preview.quo.preview
(:require
[camel-snake-kebab.core :as camel-snake-kebab]
cljs.pprint
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.colors :as colors]
@@ -1,31 +1,58 @@
(ns status-im.contexts.profile.contact.actions.view
(:require [quo.core :as quo]
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[status-im.common.not-implemented :as not-implemented]
[utils.i18n :as i18n]))
[status-im.contexts.profile.contact.add-nickname.view :as add-nickname]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
[quo/action-drawer
[[{:icon :i/edit
:label (i18n/label :t/add-nickname-title)
:on-press not-implemented/alert
:accessibility-label :add-nickname}
{:icon :i/qr-code
:label (i18n/label :t/show-qr)
:on-press not-implemented/alert
:accessibility-label :show-qr-code}
{:icon :i/share
:label (i18n/label :t/share-profile)
:on-press not-implemented/alert
:accessibility-label :share-profile}
{:icon :i/untrustworthy
:label (i18n/label :t/mark-untrustworthy)
:on-press not-implemented/alert
:accessibility-label :mark-untrustworthy
:add-divider? true
:danger? true}
{:icon :i/block
:label (i18n/label :t/block-user)
:on-press not-implemented/alert
:accessibility-label :block-user
:danger? true}]]])
(let [{:keys [nickname public-key]} (rf/sub [:contacts/current-contact])
on-add-nickname (rn/use-callback #(rf/dispatch [:show-bottom-sheet
{:content
(fn [] [add-nickname/view])}]))
on-remove-nickname (rn/use-callback
(fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:toasts/upsert
{:id :remove-nickname
:type :positive
:text (i18n/label :t/nickname-removed)}])
(rf/dispatch [:contacts/update-nickname public-key ""]))
[public-key])
has-nickname? (rn/use-memo (fn [] (not (string/blank? nickname))) [nickname])]
[quo/action-drawer
[[{:icon :i/edit
:label (if has-nickname?
(i18n/label :t/edit-nickname)
(i18n/label :t/add-nickname-title))
:on-press on-add-nickname
:accessibility-label (if nickname :edit-nickname :add-nickname)}
{:icon :i/qr-code
:label (i18n/label :t/show-qr)
:on-press not-implemented/alert
:accessibility-label :show-qr-code}
{:icon :i/share
:label (i18n/label :t/share-profile)
:on-press not-implemented/alert
:accessibility-label :share-profile}
(when has-nickname?
{:icon :i/delete
:label (i18n/label :t/remove-nickname)
:on-press on-remove-nickname
:add-divider? true
:accessibility-label :remove-nickname
:danger? true})
{:icon :i/untrustworthy
:label (i18n/label :t/mark-untrustworthy)
:on-press not-implemented/alert
:accessibility-label :mark-untrustworthy
:add-divider? (when-not has-nickname? true)
:danger? true}
{:icon :i/block
:label (i18n/label :t/block-user)
:on-press not-implemented/alert
:accessibility-label :block-user
:danger? true}]]]))
@@ -0,0 +1,6 @@
(ns status-im.contexts.profile.contact.add-nickname.style)
(def input-wrapper
{:padding-vertical 8
:padding-horizontal 20
:gap 8})
@@ -0,0 +1,81 @@
(ns status-im.contexts.profile.contact.add-nickname.view
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[status-im.common.validation.profile :as profile-validator]
[status-im.constants :as constants]
[status-im.contexts.profile.contact.add-nickname.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [{:keys [public-key primary-name nickname customization-color]
:as profile} (rf/sub [:contacts/current-contact])
;; TODO(@mohsen): remove :blue, https://github.com/status-im/status-mobile/issues/18733
customization-color (or customization-color :blue)
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
[unsaved-nickname set-unsaved-nickname] (rn/use-state nickname)
[error-msg set-error-msg] (rn/use-state nil)
validate-nickname (rn/use-callback
(debounce/debounce
(fn [name]
(set-error-msg
(profile-validator/validation-nickname name)))
300))
on-cancel (rn/use-callback #(rf/dispatch [:hide-bottom-sheet]))
on-nickname-change (rn/use-callback (fn [text]
(set-unsaved-nickname text)
(validate-nickname text)))
on-nickname-submit (rn/use-callback
(fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:toasts/upsert
{:id :add-nickname
:type :positive
:text (i18n/label
(if (string/blank? nickname)
:t/nickname-added
:t/nickname-updated)
{:primary-name primary-name})}])
(rf/dispatch [:contacts/update-nickname public-key
(string/trim unsaved-nickname)]))
[public-key unsaved-nickname])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :default
:title (i18n/label :t/add-nickname-title)
:full-name full-name
:profile-picture profile-picture
:customization-color customization-color}]
[rn/view {:style style/input-wrapper}
[quo/input
{:type :text
:char-limit constants/profile-name-max-length
:max-length constants/profile-name-max-length
:auto-focus true
:default-value unsaved-nickname
:error? (not (string/blank? error-msg))
:label (i18n/label :t/nickname)
:on-change-text on-nickname-change}
:on-submit-editing on-nickname-submit]
[quo/info-message
{:icon :i/info
:size :default
:type (if-not (string/blank? error-msg) :error :default)}
(if-not (string/blank? error-msg)
error-msg
(i18n/label :t/nickname-visible-to-you))]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/add-nickname-title)
:button-one-props {:disabled? (or (string/blank? unsaved-nickname)
(not (string/blank? error-msg)))
:on-press on-nickname-submit}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press on-cancel}}]]))
@@ -0,0 +1,10 @@
(ns status-im.contexts.profile.contact.contact-request.style)
(def message-prompt-wrapper
{:padding-top 4
:padding-bottom 8
:padding-horizontal 20})
(def message-input-wrapper
{:padding-vertical 8
:padding-horizontal 20})
@@ -0,0 +1,46 @@
(ns status-im.contexts.profile.contact.contact-request.view
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.profile.contact.contact-request.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [{:keys [public-key customization-color]
:as profile} (rf/sub [:contacts/current-contact])
;; TODO: remove :blue when #18733 merged.
customization-color (or customization-color :blue)
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
[message set-message] (rn/use-state "")
on-message-change (rn/use-callback #(set-message %))
on-message-submit (rn/use-callback (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:contact.ui/send-contact-request
public-key message]))
[public-key message])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :default
:title (i18n/label :t/send-contact-request)
:full-name full-name
:profile-picture profile-picture
:customization-color customization-color}]
[rn/text {:style style/message-prompt-wrapper}
(i18n/label :t/contact-request-message-prompt)]
[rn/view {:style style/message-input-wrapper}
[quo/input
{:type :text
:multiline? true
:char-limit 280
:label (i18n/label :t/message)
:on-change-text on-message-change}]]
[quo/bottom-actions
{:actions :one-action
:button-one-props {:disabled? (string/blank? message)
:on-press on-message-submit}
:button-one-label (i18n/label :t/send-contact-request)}]]))
@@ -7,6 +7,11 @@
:padding-left 20
:align-items :flex-start})
(def button-wrapper
{:padding-top 8
:padding-bottom 16
:padding-horizontal 20})
(defn header-container
[border-radius theme margin-top]
(reanimated/apply-animations-to-style
@@ -3,8 +3,10 @@
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[status-im.common.not-implemented]
[status-im.common.scalable-avatar.view :as avatar]
[status-im.constants :as constants]
[status-im.contexts.profile.contact.contact-request.view :as contact-request]
[status-im.contexts.profile.contact.header.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
[utils.i18n :as i18n]
@@ -19,7 +21,9 @@
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
online? (rf/sub [:visibility-status-updates/online? public-key])
theme (quo.theme/use-theme-value)]
theme (quo.theme/use-theme-value)
on-contact-request (rn/use-callback #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [contact-request/view])}]))]
[rn/view {:style style/header-container}
[rn/view {:style style/header-top-wrapper}
[rn/view {:style style/avatar-wrapper}
@@ -40,4 +44,15 @@
{:title full-name
:description :text
:description-text bio
:emoji-dash emoji-hash}]]))
:emoji-dash emoji-hash}]
(cond
(or (not contact-request-state)
(= contact-request-state constants/contact-request-state-none))
[rn/view {:style style/button-wrapper}
[quo/button
{:on-press on-contact-request
:icon-left :i/add-user}
(i18n/label :t/send-contact-request)]]
:else nil)]))
@@ -21,7 +21,7 @@
{:navigate-back? true
:height 148
:on-scroll #(reanimated/set-shared-value scroll-y %)
;TODO remove colors/primary-50 when #18733 merged.
;; TODO(@mohsen): remove colors/primary-50, https://github.com/status-im/status-mobile/issues/18733
:cover-color (or customization-color colors/primary-50)
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:page-nav-props {:right-side [{:icon-name :i/options
@@ -44,8 +44,7 @@
[rn/view {:style {:gap 22}}
[quo/text-combinations {:title (i18n/label :t/bio)}]
[quo/input
{:theme :dark
:blur? true
{:blur? true
:multiline? true
:error? (not (string/blank? @error-msg))
:container-style {:margin-bottom -11}
@@ -45,8 +45,7 @@
[rn/view {:style {:gap 22}}
[quo/text-combinations {:title (i18n/label :t/name)}]
[quo/input
{:theme :dark
:blur? true
{:blur? true
:error? (not (string/blank? @error-msg))
:container-style {:margin-bottom -11}
:default-value @full-name
@@ -39,7 +39,7 @@
(fn []
[network-preferences/view
{:blur? true
:selected-networks (set selected-networks)
:selected-networks (set @selected-networks)
:on-save (fn [chain-ids]
(rf/dispatch [:hide-bottom-sheet])
(reset! selected-networks (map #(get utils/id->network %)
@@ -48,7 +48,10 @@
[props]
(let [{:keys [account width index]} props
selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
wallet-type (reagent/atom :legacy)]
wallet-type (reagent/atom :legacy)
on-settings-press #(open-preferences selected-networks)
on-legacy-press #(reset! wallet-type :legacy)
on-multichain-press #(reset! wallet-type :multichain)]
(fn []
(let [share-title (str (:name account) " " (i18n/label :t/address))
qr-url (utils/get-wallet-qr {:wallet-type @wallet-type
@@ -72,9 +75,9 @@
:full-name (:name account)
:customization-color (:color account)
:emoji (:emoji account)
:on-multichain-press #(reset! wallet-type :multichain)
:on-legacy-press #(reset! wallet-type :legacy)
:on-settings-press #(open-preferences @selected-networks)}]]]))))
:on-multichain-press on-multichain-press
:on-legacy-press on-legacy-press
:on-settings-press on-settings-press}]]]))))
(def wallet-qr-code-item (memoize wallet-qr-code-item-internal))
@@ -130,5 +130,5 @@
[quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)]
[quo/action-drawer
[[{:icon :i/scan
:on-press #(rf/dispatch [:navigate-to :scan-sync-code-page])
:on-press #(rf/dispatch [:open-modal :scan-sync-code-page])
:label (i18n/label :t/scan-or-enter-sync-code)}]]]]]])))
@@ -17,7 +17,9 @@
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view
{:collectibles collectible-list
{:collectibles collectible-list
:on-end-reached #(rf/dispatch
[:wallet/request-collectibles-for-current-viewing-account])
:on-collectible-press (fn [{:keys [id]}]
(rf/dispatch [:wallet/get-collectible-details id]))}]
:activity [activity/view]
@@ -8,7 +8,7 @@
[utils.i18n :as i18n]))
(defn- view-internal
[{:keys [theme collectibles filtered? on-collectible-press]}]
[{:keys [theme collectibles filtered? on-collectible-press on-end-reached]}]
(let [no-results-match-query? (and filtered? (empty? collectibles))]
(cond
no-results-match-query?
@@ -26,14 +26,17 @@
:else
[rn/flat-list
{:data collectibles
:style {:flex 1}
:content-container-style {:align-items :center}
:num-columns 2
:render-fn (fn [{:keys [preview-url] :as collectible}]
[quo/collectible
{:images [preview-url]
:on-press #(when on-collectible-press
(on-collectible-press collectible))}])}])))
{:data collectibles
:style {:flex 1}
:content-container-style {:align-items :center}
:window-size 11
:num-columns 2
:render-fn (fn [{:keys [preview-url] :as collectible}]
[quo/collectible
{:images [preview-url]
:on-press #(when on-collectible-press
(on-collectible-press collectible))}])
:on-end-reached on-end-reached
:on-end-reached-threshold 4}])))
(def view (quo.theme/with-theme view-internal))
@@ -6,14 +6,6 @@
{:flex 1
:margin-top top})
(defn gradient-cover-container
[top]
{:position :absolute
:top (- top)
:left 0
:right 0
:z-index -1})
(def account-avatar-container
{:padding-horizontal 20
:padding-top 12})
@@ -2,14 +2,6 @@
(:require
[quo.foundations.colors :as colors]))
(defn gradient-cover-container
[top]
{:position :absolute
:top (- top)
:left 0
:right 0
:z-index -1})
(def account-avatar-container
{:padding-horizontal 20
:padding-top 12})
@@ -78,7 +78,7 @@
:on-press #(rf/dispatch [:navigate-back])}]
[quo/gradient-cover
{:customization-color @account-color
:container-style (style/gradient-cover-container top)}]
:container-style {:top (- top)}}]
[rn/view
{:style style/account-avatar-container}
[quo/account-avatar
@@ -1,12 +1,12 @@
(ns status-im.contexts.wallet.data-store
(:require
[camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]
[clojure.set :as set]
[clojure.string :as string]
[status-im.constants :as constants]
[utils.money :as money]
[utils.number :as utils.number]))
[utils.number :as utils.number]
[utils.transforms :as transforms]))
(defn chain-ids-string->set
[ids-string]
@@ -60,8 +60,7 @@
:color :colorId})
(update :prodPreferredChainIds chain-ids-set->string)
(update :testPreferredChainIds chain-ids-set->string)
(dissoc :watch-only?)
(dissoc :default-account?)))
(dissoc :watch-only? :default-account? :tokens :collectibles)))
(defn- rpc->balances-per-chain
[token]
@@ -79,7 +78,7 @@
[tokens]
(-> tokens
(update-keys name)
(update-vals #(cske/transform-keys csk/->kebab-case %))
(update-vals #(cske/transform-keys transforms/->kebab-case-keyword %))
(update-vals remove-tokens-with-empty-values)
(update-vals #(mapv rpc->balances-per-chain %))))
@@ -123,4 +122,4 @@
(defn parse-keypairs
[keypairs]
(let [renamed-data (rename-color-id-in-data keypairs)]
(cske/transform-keys csk/->kebab-case-keyword renamed-data)))
(cske/transform-keys transforms/->kebab-case-keyword renamed-data)))
+40 -3
View File
@@ -3,6 +3,8 @@
[clojure.string :as string]
[react-native.background-timer :as background-timer]
[react-native.platform :as platform]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.data-store :as data-store]
[status-im.contexts.wallet.events.collectibles]
[status-im.contexts.wallet.item-types :as item-types]
@@ -12,7 +14,8 @@
[utils.ethereum.eip.eip55 :as eip55]
[utils.i18n :as i18n]
[utils.number]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(rf/reg-event-fx :wallet/show-account-created-toast
(fn [{:keys [db]} [address]]
@@ -56,7 +59,7 @@
[:wallet :accounts]
(utils.collection/index-by :address (data-store/rpc->accounts wallet-accounts)))
:fx [[:dispatch [:wallet/get-wallet-token]]
[:dispatch [:wallet/request-collectibles {:start-at-index 0 :new-request? true}]]
[:dispatch [:wallet/request-collectibles-for-all-accounts {:new-request? true}]]
(when new-account?
[:dispatch [:wallet/navigate-to-new-account navigate-to-account]])]})))
@@ -426,7 +429,6 @@
(rf/reg-event-fx :wallet/store-secret-phrase store-secret-phrase)
(defn new-keypair-created
[{:keys [db]} [{:keys [new-keypair]}]]
{:db (assoc-in db [:wallet :ui :create-account :new-keypair] new-keypair)
@@ -448,3 +450,38 @@
{:db (update-in db [:wallet :ui :create-account] dissoc :new-keypair)})
(rf/reg-event-fx :wallet/clear-new-keypair clear-new-keypair)
(rf/reg-event-fx
:wallet/blockchain-status-changed
(fn [{:keys [db]} [{:keys [message]}]]
(let [chains (-> (transforms/json->clj message)
(update-keys (comp utils.number/parse-int name)))
down-chains (-> (select-keys chains
(for [[k v] chains :when (= v "down")] k))
keys)
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
disabled-chain-id? (fn [chain-id]
(let [mainnet-chain? (contains? constants/mainnet-chain-ids chain-id)]
(if test-networks-enabled?
mainnet-chain?
(not mainnet-chain?))))
chains-filtered-by-mode (remove disabled-chain-id? down-chains)
chains-down? (seq chains-filtered-by-mode)
chain-names (when chains-down?
(->> (map #(-> (utils/id->network %)
name
string/capitalize)
chains-filtered-by-mode)
distinct
(string/join ", ")))]
(when (seq down-chains)
(log/info "[wallet] Chain(s) down: " down-chains)
(log/info "[wallet] Test network enabled: " (boolean test-networks-enabled?)))
{:db (assoc-in db [:wallet :statuses :blockchains] chains)
:fx (when chains-down?
[[:dispatch
[:toasts/upsert
{:id :chains-down
:type :negative
:text (i18n/label :t/provider-is-down {:chains chain-names})
:duration 10000}]]])})))
@@ -1,11 +1,9 @@
(ns status-im.contexts.wallet.events.collectibles
(:require [camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]
[clojure.string :as string]
(:require [camel-snake-kebab.extras :as cske]
[taoensso.timbre :as log]
[utils.ethereum.chain :as chain]
[utils.re-frame :as rf]
[utils.transforms :as types]))
[utils.transforms :as transforms]))
(def collectible-data-types
{:unique-id 0
@@ -20,33 +18,23 @@
:fetch-if-cache-old 3})
(def max-cache-age-seconds 3600)
(def collectibles-request-batch-size 1000)
(def collectibles-request-batch-size 25)
(defn displayable-collectible?
[collectible]
(let [{{:keys [image-url animation-url]} :collectible-data
{collection-image-url :image-url} :collection-data} collectible]
(or (not (string/blank? animation-url))
(not (string/blank? image-url))
(not (string/blank? collection-image-url)))))
(defn- move-collectibles-to-accounts
[accounts new-collectibles-per-account]
(reduce-kv (fn [acc account new-collectibles]
(update-in acc [account :collectibles] #(reduce conj (or % []) new-collectibles)))
accounts
new-collectibles-per-account))
(defn- add-collectibles-to-accounts
[accounts collectibles]
(reduce (fn [acc {:keys [ownership] :as collectible}]
(->> ownership
(map :address) ; In ERC1155 tokens a collectible can be owned by multiple addresses.
(reduce (fn add-collectible-to-address [acc address]
(update-in acc [address :collectibles] conj collectible))
acc)))
accounts
collectibles))
(defn flush-collectibles
[{:keys [db]}]
(let [collectibles-per-account (get-in db [:wallet :ui :collectibles :fetched])]
{:db (-> db
(update-in [:wallet :ui :collectibles] dissoc :pending-requests :fetched)
(update-in [:wallet :accounts] move-collectibles-to-accounts collectibles-per-account))}))
(defn store-collectibles
[{:keys [db]} [collectibles]]
(let [displayable-collectibles (filter displayable-collectible? collectibles)]
{:db (update-in db [:wallet :accounts] add-collectibles-to-accounts displayable-collectibles)}))
(rf/reg-event-fx :wallet/store-collectibles store-collectibles)
(rf/reg-event-fx :wallet/flush-collectibles-fetched flush-collectibles)
(defn clear-stored-collectibles
[{:keys [db]}]
@@ -62,48 +50,110 @@
(rf/reg-event-fx :wallet/store-last-collectible-details store-last-collectible-details)
(rf/reg-event-fx
:wallet/request-collectibles
(fn [{:keys [db]} [{:keys [start-at-index new-request?]}]]
(let [request-id 0
collectibles-filter nil
data-type (collectible-data-types :header)
fetch-criteria {:fetch-type (fetch-type :fetch-if-not-cached)
:max-cache-age-seconds max-cache-age-seconds}
chain-ids (chain/chain-ids db)
request-params [request-id
chain-ids
(keys (get-in db [:wallet :accounts]))
collectibles-filter
start-at-index
collectibles-request-batch-size
data-type
fetch-criteria]]
:wallet/request-new-collectibles-for-account
(fn [{:keys [db]} [{:keys [request-id account amount]}]]
(let [current-collectible-idx (get-in db [:wallet :accounts account :current-collectible-idx] 0)
collectibles-filter nil
data-type (collectible-data-types :header)
fetch-criteria {:fetch-type (fetch-type :fetch-if-not-cached)
:max-cache-age-seconds max-cache-age-seconds}
chain-ids (chain/chain-ids db)
request-params [request-id
chain-ids
[account]
collectibles-filter
current-collectible-idx
amount
data-type
fetch-criteria]]
{:fx [[:json-rpc/call
[{:method "wallet_getOwnedCollectiblesAsync"
:params request-params
:on-error (fn [error]
(log/error "failed to request collectibles"
{:event :wallet/request-collectibles
(log/error "failed to request collectibles for account"
{:event :wallet/request-new-collectibles-for-account
:error error
:params request-params}))}]]
(when new-request?
[:dispatch [:wallet/clear-stored-collectibles]])]})))
:params request-params}))}]]]})))
(defonce collectibles-request-ids (atom 0))
(defn- get-unique-collectible-request-id
[amount]
(let [initial-id (deref collectibles-request-ids)
last-id (+ initial-id amount)]
(reset! collectibles-request-ids last-id)
(range initial-id last-id)))
(rf/reg-event-fx
:wallet/request-collectibles-for-all-accounts
(fn [{:keys [db]} [{:keys [new-request?]}]]
(let [accounts (->> (get-in db [:wallet :accounts])
(filter (fn [[_ {:keys [has-more-collectibles?]}]]
(or (nil? has-more-collectibles?)
(true? has-more-collectibles?))))
(keys))
num-accounts (count accounts)
collectibles-per-account (quot collectibles-request-batch-size num-accounts)
;; We need to pass unique IDs for simultaneous requests, otherwise they'll fail
request-ids (get-unique-collectible-request-id num-accounts)
collectible-requests (map (fn [id account]
[:dispatch
[:wallet/request-new-collectibles-for-account
{:request-id id
:account account
:amount collectibles-per-account}]])
request-ids
accounts)]
{:db (cond-> db
:always (assoc-in [:wallet :ui :collectibles :pending-requests] num-accounts)
new-request? (update-in [:wallet :accounts] update-vals #(dissoc % :collectibles)))
:fx collectible-requests})))
(rf/reg-event-fx
:wallet/request-collectibles-for-current-viewing-account
(fn [{:keys [db]} _]
(let [current-viewing-account (-> db :wallet :current-viewing-account-address)
[request-id] (get-unique-collectible-request-id 1)]
{:db (assoc-in db [:wallet :ui :collectibles :pending-requests] 1)
:fx [[:dispatch
[:wallet/request-new-collectibles-for-account
{:request-id request-id
:account current-viewing-account
:amount collectibles-request-batch-size}]]]})))
(defn- update-fetched-collectibles-progress
[db owner-address collectibles offset has-more?]
(-> db
(assoc-in [:wallet :ui :collectibles :fetched owner-address] collectibles)
(assoc-in [:wallet :accounts owner-address :current-collectible-idx]
(+ offset (count collectibles)))
(assoc-in [:wallet :accounts owner-address :has-more-collectibles?] has-more?)))
(rf/reg-event-fx
:wallet/owned-collectibles-filtering-done
(fn [_ [{:keys [message]}]]
(let [{:keys [has-more offset
collectibles]} (cske/transform-keys csk/->kebab-case-keyword (types/json->clj message))
start-at-index (+ offset (count collectibles))]
{:fx [[:dispatch [:wallet/store-collectibles collectibles]]
(when has-more
[:dispatch [:wallet/request-collectibles {:start-at-index start-at-index}]])]})))
(fn [{:keys [db]} [{:keys [message]}]]
(let [{:keys [offset ownershipStatus collectibles
hasMore]} (transforms/json->clj message)
collectibles (cske/transform-keys transforms/->kebab-case-keyword collectibles)
pending-requests (dec (get-in db [:wallet :ui :collectibles :pending-requests]))
owner-address (some->> ownershipStatus
first
key
name)]
{:db (cond-> db
:always (assoc-in [:wallet :ui :collectibles :pending-requests] pending-requests)
owner-address (update-fetched-collectibles-progress owner-address
collectibles
offset
hasMore))
:fx [(when (zero? pending-requests)
[:dispatch [:wallet/flush-collectibles-fetched]])]})))
(rf/reg-event-fx
:wallet/get-collectible-details
(fn [_ [collectible-id]]
(let [request-id 0
collectible-id-converted (cske/transform-keys csk/->PascalCaseKeyword collectible-id)
collectible-id-converted (cske/transform-keys transforms/->PascalCaseKeyword collectible-id)
data-type (collectible-data-types :details)
request-params [request-id [collectible-id-converted] data-type]]
{:fx [[:json-rpc/call
@@ -118,8 +168,8 @@
(rf/reg-event-fx
:wallet/get-collectible-details-done
(fn [_ [{:keys [message]}]]
(let [response (cske/transform-keys csk/->kebab-case-keyword
(types/json->clj message))
(let [response (cske/transform-keys transforms/->kebab-case-keyword
(transforms/json->clj message))
{:keys [collectibles]} response
collectible (first collectibles)]
(if collectible
+12 -22
View File
@@ -56,24 +56,8 @@
(is (match? (:db effects) expected-db))))
(deftest store-collectibles
(testing "(displayable-collectible?) helper function"
(let [expected-results [[true
{:collectible-data {:image-url "https://..." :animation-url "https://..."}}]
[true {:collectible-data {:image-url "" :animation-url "https://..."}}]
[true {:collectible-data {:image-url nil :animation-url "https://..."}}]
[true {:collectible-data {:image-url "https://..." :animation-url ""}}]
[true {:collectible-data {:image-url "https://..." :animation-url nil}}]
[false {:collectible-data {:image-url "" :animation-url nil}}]
[false {:collectible-data {:image-url nil :animation-url nil}}]
[false {:collectible-data {:image-url nil :animation-url ""}}]
[false {:collectible-data {:image-url "" :animation-url ""}}]]]
(doseq [[result collection] expected-results]
(is (match? result (collectibles/displayable-collectible? collection))))))
(testing "save-collectibles-request-details"
(let [db {:wallet {:accounts {"0x1" {}
"0x3" {}}}}
collectible-1 {:collectible-data {:image-url "https://..." :animation-url "https://..."}
(testing "flush-collectibles"
(let [collectible-1 {:collectible-data {:image-url "https://..." :animation-url "https://..."}
:ownership [{:address "0x1"
:balance "1"}]}
collectible-2 {:collectible-data {:image-url "" :animation-url "https://..."}
@@ -82,12 +66,18 @@
collectible-3 {:collectible-data {:image-url "" :animation-url nil}
:ownership [{:address "0x2"
:balance "1"}]}
collectibles [collectible-1 collectible-2 collectible-3]
expected-db {:wallet {:accounts {"0x1" {:collectibles (list collectible-2 collectible-1)}
db {:wallet {:ui {:collectibles {:pending-requests 0
:fetched {"0x1" [collectible-1
collectible-2]
"0x2" [collectible-3]}}}
:accounts {"0x1" {}
"0x3" {}}}}
expected-db {:wallet {:ui {:collectibles {}}
:accounts {"0x1" {:collectibles (list collectible-1 collectible-2)}
"0x2" {:collectibles (list collectible-3)}
"0x3" {}}}}
effects (collectibles/store-collectibles {:db db} [collectibles])
result-db (:db effects)]
result-db (:db (collectibles/flush-collectibles {:db db}))]
(is (match? result-db expected-db)))))
(deftest clear-stored-collectibles
@@ -9,12 +9,15 @@
(defn view
[{:keys [selected-tab]}]
(let [collectible-list (rf/sub [:wallet/all-collectibles])]
(let [collectible-list (rf/sub [:wallet/all-collectibles-list])
request-collectibles #(rf/dispatch
[:wallet/request-collectibles-for-all-accounts {}])]
[rn/view {:style style/container}
(case selected-tab
:assets [assets/view]
:collectibles [collectibles/view
{:collectibles collectible-list
:on-end-reached request-collectibles
:on-collectible-press (fn [{:keys [id]}]
(rf/dispatch [:wallet/get-collectible-details id]))}]
[activity/view])]))
@@ -1,6 +1,5 @@
(ns status-im.contexts.wallet.send.events
(:require
[camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]
[clojure.string :as string]
[native-module.core :as native-module]
@@ -11,7 +10,8 @@
[utils.address :as address]
[utils.money :as money]
[utils.number]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(rf/reg-event-fx :wallet/clean-send-data
(fn [{:keys [db]}]
@@ -24,7 +24,7 @@
(rf/reg-event-fx :wallet/suggested-routes-success
(fn [{:keys [db]} [suggested-routes timestamp]]
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
(let [suggested-routes-data (cske/transform-keys csk/->kebab-case suggested-routes)
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword suggested-routes)
chosen-route (:best suggested-routes-data)]
{:db (-> db
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes-data)
@@ -90,7 +90,7 @@
(rf/reg-event-fx :wallet/clean-selected-token
(fn [{:keys [db]}]
{:db (update-in db [:wallet :ui :send] dissoc :token :type)}))
{:db (assoc-in db [:wallet :ui :send :token] nil)}))
(rf/reg-event-fx :wallet/clean-selected-collectible
(fn [{:keys [db]}]
@@ -33,6 +33,7 @@
[collectibles-tab/view
{:collectibles collectibles
:filtered? search-performed?
:on-end-reached #(rf/dispatch [:wallet/request-collectibles-for-current-viewing-account])
:on-collectible-press #(rf/dispatch [:wallet/send-select-collectible
{:collectible %
:stack-id :wallet-select-asset}])}]))
@@ -48,11 +48,14 @@
(defn view
[]
(let [padding-top (:top (safe-area/get-insets))
wallet-type (reagent/atom :legacy)
;; Design team is yet to confirm the default selected networks here.
;; Should be the current selected for the account or all the networks always
selected-networks (reagent/atom [:ethereum :optimism :arbitrum])]
(let [padding-top (:top (safe-area/get-insets))
wallet-type (reagent/atom :legacy)
;; Design team is yet to confirm the default selected networks here. Should be the current
;; selected for the account or all the networks always
selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
on-settings-press #(open-preferences selected-networks)
on-legacy-press #(reset! wallet-type :legacy)
on-multichain-press #(reset! wallet-type :multichain)]
(fn []
(let [{:keys [address color emoji watch-only?]
:as account} (rf/sub [:wallet/current-viewing-account])
@@ -97,6 +100,6 @@
:full-name (:name account)
:customization-color color
:emoji emoji
:on-legacy-press #(reset! wallet-type :legacy)
:on-multichain-press #(reset! wallet-type :multichain)
:on-settings-press #(open-preferences selected-networks)}]]]]))))
:on-legacy-press on-legacy-press
:on-multichain-press on-multichain-press
:on-settings-press on-settings-press}]]]]))))
@@ -52,10 +52,9 @@
:overlay-color (quo.theme/theme-value colors/white-70-blur
colors/neutral-95-opa-70-blur
theme)}])
[rn/view {:style style/gradient-container}
[quo/gradient-cover
{:customization-color color
:opacity 0.4}]]
[quo/gradient-cover
{:customization-color color
:opacity 0.4}]
[quo/drawer-bar]
[quo/drawer-top
(cond-> {:title name
+11 -15
View File
@@ -2,12 +2,13 @@
(:require
[oops.core :as oops]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(rf/reg-event-fx
:wallet/pending-transaction-status-changed-received
(fn [{:keys [db]} [{:keys [message]}]]
(let [details (js->clj (js/JSON.parse message) :keywordize-keys true)
(let [details (transforms/json->clj message)
tx-hash (:hash details)]
{:db (update-in db [:wallet :transactions tx-hash] assoc :status :confirmed :blocks 1)})))
@@ -25,22 +26,17 @@
"pending-transaction-status-changed" {:fx
[[:dispatch
[:wallet/pending-transaction-status-changed-received
(js->clj event-js
:keywordize-keys
true)]]]}
(transforms/js->clj event-js)]]]}
"wallet-owned-collectibles-filtering-done" {:fx [[:dispatch
[:wallet/owned-collectibles-filtering-done
(js->clj event-js
:keywordize-keys
true)]]]}
(transforms/js->clj event-js)]]]}
"wallet-get-collectibles-details-done" {:fx [[:dispatch
[:wallet/get-collectible-details-done
(js->clj event-js
:keywordize-keys
true)]]]}
(transforms/js->clj event-js)]]]}
"wallet-tick-reload" {:fx [[:dispatch [:wallet/reload]]]}
"wallet-blockchain-status-changed" {:fx [[:dispatch
[:wallet/blockchain-status-changed
(transforms/js->clj event-js)]]]}
(log/debug ::unknown-wallet-event
:type type
:event (js->clj event-js
:keywordize-keys
true))))))
:type event-type
:event (transforms/js->clj event-js))))))
+10 -2
View File
@@ -423,11 +423,19 @@
(fn [previews]
(get previews :unfurled)))
(re-frame/reg-sub
:chats/status-link-previews-unfurled
:<- [:chat/status-link-previews]
(fn [previews]
(:unfurled previews)))
(re-frame/reg-sub
:chats/link-previews?
:<- [:chats/link-previews-unfurled]
(fn [previews]
(boolean (seq previews))))
:<- [:chats/status-link-previews-unfurled]
(fn [previews status-link-previews]
(boolean (or (seq status-link-previews)
(seq previews)))))
(re-frame/reg-sub
:chat/check-channel-muted?
+28 -10
View File
@@ -94,6 +94,19 @@
(def memo-communities-stack-items (atom nil))
(defn- merge-opened-communities
[{:keys [joined pending] :as assorted-communities}]
(update assorted-communities :opened concat joined pending))
(defn- group-communities-by-status
[requests
{:keys [id]
:as community}]
(cond
(:joined community) :joined
(boolean (get requests id)) :pending
:else :opened))
(re-frame/reg-sub
:communities/grouped-by-status
:<- [:view-id]
@@ -104,16 +117,21 @@
;; in app-db. Result map has form: {:joined [id1, id2] :pending [id3, id5] :opened [id4]}"
(fn [[view-id communities requests]]
(if (or (empty? @memo-communities-stack-items) (= view-id :communities-stack))
(let [grouped-communities (reduce (fn [acc community]
(let [joined? (:joined community)
community-id (:id community)
pending? (boolean (get requests community-id))]
(cond
joined? (update acc :joined conj community)
pending? (update acc :pending conj community)
:else (update acc :opened conj community))))
{:joined [] :pending [] :opened []}
(vals communities))]
(let [grouped-communities (->> communities
vals
(group-by #(group-communities-by-status requests %))
merge-opened-communities
(map (fn [[k v]]
{k (sort-by (fn [{:keys [requested-to-join-at last-opened-at
joined-at]}]
(condp = k
:joined joined-at
:pending requested-to-join-at
:opened last-opened-at
last-opened-at))
#(compare %2 %1)
v)}))
(into {}))]
(reset! memo-communities-stack-items grouped-communities)
grouped-communities)
@memo-communities-stack-items)))
+15
View File
@@ -102,6 +102,21 @@
(fn [messages [_ chat-id message-id]]
(get-in messages [chat-id message-id :link-previews])))
(re-frame/reg-sub
:chats/message-link-previews?
:<- [:messages/messages]
(fn [messages [_ chat-id message-id]]
(-> messages
(get-in [chat-id message-id :link-previews])
count
pos?)))
(re-frame/reg-sub
:chats/message-status-link-previews
:<- [:messages/messages]
(fn [messages [_ chat-id message-id]]
(get-in messages [chat-id message-id :status-link-previews])))
(re-frame/reg-sub
:chats/pinned
:<- [:messages/pin-messages]
+16
View File
@@ -159,3 +159,19 @@
:pinned-at nil
:pinned-by :test-user}]
(rf/sub [sub-name :0xChat])))))
(def message-with-link-previews
{:0xChat {:0x01 {:content {:response-to nil}
:quoted-message nil
:message-id "0x1"
:from :xyz
:timestamp-str "14:00"
:content-type constants/content-type-text
:chat-id :0xChat
:link-previews [{:dummy-link-preview 1}]}}})
(h/deftest-sub :chats/message-link-previews?
[sub-name]
(testing "It returns true if link previews exists in a message"
(swap! rf-db/app-db assoc :messages message-with-link-previews)
(is (rf/sub [sub-name :0xChat :0x01]))))
+14 -6
View File
@@ -45,13 +45,21 @@
(-> current-account :collectibles add-collectibles-preview-url)))
(re-frame/reg-sub
:wallet/all-collectibles
:wallet/all-collectibles-list
:<- [:wallet]
(fn [wallet]
(->> wallet
:accounts
(mapcat (comp :collectibles val))
(add-collectibles-preview-url))))
(fn [{:keys [accounts]}]
(let [max-collectibles (->> accounts
(map (comp count :collectibles val))
(apply max))
all-collectibles (map (fn [[_address {:keys [collectibles]}]]
(let [amount-to-add (- max-collectibles (count collectibles))
empty-collectibles (repeat amount-to-add nil)]
(reduce conj collectibles empty-collectibles)))
accounts)]
(->> all-collectibles
(apply interleave)
(remove nil?)
(add-collectibles-preview-url)))))
(re-frame/reg-sub
:wallet/current-viewing-account-collectibles-filtered
+5 -1
View File
@@ -213,10 +213,14 @@
"Add with defaults, this version is able to receive `nil` and takes them as 0."
(fnil add* (bignumber 0) (bignumber 0)))
(defn mul
(defn- mul*
[bn1 bn2]
(.mul ^js bn1 bn2))
(def mul
"Multiply with defaults, this version is able to receive `nil` and takes them as 0."
(fnil mul* (bignumber 0) (bignumber 0)))
(defn mul-and-round
[bn1 bn2]
(.round (.mul ^js bn1 bn2) 0))
+4
View File
@@ -1,6 +1,7 @@
(ns utils.transforms
(:refer-clojure :exclude [js->clj])
(:require
[camel-snake-kebab.core :as csk]
[cljs-bean.core :as clj-bean]
[oops.core :as oops]
[reagent.impl.template :as reagent.template]
@@ -20,6 +21,9 @@
(try (js->clj (.parse js/JSON json))
(catch js/Error _ (when (string? json) json)))))
(def ->kebab-case-keyword (memoize csk/->kebab-case-keyword))
(def ->PascalCaseKeyword (memoize csk/->PascalCaseKeyword))
(defn json->js
[json]
(when-not (= json "undefined")
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.176.2",
"commit-sha1": "00f50a4112ef80cc29737f8edf34cdb1cf181709",
"src-sha256": "12z9qf0hhb2pc7ask6f86pah0wjp3kyxyv32rpfnkjl42maw0bw6"
"version": "add-favicons-to-link-previews",
"commit-sha1": "ab85a9591b5ee08ebed16fed83bd53ffc1b43de3",
"src-sha256": "1ldgzvsn8hv3k4r35l1x7zhzl8xmi72bbz1wsr7jmj5x8mmlfbwm"
}
-2
View File
@@ -309,8 +309,6 @@ class ProfileView(BaseView):
xpath="//android.widget.TextView[contains(@text,'with upstream RPC')]")
self.plus_button = Button(self.driver, xpath="(//android.widget.ImageView[@content-desc='icon'])[2]")
self.custom_chain_button = Button(self.driver, translation_id="custom")
self.custom_network_url_input = EditBox(self.driver, translation_id="rpc-url",
suffix="/following-sibling::*[1]/android.widget.EditText")
self.custom_network_symbol_input = EditBox(self.driver, translation_id="specify-symbol")
self.specify_name_input = EditBox(self.driver, translation_id="name",
suffix="/following-sibling::*[1]/android.widget.EditText")
+8 -10
View File
@@ -33,7 +33,6 @@
"add-custom-token": "Add custom token",
"add-mailserver": "Add Status node",
"add-members": "Add members",
"add-network": "Add network",
"add-node": "Add node",
"add-to-contacts": "Add to contacts",
"add-to-contacts-text": "By adding a user to your contact list, you share your wallet address",
@@ -401,7 +400,6 @@
"current-pin": "Enter 6-digit passcode",
"current-pin-description": "Enter your 6-digit passcode to proceed",
"custom": "Custom",
"custom-networks": "Custom networks",
"dapp": "ÐApp",
"dapp-would-like-to-connect-wallet": "would like to connect to",
"dapps": "dApps",
@@ -662,7 +660,6 @@
"get-stickers": "Get Stickers",
"gif": "GIF",
"go-to-settings": "Go to Settings...",
"goerli-network": "Goerli network",
"got-it": "Got it",
"group-chat": "Group chat",
"group-chat-admin": "Admin",
@@ -918,7 +915,6 @@
"main-currency": "Main currency",
"main-networks": "Main networks",
"main-wallet": "Main Wallet",
"mainnet-network": "Main network",
"make-admin": "Make admin",
"make-moderator": "Make moderator",
"manage-keys-and-storage": "Manage keys and storage",
@@ -1027,8 +1023,6 @@
"opening-buy-crypto": "Opening {{site}}...",
"network": "Network",
"network-chain": "Network chain",
"network-details": "Network details",
"network-info": "Network info",
"network-fee": "Network fee",
"network-id": "Network ID",
"network-invalid-network-id": "Specified network id doesn't correspond to network id by RPC url",
@@ -1250,7 +1244,6 @@
"retry": "Retry",
"reveal-sync-code": "Reveal sync code",
"revoke-access": "Revoke access",
"rpc-url": "RPC URL",
"save": "Save",
"save-bio": "Save bio",
"save-colour": "Save colour",
@@ -1332,7 +1325,6 @@
"specify-name": "Specify a name",
"specify-symbol": "Specify a symbol",
"specify-network-id": "Specify network id",
"specify-rpc-url": "Specify a RPC URL",
"start-chat": "Start chat",
"start-conversation": "Start conversation",
"start-group-chat": "Start group chat",
@@ -1364,7 +1356,6 @@
"sign-up": "Sign up",
"tag-was-lost": "Tag was lost",
"tap-card-again": "Tap the card to the back of your phone again",
"test-networks": "Test networks",
"text-input-disabled": "Please wait a moment...",
"this-device": "This device",
"this-device-desc": "Your keys will be encrypted and securely stored on your device",
@@ -1661,12 +1652,16 @@
"page-would-like-to-use-camera": "would like to use your camera",
"page-camera-request-blocked": "camera requests blocked. To enable camera requests go to Settings",
"nickname": "Nickname",
"nickname-is-too-long": "Nickname is too long",
"add-nickname": "Add a nickname (optional)",
"edit-nickname": "Edit nickname",
"add-nickname-title": "Add nickname",
"nickname-visible-to-you": "Nickname will only be visible to you",
"type-nickname": "Type nickname",
"remove-nickname": "Remove nickname",
"nickname-removed": "Nickname removed",
"nickname-added": "Nickname for {{primary-name}} added",
"nickname-updated": "Nickname for {{primary-name}} updated",
"set-nickname-toast": "You have renamed {{primary-name}} as {{nickname}}",
"remove-nickname-toast": "You have removed {{secondary-name}}'s nickname",
"nickname-description": "Nicknames help you identify others in Status.\nOnly you can see the nicknames youve added",
@@ -1978,12 +1973,14 @@
"new-ui": "New UI",
"send-contact-request-message": "To start a chat you need to become contacts",
"contact-request": "Contact request",
"send-contact-request": "Send contact request",
"contact-request-sent-to": "Contact request sent to",
"contact-request-was-accepted": "Contact request accepted",
"contact-request-is-now-a-contact": "is now a contact",
"contact-request-removed-you-as-contact": "removed you as a contact",
"contact-request-removed-as-contact": "removed as a contact",
"contact-requests": "Contact requests",
"contact-request-message-prompt": "Why should they accept your request?",
"say-hi": "Say hi",
"opened": "Opened",
"accepted": "Accepted",
@@ -2521,5 +2518,6 @@
"keypair-name-input-placeholder": "Collectibles account, Old vault....",
"goerli-testnet-toggle-confirmation": "Are you sure you want to toggle Goerli? This will log you out and you will have to login again.",
"bridged-to": "Bridged to {{network}}",
"slide-to-bridge": "Slide to bridge"
"slide-to-bridge": "Slide to bridge",
"provider-is-down": "The provider for the following chain(s) is down: {{chains}}"
}