[#6644] Chat command recipients should be able to install an extension
Signed-off-by: Julien Eluard <julien.eluard@gmail.com>
This commit is contained in:
parent
37ef82b04d
commit
582c2960ec
2
deps.edn
2
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"}}
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]))
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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])}}
|
||||
: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 ", "))})}})))
|
||||
|
|
|
@ -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])))
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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)})
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue