🐛 Fix problems when dragging frame with comments (#10460)

* 🐛 Fix undo frame position not undoing comments

* 🐛 Fix problem with hover capturing dragging event

* 🐛 Fix watch updates for comment bubbles

* 🐛 Fix "Maximum update depth" crash on SVG shape transforms

* 🐛 Fix comment geometry problems
This commit is contained in:
Alonso Torres
2026-06-30 13:33:47 +02:00
committed by GitHub
parent 21f646aeee
commit ca81776d04
10 changed files with 341 additions and 91 deletions
@@ -355,11 +355,15 @@
(defn has-point?
[shape point]
(if (or ^boolean (cfh/path-shape? shape)
^boolean (cfh/bool-shape? shape)
^boolean (cfh/circle-shape? shape))
(slow-has-point? shape point)
(fast-has-point? shape point)))
(let [rotation (dm/get-prop shape :rotation)]
;; Rotated shapes don't match their axis-aligned box, so use the polygon test.
(if (or ^boolean (cfh/path-shape? shape)
^boolean (cfh/bool-shape? shape)
^boolean (cfh/circle-shape? shape)
(and (some? rotation)
(not ^boolean (mth/almost-zero? rotation))))
(slow-has-point? shape point)
(fast-has-point? shape point))))
(defn rect-contains-shape?
[rect shape]
@@ -8,6 +8,8 @@
(:require
[app.common.features :as ffeat]
[app.common.files.changes :as ch]
[app.common.files.changes-builder :as pcb]
[app.common.geom.point :as gpt]
[app.common.schema :as sm]
[app.common.schema.generators :as sg]
[app.common.schema.test :as smt]
@@ -736,6 +738,55 @@
{:num 1000})))
(t/deftest set-comment-thread-position
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
thread-id (uuid/custom 3 1)
frame-id (uuid/custom 4 1)
data (make-file-data file-id page-id)]
(t/testing "stores position and frame-id"
(let [change {:type :set-comment-thread-position
:page-id page-id
:comment-thread-id thread-id
:frame-id frame-id
:position (gpt/point 10 20)}
res (ch/process-changes data [change])]
(t/is (= {:frame-id frame-id :position (gpt/point 10 20)}
(get-in res [:pages-index page-id :comment-thread-positions thread-id])))))
(t/testing "removes the position when frame-id and position are nil"
(let [data (ch/process-changes data [{:type :set-comment-thread-position
:page-id page-id
:comment-thread-id thread-id
:frame-id frame-id
:position (gpt/point 10 20)}])
res (ch/process-changes data [{:type :set-comment-thread-position
:page-id page-id
:comment-thread-id thread-id
:frame-id nil
:position nil}])]
(t/is (nil? (get-in res [:pages-index page-id :comment-thread-positions thread-id])))))
(t/testing "builder round-trips the position through undo and redo"
(let [data (ch/process-changes data [{:type :set-comment-thread-position
:page-id page-id
:comment-thread-id thread-id
:frame-id frame-id
:position (gpt/point 10 20)}])
page (get-in data [:pages-index page-id])
changes (-> (pcb/empty-changes)
(pcb/with-page page)
(pcb/set-comment-thread-position {:id thread-id
:frame-id frame-id
:position (gpt/point 100 200)}))
redone (ch/process-changes data (:redo-changes changes))
undone (ch/process-changes redone (:undo-changes changes))]
(t/is (= (gpt/point 100 200)
(get-in redone [:pages-index page-id :comment-thread-positions thread-id :position])))
(t/is (= (gpt/point 10 20)
(get-in undone [:pages-index page-id :comment-thread-positions thread-id :position])))))))
(t/deftest set-plugin-data-json-encode-decode
(let [schema ch/schema:set-plugin-data-change
encode (sm/encoder schema (sm/json-transformer))
@@ -254,3 +254,19 @@
shape {:points points}]
(t/is (true? (gint/slow-has-point? shape (pt 50 25))))
(t/is (false? (gint/slow-has-point? shape (pt 150 25)))))))
(t/deftest has-point-rotated-test
;; Diamond (a square rotated 45º); its axis-aligned x/y/width/height box does
;; not match the rotated polygon.
(let [points [(pt 50 0) (pt 100 50) (pt 50 100) (pt 0 50)]
shape {:x 20 :y 20 :width 60 :height 60 :rotation 45 :points points}]
(t/testing "point inside the polygon but outside the box is contained"
(t/is (true? (gint/has-point? shape (pt 50 5)))))
(t/testing "point inside the box but outside the polygon is not contained"
(t/is (false? (gint/has-point? shape (pt 22 22)))))))
(t/deftest has-point-axis-aligned-test
(let [shape {:x 10 :y 20 :width 100 :height 50 :rotation 0}]
(t/testing "unrotated shape uses the axis-aligned box"
(t/is (true? (gint/has-point? shape (pt 50 40))))
(t/is (false? (gint/has-point? shape (pt 200 40)))))))