Revert "refactor: Performance boost for avatar widget"

This reverts commit 58577bb9e8.
This commit is contained in:
krille-chan 2024-11-06 17:25:37 +01:00
commit d2c2284182
No known key found for this signature in database
2 changed files with 119 additions and 148 deletions

View file

@ -19,7 +19,7 @@ class Avatar extends StatelessWidget {
final IconData? icon; final IconData? icon;
final BorderSide? border; final BorderSide? border;
Avatar({ const Avatar({
this.mxContent, this.mxContent,
this.name, this.name,
this.size = defaultSize, this.size = defaultSize,
@ -31,129 +31,122 @@ 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( children: [
onTap: onTap, SizedBox(
borderRadius: borderRadius, width: size,
child: Stack( height: size,
children: [ child: Material(
SizedBox( color: theme.brightness == Brightness.light
width: size, ? Colors.white
height: size, : Colors.black,
child: Material( shape: RoundedRectangleBorder(
color: theme.brightness == Brightness.light borderRadius: borderRadius,
? Colors.white side: border ?? BorderSide.none,
: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: borderRadius,
side: border ?? BorderSide.none,
),
clipBehavior: Clip.hardEdge,
child: noPic
? Container(
color: textColor,
alignment: Alignment.center,
child: Text(
fallbackLetters,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: (size / 3).roundToDouble(),
),
),
)
: 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,
),
),
),
), ),
), clipBehavior: Clip.hardEdge,
if (presenceUserId != null) child: noPic
PresenceBuilder( ? textWidget
client: client, : MxcImage(
userId: presenceUserId, client: client,
builder: (context, presence) { key: ValueKey(mxContent.toString()),
if (presence == null || cacheKey: '${mxContent}_$size',
(presence.presence == PresenceType.offline && uri: mxContent,
presence.lastActiveTimestamp == null)) { fit: BoxFit.cover,
return const SizedBox.shrink(); width: size,
} height: size,
final dotColor = presence.presence.isOnline placeholder: (_) => Center(
? Colors.green child: Icon(
: presence.presence.isUnavailable Icons.person_2,
? Colors.orange color: theme.colorScheme.tertiary,
: Colors.grey; size: size / 1.5,
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 (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,
); );
} }
} }
extension on String {
String get firstTwoCharsOrFallback {
var fallbackLetters = '@';
if (runes.length >= 2) {
fallbackLetters = String.fromCharCodes(runes, 0, 2);
} else if (runes.length == 1) {
fallbackLetters = this;
}
return fallbackLetters;
}
}

View file

@ -1,12 +1,10 @@
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 StatefulWidget { class PresenceBuilder extends StatelessWidget {
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;
@ -19,41 +17,21 @@ class PresenceBuilder extends StatefulWidget {
}); });
@override @override
State<PresenceBuilder> createState() => _PresenceBuilderState(); Widget build(BuildContext context) {
} 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);
} }