diff --git a/src/status_im/accounts/login/core.cljs b/src/status_im/accounts/login/core.cljs index f3fd9722ea..5261a5614b 100644 --- a/src/status_im/accounts/login/core.cljs +++ b/src/status_im/accounts/login/core.cljs @@ -1,27 +1,27 @@ (ns status-im.accounts.login.core (:require [re-frame.core :as re-frame] [status-im.accounts.db :as accounts.db] + [status-im.chaos-mode.core :as chaos-mode] [status-im.data-store.core :as data-store] + [status-im.fleet.core :as fleet] + [status-im.i18n :as i18n] + [status-im.models.transactions :as transactions] + [status-im.models.wallet :as models.wallet] [status-im.native-module.core :as status] + [status-im.node.core :as node] + [status-im.protocol.core :as protocol] + [status-im.tribute-to-talk.core :as tribute-to-talk] + [status-im.ui.screens.mobile-network-settings.events :as mobile-network] [status-im.ui.screens.navigation :as navigation] [status-im.utils.config :as config] - [status-im.fleet.core :as fleet] [status-im.utils.fx :as fx] - [status-im.react-native.js-dependencies :as rn-dependencies] - [status-im.utils.keychain.core :as keychain] - [status-im.utils.types :as types] - [taoensso.timbre :as log] - [status-im.utils.universal-links.core :as universal-links] - [status-im.utils.security :as security] - [status-im.utils.platform :as platform] - [status-im.protocol.core :as protocol] - [status-im.models.wallet :as models.wallet] [status-im.utils.handlers :as handlers] - [status-im.models.transactions :as transactions] - [status-im.i18n :as i18n] - [status-im.node.core :as node] - [status-im.ui.screens.mobile-network-settings.events :as mobile-network] - [status-im.chaos-mode.core :as chaos-mode])) + [status-im.utils.keychain.core :as keychain] + [status-im.utils.platform :as platform] + [status-im.utils.security :as security] + [status-im.utils.types :as types] + [status-im.utils.universal-links.core :as universal-links] + [taoensso.timbre :as log])) (def rpc-endpoint "https://goerli.infura.io/v3/f315575765b14720b32382a61a89341a") (def contract-address "0xfbf4c8e2B41fAfF8c616a0E49Fb4365a5355Ffaf") @@ -144,6 +144,7 @@ (fn [_] (when save-password? {:keychain/save-user-password [address password]})) + (tribute-to-talk/init) (mobile-network/on-network-status-change) (protocol/initialize-protocol) (universal-links/process-stored-event) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 974ae1017b..82b5f626b1 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -8,15 +8,17 @@ [status-im.accounts.update.core :as accounts.update] [status-im.bootnodes.core :as bootnodes] [status-im.browser.core :as browser] - [status-im.node.core :as node] [status-im.browser.permissions :as browser.permissions] + [status-im.chat.commands.core :as commands] [status-im.chat.commands.input :as commands.input] + [status-im.chat.db :as chat.db] [status-im.chat.models :as chat] [status-im.chat.models.input :as chat.input] [status-im.chat.models.loading :as chat.loading] [status-im.chat.models.message :as chat.message] - [status-im.contact.core :as contact] + [status-im.contact-code.core :as contact-code] [status-im.contact-recovery.core :as contact-recovery] + [status-im.contact.core :as contact] [status-im.extensions.core :as extensions] [status-im.extensions.registry :as extensions.registry] [status-im.fleet.core :as fleet] @@ -24,38 +26,36 @@ [status-im.hardwallet.core :as hardwallet] [status-im.i18n :as i18n] [status-im.init.core :as init] - [status-im.utils.logging.core :as logging] [status-im.log-level.core :as log-level] [status-im.mailserver.core :as mailserver] [status-im.network.core :as network] + [status-im.node.core :as node] [status-im.notifications.core :as notifications] [status-im.pairing.core :as pairing] - [status-im.contact-code.core :as contact-code] [status-im.privacy-policy.core :as privacy-policy] [status-im.protocol.core :as protocol] [status-im.qr-scanner.core :as qr-scanner] [status-im.search.core :as search] [status-im.signals.core :as signals] - [status-im.transport.message.core :as transport.message] - [status-im.transport.core :as transport] - [status-im.ui.screens.currency-settings.models :as currency-settings.models] - [status-im.tribute-to-talk.core :as tribute-to-talk] - [status-im.node.core :as node] - [status-im.web3.core :as web3] - [status-im.ui.screens.navigation :as navigation] - [status-im.utils.fx :as fx] - [status-im.utils.handlers :as handlers] - [status-im.utils.utils :as utils] - [taoensso.timbre :as log] - [status-im.chat.commands.core :as commands] - [status-im.chat.models.loading :as chat-loading] - [status-im.node.core :as node] [status-im.stickers.core :as stickers] - [status-im.utils.config :as config] + [status-im.transport.core :as transport] + [status-im.transport.message.core :as transport.message] + [status-im.tribute-to-talk.core :as tribute-to-talk] [status-im.ui.components.bottom-sheet.core :as bottom-sheet] [status-im.ui.components.react :as react] + [status-im.ui.screens.add-new.new-chat.db :as new-chat.db] + [status-im.ui.screens.currency-settings.models + :as + currency-settings.models] + [status-im.ui.screens.navigation :as navigation] [status-im.utils.build :as build] - [status-im.chat.db :as chat.db])) + [status-im.utils.config :as config] + [status-im.utils.fx :as fx] + [status-im.utils.handlers :as handlers] + [status-im.utils.logging.core :as logging] + [status-im.utils.utils :as utils] + [status-im.web3.core :as web3] + [taoensso.timbre :as log])) ;; init module @@ -108,7 +108,7 @@ (log/debug "PERF" :init-rest-of-chats (.now js/Date)) (fx/merge cofx {:db (assoc db :chats/loading? false)} - (chat-loading/initialize-chats {:from 10})))) + (chat.loading/initialize-chats {:from 10})))) (defn account-change-success [{:keys [db] :as cofx} [_ address nodes]] @@ -122,7 +122,7 @@ (node/initialize (get-in db [:accounts/login :address]))) (init/initialize-account address) (mailserver/initialize-ranges) - (chat-loading/initialize-chats {:to 10})))) + (chat.loading/initialize-chats {:to 10})))) (handlers/register-handler-fx :init.callback/account-change-success @@ -1656,6 +1656,11 @@ (fn [cofx [_ chat-id envelope-hash]] (transport.message/set-contact-message-envelope-hash cofx chat-id envelope-hash))) +(handlers/register-handler-fx + :transport.callback/node-info-fetched + (fn [cofx [_ node-info]] + (transport/set-node-info cofx node-info))) + ;; contact module (handlers/register-handler-fx @@ -1686,13 +1691,24 @@ (handlers/register-handler-fx :contact/qr-code-scanned [(re-frame/inject-cofx :random-id-generator)] - (fn [cofx [_ _ contact-identity]] - (contact/handle-qr-code cofx contact-identity))) + (fn [{:keys [db] :as cofx} [_ _ contact-identity]] + (let [current-account (:account/account db) + fx {:db (assoc db :contacts/new-identity contact-identity)} + validation-result (new-chat.db/validate-pub-key db contact-identity)] + (if (some? validation-result) + {:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code) + :content validation-result + :on-dismiss #(re-frame/dispatch [:navigate-to-clean :home])}} + (fx/merge cofx + fx + (if config/partitioned-topic-enabled? + (contact/add-contacts-filter contact-identity :open-chat) + (chat/start-chat contact-identity {:navigation-reset? true}))))))) (handlers/register-handler-fx :contact/filters-added (fn [cofx [_ contact-identity]] - (contact/open-chat cofx contact-identity))) + (chat/start-chat cofx contact-identity {:navigation-reset? true}))) (handlers/register-handler-fx :contact.ui/start-group-chat-pressed @@ -1703,13 +1719,13 @@ :contact.ui/send-message-pressed [(re-frame/inject-cofx :random-id-generator)] (fn [cofx [_ {:keys [public-key]}]] - (contact/open-chat cofx public-key))) + (chat/start-chat cofx public-key {:navigation-reset? true}))) (handlers/register-handler-fx :contact.ui/contact-code-submitted [(re-frame/inject-cofx :random-id-generator)] - (fn [cofx _] - (contact/add-new-identity-to-contacts cofx))) + (fn [{{:contacts/keys [new-identity]} :db :as cofx} _] + (chat/start-chat cofx new-identity {:navigation-reset? true}))) ;; search module @@ -1858,11 +1874,6 @@ (fn [cofx _] (stickers/pending-timeout cofx))) -(handlers/register-handler-fx - :transport.callback/node-info-fetched - (fn [cofx [_ node-info]] - (transport/set-node-info cofx node-info))) - ;; Tribute to Talk (handlers/register-handler-fx :tribute-to-talk.ui/menu-item-pressed @@ -1904,6 +1915,59 @@ (fn [cofx _] (tribute-to-talk/remove cofx))) +(handlers/register-handler-fx + :tribute-to-talk.callback/check-manifest-success + (fn [cofx [_ identity contenthash]] + (tribute-to-talk/fetch-manifest cofx identity contenthash))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/no-manifest-found + (fn [cofx [_ identity]] + (tribute-to-talk/update-settings cofx nil))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/fetch-manifest-success + (fn [cofx [_ identity {:keys [tribute-to-talk]}]] + (tribute-to-talk/update-settings cofx tribute-to-talk))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/fetch-manifest-failure + (fn [cofx [_ identity contenthash]] + (tribute-to-talk/fetch-manifest cofx identity contenthash))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/check-manifest + (fn [{:keys [db] :as cofx} [_ identity]] + (tribute-to-talk/check-manifest cofx identity))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/manifest-uploaded + (fn [cofx [_ hash]] + (tribute-to-talk/set-manifest-signing-flow cofx hash))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/manifest-upload-failed + (fn [cofx [_ error]] + (tribute-to-talk/on-manifest-upload-failed cofx error))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/set-manifest-transaction-completed + (fn [cofx [_ id transaction-hash method]] + (tribute-to-talk/on-set-manifest-transaction-completed cofx + transaction-hash))) + +(handlers/register-handler-fx + :tribute-to-talk.callback/set-manifest-transaction-failed + (fn [cofx [_ error]] + (tribute-to-talk/on-set-manifest-transaction-failed cofx + error))) + +(handlers/register-handler-fx + :tribute-to-talk/check-set-manifest-transaction-timeout + (fn [cofx _] + (tribute-to-talk/check-set-manifest-transaction cofx))) + +;; bottom-sheet events (handlers/register-handler-fx :bottom-sheet/show-sheet (fn [cofx [_ view]] diff --git a/src/status_im/ipfs/core.cljs b/src/status_im/ipfs/core.cljs index 38e829bff3..5548281bff 100644 --- a/src/status_im/ipfs/core.cljs +++ b/src/status_im/ipfs/core.cljs @@ -14,9 +14,9 @@ :success-event-creator (fn [{:keys [status body]}] (if (= 200 status) - (on-success {:value body}) + (on-success body) (when on-failure - (on-failure {:value status}))))} + (on-failure status))))} on-failure (assoc :failure-event-creator on-failure))}) @@ -40,8 +40,8 @@ :success-event-creator (fn [{:keys [status body]}] (if (= 200 status) - (on-success {:value (parse-ipfs-add-response body)}) + (on-success (parse-ipfs-add-response body)) (when on-failure - (on-failure {:value status}))))} + (on-failure status))))} on-failure (assoc :failure-event-creator on-failure))})) diff --git a/src/status_im/tribute_to_talk/core.cljs b/src/status_im/tribute_to_talk/core.cljs index 9627aba11f..b33e26dedd 100644 --- a/src/status_im/tribute_to_talk/core.cljs +++ b/src/status_im/tribute_to_talk/core.cljs @@ -1,35 +1,77 @@ (ns status-im.tribute-to-talk.core (:refer-clojure :exclude [remove]) (:require [clojure.string :as string] + [re-frame.core :as re-frame] [status-im.accounts.update.core :as accounts.update] + [status-im.contact.db :as contact.db] + [status-im.ipfs.core :as ipfs] + [status-im.tribute-to-talk.db :as tribute-to-talk.db] [status-im.ui.screens.navigation :as navigation] - [status-im.utils.fx :as fx])) + [status-im.utils.contenthash :as contenthash] + [status-im.utils.ethereum.contracts :as contracts] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.fx :as fx] + [taoensso.timbre :as log])) + +(fx/defn update-settings + [{:keys [db] :as cofx} {:keys [snt-amount message update] :as new-settings}] + (let [account-settings (get-in db [:account/account :settings]) + chain-keyword (-> (get-in db [:account/account :networks (:network db)]) + ethereum/network->chain-keyword) + tribute-to-talk-settings (cond-> (merge (tribute-to-talk.db/get-settings db) + new-settings) + new-settings + (assoc :seen? true) + + (not new-settings) + (dissoc :snt-amount :manifest) + + (and (contains? new-settings :update) + (nil? update)) + (dissoc :update))] + (accounts.update/update-settings + cofx + (-> account-settings + (assoc-in [:tribute-to-talk chain-keyword] + tribute-to-talk-settings)) + {}))) (fx/defn mark-ttt-as-seen [{:keys [db] :as cofx}] - (let [settings (get-in db [:account/account :settings]) - {:keys [seen?]} (:tribute-to-talk settings)] - (when-not seen? - (fx/merge cofx - {:db (assoc db :tribute-to-talk/seen? true)} - (accounts.update/update-settings - (assoc-in settings [:tribute-to-talk :seen?] true) {}))))) + (when-not (:seen (tribute-to-talk.db/get-settings db)) + (update-settings cofx {:seen? true}))) (fx/defn open-settings [{:keys [db] :as cofx}] - (let [snt-amount (get-in db [:account/account :settings :tribute-to-talk :snt-amount])] + (let [settings (tribute-to-talk.db/get-settings db) + updated-settings (:update settings)] (fx/merge cofx mark-ttt-as-seen - (navigation/navigate-to-cofx :tribute-to-talk - (if snt-amount - {:step :edit - :editing? true} - {:step :intro}))))) + (navigation/navigate-to-cofx + :tribute-to-talk + (cond + updated-settings + (merge {:step :finish} + updated-settings + (when updated-settings + {:state :pending})) + (:snt-amount settings) + (merge {:step :edit + :editing? true} + (update settings :snt-amount tribute-to-talk.db/from-wei)) + :else + {:step :intro}))))) (fx/defn set-step [{:keys [db]} step] {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :step] step)}) +(fx/defn set-step-finish + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :state] :signing)} + (set-step :finish))) + (fx/defn open-learn-more [cofx] (set-step cofx :learn-more)) @@ -53,6 +95,24 @@ :finish (set-step cofx :personalized-message)))) +(fx/defn upload-manifest + [cofx] + (let [{:keys [message snt-amount]} + (get-in cofx [:db :navigation/screen-params :tribute-to-talk]) + manifest {:tribute-to-talk + {:message message + :snt-amount (tribute-to-talk.db/to-wei snt-amount)}}] + (ipfs/add cofx + {:value (js/JSON.stringify + (clj->js manifest)) + :on-success + (fn [response] + [:tribute-to-talk.callback/manifest-uploaded + (:hash response)]) + :on-failure + (fn [error] + [:tribute-to-talk.callback/manifest-upload-failed error])}))) + (fx/defn step-forward [cofx] (let [{:keys [step editing?]} @@ -65,14 +125,9 @@ (set-step cofx :personalized-message) :personalized-message - (let [account-settings (get-in cofx [:db :account/account :settings])] - (fx/merge cofx - (set-step (if editing? - :edit - :finish)) - (accounts.update/update-settings - account-settings - {}))) + (fx/merge cofx + (set-step-finish) + (upload-manifest)) :finish (navigation/navigate-back cofx)))) @@ -81,7 +136,7 @@ [snt-amount numpad-symbol] ;; TODO: Put some logic in place so that incorrect numbers can not ;; be entered - (let [snt-amount (or snt-amount "0")] + (let [snt-amount (or (str snt-amount) "0")] (if (= numpad-symbol :remove) (let [len (count snt-amount) s (subs snt-amount 0 (dec len))] @@ -105,25 +160,140 @@ (fx/defn update-snt-amount [{:keys [db]} numpad-symbol] - {:db (update-in db [:account/account :settings :tribute-to-talk :snt-amount] + {:db (update-in db + [:navigation/screen-params :tribute-to-talk :snt-amount] #(get-new-snt-amount % numpad-symbol))}) (fx/defn update-message [{:keys [db]} message] - {:db (assoc-in db [:account/account :settings :tribute-to-talk :message] + {:db (assoc-in db + [:navigation/screen-params :tribute-to-talk :message] message)}) (fx/defn start-editing [{:keys [db]}] - {:db (assoc-in db [:navigation/screen-params :tribute-to-talk] - {:step :set-snt-amount - :editing? true})}) + {:db (assoc-in db + [:navigation/screen-params :tribute-to-talk :step] + :set-snt-amount)}) + +(fx/defn fetch-manifest + [{:keys [db] :as cofx} identity contenthash] + (contenthash/cat cofx + {:contenthash contenthash + :on-failure + (fn [error] + (re-frame/dispatch + (if (= 503 error) + [:tribute-to-talk.callback/fetch-manifest-failure + identity contenthash] + [:tribute-to-talk.callback/no-manifest-found identity]))) + :on-success + (fn [manifest-json] + (let [manifest (js->clj (js/JSON.parse manifest-json) + :keywordize-keys true)] + (re-frame/dispatch + [:tribute-to-talk.callback/fetch-manifest-success + identity manifest])))})) + +(fx/defn check-manifest + [{:keys [db] :as cofx} identity] + (or (contracts/call cofx + {:contract :status/tribute-to-talk + :method :get-manifest + :params [(contact.db/public-key->address identity)] + :return-params ["bytes"] + :callback + #(re-frame/dispatch + (if-let [contenthash (first %)] + [:tribute-to-talk.callback/check-manifest-success + identity + contenthash] + [:tribute-to-talk.callback/no-manifest-found identity]))}) + ;; `contracts/call` returns nil if there is no contract for the current network + ;; update settings if checking own manifest or do nothing otherwise + (when-let [me? (= identity + (get-in cofx [:db :account/account :public-key]))] + (update-settings cofx nil)))) + +(fx/defn check-own-manifest + [cofx] + (check-manifest cofx (get-in cofx [:db :account/account :public-key]))) + +(fx/defn set-manifest-signing-flow + [{:keys [db] :as cofx} hash] + (let [contenthash (when hash + (contenthash/encode {:hash hash + :namespace :ipfs}))] + (or (contracts/call cofx + {:contract :status/tribute-to-talk + :method :set-manifest + :params [contenthash] + :on-result [:tribute-to-talk.callback/set-manifest-transaction-completed] + :on-error [:tribute-to-talk.callback/set-manifest-transaction-failed]}) + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :state] :transaction-failed)}))) (defn remove [{:keys [db] :as cofx}] - (let [account-settings (get-in db [:account/account :settings])] + (fx/merge cofx + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk] + {:step :finish + :state :disabled})} + (set-manifest-signing-flow nil))) + +(fx/defn check-set-manifest-transaction + [{:keys [db] :as cofx}] + (let [transaction (get-in (tribute-to-talk.db/get-settings db) [:update :transaction])] + (when transaction + (let [confirmed? (pos? (js/parseInt + (get-in cofx [:db :wallet :transactions + transaction :confirmations] + 0))) + ;;TODO support failed transactions + failed? false] + (cond + failed? + (fx/merge cofx + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :state] :transaction-failed)} + (update-settings {:update nil})) + + confirmed? + (fx/merge cofx + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :state] :completed)} + check-own-manifest + (update-settings {:update nil})) + + (not confirmed?) + {:dispatch-later [{:ms 10000 + :dispatch [:tribute-to-talk/check-set-manifest-transaction-timeout]}]}))))) + +(fx/defn on-set-manifest-transaction-completed + [{:keys [db] :as cofx} transaction-hash] + (let [{:keys [snt-amount message]} (get-in db [:navigation/screen-params + :tribute-to-talk])] (fx/merge cofx - {:db (assoc-in db [:navigation/screen-params :tribute-to-talk] - {:step :finish})} - (accounts.update/update-settings - (assoc account-settings :tribute-to-talk {:seen? true}) {})))) + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :state] :pending)} + (navigation/navigate-to-clean :wallet-transaction-sent-modal {}) + (update-settings {:update {:transaction transaction-hash + :snt-amount snt-amount + :message message}}) + check-set-manifest-transaction))) + +(fx/defn on-set-manifest-transaction-failed + [{:keys [db] :as cofx} error] + (log/error :set-manifest-transaction-failed error) + {:db (assoc-in db + [:navigation/screen-params :tribute-to-talk :state] + :transaction-failed)}) + +(fx/defn on-manifest-upload-failed + [{:keys [db] :as cofx} error] + (log/error :upload-manifest-failed error) + {:db (assoc-in db + [:navigation/screen-params :tribute-to-talk :state] + :transaction-failed)}) + +(fx/defn init + [cofx] + (fx/merge cofx + check-own-manifest + check-set-manifest-transaction)) diff --git a/src/status_im/tribute_to_talk/db.cljs b/src/status_im/tribute_to_talk/db.cljs new file mode 100644 index 0000000000..1288895b06 --- /dev/null +++ b/src/status_im/tribute_to_talk/db.cljs @@ -0,0 +1,25 @@ +(ns status-im.tribute-to-talk.db + (:require [status-im.js-dependencies :as dependencies] + [status-im.utils.ethereum.core :as ethereum])) + +(def utils dependencies/web3-utils) + +(defn to-wei + [s] + (when s + (.toWei utils s))) + +(defn from-wei + [s] + (when s + (.fromWei utils s))) + +(defn get-settings + [db] + (let [chain-keyword (-> (get-in db [:account/account :networks (:network db)]) + ethereum/network->chain-keyword)] + (get-in db [:account/account :settings :tribute-to-talk chain-keyword]))) + +(defn enabled? + [db] + (:snt-amount (get-settings db))) diff --git a/src/status_im/tribute_to_talk/subs.cljs b/src/status_im/tribute_to_talk/subs.cljs index fe622abc75..2da0f1e0d8 100644 --- a/src/status_im/tribute_to_talk/subs.cljs +++ b/src/status_im/tribute_to_talk/subs.cljs @@ -1,12 +1,13 @@ (ns status-im.tribute-to-talk.subs (:require [clojure.string :as string] [re-frame.core :as re-frame] + [status-im.tribute-to-talk.db :as tribute-to-talk] [status-im.utils.money :as money])) (re-frame/reg-sub :tribute-to-talk/settings (fn [db] - (get-in db [:account/account :settings :tribute-to-talk]))) + (tribute-to-talk/get-settings db))) (re-frame/reg-sub :tribute-to-talk/screen-params @@ -19,22 +20,35 @@ :<- [:tribute-to-talk/screen-params] :<- [:prices] :<- [:wallet/currency] - (fn [[{:keys [snt-amount message]} - {:keys [step editing?] :or {step :intro}} - prices currency]] + (fn [[{:keys [seen? snt-amount message update]} + {:keys [step editing? state error] + :or {step :intro} + screen-snt-amount :snt-amount + screen-message :message} prices currency]] (let [fiat-value (if snt-amount - (money/fiat-amount-value snt-amount - :SNT - (-> currency :code keyword) - prices) - "0") - disabled? (and (= step :set-snt-amount) - (or (string/blank? snt-amount) - (= "0" snt-amount) - (string/ends-with? snt-amount ".")))] - {:snt-amount snt-amount - :disabled? disabled? - :message message - :step step - :editing? editing? - :fiat-value (str "~" fiat-value " " (:code currency))}))) + (money/fiat-amount-value + snt-amount + :SNT + (-> currency :code keyword) + prices) + "0")] + (cond-> {:seen? seen? + :snt-amount (tribute-to-talk/from-wei snt-amount) + :message message + :disabled? (nil? snt-amount) + :error error + :step step + :state (or state (if snt-amount :completed :disabled)) + :editing? editing? + :fiat-value (str "~" fiat-value " " (:code currency))} + + (= step :set-snt-amount) + (assoc :snt-amount (str screen-snt-amount) + :disable-button? + (boolean (and (= step :set-snt-amount) + (or (string/blank? screen-snt-amount) + (#{"0" "0.0" "0.00"} screen-snt-amount) + (string/ends-with? screen-snt-amount "."))))) + + (= step :personalized-message) + (assoc :message screen-message))))) diff --git a/src/status_im/ui/components/contact/contact.cljs b/src/status_im/ui/components/contact/contact.cljs index 32141b38e3..415fd6a219 100644 --- a/src/status_im/ui/components/contact/contact.cljs +++ b/src/status_im/ui/components/contact/contact.cljs @@ -1,15 +1,15 @@ (ns status-im.ui.components.contact.contact - (:require-macros [status-im.utils.views :as views]) - (:require [status-im.i18n :as i18n] - [status-im.utils.platform :as platform] - [status-im.ui.components.react :as react] - [status-im.ui.components.icons.vector-icons :as vector-icons] + (:require [clojure.string :as string] + [status-im.i18n :as i18n] [status-im.ui.components.chat-icon.screen :as chat-icon] [status-im.ui.components.contact.styles :as styles] + [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.list.views :as list] + [status-im.ui.components.react :as react] [status-im.utils.gfycat.core :as gfycat] - [clojure.string :as string])) + [status-im.utils.platform :as platform]) + (:require-macros [status-im.utils.views :as views])) (defn desktop-extended-options [options] [react/view {} diff --git a/src/status_im/ui/components/contact/styles.cljs b/src/status_im/ui/components/contact/styles.cljs index 53e78b776d..c08a55cbab 100644 --- a/src/status_im/ui/components/contact/styles.cljs +++ b/src/status_im/ui/components/contact/styles.cljs @@ -1,8 +1,5 @@ (ns status-im.ui.components.contact.styles - (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) - (:require [status-im.ui.components.styles :as common] - [status-im.utils.platform] - [status-im.ui.components.colors :as colors])) + (:require [status-im.ui.components.colors :as colors])) (def contact-container-to-refactor {:flex-direction :row diff --git a/src/status_im/ui/components/list/views.cljs b/src/status_im/ui/components/list/views.cljs index 4edac1722f..fe3b0b9b10 100644 --- a/src/status_im/ui/components/list/views.cljs +++ b/src/status_im/ui/components/list/views.cljs @@ -18,9 +18,8 @@ [section-list {:sections [{:title \"\" :key :unik :render-fn render :data {:title \"\" :subtitle \"\"}}]}] " - (:require-macros [status-im.utils.views :as views]) - (:require [reagent.core :as reagent] - [clojure.string :as string] + (:require [clojure.string :as string] + [reagent.core :as reagent] [status-im.i18n :as i18n] [status-im.ui.components.animation :as animation] [status-im.ui.components.checkbox.view :as checkbox] @@ -28,8 +27,9 @@ [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.list.styles :as styles] [status-im.ui.components.react :as react] - [status-im.utils.platform :as platform] - [status-im.ui.screens.home.animations.responder :as responder])) + [status-im.ui.screens.home.animations.responder :as responder] + [status-im.utils.platform :as platform]) + (:require-macros [status-im.utils.views :as views])) (def flat-list-class (react/get-class "FlatList")) (def section-list-class (react/get-class "SectionList")) @@ -68,7 +68,7 @@ (defn item-primary ([s] (item-primary nil s)) ([{:keys [style] :as props} s] - [react/text (merge {:style styles/primary-text} + [react/text (merge {:style (merge styles/primary-text style)} (dissoc props :style)) s])) @@ -80,8 +80,13 @@ s])) (defn item-secondary - [secondary] - [react/text {:style styles/secondary-text :ellipsize-mode :middle :number-of-lines 1} secondary]) + ([s] (item-secondary nil s)) + ([{:keys [style]} s] + [react/text + {:style (merge styles/secondary-text style) + :ellipsize-mode :middle + :number-of-lines 1} + s])) (defn item-content [& children] @@ -108,14 +113,14 @@ (defn big-list-item [{:keys [style text text-color subtext value action-fn active? destructive? hide-chevron? - accessory-value text-color new? + accessory-value text-color new? activity-indicator accessibility-label icon icon-color image-source icon-content] :or {icon-color colors/blue text-color colors/black value "" active? true style {}}}] - {:pre [(or icon image-source) + {:pre [(or icon image-source activity-indicator) (and action-fn text) (or (nil? accessibility-label) (keyword? accessibility-label))]} [react/touchable-highlight @@ -124,11 +129,16 @@ :accessibility-label accessibility-label :disabled (not active?)} [react/view (styles/settings-item subtext) - (if icon + (cond + icon [react/view (styles/settings-item-icon icon-color subtext) [vector-icons/icon icon {:color icon-color}]] + image-source [react/image {:source {:uri image-source} - :style styles/big-item-image}]) + :style styles/big-item-image}] + activity-indicator + [react/view (styles/settings-item-icon icon-color subtext) + [react/activity-indicator activity-indicator]]) (if subtext [react/view {:style styles/settings-item-text-container} [react/view {:style styles/settings-item-main-text-container} @@ -247,8 +257,8 @@ {:sections (clj->js (map wrap-per-section-render-fn sections)) :renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)})]) -(defn render-action [{:keys [label accessibility-label icon action disabled?]} - {:keys [action-style action-label-style icon-opts]}] +(defn render-action [{:keys [label subtext accessibility-label icon action disabled?]} + {:keys [action-style action-label-style action-subtext-style icon-opts]}] [react/touchable-highlight {:on-press action} [react/view {:accessibility-label accessibility-label} [item @@ -259,10 +269,21 @@ :icon-opts (merge {:color :white} icon-opts (when disabled? {:color colors/gray}))}] - [item-primary-only {:style (merge styles/action-label - action-label-style + (if-not subtext + [item-primary-only {:style (merge styles/action-label + (action-label-style false) + (when disabled? styles/action-label-disabled))} + label] + [item-content + [item-primary {:style (merge styles/action-label + (action-label-style true) + (when disabled? styles/action-label-disabled))} + label] + [item-secondary {:style (merge styles/action-label + action-subtext-style (when disabled? styles/action-label-disabled))} - label] + subtext]]) + item-icon-forward]]]) (defn action-list [actions {:keys [container-style action-separator-style] :as styles}] diff --git a/src/status_im/ui/components/qr_code_viewer/views.cljs b/src/status_im/ui/components/qr_code_viewer/views.cljs index 67520c4d0c..5c8d13075f 100644 --- a/src/status_im/ui/components/qr_code_viewer/views.cljs +++ b/src/status_im/ui/components/qr_code_viewer/views.cljs @@ -1,14 +1,10 @@ (ns status-im.ui.components.qr-code-viewer.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [reagent.core :as reagent] - [re-frame.core :as re-frame] [status-im.react-native.js-dependencies :as rn-dependencies] - [status-im.ui.components.button.view :as button] - [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.qr-code-viewer.styles :as styles] - [status-im.ui.screens.profile.tribute-to-talk.views :as tr-to-talk] [status-im.ui.components.react :as react] - [status-im.i18n :as i18n])) + [status-im.ui.screens.profile.tribute-to-talk.views :as tr-to-talk]) + (:require-macros [status-im.utils.views :refer [defview letsubs]])) (defn qr-code [props] (reagent/create-element @@ -17,12 +13,12 @@ (defview qr-code-viewer-component [{:keys [style hint-style footer-style footer-button value hint legend]}] (letsubs [{:keys [width]} [:dimensions/window] - {:keys [snt-amount]} [:tribute-to-talk/settings]] + {:keys [disabled?]} [:tribute-to-talk/ui]] [react/scroll-view {:content-container-style {:align-items :center :margin-top 16 :justify-content :center} :style (merge {:flex 1} style)} - (when snt-amount + (when-not disabled? [react/view {:style {:margin-horizontal 16}} [tr-to-talk/enabled-note]]) (when width diff --git a/src/status_im/ui/components/status_bar/view.cljs b/src/status_im/ui/components/status_bar/view.cljs index 55bb2b820c..a13a473b7d 100644 --- a/src/status_im/ui/components/status_bar/view.cljs +++ b/src/status_im/ui/components/status_bar/view.cljs @@ -50,6 +50,7 @@ :fleet-settings {:type :main} :log-level-settings {:type :main} :stickers-pack-modal {:type :main} + :tribute-learn-more {:type :main} :show-extension-modal {:type :main} :wallet {:type :wallet-tab} :wallet-stack {:type :wallet-tab} diff --git a/src/status_im/ui/screens/profile/contact/styles.cljs b/src/status_im/ui/screens/profile/contact/styles.cljs index 172b3c246a..8186b1bb68 100644 --- a/src/status_im/ui/screens/profile/contact/styles.cljs +++ b/src/status_im/ui/screens/profile/contact/styles.cljs @@ -31,11 +31,20 @@ {:background-color (colors/alpha colors/blue 0.1) :border-radius 50}) -(def action-label - {:color colors/blue}) +(defn action-label [with-subtext?] + (cond-> {:color colors/blue} + with-subtext? + (assoc :font-size 15 + :line-height 22 + :font-weight "500"))) + +(def action-subtext + {:line-height 22 + :font-size 15 + :color colors/gray}) (def action-separator - {:height 1 + {:height 0 :background-color colors/gray-light :margin-left 50}) @@ -46,7 +55,7 @@ {:background-color (colors/alpha colors/red 0.1) :border-radius 50}) -(def block-action-label +(defn block-action-label [with-subtext?] {:color colors/red}) (def block-action-icon-opts diff --git a/src/status_im/ui/screens/profile/contact/views.cljs b/src/status_im/ui/screens/profile/contact/views.cljs index a12127ad1a..015061f682 100644 --- a/src/status_im/ui/screens/profile/contact/views.cljs +++ b/src/status_im/ui/screens/profile/contact/views.cljs @@ -90,6 +90,7 @@ {:container-style styles/action-container :action-style styles/action :action-label-style styles/action-label + :action-subtext-style styles/action-subtext :action-separator-style styles/action-separator :icon-opts styles/action-icon-opts}] [react/view {:style {:height 16}}] diff --git a/src/status_im/ui/screens/profile/tribute_to_talk/styles.cljs b/src/status_im/ui/screens/profile/tribute_to_talk/styles.cljs index 747881762e..f2c3a60dc6 100644 --- a/src/status_im/ui/screens/profile/tribute_to_talk/styles.cljs +++ b/src/status_im/ui/screens/profile/tribute_to_talk/styles.cljs @@ -224,19 +224,35 @@ {:background-color colors/blue-light :padding-horizontal 12 :padding-top 8 - :width 222 :margin-top 4 :border-radius 8}) (def pay-to-chat-container - {:justify-content :center + {:justify-content :flex-start :align-items :center + :flex-direction :row :height 44}) (def pay-to-chat-text {:typography :main-medium :color colors/blue}) +(defn payment-status-icon [pending?] + {:width 24 + :height 24 + :border-radius 12 + :justify-content :center + :align-items :center + :background-color (if pending? + (colors/alpha colors/black 0.1) + colors/green)}) + +(def payment-status-text + {:font-size 15 + :color colors/gray + :margin-left 6 + :line-height 22}) + (def edit-container {:justify-content :space-between :flex-grow 1}) diff --git a/src/status_im/ui/screens/profile/tribute_to_talk/views.cljs b/src/status_im/ui/screens/profile/tribute_to_talk/views.cljs index 3592fac142..8133420325 100644 --- a/src/status_im/ui/screens/profile/tribute_to_talk/views.cljs +++ b/src/status_im/ui/screens/profile/tribute_to_talk/views.cljs @@ -3,6 +3,7 @@ [re-frame.core :as re-frame] [status-im.i18n :as i18n] [status-im.react-native.resources :as resources] + [status-im.tribute-to-talk.core :as tribute-to-talk] [status-im.ui.components.colors :as colors] [status-im.ui.components.common.common :as components.common] [status-im.ui.components.icons.vector-icons :as icons] @@ -19,8 +20,7 @@ (defn steps-numbers [editing?] {:intro 1 :set-snt-amount (if editing? 1 2) - :personalized-message (if editing? 2 3) - :finish 3}) + :personalized-message (if editing? 2 3)}) (def step-forward-label {:intro :t/get-started @@ -58,10 +58,10 @@ (defn snt-amount-label [snt-amount fiat-value] [react/view {:style styles/snt-amount-container} - [react/text {:style styles/snt-amount-label - :number-of-lines 1 - :ellipsize-mode :middle} - [react/text {:style styles/snt-amount} (or snt-amount "0")] + [react/nested-text {:style styles/snt-amount-label + :number-of-lines 1 + :ellipsize-mode :middle} + [{:style styles/snt-amount} (or snt-amount "0")] " SNT"] [snt-asset-value fiat-value]]) @@ -112,10 +112,9 @@ [react/scroll-view {:content-container-style styles/personalized-message-container} [react/view {:style styles/personalized-message-title} - [react/text {:style {:text-align :center}} + [react/nested-text {:style {:text-align :center}} (i18n/label :t/personalized-message) - [react/text {:style styles/description-label} - (str " (" (i18n/label :t/optional) ")")]]] + [{:style styles/description-label} (str " (" (i18n/label :t/optional) ")")]]] [react/text-input (cond-> {:style (assoc styles/personalized-message-input :height 144 :align-self :stretch) @@ -129,19 +128,46 @@ (i18n/label :t/tribute-to-talk-you-can-leave-a-message)]]) (defn finish - [snt-amount] + [snt-amount state] [react/view {:style styles/intro-container} [react/view {:style {:flex 1 :min-height 32}}] [react/view {:style {:justify-content :center :align-items :center}} - [react/view {:style (styles/finish-circle (if snt-amount - colors/green-transparent-10 - colors/gray-lighter) 80)} + [react/view {:style (styles/finish-circle + (case state + :completed + colors/green-transparent-10 + :disabled + colors/gray-lighter + :pending + colors/gray-lighter + :signing + colors/gray-lighter + :transaction-failed + colors/red-transparent-10) + 80)} [react/view {:style styles/finish-circle-with-shadow} - [icons/icon :main-icons/check {:color (if snt-amount - colors/green - colors/gray)}]]]] + (if (#{:signing :pending} state) + [react/activity-indicator {:animating true + :size :large + :color colors/gray}] + [icons/icon (case state + :completed :main-icons/check + :disabled :main-icons/cancel + :transaction-failed :main-icons/warning) + {:width 48 :height 48 + :color (case state + :completed + colors/green + :disabled + colors/gray + :pending + colors/gray + :signing + colors/gray + :transaction-failed + colors/red)}])]]] [react/view {:style {:flex 1 :min-height 32}}] @@ -149,17 +175,35 @@ :align-items :center :margin-bottom 32}} [react/text {:style styles/finish-label} - (i18n/label (if snt-amount + (i18n/label (case state + :completed :t/you-are-all-set - :t/tribute-to-talk-disabled))] - (if snt-amount - [react/text {:style (assoc styles/description-label :margin-top 16)} + :disabled + :t/tribute-to-talk-disabled + :pending + :t/tribute-to-talk-pending + :signing + :t/tribute-to-talk-signing + :transaction-failed + :t/transaction-failed))] + (case state + :completed + [react/nested-text {:style (assoc styles/description-label :margin-top 16)} (i18n/label :t/tribute-to-talk-finish-desc) - [react/text {:style {:text-align :center}} - snt-amount] + [{:style {:color colors/black + :font-weight "600"}} snt-amount] " SNT"] + :disabled [react/text {:style (assoc styles/description-label :margin-top 16)} - (i18n/label :t/tribute-to-talk-disabled-note)])]]) + (i18n/label :t/tribute-to-talk-disabled-note)] + :pending + [react/text {:style (assoc styles/description-label :margin-top 16)} + (i18n/label :t/tribute-to-talk-pending-note)] + :signing + nil + :transaction-failed + [react/text {:style (assoc styles/description-label :margin-top 16)} + (i18n/label :t/tribute-to-talk-transaction-failed-note)])]]) (defn enabled-note [] @@ -185,10 +229,10 @@ [react/view {:style {:margin-left 16 :justify-content :flex-start}} [react/view {:style {:justify-content :center :align-items :center}} - [react/text {:style styles/current-snt-amount} + [react/nested-text {:style styles/current-snt-amount} snt-amount - [react/text {:style (assoc styles/current-snt-amount - :color colors/gray)} " SNT"]]] + [{:style (assoc styles/current-snt-amount :color colors/gray)} + " SNT"]]] [snt-asset-value fiat-value]]] [react/view {:flex 1}] [react/text {:on-press #(re-frame/dispatch @@ -221,8 +265,9 @@ :min-height 24}] [enabled-note]]) -(defn chat-sample [] - [react/view {:style (assoc styles/learn-more-section :margin-top 24)} +(defn pay-to-chat-message [{:keys [snt-amount fiat-amount fiat-currency + personalized-message style public-key tribute-status]}] + [react/view {:style style} [react/view {:style {:flex-direction :row :align-items :center}} [react/view {:style {:background-color colors/white @@ -232,50 +277,79 @@ :font-size 13 :margin-left 4}} (i18n/label :t/tribute-to-talk)]] + (when-not (string/blank? personalized-message) + [react/view {:style styles/chat-sample-bubble} + [react/text (i18n/label :t/tribute-to-talk-sample-text)]]) [react/view {:style styles/chat-sample-bubble} - [react/text (i18n/label :t/tribute-to-talk-sample-text)]] - [react/view {:style (assoc styles/chat-sample-bubble :width 141)} ;;TODO replace hardcoded values - [react/text {:style {:font-size 22}} "1000" - [react/text {:style {:font-size 22 :color colors/gray}} " SNT"]] - [react/text {:style {:font-size 12}} - "~3.48" - [react/text {:style {:font-size 12 :color colors/gray}} " USD"]] + [react/nested-text {:style {:font-size 22}} + (str snt-amount) + [{:style {:font-size 22 :color colors/gray}} " SNT"]] + [react/nested-text + {:style {:font-size 12}} + (str "~" fiat-amount) + [{:style {:font-size 12 :color colors/gray}} (str " " fiat-currency)]] [react/view {:style styles/pay-to-chat-container} - [react/text {:style styles/pay-to-chat-text} - (i18n/label :t/pay-to-chat)]]]]) + (if (or (nil? public-key) (= tribute-status :required)) + [react/text (cond-> {:style styles/pay-to-chat-text} + public-key + (assoc :on-press #(re-frame/dispatch [:tribute-to-talk.ui/on-pay-to-chat-pressed + public-key]))) + (i18n/label :t/pay-to-chat)] + [react/view {:style {:flex-direction :row}} + [react/view {:style (styles/payment-status-icon (= tribute-status :pending))} + [icons/icon (if (= tribute-status :pending) :tiny-icons/tiny-pending :tiny-icons/tiny-check) + {:color (if (= tribute-status :pending) colors/black colors/white)}]] + [react/text {:style styles/payment-status-text} + nil]])]]]) -(defn learn-more [] - [react/scroll-view {:content-container-style styles/learn-more-container} - [react/image {:source (:tribute-to-talk resources/ui) - :style styles/learn-more-image}] - [react/text {:style styles/learn-more-title-text} - (i18n/label :t/tribute-to-talk)] - [react/view {:style styles/learn-more-text-container-1} - [react/text {:style styles/learn-more-text} - (i18n/label :t/tribute-to-talk-learn-more-1)]] - [separator] - [chat-sample] - [react/view {:style styles/learn-more-text-container-2} - [react/text {:style styles/learn-more-text} - (i18n/label :t/tribute-to-talk-learn-more-2)]] - [react/view {:style (assoc styles/learn-more-section - :flex-direction :row - :align-item :flex-stretch - :padding-horizontal 16 - :padding-vertical 12)} - [react/view {:style (styles/icon-view colors/blue-light)} - [icons/icon :main-icons/add-contact {:color colors/blue}]] - [react/view {:style {:margin-left 16 :justify-content :center}} - [react/text {:style (assoc styles/learn-more-text :color colors/blue)} - (i18n/label :t/add-to-contacts)]]] - [react/view {:style styles/learn-more-text-container-2} - [react/text {:style styles/learn-more-text} - (i18n/label :t/tribute-to-talk-learn-more-3)]]]) +(defn learn-more [owner?] + [react/view {:flex 1} + (when-not owner? + [toolbar/toolbar nil toolbar/default-nav-close + [react/view + [react/text {:style styles/tribute-to-talk} + (i18n/label :t/tribute-to-talk)] + [react/text {:style styles/step-n} + (i18n/label :t/learn-more)]]]) + [react/scroll-view {:content-container-style styles/learn-more-container} + [react/image {:source (:tribute-to-talk resources/ui) + :style styles/learn-more-image}] + [react/text {:style styles/learn-more-title-text} + (i18n/label :t/tribute-to-talk)] + [react/view {:style styles/learn-more-text-container-1} + [react/text {:style styles/learn-more-text} + (i18n/label (if owner? :t/tribute-to-talk-learn-more-1 + :t/tribute-to-talk-paywall-learn-more-1))]] + [separator] + [pay-to-chat-message {:snt-amount 1000 + :fiat-amount 3.48 + :fiat-currency (i18n/label :t/usd-currency) + :personalized-message (i18n/label :t/tribute-to-talk-sample-text) + :style (assoc styles/learn-more-section :margin-top 24)}] + [react/view {:style styles/learn-more-text-container-2} + [react/text {:style styles/learn-more-text} + (i18n/label (if owner? :t/tribute-to-talk-learn-more-2 + :t/tribute-to-talk-paywall-learn-more-2))]] + [react/view {:style (assoc styles/learn-more-section + :flex-direction :row + :align-item :flex-stretch + :padding-horizontal 16 + :padding-vertical 12)} + [react/view {:style (styles/icon-view colors/blue-light)} + [icons/icon :main-icons/add-contact {:color colors/blue}]] + [react/view {:style {:margin-left 16 :justify-content :center}} + [react/text {:style (assoc styles/learn-more-text :color colors/blue)} + (i18n/label (if owner? :t/add-to-contacts :t/share-profile))]]] + [react/view {:style styles/learn-more-text-container-2} + [react/text {:style styles/learn-more-text} + (i18n/label (if owner? :t/tribute-to-talk-learn-more-3 + :t/tribute-to-talk-paywall-learn-more-3))]]]]) (defview tribute-to-talk [] (letsubs [current-account [:account/account] - {:keys [step snt-amount editing? message fiat-value disabled?]} + {:keys [step snt-amount editing? message + fiat-value disable-button? state]} [:tribute-to-talk/ui]] [react/keyboard-avoiding-view {:style styles/container} [react/safe-area-view {:style {:flex 1}} @@ -292,7 +366,12 @@ (when-not (#{:edit :learn-more} step) [react/text {:style styles/step-n} (if (= step :finish) - (i18n/label (if snt-amount :t/completed :t/disabled)) + (i18n/label (case state + :completed :t/completed + :pending :t/pending + :signing :t/signing + :transaction-failed :t/transaction-failed + :disabled :t/disabled)) (i18n/label :t/step-i-of-n {:step ((steps-numbers editing?) step) :number (if editing? 2 3)}))]) (when (= step :learn-more) @@ -303,15 +382,15 @@ :intro [intro] :set-snt-amount [set-snt-amount snt-amount] :edit [edit snt-amount message fiat-value] - :learn-more [learn-more] + :learn-more [learn-more step] :personalized-message [personalized-message message] - :finish [finish snt-amount]) + :finish [finish snt-amount state]) (when-not (#{:learn-more :edit} step) [react/view {:style styles/bottom-toolbar} [components.common/button {:button-style styles/intro-button - :disabled? disabled? - :label-style (when disabled? {:color colors/gray}) + :disabled? disable-button? + :label-style (when disable-button? {:color colors/gray}) :on-press #(re-frame/dispatch [:tribute-to-talk.ui/step-forward-pressed]) :label (i18n/label (step-forward-label step))}]])]])) diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index ad34e747ad..8ce1ae7a5c 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -1,33 +1,30 @@ (ns status-im.ui.screens.profile.user.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [re-frame.core :as re-frame] + (:require [clojure.string :as string] + [re-frame.core :as re-frame] [reagent.core :as reagent] - [status-im.ui.components.list.views :as list.views] [status-im.i18n :as i18n] - [status-im.ui.components.action-button.styles :as action-button.styles] [status-im.ui.components.button.view :as button] [status-im.ui.components.colors :as colors] - [status-im.ui.components.common.styles :as common.styles] - [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.components.icons.vector-icons :as icons] [status-im.ui.components.list-selection :as list-selection] + [status-im.ui.components.list.views :as list.views] [status-im.ui.components.qr-code-viewer.views :as qr-code-viewer] [status-im.ui.components.react :as react] [status-im.ui.components.status-bar.view :as status-bar] - [status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.toolbar.actions :as toolbar.actions] - [status-im.ui.components.toolbar.styles :as toolbar.styles] + [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.screens.profile.components.styles + :as + profile.components.styles] [status-im.ui.screens.profile.components.views :as profile.components] - [status-im.ui.screens.profile.components.styles :as profile.components.styles] [status-im.ui.screens.profile.user.styles :as styles] - [status-im.utils.build :as build] [status-im.utils.config :as config] - [status-im.utils.platform :as platform] - [status-im.utils.utils :as utils] - [status-im.ui.components.icons.vector-icons :as icons] - [status-im.ui.components.common.common :as components.common] [status-im.utils.identicon :as identicon] - [clojure.string :as string] - [status-im.utils.universal-links.core :as universal-links])) + [status-im.utils.platform :as platform] + [status-im.utils.universal-links.core :as universal-links] + [status-im.utils.utils :as utils]) + (:require-macros [status-im.utils.views :refer [defview letsubs]])) (defn my-profile-toolbar [] [toolbar/toolbar @@ -277,18 +274,36 @@ :accessory-value active-contacts-count :action-fn #(re-frame/dispatch [:navigate-to :contacts-list])}]) -(defn tribute-to-talk-item [snt-amount seen?] +(defn tribute-to-talk-item [state snt-amount seen?] [list.views/big-list-item (cond-> {:text (i18n/label :t/tribute-to-talk) - :icon :main-icons/tribute-to-talk :accessibility-label :notifications-button :new? (not seen?) :action-fn #(re-frame/dispatch [:tribute-to-talk.ui/menu-item-pressed])} - snt-amount - (assoc :accessory-value (str snt-amount " SNT")) - (not (and seen? snt-amount)) - (assoc :subtext (i18n/label :t/tribute-to-talk-desc)))]) + (and (not (and seen? + snt-amount + (#{:signing :pending :transaction-failed} state)))) + (assoc :subtext (i18n/label :t/tribute-to-talk-desc)) + + (#{:signing :pending} state) + (assoc :activity-indicator {:animating true + :color colors/blue} + :subtext (case state + :pending (i18n/label :t/pending-confirmation) + :signing (i18n/label :t/waiting-to-sign))) + + (= state :transaction-failed) + (assoc :icon :main-icons/warning + :icon-color colors/red + :subtext (i18n/label :t/transaction-failed)) + + (not (#{:signing :pending :transaction-failed} state)) + (assoc :icon :main-icons/tribute-to-talk) + + (and (= state :completed) + (not-empty snt-amount)) + (assoc :accessory-value (str snt-amount " SNT")))]) (defview extensions-settings [] (letsubs [{:keys [label view on-close]} [:get-screen-params :my-profile-ext-settings]] @@ -308,7 +323,8 @@ scroll (reagent/atom nil) active-contacts-count [:contacts/active-count] {tribute-to-talk-seen? :seen? - snt-amount :snt-amount} [:tribute-to-talk/settings]] + snt-amount :snt-amount + tribute-to-talk-state :state} [:tribute-to-talk/ui]] (let [shown-account (merge current-account changed-account) ;; We scroll on the component once rendered. setTimeout is necessary, ;; likely to allow the animation to finish. @@ -342,7 +358,10 @@ [share-profile-item (dissoc current-account :mnemonic)] [contacts-list-item active-contacts-count] (when config/tr-to-talk-enabled? - [tribute-to-talk-item snt-amount tribute-to-talk-seen?]) + [tribute-to-talk-item + tribute-to-talk-state + snt-amount + tribute-to-talk-seen?]) [my-profile-settings current-account shown-account currency (nil? login-data) extensions] (when (nil? login-data) [advanced shown-account on-show-advanced])]]]))) diff --git a/src/status_im/ui/screens/routing/modals.cljs b/src/status_im/ui/screens/routing/modals.cljs index 79025ace4a..ba50b80ccd 100644 --- a/src/status_im/ui/screens/routing/modals.cljs +++ b/src/status_im/ui/screens/routing/modals.cljs @@ -19,6 +19,7 @@ :chat-modal :show-extension-modal :stickers-pack-modal + :tribute-learn-more :wallet-sign-message-modal :selection-modal-screen :wallet-settings-assets diff --git a/src/status_im/ui/screens/routing/screens.cljs b/src/status_im/ui/screens/routing/screens.cljs index 153b781ed5..b835c38c1e 100644 --- a/src/status_im/ui/screens/routing/screens.cljs +++ b/src/status_im/ui/screens/routing/screens.cljs @@ -1,63 +1,82 @@ (ns status-im.ui.screens.routing.screens - (:require - [status-im.ui.screens.accounts.login.views :as login] - [status-im.ui.screens.accounts.recover.views :as recover] - [status-im.ui.screens.accounts.views :as accounts] - [status-im.ui.screens.progress.views :as progress] - [status-im.ui.screens.chat.views :as chat] - [status-im.ui.screens.add-new.views :as add-new] - [status-im.ui.screens.add-new.new-chat.views :as new-chat] - [status-im.ui.screens.add-new.new-public-chat.view :as new-public-chat] - [status-im.ui.screens.qr-scanner.views :as qr-scanner] - [status-im.ui.screens.group.views :as group] - [status-im.ui.screens.profile.user.views :as profile.user] - [status-im.ui.screens.profile.contact.views :as profile.contact] - [status-im.ui.screens.profile.group-chat.views :as profile.group-chat] - [status-im.ui.screens.profile.photo-capture.views :as photo-capture] - [status-im.extensions.capacities.camera.views :as extensions.camera.views] - [status-im.ui.screens.wallet.main.views :as wallet.main] - [status-im.ui.screens.wallet.collectibles.views :as collectibles] - [status-im.ui.screens.wallet.send.views :as send] - [status-im.ui.screens.wallet.sign-message.views :as sign-message] - [status-im.ui.screens.wallet.request.views :as request] - [status-im.ui.screens.wallet.components.views :as wallet.components] - [status-im.ui.screens.wallet.onboarding.views :as wallet.onboarding] - [status-im.ui.screens.wallet.transaction-fee.views :as wallet.transaction-fee] - [status-im.ui.screens.wallet.settings.views :as wallet-settings] - [status-im.ui.screens.wallet.transactions.views :as wallet-transactions] - [status-im.ui.screens.wallet.transaction-sent.views :as transaction-sent] - [status-im.ui.screens.contacts-list.views :as contacts-list] - [status-im.ui.screens.network-settings.views :as network-settings] - [status-im.ui.screens.network-settings.network-details.views :as network-details] - [status-im.ui.screens.network-settings.edit-network.views :as edit-network] - [status-im.ui.screens.extensions.views :as screens.extensions] - [status-im.ui.screens.log-level-settings.views :as log-level-settings] - [status-im.ui.screens.fleet-settings.views :as fleet-settings] - [status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings] - [status-im.ui.screens.offline-messaging-settings.edit-mailserver.views :as edit-mailserver] - [status-im.ui.screens.extensions.add.views :as extensions.add] - [status-im.ui.screens.bootnodes-settings.views :as bootnodes-settings] - [status-im.ui.screens.pairing.views :as pairing] - [status-im.ui.screens.bootnodes-settings.edit-bootnode.views :as edit-bootnode] - [status-im.ui.screens.currency-settings.views :as currency-settings] - [status-im.ui.screens.hardwallet.settings.views :as hardwallet.settings] - [status-im.ui.screens.help-center.views :as help-center] - [status-im.ui.screens.browser.views :as browser] - [status-im.ui.screens.browser.open-dapp.views :as open-dapp] - [status-im.ui.screens.intro.views :as intro] - [status-im.ui.screens.accounts.create.views :as accounts.create] - [status-im.ui.screens.hardwallet.authentication-method.views :as hardwallet.authentication] - [status-im.ui.screens.hardwallet.connect.views :as hardwallet.connect] - [status-im.ui.screens.hardwallet.pin.views :as hardwallet.pin] - [status-im.ui.screens.hardwallet.setup.views :as hardwallet.setup] - [status-im.ui.screens.hardwallet.success.views :as hardwallet.success] - [status-im.ui.screens.profile.seed.views :as profile.seed] - [status-im.ui.screens.profile.tribute-to-talk.views :as tr-to-talk] - [status-im.ui.screens.about-app.views :as about-app] - [status-im.ui.screens.stickers.views :as stickers] - [status-im.ui.screens.dapps-permissions.views :as dapps-permissions] - [status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings] - [status-im.ui.screens.home.views :as home])) + (:require [status-im.extensions.capacities.camera.views + :as + extensions.camera.views] + [status-im.ui.screens.about-app.views :as about-app] + [status-im.ui.screens.accounts.create.views :as accounts.create] + [status-im.ui.screens.accounts.login.views :as login] + [status-im.ui.screens.accounts.recover.views :as recover] + [status-im.ui.screens.accounts.views :as accounts] + [status-im.ui.screens.add-new.new-chat.views :as new-chat] + [status-im.ui.screens.add-new.new-public-chat.view :as new-public-chat] + [status-im.ui.screens.add-new.views :as add-new] + [status-im.ui.screens.bootnodes-settings.edit-bootnode.views + :as + edit-bootnode] + [status-im.ui.screens.bootnodes-settings.views :as bootnodes-settings] + [status-im.ui.screens.browser.open-dapp.views :as open-dapp] + [status-im.ui.screens.browser.views :as browser] + [status-im.ui.screens.chat.views :as chat] + [status-im.ui.screens.contacts-list.views :as contacts-list] + [status-im.ui.screens.currency-settings.views :as currency-settings] + [status-im.ui.screens.dapps-permissions.views :as dapps-permissions] + [status-im.ui.screens.extensions.add.views :as extensions.add] + [status-im.ui.screens.extensions.views :as screens.extensions] + [status-im.ui.screens.fleet-settings.views :as fleet-settings] + [status-im.ui.screens.group.views :as group] + [status-im.ui.screens.hardwallet.authentication-method.views + :as + hardwallet.authentication] + [status-im.ui.screens.hardwallet.connect.views :as hardwallet.connect] + [status-im.ui.screens.hardwallet.pin.views :as hardwallet.pin] + [status-im.ui.screens.hardwallet.settings.views :as hardwallet.settings] + [status-im.ui.screens.hardwallet.setup.views :as hardwallet.setup] + [status-im.ui.screens.hardwallet.success.views :as hardwallet.success] + [status-im.ui.screens.help-center.views :as help-center] + [status-im.ui.screens.home.views :as home] + [status-im.ui.screens.intro.views :as intro] + [status-im.ui.screens.log-level-settings.views :as log-level-settings] + [status-im.ui.screens.mobile-network-settings.view + :as + mobile-network-settings] + [status-im.ui.screens.network-settings.edit-network.views + :as + edit-network] + [status-im.ui.screens.network-settings.network-details.views + :as + network-details] + [status-im.ui.screens.network-settings.views :as network-settings] + [status-im.ui.screens.offline-messaging-settings.edit-mailserver.views + :as + edit-mailserver] + [status-im.ui.screens.offline-messaging-settings.views + :as + offline-messaging-settings] + [status-im.ui.screens.pairing.views :as pairing] + [status-im.ui.screens.profile.contact.views :as profile.contact] + [status-im.ui.screens.profile.group-chat.views :as profile.group-chat] + [status-im.ui.screens.profile.photo-capture.views :as photo-capture] + [status-im.ui.screens.profile.seed.views :as profile.seed] + [status-im.ui.screens.profile.tribute-to-talk.views :as tr-to-talk] + [status-im.ui.screens.profile.user.views :as profile.user] + [status-im.ui.screens.progress.views :as progress] + [status-im.ui.screens.qr-scanner.views :as qr-scanner] + [status-im.ui.screens.stickers.views :as stickers] + [status-im.ui.screens.wallet.collectibles.views :as collectibles] + [status-im.ui.screens.wallet.components.views :as wallet.components] + [status-im.ui.screens.wallet.main.views :as wallet.main] + [status-im.ui.screens.wallet.onboarding.views :as wallet.onboarding] + [status-im.ui.screens.wallet.request.views :as request] + [status-im.ui.screens.wallet.send.views :as send] + [status-im.ui.screens.wallet.settings.views :as wallet-settings] + [status-im.ui.screens.wallet.sign-message.views :as sign-message] + [status-im.ui.screens.wallet.transaction-fee.views + :as + wallet.transaction-fee] + [status-im.ui.screens.wallet.transaction-sent.views + :as + transaction-sent] + [status-im.ui.screens.wallet.transactions.views :as wallet-transactions])) (def all-screens {:login login/login @@ -89,6 +108,7 @@ :stickers stickers/packs :stickers-pack stickers/pack :stickers-pack-modal [:modal stickers/pack-modal] + :tribute-learn-more [:modal tr-to-talk/learn-more] :chat-modal [:modal chat/chat-modal] :show-extension-modal [:modal extensions.add/show-extension-modal] :wallet-send-transaction-modal [:modal send/send-transaction-modal] diff --git a/src/status_im/utils/ethereum/contracts.cljs b/src/status_im/utils/ethereum/contracts.cljs index 200f70a10f..51003e7037 100644 --- a/src/status_im/utils/ethereum/contracts.cljs +++ b/src/status_im/utils/ethereum/contracts.cljs @@ -7,7 +7,16 @@ [status-im.utils.money :as money])) (def contracts - {:status/tribute-to-talk + {:status/snt + {:address + {:mainnet "0x744d70fdbe2ba4cf95131626614a1763df805b9e" + :testnet "0xc55cf4b03948d7ebc8b9e8bad92643703811d162" + :rinkeby nil} + :methods + {:erc20/transfer + {:signature "transfer(address,uint256)" + :write? true}}} + :status/tribute-to-talk {:address {:mainnet nil :testnet "0x3da3fc53e24707f36c5b4433b442e896c4955f0e" @@ -40,7 +49,8 @@ callback))) (fx/defn call - [{:keys [db] :as cofx} {:keys [contract method params callback on-result on-error details]}] + [{:keys [db] :as cofx} + {:keys [contract method params callback on-result on-error details]}] (let [chain-keyword (-> (get-in db [:account/account :networks (:network db)]) ethereum/network->chain-keyword) contract-address (get-in contracts [contract :address chain-keyword])] diff --git a/test/appium/views/profile_view.py b/test/appium/views/profile_view.py index 73dd1ab401..9b8e2f6a44 100644 --- a/test/appium/views/profile_view.py +++ b/test/appium/views/profile_view.py @@ -225,7 +225,7 @@ class OkGotItButton(BaseButton): def __init__(self, driver): super(OkGotItButton, self).__init__(driver) - self.locator = self.Locator.text_selector('Ok, got it') + self.locator = self.Locator.text_selector('OK, got it') class DebugModeToggle(BaseButton): diff --git a/translations/en.json b/translations/en.json index d290e1da1a..f25ad4cd8f 100644 --- a/translations/en.json +++ b/translations/en.json @@ -480,7 +480,7 @@ "dapp": "ÐApp", "mainnet-text": "You’re on the Mainnet. Real ETH will be sent", "receive": "Receive", - "ok-got-it": "Ok, got it", + "ok-got-it": "OK, got it", "ok": "OK", "main-currency": "Main currency", "ens-names": "ENS names", @@ -918,23 +918,43 @@ "tribute-to-talk-set-snt-amount": "Set the amount of SNT required for new people to start a chat", "personalized-message": "Personalized message", "optional": "optional", + "pending-confirmation": "Pending confirmation...", + "waiting-to-sign": "Waiting to sign transaction...", "tribute-to-talk-message-placeholder": "Hi there, I ask you to pay tribute to start a chat with me. If you know me in real life, you know how to find me...", "tribute-to-talk-you-can-leave-a-message": "You can leave a message for people to see when they want to start a chat with you.", "tribute-to-talk-sign-and-set-tribute": "Sign and set tribute", "tribute-to-talk-finish-desc": "From now on, you will only receive chats from contacts, and people who paid ", "tribute-to-talk-you-require-snt": "You require SNT for new people to start a chat.", + "tribute-to-talk-signing": "Waiting to sign transaction", + "tribute-to-talk-pending": "Tribute pending confirmation", + "tribute-to-talk-pending-note": "Tribute transaction is pending confirmation on the network. You can check its status in transaction history", + "tribute-to-talk-transaction-failed-note": "Transaction has failed and your Tribute to Talk settings have not been changed", "tribute-to-talk-removing-note": "Removing Tribute to Talk will allow new people to start a chat without sending SNT. Requires a transaction to be made.", "tribute-to-talk-enabled": "You have Tribute to Talk enabled.", "tribute-to-talk-add-friends": "Add friends as a contact to allow chats without tribute payment.", + "signing": "Signing", + "learn-more": "Learn more", + "loading": "Loading...", "tribute-to-talk-learn-more-1": "Your time and attention are your most valuable assets. Tribute to Talk lets you set an amount of SNT required for new people to start a chat with you.", "tribute-to-talk-learn-more-2": "Anyone who is not in your contact list will be asked to pay, and you can respond once they have.", "tribute-to-talk-learn-more-3": "You can always send the money back, but to ensure that friends can reach you freely, add them as a contact first.", "tribute-to-talk-sample-text": "Hi I’m Carmen. Message me to have your fortune told 🔮", "tribute-to-talk-disabled": "Tribute to Talk disabled", "tribute-to-talk-disabled-note": "From now on, new people can start a chat with you without sending SNT.", + "tribute-state-required": "Requires {{snt-amount}} SNT tribute", + "tribute-state-pending": "Tribute pending", + "tribute-state-paid": "Tribute paid", + "tribute-required-by-account": "{{account-name}} requires SNT to start a chat.", + "tribute-to-talk-are-you-friends": "Are you friends?", + "tribute-to-talk-ask-to-be-added": "Ask to be added as a contact", + "tribute-to-talk-paywall-learn-more-1": "Our time and attention are our most valuable assets. Tribute to Talk lets you contact new people in exchange for an SNT payment.", + "tribute-to-talk-paywall-learn-more-2": "To start a chat with someone who has a tribute set, simply pay the required SNT and you will be added as a contact.", + "tribute-to-talk-paywall-learn-more-3": "If you know them, you can share your profile outside of Status to be added for free.", + "tribute-to-talk-contact-received-your-tribute": " received your tribute. You are now contacts and can securely chat with each other.", "pay-to-chat": "Pay to chat", "share-chat": "Share chat", "share-link": "Share link", + "share-profile": "Share profile", "share-profile-link": "Share profile link", "add-contact": "Add contact", "blocked-users": "Blocked users",