diff --git a/apps/app_seeds/lib/ui/chat_screen.dart b/apps/app_seeds/lib/ui/chat_screen.dart index 1bdcac8..eb00ab9 100644 --- a/apps/app_seeds/lib/ui/chat_screen.dart +++ b/apps/app_seeds/lib/ui/chat_screen.dart @@ -302,6 +302,7 @@ class ChatMessageList extends StatelessWidget { message: message, mine: cubit.isMine(message), peerName: peerName, + selfPubkey: cubit.selfPubkey, ), }; }, @@ -408,32 +409,44 @@ class _DaySeparator extends StatelessWidget { } } -/// One message line: my messages align to the trailing edge with no avatar; -/// the peer's align to the leading edge with their avatar (1:1 convention). +/// One message line. Each sender gets their own coloured avatar on their side — +/// mine on the trailing edge, the peer's on the leading edge — so at a glance +/// the two sides are two people, not one column of look-alike bubbles. class _MessageRow extends StatelessWidget { - const _MessageRow({required this.message, required this.mine, this.peerName}); + const _MessageRow({ + required this.message, + required this.mine, + this.peerName, + this.selfPubkey, + }); final PrivateMessage message; final bool mine; final String? peerName; + /// My own pubkey, so my messages carry my (distinctly coloured) avatar. + final String? selfPubkey; + @override Widget build(BuildContext context) { - if (mine) { - return Align( - alignment: AlignmentDirectional.centerEnd, - child: _Bubble(message: message, mine: true), - ); - } + // My avatar has no name (it's me) → a glyph on my colour; the peer's shows + // their initial on theirs. Different pubkeys → different colours. + final avatar = mine + ? PeerAvatar(pubkey: selfPubkey ?? message.fromPubkey) + : PeerAvatar(pubkey: message.fromPubkey, name: peerName); + final bubble = Flexible( + child: _Bubble(message: message, mine: mine), + ); return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.end, - children: [ - PeerAvatar(pubkey: message.fromPubkey, name: peerName), - const SizedBox(width: 8), - Flexible(child: _Bubble(message: message, mine: false)), - ], + mainAxisAlignment: mine + ? MainAxisAlignment.end + : MainAxisAlignment.start, + children: mine + ? [bubble, const SizedBox(width: 8), avatar] + : [avatar, const SizedBox(width: 8), bubble], ), ); } diff --git a/apps/app_seeds/test/ui/chat_message_list_test.dart b/apps/app_seeds/test/ui/chat_message_list_test.dart index cf28685..2eea2a2 100644 --- a/apps/app_seeds/test/ui/chat_message_list_test.dart +++ b/apps/app_seeds/test/ui/chat_message_list_test.dart @@ -113,9 +113,7 @@ void main() { expect(find.byKey(const Key('chat.daySeparator')), findsNWidgets(2)); }); - testWidgets('the peer bubble carries an avatar, mine does not', ( - tester, - ) async { + testWidgets('each sender gets a distinctly coloured avatar', (tester) async { final transport = _FakeMessageTransport(); final cubit = MessagesCubit(transport, peerPubkey: peer, selfPubkey: me) ..start(); @@ -126,8 +124,14 @@ void main() { await tester.pumpWidget(host(cubit)); await tester.pump(); - // One avatar, for the single peer message; my own bubble has none. - expect(find.byType(PeerAvatar), findsOneWidget); + // Both sides carry an avatar, and the two people are different colours — + // so you can tell who said what at a glance. + expect(find.byType(PeerAvatar), findsNWidgets(2)); + final discs = tester + .widgetList(find.byType(CircleAvatar)) + .toList(); + expect(discs, hasLength(2)); + expect(discs.first.backgroundColor, isNot(discs.last.backgroundColor)); }); testWidgets('a new message lands in view at the bottom, not below the fold', (