Skip to content

feat(ui): floating header#115

Open
renefloor wants to merge 37 commits into
mainfrom
feat/floating-header
Open

feat(ui): floating header#115
renefloor wants to merge 37 commits into
mainfrom
feat/floating-header

Conversation

@renefloor

@renefloor renefloor commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Submit a pull request

Linear: FLU-502

CLA

  • I have signed the Stream CLA (required).
  • The code changes follow best practices
  • Code changes are tested (add some information if not applicable)

Description of the pull request

This adds the option to create a floating appbar. It automatically adjusts the background from a color to a gradient and removes the border. Also makes the back button floating by default.

Screenshots / Videos

image

Summary by CodeRabbit

  • New Features
    • Added StreamScaffold with built-in support for floating and regular app bar/bottom layouts
    • Enhanced StreamAppBar floating mode with gradient fade over content
    • Added StreamBottomNavBar/StreamBottomNavBarItem with regular docked and floating pill styles
    • Avatars now support floating/shadow via isFloating (including theme-level controls for consistent behavior)
  • Bug Fixes
    • Improved disabled styling for floating buttons to keep the intended surface/elevation behavior
  • Tests
    • Added golden and widget test coverage for floating/regular variants across components

@renefloor
renefloor requested a review from a team as a code owner May 27, 2026 12:52
@renefloor renefloor changed the title Feat/floating header feat(ui): floating header May 27, 2026
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@xsahil03x, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f616461f-ebf4-43e7-b08e-e0eeb70dd5c3

📥 Commits

Reviewing files that changed from the base of the PR and between 111b96a and f212d5a.

📒 Files selected for processing (1)
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
📝 Walkthrough

Walkthrough

Introduces floating rendering across app bars, scaffolds, bottom navigation, and avatar widgets. Adds shared theme contracts, gradient utilities, component customization, disabled floating-button styling, gallery previews, and widget/golden coverage.

Changes

Floating UI feature

Layer / File(s) Summary
Theme and behavior foundation
packages/stream_core_flutter/lib/src/theme/..., packages/stream_core_flutter/lib/core.dart
Adds ambient and component floating behavior contracts, bottom-navigation theme data, gradient utilities, theme propagation, generated value handling, and barrel exports.
App bar and scaffold layout
packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart, packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart
Adds behavior-aware app-bar gradients and leading buttons, plus floating scaffold layout, measured bottom positioning, and inherited insets.
Bottom navigation
packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart, packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart
Adds bottom-navigation models, theme resolution, factory customization, animated tiles, regular docked rendering, and floating pill rendering.
Avatars and buttons
packages/stream_core_flutter/lib/src/components/avatar/..., packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart
Adds floating avatar elevation through individual, group, and stack APIs, and preserves disabled floating button surfaces.
Gallery and validation
apps/design_system_gallery/..., packages/stream_core_flutter/test/..., packages/stream_core_flutter/CHANGELOG.md
Adds floating controls and previews, bottom-navigation gallery registration, widget and golden tests, semantics synchronization, and changelog entries.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: xsahil03x

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding a floating header/app bar.
Description check ✅ Passed The description covers the required sections and checklist, with only optional GitHub issue and before/after table omitted.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/floating-header

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart (1)

100-100: ⚡ Quick win

Replace hardcoded margin with spacing token.

The horizontal margin of 32 should use a spacing token from context.streamSpacing rather than a hardcoded value. As per coding guidelines, always use spacing tokens from the theme context instead of hardcoded values.

♻️ Proposed fix
               margin: const EdgeInsets.symmetric(horizontal: 32),
+              // Replace with appropriate spacing token, e.g.:
+              // margin: EdgeInsets.symmetric(horizontal: spacing.xl),

