refactor: Performance boost for avatar widget

pull/1462/head
Krille 9 months ago
parent 9906668f1c
commit 58577bb9e8
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652

@ -19,7 +19,7 @@ class Avatar extends StatelessWidget {
final IconData? icon; final IconData? icon;
final BorderSide? border; final BorderSide? border;
const Avatar({ Avatar({
this.mxContent, this.mxContent,
this.name, this.name,
this.size = defaultSize, this.size = defaultSize,
@ -31,40 +31,27 @@ class Avatar extends StatelessWidget {
this.border, this.border,
this.icon, this.icon,
super.key, super.key,
}); }) : fallbackLetters = name?.firstTwoCharsOrFallback ?? '@',
textColor = name?.lightColorAvatar,
noPic = mxContent == null ||
mxContent.toString().isEmpty ||
mxContent.toString() == 'null';
final String fallbackLetters;
final Color? textColor;
final bool noPic;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(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 borderRadius = this.borderRadius ?? BorderRadius.circular(size / 2);
final presenceUserId = this.presenceUserId; final presenceUserId = this.presenceUserId;
final container = Stack(
return InkWell(
onTap: onTap,
borderRadius: borderRadius,
child: Stack(
children: [ children: [
SizedBox( SizedBox(
width: size, width: size,
@ -79,7 +66,18 @@ class Avatar extends StatelessWidget {
), ),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: noPic child: noPic
? textWidget ? Container(
color: textColor,
alignment: Alignment.center,
child: Text(
fallbackLetters,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: (size / 3).roundToDouble(),
),
),
)
: MxcImage( : MxcImage(
client: client, client: client,
key: ValueKey(mxContent.toString()), key: ValueKey(mxContent.toString()),
@ -120,7 +118,8 @@ class Avatar extends StatelessWidget {
width: 16, width: 16,
height: 16, height: 16,
decoration: BoxDecoration( decoration: BoxDecoration(
color: presenceBackgroundColor ?? theme.colorScheme.surface, color:
presenceBackgroundColor ?? theme.colorScheme.surface,
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
), ),
alignment: Alignment.center, alignment: Alignment.center,
@ -141,12 +140,20 @@ class Avatar extends StatelessWidget {
}, },
), ),
], ],
),
); );
if (onTap == null) return container; }
return InkWell( }
onTap: onTap,
borderRadius: borderRadius, extension on String {
child: container, String get firstTwoCharsOrFallback {
); var fallbackLetters = '@';
if (runes.length >= 2) {
fallbackLetters = String.fromCharCodes(runes, 0, 2);
} else if (runes.length == 1) {
fallbackLetters = this;
}
return fallbackLetters;
} }
} }

@ -1,10 +1,12 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
class PresenceBuilder extends StatelessWidget { class PresenceBuilder extends StatefulWidget {
final Widget Function(BuildContext context, CachedPresence? presence) builder; final Widget Function(BuildContext context, CachedPresence? presence) builder;
final String? userId; final String? userId;
final Client? client; final Client? client;
@ -17,21 +19,41 @@ class PresenceBuilder extends StatelessWidget {
}); });
@override @override
Widget build(BuildContext context) { State<PresenceBuilder> createState() => _PresenceBuilderState();
final userId = this.userId; }
if (userId == null) return builder(context, null);
class _PresenceBuilderState extends State<PresenceBuilder> {
final client = this.client ?? Matrix.of(context).client; CachedPresence? _presence;
return FutureBuilder<CachedPresence>( StreamSubscription<CachedPresence>? _sub;
future: client.fetchCurrentPresence(userId),
builder: (context, cachedPresenceSnapshot) => StreamBuilder( @override
stream: client.onPresenceChanged.stream void initState() {
.where((cachedPresence) => cachedPresence.userid == userId), final client = widget.client ?? Matrix.of(context).client;
builder: (context, snapshot) => builder( final userId = widget.userId;
context, if (userId != null) {
snapshot.data ?? cachedPresenceSnapshot.data, WidgetsBinding.instance.addPostFrameCallback((_) async {
), final presence = await client.fetchCurrentPresence(userId);
), setState(() {
); _presence = presence;
_sub = client.onPresenceChanged.stream.listen((presence) {
if (!mounted) return;
setState(() {
_presence = presence;
});
});
});
});
}
super.initState();
}
@override
void dispose() {
_sub?.cancel();
super.dispose();
} }
@override
Widget build(BuildContext context) => widget.builder(context, _presence);
} }

Loading…
Cancel
Save