Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70f99407fc | ||
|
|
bf9fc03670 | ||
|
|
7a6714eeb2 | ||
|
|
a3b04f8ce0 | ||
|
|
c2db5ec102 | ||
|
|
ab880b11cd | ||
|
|
f72f3ad1c8 | ||
|
|
aaef05a3c0 | ||
|
|
3bf8734a7e | ||
|
|
43493f82c0 | ||
|
|
a80f16f632 | ||
|
|
109ab6b2ff | ||
|
|
cfa893c746 | ||
|
|
8f76fb9f97 | ||
|
|
5b5d602511 | ||
|
|
5e32ba8e6c | ||
|
|
d63c73b6bf | ||
|
|
f079f52941 | ||
|
|
545abee7d1 | ||
|
|
fe6beef442 | ||
|
|
5f44d2b319 | ||
|
|
8f0c4087c2 | ||
|
|
690aab3185 | ||
|
|
843b1b57d7 | ||
|
|
160d4e6d71 | ||
|
|
d7e8d3c5c2 | ||
|
|
962ba6ccd0 | ||
|
|
928a87a368 | ||
|
|
e4c2bd0683 | ||
|
|
66f1de8d6b | ||
|
|
3455f9f1ef | ||
|
|
26acf1dd38 | ||
|
|
b1cb5221f1 | ||
|
|
00ea2f9f71 | ||
|
|
6be6c39bae | ||
|
|
c3df5139df | ||
|
|
b3bebe1859 | ||
|
|
ad546f9f14 | ||
|
|
3145ecd6bf | ||
|
|
669a232ad9 | ||
|
|
29e69c54bd | ||
|
|
5fd0b27589 | ||
|
|
7d6b2ac87a | ||
|
|
93f488e61a | ||
|
|
f7498ef81f | ||
|
|
f1834c6a15 | ||
|
|
ffcca1aea3 | ||
|
|
0937da9e50 | ||
|
|
33e637ff71 | ||
|
|
a538e2896e | ||
|
|
c02cc5d391 | ||
|
|
613e48ece3 |
@@ -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' \
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"}}})))
|
||||
|
||||
|
||||
@@ -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])))))
|
||||
|
||||
@@ -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,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}))
|
||||
|
||||
@@ -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"])))))
|
||||
|
||||
@@ -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))))
|
||||
@@ -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}
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]]]]]))
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))))))
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]))))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,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"
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 you’ve 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}}"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user