Note: Choose the spacing token that best matches the intended 32-pixel spacing (likely spacing.xl or similar).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart` at
line 100, Replace the hardcoded horizontal margin of 32 in StreamAppBar with the
theme spacing token: locate the margin: const EdgeInsets.symmetric(horizontal:
32) in stream_app_bar.dart (the AppBar/Container/widget that sets margin) and
use the spacing token from context.streamSpacing (e.g.,
EdgeInsets.symmetric(horizontal: context.streamSpacing.xl) or the appropriate
token that maps to 32px) so the layout uses the theme spacing instead of a
literal value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart`:
- Line 100: Replace the hardcoded horizontal margin of 32 in StreamAppBar with
the theme spacing token: locate the margin: const
EdgeInsets.symmetric(horizontal: 32) in stream_app_bar.dart (the
AppBar/Container/widget that sets margin) and use the spacing token from
context.streamSpacing (e.g., EdgeInsets.symmetric(horizontal:
context.streamSpacing.xl) or the appropriate token that maps to 32px) so the
layout uses the theme spacing instead of a literal value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f9bb118-2547-48c3-ab91-fa8c2e73b2eb

📥 Commits

Reviewing files that changed from the base of the PR and between 333f7b7 and 84123de.

📒 Files selected for processing (6)
  • apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/stream_core_flutter/lib/src/theme/stream_app_style.dart (1)

7-11: 💤 Low value

Clarify naming: StreamAppStyle.floating() keeps appBarBehavior as regular.

The .floating() constructor sets composerLocation = floating but appBarBehavior = AppBarBehavior.regular. This may confuse consumers who expect "floating" to also affect the app bar. Consider either:

  • Adding a doc comment explaining this distinction, or
  • Renaming to StreamAppStyle.floatingComposer() for clarity
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_core_flutter/lib/src/theme/stream_app_style.dart` around
lines 7 - 11, The floating constructor StreamAppStyle.floating() sets
composerLocation = ComposerLocation.floating but leaves appBarBehavior =
AppBarBehavior.regular which can confuse callers; update the API to make intent
explicit by either adding a doc comment on StreamAppStyle.floating() that
documents that only the composerLocation changes (appBarBehavior remains
regular), or rename the constructor to StreamAppStyle.floatingComposer() and
update all usages to the new name so it clearly indicates only the composer is
floating while composerLocation and appBarBehavior fields remain explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart`:
- Around line 1-2: Remove the unused JavaScript interop import: delete the line
"import 'dart:js_interop';" from stream_app_bar.dart (the import at the top of
the file) and run the analyzer or build to confirm there are no remaining
references to dart:js_interop in this file; this file's symbols like the
StreamAppBar widget/constructor do not require JS interop so the import is safe
to remove.

---

Nitpick comments:
In `@packages/stream_core_flutter/lib/src/theme/stream_app_style.dart`:
- Around line 7-11: The floating constructor StreamAppStyle.floating() sets
composerLocation = ComposerLocation.floating but leaves appBarBehavior =
AppBarBehavior.regular which can confuse callers; update the API to make intent
explicit by either adding a doc comment on StreamAppStyle.floating() that
documents that only the composerLocation changes (appBarBehavior remains
regular), or rename the constructor to StreamAppStyle.floatingComposer() and
update all usages to the new name so it clearly indicates only the composer is
floating while composerLocation and appBarBehavior fields remain explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ac5ca1cf-6f3b-4b23-a425-08b5d6d077c5

📥 Commits

Reviewing files that changed from the base of the PR and between 84123de and 234103c.

📒 Files selected for processing (5)
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/lib/src/theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_app_style.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart
✅ Files skipped from review due to trivial changes (1)
  • packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart

Comment thread packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart Outdated
@renefloor
renefloor force-pushed the feat/floating-header branch from 234103c to 24ae763 Compare May 28, 2026 15:06
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Actionable comments posted: 0

