You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Dart
		
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Dart
		
	
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;
 | 
						|
  final Color? backgroundColor;
 | 
						|
  final Color? textColor;
 | 
						|
 | 
						|
  const Avatar({
 | 
						|
    this.mxContent,
 | 
						|
    this.name,
 | 
						|
    this.size = defaultSize,
 | 
						|
    this.onTap,
 | 
						|
    this.client,
 | 
						|
    this.presenceUserId,
 | 
						|
    this.presenceBackgroundColor,
 | 
						|
    this.borderRadius,
 | 
						|
    this.border,
 | 
						|
    this.icon,
 | 
						|
    this.backgroundColor,
 | 
						|
    this.textColor,
 | 
						|
    super.key,
 | 
						|
  });
 | 
						|
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    final theme = Theme.of(context);
 | 
						|
 | 
						|
    final name = this.name;
 | 
						|
    final fallbackLetters =
 | 
						|
        name == null || name.isEmpty ? '@' : name.substring(0, 1);
 | 
						|
 | 
						|
    final noPic = mxContent == null ||
 | 
						|
        mxContent.toString().isEmpty ||
 | 
						|
        mxContent.toString() == 'null';
 | 
						|
    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.antiAlias,
 | 
						|
            child: MxcImage(
 | 
						|
              client: client,
 | 
						|
              borderRadius: borderRadius,
 | 
						|
              key: ValueKey(mxContent.toString()),
 | 
						|
              cacheKey: '${mxContent}_$size',
 | 
						|
              uri: mxContent,
 | 
						|
              fit: BoxFit.cover,
 | 
						|
              width: size,
 | 
						|
              height: size,
 | 
						|
              placeholder: (_) => noPic
 | 
						|
                  ? Container(
 | 
						|
                      decoration: BoxDecoration(
 | 
						|
                        color: backgroundColor ?? name?.lightColorAvatar,
 | 
						|
                      ),
 | 
						|
                      alignment: Alignment.center,
 | 
						|
                      child: Text(
 | 
						|
                        fallbackLetters,
 | 
						|
                        textAlign: TextAlign.center,
 | 
						|
                        style: TextStyle(
 | 
						|
                          fontFamily: 'RobotoMono',
 | 
						|
                          color: textColor ?? Colors.white,
 | 
						|
                          fontWeight: FontWeight.bold,
 | 
						|
                          fontSize: (size / 2.5).roundToDouble(),
 | 
						|
                        ),
 | 
						|
                      ),
 | 
						|
                    )
 | 
						|
                  : 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 MouseRegion(
 | 
						|
      cursor: SystemMouseCursors.click,
 | 
						|
      child: GestureDetector(
 | 
						|
        onTap: onTap,
 | 
						|
        child: container,
 | 
						|
      ),
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 |