From 1939cc1bc8ef1f225e68cb69879f23b605452782 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Jul 2021 13:46:53 +0530 Subject: [PATCH 01/30] feat: Added gradient avatar --- .../lib/src/gradient_avatar.dart | 199 ++++++++++++++++++ .../lib/src/stream_chat_theme.dart | 8 +- 2 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 packages/stream_chat_flutter/lib/src/gradient_avatar.dart diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart new file mode 100644 index 00000000..afc02fb6 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -0,0 +1,199 @@ +import 'dart:math'; +import 'dart:ui'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +class GradientAvatar extends StatefulWidget { + final String name; + final String userId; + + const GradientAvatar({ + Key? key, + required this.name, + required this.userId, + }) : super(key: key); + + @override + _GradientAvatarState createState() => _GradientAvatarState(); +} + +class _GradientAvatarState extends State { + @override + Widget build(BuildContext context) { + return Center( + child: RepaintBoundary( + child: Container( + width: 100.0, + height: 100.0, + child: Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + painter: DemoPainter(widget.userId), + child: SizedBox.expand(), + ), + FittedBox( + child: Padding( + padding: const EdgeInsets.all(32.0), + child: Opacity( + opacity: 0.8, + child: Text( + getShortenedName(widget.name), + style: TextStyle( + color: Colors.white, + fontSize: 112.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + String getShortenedName(String name) { + List parts = name.split(' ')..removeWhere((e) => e == ''); + + if (parts.length > 2) { + parts = parts.take(2).toList(); + } + + String result = ''; + + for (int i = 0; i < parts.length; i++) { + result = result + parts[i][0]; + } + + return result; + } +} + +class DemoPainter extends CustomPainter { + static const int rowCount = 5; + static const int columnCount = 5; + + String userId; + + DemoPainter(this.userId); + + @override + void paint(Canvas canvas, Size size) { + var rowUnit = size.width / columnCount; + var columnUnit = size.height / rowCount; + var rand = Random(userId.length); + + List squares = []; + Set points = {}; + List gradient = colorGradients[rand.nextInt(colorGradients.length)]; + + for (int i = 0; i < rowCount; i++) { + for (int j = 0; j < columnCount; j++) { + var off1 = Offset(rowUnit * j, columnUnit * i); + var off2 = Offset(rowUnit * (j + 1), columnUnit * i); + var off3 = Offset(rowUnit * (j + 1), columnUnit * (i + 1)); + var off4 = Offset(rowUnit * j, columnUnit * (i + 1)); + + points.addAll([off1, off2, off3, off4]); + + var p1 = points.toList().indexOf(off1); + var p2 = points.toList().indexOf(off2); + var p3 = points.toList().indexOf(off3); + var p4 = points.toList().indexOf(off4); + + squares.add( + Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient)); + } + } + + var list = transformPoints(points, size); + squares.forEach((e) => e.draw(canvas, list)); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } + + List transformPoints(Set points, Size size) { + List transformedList = []; + var orgList = points.toList(); + var rand = Random(userId.length); + + for (int i = 0; i < points.length; i++) { + var orgDx = orgList[i].dx; + var orgDy = orgList[i].dy; + + if (orgDx == 0 || + orgDy == 0 || + orgDx == size.width || + orgDy == size.height) { + transformedList.add(Offset(orgDx, orgDy)); + continue; + } + + int sign1 = rand.nextInt(2) == 1 ? 1 : -1; + int sign2 = rand.nextInt(2) == 1 ? 1 : -1; + + double dx = 0.6 * sign1 * rand.nextInt(size.width ~/ columnCount); + double dy = 0.6 * sign2 * rand.nextInt(size.height ~/ rowCount); + + transformedList.add(Offset(orgDx + dx, orgDy + dy)); + } + + return transformedList; + } +} + +class Offset4 { + int p1; + int p2; + int p3; + int p4; + int row; + int column; + int rowSize; + int colSize; + List gradient; + + Offset4(this.p1, this.p2, this.p3, this.p4, this.row, this.column, + this.rowSize, this.colSize, this.gradient); + + void draw(Canvas canvas, List points) { + Paint paint = Paint() + ..color = Color.fromARGB(255, Random().nextInt(255), + Random().nextInt(255), Random().nextInt(255)) + ..shader = ui.Gradient.linear( + points[p1], + points[p3], + gradient, + ); + + final backgroundPath = Path() + ..moveTo(points[p1].dx, points[p1].dy) + ..lineTo(points[p2].dx, points[p2].dy) + ..lineTo(points[p3].dx, points[p3].dy) + ..lineTo(points[p4].dx, points[p4].dy) + ..lineTo(points[p1].dx, points[p1].dy) + ..close(); + + canvas.drawPath(backgroundPath, paint); + } +} + +const colorGradients = [ + [Color(0xffffafbd), Color(0xffffc3a0)], + [Color(0xff2193b0), Color(0xff6dd5ed)], + [Color(0xffcc2b5e), Color(0xff753a88)], + [Color(0xffee9ca7), Color(0xffffdde1)], + [Color(0xff42275a), Color(0xff734b6d)], + [Color(0xffde6262), Color(0xffffb88c)], + [Color(0xff56ab2f), Color(0xffa8e063)], + [Color(0xff614385), Color(0xff516395)], + [Color(0xffeacda3), Color(0xffd6ae7b)], + [Color(0xff02aab0), Color(0xff00cdac)], +]; diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index c62e92ec..74976e07 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/extension.dart'; +import 'package:stream_chat_flutter/src/gradient_avatar.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; @@ -270,10 +271,9 @@ class StreamChatThemeData { colorTheme: colorTheme, primaryIconTheme: iconTheme, defaultUserImage: (context, user) => Center( - child: CachedNetworkImage( - filterQuality: FilterQuality.high, - imageUrl: getRandomPicUrl(user), - fit: BoxFit.cover, + child: GradientAvatar( + name: user.name, + userId: user.id, ), ), channelPreviewTheme: channelPreviewTheme, From ec1c2fce8cefae5a7336b69edc00c021c2b34b72 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Jul 2021 13:53:33 +0530 Subject: [PATCH 02/30] feat: Added docs and cleanup --- .../lib/src/gradient_avatar.dart | 180 +++++++++++------- 1 file changed, 109 insertions(+), 71 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart index afc02fb6..aef80712 100644 --- a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -4,68 +4,71 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; +/// Fallback user avatar with a polygon gradient overlayed with text class GradientAvatar extends StatefulWidget { - final String name; - final String userId; - + /// Constructor for [GradientAvatar] const GradientAvatar({ Key? key, required this.name, required this.userId, }) : super(key: key); + /// Name of user to shorten and display + final String name; + + /// ID of user to be used for key + final String userId; + @override _GradientAvatarState createState() => _GradientAvatarState(); } class _GradientAvatarState extends State { @override - Widget build(BuildContext context) { - return Center( - child: RepaintBoundary( - child: Container( - width: 100.0, - height: 100.0, - child: Stack( - alignment: Alignment.center, - children: [ - CustomPaint( - painter: DemoPainter(widget.userId), - child: SizedBox.expand(), - ), - FittedBox( - child: Padding( - padding: const EdgeInsets.all(32.0), - child: Opacity( - opacity: 0.8, - child: Text( - getShortenedName(widget.name), - style: TextStyle( - color: Colors.white, - fontSize: 112.0, - fontWeight: FontWeight.bold, + Widget build(BuildContext context) => Center( + child: RepaintBoundary( + child: SizedBox( + width: 100, + height: 100, + child: Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + painter: DemoPainter(widget.userId), + child: const SizedBox.expand(), + ), + FittedBox( + child: Padding( + padding: const EdgeInsets.all(32), + child: Opacity( + opacity: 0.8, + child: Text( + getShortenedName(widget.name), + style: const TextStyle( + color: Colors.white, + fontSize: 112, + fontWeight: FontWeight.bold, + ), ), ), ), ), - ), - ], + ], + ), ), ), - ), - ); - } + ); String getShortenedName(String name) { - List parts = name.split(' ')..removeWhere((e) => e == ''); + var parts = name.split(' ')..removeWhere((e) => e == ''); if (parts.length > 2) { parts = parts.take(2).toList(); } - String result = ''; + var result = ''; - for (int i = 0; i < parts.length; i++) { + for (var i = 0; i < parts.length; i++) { result = result + parts[i][0]; } @@ -73,60 +76,65 @@ class _GradientAvatarState extends State { } } +/// Painter for bg polygon gradient class DemoPainter extends CustomPainter { + /// Constructor for [DemoPainter] + DemoPainter(this.userId); + + /// Init grid row count static const int rowCount = 5; + + /// Init grid column count static const int columnCount = 5; + /// User ID used for key String userId; - DemoPainter(this.userId); - @override void paint(Canvas canvas, Size size) { - var rowUnit = size.width / columnCount; - var columnUnit = size.height / rowCount; - var rand = Random(userId.length); + final rowUnit = size.width / columnCount; + final columnUnit = size.height / rowCount; + final rand = Random(userId.length); - List squares = []; - Set points = {}; - List gradient = colorGradients[rand.nextInt(colorGradients.length)]; + final squares = []; + final points = {}; + final gradient = colorGradients[rand.nextInt(colorGradients.length)]; - for (int i = 0; i < rowCount; i++) { - for (int j = 0; j < columnCount; j++) { - var off1 = Offset(rowUnit * j, columnUnit * i); - var off2 = Offset(rowUnit * (j + 1), columnUnit * i); - var off3 = Offset(rowUnit * (j + 1), columnUnit * (i + 1)); - var off4 = Offset(rowUnit * j, columnUnit * (i + 1)); + for (var i = 0; i < rowCount; i++) { + for (var j = 0; j < columnCount; j++) { + final off1 = Offset(rowUnit * j, columnUnit * i); + final off2 = Offset(rowUnit * (j + 1), columnUnit * i); + final off3 = Offset(rowUnit * (j + 1), columnUnit * (i + 1)); + final off4 = Offset(rowUnit * j, columnUnit * (i + 1)); points.addAll([off1, off2, off3, off4]); - var p1 = points.toList().indexOf(off1); - var p2 = points.toList().indexOf(off2); - var p3 = points.toList().indexOf(off3); - var p4 = points.toList().indexOf(off4); + final p1 = points.toList().indexOf(off1); + final p2 = points.toList().indexOf(off2); + final p3 = points.toList().indexOf(off3); + final p4 = points.toList().indexOf(off4); squares.add( Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient)); } } - var list = transformPoints(points, size); + final list = transformPoints(points, size); squares.forEach((e) => e.draw(canvas, list)); } @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return false; - } + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; + /// Transforms initial grid into a polygon grid List transformPoints(Set points, Size size) { - List transformedList = []; - var orgList = points.toList(); - var rand = Random(userId.length); + final transformedList = []; + final orgList = points.toList(); + final rand = Random(userId.length); - for (int i = 0; i < points.length; i++) { - var orgDx = orgList[i].dx; - var orgDy = orgList[i].dy; + for (var i = 0; i < points.length; i++) { + final orgDx = orgList[i].dx; + final orgDy = orgList[i].dy; if (orgDx == 0 || orgDy == 0 || @@ -136,11 +144,11 @@ class DemoPainter extends CustomPainter { continue; } - int sign1 = rand.nextInt(2) == 1 ? 1 : -1; - int sign2 = rand.nextInt(2) == 1 ? 1 : -1; + final sign1 = rand.nextInt(2) == 1 ? 1 : -1; + final sign2 = rand.nextInt(2) == 1 ? 1 : -1; - double dx = 0.6 * sign1 * rand.nextInt(size.width ~/ columnCount); - double dy = 0.6 * sign2 * rand.nextInt(size.height ~/ rowCount); + final dx = 0.6 * sign1 * rand.nextInt(size.width ~/ columnCount); + final dy = 0.6 * sign2 * rand.nextInt(size.height ~/ rowCount); transformedList.add(Offset(orgDx + dx, orgDy + dy)); } @@ -149,22 +157,51 @@ class DemoPainter extends CustomPainter { } } +/// Class for storing and drawing four points of a polygon class Offset4 { + /// Constructor for [Offset4] + Offset4( + this.p1, + this.p2, + this.p3, + this.p4, + this.row, + this.column, + this.rowSize, + this.colSize, + this.gradient, + ); + + /// Point 1 int p1; + + /// Point 2 int p2; + + /// Point 3 int p3; + + /// Point 4 int p4; + + /// Position of polygon on grid int row; + + /// Position of polygon on grid int column; + + /// Max row size int rowSize; + + /// Max col size int colSize; + + /// Gradient to be applied to polygon List gradient; - Offset4(this.p1, this.p2, this.p3, this.p4, this.row, this.column, - this.rowSize, this.colSize, this.gradient); - + /// Draw the polygon on canvas void draw(Canvas canvas, List points) { - Paint paint = Paint() + final paint = Paint() ..color = Color.fromARGB(255, Random().nextInt(255), Random().nextInt(255), Random().nextInt(255)) ..shader = ui.Gradient.linear( @@ -185,6 +222,7 @@ class Offset4 { } } +/// Gradient list for polygons const colorGradients = [ [Color(0xffffafbd), Color(0xffffc3a0)], [Color(0xff2193b0), Color(0xff6dd5ed)], From 5670e18c0f938156df4aea9c2d4540553d830518 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Jul 2021 13:54:19 +0530 Subject: [PATCH 03/30] fix: remove deps --- packages/stream_chat_flutter/lib/src/stream_chat_theme.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 74976e07..d8d50077 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; @@ -7,7 +6,6 @@ import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/gradient_avatar.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; -import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; From 7df908f9c21d894e31a0d85a5e8e56033279c184 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Jul 2021 14:14:06 +0530 Subject: [PATCH 04/30] fix: text style correction --- .../lib/src/gradient_avatar.dart | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart index aef80712..45cc1e96 100644 --- a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -27,34 +27,30 @@ class _GradientAvatarState extends State { @override Widget build(BuildContext context) => Center( child: RepaintBoundary( - child: SizedBox( - width: 100, - height: 100, - child: Stack( - alignment: Alignment.center, - children: [ - CustomPaint( - painter: DemoPainter(widget.userId), - child: const SizedBox.expand(), - ), - FittedBox( - child: Padding( - padding: const EdgeInsets.all(32), - child: Opacity( - opacity: 0.8, - child: Text( - getShortenedName(widget.name), - style: const TextStyle( - color: Colors.white, - fontSize: 112, - fontWeight: FontWeight.bold, - ), + child: Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + painter: DemoPainter(widget.userId), + child: const SizedBox.expand(), + ), + Padding( + padding: const EdgeInsets.all(8), + child: Opacity( + opacity: 0.7, + child: FittedBox( + child: Text( + getShortenedName(widget.name), + style: const TextStyle( + color: Colors.white, + fontSize: 120, + fontWeight: FontWeight.w500, ), ), ), ), - ], - ), + ), + ], ), ), ); From cfa9d2539911d49ff0314a4e8150fd777b044a8c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Jul 2021 15:39:45 +0530 Subject: [PATCH 05/30] fix: Replaced stack text with canvas text --- .../lib/src/gradient_avatar.dart | 67 ++++++++++++------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart index 45cc1e96..a7e18983 100644 --- a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -27,30 +27,12 @@ class _GradientAvatarState extends State { @override Widget build(BuildContext context) => Center( child: RepaintBoundary( - child: Stack( - alignment: Alignment.center, - children: [ - CustomPaint( - painter: DemoPainter(widget.userId), - child: const SizedBox.expand(), - ), - Padding( - padding: const EdgeInsets.all(8), - child: Opacity( - opacity: 0.7, - child: FittedBox( - child: Text( - getShortenedName(widget.name), - style: const TextStyle( - color: Colors.white, - fontSize: 120, - fontWeight: FontWeight.w500, - ), - ), - ), - ), - ), - ], + child: CustomPaint( + painter: DemoPainter( + widget.userId, + getShortenedName(widget.name), + ), + child: const SizedBox.expand(), ), ), ); @@ -75,7 +57,10 @@ class _GradientAvatarState extends State { /// Painter for bg polygon gradient class DemoPainter extends CustomPainter { /// Constructor for [DemoPainter] - DemoPainter(this.userId); + DemoPainter( + this.userId, + this.username, + ); /// Init grid row count static const int rowCount = 5; @@ -86,6 +71,9 @@ class DemoPainter extends CustomPainter { /// User ID used for key String userId; + /// User name to display + String username; + @override void paint(Canvas canvas, Size size) { final rowUnit = size.width / columnCount; @@ -117,6 +105,35 @@ class DemoPainter extends CustomPainter { final list = transformPoints(points, size); squares.forEach((e) => e.draw(canvas, list)); + + final smallerSide = size.width > size.height ? size.width : size.height; + + final textSize = smallerSide / 3; + + final dxShift = (username.length == 2 ? 1.45 : 0.75) * textSize / 2; + final dyShift = (username.length == 2 ? 1.0 : 1.8) * textSize / 2; + + final fontSize = username.length == 2 ? textSize : textSize * 1.5; + + TextPainter( + text: TextSpan( + text: username, + style: TextStyle( + fontSize: fontSize, + fontWeight: FontWeight.w500, + color: Colors.white.withOpacity(0.7), + ), + ), + textAlign: TextAlign.center, + textDirection: TextDirection.ltr) + ..layout(maxWidth: size.width) + ..paint( + canvas, + Offset( + (size.width / 2) - dxShift, + (size.height / 2) - dyShift, + ), + ); } @override From 88ece480a27dd8a0bb633ddf8bee7c04a1fd4e92 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Jul 2021 15:44:47 +0530 Subject: [PATCH 06/30] fix: cleanup --- .../stream_chat_flutter/lib/src/gradient_avatar.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart index a7e18983..0cb8c41c 100644 --- a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -93,10 +93,12 @@ class DemoPainter extends CustomPainter { points.addAll([off1, off2, off3, off4]); - final p1 = points.toList().indexOf(off1); - final p2 = points.toList().indexOf(off2); - final p3 = points.toList().indexOf(off3); - final p4 = points.toList().indexOf(off4); + final pointsList = points.toList(); + + final p1 = pointsList.indexOf(off1); + final p2 = pointsList.indexOf(off2); + final p3 = pointsList.indexOf(off3); + final p4 = pointsList.indexOf(off4); squares.add( Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient)); From f8911bb6e3087898e91f686ded96a3db874d3eee Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 21 Jul 2021 15:02:57 +0530 Subject: [PATCH 07/30] feat: Added tests and minor fixes --- .../lib/src/gradient_avatar.dart | 6 +- .../test/src/goldens/gradient_avatar_0.png | Bin 0 -> 35488 bytes .../test/src/goldens/gradient_avatar_1.png | Bin 0 -> 38197 bytes .../test/src/gradient_avatar_test.dart | 82 ++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 packages/stream_chat_flutter/test/src/goldens/gradient_avatar_0.png create mode 100644 packages/stream_chat_flutter/test/src/goldens/gradient_avatar_1.png create mode 100644 packages/stream_chat_flutter/test/src/gradient_avatar_test.dart diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart index 0cb8c41c..dc97fb98 100644 --- a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -47,7 +47,7 @@ class _GradientAvatarState extends State { var result = ''; for (var i = 0; i < parts.length; i++) { - result = result + parts[i][0]; + result = result + parts[i][0].toUpperCase(); } return result; @@ -112,8 +112,8 @@ class DemoPainter extends CustomPainter { final textSize = smallerSide / 3; - final dxShift = (username.length == 2 ? 1.45 : 0.75) * textSize / 2; - final dyShift = (username.length == 2 ? 1.0 : 1.8) * textSize / 2; + final dxShift = (username.length == 2 ? 1.45 : 0.9) * textSize / 2; + final dyShift = (username.length == 2 ? 1.0 : 1.65) * textSize / 2; final fontSize = username.length == 2 ? textSize : textSize * 1.5; diff --git a/packages/stream_chat_flutter/test/src/goldens/gradient_avatar_0.png b/packages/stream_chat_flutter/test/src/goldens/gradient_avatar_0.png new file mode 100644 index 0000000000000000000000000000000000000000..0906f11aca5a82f0fd4a2f6d9fd4cc712b5696cc GIT binary patch literal 35488 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≫B3&Iwv02P3D1z%;8>US?8W2DYwXeQ_HO8|V9D+*iH2-55n{y>uHEPx>TC zhl1pm;mwiku|uV-JvT9X485#IQ9kC7+XV}VaX>eZgN}w7Aa%`MaaLrKg?^kBspoXL zEuN7!69{H}VHF35c4P_7rz-K^j_y$hNr>F)i)oWn2w;{BsX`JA`{6BX+Ahm_6s5^@ z&Mx`Zu8q&DA{Vx+(WHzpf@YVP1v$P}W5rV-^tvm1u9fwr884i3GJYK$M(7d{1*3Be z&8HxMGYX9CYfI*QqFnPy@vzNw#%3+ke=X!+vAZxt(Nx0d6etI-W=ibrWp<$!DOTY? zIkGUVd|$i1z4@CcXohTD&GPN?27Fmb1(4h{J7?9Ywr^;EZ1e&+bsX_&XXMIIn`gAL z%bDOlGUSq5NXlZpk;Tu2%NcUC%BOCjZgjYXkV&UM){{#FegJ*UGOWD0quz!G%#)$y zy5gzTvP?UAJkHJBCyJD%ll~Mq&ch1|YnF!!BjJQOd)>x7rakXy=r`|T|Ic>t3>Tl~ zNNVe-17R!%?aQlJwtmRi*#3^vB<$iyVyuqrQ(&B*J!dg&l|R`bc!+@CK`ob^v6&s~ zsv<$T=sufRA$L`$*MViBp$;U8*$Job!!C3Qj;v)r8XMZawNpT$7p)qXusYS_3%YY% zgyFli6$Rx%qtv%Rt{tF2ndp!PcQ zg)eB;fs~CV!ps#DW}o8%b~(ThxJI7AdoDq2(c)^xpTWLr^&t>?|)Wmlr z48y>1FYvO5S&@eqSH$9@m6Mhf@( z5o$QnBoEM}eQSXaeKemGs@3B+9M;BmnD|fgVuX(ZLKBfWy@EYdYMfkeMV?%K_%UeS zby(1>t51-zaeIkARYtIAshtZx?AP3e6hJhrRHk*>*5^tgGdNkrk^8JpcTV(R&PH?F z-vfdqE|VyqfprJWcXA}Z$sdgM0Ady-IS<-00u)e~I>&Ji;A+8HK?5n_JfiR^MKjQ> z2*qAB)~hA)i47$ugwt)P?z)aJ&shQto8)l&{g%f(!9lC7F&A>V{Bucy{`bN?e#7U* zsfd+azs_ME{<=9I@r+T<%?hy^t%z|Pt-sN?ON0YfU6a!cUWNgA7RHxS^B7 z<*vRHbfz0vlF3wt-veA0JClN=j&;FB&x~v|SBGmm3gi}c14h~0^{6Memp;{7GM#~c zmN+g8aB`st${*3eYiNXT<*RJlApykp)F3R1&LDOTWfqq zK6=|Ms0k+WntZRIxYcMve<`JSkrbyC6Uh-jz_qFHFz85oMXm4Y?#97tLhbjJGI_1a z#F{sP2cNzW)qWN<#9~XIj`K?VG51BGZR5;k|4wm8Qkwm0vT1|eE_Hz07t|oUyu9n| zl_adrsJN`xZa*(^8$$Rax^;s`HV(iXs(>+K@z^CyH|-JtN_)9q)D3nbv9eNc^?@*h z7QOCDu06UWx)@tKs95{LVoe^=1$-^n7QO$n*3ck&|2}ICUPTvkYfq7g-WMr}KtuHY z31F>MF1pwzAttu1C^4~ZixT_4$uE|V1&oWH8oT?VhI=$X%24Eo!v7LPhqm8y>geaRU{$y|EM{{b$%c_07) literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter/test/src/goldens/gradient_avatar_1.png b/packages/stream_chat_flutter/test/src/goldens/gradient_avatar_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d288abf084fc623592103f82517695b17398972d GIT binary patch literal 38197 zcmeFaXIPWx8#hc_tF+b;1yK;t&>~9^l_9e#0kr}JOacl-KtP!yhLwcaN(I6ye?Tl# zK~xeT4A~}e0I7_ig)j|a2+=@5hzXF82uoqPQ55dW*4 z&9?6qzn77b*>?7fm7|Qzcb8>kw#dqE27XdU7i+>Cdd1S9lqV|`FY=<@_>JCQy5K;iNRW^jLqLc ziN3PO45jr4ggFD0m%rZVr-X&E#XT_Psp%T?@prm`0o@%OPK|H**IhMR)}DGEQdUOn zy%av({du&x=5fxT-VT*+R&8*t`EB`~m%m!u%LS~{V0Y`=)o*`(9AEz7=vRBzHpxBo zvVgGZU&^0(+xq3KJ^lj0(w2{wy?(UBmZRVj!{wvRZ#Y^8*UCAt zMS8R#(7&=dVsbWy{>SpZ${Y6mr~`s!F7IHpVTV!(xI}k(2fnRORlmoe+8XEX+pg=H z1)tP5OLq{WP&^T%k=L7IS@w&P5;7Fk$T?eh@Zam-iZXf0{soQfwwz`VDCp0rvV@a% zJJ*>0vpFXD6KjS{5RpiC;kg}j%cU15UfwCiER4ir15i?1TmHKFBG^5$$Q>=>Mctfn z7k#F~k#!V=9<$D&tGc@8@!=~CH8AOSu|gs5RVJcm2NUho8^y=Lnd|o&mIdwc-Ego& zaplhGGF#V3Bp-a~30mik@o%yTzUvHpu4(0*WBsrAWI7ML9Q|?qY3EzA31jP|E}sPJ zo@)}6aOHXJf^r$i%Z2-EPUR3XS>azRxD3fde>eF@TjpeufA2tEb@}U?7dsL4j$2SD z_m?KWtrLcQxEjOjM9s6Cd))~NWv(APPP}}5Wpw|D=K8hEJ#ExVC`{5NsR-wilt}UA zkNo|?CA-(TdjBi?JT*CwZMWBVRs_FPR9QEl<7Z+Fbk^B(^`5N1@j8h&0Jn~8*zPC5 zdUyY8B0nbp?m&H=d3WQ>1;4BdT=~FD_Mvr3H)CW88{EX3gW!_rb#3{X8dokjy zFWFl*EKZjt2sfO|1F+Q%2cZIdW&jzQBqPvJ&D0D=zGdpbNMpQ`(51-#MdqzA`hCH&)v*(n8yLlZQg7Fu(1xtKRjY4zIfi@a&FtWc$Y`+#>MAjkQN&j*FUgw z)^jDhVue#x)@nNIQobG#gIr89!mFpPc{jI47~pG@$T2_t%U~Hi`=jh+Es^5hNtrum z`=|?ew&Y`I%sPQ#Y_hd8GkO-Hyd?0~>jW9fd#p3<7IlAk@~<&Svvsnc