import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/mxc_image.dart'; import 'package:fluffychat/widgets/presence_builder.dart'; class Avatar extends StatelessWidget { final Uri? mxContent; final String? name; final double size; final void Function()? onTap; static const double defaultSize = 44; final Client? client; final String? presenceUserId; final Color? presenceBackgroundColor; final BorderRadius? borderRadius; final IconData? icon; final BorderSide? border; const Avatar({ this.mxContent, this.name, this.size = defaultSize, this.onTap, this.client, this.presenceUserId, this.presenceBackgroundColor, this.borderRadius, this.border, this.icon, super.key, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); var fallbackLetters = '@'; final name = this.name; if (name != null) { if (name.runes.length >= 2) { fallbackLetters = String.fromCharCodes(name.runes, 0, 2); } else if (name.runes.length == 1) { fallbackLetters = name; } } final noPic = mxContent == null || mxContent.toString().isEmpty || mxContent.toString() == 'null'; final textColor = name?.lightColorAvatar; final textWidget = Container( color: textColor, alignment: Alignment.center, child: Text( fallbackLetters, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: (size / 3).roundToDouble(), ), ), ); final borderRadius = this.borderRadius ?? BorderRadius.circular(size / 2); final presenceUserId = this.presenceUserId; final container = Stack( children: [ SizedBox( width: size, height: size, child: Material( color: theme.brightness == Brightness.light ? Colors.white : Colors.black, shape: RoundedRectangleBorder( borderRadius: borderRadius, side: border ?? BorderSide.none, ), clipBehavior: Clip.hardEdge, child: noPic ? textWidget : MxcImage( client: client, key: ValueKey(mxContent.toString()), cacheKey: '${mxContent}_$size', uri: mxContent, fit: BoxFit.cover, width: size, height: size, placeholder: (_) => Center( child: Icon( Icons.person_2, color: theme.colorScheme.tertiary, size: size / 1.5, ), ), ), ), ), if (presenceUserId != null) PresenceBuilder( client: client, userId: presenceUserId, builder: (context, presence) { if (presence == null || (presence.presence == PresenceType.offline && presence.lastActiveTimestamp == null)) { return const SizedBox.shrink(); } final dotColor = presence.presence.isOnline ? Colors.green : presence.presence.isUnavailable ? Colors.orange : Colors.grey; return Positioned( bottom: -3, right: -3, child: Container( width: 16, height: 16, decoration: BoxDecoration( color: presenceBackgroundColor ?? theme.colorScheme.surface, borderRadius: BorderRadius.circular(32), ), alignment: Alignment.center, child: Container( width: 10, height: 10, decoration: BoxDecoration( color: dotColor, borderRadius: BorderRadius.circular(16), border: Border.all( width: 1, color: theme.colorScheme.surface, ), ), ), ), ); }, ), ], ); if (onTap == null) return container; return InkWell( onTap: onTap, borderRadius: borderRadius, child: container, ); } }