🎉 Add component thumbnails

This commit is contained in:
Aitor 2023-09-14 15:57:21 +02:00 committed by Andrés Moya
parent 77964604fd
commit f639c73d03
4 changed files with 115 additions and 31 deletions

View file

@ -225,6 +225,10 @@
(fn [{:keys [id data] :as file}] (fn [{:keys [id data] :as file}]
(->> (resolve-file-data id data) (->> (resolve-file-data id data)
(rx/map (fn [data] (assoc file :data data)))))) (rx/map (fn [data] (assoc file :data data))))))
(rx/merge-map
(fn [{:keys [id] :as file}]
(->> (rp/cmd! :get-file-object-thumbnails {:file-id id})
(rx/map #(assoc file :thumbnails %)))))
(rx/reduce conj []) (rx/reduce conj [])
(rx/map libraries-fetched))) (rx/map libraries-fetched)))
(rx/of (with-meta (workspace-initialized) {:file-id id}))) (rx/of (with-meta (workspace-initialized) {:file-id id})))

View file

@ -33,6 +33,7 @@
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.main.features :as features] [app.main.features :as features]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -309,7 +310,10 @@
(when-not (empty? (:redo-changes changes)) (when-not (empty? (:redo-changes changes))
(rx/of (dch/commit-changes changes) (rx/of (dch/commit-changes changes)
(dws/select-shapes (d/ordered-set (:id root))) (dws/select-shapes (d/ordered-set (:id root)))
(ptk/data-event :layout/update parents))))))))) (ptk/data-event :layout/update parents)
(dwt/update-thumbnail file-id page-id (:id root))))))))))
(defn add-component (defn add-component
"Add a new component to current file library, from the currently selected shapes. "Add a new component to current file library, from the currently selected shapes.
@ -444,14 +448,17 @@
(let [data (get state :workspace-data)] (let [data (get state :workspace-data)]
(if (features/active-feature? state :components-v2) (if (features/active-feature? state :components-v2)
(let [component (ctkl/get-component data id) (let [component (ctkl/get-component data id)
page (ctf/get-component-page data component) page-id (:main-instance-page component)
shape (ctf/get-component-root data component)] root-id (:main-instance-id component)]
(rx/of (dwsh/delete-shapes (:id page) #{(:id shape)}))) ;; Deleting main root triggers component delete (rx/of
(dwt/clear-thumbnail (:current-file-id state) page-id root-id)
(dwsh/delete-shapes page-id #{root-id}))) ;; Deleting main root triggers component delete
(let [changes (-> (pcb/empty-changes it) (let [changes (-> (pcb/empty-changes it)
(pcb/with-library-data data) (pcb/with-library-data data)
(pcb/delete-component id))] (pcb/delete-component id))]
(rx/of (dch/commit-changes changes)))))))) (rx/of (dch/commit-changes changes))))))))
(defn restore-component (defn restore-component
"Restore a deleted component, with the given id, in the given file library." "Restore a deleted component, with the given id, in the given file library."
[library-id component-id] [library-id component-id]
@ -568,17 +575,24 @@
:query-params query-params})))))) :query-params query-params}))))))
(defn ext-library-changed (defn ext-library-changed
[file-id modified-at revn changes] [library-id modified-at revn changes]
(dm/assert! (uuid? file-id)) (dm/assert! (uuid? library-id))
(dm/assert! (ch/valid-changes? changes)) (dm/assert! (ch/valid-changes? changes))
(ptk/reify ::ext-library-changed (ptk/reify ::ext-library-changed
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(update-in [:workspace-libraries file-id] (update-in [:workspace-libraries library-id]
assoc :modified-at modified-at :revn revn) assoc :modified-at modified-at :revn revn)
(d/update-in-when [:workspace-libraries file-id :data] (d/update-in-when [:workspace-libraries library-id :data]
cp/process-changes changes))))) cp/process-changes changes)))
ptk/WatchEvent
(watch [_ _ _]
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id})
(rx/map (fn [thumbnails]
(fn [state]
(assoc-in state [:workspace-libraries library-id :thumbnails] thumbnails))))))))
(defn reset-component (defn reset-component
"Cancels all modifications in the shape with the given id, and all its children, in "Cancels all modifications in the shape with the given id, and all its children, in
@ -710,6 +724,23 @@
(sync-file file-id file-id :components component-id undo-group)) (sync-file file-id file-id :components component-id undo-group))
(dwu/commit-undo-transaction undo-id))))))) (dwu/commit-undo-transaction undo-id)))))))
(defn update-component-thumbnail
"Update the thumbnail of the component with the given id, in the
current file and in the imported libraries."
[component-id file-id]
(ptk/reify ::update-component-thumbnail
ptk/WatchEvent
(watch [_ state _]
(let [data (get state :workspace-data)
component (ctkl/get-component data component-id)
page-id (:main-instance-page component)
root-id (:main-instance-id component)
current-file-id (:current-file-id state)]
(rx/of
(dwt/update-thumbnail current-file-id page-id root-id)
(when (not= current-file-id file-id)
(dwt/update-thumbnail file-id page-id root-id)))))))
(defn update-component-in-bulk (defn update-component-in-bulk
[shapes file-id] [shapes file-id]
(ptk/reify ::update-component-in-bulk (ptk/reify ::update-component-in-bulk
@ -866,6 +897,17 @@
:callback do-dismiss}] :callback do-dismiss}]
:tag :sync-dialog))))))) :tag :sync-dialog)))))))
(defn component-changed
"Notify that the component with the given id has changed, so it needs to be updated
in the current file and in the copies. And also update its thumbnails."
[component-id file-id undo-group]
(ptk/reify ::component-changed
ptk/WatchEvent
(watch [_ _ _]
(rx/of
(launch-component-sync component-id file-id undo-group)
(update-component-thumbnail component-id file-id)))))
(defn watch-component-changes (defn watch-component-changes
"Watch the state for changes that affect to any main instance. If a change is detected will throw "Watch the state for changes that affect to any main instance. If a change is detected will throw
an update-component-sync, so changes are immediately propagated to the component and copies." an update-component-sync, so changes are immediately propagated to the component and copies."
@ -912,7 +954,7 @@
:undo-group undo-group) :undo-group undo-group)
(->> changed-components (->> changed-components
(map #(launch-component-sync % (:id old-data) undo-group)) (map #(component-changed % (:id old-data) undo-group))
(run! st/emit!))))))] (run! st/emit!))))))]
(when components-v2? (when components-v2?
@ -986,7 +1028,11 @@
(->> (rp/cmd! :get-file {:id library-id :features features}) (->> (rp/cmd! :get-file {:id library-id :features features})
(rx/map (fn [file] (rx/map (fn [file]
(fn [state] (fn [state]
(assoc-in state [:workspace-libraries library-id] file)))))))))) (assoc-in state [:workspace-libraries library-id] file)))))
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id})
(rx/map (fn [thumbnails]
(fn [state]
(assoc-in state [:workspace-libraries library-id :thumbnails] thumbnails))))))))))
(defn unlink-file-from-library (defn unlink-file-from-library
[file-id library-id] [file-id library-id]

View file

@ -47,7 +47,7 @@
(rx/tap #(l/dbg :hint "thumbnail rendered" (rx/tap #(l/dbg :hint "thumbnail rendered"
:elapsed (dm/str (tp) "ms")))))) :elapsed (dm/str (tp) "ms"))))))
(defn- clear-thumbnail (defn clear-thumbnail
([file-id page-id frame-id] ([file-id page-id frame-id]
(clear-thumbnail file-id (fmt-object-id file-id page-id frame-id))) (clear-thumbnail file-id (fmt-object-id file-id page-id frame-id)))
([file-id object-id] ([file-id object-id]

View file

@ -17,6 +17,7 @@
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.media :as dwm] [app.main.data.workspace.media :as dwm]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.render :refer [component-svg]] [app.main.render :refer [component-svg]]
@ -45,11 +46,40 @@
(if components-v2 (if components-v2
(ctf/get-component-page data component) (ctf/get-component-page data component)
component)]) component)])
(let [data (dm/get-in @refs/workspace-libraries [file-id :data])] (let [data (dm/get-in @refs/workspace-libraries [file-id :data])
[(ctf/get-component-root data component) root-shape (ctf/get-component-root data component)
(if components-v2 container (if components-v2
(ctf/get-component-page data component) (ctf/get-component-page data component)
component)]))) component)]
[root-shape container])))
(defn- get-component-thumbnail-uri
"Returns the component thumbnail uri"
[file-id component]
(let [page-id (:main-instance-page component)
root-id (:main-instance-id component)
object-id (dwt/fmt-object-id file-id page-id root-id)]
(if (= file-id (:id @refs/workspace-file))
(mf/deref (refs/workspace-thumbnail-by-id object-id))
(let [thumbnails (dm/get-in @refs/workspace-libraries [file-id :thumbnails (dm/str object-id)])]
thumbnails))))
(mf/defc component-item-thumbnail
"Component that renders the thumbnail image or the original SVG."
{::mf/wrap-props false}
[{:keys [file-id root-shape component container]}]
(let [retry (mf/use-state 0)
thumbnail-uri (get-component-thumbnail-uri file-id component)]
(if (some? thumbnail-uri)
[:img {:src thumbnail-uri
:on-error (fn []
(when (@retry < 3)
(inc retry)))
:loading "lazy"
:decoding "async"
:class (dom/classnames (css :thumbnail) true)}]
[:& component-svg {:root-shape root-shape
:objects (:objects container)}])))
(mf/defc components-item (mf/defc components-item
{::mf/wrap-props false} {::mf/wrap-props false}
@ -144,8 +174,10 @@
(when (and (some? root-shape) (when (and (some? root-shape)
(some? container)) (some? container))
[:* [:*
[:& component-svg {:root-shape root-shape [:& component-item-thumbnail {:file-id file-id
:objects (:objects container)}] :root-shape root-shape
:component component
:container container}]
(let [renaming? (= renaming (:id component))] (let [renaming? (= renaming (:id component))]
[:* [:*
[:& editable-label [:& editable-label
@ -184,8 +216,10 @@
(some? container)) (some? container))
[:* [:*
(when visible? (when visible?
[:& component-svg {:root-shape root-shape [:& component-item-thumbnail {:file-id file-id
:objects (:objects container)}]) :root-shape root-shape
:component component
:container container}])
(let [renaming? (= renaming (:id component))] (let [renaming? (= renaming (:id component))]
[:* [:*
[:& editable-label [:& editable-label