Files
buzz/mobile/test/shared/widgets/frosted_scaffold_test.dart
klopez4212 5f2d801b8f fix(mobile): align Android conversation headers and reactions (#8082)
## Summary
Align Android channel and DM headers with iOS: centered, tappable titles
with presence or member counts and no avatars. Keep conversation
navigation frosted through keyboard and scroll changes, and run the
typing shimmer left to right.

Add an Android reaction details sheet with All/emoji tabs, swipe
navigation, and compact rows aligned to the tab gutters. Native iOS
reaction presentation is unchanged.

### Related issue
None found.

### Testing
- Mobile analysis, formatting, file-size checks, and full mobile tests
passed.
- Android debug build installed and launched on Pixel 10.
- Full `just ci` could not complete: disk space exhausted while fetching
an unrelated Rust dependency.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
2026-10-04 16:49:12 +01:00

183 lines
5.9 KiB
Dart

import 'package:buzz/shared/theme/theme.dart';
import 'package:buzz/shared/widgets/frosted_app_bar.dart';
import 'package:buzz/shared/widgets/frosted_scaffold.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Border? _appBarBorder(WidgetTester tester) {
final container = tester.widget<Container>(
find.byKey(const ValueKey('frosted-app-bar-background')),
);
return (container.decoration as BoxDecoration?)?.border as Border?;
}
void main() {
testWidgets('utility pages expose the inverted surface hierarchy', (
tester,
) async {
const pageSurface = Color(0xFFEEEEEE);
const containerSurface = Color(0xFFFFFFFF);
await tester.pumpWidget(
MaterialApp(
theme: AppTheme.light(
colorScheme: lightColorScheme.copyWith(
surface: containerSurface,
surfaceContainerHighest: pageSurface,
),
),
home: FrostedScaffold(
useUtilitySurfaceTheme: true,
appBar: const FrostedAppBar(title: Text('Settings')),
body: Builder(
builder: (context) => Column(
children: [
ColoredBox(
key: const ValueKey('utility-page-surface'),
color: Theme.of(context).colorScheme.surface,
child: const SizedBox.square(dimension: 20),
),
ColoredBox(
key: const ValueKey('utility-container-surface'),
color: Theme.of(context).colorScheme.surfaceContainerHighest,
child: const SizedBox.square(dimension: 20),
),
],
),
),
),
),
);
expect(
tester
.widget<ColoredBox>(
find.byKey(const ValueKey('utility-page-surface')),
)
.color,
pageSurface,
);
expect(
tester
.widget<ColoredBox>(
find.byKey(const ValueKey('utility-container-surface')),
)
.color,
containerSurface,
);
});
for (final reverse in [false, true]) {
testWidgets(
'composer scrolling preserves timeline frost reverse=$reverse',
(tester) async {
tester.view.physicalSize = const Size(400, 800);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final timeline = ScrollController(
initialScrollOffset: reverse ? 0 : 120,
);
addTearDown(timeline.dispose);
final composer = TextEditingController();
addTearDown(composer.dispose);
await tester.pumpWidget(
MaterialApp(
theme: AppTheme.light(),
home: FrostedScaffold(
appBar: const FrostedAppBar(title: Text('Conversation')),
body: Column(
children: [
Expanded(
child: ListView.builder(
reverse: reverse,
controller: timeline,
itemCount: 40,
itemBuilder: (_, index) =>
SizedBox(height: 48, child: Text('Message $index')),
),
),
SizedBox(
height: 100,
child: TextField(
controller: composer,
minLines: 1,
maxLines: 3,
),
),
],
),
),
),
);
await tester.pumpAndSettle();
expect(find.byType(BackdropFilter), findsOneWidget);
await tester.tap(find.byType(TextField));
tester.view.viewInsets = const FakeViewPadding(bottom: 300);
await tester.enterText(
find.byType(TextField),
'One\nTwo\nThree\nFour\nFive',
);
await tester.pumpAndSettle();
expect(find.byType(BackdropFilter), findsOneWidget);
await tester.enterText(find.byType(TextField), '');
await tester.pumpAndSettle();
expect(find.byType(BackdropFilter), findsOneWidget);
expect(_appBarBorder(tester)?.bottom.color.a, greaterThan(0));
timeline.jumpTo(reverse ? timeline.position.maxScrollExtent : 0);
await tester.pumpAndSettle();
expect(find.byType(BackdropFilter), findsNothing);
await tester.enterText(
find.byType(TextField),
'One\nTwo\nThree\nFour\nFive',
);
await tester.pumpAndSettle();
expect(find.byType(BackdropFilter), findsNothing);
},
);
}
testWidgets(
'page frost and divider appear only while content scrolls under header',
(tester) async {
await tester.pumpWidget(
MaterialApp(
theme: AppTheme.light(),
home: FrostedScaffold(
appBar: const FrostedAppBar(title: Text('Theme')),
body: ListView.builder(
key: const ValueKey('page-scroll-view'),
padding: const EdgeInsets.only(top: 57),
itemCount: 40,
itemBuilder: (_, index) =>
SizedBox(height: 48, child: Text('Theme option $index')),
),
),
),
);
expect(_appBarBorder(tester)?.bottom.color.a, 0);
expect(find.byType(BackdropFilter), findsNothing);
await tester.drag(
find.byKey(const ValueKey('page-scroll-view')),
const Offset(0, -120),
);
await tester.pumpAndSettle();
final border = _appBarBorder(tester);
expect(border, isNotNull);
expect(border!.bottom.color.a, greaterThan(0));
expect(find.byType(BackdropFilter), findsOneWidget);
await tester.drag(
find.byKey(const ValueKey('page-scroll-view')),
const Offset(0, 500),
);
await tester.pumpAndSettle();
expect(_appBarBorder(tester)?.bottom.color.a, 0);
expect(find.byType(BackdropFilter), findsNothing);
},
);
}