diff --git a/resources/icons/newchat.svg b/resources/icons/newchat.svg new file mode 100644 index 0000000000..296b02065f --- /dev/null +++ b/resources/icons/newchat.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/status_im/chat/new_chat/styles.cljs b/src/status_im/chat/new_chat/styles.cljs deleted file mode 100644 index 67e1296372..0000000000 --- a/src/status_im/chat/new_chat/styles.cljs +++ /dev/null @@ -1,10 +0,0 @@ -(ns status-im.chat.new-chat.styles - (:require [status-im.ui.components.styles :as common])) - -(def contacts-list-container - {:flex 1 - :margin-bottom 0}) - -(def contacts-list - {:background-color common/color-light-gray}) - diff --git a/src/status_im/chat/new_chat/view.cljs b/src/status_im/chat/new_chat/view.cljs deleted file mode 100644 index 46b390d538..0000000000 --- a/src/status_im/chat/new_chat/view.cljs +++ /dev/null @@ -1,82 +0,0 @@ -(ns status-im.chat.new-chat.view - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [re-frame.core :refer [dispatch]] - [status-im.ui.components.common.common :as common] - [status-im.ui.components.action-button.action-button :refer [action-button - action-separator]] - [status-im.ui.components.action-button.styles :refer [actions-list]] - [status-im.ui.components.list.views :as list] - [status-im.ui.components.contact.contact :refer [contact-view]] - [status-im.ui.components.react :as react] - [status-im.ui.components.status-bar.view :refer [status-bar]] - [status-im.ui.components.toolbar.view :refer [toolbar-with-search]] - [status-im.chat.new-chat.styles :as styles] - [status-im.i18n :as i18n])) - -(defn options-list [] - [react/view actions-list - [action-button {:label (i18n/label :t/new-group-chat) - :icon :icons/group-big - :icon-opts {:color :blue} - :on-press #(dispatch [:open-contact-toggle-list :chat-group])}] - [action-separator] - [action-button {:label (i18n/label :t/new-public-group-chat) - :icon :icons/public - :icon-opts {:color :blue} - :on-press #(dispatch [:navigate-to :new-public-chat])}] - [action-separator] - [action-button {:label (i18n/label :t/add-new-contact) - :icon :icons/add - :icon-opts {:color :blue} - :on-press #(dispatch [:navigate-to :new-contact])}] - [action-separator] - [action-button {:label (i18n/label :t/open-url) - :icon :icons/address - :icon-opts {:color :blue} - :on-press #(do - (dispatch [:navigate-to-clean :home]) - (dispatch [:navigate-to :browser]))}]]) - -(defn contact-list-row [{:keys [dapp-url] :as contact}] - [contact-view {:contact contact - :on-press #(if dapp-url - (do - (dispatch [:navigate-to-clean :home]) - (dispatch [:open-dapp-in-browser contact])) - (dispatch [:open-chat-with-contact %]))}]) - -(defview new-chat-toolbar [] - (letsubs [show-search [:get-in [:toolbar-search :show]] - search-text [:get-in [:toolbar-search :text]]] - [react/view - [status-bar] - (toolbar-with-search - {:show-search? (= show-search :contact-list) - :search-text search-text - :search-key :contact-list - :title (i18n/label :t/contacts-group-new-chat) - :search-placeholder (i18n/label :t/search-for)})])) - -(defn- header [contacts] - [react/view - [options-list] - [common/bottom-shadow] - [common/form-title (i18n/label :t/choose-from-contacts) - {:count-value (count contacts)}] - [common/list-header]]) - -(defview new-chat [] - (letsubs [contacts [:all-added-group-contacts-filtered] - params [:get :contacts/click-params]] - [react/view styles/contacts-list-container - [new-chat-toolbar] - (when contacts - [list/flat-list {:style styles/contacts-list - :data contacts - :render-fn contact-list-row - :bounces false - :keyboardShouldPersistTaps :always - :header (header contacts) - :footer [react/view - [common/list-footer] - [common/bottom-shadow]]}])])) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index f00050e99a..af4bdc85ae 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -14,7 +14,7 @@ :open "Open" :description "Description" :enter-url "Enter URL" - :open-url "Open URL" + :open-dapp "Open ÐApp" :url "URL" :type-a-message "Type a message..." :type-a-command "Start typing a command..." @@ -142,6 +142,11 @@ :phone-significant "Significant" ;;chats + :new "New" + :new-chat "New chat" + :start-new-chat "Start new chat" + :start-group-chat "Start group chat" + :invite-friends "Invite friends" :chats "Chats" :delete-chat "Delete chat" :new-group-chat "New group chat" @@ -188,6 +193,7 @@ :show-qr "Show QR code" :qr-code-public-key-hint "Share this code to \nstart chatting" :enter-address "Enter address" + :enter-contact-code "Enter contact code" :more "more" ;;group-settings @@ -227,6 +233,7 @@ :scan-qr "Scan QR code" :name "Name" :address-explication "Your public key is used to generate your address on Ethereum and is a series of numbers and letters. You can find it easily in your profile" + :use-valid-contact-code "Please enter a valid contact code" :enter-valid-public-key "Please enter a valid public key or scan a QR code" :contact-already-added "The contact has already been added" :can-not-add-yourself "You can't add yourself" @@ -265,7 +272,6 @@ :recipient "Recipient" :specify-recipient "Specify recipient..." :recipient-code "Enter recipient address" - :enter-contact-code "Enter Contact Code" :recent-recipients "Recent recipients" :to "To" :from "From" @@ -397,4 +403,5 @@ ;; browser :browser "Browser" :enter-dapp-url "Enter a ÐApp URL" - :dapp "ÐApp"}) + :dapp "ÐApp" + :selected-dapps "Selected ÐApps"}) diff --git a/src/status_im/ui/components/action_button/styles.cljs b/src/status_im/ui/components/action_button/styles.cljs index 848cf6c814..0f0b19e004 100644 --- a/src/status_im/ui/components/action_button/styles.cljs +++ b/src/status_im/ui/components/action_button/styles.cljs @@ -1,6 +1,7 @@ (ns status-im.ui.components.action-button.styles (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) - (:require [status-im.ui.components.styles :as styles])) + (:require [status-im.ui.components.styles :as styles] + [status-im.ui.components.colors :as colors])) (defstyle action-button {:padding-left 16 @@ -20,13 +21,10 @@ (def action-button-label-container {:padding-left 16}) -(defstyle action-button-label - {:ios {:color styles/color-light-blue - :letter-spacing -0.2 - :font-size 17 - :line-height 20} - :android {:color styles/color-black - :font-size 16}}) +(def action-button-label + {:color colors/blue + :letter-spacing -0.2 + :font-size 16}) (defstyle actions-list {:background-color styles/color-white diff --git a/src/status_im/ui/components/chat_icon/screen.cljs b/src/status_im/ui/components/chat_icon/screen.cljs index 5b2db9ab0f..f245869ab6 100644 --- a/src/status_im/ui/components/chat_icon/screen.cljs +++ b/src/status_im/ui/components/chat_icon/screen.cljs @@ -131,15 +131,15 @@ :default-chat-icon (styles/default-chat-icon-chat-list components.styles/default-chat-color) :default-chat-icon-text styles/default-chat-icon-text}]) -(defn dapp-icon-browser [contact] +(defn dapp-icon-browser [contact size] [contact-icon-view contact - {:container styles/container-chat-list + {:container {:width size :height size} :online-view-wrapper styles/online-view-wrapper :online-view styles/online-view :online-dot-left styles/online-dot-left :online-dot-right styles/online-dot-right - :size 36 - :chat-icon styles/chat-icon-chat-list + :size size + :chat-icon (styles/custom-size-icon size) :default-chat-icon (styles/default-chat-icon-chat-list components.styles/default-chat-color) :default-chat-icon-text styles/default-chat-icon-text}]) diff --git a/src/status_im/ui/components/chat_icon/styles.cljs b/src/status_im/ui/components/chat_icon/styles.cljs index 9989a7e54f..f933e61545 100644 --- a/src/status_im/ui/components/chat_icon/styles.cljs +++ b/src/status_im/ui/components/chat_icon/styles.cljs @@ -64,6 +64,12 @@ :height 40 :margin 0})) +(defn custom-size-icon [size] + (merge chat-icon + {:width size + :height size + :margin 0})) + (def chat-icon-menu-item {:width 24 :height 24 diff --git a/src/status_im/ui/components/contact/contact.cljs b/src/status_im/ui/components/contact/contact.cljs index 6d2dafac9b..3efa1d115c 100644 --- a/src/status_im/ui/components/contact/contact.cljs +++ b/src/status_im/ui/components/contact/contact.cljs @@ -1,5 +1,5 @@ (ns status-im.ui.components.contact.contact - (:require-macros [status-im.utils.views :refer [defview]]) + (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [status-im.ui.components.react :refer [view touchable-highlight text]] [status-im.ui.components.icons.vector-icons :as vi] [status-im.ui.components.chat-icon.screen :refer [contact-icon-contacts-tab]] @@ -27,27 +27,28 @@ [text {:style st/info-text} info])]])) -(defn contact-view [{:keys [contact extended? on-press extend-options info]}] +(defn contact-view [{:keys [contact extended? on-press extend-options info show-forward?]}] [touchable-highlight (when-not extended? {:on-press (when on-press #(on-press contact))}) - [view [view st/contact-container [contact-inner-view {:contact contact :info info}] + (when show-forward? + [view st/forward-btn + [vi/icon :icons/forward]]) (when (and extended? (not (empty? extend-options))) [view st/more-btn-container [context-menu [vi/icon :icons/options {:accessibility-label :options}] extend-options nil - st/more-btn]])]]]) + st/more-btn]])]]) (defview toogle-contact-view [{:keys [whisper-identity] :as contact} selected-key on-toggle-handler] - [checked [selected-key whisper-identity]] - [touchable-highlight {:on-press #(on-toggle-handler checked whisper-identity)} - [view - [view (merge st/contact-container (when checked {:style st/selected-contact})) - [contact-inner-view (merge {:contact contact} - (when checked {:style st/selected-contact}))] - [view (st/icon-check-container checked) - (when checked - [vi/icon :icons/ok {:style st/check-icon}])]]]]) + (letsubs [checked [selected-key whisper-identity]] + [touchable-highlight {:on-press #(on-toggle-handler checked whisper-identity)} + [view (merge st/contact-container (when checked {:style st/selected-contact})) + [contact-inner-view (merge {:contact contact} + (when checked {:style st/selected-contact}))] + [view (st/icon-check-container checked) + (when checked + [vi/icon :icons/ok {:style st/check-icon}])]]])) diff --git a/src/status_im/ui/components/contact/styles.cljs b/src/status_im/ui/components/contact/styles.cljs index f43b8f7b7e..55f6a8f2f0 100644 --- a/src/status_im/ui/components/contact/styles.cljs +++ b/src/status_im/ui/components/contact/styles.cljs @@ -21,7 +21,7 @@ (defstyle name-text {:color common/text1-color - :android {:font-size 16} + :android {:font-size 16} :ios {:font-size 17 :letter-spacing -0.2}}) @@ -35,6 +35,12 @@ :align-items :center :background-color common/color-white}) +(def forward-btn + {:opacity 0.4 + :padding 12 + :alignItems :center + :justifyContent :center}) + (def more-btn-container {:alignItems :center :justifyContent :center}) @@ -53,15 +59,15 @@ (defnstyle icon-check-container [checked] {:background-color (if checked common/color-light-blue common/color-gray5) - :alignItems :center - :justifyContent :center - :margin-right 16 - :android {:border-radius 2 - :width 17 - :height 17} - :ios {:border-radius 50 - :width 24 - :height 24}}) + :alignItems :center + :justifyContent :center + :margin-right 16 + :android {:border-radius 2 + :width 17 + :height 17} + :ios {:border-radius 50 + :width 24 + :height 24}}) (def check-icon {:width 12 diff --git a/src/status_im/ui/components/icons/vector_icons.cljs b/src/status_im/ui/components/icons/vector_icons.cljs index 2aa91d7b48..7fdeec6de4 100644 --- a/src/status_im/ui/components/icons/vector_icons.cljs +++ b/src/status_im/ui/components/icons/vector_icons.cljs @@ -26,6 +26,7 @@ (def defs (get-class "Defs")) (def icons {:icons/discover (slurp-svg "./resources/icons/bottom/discover_gray.svg") + :icons/contacts (slurp-svg "./resources/icons/bottom/contacts_gray.svg") :icons/home (slurp-svg "./resources/icons/bottom/home_gray.svg") :icons/home-active (slurp-svg "./resources/icons/bottom/home_blue.svg") :icons/profile (slurp-svg "./resources/icons/bottom/profile_gray.svg") @@ -75,7 +76,8 @@ :icons/open (slurp-svg "./resources/icons/open.svg") :icons/network (slurp-svg "./resources/icons/network.svg") :icons/wnode (slurp-svg "./resources/icons/wnode.svg") - :icons/refresh (slurp-svg "./resources/icons/refresh.svg")}) + :icons/refresh (slurp-svg "./resources/icons/refresh.svg") + :icons/newchat (slurp-svg "./resources/icons/newchat.svg")}) (defn normalize-property-name [n] (if (= n :icons/options) diff --git a/src/status_im/ui/components/styles.cljs b/src/status_im/ui/components/styles.cljs index 4d5d2b1a95..9779474a98 100644 --- a/src/status_im/ui/components/styles.cljs +++ b/src/status_im/ui/components/styles.cljs @@ -7,7 +7,7 @@ (def color-blue "#7099e6") (def color-blue2 "#5b6dee") (def color-blue3 "#424fae") -(def color-blue4 "#4360df") +(def color-blue4 "#4360df") ; colors/blue (def color-blue4-faded "rgba(67,96,222,0.87)") (def color-blue4-transparent "rgba(67, 96, 223, 0.10)") (def color-blue5 "#3c56c8") diff --git a/src/status_im/ui/screens/add_new/db.cljs b/src/status_im/ui/screens/add_new/db.cljs new file mode 100644 index 0000000000..fa0076f8ed --- /dev/null +++ b/src/status_im/ui/screens/add_new/db.cljs @@ -0,0 +1,5 @@ +(ns status-im.ui.screens.add-new.db + (:require [cljs.spec.alpha :as spec] + status-im.ui.screens.contacts.db)) + +(spec/def :new/open-dapp (spec/nilable :contact/contact)) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/new_chat/db.cljs b/src/status_im/ui/screens/add_new/new_chat/db.cljs new file mode 100644 index 0000000000..49b7b597a2 --- /dev/null +++ b/src/status_im/ui/screens/add_new/new_chat/db.cljs @@ -0,0 +1,15 @@ +(ns status-im.ui.screens.add-new.new-chat.db + (:require [status-im.utils.hex :as hex] + [status-im.i18n :as i18n] + [cljs.spec.alpha :as spec] + [clojure.string :as string])) + +(defn- validate-pub-key [whisper-identity {:keys [address public-key]}] + (when (and whisper-identity (not (string/blank? whisper-identity))) + (cond + (#{(hex/normalize-hex address) (hex/normalize-hex public-key)} + (hex/normalize-hex whisper-identity)) + (i18n/label :t/can-not-add-yourself) + + (not (spec/valid? :global/public-key whisper-identity)) + (i18n/label :t/use-valid-contact-code)))) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/new_chat/styles.cljs b/src/status_im/ui/screens/add_new/new_chat/styles.cljs new file mode 100644 index 0000000000..629d89d3ef --- /dev/null +++ b/src/status_im/ui/screens/add_new/new_chat/styles.cljs @@ -0,0 +1,9 @@ +(ns status-im.ui.screens.add-new.new-chat.styles + (:require [status-im.ui.components.colors :as colors])) + +(def error-message + {:margin-horizontal 14 + :margin-top 4 + :font-size 12 + :letter-spacing -0.2 + :color colors/red}) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/new_chat/subs.cljs b/src/status_im/ui/screens/add_new/new_chat/subs.cljs new file mode 100644 index 0000000000..2d671a4dff --- /dev/null +++ b/src/status_im/ui/screens/add_new/new_chat/subs.cljs @@ -0,0 +1,10 @@ +(ns status-im.ui.screens.add-new.new-chat.subs + (:require [re-frame.core :as re-frame] + [status-im.ui.screens.add-new.new-chat.db :as db])) + +(re-frame/reg-sub + :new-contact-error-message + :<- [:get :contacts/new-identity] + :<- [:get-current-account] + (fn [[new-identity account]] + (db/validate-pub-key new-identity account))) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/new_chat/views.cljs b/src/status_im/ui/screens/add_new/new_chat/views.cljs new file mode 100644 index 0000000000..1cc0e23a8d --- /dev/null +++ b/src/status_im/ui/screens/add_new/new_chat/views.cljs @@ -0,0 +1,48 @@ +(ns status-im.ui.screens.add-new.new-chat.views + (:require-macros [status-im.utils.views :as views]) + (:require [status-im.ui.components.react :as react] + [status-im.ui.components.list.views :as list] + [status-im.ui.components.contact.contact :as contact-view] + [re-frame.core :as re-frame] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.toolbar.view :as toolbar.view] + [status-im.i18n :as i18n] + [status-im.ui.components.common.common :as components] + [status-im.ui.screens.add-new.open-dapp.styles :as open-dapp.styles] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.screens.add-new.new-chat.styles :as styles] + [status-im.ui.components.colors :as colors])) + +(defn render-row [row _ _] + [contact-view/contact-view {:contact row + :on-press #(re-frame/dispatch [:open-chat-with-contact %]) + :show-forward? true}]) + +(views/defview new-chat [] + (views/letsubs [contacts [:all-added-people-contacts] + error-message [:new-contact-error-message]] + [react/keyboard-avoiding-view open-dapp.styles/main-container + [status-bar/status-bar] + [toolbar.view/simple-toolbar (i18n/label :t/new-chat)] + [components/separator] + [react/view open-dapp.styles/enter-url + [react/text-input {:on-change-text #(re-frame/dispatch [:set :contacts/new-identity %]) + :on-submit-editing #(when-not error-message + (re-frame/dispatch [:add-contact-handler])) + :placeholder (i18n/label :t/enter-contact-code) + :style open-dapp.styles/url-input}] + [react/touchable-highlight {:on-press #(re-frame/dispatch [:scan-qr-code + {:toolbar-title (i18n/label :t/new-contact)} + :set-contact-identity-from-qr]) + :style {:margin-right 14}} + [react/view + [vector-icons/icon :icons/qr {:color colors/blue}]]]] + [react/text {:style styles/error-message} + error-message] + [react/text {:style open-dapp.styles/list-title} + (i18n/label :t/contacts)] + [list/flat-list {:data contacts + :render-fn render-row + :default-separator? true + :enableEmptySections true + :keyboardShouldPersistTaps :always}]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/open_dapp/events.cljs b/src/status_im/ui/screens/add_new/open_dapp/events.cljs new file mode 100644 index 0000000000..6b5ab97514 --- /dev/null +++ b/src/status_im/ui/screens/add_new/open_dapp/events.cljs @@ -0,0 +1,2 @@ +(ns status-im.ui.screens.add-new.open-dapp.events + (:require status-im.ui.screens.add-new.open-dapp.navigation)) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/open_dapp/navigation.cljs b/src/status_im/ui/screens/add_new/open_dapp/navigation.cljs new file mode 100644 index 0000000000..a09051071f --- /dev/null +++ b/src/status_im/ui/screens/add_new/open_dapp/navigation.cljs @@ -0,0 +1,6 @@ +(ns status-im.ui.screens.add-new.open-dapp.navigation + (:require [status-im.ui.screens.navigation :as navigation])) + +(defmethod navigation/preload-data! :dapp-description + [db [_ _ dapp]] + (assoc db :new/open-dapp dapp)) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/open_dapp/styles.cljs b/src/status_im/ui/screens/add_new/open_dapp/styles.cljs new file mode 100644 index 0000000000..8d944e858a --- /dev/null +++ b/src/status_im/ui/screens/add_new/open_dapp/styles.cljs @@ -0,0 +1,49 @@ +(ns status-im.ui.screens.add-new.open-dapp.styles + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) + (:require [status-im.ui.components.colors :as colors])) + +(def main-container {:flex 1}) + +(def enter-url + {:flex-direction :row + :align-items :center + :border-radius 8 + :height 52 + :background-color colors/light-gray + :margin-horizontal 14 + :margin-top 24}) + +(defstyle url-input + {:flex 1 + :font-size 15 + :letter-spacing -0.2 + :padding-horizontal 14 + :android {:padding 0}}) + +(def gray-label + {:font-size 14 + :letter-spacing -0.2 + :color colors/gray}) + +(def black-label + {:font-size 15 + :letter-spacing -0.2}) + +(def dapp + (merge gray-label + {:margin-top 4})) + +(def dapp-name + (merge black-label + {:margin-top 8})) + +(def list-title + {:margin-top 24 + :margin-left 16 + :font-size 14 + :letter-spacing -0.2 + :color colors/gray}) + +(def description-container + {:margin-top 26 + :margin-horizontal 16}) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/open_dapp/views.cljs b/src/status_im/ui/screens/add_new/open_dapp/views.cljs new file mode 100644 index 0000000000..784141e196 --- /dev/null +++ b/src/status_im/ui/screens/add_new/open_dapp/views.cljs @@ -0,0 +1,68 @@ +(ns status-im.ui.screens.add-new.open-dapp.views + (:require-macros [status-im.utils.views :as views]) + (:require [status-im.ui.components.react :as react] + [status-im.ui.screens.add-new.open-dapp.styles :as styles] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.toolbar.view :as toolbar.view] + [status-im.i18n :as i18n] + [re-frame.core :as re-frame] + [status-im.ui.components.action-button.action-button :as action-button] + [status-im.ui.components.common.common :as components] + [status-im.ui.components.list.views :as list] + [status-im.ui.components.contact.contact :as contact-view] + [status-im.ui.components.chat-icon.screen :as chat-icon.screen])) + +(defn render-row [row _ _] + [contact-view/contact-view {:contact row + :on-press #(re-frame/dispatch [:navigate-to :dapp-description row]) + :show-forward? true}]) + +(views/defview open-dapp [] + (views/letsubs [dapps [:all-dapp-with-url-contacts] + url-text (atom nil)] + [react/keyboard-avoiding-view styles/main-container + [status-bar/status-bar] + [toolbar.view/simple-toolbar (i18n/label :t/open-dapp)] + [components/separator] + [react/view styles/enter-url + [react/text-input {:on-change-text #(reset! url-text %) + :on-submit-editing #(do + (re-frame/dispatch [:navigate-to-clean :home]) + (re-frame/dispatch [:open-browser {:url @url-text}])) + :placeholder (i18n/label :t/enter-url) + :style styles/url-input}]] + [react/text {:style styles/list-title} + (i18n/label :t/selected-dapps)] + [list/flat-list {:data dapps + :render-fn render-row + :default-separator? true + :enableEmptySections true + :keyboardShouldPersistTaps :always}]])) + +(views/defview dapp-description [] + (views/letsubs [{:keys [name dapp-url] :as dapp} [:get :new/open-dapp]] + [react/keyboard-avoiding-view styles/main-container + [status-bar/status-bar] + [toolbar.view/simple-toolbar] + [react/view {:margin-top 24 :align-items :center} + [chat-icon.screen/dapp-icon-browser dapp 56] + [react/text {:style styles/dapp-name} + name] + [react/text {:style styles/dapp} + (i18n/label :t/dapp)]] + [react/view {:margin-top 24} + [action-button/action-button {:label (i18n/label :t/open) :icon :icons/address + :on-press #(do + (re-frame/dispatch [:navigate-to-clean :home]) + (re-frame/dispatch [:open-dapp-in-browser dapp]))}] + [components/separator {:margin-left 72}]] + [react/view styles/description-container + [react/text {:style styles/gray-label} + (i18n/label :t/description)] + [react/text {:style (merge styles/black-label {:padding-top 18})}] + [components/separator {:margin-top 15}] + [react/text {:style (merge styles/gray-label {:padding-top 18})} + (i18n/label :t/url)] + [react/text {:style (merge styles/black-label {:padding-top 14})} + dapp-url] + [components/separator {:margin-top 6}]]])) diff --git a/src/status_im/ui/screens/add_new/views.cljs b/src/status_im/ui/screens/add_new/views.cljs new file mode 100644 index 0000000000..03f1566fa3 --- /dev/null +++ b/src/status_im/ui/screens/add_new/views.cljs @@ -0,0 +1,52 @@ +(ns status-im.ui.screens.add-new.views + (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require [re-frame.core :as re-frame] + [status-im.ui.components.action-button.action-button :as action-button] + [status-im.ui.components.action-button.styles :as action-button.styles] + [status-im.ui.components.react :as react] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.i18n :as i18n] + [status-im.ui.components.toolbar.view :as toolbar.view] + [status-im.ui.components.common.common :as components])) + +(defn options-list [] + [react/view action-button.styles/actions-list + [action-button/action-button + {:label (i18n/label :t/start-new-chat) + :icon :icons/newchat + :icon-opts {:color colors/blue} + :on-press #(re-frame/dispatch [:navigate-to :new-chat])}] + [action-button/action-separator] + [action-button/action-button + {:label (i18n/label :t/start-group-chat) + :icon :icons/contacts + :icon-opts {:color colors/blue} + :on-press #(re-frame/dispatch [:open-contact-toggle-list :chat-group])}] + [action-button/action-separator] + [action-button/action-button + {:label (i18n/label :t/new-public-group-chat) + :icon :icons/public + :icon-opts {:color colors/blue} + :on-press #(re-frame/dispatch [:navigate-to :new-public-chat])}] + [action-button/action-separator] + [action-button/action-button + {:label (i18n/label :t/open-dapp) + :icon :icons/address + :icon-opts {:color colors/blue} + :on-press #(re-frame/dispatch [:navigate-to :open-dapp])}] + [action-button/action-separator] + [action-button/action-button + {:label (i18n/label :t/invite-friends) + :icon :icons/share + :icon-opts {:color colors/blue} + :on-press #()}]]) + +(defview add-new [] + (letsubs [contacts [:all-added-group-contacts-filtered] + params [:get :contacts/click-params]] + [react/view {:flex 1} + [status-bar/status-bar] + [toolbar.view/simple-toolbar (i18n/label :t/new)] + [components/separator] + [options-list]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/browser/events.cljs b/src/status_im/ui/screens/browser/events.cljs index b45d0aeedf..1a9ea34bb8 100644 --- a/src/status_im/ui/screens/browser/events.cljs +++ b/src/status_im/ui/screens/browser/events.cljs @@ -25,6 +25,9 @@ (fn [browser] (browser-store/save browser))) +(defn match-url [url] + (str (when (and url (not (re-find #"^[a-zA-Z-_]+:/" url))) "http://") url)) + (defn get-new-browser [browser now] (cond-> browser true @@ -32,7 +35,9 @@ (not (:browser-id browser)) (assoc :browser-id (random/id)) (not (:name browser)) - (assoc :name (i18n/label :t/browser)))) + (assoc :name (i18n/label :t/browser)) + (:url browser) + (update :url match-url))) (defn add-browser-fx [{:keys [db now] :as cofx} browser] (let [new-browser (get-new-browser browser now)] diff --git a/src/status_im/ui/screens/browser/views.cljs b/src/status_im/ui/screens/browser/views.cljs index 67275c3892..61eb879e37 100644 --- a/src/status_im/ui/screens/browser/views.cljs +++ b/src/status_im/ui/screens/browser/views.cljs @@ -17,7 +17,7 @@ (views/defview toolbar-content-dapp [contact-identity] (views/letsubs [contact [:contact-by-identity contact-identity]] [react/view styles/toolbar-content-dapp - [chat-icon.screen/dapp-icon-browser contact] + [chat-icon.screen/dapp-icon-browser contact 36] [react/view styles/dapp-name [react/text {:style styles/dapp-name-text :number-of-lines 1 @@ -26,14 +26,11 @@ [react/text {:style styles/dapp-text} (i18n/label :t/dapp)]]])) -(defn match-url [url] - (str (when (and url (not (re-find #"^[a-zA-Z-_]+:/" url))) "http://") url)) - (defn toolbar-content [{:keys [url] :as browser}] (let [url-text (atom nil)] [react/view (styles/toolbar-content false) [react/text-input {:on-change-text #(reset! url-text %) - :on-submit-editing #(re-frame/dispatch [:update-browser (assoc browser :url (match-url @url-text))]) + :on-submit-editing #(re-frame/dispatch [:update-browser (assoc browser :url @url-text)]) :auto-focus (not url) :placeholder (i18n/label :t/enter-url) :default-value url diff --git a/src/status_im/ui/screens/contacts/db.cljs b/src/status_im/ui/screens/contacts/db.cljs index 60c9084cc5..6c3a11e30b 100644 --- a/src/status_im/ui/screens/contacts/db.cljs +++ b/src/status_im/ui/screens/contacts/db.cljs @@ -1,14 +1,8 @@ (ns status-im.ui.screens.contacts.db (:require-macros [status-im.utils.db :refer [allowed-keys]]) (:require [cljs.spec.alpha :as spec] - status-im.utils.db [clojure.string :as string] - [status-im.data-store.contacts :as contacts])) - -(defn contact-can-be-added? [identity] - (if (contacts/exists? identity) - (:pending? (contacts/get-by-id identity)) - true)) + status-im.utils.db)) ;;;; DB @@ -90,7 +84,4 @@ ;used in modal list (for example for wallet) (spec/def :contacts/click-action (spec/nilable #{:send :request})) ;used in modal list (for example for wallet) -(spec/def :contacts/click-params (spec/nilable map?)) - - - +(spec/def :contacts/click-params (spec/nilable map?)) \ No newline at end of file diff --git a/src/status_im/ui/screens/contacts/events.cljs b/src/status_im/ui/screens/contacts/events.cljs index 90e14cce58..10964d260a 100644 --- a/src/status_im/ui/screens/contacts/events.cljs +++ b/src/status_im/ui/screens/contacts/events.cljs @@ -22,8 +22,9 @@ [status-im.chat.console :as console-chat] [status-im.commands.events.loading :as loading-events] [cljs.spec.alpha :as spec] - [status-im.protocol.web3.utils :as web3.utils])) - + [status-im.protocol.web3.utils :as web3.utils] + [status-im.ui.screens.add-new.new-chat.db :as new-chat.db] + [clojure.string :as string])) ;;;; COFX (reg-cofx @@ -146,22 +147,6 @@ (fn [{:keys [contacts]}] (dispatch (on-contacts-event-creator (add-identity contacts-by-hash contacts)))))))) -(reg-fx - ::request-contact-by-address - (fn [id] - (http-post "get-contacts-by-address" {:addresses [id]} - (fn [{:keys [contacts]}] - (if-let [contact (first contacts)] - (let [{:keys [whisper-identity]} contact - contact {:name (generate-gfy whisper-identity) - :address id - :photo-path (identicon whisper-identity) - :whisper-identity whisper-identity}] - (if (contacts/exists? whisper-identity) - (dispatch [:add-pending-contact-and-open-chat whisper-identity]) - (dispatch [:add-new-contact-and-open-chat contact]))) - (dispatch [:set :contacts/new-public-key-error (label :t/unknown-address)])))))) - ;;;; Handlers (register-handler-fx @@ -370,10 +355,13 @@ (update :db #(navigation/navigate-to-clean % :home)) (assoc :dispatch [:start-chat whisper-id {:navigation-replace? true}])))) -(register-handler-db +(register-handler-fx :set-contact-identity-from-qr - (fn [db [_ _ contact-identity]] - (assoc db :contacts/new-identity contact-identity))) + (fn [{{:accounts/keys [accounts current-account-id] :as db} :db} [_ _ contact-identity]] + (let [current-account (get accounts current-account-id)] + (cond-> {:db (assoc db :contacts/new-identity contact-identity)} + (not (new-chat.db/validate-pub-key contact-identity current-account)) + (assoc :dispatch [:add-contact-handler]))))) (register-handler-fx :contact-update-received @@ -443,9 +431,7 @@ (assoc :group/group-type group-type :group/selected-contacts #{} :new-chat-name "") - (assoc-in [:toolbar-search :show] nil) - (assoc-in [:toolbar-search :text] "") - (navigation/navigate-to-clean :contact-toggle-list))})) + (navigation/navigate-to :contact-toggle-list))})) (register-handler-fx :open-chat-with-contact @@ -457,11 +443,11 @@ (register-handler-fx :add-contact-handler - (fn [{:keys [db]} [_ id]] - (if (spec/valid? :global/address id) - {::request-contact-by-address id} - {:dispatch (if (get-in db [:contacts/contacts id]) - [:add-pending-contact-and-open-chat id] - [:add-new-contact-and-open-chat {:name (generate-gfy id) - :photo-path (identicon id) - :whisper-identity id}])}))) + (fn [{:keys [db]}] + (let [{:contacts/keys [new-identity]} db] + (when (and new-identity (not (string/blank? new-identity))) + {:dispatch (if (get-in db [:contacts/contacts new-identity]) + [:add-pending-contact-and-open-chat new-identity] + [:add-new-contact-and-open-chat {:name (generate-gfy new-identity) + :photo-path (identicon new-identity) + :whisper-identity new-identity}])})))) \ No newline at end of file diff --git a/src/status_im/ui/screens/contacts/new_contact/views.cljs b/src/status_im/ui/screens/contacts/new_contact/views.cljs deleted file mode 100644 index fd4c895478..0000000000 --- a/src/status_im/ui/screens/contacts/new_contact/views.cljs +++ /dev/null @@ -1,79 +0,0 @@ -(ns status-im.ui.screens.contacts.new-contact.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [re-frame.core :as re-frame] - [clojure.string :as string] - [cljs.spec.alpha :as s] - [status-im.ui.components.react :as react] - [status-im.ui.components.text-field.view :as text-field] - [status-im.ui.components.status-bar.view :as status-bar] - [status-im.ui.components.toolbar.view :as toolbar] - [status-im.ui.components.styles :as components.styles :refer [icon-ok button-input-container button-input color-blue]] - [status-im.ui.components.image-button.view :as scan-button] - [status-im.i18n :as i18n] - [status-im.ui.screens.contacts.db :as v] - [status-im.ui.screens.contacts.styles :as st] - [status-im.utils.hex :as hex] - [status-im.utils.platform :as platform])) - -(defn- validation-error-message - [whisper-identity {:keys [address public-key]} error] - (cond - (#{(hex/normalize-hex address) (hex/normalize-hex public-key)} - (hex/normalize-hex whisper-identity)) - (i18n/label :t/can-not-add-yourself) - - (not (s/valid? :global/public-key whisper-identity)) - (i18n/label :t/enter-valid-public-key) - - (not (v/contact-can-be-added? whisper-identity)) - (i18n/label :t/contact-already-added) - - :else error)) - -(defn- toolbar-actions [new-contact-identity account error] - (let [error-message (validation-error-message new-contact-identity account error)] - [{:icon :icons/ok - :icon-opts {:color (if (string/blank? error-message) - components.styles/color-blue4 - components.styles/color-gray11)} - :handler #(when (string/blank? error-message) - (re-frame/dispatch [:add-contact-handler new-contact-identity])) - :accessibility-label :confirm-button}])) - -(defview contact-whisper-id-input [whisper-identity error] - (letsubs [current-account [:get-current-account]] - (let [error (when-not (string/blank? whisper-identity) - (validation-error-message whisper-identity current-account error))] - [react/view button-input-container - [text-field/text-field - {:error error - :error-color color-blue - :input-style st/qr-input - :value whisper-identity - :wrapper-style button-input - :label (i18n/label :t/public-key) - :on-change-text #(do - (re-frame/dispatch [:set :contacts/new-identity %]) - (re-frame/dispatch [:set :contacts/new-public-key-error nil])) - :accessibility-label :public-key-input}] - [scan-button/scan-button {:show-label? (zero? (count whisper-identity)) - :handler #(re-frame/dispatch [:scan-qr-code - {:toolbar-title (i18n/label :t/new-contact)} - :set-contact-identity-from-qr])}]]))) - -(defview new-contact [] - (letsubs [new-contact-identity [:get :contacts/new-identity] - error [:get :contacts/new-public-key-error] - account [:get-current-account]] - [react/view st/contact-form-container - [status-bar/status-bar] - [toolbar/toolbar {} - toolbar/default-nav-back - [toolbar/content-title (i18n/label :t/add-new-contact)] - [toolbar/actions (toolbar-actions new-contact-identity account error)]] - [react/view st/form-container - [contact-whisper-id-input new-contact-identity error]] - [react/view st/address-explication-container - [react/text {:style st/address-explication - :font :default} - (i18n/label :t/address-explication)]]])) diff --git a/src/status_im/ui/screens/contacts/subs.cljs b/src/status_im/ui/screens/contacts/subs.cljs index cb415b0fbf..8b1520c183 100644 --- a/src/status_im/ui/screens/contacts/subs.cljs +++ b/src/status_im/ui/screens/contacts/subs.cljs @@ -33,6 +33,11 @@ (fn [contacts] (remove #(true? (:dapp? %)) contacts))) +(reg-sub :all-dapp-with-url-contacts + :<- [:all-added-contacts] + (fn [contacts] + (filter #(and (true? (:dapp? %)) (:dapp-url %)) contacts))) + (reg-sub :people-in-current-chat :<- [:current-chat-contacts] (fn [contacts] diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 87ebf78002..1738471079 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -15,7 +15,8 @@ status-im.ui.screens.discover.db status-im.ui.screens.network-settings.db status-im.ui.screens.offline-messaging-settings.db - status-im.ui.screens.browser.db)) + status-im.ui.screens.browser.db + status-im.ui.screens.add-new.db)) (def transaction-send-default {:symbol :ETH @@ -134,7 +135,8 @@ :inbox/topic :inbox/password :browser/browsers - :browser/options] + :browser/options + :new/open-dapp] :opt-un [::current-public-key ::modal diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 614622b256..9ebb394b3a 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -23,6 +23,7 @@ status-im.ui.screens.wallet.transactions.events status-im.ui.screens.wallet.choose-recipient.events status-im.ui.screens.browser.events + status-im.ui.screens.add-new.open-dapp.events [re-frame.core :as re-frame] [status-im.native-module.core :as status] [status-im.ui.components.react :as react] @@ -349,7 +350,7 @@ "local-storage" (re-frame/dispatch [:set-local-storage {:chat-id chat_id :data data}]) "show-suggestions" (re-frame/dispatch [:show-suggestions-from-jail {:chat-id chat_id - :markup data}]) + :markup data}]) "send-message" (re-frame/dispatch [:chat-send-message/from-jail {:chat-id chat_id :message data}]) "handler-result" (let [orig-params (:origParams data)] diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index d52a83611d..b34a67c0af 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -20,7 +20,7 @@ [toolbar/content-title (i18n/label :t/status)] [toolbar/actions (when platform/ios? - [(toolbar.actions/add #(re-frame/dispatch [:navigate-to :new-chat]))])]]) + [(toolbar.actions/add #(re-frame/dispatch [:navigate-to :new]))])]]) (defn home-action-button [] [native-action-button {:button-color components.styles/color-blue @@ -29,7 +29,7 @@ :spacing 13 :hide-shadow true :accessibility-label :plus-button - :on-press #(re-frame/dispatch [:navigate-to :new-chat])}]) + :on-press #(re-frame/dispatch [:navigate-to :new])}]) (defn home-list-item [[home-item-id home-item]] (if (:chat-id home-item) diff --git a/src/status_im/ui/screens/home/views/inner_item.cljs b/src/status_im/ui/screens/home/views/inner_item.cljs index 16b31da1c8..a1d511a0e2 100644 --- a/src/status_im/ui/screens/home/views/inner_item.cljs +++ b/src/status_im/ui/screens/home/views/inner_item.cljs @@ -123,7 +123,7 @@ [react/view styles/chat-container [react/view styles/chat-icon-container (if contact' - [chat-icon.screen/dapp-icon-browser contact'] + [chat-icon.screen/dapp-icon-browser contact' 36] [react/view styles/browser-icon-container [vector-icons/icon :icons/discover {:color component.styles/color-light-gray6}]])] [react/view styles/chat-info-container diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index df456234e4..6becc8d32f 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -16,7 +16,8 @@ status-im.ui.screens.wallet.transactions.subs status-im.ui.screens.network-settings.subs status-im.ui.screens.browser.subs - status-im.bots.subs)) + status-im.bots.subs + status-im.ui.screens.add-new.new-chat.subs)) (reg-sub :get (fn [db [_ k]] diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 1f7f886dbf..23b1eebcfd 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -12,11 +12,11 @@ [status-im.ui.screens.accounts.views :refer [accounts]] [status-im.chat.screen :refer [chat]] - [status-im.chat.new-chat.view :refer [new-chat]] + [status-im.ui.screens.add-new.views :refer [add-new]] + [status-im.ui.screens.add-new.new-chat.views :refer [new-chat]] [status-im.chat.new-public-chat.view :refer [new-public-chat]] [status-im.ui.screens.contacts.contact-list-modal.views :refer [contact-list-modal]] - [status-im.ui.screens.contacts.new-contact.views :refer [new-contact]] [status-im.ui.screens.qr-scanner.views :refer [qr-scanner]] @@ -53,7 +53,8 @@ [status-im.ui.screens.network-settings.add-rpc.views :refer [add-rpc-url]] [status-im.ui.screens.network-settings.network-details.views :refer [network-details]] [status-im.ui.screens.network-settings.parse-json.views :refer [paste-json-text]] - [status-im.ui.screens.browser.views :refer [browser]])) + [status-im.ui.screens.browser.views :refer [browser]] + [status-im.ui.screens.add-new.open-dapp.views :refer [open-dapp dapp-description]])) (defn validate-current-view [current-view signed-up?] @@ -135,6 +136,8 @@ (let [component (case current-view (:home :wallet :my-profile) main-tabs :browser browser + :open-dapp open-dapp + :dapp-description dapp-description :wallet-send-transaction send-transaction :wallet-transaction-sent transaction-sent :wallet-request-transaction request-transaction @@ -142,7 +145,7 @@ :wallet-transaction-details wallet-transactions/transaction-details :wallet-send-assets wallet.components/send-assets :wallet-request-assets wallet.components/request-assets - :new-chat new-chat + :new add-new :new-group new-group :edit-contact-group edit-contact-group :chat-group-settings chat-group-settings @@ -153,7 +156,7 @@ :new-public-chat new-public-chat :contact-toggle-list contact-toggle-list :reorder-groups reorder-groups - :new-contact new-contact + :new-chat new-chat :qr-scanner qr-scanner :chat chat :profile profile/profile diff --git a/test/cljs/status_im/test/contacts/events.cljs b/test/cljs/status_im/test/contacts/events.cljs index fb22b9c6cc..257085a5de 100644 --- a/test/cljs/status_im/test/contacts/events.cljs +++ b/test/cljs/status_im/test/contacts/events.cljs @@ -260,7 +260,8 @@ ;; :status-im.contacts.events/send-contact-request ;;TODO :start-chat - (rf/dispatch [:add-contact-handler new-contact-public-key]) + (rf/dispatch [:set :contacts/new-identity new-contact-public-key]) + (rf/dispatch [:add-contact-handler]) (testing "it returns the new contact from the contact-by-identity sub" (is (= new-contact (assoc @contact :photo-path "" :name "")))) @@ -353,8 +354,8 @@ (rf/dispatch [:set :view-id nil]) (rf/dispatch [:set :current-chat-id nil]) - - (rf/dispatch [:add-contact-handler new-contact-public-key]) + (rf/dispatch [:set :contacts/new-identity new-contact-public-key]) + (rf/dispatch [:add-contact-handler]) (testing "it sets the pending? flag to false" (is (= (assoc received-contact'' :pending? false)