mirror of
https://github.com/block/buzz.git
synced 2026-11-10 11:21:05 +00:00
fix(mobile): keep Home bell tappable while scrolled (#9241)
## Summary Keep the mobile Home bell tappable while scrolling. Reserve both header buttons’ space as soon as the filters overlap the toolbar, and clip filter overflow. ### Related issue No matching open issue or PR found. ### Testing - `just mobile-check` and `just mobile-test` passed. - Android/iOS regression coverage checks the bell at five scroll positions and Activity navigation. iOS uses platform-view hit testing plus its callback; no physical-device verification. - Pre-push checks passed. The additional `just ci` run passed workspace Rust lint and desktop source checks; stopped during desktop native dependency compilation, so full local CI is incomplete. Signed-off-by: kenny lopez <klopez4212@gmail.com> Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -116,6 +116,7 @@ class ChannelsPage extends HookConsumerWidget {
|
||||
this.onSearch,
|
||||
this.messagesFilters,
|
||||
this.messagesActionsBuilder,
|
||||
this.messagesActionsWidth = 0,
|
||||
this.soloSliver,
|
||||
this.showTeam = true,
|
||||
this.showTeamHeading = false,
|
||||
@@ -133,6 +134,9 @@ class ChannelsPage extends HookConsumerWidget {
|
||||
final Widget Function(bool isCollapsed)? messagesFilters;
|
||||
final List<Widget> Function(VoidCallback openSwitcher, GlobalKey avatarKey)?
|
||||
messagesActionsBuilder;
|
||||
|
||||
/// Width of the trailing controls that collapsed filters must leave clear.
|
||||
final double messagesActionsWidth;
|
||||
final Widget? soloSliver;
|
||||
final bool showTeam;
|
||||
final bool showTeamHeading;
|
||||
@@ -737,10 +741,22 @@ class ChannelsPage extends HookConsumerWidget {
|
||||
? const SizedBox.expand()
|
||||
: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: 60 * headerCollapse.value / filterContentHeight,
|
||||
// As soon as the rows overlap, keep the entire action
|
||||
// cluster clear. Interpolating this inset blocks the bell
|
||||
// during partial collapse even when the final layout fits.
|
||||
right: headerCollapse.value > 0
|
||||
? messagesActionsWidth + _kTopSectionInset
|
||||
: 0,
|
||||
),
|
||||
child: messagesFilters!(
|
||||
headerCollapse.value >= filterContentHeight,
|
||||
child: ClipRect(
|
||||
// Native glass paints its shadows outside the viewport, but
|
||||
// scrolled filters must not paint over the header actions.
|
||||
clipBehavior: headerCollapse.value > 0
|
||||
? Clip.hardEdge
|
||||
: Clip.none,
|
||||
child: messagesFilters!(
|
||||
headerCollapse.value >= filterContentHeight,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -99,6 +99,8 @@ class HomePage extends HookConsumerWidget {
|
||||
);
|
||||
final messages = ChannelsPage(
|
||||
settingsPageBuilder: settingsPageBuilder,
|
||||
messagesActionsWidth:
|
||||
2 * (defaultTargetPlatform == TargetPlatform.iOS ? 44 : 48) + Grid.xs,
|
||||
messagesActionsBuilder: (openSwitcher, avatarKey) {
|
||||
final moreActions = [
|
||||
// An internal build reaches only its organization's community.
|
||||
|
||||
@@ -342,6 +342,49 @@ void main() {
|
||||
}
|
||||
|
||||
for (final platform in [TargetPlatform.android, TargetPlatform.iOS]) {
|
||||
testWidgets('$platform scrolled bell opens Activity', (tester) async {
|
||||
debugDefaultTargetPlatformOverride = platform;
|
||||
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(await buildHome(longSolo: true));
|
||||
await tester.pumpAndSettle();
|
||||
final scroll = tester
|
||||
.widget<CustomScrollView>(find.byType(CustomScrollView).first)
|
||||
.controller!;
|
||||
final collapseHeight = tester
|
||||
.widget<FrostedAppBar>(find.byType(FrostedAppBar))
|
||||
.bottomHeight;
|
||||
for (final fraction in [0.01, 0.25, 0.5, 0.75, 1.0]) {
|
||||
scroll.jumpTo(collapseHeight * fraction);
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
find.byTooltip('Activity').hitTestable(),
|
||||
findsOneWidget,
|
||||
reason: 'Bell must remain tappable at collapse fraction $fraction',
|
||||
);
|
||||
}
|
||||
if (platform == TargetPlatform.iOS) {
|
||||
// Widget tests hit-test the platform view but cannot run UIKit's
|
||||
// button action. Exercise the callback that native taps dispatch.
|
||||
tester
|
||||
.widget<IosGlassNavigationButton>(
|
||||
find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is IosGlassNavigationButton &&
|
||||
widget.icon == IosGlassNavigationIcon.bell,
|
||||
),
|
||||
)
|
||||
.onPressed!();
|
||||
} else {
|
||||
await tester.tap(find.byTooltip('Activity'));
|
||||
}
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(ActivityPage), findsOneWidget);
|
||||
debugDefaultTargetPlatformOverride = null;
|
||||
});
|
||||
|
||||
testWidgets('$platform bell follows unread inbox state', (tester) async {
|
||||
debugDefaultTargetPlatformOverride = platform;
|
||||
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
||||
|
||||
Reference in New Issue
Block a user