fix(mobile): clip preset agent avatar previews to the squircle

Catalog avatars in the picker and Create agent previews rendered unclipped,
so the default create preview did not match the created agent. Let
PresetAgentAvatar own the agent clip and assert the catalog state in the
picker journey.

Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@localhost>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tom Brow <tomb@squareup.com>
This commit is contained in:
Tom Brow
2026-10-31 10:55:41 -07:00
parent 00b1ec6cc1
commit 355ebca27e
2 changed files with 35 additions and 26 deletions

View File

@@ -7,6 +7,7 @@ import 'package:video_player/video_player.dart';
import '../animated_avatar.dart'; import '../animated_avatar.dart';
import 'avatar_image.dart'; import 'avatar_image.dart';
import 'avatar_shape.dart';
import 'android_transparent_avatar.dart'; import 'android_transparent_avatar.dart';
/// Plays the transparent video paired with a bundled character poster. /// Plays the transparent video paired with a bundled character poster.
@@ -98,6 +99,8 @@ class PresetAgentAvatar extends HookWidget {
return SizedBox.square( return SizedBox.square(
dimension: size, dimension: size,
child: AvatarClip(
isAgent: true,
child: Transform.scale( child: Transform.scale(
scale: animatedAvatarArtworkScale, scale: animatedAvatarArtworkScale,
child: isAndroid && videoUrl != null child: isAndroid && videoUrl != null
@@ -114,6 +117,7 @@ class PresetAgentAvatar extends HookWidget {
? VideoPlayer(controller) ? VideoPlayer(controller)
: AvatarImageContent(imageUrl: poster, fallback: fallback), : AvatarImageContent(imageUrl: poster, fallback: fallback),
), ),
),
); );
} }
} }

View File

@@ -67,17 +67,8 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(selection.url, isNot(agentAvatarCatalog.first.url)); expect(selection.url, isNot(agentAvatarCatalog.first.url));
final character = selection.url; final character = selection.url;
await tester.runAsync(() async { // Every preview uses the same squircle the agent gets once created.
rendered = Completer<void>(); void expectSquirclePreview() {
tester
.widget<SegmentedButton<int>>(find.byType(SegmentedButton<int>))
.onSelectionChanged!({1});
await rendered.future.timeout(const Duration(seconds: 5));
});
await tester.pumpAndSettle();
expect(selection.bytes, isNotNull);
// The preview uses the same squircle the agent gets once created.
final previewClip = tester.widget<ClipPath>( final previewClip = tester.widget<ClipPath>(
find.descendant( find.descendant(
of: find.bySemanticsLabel('Selected agent avatar'), of: find.bySemanticsLabel('Selected agent avatar'),
@@ -88,6 +79,20 @@ void main() {
(previewClip.clipper! as ShapeBorderClipper).shape, (previewClip.clipper! as ShapeBorderClipper).shape,
avatarShape(isAgent: true), avatarShape(isAgent: true),
); );
}
expectSquirclePreview();
await tester.runAsync(() async {
rendered = Completer<void>();
tester
.widget<SegmentedButton<int>>(find.byType(SegmentedButton<int>))
.onSelectionChanged!({1});
await rendered.future.timeout(const Duration(seconds: 5));
});
await tester.pumpAndSettle();
expect(selection.bytes, isNotNull);
expectSquirclePreview();
expect( expect(
(tester (tester
.widget<GridView>( .widget<GridView>(