Repository navigation
fix(ui): iPhone Duo polish: picker height, list states, full-width suggestions - #3021
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## sahil/flu-820-respect-asymmetric-safe-area-insets-on-iphone-duo-composer #3021 +/- ##
============================================================================================================
+ Coverage 79.13% 79.67% +0.54%
============================================================================================================
Files 452 453 +1
Lines 29459 29476 +17
============================================================================================================
+ Hits 23312 23486 +174
+ Misses 6147 5990 -157 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
On short screens, such as a phone in landscape, the tabbed picker left no room under the app bar and overflowed. Below 480pt of height its options area is now 158pt, so with the 72pt tabs the picker takes the height of the landscape keyboard it replaces (230pt on iPhone Duo's outer display). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When the list had less room than its default loading, empty or error state needed, such as in landscape with the attachment picker open, the state overflowed. Each state now scrolls instead: the empty and error states fill the space with SliverFillRemaining, so they stay centred when they fit, and the skeleton scrolls. The error state moves into its own internal widget, StreamMessageListErrorState, so the list only decides the safe-area insets. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… width The suggestions were anchored to the inset input, so under a side safe-area inset their background and border stopped short of the screen edge while the composer and app bar ran edge to edge. The autocomplete now wraps the inset input, so its suggestions span the composer, and StreamAutocompleteOptions keeps its options clear of the side insets. Custom trigger suggestions span the full width too and handle the insets themselves. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
085dfd9 to
d2e6a78
Compare
…hone-duo-composer' into sahil/flu-823-iphone-duo-polish-viewer-fit-thumbnails-autocomplete-height
renefloor
left a comment
There was a problem hiding this comment.
Reviewed this layer on its own. The SliverFillRemaining(hasScrollBody: false) approach for the list states and the _insetContent extraction both look like the right shape.
Main concern: there are no test changes in this layer, despite behaviour changes in 7 lib files. Tests I'd expect:
- List states: pump
StreamMessageListEmptyState,StreamMessageListErrorStateandStreamMessageListSkeletonLoadingin a ~120pt-tall box; expect no exception and aScrollable. On revert these fail with a RenderFlex overflow. - Error state retry: tap "Try again" and verify
reloadChannelis called. - Autocomplete width: composer with a side inset, type
/; the options card spans the full width and an option tile stays clear of the inset. Same with a custom trigger. - No-permission message: with a side and bottom inset, the message stays clear of both.
- Picker height:
StreamTabbedAttachmentPickerat heights 479 and 480 → 158 and 260, selecting every tab, withexpect(tester.takeException(), isNull). That would have caught the overflow below.
|
|
||
| // The height of the attachment picker when using the tabbed interface on | ||
| // compact-height screens. | ||
| const _kCompactTabbedAttachmentPickerHeight = 158.0; |
There was a problem hiding this comment.
I think 158 is too short for every tab except the gallery. The file, camera, video and poll tabs wrap their content in OptionDrawer, which defaults to vertical: spacing.xxxl (40) margins, which leaves 78pt. Their column is a 32 icon + 8 gap + ~20 text + 16 gap + 40 button ≈ 116pt, and it doesn't scroll.
So on a phone in landscape, switching to Files/Camera/Video/Poll should still hit a ~38px RenderFlex overflow, which is the overflow this PR is fixing. Only the gallery tab (margin: .zero) fits. I worked this out from the code and haven't run it, so it's worth checking on the simulator with each tab. Fix: either reduce the OptionDrawer vertical margin at compact height, or make the drawer content scrollable.
There was a problem hiding this comment.
Confirmed: on the iPhone Duo in landscape the file, camera, video and poll tabs overflowed by 45px at 158. Fixed in d9e226a by giving those four tabs only the side margin. Their prompt is wrapped in a Center, so the 40pt top and bottom margin never moved it; it only took away the room it needed. The regular 260 layout is unchanged, and OptionDrawer's default margin is untouched, so custom drawers don't move. The new stream_tabbed_attachment_picker_height_test.dart covers every tab at 479 and 480 tall and fails on the old margin.
| focusNode: _effectiveFocusNode, | ||
| messageComposerController: _effectiveController, | ||
| fieldViewBuilder: _buildMessageInput, | ||
| // Inset inside the autocomplete so its suggestions span the full width. |
There was a problem hiding this comment.
Moving the inset into fieldViewBuilder means a customer's customAutocompleteTriggers overlay now runs under the notch/rail instead of being clipped to the inset width. It's in the changelog, which is good, but under CLAUDE.md's rules it's a behavioural break (no compile error, rendering changes), so I think it needs a ! in the title and a migration hint, e.g. "wrap custom options in SafeArea(top: false, bottom: false)".
There was a problem hiding this comment.
Intentional. The suggestions area now matches the composer and app bar: the background runs under the side insets, and our own StreamAutocompleteOptions keeps its rows clear of them. Customer content is laid out as built rather than wrapped, the same as the paged-list states in #3017. It's documented under 🔄 Changed with the one-line migration (a552d1d). I'm not marking it !: it's layout-only and affects only fully custom options views, like the composer border change. a5f716e adds tests for both the command and custom-trigger suggestions under the insets.
| ), | ||
| ], | ||
| ), | ||
| child: StreamSafeArea(top: false, bottom: false, child: content), |
There was a problem hiding this comment.
StreamAutocompleteOptions is exported, and it now always adds side padding, which changes any custom overlay built on it. This isn't in the changelog; could it get its own 🔄 Changed line?
| /// A widget that is used to display the error state of the message list. | ||
| /// | ||
| /// Scrolls instead of overflowing when it has less room than it needs. | ||
| class StreamMessageListErrorState extends StatelessWidget { |
There was a problem hiding this comment.
nit: this isn't exported (consistent with the empty/skeleton states), but the Stream prefix and "Creates a new instance" dartdoc make it look like public API. If customers are meant to reuse it in builders.error, export it and add a changelog Added line; otherwise, fine as is.
There was a problem hiding this comment.
Leaving it internal for now. It matches StreamMessageListEmptyState and StreamMessageListSkeletonLoading, which have the same prefix and doc style and aren't exported either. Exporting the three would be new public API, so I'd do that as its own feat when there's a use for them in builders.
… entry Options built on StreamAutocompleteOptions keep clear of the side insets on their own, so only other options views need to wrap their content. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ates Command and custom suggestions run under the side insets while their content stays clear of them, the no-permission message clears the side and bottom insets, and the message list's default states fit a 120pt-tall list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…idgets Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The camera, video, file and poll tabs centred their prompt inside a 40pt top and bottom margin, which moved nothing but left too little room in the compact picker on a short screen, so the prompt's button overflowed. Those tabs now keep only the side margin. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Part of FLU-823. Stacked on #3017 (FLU-820); review only the commits on top of it.
SliverFillRemaining, so they stay centred when they fit; the error UI moves into an internalStreamMessageListErrorState, leaving the list to decide only the safe-area insets.StreamAutocompleteOptionskeeps its options clear of the side insets. Suggestions fromcustomAutocompleteTriggersspan the full width too and handle the insets themselves (noted under Changed).StreamSafeArea.Verified on the iPhone Duo simulator (outer display, portrait and landscape): no overflow with the picker open, the empty state scrolls in the remaining space, and the suggestions span the full width with their rows clear of the rail. The semantics of the list states are unchanged apart from the scroll container.
🤖 Generated with Claude Code
Summary by CodeRabbit