mirror of
https://github.com/block/buzz.git
synced 2026-10-30 22:11:36 +00:00
## Summary - add mobile editing for display name, profile description, and profile photo - support image positioning, emoji backgrounds, and animated avatar capture with native iOS controls - refine settings navigation, profile motion, and the connection identity row ## Testing - `just mobile-check` - `just mobile-test` (1,685 tests) --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Kenny Lopez <klopez4212@gmail.com> Co-authored-by: Carl <3c4caeafb646d23867f1c4832e68211d77e2561946171625f75c3ce1a3f2670f@buzz.block.builderlab.xyz>
281 lines
8.4 KiB
Dart
281 lines
8.4 KiB
Dart
import 'package:buzz/shared/theme/theme.dart';
|
|
import 'package:buzz/shared/widgets/frosted_app_bar.dart';
|
|
import 'package:buzz/shared/widgets/ios_glass_navigation_button.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
testWidgets('title row and reported height grow with accessible text', (
|
|
tester,
|
|
) async {
|
|
const titleStyle = TextStyle(fontSize: 22, height: 1.3);
|
|
late double reportedHeight;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: MediaQuery(
|
|
data: const MediaQueryData(textScaler: TextScaler.linear(2)),
|
|
child: Builder(
|
|
builder: (context) {
|
|
reportedHeight = frostedAppBarHeight(
|
|
context,
|
|
titleStyle: titleStyle,
|
|
);
|
|
return const Stack(
|
|
children: [
|
|
FrostedAppBar(title: Text('Search'), titleStyle: titleStyle),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
final clip = find.descendant(
|
|
of: find.byType(FrostedAppBar),
|
|
matching: find.byType(ClipRect),
|
|
);
|
|
expect(reportedHeight, greaterThan(48));
|
|
expect(tester.getSize(clip).height, closeTo(reportedHeight, 0.01));
|
|
expect(tester.getSize(find.text('Search')).height, greaterThan(48));
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('custom multi-line title height matches reported height', (
|
|
tester,
|
|
) async {
|
|
const titleContentHeight = 64.0;
|
|
late double reportedHeight;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Builder(
|
|
builder: (context) {
|
|
reportedHeight = frostedAppBarHeight(
|
|
context,
|
|
titleContentHeight: titleContentHeight,
|
|
);
|
|
return const Stack(
|
|
children: [
|
|
FrostedAppBar(
|
|
titleContentHeight: titleContentHeight,
|
|
title: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [Text('Title'), Text('Subtitle')],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
final clip = find.descendant(
|
|
of: find.byType(FrostedAppBar),
|
|
matching: find.byType(ClipRect),
|
|
);
|
|
expect(tester.getSize(clip).height, closeTo(reportedHeight, 0.01));
|
|
expect(reportedHeight, closeTo(titleContentHeight + Grid.xs + 1, 0.01));
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('centers a title between asymmetric navigation controls', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: const Stack(
|
|
children: [
|
|
FrostedAppBar(
|
|
centerTitle: true,
|
|
leading: SizedBox(width: 48, height: 48),
|
|
title: Text('Profile', key: ValueKey('centered-title')),
|
|
actions: [SizedBox(width: 96, height: 48)],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
final titleRect = tester.getRect(
|
|
find.byKey(const ValueKey('centered-title')),
|
|
);
|
|
expect(
|
|
titleRect.center.dx,
|
|
closeTo(
|
|
tester.view.physicalSize.width / tester.view.devicePixelRatio / 2,
|
|
0.01,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('uses the native glass back control on iOS', (tester) async {
|
|
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
|
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Builder(
|
|
builder: (context) => TextButton(
|
|
onPressed: () => Navigator.of(context).push(
|
|
MaterialPageRoute<void>(
|
|
builder: (_) => const Stack(
|
|
children: [
|
|
FrostedAppBar(
|
|
title: Text(
|
|
'Destination',
|
|
key: ValueKey('destination-title'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
child: const Text('Open'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
final nativeBack = tester.widget<UiKitView>(find.byType(UiKitView));
|
|
expect(nativeBack.viewType, 'buzz/navigation_glass');
|
|
expect(nativeBack.creationParams, containsPair('icon', 'back'));
|
|
expect(
|
|
nativeBack.creationParams,
|
|
containsPair('accessibilityLabel', 'Back'),
|
|
);
|
|
expect(
|
|
nativeBack.creationParams,
|
|
containsPair('buttonCenterX', iosGlassChannelHeaderButtonCenterX),
|
|
);
|
|
expect(
|
|
nativeBack.creationParams,
|
|
containsPair('hitTargetWidth', iosGlassChannelHeaderLeadingWidth),
|
|
);
|
|
expect(nativeBack.creationParams, containsPair('hitTargetHeight', 48.0));
|
|
final backRect = tester.getRect(find.byType(IosGlassNavigationButton));
|
|
final titleRect = tester.getRect(
|
|
find.byKey(const ValueKey('destination-title')),
|
|
);
|
|
expect(titleRect.left - backRect.right, iosGlassChannelHeaderTitleSpacing);
|
|
expect(find.byTooltip('Back'), findsOneWidget);
|
|
expect(
|
|
tester.widget<Tooltip>(find.byTooltip('Back')).excludeFromSemantics,
|
|
isTrue,
|
|
);
|
|
debugDefaultTargetPlatformOverride = null;
|
|
});
|
|
|
|
testWidgets('uses the theme primary color for automatic navigation glyphs', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Builder(
|
|
builder: (context) => TextButton(
|
|
onPressed: () => Navigator.of(context).push(
|
|
MaterialPageRoute<void>(
|
|
builder: (_) => const Stack(
|
|
children: [FrostedAppBar(title: Text('Destination'))],
|
|
),
|
|
),
|
|
),
|
|
child: const Text('Open'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
final backButton = tester.widget<IconButton>(
|
|
find.byWidgetPredicate(
|
|
(widget) => widget is IconButton && widget.tooltip == 'Back',
|
|
),
|
|
);
|
|
expect(backButton.color, AppTheme.light().colorScheme.primary);
|
|
});
|
|
|
|
testWidgets('replaces native glass while a Flutter backdrop is active', (
|
|
tester,
|
|
) async {
|
|
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
|
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
|
final suppressNativeView = ValueNotifier(false);
|
|
addTearDown(suppressNativeView.dispose);
|
|
var pressCount = 0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Scaffold(
|
|
body: IosGlassNavigationButton(
|
|
icon: IosGlassNavigationIcon.back,
|
|
semanticLabel: 'Back',
|
|
onPressed: () => pressCount++,
|
|
nativeViewSuppressed: suppressNativeView,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byType(UiKitView), findsOneWidget);
|
|
expect(
|
|
find.byKey(const ValueKey('ios-glass-navigation-flutter-fallback')),
|
|
findsNothing,
|
|
);
|
|
expect(find.bySemanticsLabel('Back'), findsNothing);
|
|
|
|
suppressNativeView.value = true;
|
|
await tester.pump();
|
|
|
|
expect(find.byType(UiKitView), findsNothing);
|
|
expect(
|
|
find.byKey(const ValueKey('ios-glass-navigation-flutter-fallback')),
|
|
findsOneWidget,
|
|
);
|
|
final fallbackFinder = find.bySemanticsLabel('Back');
|
|
expect(fallbackFinder, findsOneWidget);
|
|
final fallbackSemantics = tester.getSemantics(fallbackFinder);
|
|
expect(fallbackSemantics.flagsCollection.isButton, isTrue);
|
|
expect(
|
|
fallbackSemantics.flagsCollection.isEnabled.toString(),
|
|
'Tristate.isTrue',
|
|
);
|
|
expect(
|
|
fallbackSemantics.getSemanticsData().hasAction(SemanticsAction.tap),
|
|
isTrue,
|
|
);
|
|
tester.binding.performSemanticsAction(
|
|
SemanticsActionEvent(
|
|
type: SemanticsAction.tap,
|
|
viewId: tester.view.viewId,
|
|
nodeId: fallbackSemantics.id,
|
|
),
|
|
);
|
|
await tester.pump();
|
|
expect(pressCount, 1);
|
|
|
|
suppressNativeView.value = false;
|
|
await tester.pump();
|
|
|
|
expect(find.byType(UiKitView), findsOneWidget);
|
|
debugDefaultTargetPlatformOverride = null;
|
|
});
|
|
}
|