@renefloor
renefloor force-pushed the feat/floating-header branch from 61b0dfb to 3bd5156 Compare May 29, 2026 11:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart`:
- Around line 203-224: Wrap the floating nav item in a Semantics widget (around
the existing GestureDetector or its child) and set semantics properties to
expose it as a button with selection state: provide button: true, selected:
selected, label: item.label (and optionally a meaningful onTapHint), and include
the onTap callback via the Semantics onTap so assistive tech announces role and
selected/unselected state while preserving the existing onTap behavior; update
the build that uses item, selected, and onTap accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a1618e8-8268-4f3e-a9c4-cd1534d3b36c

📥 Commits

Reviewing files that changed from the base of the PR and between 24ae763 and 61b0dfb.

📒 Files selected for processing (4)
  • packages/stream_core_flutter/lib/src/components.dart
  • packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart
  • packages/stream_core_flutter/lib/src/theme/stream_app_style.dart
✅ Files skipped from review due to trivial changes (1)
  • packages/stream_core_flutter/lib/src/components.dart

@renefloor
renefloor force-pushed the feat/floating-header branch 2 times, most recently from e41df72 to bb75889 Compare June 12, 2026 08:20
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.69841% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.32%. Comparing base (59b3f4e) to head (f212d5a).

Files with missing lines Patch % Lines
.../src/components/toolbar/stream_bottom_nav_bar.dart 92.99% 11 Missing ⚠️
.../theme/components/stream_bottom_nav_bar_theme.dart 42.85% 8 Missing ⚠️
...utter/lib/src/components/avatar/stream_avatar.dart 90.00% 2 Missing ⚠️
...r/lib/src/components/scaffold/stream_scaffold.dart 97.40% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #115      +/-   ##
==========================================
+ Coverage   44.53%   50.32%   +5.78%     
==========================================
  Files         178      183       +5     
  Lines        7243     7531     +288     
==========================================
+ Hits         3226     3790     +564     
+ Misses       4017     3741     -276     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@renefloor
renefloor force-pushed the feat/floating-header branch from 8c584a4 to 682d15f Compare June 16, 2026 14:03
Comment thread packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart Outdated
# Conflicts:
#	packages/stream_core_flutter/CHANGELOG.md
#	packages/stream_core_flutter/lib/src/components.dart
#	packages/stream_core_flutter/lib/src/theme.dart
@renefloor
renefloor force-pushed the feat/floating-header branch 2 times, most recently from a8ee82d to a78be57 Compare June 19, 2026 09:20
@renefloor
renefloor force-pushed the feat/floating-header branch from a78be57 to 7c55b73 Compare June 19, 2026 09:30
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/stream_core_flutter/CHANGELOG.md (1)

12-14: ⚡ Quick win

Vary the opening phrasing to reduce repetition in the "Upcoming" release notes.

Lines 12–14 begin three consecutive bullet points with "- Added", which reads awkwardly and affects documentation clarity. Consider grouping related additions or rewording for variety (e.g., "Introduced", "Added support for", "New component").

- Added `StreamSnackbar` and `StreamSnackbarTheme` — Stream-styled transient feedback snackbars with a messenger-driven queue.
- Added `StreamIcons.megaphone` and `StreamIcons.shield` (20px) to the icon set.
- Added `StreamMentionType` identifier for supported mention types and options for mention text customisation per type.
+ Introduced `StreamSnackbar` and `StreamSnackbarTheme` — Stream-styled transient feedback snackbars with a messenger-driven queue.
+ Added new icon variants (`StreamIcons.megaphone` and `StreamIcons.shield`, 20px) to the icon set.
+ Added `StreamMentionType` identifier for supported mention types and options for mention text customisation per type.

This pattern also appears frequently in the 0.3.0 section (lines 24–29+); consider applying similar rewording there for consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_core_flutter/CHANGELOG.md` around lines 12 - 14, The
"Upcoming" release notes section contains three consecutive bullet points (lines
12-14) that all begin with "- Added", creating repetitive and awkward phrasing.
Reword these bullet points with varied opening phrases such as "Introduced",
"Added support for", or "New component" to improve readability and flow.
Additionally, apply the same rewording approach to the 0.3.0 section (lines
24-29+) where the same repetitive "- Added" pattern appears multiple times,
ensuring consistent and varied language throughout the changelog.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/stream_core_flutter/CHANGELOG.md`:
- Around line 12-14: The "Upcoming" release notes section contains three
consecutive bullet points (lines 12-14) that all begin with "- Added", creating
repetitive and awkward phrasing. Reword these bullet points with varied opening
phrases such as "Introduced", "Added support for", or "New component" to improve
readability and flow. Additionally, apply the same rewording approach to the
0.3.0 section (lines 24-29+) where the same repetitive "- Added" pattern appears
multiple times, ensuring consistent and varied language throughout the
changelog.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 460a0c5a-50a6-4464-88a8-469e7a5907ed

📥 Commits

Reviewing files that changed from the base of the PR and between 61b0dfb and 66ee511.

⛔ Files ignored due to path filters (12)
  • packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_light.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_shadow_dark.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_shadow_light.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating_disabled.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_dark.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_floating_dark.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_floating_light.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_light.png is excluded by !**/*.png
📒 Files selected for processing (27)
  • apps/design_system_gallery/lib/components/avatar/stream_avatar.dart
  • apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart
  • apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart
  • apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/CHANGELOG.md
  • packages/stream_core_flutter/lib/core.dart
  • packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart
  • packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart
  • packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart
  • packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart
  • packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_app_style.dart
  • packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart
  • packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart
  • packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart
✅ Files skipped from review due to trivial changes (3)
  • packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/stream_core_flutter/lib/src/theme/stream_theme.dart
  • apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart
  • packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart

renefloor and others added 6 commits July 17, 2026 11:09
# Conflicts:
#	packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
#	packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart
Restructure StreamBottomNavBar onto the standard design-system shape:
Props + StreamBottomNavBar (factory lookup) + DefaultStreamBottomNavBar,
with styling resolved via effective-value locals off a token-backed
_StreamBottomNavBarStyleDefaults.

- Add StreamBottomNavBarTheme / ThemeData / Style (@themeGen), registered
  on StreamTheme, exposed via context.streamBottomNavBarTheme and core.dart.
- Add a dedicated StreamBottomNavBarBehavior enum; resolution order is
  per-instance behavior -> nav-bar theme -> StreamAppStyle.
- Own the docked + floating rendering (animated tiles, tap ripple, tab
  semantics) instead of delegating the regular case to a Material widget.
- Register a bottomNavBar hook on StreamComponentFactory.
- Add unit + semantics tests and a golden test (regular/floating x light/dark);
  update the gallery use-cases to sit in a StreamScaffold-style preview.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…wner

Toggling the semantics debugger on threw a null-check error: the pipeline
owner was only wired in didChangeDependencies (gated on enabled), which
isn't re-run on a plain prop toggle, so build hit `_pipelineOwner!` while
still null. Sync the owner when enabling and fall back to the child when it
is unset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tomNavBar

Resolve the regular and floating backgrounds as separate, unconditional
effective-value locals (effectiveBackgroundColor / effectiveFloatingBackgroundColor)
instead of a behavior switch that collapsed them into one value, and rename
effectiveStreamAppBarBehavior to effectiveBehavior. Behavior-preserving — the
rendered output is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart`:
- Around line 214-222: Update the Container wrapping bar to move its border from
BoxDecoration.border into a foregroundDecoration BoxDecoration, preserving the
existing color, radius, and border styling while keeping clipBehavior unchanged.
- Around line 74-86: Convert the result of _currentIndex.clamp(0, items.length -
1) to int when assigning currentIndex, so it satisfies StreamBottomNavBar’s int
currentIndex parameter while preserving the existing bounds.

