diff --git a/resources/images/ui/tribute-to-talk.png b/resources/images/ui/tribute-to-talk.png new file mode 100644 index 0000000000..9a6bea6b1f Binary files /dev/null and b/resources/images/ui/tribute-to-talk.png differ diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 5d78f8226e..e237223037 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -39,6 +39,7 @@ [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] @@ -1729,3 +1730,44 @@ :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 + (fn [cofx _] + (tribute-to-talk/open-settings cofx))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/learn-more-pressed + (fn [cofx _] + (tribute-to-talk/open-learn-more cofx))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/step-back-pressed + (fn [cofx _] + (tribute-to-talk/step-back cofx))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/step-forward-pressed + (fn [cofx _] + (tribute-to-talk/step-forward cofx))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/numpad-key-pressed + (fn [cofx [_ numpad-key]] + (tribute-to-talk/update-snt-amount cofx numpad-key))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/message-changed + (fn [cofx [_ message]] + (tribute-to-talk/update-message cofx message))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/edit-pressed + (fn [cofx _] + (tribute-to-talk/start-editing cofx))) + +(handlers/register-handler-fx + :tribute-to-talk.ui/remove-pressed + (fn [cofx _] + (tribute-to-talk/remove cofx))) diff --git a/src/status_im/react_native/resources.cljs b/src/status_im/react_native/resources.cljs index b14399f642..9badca7285 100644 --- a/src/status_im/react_native/resources.cljs +++ b/src/status_im/react_native/resources.cljs @@ -65,6 +65,7 @@ :lock {:image (js/require "./resources/images/ui/lock.png") :width 993 :height 933} + :tribute-to-talk (js/require "./resources/images/ui/tribute-to-talk.png") :wallet-welcome (js/require "./resources/images/ui/wallet-welcome.png") :hardwallet-card (js/require "./resources/images/ui/hardwallet-card.png") :secret-keys (js/require "./resources/images/ui/secret-keys.png") diff --git a/src/status_im/tribute_to_talk/core.cljs b/src/status_im/tribute_to_talk/core.cljs new file mode 100644 index 0000000000..9627aba11f --- /dev/null +++ b/src/status_im/tribute_to_talk/core.cljs @@ -0,0 +1,129 @@ +(ns status-im.tribute-to-talk.core + (:refer-clojure :exclude [remove]) + (:require [clojure.string :as string] + [status-im.accounts.update.core :as accounts.update] + [status-im.ui.screens.navigation :as navigation] + [status-im.utils.fx :as fx])) + +(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) {}))))) + +(fx/defn open-settings + [{:keys [db] :as cofx}] + (let [snt-amount (get-in db [:account/account :settings :tribute-to-talk :snt-amount])] + (fx/merge cofx + mark-ttt-as-seen + (navigation/navigate-to-cofx :tribute-to-talk + (if snt-amount + {:step :edit + :editing? true} + {:step :intro}))))) + +(fx/defn set-step + [{:keys [db]} step] + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk :step] step)}) + +(fx/defn open-learn-more + [cofx] + (set-step cofx :learn-more)) + +(fx/defn step-back + [cofx] + (let [{:keys [step editing?]} + (get-in cofx [:db :navigation/screen-params :tribute-to-talk])] + (case step + (:intro :edit) + (navigation/navigate-back cofx) + + (:learn-more :set-snt-amount) + (set-step cofx (if editing? + :edit + :intro)) + + :personalized-message + (set-step cofx :set-snt-amount) + + :finish + (set-step cofx :personalized-message)))) + +(fx/defn step-forward + [cofx] + (let [{:keys [step editing?]} + (get-in cofx [:db :navigation/screen-params :tribute-to-talk])] + (case step + :intro + (set-step cofx :set-snt-amount) + + :set-snt-amount + (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 + {}))) + + :finish + (navigation/navigate-back cofx)))) + +(defn get-new-snt-amount + [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")] + (if (= numpad-symbol :remove) + (let [len (count snt-amount) + s (subs snt-amount 0 (dec len))] + (cond-> s + ;; Remove both the digit after the dot and the dot itself + (string/ends-with? s ".") (subs 0 (- len 2)) + ;; Set default value if last digit is removed + (string/blank? s) (do "0"))) + (cond + ;; Disallow two consecutive dots + (and (string/includes? snt-amount ".") (= numpad-symbol ".")) + snt-amount + ;; Disallow more than 2 digits after the dot + (and (string/includes? snt-amount ".") + (> (count (second (string/split snt-amount #"\."))) 1)) + snt-amount + ;; Replace initial "0" by the first digit + (and (= snt-amount "0") (not= numpad-symbol ".")) + (str numpad-symbol) + :else (str snt-amount numpad-symbol))))) + +(fx/defn update-snt-amount + [{:keys [db]} numpad-symbol] + {:db (update-in db [:account/account :settings :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] + message)}) + +(fx/defn start-editing + [{:keys [db]}] + {:db (assoc-in db [:navigation/screen-params :tribute-to-talk] + {:step :set-snt-amount + :editing? true})}) + +(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})} + (accounts.update/update-settings + (assoc account-settings :tribute-to-talk {:seen? true}) {})))) diff --git a/src/status_im/tribute_to_talk/subs.cljs b/src/status_im/tribute_to_talk/subs.cljs new file mode 100644 index 0000000000..fe622abc75 --- /dev/null +++ b/src/status_im/tribute_to_talk/subs.cljs @@ -0,0 +1,40 @@ +(ns status-im.tribute-to-talk.subs + (:require [clojure.string :as string] + [re-frame.core :as re-frame] + [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]))) + +(re-frame/reg-sub + :tribute-to-talk/screen-params + (fn [db] + (get-in db [:navigation/screen-params :tribute-to-talk]))) + +(re-frame/reg-sub + :tribute-to-talk/ui + :<- [:tribute-to-talk/settings] + :<- [:tribute-to-talk/screen-params] + :<- [:prices] + :<- [:wallet/currency] + (fn [[{:keys [snt-amount message]} + {:keys [step editing?] :or {step :intro}} + 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))}))) diff --git a/src/status_im/ui/components/common/common.cljs b/src/status_im/ui/components/common/common.cljs index dae2f9fd9a..2c4b24a51e 100644 --- a/src/status_im/ui/components/common/common.cljs +++ b/src/status_im/ui/components/common/common.cljs @@ -85,9 +85,10 @@ (when forward? [vector-icons/icon :main-icons/next {:color colors/blue}])]]) -(defn button [{:keys [on-press label background? uppercase? button-style label-style] :or {background? true uppercase? true}}] - [react/touchable-highlight {:on-press on-press} - [react/view {:style (styles/button button-style background?)} +(defn button [{:keys [on-press label background? uppercase? button-style label-style disabled?] :or {background? true uppercase? true disabled false}}] + [react/touchable-highlight {:on-press on-press + :disabled disabled?} + [react/view {:style (styles/button button-style background? disabled?)} [react/text {:uppercase? uppercase? :style (merge styles/button-label label-style)} label]]]) diff --git a/src/status_im/ui/components/common/styles.cljs b/src/status_im/ui/components/common/styles.cljs index fc9738204a..95bf754363 100644 --- a/src/status_im/ui/components/common/styles.cljs +++ b/src/status_im/ui/components/common/styles.cljs @@ -130,13 +130,15 @@ :letter-spacing -0.2 :color colors/blue}) -(defn button [style background?] +(defn button [style background? disabled?] (merge {:padding-vertical 12 :padding-horizontal 42 :border-radius 8 - :background-color (when background? - (colors/alpha colors/blue 0.1))} + :background-color (cond disabled? + colors/gray-lighter + background? + (colors/alpha colors/blue 0.1))} style)) (def button-label diff --git a/src/status_im/ui/components/icons/vector_icons.cljs b/src/status_im/ui/components/icons/vector_icons.cljs index e7dad7fdbf..b913e47bd2 100644 --- a/src/status_im/ui/components/icons/vector_icons.cljs +++ b/src/status_im/ui/components/icons/vector_icons.cljs @@ -272,3 +272,4 @@ ([name options] (let [icon-fn (if platform/desktop? desktop-icon mobile-icon)] [icon-fn name options]))) + diff --git a/src/status_im/ui/components/list/styles.cljs b/src/status_im/ui/components/list/styles.cljs index 2676090fa1..8afa4f929a 100644 --- a/src/status_im/ui/components/list/styles.cljs +++ b/src/status_im/ui/components/list/styles.cljs @@ -76,30 +76,59 @@ (def settings-item-separator {:margin-left 16}) -(def settings-item - {:padding-left 16 - :padding-right 8 +(defn settings-item + [large?] + {:padding-left 16 + :padding-right 8 :flex 1 :flex-direction :row :align-items :center :background-color colors/white - :height 64}) + :height (if large? 82 52)}) -(defn settings-item-icon [icon-color] - {:background-color (colors/alpha icon-color 0.1) - :width 40 - :height 40 - :border-radius 40 - :margin-right 16 - :justify-content :center - :align-items :center}) +(defn settings-item-icon + [icon-color large?] + (cond-> {:background-color (colors/alpha icon-color 0.1) + :width 40 + :height 40 + :border-radius 40 + :margin-right 16 + :justify-content :center + :align-items :center} + large? + (merge {:align-self :flex-start + :margin-top 12}))) (defn settings-item-text [color] - {:flex 1 - :flex-wrap :nowrap - :font-size 17 - :color color}) + {:flex 1 + :flex-wrap :nowrap + :line-height 20 + :font-size 17 + :color color}) + +(def settings-item-text-container + {:flex 1 + :align-self :flex-start + :margin-top 12}) + +(def settings-item-main-text-container + {:flex-direction :row + :height 18 + :align-items :center}) + +(defn settings-item-text-new + [color] + (assoc (settings-item-text color) + :font-weight "500" + :line-height 22 + :font-size 15)) + +(def settings-item-subtext + {:line-height 22 + :font-size 15 + :margin-top 2 + :color colors/gray}) (def settings-item-value {:flex-wrap :nowrap @@ -108,6 +137,22 @@ :font-size 15 :color colors/gray}) +(def new-label + {:background-color colors/blue + :border-radius 4 + :justify-content :center + :align-items :center + :height 16 + :margin-right 6}) + +(def new-label-text + {:color colors/white + :margin-left 6 + :margin-right 4 + :font-size 11 + :letter-spacing 1 + :font-weight :bold}) + (def base-separator {:height 1 :background-color colors/gray-light}) diff --git a/src/status_im/ui/components/list/views.cljs b/src/status_im/ui/components/list/views.cljs index 124ab6a769..7af943077f 100644 --- a/src/status_im/ui/components/list/views.cljs +++ b/src/status_im/ui/components/list/views.cljs @@ -107,8 +107,8 @@ :icon-opts {:color colors/white}}]) (defn big-list-item - [{:keys [text text-color value action-fn active? destructive? hide-chevron? - accessory-value text-color + [{:keys [text text-color subtext value action-fn active? destructive? hide-chevron? + accessory-value text-color new? accessibility-label icon icon-color image-source icon-content] :or {icon-color colors/blue text-color colors/black @@ -121,15 +121,29 @@ {:on-press action-fn :accessibility-label accessibility-label :disabled (not active?)} - [react/view styles/settings-item + [react/view (styles/settings-item subtext) (if icon - [react/view (styles/settings-item-icon icon-color) + [react/view (styles/settings-item-icon icon-color subtext) [vector-icons/icon icon {:color icon-color}]] [react/image {:source {:uri image-source} :style styles/big-item-image}]) - [react/text {:style (styles/settings-item-text text-color) - :number-of-lines 1} - text] + (if subtext + [react/view {:style styles/settings-item-text-container} + [react/view {:style styles/settings-item-main-text-container} + (when new? + [react/view {:style styles/new-label} + [react/text {:style styles/new-label-text} + (string/upper-case (i18n/label :t/new))]]) + [react/text {:style (styles/settings-item-text-new text-color)} + text]] + [react/view {:style {:margin-top 2 + :justify-content :flex-start}} + [react/text {:style styles/settings-item-subtext + :number-of-lines 2} + subtext]]] + [react/text {:style (styles/settings-item-text text-color) + :number-of-lines 1} + text]) (when accessory-value [react/text {:style styles/settings-item-value :number-of-lines 1 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 26a315eeb4..ef65d7826a 100644 --- a/src/status_im/ui/components/qr_code_viewer/views.cljs +++ b/src/status_im/ui/components/qr_code_viewer/views.cljs @@ -1,10 +1,12 @@ (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])) @@ -13,24 +15,32 @@ rn-dependencies/qr-code (clj->js (merge {:inverted true} props)))) -(defn qr-code-viewer [{:keys [style hint-style footer-style footer-button value hint legend]}] +(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]] + [react/view {:style (merge styles/qr-code style)} + (when snt-amount + [react/view {:style {:margin-horizontal 16}} + [tr-to-talk/enabled-note]]) + (when width + (let [size (int (min width styles/qr-code-max-width))] + [react/view {:style (styles/qr-code-container size) + :accessibility-label :qr-code-image} + [qr-code {:value value + :size size}]])) + [react/text {:style (merge styles/qr-code-hint hint-style)} + hint] + [react/view styles/footer + [react/view styles/wallet-info + [react/text {:style (merge styles/hash-value-text footer-style) + :accessibility-label :address-text + :selectable true} + legend]]] + (when footer-button + [footer-button value])])) + +(defn qr-code-viewer [{:keys [style hint-style footer-style footer-button value hint legend] + :as params}] (if value - (let [{:keys [width]} @(re-frame/subscribe [:dimensions/window])] - [react/view {:style (merge styles/qr-code style)} - (when width - (let [size (int (min width styles/qr-code-max-width))] - [react/view {:style (styles/qr-code-container size) - :accessibility-label :qr-code-image} - [qr-code {:value value - :size size}]])) - [react/text {:style (merge styles/qr-code-hint hint-style)} - hint] - [react/view styles/footer - [react/view styles/wallet-info - [react/text {:style (merge styles/hash-value-text footer-style) - :accessibility-label :address-text - :selectable true} - legend]]] - (when footer-button - [footer-button value])]) + [qr-code-viewer-component params] [react/view [react/text "no value"]])) diff --git a/src/status_im/ui/screens/profile/events.cljs b/src/status_im/ui/screens/profile/events.cljs index 23b7d2ab8d..b1a9414fc0 100644 --- a/src/status_im/ui/screens/profile/events.cljs +++ b/src/status_im/ui/screens/profile/events.cljs @@ -97,4 +97,3 @@ :profile/share-profile-link (fn [_ [_ value]] {:profile/share-profile-link value})) - 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 new file mode 100644 index 0000000000..5ad0c4feb6 --- /dev/null +++ b/src/status_im/ui/screens/profile/tribute_to_talk/styles.cljs @@ -0,0 +1,311 @@ +(ns status-im.ui.screens.profile.tribute-to-talk.styles + (:require [status-im.ui.components.colors :as colors])) + +(def intro-container + {:flex 1 + :align-items :center + :margin-horizontal 32}) + +(def intro-image + {:width 246 + :height 219 + :margin-vertical 32}) + +(def intro-text + {:text-align :center + :font-size 22 + :color colors/black + :font-weight :bold + :line-height 28}) + +(def description-label + {:line-height 22 + :font-size 15 + :text-align :center + :color colors/gray}) + +(def intro-button + {:margin-vertical 8 + :padding-horizontal 32 + :align-self :center + :justify-content :center + :align-items :center}) + +(def bottom-toolbar + {:height 60 + :border-top-width 1 + :border-top-color colors/gray-lighter}) + +(def step-n + {:margin-top 5 + :font-size 14 + :text-align :center + :color colors/gray}) + +(def tribute-to-talk + {:font-weight "500" + :line-height 22 + :font-size 15 + :color colors/black + :text-align :center}) + +(def container + {:flex 1 + :background-color colors/white}) + +(def set-snt-amount-container + {:flex-grow 1 + :flex-direction :column + :background-color colors/white}) + +(defn horizontal-separator + [min-height max-height] + {:flex 1 + :min-height min-height + :max-height max-height}) + +(def number-row + {:flex-direction :row}) + +(def number-pad + {:flex 1 + :align-items :center + :margin-bottom 24 + :min-height 292 + :max-height 328}) + +(def number-container + {:width 64 + :height 64 + :border-radius 32 + :justify-content :center + :align-items :center + :background-color colors/blue-light}) + +(def vertical-number-separator + {:flex 1 + :min-width 16 + :max-width 32}) + +(def number + {:line-height 28 + :font-size 22 + :color colors/blue}) + +(def snt-amount-container + {:margin-horizontal 16 + :justify-content :center + :align-items :center}) + +(def snt-amount + {:font-size 32 + :color colors/black}) + +(def snt-amount-label + (assoc snt-amount :color colors/gray)) + +(def snt-asset-value + {:font-size 15 + :font-weight "500" + :line-height 22 + :color colors/gray}) + +(def personalized-message-container + {:flex-grow 1 + :align-items :center + :margin-horizontal 16 + :justify-content :flex-start}) + +(def personalized-message-title + {:margin-top 24 + :margin-bottom 10 + :align-self :flex-start}) + +(def personalized-message-input + {:border-radius 8 + :background-color colors/gray-lighter + :text-align-vertical :top + :font-size 15 + :line-height 22 + :padding-horizontal 16 + :padding-vertical 16}) + +(def edit-view-message-container + {:border-radius 8 + :background-color colors/blue-light + :margin-horizontal 72 + :padding-horizontal 12 + :padding-vertical 8}) + +(def edit-view-message + {:color colors/black + :line-height 22 + :font-size 15}) + +(def finish-label + {:font-size 22 + :line-height 28 + :font-weight :bold + :text-align :center + :color colors/black}) + +(defn finish-circle [color radius] + {:background-color color + :width (* 2 radius) + :height (* 2 radius) + :border-radius radius + :justify-content :center + :align-items :center}) + +(def finish-circle-with-shadow + (assoc (finish-circle colors/white 40) + :elevation 5 + :shadow-offset {:width 0 :height 2} + :shadow-radius 4 + :shadow-color (colors/alpha "#435971" 0.124066))) + +(defn icon-view [color] + {:background-color color + :justify-content :center + :align-items :center + :border-radius 20 + :width 40 + :height 40}) + +(def current-snt-amount + {:font-size 28 + :line-height 28 + :color colors/black + :font-weight "500"}) + +(def edit-label + {:font-size 15 + :color colors/blue}) + +(def edit-note + {:font-size 15 + :color colors/gray + :margin-top 16 + :margin-horizontal 16 + :text-align :center}) + +(def enabled-note + {:border-radius 8 + :border-width 1 + :padding 12 + :border-color colors/gray-lighter + :margin-horizontal 16 + :margin-bottom 16}) + +(def learn-more-container + {:flex-grow 1 + :justify-content :flex-start}) + +(def learn-more-link + {:height 52 + :padding-horizontal 32 + :margin-bottom 16 + :align-items :center + :justify-content :center}) + +(def learn-more-link-text + {:font-size 15 + :line-height 21 + :color colors/blue}) + +(def learn-more-image + {:width 120 + :height 110 + :margin-top 32 + :margin-left 32 + :margin-bottom 16 + :align-items :flex-start + :justify-content :center}) + +(def learn-more-title-text + (assoc intro-text + :text-align :left + :margin-left 32)) + +(def learn-more-text-container-1 + {:margin-horizontal 32 + :margin-top 12 + :margin-bottom 24}) + +(def learn-more-text-container-2 + {:margin-horizontal 32 + :margin-top 16 + :margin-bottom 32}) + +(def learn-more-text + {:font-size 17 + :line-height 22 + :color colors/black}) + +(def learn-more-section + {:border-radius 12 + :border-width 1 + :margin-horizontal 32 + :padding 8 + :width 238 + :border-color colors/gray-lighter}) + +(def chat-sample-bubble + {: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 + :align-items :center + :height 44}) + +(def pay-to-chat-text + {:font-size 15 + :color colors/blue + :line-height 22 + :font-weight "500"}) + +(def edit-container + {:justify-content :space-between + :flex-grow 1}) + +(def edit-screen-top-row + {:flex-direction :row + :margin-vertical 16 + :margin-horizontal 16 + :align-items :flex-start + :justify-content :space-between}) + +(def remove-view + {:flex-direction :row + :justify-content :flex-start + :align-self :flex-start + :margin-horizontal 16 + :margin-top 52}) + +(def remove-text + {:color colors/red + :margin-left 16 + :font-size 17}) + +(def remove-note + {:font-size 15 + :margin-horizontal 16 + :color colors/gray + :text-align :center + :margin-top 12}) + +(def enabled-note-text + {:color colors/black + :line-height 22 + :font-weight "500" + :font-size 15}) + +(def separator-style + {:height 1 + :background-color colors/gray-lighter + :align-self :stretch}) 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 new file mode 100644 index 0000000000..f198738f2f --- /dev/null +++ b/src/status_im/ui/screens/profile/tribute_to_talk/views.cljs @@ -0,0 +1,323 @@ +(ns status-im.ui.screens.profile.tribute-to-talk.views + (:require [clojure.string :as string] + [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.react-native.resources :as resources] + [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] + [status-im.ui.components.react :as react] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.toolbar.actions :as actions] + [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.screens.profile.tribute-to-talk.styles :as styles]) + (:require-macros [status-im.utils.views :refer [defview letsubs]])) + +(defn separator [] + [react/view {:style styles/separator-style}]) + +(defn steps-numbers [editing?] + {:intro 1 + :set-snt-amount (if editing? 1 2) + :personalized-message (if editing? 2 3) + :finish 3}) + +(def step-forward-label + {:intro :t/get-started + :set-snt-amount :t/continue + :personalized-message :t/tribute-to-talk-sign-and-set-tribute + :finish :t/ok-got-it}) + +(defn intro + [] + [react/view {:style styles/intro-container} + [react/view {:style {:flex 1 + :min-height 32}}] + + [react/image {:source (:tribute-to-talk resources/ui) + :style styles/intro-image}] + [react/view {:style {:flex 1 + :min-height 32}}] + + [react/view + [react/i18n-text {:style styles/intro-text + :key :tribute-to-talk}] + [react/i18n-text {:style (assoc styles/description-label :margin-top 12) + :key :tribute-to-talk-desc}] + [react/view {:style styles/learn-more-link} + [react/text {:style styles/learn-more-link-text + :on-press #(re-frame/dispatch + [:tribute-to-talk.ui/learn-more-pressed])} + (i18n/label :t/learn-more)]]]]) + +(defn snt-asset-value + [fiat-value] + [react/text {:style styles/snt-asset-value} + fiat-value]) + +(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")] + " SNT"] + [snt-asset-value fiat-value]]) + +(defn number-view + [numpad-symbol {:keys [on-press]}] + [react/touchable-opacity + {:on-press #(on-press numpad-symbol)} + [react/view {:style styles/number-container} + (if (= numpad-symbol :remove) + [icons/icon :main-icons/backspace {:color colors/blue}] + [react/text {:style styles/number} numpad-symbol])]]) + +(defn number-row + [[left middle right] opts] + [react/view {:style styles/number-row} + [number-view left opts] + [react/view {:style styles/vertical-number-separator}] + [number-view middle opts] + [react/view {:style styles/vertical-number-separator}] + [number-view right opts]]) + +(defn number-pad + [opts] + [react/view {:style styles/number-pad} + [number-row [1 2 3] opts] + [react/view {:style (styles/horizontal-separator 12 24)}] + [number-row [4 5 6] opts] + [react/view {:style (styles/horizontal-separator 12 24)}] + [number-row [7 8 9] opts] + [react/view {:style (styles/horizontal-separator 12 24)}] + [number-row ["." 0 :remove] opts]]) + +(defn set-snt-amount + [snt-amount] + [react/scroll-view + {:content-container-style styles/set-snt-amount-container} + [react/view {:style (styles/horizontal-separator 16 32)}] + [snt-amount-label snt-amount] + [react/view {:style (styles/horizontal-separator 16 40)}] + [number-pad {:on-press (fn [numpad-symbol] + (re-frame/dispatch + [:tribute-to-talk.ui/numpad-key-pressed numpad-symbol]))}] + [react/i18n-text {:style (assoc styles/description-label :margin-horizontal 16) + :key :tribute-to-talk-set-snt-amount}]]) + +(defn personalized-message + [message] + [react/scroll-view + {:content-container-style styles/personalized-message-container} + [react/view {:style styles/personalized-message-title} + [react/text {:style (assoc styles/description-label + :color colors/black)} + (i18n/label :t/personalized-message) + [react/text {:style styles/description-label} + (str " (" (i18n/label :t/optional) ")")]]] + [react/text-input + (cond-> {:style (assoc styles/personalized-message-input :height 144 + :align-self :stretch) + :multiline true + :on-change-text #(re-frame/dispatch + [:tribute-to-talk.ui/message-changed %1]) + :placeholder (i18n/label :t/tribute-to-talk-message-placeholder)} + (not (string/blank? message)) + (assoc :default-value message))] + [react/text {:style (assoc styles/description-label :margin-top 16 :margin-horizontal 32)} + (i18n/label :t/tribute-to-talk-you-can-leave-a-message)]]) + +(defn finish + [snt-amount] + [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-with-shadow} + [icons/icon :main-icons/check {:color (if snt-amount + colors/green + colors/gray)}]]]] + + [react/view {:style {:flex 1 + :min-height 32}}] + [react/view {:style {:justify-content :center + :align-items :center + :margin-bottom 32}} + [react/text {:style styles/finish-label} + (i18n/label (if snt-amount + :t/you-are-all-set + :t/tribute-to-talk-disabled))] + (if snt-amount + [react/text {:style (assoc styles/description-label :margin-top 16)} + (i18n/label :t/tribute-to-talk-finish-desc) + [react/text {:style (assoc styles/description-label :color colors/black)} + snt-amount] + " SNT"] + [react/text {:style (assoc styles/description-label :margin-top 16)} + (i18n/label :t/tribute-to-talk-disabled-note)])]]) + +(defn enabled-note + [] + [react/view {:style styles/enabled-note} + [react/view {:flex-direction :row} + [icons/icon :main-icons/info {:color colors/gray}] + [react/text {:style (assoc styles/enabled-note-text + :margin-left 11)} + (i18n/label :t/tribute-to-talk-enabled)]] + [react/text {:style (assoc styles/enabled-note-text + :font-weight :normal + :margin-left 35)} + (i18n/label :t/tribute-to-talk-add-friends)]]) + +(defn edit + [snt-amount message fiat-value] + [react/scroll-view {:content-container-style styles/edit-container} + [react/view {:style styles/edit-screen-top-row} + [react/view {:style {:flex-direction :row + :justify-content :flex-start + :align-items :flex-start}} + [react/view {:style (styles/icon-view colors/blue)} + [icons/icon :icons/logo {:color colors/white :width 20 :height 20}]] + [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} + snt-amount + [react/text {: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 + [:tribute-to-talk.ui/edit-pressed]) + :style styles/edit-label} + (i18n/label :t/edit)]] + (when-not (string/blank? message) + [react/view {:flex-direction :row + :margin-bottom 16} + [react/view {:style styles/edit-view-message-container} + [react/text {:style styles/edit-view-message} + message]] + [react/view {:flex 1}]]) + [separator] + [react/text {:style styles/edit-note} + (i18n/label :t/tribute-to-talk-you-require-snt)] + + [react/touchable-highlight {:on-press #(re-frame/dispatch + [:tribute-to-talk.ui/remove-pressed]) + :style styles/remove-view} + [react/view {:style {:flex-direction :row}} + [react/view {:style (styles/icon-view (colors/alpha colors/red 0.1))} + [icons/icon :main-icons/logout {:color colors/red}]] + [react/view {:style {:justify-content :center + :align-items :center}} + [react/text {:style styles/remove-text} + (i18n/label :t/remove)]]]] + [react/text {:style styles/remove-note} + (i18n/label :t/tribute-to-talk-removing-note)] + [react/view {:flex 1 + :min-height 24}] + [enabled-note]]) + +(defn chat-sample [] + [react/view {:style (assoc styles/learn-more-section :margin-top 24)} + [react/view {:style {:flex-direction :row + :align-items :center}} + [react/view {:style {:background-color colors/white + :justify-content :center :align-items :center}} + [icons/icon :tiny-icons/tribute-to-talk {:color colors/blue}]] + [react/text {:style {:color colors/gray + :font-size 13 + :line-height 22 + :margin-left 4}} + (i18n/label :t/tribute-to-talk)]] + [react/view {:style styles/chat-sample-bubble} + [react/text {:style {:font-size 15 :color colors/black}} + (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 :color colors/black}} "1000" + [react/text {:style {:font-size 22 :color colors/gray}} " SNT"]] + [react/text {:style {:font-size 12 :color colors/black}} + "~3.48" + [react/text {:style {:font-size 12 :color colors/gray}} " USD"]] + [react/view {:style styles/pay-to-chat-container} + [react/text {:style styles/pay-to-chat-text} + (i18n/label :t/pay-to-chat)]]]]) + +(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)]]]) + +(defview tribute-to-talk [] + (letsubs [current-account [:account/account] + {:keys [step snt-amount editing? message fiat-value disabled?]} + [:tribute-to-talk/ui]] + [react/keyboard-avoiding-view {:style styles/container} + [react/safe-area-view {:style {:flex 1}} + [status-bar/status-bar] + [toolbar/toolbar + nil + (when-not (= :finish step) + (toolbar/nav-button + (actions/back #(re-frame/dispatch + [:tribute-to-talk.ui/step-back-pressed])))) + [react/view + [react/text {:style styles/tribute-to-talk} + (i18n/label :t/tribute-to-talk)] + (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 :t/step-i-of-n {:step ((steps-numbers editing?) step) + :number (if editing? 2 3)}))]) + (when (= step :learn-more) + [react/text {:style styles/step-n} + (i18n/label :t/learn-more)])]] + + (case step + :intro [intro] + :set-snt-amount [set-snt-amount snt-amount] + :edit [edit snt-amount message fiat-value] + :learn-more [learn-more] + :personalized-message [personalized-message message] + :finish [finish snt-amount]) + + (when-not (#{:learn-more :edit} step) + [react/view {:style styles/bottom-toolbar} + [components.common/button {:button-style styles/intro-button + :disabled? disabled? + :uppercase? false + :label-style (when disabled? {: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 2ad8227e85..d3df5ec607 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -258,6 +258,20 @@ :accessory-value active-contacts-count :action-fn #(re-frame/dispatch [:navigate-to :contacts-list])}]) +(defn tribute-to-talk-item [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)))]) + (defview my-profile [] (letsubs [{:keys [public-key photo-path] :as current-account} [:account/account] editing? [:get :my-profile/editing?] @@ -265,7 +279,9 @@ currency [:wallet/currency] login-data [:get :accounts/login] scroll (reagent/atom nil) - active-contacts-count [:contacts/active-count]] + active-contacts-count [:contacts/active-count] + {tribute-to-talk-seen? :seen? + snt-amount :snt-amount} [:tribute-to-talk/settings]] (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. @@ -291,12 +307,15 @@ :edited-contact changed-account :editing? editing? :allow-icon-change? true - :options (if (not= (identicon/identicon public-key) photo-path) + :options (if (not= (identicon/identicon public-key) + photo-path) (profile-icon-options-ext) profile-icon-options) :on-change-text-event :my-profile/update-name}]] [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?]) [react/view styles/my-profile-info-container [my-profile-settings current-account shown-account currency (nil? login-data)]] (when (nil? login-data) diff --git a/src/status_im/ui/screens/routing/profile_stack.cljs b/src/status_im/ui/screens/routing/profile_stack.cljs index f911cf9328..e4fb998607 100644 --- a/src/status_im/ui/screens/routing/profile_stack.cljs +++ b/src/status_im/ui/screens/routing/profile_stack.cljs @@ -28,6 +28,7 @@ :currency-settings :mobile-network-settings :backup-seed + :tribute-to-talk :qr-scanner] config/hardwallet-enabled? diff --git a/src/status_im/ui/screens/routing/screens.cljs b/src/status_im/ui/screens/routing/screens.cljs index 0ade44a02d..25c24af4aa 100644 --- a/src/status_im/ui/screens/routing/screens.cljs +++ b/src/status_im/ui/screens/routing/screens.cljs @@ -51,6 +51,7 @@ [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] @@ -139,6 +140,7 @@ :fleet-settings fleet-settings/fleet-settings :currency-settings currency-settings/currency-settings :backup-seed profile.seed/backup-seed + :tribute-to-talk tr-to-talk/tribute-to-talk :reset-card hardwallet.settings/reset-card :keycard-settings hardwallet.settings/keycard-settings :mobile-network-settings mobile-network-settings/mobile-network-settings}) diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index a85029d72a..3eed15a497 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -5,6 +5,7 @@ status-im.contact.subs status-im.search.subs status-im.mailserver.subs + status-im.tribute-to-talk.subs status-im.ui.components.connectivity.subs status-im.ui.screens.accounts.subs status-im.ui.screens.chat.stickers.subs diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index dee5e8bed8..76daea5383 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -80,3 +80,4 @@ ;; see https://reactnavigation.org/docs/en/state-persistence.html#development-mode :persistenceKey (when js/goog.DEBUG rand-label)}] [bottom-sheet]]))}))) + diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index 92d4bc8b5c..09f326dd01 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -31,6 +31,7 @@ (def dev-build? (enabled? (get-config :DEV_BUILD 0))) (def erc20-contract-warnings-enabled? (enabled? (get-config :ERC20_CONTRACT_WARNINGS))) (def partitioned-topic-enabled? (enabled? (get-config :PARTITIONED_TOPIC "0"))) +(def tr-to-talk-enabled? (enabled? (get-config :TRIBUTE_TO_TALK 0))) ;; CONFIG VALUES (def log-level diff --git a/translations/en.json b/translations/en.json index 4547c2a15e..c36f0b09fe 100644 --- a/translations/en.json +++ b/translations/en.json @@ -17,6 +17,8 @@ "sync-all-devices": "Sync all devices", "syncing-devices": "Syncing...", "notify": "Notify", + "completed": "Completed", + "disabled": "Disabled", "paired-devices": "Paired devices", "contact-recovery-title": "{{name}} has sent you a message", "contact-recovery-content": "{{name}} has sent you a message but did not include this device.\nThis might happen if you have more than 3 devices, you haven't paired your devices correctly or you just recovered your account.\nPlease make sure your devices are paired correctly and click Notify to let the user know of this device.", @@ -896,6 +898,29 @@ "pairing": "Pairing", "view-my-wallet": "View my wallet", "share-my-profile": "Share my profile", + "get-started": "Get started", + "continue": "Continue", + "tribute-to-talk": "Tribute to talk", + "tribute-to-talk-desc": "Monetize your attention by requiring SNT for new people to start a chat", + "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", + "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-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.", + "learn-more": "Learn more", + "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.", + "pay-to-chat": "Pay to chat", "share-chat": "Share chat", "share-link": "Share link", "share-profile-link": "Share profile link",