Commit Graph
494 Commits
Author SHA1 Message Date
BFlat 4a0bd79797 Merge pull request #1488 from ChristopherLinnett/issue/1086-image-validation
fix(collab): image entries must match their hash and sane bounds (#1086)
2026-10-29 09:49:20 +07:00
BFlat cff1d0bf45 Merge pull request #1487 from ChristopherLinnett/issue/1096-openurl-gesture
fix(present): prototype links open only behind the notice or a viewer's click (#1096)
2026-10-29 09:30:04 +07:00
Christopher Linnett 949d74f7ca fix(collab): image checks keep documents shareable and history replayable (#1086)
- The entry size cap is figcraft_doc::ImageData::MAX_BYTES (256 MiB), the
  cap the .fig, .sketch and REST importers already read images with (now
  one constant), instead of 32 MiB: an imported image larger than 32 MiB
  made the document unjoinable and its server snapshot unrestorable.
- History written before the checks (a restored or joined snapshot, a
  replayed server log, a file published to a server) applies without the
  image entries they refuse (docprops::without_refused_images), instead of
  the file not opening or a restart dropping every edit after the image.
- A key that already holds an image can't be given other bytes: producers
  key images by their bytes (the REST importer's placeholder keys always
  hold the same picture), and merge treats a key's image as never
  changing.
- REST import: an unresolved imageRef shaped like a content hash shares
  the rest-image-missing placeholder (the placeholder's bytes don't hash to
  it); ImageData::claims_content_hash is shared with collab.
- Tests: collab image_tests (4 new, size test uses a small cap), format
  image_tests (1 new).
- Docs: collab-protocol.md, collaboration-parity.md, file-format-parity.md.
2026-10-29 08:55:03 +08:00
Christopher Linnett 53f47706ec fix(present): prototype links open only behind the notice or a viewer's click (#1096)
An Open link action carries a URL from the document and fires from whatever
trigger the prototype sets, so an unattended presentation could open web links
and mail messages one after another: a mail link bypassed the leaving-the-
prototype notice entirely, and a skipped notice let any trigger open any
number of links.

- finish() routes every openable URL, mail included, through the notice.
- Skipping the notice ("Don't show this again") opens at once only a link the
  viewer's own click, press, drag or key fired, one per frame. A delay, the
  pointer passing over a layer (enter, leave, hover) and a timed mouse
  trigger that fires after the gesture is over still show the notice, which
  then offers no checkbox: it couldn't skip that notice anyway.
- The player tags each queued link with whether the viewer fired it
  (Presenter::fire_from); an OpenUrl outside an interaction defaults to not.
- The notice covers mail links (new locale string, mail wording).
- Engine prefs/command doc text follows the rule; behavior untouched there.
- present_links_tests: shared setup helpers for the link tests; new
  tests for the skip rule (delay, hover, delayed mouse-up, key, one link per
  click, checkbox only for clicked links); the scheme-filter test now clicks
  with the notice skipped so the filter alone keeps those URLs out.
- docs/prototyping-parity.md row, status line and revision history updated.
2026-10-29 08:11:13 +08:00
Filip StrajnarandClaude Opus 5.5 652bf35b19 M1: page ruler guides survive save and reopen (#1476)
A page kept its ruler guides in `NodeKind::Page`, and since frame guides
(#70) every layer also has its own `guides` field. Both are written as
`guides`, and on reading the layer's own field takes the key, so:

- a reopened page's guides landed in the layer field and were not drawn;
- saving that page wrote `guides` twice (the page kind's list, always
  written, then the layer's), and the file no longer opened ("duplicate
  field `guides`").

Every layer, pages included, now keeps its guides in the one layer field;
the key in the file is unchanged, so existing files open with their guides.
The field reads every `guides` list a layer has, so files already saved
with the key twice open again with both lists, in file order. This also
covers collab `Create` payloads from older peers.

Regressions: JSON round trips of page and frame guides, a page with two
lists, a bad list still refused (doc); save, reopen, save, reopen through
`.figcraft` and a document.json with the key twice (format). Checked in the
app over the control channel: guides drawn after two save/reopen cycles, and
a file with the key twice opens with all its guides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6Dyzof21BCrUsByhx2w
2026-10-28 22:47:24 +01:00
Dylan M. Taylor 23f57c8660 refactor(engine): simplify command handling for strict clippy 2026-10-28 16:00:36 +00:00
aiongg a9d93f8310 refactor(engine): split cmd/file.rs into file/ 2026-10-26 20:17:48 +00:00
aiongg 96423f5a6e refactor(engine): move cmd/file.rs zip_cap_tests to file/zip_cap_tests.rs 2026-10-26 20:17:48 +00:00
aiongg 13855cfabe refactor(engine): move cmd/file.rs staging_write_tests to file/staging_write_tests.rs 2026-10-26 20:17:48 +00:00
aiongg 47c807f209 refactor(engine): move cmd/file.rs rest_import_tests to file/rest_import_tests.rs 2026-10-26 20:17:48 +00:00
aiongg f0f1c2003d refactor(engine): move cmd/file.rs tab_order_tests to file/tab_order_tests.rs 2026-10-26 20:17:48 +00:00
aiongg 0b9fcb7f4e refactor(engine): split cmd/component.rs into component/ 2026-10-26 20:17:48 +00:00
aiongg cea90cf935 refactor(engine): split cmd/edit.rs into edit/ 2026-10-26 20:17:48 +00:00
aiongg d853eee820 refactor(engine): move crates/engine/src/cmd/mod.rs to crates/engine/src/cmd.rs 2026-10-26 20:17:47 +00:00
BFlat cac54fd552 Merge pull request #840 from StrajnarFilip/feat/vector-drawable-export
M6: export as Android Vector Drawable (XML)
2026-10-27 01:06:21 +07:00
BFlat 740cc2a2c6 Merge pull request #726 from ijashuzain/feat/variables-dart-export
M6: export variables as Dart constants for Flutter
2026-10-27 00:53:10 +07:00
BFlat 29c89f7d5b Merge pull request #650 from JimKnoxx/overlay-anchor-trigger
M5: overlay positions relative to the layer that opens them
2026-10-27 00:49:52 +07:00
bflatastic 2aae395310 Merge main into #840 2026-10-27 00:31:32 +07:00
BFlat ad9abe7ce6 Merge pull request #1133 from g1obalworlds/fix-batch-rollback-closed-tabs
engine: restore tabs closed inside a failed command group
2026-10-27 00:13:37 +07:00
BFlat dd5b5c0dc0 Merge pull request #1374 from Ridzzz0Alam/fix/1330-save-disk-changes
fix: Issue #1330 Save no longer overwrites changes another app made to the open file
2026-10-27 00:13:15 +07:00
bflatastic 632f2cef4b Merge main into #840
# Conflicts:
#	docs/roadmap.md
2026-10-27 00:12:27 +07:00
bflatastic 56ed786e0e #726: reuse codegen's kotlin_color for Dart colours 2026-10-26 23:54:09 +07:00
bflatastic 5a5175cc7e #726: write Dart numbers at full precision 2026-10-26 23:54:08 +07:00
bflatastic a683e51045 #726: Dart names never shadow Dart types (classes and constants) 2026-10-26 23:54:08 +07:00
bflatastic 6145409859 Merge main into #726
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/variables_io.rs
#	crates/engine/src/variables_io_tests.rs
#	docs/components-parity.md
#	docs/mcp.md
2026-10-26 23:28:15 +07:00
bflatastic de826e14cf Merge main into #650
# Conflicts:
#	crates/ui-egui/locales/es.toml
#	crates/ui-egui/locales/pl.toml
#	docs/prototyping-parity.md
2026-10-26 23:24:22 +07:00
bflatastic e469cc8135 Merge main into #840
# Conflicts:
#	apps/figcraft-cli/src/files.rs
#	apps/figcraft-cli/src/main.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/lib.rs
#	crates/ui-egui/locales/en.toml
#	crates/ui-egui/locales/es.toml
#	crates/ui-egui/src/export_panel.rs
#	crates/ui-egui/src/export_preview_tests.rs
#	docs/file-format-parity.md
#	docs/mcp.md
#	docs/roadmap.md
#	docs/ui-parity.md
2026-10-26 23:23:07 +07:00
bflatastic b90749b377 Merge main into #1133 2026-10-26 22:57:23 +07:00
Muamer MustaficandCursor b6d3e002df M4: truncated text fills its last line, keeps truncating when resized, and auto height takes max lines (#1375, #1376, #1377)
- The last line shown runs on into the word wrapped after it, so the ellipsis
  fills the line ("Lorem consec…") instead of following the last whole word.
- An explicit height (node.set, transform.resize, a resize handle, fixed
  sizing) on truncating text keeps it truncating (TextData::fix_size).
- Max lines on auto-height text hugs up to that many lines and ends in an
  ellipsis; text.maxLines keeps auto height, Type settings show it as
  truncating, .fig export writes textTruncation and import keeps auto height.
- node.get reports maxLines; text.fit measures every line.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 13:14:51 +01:00
Ridzzz0Alam 0d7d9ebd00 M1: stamp the file before reading it, so a change made during the read isn't missed (#1330)
Open and Revert to saved recorded the file's size and modification time after reading it: a change written in between would be stamped as already loaded and a later save would replace it. Taking the stamp first makes such a change refuse the next save instead (CodeRabbit on #1374).
2026-10-26 11:46:23 +01:00
Ridzzz0Alam a648700fcc M1: Save no longer overwrites changes another app made to the open file (#1330)
With a file open in the desktop app, figcraft-cli could change it on disk;
the next Save (or auto-save) wrote the app's copy over it and said
"Saved", losing the CLI's changes.

Each tab now remembers its file's size and modification time when it
opens, reverts or saves it (the Stamp library files already use), and
Save and auto-save refuse while the file on disk differs, pointing to
Revert to saved or Save as. Scripts pass `file.save {overwrite: true}`.
Save as and saves to an explicit path are unchanged.
2026-10-26 11:04:01 +01:00
BFlat d3782fdc43 M12: board templates and tables (#1363)
* M12: board templates and tables

Five built-in board templates (retrospective, brainstorm, weekly planner,
flow chart, kanban board) placed as ordinary board objects in one undo step
(board.template, board.templates) from a toolbar picker with pictures, and
board tables made of auto layout frames (board.table, board.tableEdit; up to
50 x 20), typed into with a double-click and edited by row and column from
the bar over the selection. Docs: boards-parity, gap 24, ROADMAP, mcp.

* M12: board templates picker on egui 0.37

Id::new and Ui::id are deprecated in egui 0.37: the templates picker's area uses Id::unique, its buttons' interaction ids come from ui.scope_id(), and its test reads the board bar's area by Id::unique.
2026-10-26 12:52:39 +07:00
BFlat 4fad29a66e M12: board timer and voting sessions (#1361)
* M12: board timer and voting

A countdown everyone on a board sees (board.timer, board.timerState), synced as its end time or the
time left while paused, and voting sessions (board.vote, board.voteResults): votes per person, on
everything, stickies or the selection; clicks vote, your badge takes a vote back; your own votes
show while it runs, everyone's with a ranked list once it ends. Timer and vote sync as document
properties and ballots as one entry per voter; neither is an undo step. A pill at the top right
of the board, new Timer, Pause and Vote icons, labels and strings in every catalog, docs.

* M12: board timer and voting on egui 0.37

Id::new is deprecated in egui 0.37: the timer and voting area and its memory ids use Id::unique.

* M12: board.vote's start and ballot changes in functions of their own (Sonar)
2026-10-26 12:28:59 +07:00
BFlat 8e79ffc3d7 Merge pull request #1021 from sarsonj/feat/sketch-import
M6: .sketch import (Sketch 48 and newer)
2026-10-26 11:10:16 +07:00
BFlat d203f8fdcf Merge pull request #698 from Dubblbindong/firma/fix/plugin-permission-to-save-a-file-86
feat(plugin): add saveFile permission with host-owned save dialog
2026-10-26 10:55:11 +07:00
BFlat 3a641026ad Merge pull request #1202 from culiulemon/main
Vector editing, property copy/paste, dev-mode assets, ArkUI codegen and shape-builder fixes
2026-10-26 10:53:13 +07:00
bflatastic 27d1089847 Merge main into #1021
# Conflicts:
#	ROADMAP.md
#	docs/target-app-parity.md
2026-10-26 10:43:34 +07:00
BFlat bcde334043 Merge pull request #1314 from denisg0mes/keep-images-past-budget
M7: don't save over a file whose images past the budget weren't loaded
2026-10-26 10:41:03 +07:00
bflatastic 1b946a247f Merge main into #698
# Conflicts:
#	README.md
#	crates/ui-egui/locales/fr.toml
#	crates/ui-egui/locales/sv.toml
2026-10-26 10:37:14 +07:00
bflatastic f0385ef089 Merge main into #1202 2026-10-26 10:34:05 +07:00
bflatastic 76b5c8da6b Merge main into #1021 2026-10-26 10:31:59 +07:00
bflatastic 6c4bb00c9e Merge main into #1021
# Conflicts:
#	crates/text/src/fontdb_tests.rs
2026-10-26 10:20:43 +07:00
bflatastic d0a165efaa Merge main into #1026
# Conflicts:
#	docs/translating.md
2026-10-26 10:15:28 +07:00
BFlat 3a845b9717 Merge pull request #703 from timrrrr/codex/cmd-resize-image-crop
M1: crop image fills on Command/Ctrl resize
2026-10-26 10:15:04 +07:00
BFlat 8a89d5c20e Merge pull request #607 from MMexicann/fix/outline-stroke-rings
M4: preserve stroke rings when outlining shapes
2026-10-26 10:14:58 +07:00
bflatastic 3b56f18e8e Merge main into #1202
# Conflicts:
#	crates/engine/src/codegen.rs
#	docs/mcp.md
2026-10-26 09:21:24 +07:00
bflatastic eb16585ec2 Merge main into #698 2026-10-26 09:20:18 +07:00
bflatastic 27f3bf6730 Merge main into #703 2026-10-26 09:20:12 +07:00
bflatastic c6d43e7903 Merge main into #607 2026-10-26 09:20:09 +07:00
bflatastic 0dd8bf591e Merge main into #921 2026-10-26 09:20:03 +07:00