Skip to content

v4.5 — Refinement, plus one freeze and one thing quietly wrong

Choose a tag to compare

@agirish agirish released this 26 Aug 21:15
· 659 commits to main since this release

Refinement, mostly — plus one freeze and one thing quietly wrong. A bulk sync on a large
comparison locked the window for about eleven seconds at each end, doing nothing in that time but
setting a flag. And a file rewritten while it was being hashed could be remembered under a
digest belonging to no version of it. Alongside those, “Text contains” means one thing on every
surface rather than two, the “None” accent finally reads as no accent, and the markers saying
which workspace and which tab you are in travel instead of blinking.

On the v4 line, so it requires macOS 26 — coming from 3.x or 2.x, read the v4.0 section first.

Organize

  • “Text contains” now means the exact phrase, everywhere. It had two readings: the loose
    word-by-word one on the Organize scan, which is the path that moves files, and the strict one
    in the Automations preview. So “tax return” could move a document that said “tax” and “return”
    pages apart, after a preview that said it would not. Separate words are still matchable, as
    “Mentions the words”.

Duplicates and comparison

  • A file rewritten while it was being hashed could be remembered under the wrong digest.
    Everything the scan knew about a file came from its path, read before the file was opened, so
    none of it was provably about the bytes that followed — and a rewrite of the same byte count
    produced a digest of two files spliced together. The file is now stat'd through its own
    descriptor before the read and after, where the timestamp catches what a byte count cannot.
  • Files a duplicate scan could not read are counted now, instead of vanishing from it. A
    candidate that was gone, unreadable, or changed while it was being hashed was dropped with
    nothing recording it — no pill, no note, no log — while every other skip reason was tallied
    and named. They join the “skipped” note now, as “unreadable or changed while being read”.
  • A duplicate scan does less work to reach the same answer. It read a file's path three
    times before opening it; now once, plus one more for a symlink and one for a file it is about
    to open. On a repeat scan every digest is cached, so that first read is all the hashing does.
    Digest text is now a table lookup, and a long scan publishes progress about a hundred times
    instead of several hundred.
  • Duplicate thumbnails no longer decompress while you scroll. Each was compressed to PNG
    purely to satisfy a rule about what may cross between threads, then decompressed again —
    lazily, which means at draw time, on the main thread, during the scroll that asked for it.
  • A comparison with ignore patterns set folds them once per scan rather than once per item
    compared, and folds each name once rather than once per pattern it is tested against.
  • Starting or finishing a bulk sync no longer locks the window while it marks the rows.
    Flagging each row as in-flight rewrote the whole difference list and asked for a redraw, once
    per row. On a comparison with tens of thousands of differences that cost about eleven seconds
    at each end, doing nothing but setting a flag. The rows are marked in one pass now, and drawn
    once.
  • Rebuilding the difference list stops taking every path apart to ask one question of it.
    Deciding whether a path is hidden split it into components and built a string for each, once
    per difference, on every rebuild — and hiding hidden files is the one filter of five that runs
    unless you turn it off. On 29,000 differences that was about 37 ms a pass, now about 2 ms,
    with exactly the same files hidden.
  • Scanning a large tree resolves far fewer paths. Every directory the walk entered had its
    whole path resolved so the scan could tell whether it had been there before — a symlink-loop
    guard that fires essentially never, and about half the cost of entering a directory. Only a
    directory whose last component is a symlink needs it now, and every cycle is still caught.

Appearance

  • The “None” accent now reads white in light, not the faintest gray. At low Tint, bare
    material and Graphite's neutral wash landed within a couple of points of the same gray, so the
    two were told apart by their swatches and nothing else. “None” now lays a white film over the
    background in light, titlebar included. Dark is untouched.
  • The Info inspector's toolbar button moved to the far right. The trailing pill read Go to,
    Info, Logs, Settings, which put the control that opens the right-hand rail three glyphs from the
    edge it opens against. It now reads Go to, Settings, Logs, Info, mirroring the folder-sidebar
    toggle at the far left. Same buttons, same ⌘I.
  • The selected workspace and the active pane tab now slide between positions. Both markers
    were drawn per item, so switching cut one out where it was and cut a new one in where it was
    going — two bars, one above the other, both blinking. Reduce Motion takes the destination and
    skips the journey.
  • A count that changes rolls its digits instead of cutting to a new number. Diff totals,
    duplicate-group counts and the filing backlog hard-swapped: the old number vanished, a new one
    appeared, and nothing said they were the same quantity. Words are left alone — rolling a
    word's glyphs reads as a glitch.
  • The first-run sheet answers the pointer. Seven of its controls drew their own chrome,
    which means macOS contributes no hover state at all — so the app's first impression was its
    least responsive surface. Each has an affordance now, chosen for what the control does.
  • One vocabulary for corner radii. Eleven distinct radii were hand-written across the app,
    so three chips inside one card could round by different amounts. Four named stops now, each a
    value the app already used most, with the strays moved to their nearest by a point.
  • Twenty-two of the app's animations honour Reduce Motion that did not before. Opting in used
    to mean wiring an environment read into whatever view owned the animation, so most motion was
    unconditional — friction rather than a decision. What is gated now is anything that travels:
    panes collapsing, a workspace switch, the inspector, tabs sliding under a drag, the focus ring
    moving between panes, the search field growing out of its magnifier, Browse's folder sidebar.
    Motion that reports rather than travels — a hover wash, a rolling count — is left alone.
  • The small inline spinners are drawn at their size instead of shrunk to it. Three status
    rows scaled an already-drawn spinner down to seven-tenths, and scaling resamples, so those
    three read softer than identical spinners a few files away. They are framed to occupy exactly
    what the old recipe reserved, so no row moves.
  • Twenty-seven controls that are nothing but an icon now have names. A tooltip is not a name
    on macOS, so VoiceOver read them as “button” and Voice Control could not be told to click them
    at all. Toolbars, row actions, dismiss glyphs and the new-tab plus now say what they do.
    Nothing about this is visible on screen.