Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
c9e00d4
Create ChannelPage with floating logic
renefloor May 6, 2026
9e5ba93
simplify composer setup
renefloor May 6, 2026
e6e3444
poc for floating app bar
renefloor May 6, 2026
c99bc63
fixes for merge issues
renefloor May 27, 2026
905b868
Revert "simplify composer setup"
renefloor May 27, 2026
bb28a92
fix avatar press
renefloor May 27, 2026
c6b4840
fix composer safeArea
renefloor May 27, 2026
413e987
Add floating header
renefloor May 27, 2026
66af712
Cleanup sample app
renefloor May 27, 2026
2c156b2
Fix topPadding on listview
renefloor May 27, 2026
d42cc51
Fix attachment picker padding
renefloor May 27, 2026
68f1ed0
Using theming for floating config
renefloor May 28, 2026
aac36c3
improve using default floatings from theme
renefloor May 28, 2026
558f073
Use streamscaffold
renefloor May 29, 2026
1ff997d
migrate to SDK navbar
renefloor May 29, 2026
4bd8056
fix edit message in thread
renefloor Jun 10, 2026
84e85ce
Add shadow to avatar on channel header
renefloor Jun 11, 2026
c27569b
Add gradient behind floating composer
renefloor Jun 12, 2026
4b0a700
fix attachmentpicker background
renefloor Jun 12, 2026
cee1b1d
Add sample app config
renefloor Jun 12, 2026
9ba1ba8
Fix extra padding on loading skeletons
renefloor Jun 12, 2026
dfedb96
Update all sample app pages
renefloor Jun 12, 2026
c431a3b
update core dependency
renefloor Jun 12, 2026
fb4f234
Add global message list config
renefloor Jun 12, 2026
3ac8eb5
Fix scroll button showing on thread
renefloor Jun 12, 2026
cf907e7
Check if thread replies are enabled
renefloor Jun 12, 2026
3e477cc
fix background attachment picker
renefloor Jun 12, 2026
74888d1
set default appstyle to regular
renefloor Jun 12, 2026
a67a716
fix review comments
renefloor Jun 12, 2026
d1ad9e1
update core dependency
renefloor Jun 16, 2026
c44ba13
update changelog
renefloor Jun 16, 2026
0c62f89
update core dependency
renefloor Jun 17, 2026
738d676
fix(ui): channel page controller leak, shared fade helper, photo gall…
renefloor Jun 17, 2026
e966ad3
Update appstyle theming
renefloor Jun 17, 2026
faf7c8a
update core dependency
renefloor Jun 17, 2026
01a5a71
Merge remote-tracking branch 'origin/master' into feat/channel-page
renefloor Jun 19, 2026
38a0c59
update core dependency
renefloor Jun 19, 2026
26d0f3f
chore: Update Goldens
renefloor Jun 19, 2026
5730ff6
update core and fix analysis
renefloor Jun 19, 2026
6b1db2a
add option for reply in channel config
renefloor Jun 19, 2026
6593cc7
chore: Update Goldens
renefloor Jun 19, 2026
edd53f2
fix not using new api
renefloor Jun 19, 2026
414fd1b
fix test and analysis
renefloor Jun 19, 2026
017e9c4
Merge remote-tracking branch 'origin/master' into feat/channel-page
renefloor Jun 19, 2026
3eb63d5
Merge remote-tracking branch 'origin/master' into feat/channel-page
renefloor Jul 29, 2026
1862ec0
project update
renefloor Jul 29, 2026
4490030
fix pixel artifact between components
renefloor Jul 29, 2026
00ee06e
change background into 1 gradient
renefloor Jul 29, 2026
2fc96e3
Add fixes for channelpage and deleted message
renefloor Jul 29, 2026
a9ad64c
Add snapshot tests for deleted message
renefloor Jul 29, 2026
f7ae533
chore: Update Goldens
renefloor Jul 29, 2026
a54b59e
Add floating to edit button group page
renefloor Jul 29, 2026
0dd9add
use elevation for composer
renefloor Jul 30, 2026
d694d88
Add composer background animation
renefloor Jul 30, 2026
775efe0
update core dependency
renefloor Jul 30, 2026
a0ea0e6
Merge remote-tracking branch 'origin/master' into feat/channel-page
renefloor Jul 30, 2026
69df35a
update core dependency
renefloor Jul 30, 2026
d310daa
fix change in elevation logic
renefloor Jul 30, 2026
989e58e
Merge remote-tracking branch 'origin/master' into feat/channel-page
renefloor Jul 30, 2026
95cf893
fix(sample): restore location sharing in the channel page
renefloor Jul 30, 2026
e240ac2
docs(ui): document the channel/thread page extension points
renefloor Jul 30, 2026
557b9ab
docs(changelog): correct the appBarBehavior entry
renefloor Jul 30, 2026
14ed0a6
docs(changelog): note the thread scroll-to-bottom fix
renefloor Jul 30, 2026
ad9e6a6
fix(ui): resolve message list config on the build path
renefloor Jul 30, 2026
33eeab5
test(ui): cover replies-disabled hiding the thread reply action
renefloor Jul 30, 2026
e97ab7f
refactor(ui): extract the app bar behavior resolver
renefloor Jul 30, 2026
26ea9ff
chore: minor cleanups from PR review
renefloor Jul 30, 2026
d63dde3
Merge remote-tracking branch 'origin/master' into feat/channel-page
renefloor Jul 30, 2026
af5ec1e
move custom composer
renefloor Jul 30, 2026
1a156e4
formatting
renefloor Jul 30, 2026
42bfd56
minor improvements
renefloor Jul 30, 2026
e3e50b8
improvements on custom attachment picker
renefloor Jul 30, 2026
4cf55e1
Merge branch 'fix/empty-unread-indicator' into feat/channel-page
renefloor Jul 31, 2026
bd3c0a2
fix test mocks
renefloor Jul 31, 2026
da535fb
Simplify back buttons in new pages
renefloor Jul 31, 2026
217be1a
Minor PR improvements
renefloor Aug 4, 2026
427bcdc
fix ripple effect on attachments
renefloor Aug 4, 2026
d07bcf5
revert repliesEnabled change
renefloor Aug 4, 2026
c4b5391
wip: floating message list + toolbar migration (checkpoint before mas…
xsahil03x Aug 6, 2026
2ad6e44
Merge origin/master into feat/channel-page
xsahil03x Aug 6, 2026
277c60e
docs(ui): address channel-page PR review doc findings
xsahil03x Aug 6, 2026
ffb6485
docs(ui): fix dangling [config] ref + document isFloating default
xsahil03x Aug 6, 2026
a70661f
docs(ui): tighten StreamThreadHeader.onBackPressed per Effective Dart
xsahil03x Aug 6, 2026
00e420b
test(ui): cover ItemPosition content edges + correct their doc
xsahil03x Aug 6, 2026
b05efcc
fix(repo): point stream_core_flutter at the core PR ref for CI
xsahil03x Aug 7, 2026
be12eb6
test(ui): drop StreamMessageItem a11y tests without backing impl
xsahil03x Aug 7, 2026
d5e807a
refactor(ui): adopt StreamSurfaceStyle and address PR review
xsahil03x Aug 7, 2026
97f2caf
chore: Update Goldens
xsahil03x Aug 7, 2026
0759c21
test(ui): align thread-reply test with reverted replies-config gating
xsahil03x Aug 7, 2026
26de77a
test(ui): drop replies-config thread-reply test
xsahil03x Aug 7, 2026
5b07f96
style(ui): dart format padding_scrollable_positioned_list_test
xsahil03x Aug 7, 2026
0f5ff5a
feat(ui): implement transparent edge-to-edge system bars
xsahil03x Aug 7, 2026
2af9b6b
fix(ui): adjust message composer bottom padding for keyboard visibility
xsahil03x Aug 7, 2026
1b0588e
chore(deps): update stream_core_flutter dependency reference
xsahil03x Aug 7, 2026
2305535
chore: Update Goldens
xsahil03x Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs_screenshots/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies:
stream_core_flutter:
git:
url: https://github.com/GetStream/stream-core-flutter.git
ref: 3ba1a36b6a3d9d3a194ccb8f0deaf4d69c5842eb
ref: c4308b3a2ea286483fc24c09c0168b10ad9de8a8
path: packages/stream_core_flutter

dev_dependencies:
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/docs_screenshots/test/src/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void setupMockChannel({
).thenAnswer((_) => Stream.value(DateTime.parse('2020-06-22 12:00:00')));
when(() => channel.state).thenReturn(channelState);
when(() => channel.client).thenReturn(client);
when(() => channel.config).thenReturn(ChannelConfig(mutes: true));
when(() => channel.config).thenReturn(ChannelConfig(mutes: true, replies: true));
when(channel.getRemainingCooldown).thenReturn(0);
when(() => channel.getRemainingCooldown(lastMessageAt: any(named: 'lastMessageAt'))).thenReturn(0);
when(() => channel.isDistinct).thenReturn(false);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/docs_screenshots/test/theming/goldens/macos/theming_red.png

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is from the HSL -> HCT color change

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ command:
stream_core_flutter:
git:
url: https://github.com/GetStream/stream-core-flutter.git
ref: 3ba1a36b6a3d9d3a194ccb8f0deaf4d69c5842eb
ref: c4308b3a2ea286483fc24c09c0168b10ad9de8a8
path: packages/stream_core_flutter
stream_thumbnail: ^0.1.0
synchronized: ^3.4.0
Expand Down
17 changes: 17 additions & 0 deletions packages/stream_chat_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
## Upcoming

⚠️ Changed

- `StreamPhotoGallery` now defaults its `padding` to the bottom safe-area inset instead of no padding, so the last row clears the home indicator. Pass an explicit `padding` to opt out.
- `StreamMessageListView.config` is now nullable (`StreamMessageListViewConfiguration?`) instead of defaulting to `const StreamMessageListViewConfiguration()`. Passing a value is unchanged; code that *reads* `config` off a `StreamMessageListView` instance now gets a nullable value.
- `StreamMediaGalleryPreview` chrome now follows the app style — when floating, the header and footer float over full-bleed media and the footer's share / gallery buttons outline + elevate to match the back button; when regular, the chrome is docked and the media is inset between the bars.

✅ Added

- Added `StreamChannelPage` — a ready-to-use channel page widget that wires up `StreamChannelHeader`, `StreamMessageListView`, and `StreamMessageComposer` with floating or docked layout driven by the active app style.
- Added `StreamThreadPage` — a ready-to-use thread page widget with the same floating/docked layout support, plus an `onBackPressed` callback that replaces the header back button's default pop.
- Added `onBackPressed` to `StreamChannelHeader` and `StreamThreadHeader` — replaces the default back button's `Navigator.maybePop` without rebuilding the whole `leading`, so callers keep the header's default unread badge. Ignored when `leading` is supplied.
- Added `MessageComposerProps.surfaceStyle` (a `StreamSurfaceStyle`) — explicitly controls whether `StreamMessageComposer` renders `floating` or `regular`. When null it falls back to `StreamMessageComposerThemeData.surfaceStyle`, and then to the ambient `StreamSurfaceStyle`.
- Added `StreamMessageComposerTheme` and `StreamMessageComposerThemeData` — a component theme for the composer, also available globally as `StreamChatThemeData.messageComposerTheme`.
- Added `StreamMessageListView.config` — accepts an explicit `StreamMessageListViewConfiguration` per widget; falls back to `StreamChatConfigurationData.messageListViewConfiguration` from the nearest ancestor when omitted.
- Added an `isFloating` parameter to `StreamBackButton`, controlling floating vs pinned back-button appearance. Falls back to `StreamAppBarTheme`, and then to the ambient `StreamSurfaceStyle`, when null. `StreamChannelHeader`, `StreamChannelListHeader`, and `StreamThreadHeader` now apply their per-header theme (`channelHeaderTheme` / `channelListHeaderTheme` / `threadHeaderTheme`) as a `StreamAppBarTheme` and pass `style` to the bar, which republishes its resolved behavior to its slots — so every slot in the bar — the default avatar's drop shadow, the default back button, and any `leading`/`trailing` the caller supplies — resolves the same chain the bar itself uses: `style`, then the per-header theme, then the ambient `StreamAppBarTheme`, then `StreamSurfaceStyle`.
- Added `messageListViewConfiguration` field to `StreamChatConfigurationData`, allowing a global `StreamMessageListViewConfiguration` default for all `StreamMessageListView` widgets. Pass it via `StreamChat.configData` to configure behaviors like `swipeToReply` and `highlightInitialMessage` app-wide without wiring them per-page.
- Re-exported `StreamScaffold`, `StreamScaffoldInsets`, `StreamBottomNavBar`, `StreamBottomNavBarItem`, `StreamSurfaceStyle`, and `streamFloatingFadeLinearGradient` from `stream_core_flutter` via `package:stream_chat_flutter/stream_chat_flutter.dart`.
- Added `StreamMessageListViewConfiguration.autoScrollPolicy` to control whether and how `StreamMessageListView` scrolls to the newest message when a new message arrives. Use `StreamAutoScrollPolicy.disabled` to fully control scrolling yourself.
- Added `onReactionSelected` to `StreamMessageReactionPicker`, a context-aware callback that provides the `BuildContext` for navigation.
- Added an `errorSubtitle` to `StreamScrollViewErrorWidget`, which now falls back to the design's generic error copy (title, description, and a "Try Again" retry label) when values aren't provided.
Expand All @@ -22,6 +37,8 @@
- Fixed the default list/scroll-view error states (channel, message, member, user, thread, poll-vote, reaction, search, and photo) showing raw or fixed errors; they are now connection-aware (no internet / slow connection), falling back to each view's specific error text.
- Fixed `StreamTypingIndicator` briefly showing typing users from a different context (main channel vs. thread) on its first frame.
- Fixed the attachment picker throwing a `Tooltip` assertion error when a custom `TabbedAttachmentPickerOption` is added without a `title`; the tooltip is now only shown when a title is provided.
- Fixed the "Message deleted" bubble overflowing its maximum width when the localized label is long; the label now wraps instead.
- Fixed the scroll-to-bottom button in thread views keying off the parent channel's up-to-date state instead of the thread's own scroll position, so it no longer appears while already at the newest reply. Note that thread views now show the button at all: it follows `showScrollToBottom` from the effective `StreamMessageListViewConfiguration`, so set that to `false` to restore the previous always-hidden behavior.
- Fixed the `StreamBackButton` unread badge including the currently open channel in its total count.
- Fixed `StreamMessageListView` jumping several screens when selecting text in a message on desktop or web. The `ScrollablePositionedList` viewports now account for their `anchor` in `getOffsetToReveal`, so implicit reveals (`Scrollable.ensureVisible`, `RenderObject.showOnScreen`) no longer overshoot. [#2862](https://github.com/GetStream/stream-chat-flutter/issues/2862)
- Fixed modal dialogs (message actions, delete/flag confirmation) rendering over a white scrim in light theme; they now use the design system's scrim token.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class ItemPosition {
required this.index,
required this.itemLeadingEdge,
required this.itemTrailingEdge,
this.contentLeadingEdge,
this.contentTrailingEdge,
});

/// Index of the item.
Expand All @@ -41,19 +43,43 @@ class ItemPosition {
/// May be greater than one if the item is partially visible.
final double itemTrailingEdge;

/// Distance in proportion of the visible content's main axis length from the
/// leading edge of that content to the leading edge of the item.
///
/// The visible content is the area inside the list's padding. Consider using
/// this for overlays inside that area, such as under a floating bar; scroll
/// logic keeps using [itemLeadingEdge]. Equal to [itemLeadingEdge] when the list has no
/// inset, and `null` only when the source omits it (a list always provides
/// it).
final double? contentLeadingEdge;

/// Distance in proportion of the visible content's main axis length from the
/// leading edge of that content to the trailing edge of the item.
///
/// See [contentLeadingEdge].
final double? contentTrailingEdge;

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ItemPosition &&
runtimeType == other.runtimeType &&
index == other.index &&
itemLeadingEdge == other.itemLeadingEdge &&
itemTrailingEdge == other.itemTrailingEdge;
itemTrailingEdge == other.itemTrailingEdge &&
contentLeadingEdge == other.contentLeadingEdge &&
contentTrailingEdge == other.contentTrailingEdge;

@override
int get hashCode => 31 * (31 * (index.hashCode + 7) + itemLeadingEdge.hashCode) + itemTrailingEdge.hashCode;
int get hashCode => Object.hash(
index,
itemLeadingEdge,
itemTrailingEdge,
contentLeadingEdge,
contentTrailingEdge,
);

@override
String toString() =>
'''ItemPosition(index: $index, itemLeadingEdge: $itemLeadingEdge, itemTrailingEdge: $itemTrailingEdge)''';
'''ItemPosition(index: $index, itemLeadingEdge: $itemLeadingEdge, itemTrailingEdge: $itemTrailingEdge, contentLeadingEdge: $contentLeadingEdge, contentTrailingEdge: $contentTrailingEdge)''';
}
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ class _PositionedListState extends State<PositionedList> {
@override
Widget build(BuildContext context) {
_rebuildKeyIndexMap();
return RegistryWidget(
Widget list = RegistryWidget(
elementNotifier: registeredElements,
child: UnboundedCustomScrollView(
anchor: widget.alignment,
Expand Down Expand Up @@ -409,6 +409,23 @@ class _PositionedListState extends State<PositionedList> {
],
),
);

// Match BoxScrollView: when the main-axis MediaQuery padding was
// auto-consumed (no explicit padding), strip it from descendants so nested
// widgets and scrollables don't inset for it a second time.
final mediaQuery = MediaQuery.maybeOf(context);
if (widget.padding == null && mediaQuery != null) {
list = MediaQuery(
data: mediaQuery.copyWith(
padding: widget.scrollDirection == Axis.vertical
? mediaQuery.padding.copyWith(top: 0, bottom: 0)
: mediaQuery.padding.copyWith(left: 0, right: 0),
),
child: list,
);
}

return list;
}

Widget _buildSeparatedListElement(int index) {
Expand Down Expand Up @@ -440,8 +457,19 @@ class _PositionedListState extends State<PositionedList> {
);
}

EdgeInsets get _resolvedPadding =>
widget.padding?.resolve(Directionality.maybeOf(context) ?? TextDirection.ltr) ?? EdgeInsets.zero;
EdgeInsets get _resolvedPadding {
final padding = widget.padding;
if (padding != null) {
return padding.resolve(Directionality.maybeOf(context) ?? TextDirection.ltr);
}
// Match BoxScrollView: with no explicit padding, consume the main-axis
// MediaQuery padding so the list auto-insets like a ListView. The cross-axis
// remainder is handed to descendants in [build].
final mediaPadding = MediaQuery.maybeOf(context)?.padding ?? EdgeInsets.zero;
return widget.scrollDirection == Axis.vertical
? mediaPadding.copyWith(left: 0, right: 0)
: mediaPadding.copyWith(top: 0, bottom: 0);
}

AxisDirection get _axisDirection {
if (widget.scrollDirection == Axis.vertical) {
Expand Down Expand Up @@ -558,12 +586,22 @@ class _PositionedListState extends State<PositionedList> {
final reveal = viewport!.getOffsetToReveal(box, 0).offset;
if (!reveal.isFinite) continue;
final itemOffset = reveal - viewport.offset.pixels;
final viewportDimension = scrollController.position.viewportDimension;
// content* edges are measured from the visible content (inside the
// padding) so overlays under a floating bar can key off 0..1;
// subtract the leading padding (the bottom when reversed, which
// `_leadingSliverPadding` resolves). item* stays viewport-relative
// for scroll mechanics (alignment / anchor preservation).
final leadingPad = _leadingSliverPadding.vertical;
final contentExtent = viewportDimension - _resolvedPadding.vertical;
final contentDenom = contentExtent > 0 ? contentExtent : viewportDimension;
positions.add(
ItemPosition(
index: key.index,
itemLeadingEdge: itemOffset.round() / scrollController.position.viewportDimension,
itemTrailingEdge:
(itemOffset + box.size.height).round() / scrollController.position.viewportDimension,
itemLeadingEdge: itemOffset.round() / viewportDimension,
itemTrailingEdge: (itemOffset + box.size.height).round() / viewportDimension,
contentLeadingEdge: (itemOffset - leadingPad).round() / contentDenom,
contentTrailingEdge: (itemOffset + box.size.height - leadingPad).round() / contentDenom,
),
);
} else {
Expand All @@ -574,11 +612,18 @@ class _PositionedListState extends State<PositionedList> {
final isRight = _axisDirection == AxisDirection.right;
final leadingPx = isRight ? itemOffset : viewportDimension - (itemOffset + box.size.width);
final trailingPx = isRight ? itemOffset + box.size.width : viewportDimension - itemOffset;
// content* edges (see the vertical branch): drop the leading
// padding so 0..1 spans the visible content.
final leadingPad = _leadingSliverPadding.horizontal;
final contentExtent = viewportDimension - _resolvedPadding.horizontal;
final contentDenom = contentExtent > 0 ? contentExtent : viewportDimension;
positions.add(
ItemPosition(
index: key.index,
itemLeadingEdge: leadingPx.round() / viewportDimension,
itemTrailingEdge: trailingPx.round() / viewportDimension,
contentLeadingEdge: (leadingPx - leadingPad).round() / contentDenom,
contentTrailingEdge: (trailingPx - leadingPad).round() / contentDenom,
),
);
}
Expand Down
Loading
Loading