feat(ui): redesign the desktop screen share picker - #1342
Draft
renefloor wants to merge 7 commits into
Draft
Conversation
Rebuilds the picker on the design system's modal dialog, and stops it re-enumerating the platform's screens and windows every two seconds. The old picker ran a `Timer.periodic(2s)` calling `updateSources()` for as long as it was open, which made the platform re-capture a full-resolution bitmap of every screen and window, rebuild the whole dialog per thumbnail event, and re-decode each image on the UI isolate. The timer also outlived a dismissal by escape or barrier tap, so it kept running for the rest of the app's life, one more per open. `ScreenShareSourceController` reads both source types in a single call when it opens, and again only when the refresh button is pressed. It asks for 480x300 thumbnails rather than whatever the platform defaults to, holds no timers and no stream subscriptions, and is disposed whichever way the dialog goes away. `StreamModalDialog`, `StreamBlurScrim` and `StreamTabBar` join the design-system candidates; `StreamScreenShareSelector` is the grid, with `StreamScreenShareSelectorThemeData` to restyle it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
StreamScreenShareDialog takes an optional controller, so the modal's header and footer are reachable from a test and from a golden. The golden used to hand-roll a copy of the chrome, which would have kept passing while the real dialog changed underneath it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A controller starts reading the platform as soon as it exists, so creating one lazily on first build made that a side effect of building. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## v2 #1342 +/- ##
=====================================
Coverage ? 32.15%
=====================================
Files ? 378
Lines ? 28992
Branches ? 0
=====================================
Hits ? 9321
Misses ? 19671
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
macOS leaves the bitmaps out of the getDesktopSources result entirely —
the `thumbnail` key is commented out natively and thumbnailSize comes
back as {0,0}. They arrive only as events raised by the enumeration, and
the plugin's own getSources then rebuilds its source map from the
bitmap-less response, dropping whatever those events had delivered. The
old picker's two-second timer was the only thing that ever put an image
on screen, one tick after the dialog opened.
The controller now subscribes to onAdded and onThumbnailChanged before
the first load — getDesktopSources passes forceReload:YES, so every
source is re-added with its bitmap — and keeps the bytes by source id in
its own state, where a reload cannot clobber them. A capture pass is
asked for only if something is still missing afterwards, so the
platforms that report bitmaps inline pay nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Redesigns the desktop screen-share picker onto the design system, and stops it hammering the platform while it is open.
Figma: Screen Share Modal
Why
The old picker was a raw Material
AlertDialogwith a MaterialTabBar, styled from the pre-design-systemStreamVideoTheme.colorTheme, with a hard-coded 640×560 body andColors.blueAccentselection borders.It was also slow.
ScreenSelectorStateNotifierran aTimer.periodic(2s)callingupdateSources()for as long as the dialog was open. Every tick made the platform re-enumerate every screen and window and re-capture a full-resolution bitmap of each —getSourceswas called without athumbnailSize. Each thumbnail event then allocated a new state object, which rebuilt the entire dialog through one top-levelValueListenableBuilder, and calledsetStateon the tile, re-decoding an uncappedImage.memoryon the UI isolate. With ~30 windows open that is 30 full-tree rebuilds and 30 full-res decodes every two seconds.On top of that, the notifier was disposed only in the Cancel and Share handlers. Dismissing with Esc or a tap outside leaked the notifier, its three subscriptions and the timer — which then kept re-enumerating sources for the rest of the app's life, stacking one more per open.
What changed
Loading.
ScreenShareSourceControllerreplacesScreenSelectorStateNotifier. It reads both source types in a singlegetSourcescall when the picker opens, and again only when the refresh button in the header is pressed. No timer, noonAdded/onRemoved/onThumbnailChangedsubscriptions. It asks for 480×300 thumbnails instead of whatever the platform defaults to. Switching tabs is now a filter over already-loaded state rather than a wipe-and-refetch. The dialog owns the controller through aStatefulWidget, so it is disposed whichever way the dialog goes away.Design.
StreamModalDialog+showStreamModalDialog(header with title and actions, footer,StreamBlurScrimbarrier) andStreamTabBarjoinsrc/widgets/design_system_candidates/—stream_core_flutterships none of them yet.StreamScreenShareSelectoris the grid,StreamScreenShareThumbnailone tile, andStreamScreenShareSelectorThemeDatarestyles them.A tile's selection border paints as a
foregroundDecoration, so going from the unselected 1px to the selected 2px never resizes the tile.Breaking
TabbedScreenSelectWidget,ThumbnailGrid,ScreenSelectorStateNotifierandScreenSelectorStateare gone;ScreenShareThumbnailWidgetisStreamScreenShareThumbnail.showDefaultScreenSelectionDialogandStreamScreenShareButton.desktopScreenSelectorBuilderkeep their signatures, so the common path needs no change. The dogfooding custom-selector example is ported.Tests
ScreenShareSourceController: onegetSourcesfor both types, a cappedthumbnailSize,updateSourcesnever called, a tab switch that reloads nothing, refresh that reloads once, a dropped selection, a failed load.StreamScreenShareSelectorandshowDefaultScreenSelectionDialog: tab contents, selection, the empty state, no polling over ten seconds, and picking a source through the real entry point.StreamTabBarandStreamModalDialog: indicator, tap reporting, header and footer slots, close button, dismissal through the scrim.Overlaycontent.🤖 Generated with Claude Code