diff --git a/mobile/lib/features/channels/emoji_picker/category_rail.dart b/mobile/lib/features/channels/emoji_picker/category_rail.dart index 92d8806f0..e654134ec 100644 --- a/mobile/lib/features/channels/emoji_picker/category_rail.dart +++ b/mobile/lib/features/channels/emoji_picker/category_rail.dart @@ -105,7 +105,10 @@ class _SkinToneSelector extends StatelessWidget { value: index, child: Row( children: [ - _SkinToneDot(color: tone.color), + _SkinToneDot( + key: ValueKey('emoji-skin-tone-dot-$index'), + color: tone.color, + ), const SizedBox(width: Grid.xs), Expanded(child: Text(tone.label)), if (index == value) @@ -139,19 +142,36 @@ class _SkinToneDot extends StatelessWidget { @override Widget build(BuildContext context) { - return DecoratedBox( - decoration: BoxDecoration( - color: color, - gradient: LinearGradient( - colors: [Colors.white.withValues(alpha: 0.2), Colors.transparent], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - backgroundBlendMode: BlendMode.overlay, - shape: BoxShape.circle, - border: Border.all(color: Colors.black.withValues(alpha: 0.8)), + return SizedBox.square( + dimension: 16, + child: Stack( + fit: StackFit.expand, + children: [ + DecoratedBox( + decoration: BoxDecoration(color: color, shape: BoxShape.circle), + ), + ClipOval( + child: DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.white.withValues(alpha: 0.2), + Colors.transparent, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + ), + ), + DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.black.withValues(alpha: 0.8)), + ), + ), + ], ), - child: const SizedBox.square(dimension: 16), ); } } diff --git a/mobile/test/features/channels/emoji_picker_test.dart b/mobile/test/features/channels/emoji_picker_test.dart index a5bbea9ec..4635f1f8b 100644 --- a/mobile/test/features/channels/emoji_picker_test.dart +++ b/mobile/test/features/channels/emoji_picker_test.dart @@ -503,6 +503,45 @@ void main() { expect(selected, ['\u{261D}\u{1F3FD}']); }); + testWidgets('skin tone choices paint their colors on a solid layer', ( + tester, + ) async { + await _pumpPicker(tester, prefs: await _prefs()); + + await tester.tap(find.byTooltip('Skin tone')); + await tester.pumpAndSettle(); + + const expectedColors = [ + Color(0xFFFFC93A), + Color(0xFFFFDAB7), + Color(0xFFE7B98F), + Color(0xFFC88C61), + Color(0xFFA46134), + Color(0xFF5D4437), + ]; + for (final (index, expectedColor) in expectedColors.indexed) { + final decorations = tester + .widgetList( + find.descendant( + of: find.byKey(ValueKey('emoji-skin-tone-dot-$index')), + matching: find.byType(DecoratedBox), + ), + ) + .map((widget) => widget.decoration) + .whereType(); + + expect( + decorations.any( + (decoration) => + decoration.color == expectedColor && + decoration.gradient == null && + decoration.backgroundBlendMode == null, + ), + isTrue, + ); + } + }); + testWidgets('a custom emoji emits :shortcode:', (tester) async { final selected = await _pumpPicker(tester, prefs: await _prefs());