mirror of
https://github.com/block/buzz.git
synced 2026-10-30 22:11:36 +00:00
## Summary - Align mobile home avatars and share the same sticky-date and Latest controls across channels and threads. - Stabilize thread tail navigation and emoji category scrolling. - Remove iOS glass compositing artifacts and match long-press blur across action surfaces. ## Why Threads and emoji selection used competing scroll and compositing paths, causing rebounds, flicker, and inconsistent controls. ## Testing - `just mobile-check` - `flutter test` (1,529 tests) - Signed Release installed, launched, and reviewed on a connected iPhone --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: Watcher <bb7abfd757d0af7b66569d02ab9c0316b616f9d0c151ecf5b964344c462e7f8f@buzz.block.builderlab.xyz> Co-authored-by: Carl <3c4caeafb646d23867f1c4832e68211d77e2561946171625f75c3ce1a3f2670f@buzz.block.builderlab.xyz> Co-authored-by: Watcher <bb7abfd757d0af7b66569d02ab9c0316b616f9d0c151ecf5b964344c462e7f8f@buzz.block.builderlab.xyz>
212 lines
6.6 KiB
Dart
212 lines
6.6 KiB
Dart
import 'package:buzz/features/channels/message_action_backdrop_state.dart';
|
|
import 'package:buzz/features/channels/sticky_date_header.dart';
|
|
import 'package:buzz/shared/theme/theme.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
testWidgets(
|
|
'keeps the native iOS date compact and stationary during push-off',
|
|
(tester) async {
|
|
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
|
final state = ValueNotifier(
|
|
const StickyDateHeaderState(label: 'Yesterday'),
|
|
);
|
|
const channel = MethodChannel('buzz/sticky_date_glass/42');
|
|
final methodCalls = <MethodCall>[];
|
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
|
|
call,
|
|
) async {
|
|
methodCalls.add(call);
|
|
return null;
|
|
});
|
|
try {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Scaffold(body: StickyDateHeader(state: state)),
|
|
),
|
|
);
|
|
|
|
var nativeView = tester.widget<UiKitView>(find.byType(UiKitView));
|
|
expect(nativeView.viewType, 'buzz/sticky_date_glass');
|
|
expect(nativeView.creationParams, <String, Object>{
|
|
'label': 'Yesterday',
|
|
'brightness': 'light',
|
|
});
|
|
expect(find.byType(BackdropFilter), findsNothing);
|
|
final nativeSurface = find.byKey(
|
|
const ValueKey('channel-sticky-date-header-surface'),
|
|
);
|
|
expect(
|
|
tester.getSize(nativeSurface).width,
|
|
lessThan(tester.getSize(find.byType(StickyDateHeader)).width),
|
|
);
|
|
expect(
|
|
tester.getSize(nativeSurface).height,
|
|
StickyDateHeader.heightOf(
|
|
tester.element(find.byType(StickyDateHeader)),
|
|
),
|
|
);
|
|
expect(
|
|
find.byKey(const ValueKey('sticky-date-header-clip')),
|
|
findsNothing,
|
|
);
|
|
final initialSurfaceTop = tester.getTopLeft(nativeSurface).dy;
|
|
final stickyHeight = StickyDateHeader.heightOf(
|
|
tester.element(find.byType(StickyDateHeader)),
|
|
);
|
|
|
|
state.value = StickyDateHeaderState(
|
|
label: 'Yesterday',
|
|
translateY: -(stickyHeight + 5) / 2,
|
|
);
|
|
await tester.pump();
|
|
expect(
|
|
tester
|
|
.widget<Opacity>(
|
|
find.byKey(const ValueKey('sticky-date-push-off-opacity')),
|
|
)
|
|
.opacity,
|
|
closeTo(0.5, 0.001),
|
|
);
|
|
expect(
|
|
tester.getTopLeft(nativeSurface).dy,
|
|
closeTo(initialSurfaceTop, 0.01),
|
|
reason: 'Native glass must not cross the app-bar compositing edge.',
|
|
);
|
|
|
|
state.value = StickyDateHeaderState(
|
|
label: 'Yesterday',
|
|
translateY: -(stickyHeight + 5),
|
|
);
|
|
await tester.pump();
|
|
expect(
|
|
tester
|
|
.widget<Opacity>(
|
|
find.byKey(const ValueKey('sticky-date-push-off-opacity')),
|
|
)
|
|
.opacity,
|
|
0,
|
|
);
|
|
|
|
nativeView.onPlatformViewCreated!(42);
|
|
await tester.pump();
|
|
expect(
|
|
methodCalls.lastWhere((call) => call.method == 'setLabel').arguments,
|
|
'Yesterday',
|
|
);
|
|
|
|
state.value = const StickyDateHeaderState(label: 'Today');
|
|
await tester.pump();
|
|
nativeView = tester.widget<UiKitView>(find.byType(UiKitView));
|
|
expect(nativeView.creationParams, <String, Object>{
|
|
'label': 'Today',
|
|
'brightness': 'light',
|
|
});
|
|
expect(
|
|
methodCalls.lastWhere((call) => call.method == 'setLabel').arguments,
|
|
'Today',
|
|
);
|
|
expect(
|
|
tester
|
|
.widget<Opacity>(
|
|
find.byKey(const ValueKey('sticky-date-push-off-opacity')),
|
|
)
|
|
.opacity,
|
|
1,
|
|
);
|
|
|
|
messageActionBackdropActive.value = true;
|
|
await tester.pump();
|
|
expect(find.byType(UiKitView), findsNothing);
|
|
expect(find.byType(BackdropFilter), findsOneWidget);
|
|
expect(
|
|
find.byKey(const ValueKey('sticky-date-header-clip')),
|
|
findsNothing,
|
|
);
|
|
expect(
|
|
tester
|
|
.getSize(
|
|
find.byKey(
|
|
const ValueKey('channel-sticky-date-header-surface'),
|
|
),
|
|
)
|
|
.width,
|
|
lessThan(tester.getSize(find.byType(StickyDateHeader)).width),
|
|
);
|
|
} finally {
|
|
messageActionBackdropActive.value = false;
|
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
channel,
|
|
null,
|
|
);
|
|
state.dispose();
|
|
debugDefaultTargetPlatformOverride = null;
|
|
}
|
|
},
|
|
);
|
|
|
|
testWidgets('keeps the compact Flutter date surface on Android', (
|
|
tester,
|
|
) async {
|
|
debugDefaultTargetPlatformOverride = TargetPlatform.android;
|
|
final state = ValueNotifier(const StickyDateHeaderState(label: 'Today'));
|
|
try {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Scaffold(body: StickyDateHeader(state: state)),
|
|
),
|
|
);
|
|
|
|
expect(find.byType(UiKitView), findsNothing);
|
|
expect(find.byType(BackdropFilter), findsOneWidget);
|
|
expect(find.text('Today'), findsOneWidget);
|
|
expect(
|
|
find.byKey(const ValueKey('sticky-date-header-clip')),
|
|
findsNothing,
|
|
);
|
|
final flutterSurface = find.byKey(
|
|
const ValueKey('channel-sticky-date-header-surface'),
|
|
);
|
|
final initialSurfaceTop = tester.getTopLeft(flutterSurface).dy;
|
|
final stickyHeight = StickyDateHeader.heightOf(
|
|
tester.element(find.byType(StickyDateHeader)),
|
|
);
|
|
|
|
state.value = StickyDateHeaderState(
|
|
label: 'Today',
|
|
translateY: -(stickyHeight + 5) / 2,
|
|
);
|
|
await tester.pump();
|
|
expect(
|
|
tester
|
|
.widget<Opacity>(
|
|
find.byKey(const ValueKey('sticky-date-push-off-opacity')),
|
|
)
|
|
.opacity,
|
|
closeTo(0.5, 0.001),
|
|
);
|
|
expect(
|
|
tester.getTopLeft(flutterSurface).dy,
|
|
closeTo(initialSurfaceTop, 0.01),
|
|
reason: 'Android uses the same stationary date handoff as iOS.',
|
|
);
|
|
expect(
|
|
tester
|
|
.getSize(
|
|
find.byKey(const ValueKey('channel-sticky-date-header-surface')),
|
|
)
|
|
.width,
|
|
lessThan(tester.getSize(find.byType(StickyDateHeader)).width),
|
|
);
|
|
} finally {
|
|
state.dispose();
|
|
debugDefaultTargetPlatformOverride = null;
|
|
}
|
|
});
|
|
}
|