In `@packages/stream_core_flutter/CHANGELOG.md`:
- Line 24: Correct the changelog entry for StreamBottomNavBar to remove
StreamBottomAppBarTheme from the behavior resolution chain, since
StreamBottomNavBarTheme.of() only resolves the local and ambient bottom
navigation bar themes. Preserve the remaining documented themes and resolution
order.

In
`@packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart`:
- Around line 97-111: Add an assertion in the StreamBottomNavBar constructor
validating that currentIndex is within the items range (currentIndex >= 0 &&
currentIndex < items.length), with a clear message. Keep the existing
minimum-items assertion and ensure the same invariant protects _resetState and
didUpdateWidget from out-of-range controller access.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6535d66f-b59c-46c8-9856-bf1e44295f01

📥 Commits

Reviewing files that changed from the base of the PR and between 66ee511 and 111b96a.

⛔ Files ignored due to path filters (2)
  • packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_bottom_nav_bar_floating.png is excluded by !**/*.png
  • packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_bottom_nav_bar_regular.png is excluded by !**/*.png
📒 Files selected for processing (21)
  • apps/design_system_gallery/lib/app/gallery_app.directories.g.dart
  • apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart
  • apps/design_system_gallery/lib/widgets/scoped_semantics_debugger.dart
  • packages/stream_core_flutter/CHANGELOG.md
  • packages/stream_core_flutter/lib/core.dart
  • packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart
  • packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart
  • packages/stream_core_flutter/lib/src/factory/stream_component_factory.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme_extensions.dart
  • packages/stream_core_flutter/test/components/avatar/stream_avatar_test.dart
  • packages/stream_core_flutter/test/components/scaffold/stream_scaffold_test.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_golden_test.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart
  • packages/stream_core_flutter/test/theme/stream_theme_test.dart
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart
  • packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart
  • packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart
  • packages/stream_core_flutter/lib/core.dart

