Skip to content

Fix: reduce timeline flickering and generate video thumbnails#79

Closed
beezly wants to merge 3 commits intoviktorstrate:mainfrom
beezly:fix/timeline-flicker-and-video-thumbnails
Closed

Fix: reduce timeline flickering and generate video thumbnails#79
beezly wants to merge 3 commits intoviktorstrate:mainfrom
beezly:fix/timeline-flicker-and-video-thumbnails

Conversation

@beezly
Copy link
Contributor

@beezly beezly commented Mar 12, 2026

Summary

Addresses multiple causes of timeline flickering and adds local video thumbnail generation.

Timeline Flickering Fixes

  1. Height measurement mismatchheightOfRow was measuring rows with timeline: nil, producing wrong heights. Fixed by passing the real timeline to the measurement view.
  2. Full snapshot rebuildsupdateTimelineItems rebuilt the entire diffable data source snapshot on every update. Now skips the full rebuild when item IDs haven't changed (content-only updates like reactions, read receipts) and reloads only visible rows in place.
  3. Guard empty visible rows — Added visibleRows.length > 0 check before noteHeightOfRows.
  4. Re-measure after apply — Re-measures visible rows after snapshot apply to let hosting views settle.
  5. Zero-height rows — Returns max(height, 1) to avoid zero-height rows.

Video Thumbnail Fixes

  • Videos without a server-provided thumbnailSource showed a perpetual spinner. Now shows a gray placeholder immediately.
  • Added local thumbnail generation using AVAssetImageGenerator — downloads the video file in the background and extracts the first frame.
  • Generated thumbnails are cached in the shared NSCache for reuse.

Files Changed

  • Mactrix/Views/ChatView/TimelineView/TimelineTableView.swift
  • Mactrix/Views/ChatView/MessageVideoView.swift

Merge order: merge #77 and #78 first, then this PR. Split from #75 (4/4)

⚠️ Rebase required: after #78 is merged, rebase this branch onto main before merging:

beezly added 3 commits March 12, 2026 18:19
…trate#72)

AvatarImage and UserAvatarPlaceholder both used GeometryReader internally.
When placed inside small fixed-size frames, GeometryReader caused layout
issues — content defaulted to top-leading alignment, clipping the bottom.

AvatarImage now uses .scaledToFill() directly. UserAvatarPlaceholder uses
.minimumScaleFactor(0.01) for font sizing instead of reading geometry.

Fixes viktorstrate#72
NSTableView recycles rows, which resets @State and causes images to
flash back to placeholder. Add an NSCache-based image cache to
MatrixClient with a synchronous cachedImage() lookup.

AvatarImage, MessageImageView, and MatrixImageView all pre-populate
their @State from the cache in init, so the first frame already has
the image. Also suppresses implicit animation on the avatar swap.

MatrixImageView now shows a gray placeholder immediately when
mediaSource is nil instead of a perpetual spinner.
Timeline flickering fixes:
- Pass real timeline to measurement view (was using nil, producing wrong heights)
- Skip full snapshot rebuild when item IDs unchanged (content-only updates
  like reactions, read receipts) — reload only visible rows in place
- Guard visibleRows.length > 0 before noteHeightOfRows
- Re-measure visible rows after snapshot apply
- Return max(height, 1) to avoid zero-height rows

Video thumbnail fixes:
- Show gray placeholder immediately when no thumbnailSource
- Generate thumbnails locally using AVAssetImageGenerator
- Cache generated thumbnails in the shared NSCache
@beezly
Copy link
Contributor Author

beezly commented Mar 12, 2026

Superseded by #80 and #81 — split into separate PRs for timeline flickering and video thumbnails.

@beezly beezly closed this Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant