Skip to content

Commit 355ebca

Browse files
square-tombstudioclaude
committed
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 <[email protected]> Signed-off-by: Tom Brow <[email protected]>
1 parent 00b1ec6 commit 355ebca

2 files changed

Lines changed: 35 additions & 26 deletions

File tree

‎mobile/lib/shared/widgets/preset_agent_avatar.dart‎

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:video_player/video_player.dart';
77

88
import '../animated_avatar.dart';
99
import 'avatar_image.dart';
10+
import 'avatar_shape.dart';
1011
import 'android_transparent_avatar.dart';
1112

1213
/// Plays the transparent video paired with a bundled character poster.
@@ -98,21 +99,24 @@ class PresetAgentAvatar extends HookWidget {
9899

99100
return SizedBox.square(
100101
dimension: size,
101-
child: Transform.scale(
102-
scale: animatedAvatarArtworkScale,
103-
child: isAndroid && videoUrl != null
104-
? AndroidTransparentAvatar(
105-
key: ValueKey(videoUrl),
106-
url: videoUrl,
107-
playing: playing,
108-
fallback: AvatarImageContent(
109-
imageUrl: poster,
110-
fallback: fallback,
111-
),
112-
)
113-
: controller != null && ready.value == controller
114-
? VideoPlayer(controller)
115-
: AvatarImageContent(imageUrl: poster, fallback: fallback),
102+
child: AvatarClip(
103+
isAgent: true,
104+
child: Transform.scale(
105+
scale: animatedAvatarArtworkScale,
106+
child: isAndroid && videoUrl != null
107+
? AndroidTransparentAvatar(
108+
key: ValueKey(videoUrl),
109+
url: videoUrl,
110+
playing: playing,
111+
fallback: AvatarImageContent(
112+
imageUrl: poster,
113+
fallback: fallback,
114+
),
115+
)
116+
: controller != null && ready.value == controller
117+
? VideoPlayer(controller)
118+
: AvatarImageContent(imageUrl: poster, fallback: fallback),
119+
),
116120
),
117121
);
118122
}

‎mobile/test/features/agents/agent_avatar_picker_test.dart‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@ void main() {
6767
await tester.pumpAndSettle();
6868
expect(selection.url, isNot(agentAvatarCatalog.first.url));
6969
final character = selection.url;
70+
// Every preview uses the same squircle the agent gets once created.
71+
void expectSquirclePreview() {
72+
final previewClip = tester.widget<ClipPath>(
73+
find.descendant(
74+
of: find.bySemanticsLabel('Selected agent avatar'),
75+
matching: find.byType(ClipPath),
76+
),
77+
);
78+
expect(
79+
(previewClip.clipper! as ShapeBorderClipper).shape,
80+
avatarShape(isAgent: true),
81+
);
82+
}
83+
84+
expectSquirclePreview();
7085
await tester.runAsync(() async {
7186
rendered = Completer<void>();
7287
tester
@@ -77,17 +92,7 @@ void main() {
7792

7893
await tester.pumpAndSettle();
7994
expect(selection.bytes, isNotNull);
80-
// The preview uses the same squircle the agent gets once created.
81-
final previewClip = tester.widget<ClipPath>(
82-
find.descendant(
83-
of: find.bySemanticsLabel('Selected agent avatar'),
84-
matching: find.byType(ClipPath),
85-
),
86-
);
87-
expect(
88-
(previewClip.clipper! as ShapeBorderClipper).shape,
89-
avatarShape(isAgent: true),
90-
);
95+
expectSquirclePreview();
9196
expect(
9297
(tester
9398
.widget<GridView>(

0 commit comments

Comments
 (0)