Files
buzz/mobile/lib/shared/widgets/buzz_titled_sheet_layout.dart
klopez4212 ed11c8d8bf Refresh mobile utility surfaces and theme picker (#6944)
## Summary

- invert mobile utility surfaces so pages and sheets use the softer page
background with raised containers
- rebuild the community theme picker around swipeable Home/Chat
previews, accent and appearance controls, and native iOS glass
interactions
- align shared sheet/profile spacing and radii, and move Theme into the
Community settings card

### Related issue

None found.

### Testing

- `just mobile-check`
- `just mobile-test` (1,871 tests)
- signed iOS Release build installed on a physical iPhone

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
2026-08-28 18:56:42 +01:00

120 lines
3.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import '../theme/theme.dart';
import 'buzz_sheet_header.dart';
import 'concentric_sheet_surface.dart';
/// Shared solid sheet surface with a centered navigation row.
class BuzzTitledSheetLayout extends HookWidget {
const BuzzTitledSheetLayout({
super.key,
required this.title,
required this.child,
this.leading,
this.trailing,
this.titleKey,
this.showDragHandle = false,
this.surfaceColor,
});
final String title;
final Widget child;
final Widget? leading;
final Widget? trailing;
final Key? titleKey;
final bool showDragHandle;
final Color? surfaceColor;
@override
Widget build(BuildContext context) {
final isScrolledUnder = useState(false);
final pendingScrolledUnder = useRef<bool?>(null);
final scrollUpdateScheduled = useRef(false);
final color = surfaceColor ?? context.colors.surface;
final paintsSurface = !ConcentricSheetSurface.providesSurfaceOf(context);
void updateScrollUnder(bool next) {
if (scrollUpdateScheduled.value) {
pendingScrolledUnder.value =
(pendingScrolledUnder.value ?? false) || next;
return;
}
pendingScrolledUnder.value = next;
scrollUpdateScheduled.value = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
scrollUpdateScheduled.value = false;
final pending = pendingScrolledUnder.value;
pendingScrolledUnder.value = null;
if (!context.mounted ||
pending == null ||
pending == isScrolledUnder.value) {
return;
}
isScrolledUnder.value = pending;
});
}
final sheet = SizedBox(
width: double.infinity,
child: ColoredBox(
key: const ValueKey('buzz-sheet-surface'),
color: paintsSurface ? color : Colors.transparent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DecoratedBox(
key: const ValueKey('buzz-sheet-scroll-divider'),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: isScrolledUnder.value
? navigationDivider(context, 0.05)
: Colors.transparent,
),
),
),
child: BuzzSheetHeader(
title: title,
titleKey: titleKey,
leading: leading,
trailing: trailing,
showDragHandle: showDragHandle,
),
),
Flexible(
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification.depth != 0 ||
notification.metrics.axis != Axis.vertical ||
(notification is! ScrollUpdateNotification &&
notification is! OverscrollNotification)) {
return false;
}
final next = notification.metrics.extentBefore > 0.5;
if (next != isScrolledUnder.value) updateScrollUnder(next);
return false;
},
child: child,
),
),
],
),
),
);
// The native iOS surface owns its exact iOS 26 container-concentric mask.
// A second fixed Flutter radius would visibly square off those corners.
if (!paintsSurface) return sheet;
return ClipRRect(
key: const ValueKey('buzz-sheet-surface-clip'),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(Radii.dialog),
),
clipBehavior: Clip.antiAlias,
child: sheet,
);
}
}