Comment on lines +74 to +86
final items = _navItems(context).take(itemCount).toList();
// Keep the selected index in range as the item count changes.
final currentIndex = _currentIndex.clamp(0, items.length - 1);

return Align(
alignment: Alignment.bottomCenter,
child: StreamBottomNavBar(
items: items,
currentIndex: currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
behavior: floating ? StreamBottomNavBarBehavior.floating : StreamBottomNavBarBehavior.regular,
),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Call site ==\n'
sed -n '68,90p' apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart

printf '\n== StreamBottomNavBar signature ==\n'
rg -n "class StreamBottomNavBar|currentIndex" apps/design_system_gallery/lib/components/toolbar -A 4 -B 4

Repository: GetStream/stream-core-flutter

Length of output: 6006


🌐 Web query:

Dart int.clamp return type num official docs

💡 Result:

According to the official Dart documentation, the clamp method is defined on the num class, and its static return type is num [1][2][3]. While int inherits this method from num, the static signature remains num clamp(num lowerLimit, num upperLimit) [1][2]. Although the method will return an int at runtime if the receiver and both arguments are integers, the Dart type system statically treats the return value as num [4][2][5].

Citations:


Convert the clamped index back to int.
clamp() returns num, so currentIndex is not assignable to the int parameter here and the file won’t type-check.

🐛 Proposed fix
-    final currentIndex = _currentIndex.clamp(0, items.length - 1);
+    final currentIndex = _currentIndex.clamp(0, items.length - 1).toInt();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final items = _navItems(context).take(itemCount).toList();
// Keep the selected index in range as the item count changes.
final currentIndex = _currentIndex.clamp(0, items.length - 1);
return Align(
alignment: Alignment.bottomCenter,
child: StreamBottomNavBar(
items: items,
currentIndex: currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
behavior: floating ? StreamBottomNavBarBehavior.floating : StreamBottomNavBarBehavior.regular,
),
);
final items = _navItems(context).take(itemCount).toList();
// Keep the selected index in range as the item count changes.
final currentIndex = _currentIndex.clamp(0, items.length - 1).toInt();
return Align(
alignment: Alignment.bottomCenter,
child: StreamBottomNavBar(
items: items,
currentIndex: currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
behavior: floating ? StreamBottomNavBarBehavior.floating : StreamBottomNavBarBehavior.regular,
),
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart`
around lines 74 - 86, Convert the result of _currentIndex.clamp(0, items.length
- 1) to int when assigning currentIndex, so it satisfies StreamBottomNavBar’s
int currentIndex parameter while preserving the existing bounds.

Comment on lines +214 to +222
Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: colorScheme.backgroundSurface,
borderRadius: BorderRadius.all(radius.lg),
border: Border.all(color: colorScheme.borderSubtle),
),
child: bar,
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Move the border to foregroundDecoration.

Border drawn via BoxDecoration.border here is painted behind the child and can be clipped by clipBehavior: Clip.antiAlias. As per path instructions, apps/design_system_gallery/{lib/components,lib/semantics,lib/primitives,lib/widgets}/**/*.dart: "Use foregroundDecoration for borders to prevent clipping issues, rather than using border property in BoxDecoration."

♻️ Proposed fix
         Container(
           clipBehavior: Clip.antiAlias,
           decoration: BoxDecoration(
             color: colorScheme.backgroundSurface,
             borderRadius: BorderRadius.all(radius.lg),
-            border: Border.all(color: colorScheme.borderSubtle),
+          ),
+          foregroundDecoration: BoxDecoration(
+            borderRadius: BorderRadius.all(radius.lg),
+            border: Border.all(color: colorScheme.borderSubtle),
           ),
           child: bar,
         ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: colorScheme.backgroundSurface,
borderRadius: BorderRadius.all(radius.lg),
border: Border.all(color: colorScheme.borderSubtle),
),
child: bar,
),
Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: colorScheme.backgroundSurface,
borderRadius: BorderRadius.all(radius.lg),
),
foregroundDecoration: BoxDecoration(
borderRadius: BorderRadius.all(radius.lg),
border: Border.all(color: colorScheme.borderSubtle),
),
child: bar,
),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart`
around lines 214 - 222, Update the Container wrapping bar to move its border
from BoxDecoration.border into a foregroundDecoration BoxDecoration, preserving
the existing color, radius, and border styling while keeping clipBehavior
unchanged.

Source: Path instructions


- Split the public API into `package:stream_core_flutter/core.dart` (shared primitives for any Stream SDK) and `package:stream_core_flutter/chat.dart` (chat-only widgets; re-exports `core.dart`); the convenience barrel `package:stream_core_flutter/stream_core_flutter.dart` is now deprecated.
- Added `StreamScaffold` — a full-page scaffold that supports both regular and floating app-bar / bottom-bar layouts. Injects `StreamScaffoldInsets` into the widget tree so scrollable bodies can read the effective top and bottom padding from floating bars without coupling to layout details.
- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Renders either a regular docked bar or a floating pill with a gradient fade-out beneath it, resolved from the per-instance `behavior`, the `StreamBottomNavBarTheme`, the `StreamBottomAppBarTheme` (kept in sync with `StreamScaffold`), then `StreamAppStyle`. Follows the standard `Props`/`Default`/`StreamComponentFactory` pattern (`bottomNavBar` builder) and is themeable via `StreamBottomNavBarTheme` / `StreamBottomNavBarStyle` (selected/unselected item colours, icon size, label styles, border, pill radius). Items announce themselves as accessible buttons via `Semantics`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Changelog describes StreamBottomAppBarTheme in the resolution chain, but it has no effect.

StreamBottomNavBarTheme.of() only merges the local StreamBottomNavBarTheme with the ambient StreamTheme.of(context).bottomNavBarTheme — it never reads StreamBottomAppBarTheme. This is explicitly confirmed by the new test 'is independent of StreamBottomAppBarTheme' in stream_bottom_nav_bar_test.dart, which asserts a floating StreamBottomAppBarTheme has no effect on the nav bar's behavior. The changelog entry should be corrected to avoid misleading consumers about the resolution order.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_core_flutter/CHANGELOG.md` at line 24, Correct the changelog
entry for StreamBottomNavBar to remove StreamBottomAppBarTheme from the behavior
resolution chain, since StreamBottomNavBarTheme.of() only resolves the local and
ambient bottom navigation bar themes. Preserve the remaining documented themes
and resolution order.

Comment on lines +97 to +111
StreamBottomNavBar({
super.key,
required List<StreamBottomNavBarItem> items,
required int currentIndex,
required ValueChanged<int> onTap,
StreamBottomNavBarBehavior? behavior,
StreamBottomNavBarStyle? style,
}) : assert(items.length >= 2, 'StreamBottomNavBar requires at least 2 items'),
props = .new(
items: items,
currentIndex: currentIndex,
onTap: onTap,
behavior: behavior,
style: style,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add a bounds assertion for currentIndex.

items.length is validated but currentIndex isn't; an out-of-range value crashes with an unguarded RangeError in _resetState/didUpdateWidget (_controllers[widget.props.currentIndex]) instead of a clear assertion message.

🛡️ Proposed fix
   }) : assert(items.length >= 2, 'StreamBottomNavBar requires at least 2 items'),
+       assert(
+         currentIndex >= 0 && currentIndex < items.length,
+         'currentIndex must be within the bounds of items',
+       ),
        props = .new(

Also applies to: 199-218, 243-257

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart`
around lines 97 - 111, Add an assertion in the StreamBottomNavBar constructor
validating that currentIndex is within the items range (currentIndex >= 0 &&
currentIndex < items.length), with a clear message. Keep the existing
minimum-items assertion and ensure the same invariant protects _resetState and
didUpdateWidget from out-of-range controller access.

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.

2 participants