diff --git a/lib/view/common/avatar_icon.dart b/lib/view/common/avatar_icon.dart index 63258a520..3bb153513 100644 --- a/lib/view/common/avatar_icon.dart +++ b/lib/view/common/avatar_icon.dart @@ -25,6 +25,7 @@ class AvatarIcon extends StatelessWidget { id: response.id, username: response.username, avatarUrl: response.avatarUrl, + avatarBlurhash: response.avatarBlurhash, isCat: response.isCat, isBot: response.isBot, ), @@ -32,13 +33,16 @@ class AvatarIcon extends StatelessWidget { ); } - factory AvatarIcon.fromUserResponse(UsersShowResponse response, - {double height = 48}) { + factory AvatarIcon.fromUserResponse( + UsersShowResponse response, { + double height = 48, + }) { return AvatarIcon( user: User( id: response.id, username: response.username, avatarUrl: response.avatarUrl, + avatarBlurhash: response.avatarBlurhash, isCat: response.isCat, isBot: response.isBot, ), @@ -46,75 +50,98 @@ class AvatarIcon extends StatelessWidget { ); } + Color? averageColor() { + // https://github.com/woltapp/blurhash/blob/master/Algorithm.md + final blurhash = user.avatarBlurhash; + if (blurhash == null) { + return null; + } + final value = blurhash + .substring(2, 6) + .split("") + .map( + r'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~' + .indexOf, + ) + .fold(0, (acc, i) => acc * 83 + i); + return Color(0xFF000000 | value); + } + @override Widget build(BuildContext context) { + final catEarColor = + (user.isCat ? averageColor() : null) ?? Theme.of(context).primaryColor; + return GestureDetector( - onTap: onTap ?? - () { - context.pushRoute(UserRoute( - userId: user.id, account: AccountScope.of(context))); - }, - child: Padding( - padding: const EdgeInsets.only(top: 3), - child: Stack(children: [ - if (user.isCat) - Positioned( - left: 0, - top: 0, - width: height * MediaQuery.of(context).textScaleFactor, - height: height * MediaQuery.of(context).textScaleFactor, - child: Transform.rotate( - angle: -0 * pi / 180, - child: Transform.translate( - offset: Offset( - -height * - 0.3 * - MediaQuery.of(context).textScaleFactor, - -height * - 0.3 * - MediaQuery.of(context).textScaleFactor), - child: Icon(Icons.play_arrow_rounded, - color: Theme.of(context).primaryColor, - size: height * - 1 * - MediaQuery.of(context).textScaleFactor), - ), - )), - if (user.isCat) - Positioned( - left: 0, - top: 0, - width: height * MediaQuery.of(context).textScaleFactor, - height: height * MediaQuery.of(context).textScaleFactor, - child: Transform.translate( - offset: Offset( - height * - 1.333 * - MediaQuery.of(context).textScaleFactor, - -height * - 0.3 * - MediaQuery.of(context).textScaleFactor), - child: Transform( - transform: Matrix4.rotationY(pi), - child: Icon(Icons.play_arrow_rounded, - color: Theme.of(context).primaryColor, - size: height * - 1 * - MediaQuery.of(context).textScaleFactor), - ), - )), - ClipRRect( - borderRadius: BorderRadius.circular( - height * MediaQuery.of(context).textScaleFactor), - child: SizedBox( - width: height * MediaQuery.of(context).textScaleFactor, - height: height * MediaQuery.of(context).textScaleFactor, - child: NetworkImageView( - fit: BoxFit.cover, - url: user.avatarUrl.toString(), - type: ImageType.avatarIcon, - )), + onTap: onTap ?? + () { + context.pushRoute( + UserRoute(userId: user.id, account: AccountScope.of(context)), + ); + }, + child: Padding( + padding: const EdgeInsets.only(top: 3), + child: Stack( + children: [ + if (user.isCat) + Positioned( + left: 0, + top: 0, + width: height * MediaQuery.of(context).textScaleFactor, + height: height * MediaQuery.of(context).textScaleFactor, + child: Transform.rotate( + angle: -0 * pi / 180, + child: Transform.translate( + offset: Offset( + -height * 0.3 * MediaQuery.of(context).textScaleFactor, + -height * 0.3 * MediaQuery.of(context).textScaleFactor, + ), + child: Icon( + Icons.play_arrow_rounded, + color: catEarColor, + size: height * 1 * MediaQuery.of(context).textScaleFactor, + ), + ), + ), + ), + if (user.isCat) + Positioned( + left: 0, + top: 0, + width: height * MediaQuery.of(context).textScaleFactor, + height: height * MediaQuery.of(context).textScaleFactor, + child: Transform.translate( + offset: Offset( + height * 1.333 * MediaQuery.of(context).textScaleFactor, + -height * 0.3 * MediaQuery.of(context).textScaleFactor, + ), + child: Transform( + transform: Matrix4.rotationY(pi), + child: Icon( + Icons.play_arrow_rounded, + color: catEarColor, + size: height * 1 * MediaQuery.of(context).textScaleFactor, + ), + ), + ), ), - ]))); + ClipRRect( + borderRadius: BorderRadius.circular( + height * MediaQuery.of(context).textScaleFactor, + ), + child: SizedBox( + width: height * MediaQuery.of(context).textScaleFactor, + height: height * MediaQuery.of(context).textScaleFactor, + child: NetworkImageView( + fit: BoxFit.cover, + url: user.avatarUrl.toString(), + type: ImageType.avatarIcon, + ), + ), + ), + ], + ), + ), + ); } }