diff --git a/deps.edn b/deps.edn index d65ce6af1c..c27e196821 100644 --- a/deps.edn +++ b/deps.edn @@ -11,7 +11,7 @@ com.taoensso/timbre {:mvn/version "4.10.0"} hickory {:mvn/version "0.7.1"} com.cognitect/transit-cljs {:mvn/version "0.8.248"} - status-im/pluto {:mvn/version "iteration-4-4"} + status-im/pluto {:mvn/version "iteration-4-5"} mvxcvi/alphabase {:mvn/version "1.0.0"} rasom/cljs-react-navigation {:mvn/version "0.1.4"}} diff --git a/project.clj b/project.clj index e95c21f8da..1de59c1f50 100644 --- a/project.clj +++ b/project.clj @@ -11,7 +11,7 @@ [com.taoensso/timbre "4.10.0"] [hickory "0.7.1"] [com.cognitect/transit-cljs "0.8.248"] - [status-im/pluto "iteration-4-4"] + [status-im/pluto "iteration-4-5"] [mvxcvi/alphabase "1.0.0"] [rasom/cljs-react-navigation "0.1.4"]] :plugins [[lein-cljsbuild "1.1.7"] diff --git a/src/status_im/chat/commands/core.cljs b/src/status_im/chat/commands/core.cljs index 9ce16643e8..95c82fefdc 100644 --- a/src/status_im/chat/commands/core.cljs +++ b/src/status_im/chat/commands/core.cljs @@ -127,7 +127,8 @@ :suggestions? :view}]} :hook (reify hooks/Hook - (hook-in [_ id {:keys [description scope parameters preview short-preview on-send on-receive on-send-sync]} cofx] + (hook-in [_ id {extension-id :id} {:keys [description scope parameters preview short-preview + on-send on-receive on-send-sync]} cofx] (let [new-command (if on-send-sync (reify protocol/Command (id [_] (name id)) @@ -140,7 +141,9 @@ (short-preview [_ props] (short-preview props)) (preview [_ props] (preview props)) protocol/Yielding - (yield-control [_ props _] {:dispatch (on-send-sync props)})) + (yield-control [_ props _] {:dispatch (on-send-sync props)}) + protocol/Extension + (extension-id [_] extension-id)) (reify protocol/Command (id [_] (name id)) (scope [_] scope) @@ -150,9 +153,11 @@ (on-send [_ command-message _] (when on-send {:dispatch (on-send command-message)})) (on-receive [_ command-message _] (when on-receive {:dispatch (on-receive command-message)})) (short-preview [_ props] (short-preview props)) - (preview [_ props] (preview props))))] + (preview [_ props] (preview props)) + protocol/Extension + (extension-id [_] extension-id)))] (load-commands cofx [new-command]))) - (unhook [_ id {:keys [scope]} {:keys [db] :as cofx}] + (unhook [_ id _ {:keys [scope]} {:keys [db] :as cofx}] (remove-command (get-in db [:id->command [(name id) scope] :type]) cofx)))}) (handlers/register-handler-fx diff --git a/src/status_im/chat/commands/protocol.cljs b/src/status_im/chat/commands/protocol.cljs index 50c5ba9966..d29c4cca43 100644 --- a/src/status_im/chat/commands/protocol.cljs +++ b/src/status_im/chat/commands/protocol.cljs @@ -68,3 +68,7 @@ "Function which takes original parameters + cofx map and returns new map of parameters") (enhance-receive-parameters [this parameters cofx] "Function which takes original parameters + cofx map and returns new map of parameters")) + +(defprotocol Extension + "Protocol for defining extension" + (extension-id [this])) \ No newline at end of file diff --git a/src/status_im/chat/commands/sending.cljs b/src/status_im/chat/commands/sending.cljs index b1859910c9..8190e4ffa9 100644 --- a/src/status_im/chat/commands/sending.cljs +++ b/src/status_im/chat/commands/sending.cljs @@ -12,12 +12,15 @@ [chat-id type parameter-map cofx] (let [command-path (commands/command-id type) new-parameter-map (and (satisfies? protocol/EnhancedParameters type) - (protocol/enhance-send-parameters type parameter-map cofx))] + (protocol/enhance-send-parameters type parameter-map cofx)) + params (merge (or new-parameter-map parameter-map) + (when (satisfies? protocol/Extension type) + {:extension-id (protocol/extension-id type)}))] {:chat-id chat-id :content-type constants/content-type-command :content {:chat-id chat-id :command-path command-path - :params (or new-parameter-map parameter-map)}})) + :params params}})) (fx/defn validate-and-send "Validates and sends command in current chat" diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 1e0211ad83..32642ad3c8 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -512,13 +512,19 @@ (handlers/register-handler-fx :extensions.ui/show-button-pressed (fn [cofx [_ url]] - (extensions.registry/load cofx url))) + (extensions.registry/load cofx url false))) + +(handlers/register-handler-fx + :extensions.ui/install-extension-button-pressed + (fn [{:keys [db] :as cofx} [_ url]] + (fx/merge cofx + {:db (assoc-in db [:extensions/manage :url :value] url)} + (extensions.registry/load url true)))) (handlers/register-handler-fx :extensions.ui/install-button-pressed - [(re-frame/inject-cofx :random-id-generator)] - (fn [cofx [_ data]] - (extensions.registry/install cofx data))) + (fn [cofx [_ data modal?]] + (extensions.registry/install cofx data modal?))) ;; log-level module diff --git a/src/status_im/extensions/registry.cljs b/src/status_im/extensions/registry.cljs index 510a12b8c5..9bf002258a 100644 --- a/src/status_im/extensions/registry.cljs +++ b/src/status_im/extensions/registry.cljs @@ -6,35 +6,36 @@ [status-im.accounts.update.core :as accounts.update] [status-im.i18n :as i18n] [status-im.utils.fx :as fx] - [clojure.set :as set])) + [clojure.set :as set] + [status-im.ui.screens.navigation :as navigation])) (fx/defn update-hooks - [{:keys [db] :as cofx} hook-fn extension-key] + [{:keys [db] :as cofx} hook-fn extension-id] (let [account (get db :account/account) - hooks (get-in account [:extensions extension-key :hooks])] + hooks (get-in account [:extensions extension-id :hooks])] (apply fx/merge cofx (mapcat (fn [[_ extension-hooks]] (map (fn [[hook-id {:keys [hook-ref parsed]}]] - (partial hook-fn (:hook hook-ref) hook-id parsed)) + (partial hook-fn (:hook hook-ref) hook-id {:id extension-id} parsed)) extension-hooks)) hooks)))) (fx/defn add-to-registry - [{:keys [db] :as cofx} extension-key extension-data active?] + [{:keys [db] :as cofx} extension-id extension-data active?] (let [{:keys [hooks]} extension-data data {:hooks hooks :active? active?}] (fx/merge cofx - {:db (update-in db [:account/account :extensions extension-key] merge data)} - (update-hooks hooks/hook-in extension-key)))) + {:db (update-in db [:account/account :extensions extension-id] merge data)} + (update-hooks hooks/hook-in extension-id)))) (fx/defn remove-from-registry - [cofx extension-key] + [cofx extension-id] (let [extensions (get-in cofx [:db :account/account :extensions])] (fx/merge cofx - (when (get-in extensions [extension-key :active?]) - (update-hooks hooks/unhook extension-key)) - {:db (update-in cofx [:db :account/account :extensions] dissoc extension-key)}))) + (when (get-in extensions [extension-id :active?]) + (update-hooks hooks/unhook extension-id)) + {:db (update-in cofx [:db :account/account :extensions] dissoc extension-id)}))) (fx/defn change-state [cofx extension-key active?] @@ -48,21 +49,23 @@ (update-hooks hook-fn extension-key)))) (fx/defn install - [{:keys [db] :as cofx} {:keys [hooks] :as extension-data}] + [{:keys [db] :as cofx} {:keys [hooks] :as extension-data} modal?] (let [{:extensions/keys [manage] :account/keys [account]} db - {:keys [url]} manage - extension {:id (:value url) + url (get-in manage [:url :value]) + extension {:id url :name (get-in extension-data ['meta :name]) - :url (:value url) + :url url :active? true} - new-extensions (assoc (:extensions account) (:url extension) extension)] + new-extensions (assoc (:extensions account) url extension)] (fx/merge cofx - {:utils/show-popup {:title (i18n/label :t/success) - :content (i18n/label :t/extension-installed) - :on-dismiss #(re-frame/dispatch [:navigate-to-clean :my-profile])}} + {:utils/show-popup {:title (i18n/label :t/success) + :content (i18n/label :t/extension-installed) + :on-dismiss #(re-frame/dispatch (if modal? + [:navigate-back] + [:navigate-to-clean :my-profile]))}} (when hooks (accounts.update/account-update {:extensions new-extensions} {})) - (when hooks (add-to-registry (:value url) extension-data true))))) + (when hooks (add-to-registry url extension-data true))))) (fx/defn uninstall [{:keys [db] :as cofx} extension-key] @@ -75,13 +78,13 @@ (accounts.update/account-update {:extensions new-extensions} {})))) (fx/defn load - [cofx url] + [cofx url modal?] (if (get-in cofx [:db :account/account :extensions url]) {:utils/show-popup {:title (i18n/label :t/error) :content (i18n/label :t/extension-is-already-added)}} {:extensions/load {:extensions [{:url (string/trim url) :active? true}] - :follow-up :extensions/stage}})) + :follow-up (if modal? :extensions/stage-modal :extensions/stage)}})) (fx/defn initialize [{{:account/keys [account]} :db}] @@ -108,3 +111,15 @@ (keys) (map #(existing-hooks-for % cofx extension-data)) (apply set/union))) + +(fx/defn stage-extension [{:keys [db] :as cofx} extension-data modal?] + (let [hooks (existing-hooks cofx extension-data)] + (if (empty? hooks) + (fx/merge cofx + {:db (assoc db :staged-extension extension-data)} + (navigation/navigate-to-cofx (if modal? :show-extension-modal :show-extension) nil)) + {:utils/show-popup {:title (i18n/label :t/error) + :content (i18n/label :t/extension-hooks-cannot-be-added + {:hooks (->> hooks + (map name) + (clojure.string/join ", "))})}}))) diff --git a/src/status_im/ui/components/toolbar/view.cljs b/src/status_im/ui/components/toolbar/view.cljs index fab0ef3284..74459c39d2 100644 --- a/src/status_im/ui/components/toolbar/view.cljs +++ b/src/status_im/ui/components/toolbar/view.cljs @@ -53,6 +53,7 @@ (nav-text (merge props styles/item-text-white-background) text))) (def default-nav-back [nav-button actions/default-back]) +(def default-nav-close [nav-button actions/default-close]) (defn nav-back-count ([] @@ -160,4 +161,5 @@ (defn simple-toolbar "A simple toolbar composed of a nav-back item and a single line title." ([] (simple-toolbar nil)) - ([title] (toolbar nil default-nav-back [content-title title]))) + ([title] (simple-toolbar title false)) + ([title modal?] (toolbar nil (if modal? default-nav-close default-nav-back) [content-title title]))) diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index 7960d65b82..57ee59b8c2 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -1,9 +1,7 @@ (ns status-im.ui.screens.chat.message.message (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [re-frame.core :as re-frame] - [reagent.core :as reagent] [status-im.ui.components.react :as react] - [status-im.ui.components.animation :as animation] [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.action-sheet :as action-sheet] @@ -12,22 +10,31 @@ [status-im.ui.screens.chat.styles.message.message :as style] [status-im.ui.screens.chat.photos :as photos] [status-im.constants :as constants] - [status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [status-im.utils.core :as utils] [status-im.ui.screens.chat.utils :as chat.utils] [status-im.utils.identicon :as identicon] - [status-im.utils.gfycat.core :as gfycat] [status-im.utils.platform :as platform] [status-im.i18n :as i18n] [status-im.ui.components.colors :as colors] - [clojure.string :as string])) + [status-im.ui.components.icons.vector-icons :as icons])) + +(defn install-extension-message [extension-id outgoing] + [react/touchable-highlight {:on-press #(re-frame/dispatch + [:extensions.ui/install-extension-button-pressed extension-id])} + [react/view style/extension-container + [icons/icon :icons/info {:color (if outgoing colors/white colors/gray)}] + [react/text {:style (style/extension-text outgoing)} + (i18n/label :to-see-this-message)] + [react/text {:style (style/extension-install outgoing)} + (i18n/label :install-the-extension)]]]) (defview message-content-command [command-message] (letsubs [id->command [:chats/id->command]] (if-let [command (commands-receiving/lookup-command-by-ref command-message id->command)] (commands/generate-preview command command-message) - [react/text (str "Unhandled command: " (-> command-message :content :command-path first))]))) + (if-let [extension-id (get-in command-message [:content :params :extension-id])] + [install-extension-message extension-id (:outgoing command-message)] + [react/text (str "Unhandled command: " (-> command-message :content :command-path first))])))) (defview message-timestamp [t justify-timestamp? outgoing command? content] (when-not command? diff --git a/src/status_im/ui/screens/chat/styles/message/message.cljs b/src/status_im/ui/screens/chat/styles/message/message.cljs index 353e70f8c4..877f374425 100644 --- a/src/status_im/ui/screens/chat/styles/message/message.cljs +++ b/src/status_im/ui/screens/chat/styles/message/message.cljs @@ -198,3 +198,17 @@ :color (if outgoing colors/wild-blue-yonder colors/gray)}) + +(def extension-container + {:align-items :center + :margin 10}) + +(defn extension-text [outgoing] + {:font-size 12 + :margin-top 10 + :color (if outgoing colors/white-transparent colors/gray)}) + +(defn extension-install [outgoing] + {:font-size 12 + :color (if outgoing colors/white colors/blue)}) + diff --git a/src/status_im/ui/screens/extensions/add/events.cljs b/src/status_im/ui/screens/extensions/add/events.cljs index a17a20e17b..8dee276a2c 100644 --- a/src/status_im/ui/screens/extensions/add/events.cljs +++ b/src/status_im/ui/screens/extensions/add/events.cljs @@ -15,17 +15,13 @@ (handlers/register-handler-fx :extensions/stage - (fn [{:keys [db] :as cofx} [_ _ extension-data]] - (let [hooks (extensions.registry/existing-hooks cofx extension-data)] - (if (empty? hooks) - (fx/merge cofx - {:db (assoc db :staged-extension extension-data)} - (navigation/navigate-to-cofx :show-extension nil)) - {:utils/show-popup {:title (i18n/label :t/error) - :content (i18n/label :t/extension-hooks-cannot-be-added - {:hooks (->> hooks - (map name) - (clojure.string/join ", "))})}})))) + (fn [cofx [_ _ extension-data]] + (extensions.registry/stage-extension cofx extension-data false))) + +(handlers/register-handler-fx + :extensions/stage-modal + (fn [cofx [_ _ extension-data]] + (extensions.registry/stage-extension cofx extension-data true))) (handlers/register-handler-fx :extensions/add-to-registry diff --git a/src/status_im/ui/screens/extensions/add/views.cljs b/src/status_im/ui/screens/extensions/add/views.cljs index 7a719b167c..e492617e73 100644 --- a/src/status_im/ui/screens/extensions/add/views.cljs +++ b/src/status_im/ui/screens/extensions/add/views.cljs @@ -30,13 +30,13 @@ values)) hooks)) -(views/defview show-extension [] +(views/defview show-extension-base [modal?] (views/letsubs [{:keys [data errors]} [:get-staged-extension]] (if data [react/view styles/screen [status-bar/status-bar] [react/keyboard-avoiding-view components.styles/flex - [toolbar/simple-toolbar (i18n/label :t/extension)] + [toolbar/simple-toolbar (i18n/label :t/extension) modal?] [react/scroll-view {:keyboard-should-persist-taps :handled} [react/view styles/wrapper [react/view {:style {:border-radius 8 :margin 10 :padding 8 :background-color colors/red}} @@ -71,7 +71,7 @@ {:forward? true :label (i18n/label :t/install) :disabled? (not (empty? errors)) - :on-press #(re-frame/dispatch [:extensions.ui/install-button-pressed data])}]]]] + :on-press #(re-frame/dispatch [:extensions.ui/install-button-pressed data modal?])}]]]] [react/view styles/screen [status-bar/status-bar] [react/view {:flex 1} @@ -80,6 +80,12 @@ [react/text (i18n/label :t/invalid-extension)] [react/text (str errors)]]]]))) +(views/defview show-extension [] + [show-extension-base false]) + +(views/defview show-extension-modal [] + [show-extension-base true]) + (def qr-code [react/touchable-highlight {:on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed {:toolbar-title (i18n/label :t/scan-qr)} diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index c46f227966..a5dad6af38 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -47,7 +47,7 @@ [status-im.ui.screens.fleet-settings.views :refer [fleet-settings]] [status-im.ui.screens.offline-messaging-settings.views :refer [offline-messaging-settings]] [status-im.ui.screens.offline-messaging-settings.edit-mailserver.views :refer [edit-mailserver]] - [status-im.ui.screens.extensions.add.views :refer [edit-extension show-extension]] + [status-im.ui.screens.extensions.add.views :refer [edit-extension show-extension show-extension-modal]] [status-im.ui.screens.bootnodes-settings.views :refer [bootnodes-settings]] [status-im.ui.screens.pairing.views :refer [installations]] [status-im.ui.screens.bootnodes-settings.edit-bootnode.views :refer [edit-bootnode]] @@ -177,6 +177,9 @@ :chat-modal (wrap-modal :chat-modal chat-modal) + :show-extension-modal + (wrap-modal :show-extension-modal show-extension-modal) + :wallet-send-modal-stack {:screens {:wallet-send-transaction-modal diff --git a/src/status_im/ui/screens/wallet/settings/views.cljs b/src/status_im/ui/screens/wallet/settings/views.cljs index 6b27869272..bc13689091 100644 --- a/src/status_im/ui/screens/wallet/settings/views.cljs +++ b/src/status_im/ui/screens/wallet/settings/views.cljs @@ -21,9 +21,9 @@ :on-click? :event} :hook (reify hooks/Hook - (hook-in [_ id {:keys [label view on-click]} {:keys [db]}] + (hook-in [_ id env {:keys [label view on-click]} {:keys [db]}] {:db (assoc-in db [:wallet :settings id] {:label label :view view :on-click on-click})}) - (unhook [_ id _ {:keys [db]}] + (unhook [_ id env _ {:keys [db]}] {:db (update-in db [:wallet :settings] dissoc id)}))}) (defn- render-token [{:keys [symbol name icon]} visible-tokens] diff --git a/src/status_im/utils/universal_links/core.cljs b/src/status_im/utils/universal_links/core.cljs index a09a757bcf..9fe8276da1 100644 --- a/src/status_im/utils/universal_links/core.cljs +++ b/src/status_im/utils/universal_links/core.cljs @@ -72,7 +72,7 @@ (fx/defn handle-extension [cofx url] (log/info "universal-links: handling url profile" url) - (extensions.registry/load cofx url)) + (extensions.registry/load cofx url false)) (defn handle-not-found [full-url] (log/info "universal-links: no handler for " full-url)) diff --git a/translations/en.json b/translations/en.json index 1ee6355661..a8d4c5f94b 100644 --- a/translations/en.json +++ b/translations/en.json @@ -780,9 +780,11 @@ "share-dapp-text": "Check out this DApp I'm using on Status: {{link}}", "network-invalid-url": "Network URL is invalid", "network-invalid-status-code": "Invalid status code: {{code}}", - "extension-is-already-added": "The extension is already added", + "extension-is-already-added": "The extension is already installed", "extension-uninstalled": "The extension was uninstalled", "extension-hooks-cannot-be-added": "The following hooks from this extension cannot be added: {{hooks}}", + "to-see-this-message": "To see this message,", + "install-the-extension": "install the extension", "migrations-failed-title": "Migration failed", "migrations-failed-content": "{{message}}\n\nPlease let us know about this problem at #status public chat. If you press \"Cancel\" button, nothing will happen. If you press \"{{erase-accounts-data-button-text}}\" button, account's db will be removed and you will be able to unlock account. All account's data will be lost.", "migrations-erase-accounts-data-button": "Erase account's db"