parent
ee36a9b1c8
commit
c0f4c053b0
4 changed files with 94 additions and 74 deletions
13
lib/helpers/extensions/displayname_color.dart
Normal file
13
lib/helpers/extensions/displayname_color.dart
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:material_ui/material_ui.dart";
|
||||||
|
import "package:nexus/controllers/room_power_levels.dart";
|
||||||
|
import "package:nexus/helpers/extensions/string_to_color.dart";
|
||||||
|
|
||||||
|
extension DisplaynameColor on WidgetRef {
|
||||||
|
/// The color of [userId]'s name in [roomId], hashed from their power level,
|
||||||
|
/// so everyone with the same level shares one.
|
||||||
|
Color displaynameColor(String roomId, String userId) => watch(
|
||||||
|
RoomPowerLevelsController.provider(roomId)
|
||||||
|
.select((levels) => levels.levelOf(userId)),
|
||||||
|
).toString().colorHash;
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/author.dart";
|
import "package:nexus/controllers/author.dart";
|
||||||
import "package:nexus/helpers/extensions/get_localpart.dart";
|
import "package:nexus/helpers/extensions/get_localpart.dart";
|
||||||
import "package:nexus/helpers/extensions/show_user_popover.dart";
|
import "package:nexus/helpers/extensions/show_user_popover.dart";
|
||||||
import "package:nexus/helpers/extensions/string_to_color.dart";
|
import "package:nexus/helpers/extensions/displayname_color.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/content/membership.dart";
|
import "package:nexus/models/content/membership.dart";
|
||||||
|
|
||||||
|
|
@ -15,43 +15,44 @@ class const MessageDisplayname(
|
||||||
super.key,
|
super.key,
|
||||||
}) extends ConsumerWidget {
|
}) extends ConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => switch (ref.watch(
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
AuthorController.provider(event),
|
final color = ref.displaynameColor(event.roomId, event.sender);
|
||||||
)) {
|
|
||||||
AsyncData(:final MembershipContent? value) ||
|
return switch (ref.watch(AuthorController.provider(event))) {
|
||||||
AsyncLoading(:final value) ||
|
AsyncData(:final MembershipContent? value) ||
|
||||||
AsyncError(:final value) => InkWell(
|
AsyncLoading(:final value) ||
|
||||||
onTap: clickable
|
AsyncError(:final value) => InkWell(
|
||||||
? () => context.showUserPopover(event.sender, roomId: event.roomId)
|
onTap: clickable
|
||||||
: null,
|
? () => context.showUserPopover(event.sender, roomId: event.roomId)
|
||||||
child: switch ([
|
: null,
|
||||||
Text(
|
child: switch ([
|
||||||
value?.displayName ?? event.sender.localpart,
|
|
||||||
style:
|
|
||||||
style ?? .new(color: event.sender.colorHash, fontWeight: .bold),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: .ellipsis,
|
|
||||||
),
|
|
||||||
if (event.pmp != null)
|
|
||||||
Text(
|
Text(
|
||||||
"(via ${event.sender})",
|
value?.displayName ?? event.sender.localpart,
|
||||||
style: Theme.of(context).textTheme.labelSmall
|
style: style ?? .new(color: color, fontWeight: .bold),
|
||||||
?.copyWith(color: event.sender.colorHash, fontWeight: .bold),
|
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: .ellipsis,
|
overflow: .ellipsis,
|
||||||
),
|
),
|
||||||
]) {
|
if (event.pmp != null)
|
||||||
final children when shouldWrap => Wrap(
|
Text(
|
||||||
spacing: 4,
|
"(via ${event.sender})",
|
||||||
crossAxisAlignment: .center,
|
style: Theme.of(context).textTheme.labelSmall
|
||||||
children: children,
|
?.copyWith(color: color, fontWeight: .bold),
|
||||||
),
|
maxLines: 1,
|
||||||
final children => Row(
|
overflow: .ellipsis,
|
||||||
spacing: 4,
|
),
|
||||||
mainAxisSize: .min,
|
]) {
|
||||||
children: [for (final child in children) Flexible(child: child)],
|
final children when shouldWrap => Wrap(
|
||||||
),
|
spacing: 4,
|
||||||
},
|
crossAxisAlignment: .center,
|
||||||
),
|
children: children,
|
||||||
};
|
),
|
||||||
|
final children => Row(
|
||||||
|
spacing: 4,
|
||||||
|
mainAxisSize: .min,
|
||||||
|
children: [for (final child in children) Flexible(child: child)],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import "package:nexus/controllers/members_by_status.dart";
|
||||||
import "package:nexus/controllers/members_grouped.dart";
|
import "package:nexus/controllers/members_grouped.dart";
|
||||||
import "package:nexus/helpers/extensions/get_localpart.dart";
|
import "package:nexus/helpers/extensions/get_localpart.dart";
|
||||||
import "package:nexus/helpers/extensions/show_user_popover.dart";
|
import "package:nexus/helpers/extensions/show_user_popover.dart";
|
||||||
import "package:nexus/helpers/extensions/string_to_color.dart";
|
import "package:nexus/helpers/extensions/displayname_color.dart";
|
||||||
import "package:nexus/models/content/membership.dart";
|
import "package:nexus/models/content/membership.dart";
|
||||||
import "package:nexus/models/membership_status.dart";
|
import "package:nexus/models/membership_status.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
|
|
@ -108,42 +108,44 @@ class const MemberList(final String roomId, {super.key})
|
||||||
:final avatarUrl,
|
:final avatarUrl,
|
||||||
:final displayName,
|
:final displayName,
|
||||||
) =>
|
) =>
|
||||||
Builder(
|
Consumer(
|
||||||
builder: (context) => ListTile(
|
builder: (context, ref, _) =>
|
||||||
onTap: () =>
|
ListTile(
|
||||||
context.showUserPopover(
|
onTap: () =>
|
||||||
|
context.showUserPopover(
|
||||||
|
members[index].stateKey!,
|
||||||
|
roomId: roomId,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
displayName ??
|
||||||
|
members[index]
|
||||||
|
.stateKey!
|
||||||
|
.localpart,
|
||||||
|
overflow: .ellipsis,
|
||||||
|
style: .new(
|
||||||
|
color: ref.displaynameColor(
|
||||||
|
roomId,
|
||||||
|
members[index].stateKey!,
|
||||||
|
),
|
||||||
|
fontWeight: .bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
members[index].stateKey!,
|
members[index].stateKey!,
|
||||||
roomId: roomId,
|
overflow: .ellipsis,
|
||||||
|
),
|
||||||
|
leading: Transform.translate(
|
||||||
|
offset: .new(0, 2),
|
||||||
|
child: AvatarOrHash(
|
||||||
|
avatarUrl,
|
||||||
|
dimension: 40,
|
||||||
|
displayName ??
|
||||||
|
members[index]
|
||||||
|
.stateKey!
|
||||||
|
.localpart,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
|
||||||
displayName ??
|
|
||||||
members[index]
|
|
||||||
.stateKey!
|
|
||||||
.localpart,
|
|
||||||
overflow: .ellipsis,
|
|
||||||
style: .new(
|
|
||||||
color: members[index]
|
|
||||||
.stateKey!
|
|
||||||
.colorHash,
|
|
||||||
fontWeight: .bold,
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
members[index].stateKey!,
|
|
||||||
overflow: .ellipsis,
|
|
||||||
),
|
|
||||||
leading: Transform.translate(
|
|
||||||
offset: .new(0, 2),
|
|
||||||
child: AvatarOrHash(
|
|
||||||
avatarUrl,
|
|
||||||
dimension: 40,
|
|
||||||
displayName ??
|
|
||||||
members[index]
|
|
||||||
.stateKey!
|
|
||||||
.localpart,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
_ => throw Exception(
|
_ => throw Exception(
|
||||||
"Member content was not MembershipContent",
|
"Member content was not MembershipContent",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:nexus/helpers/extensions/get_localpart.dart";
|
import "package:nexus/helpers/extensions/get_localpart.dart";
|
||||||
import "package:nexus/helpers/extensions/show_user_popover.dart";
|
import "package:nexus/helpers/extensions/show_user_popover.dart";
|
||||||
import "package:nexus/helpers/extensions/string_to_color.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:nexus/helpers/extensions/displayname_color.dart";
|
||||||
import "package:nexus/models/content/membership.dart";
|
import "package:nexus/models/content/membership.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
|
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
|
||||||
|
|
@ -11,9 +12,9 @@ class const MembershipRenderer(
|
||||||
final Event event, {
|
final Event event, {
|
||||||
final int? maxLines,
|
final int? maxLines,
|
||||||
super.key,
|
super.key,
|
||||||
}) extends StatelessWidget {
|
}) extends ConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
assert(
|
assert(
|
||||||
event.content is MembershipContent,
|
event.content is MembershipContent,
|
||||||
"Make sure to only pass membership events to MembershipRenderer",
|
"Make sure to only pass membership events to MembershipRenderer",
|
||||||
|
|
@ -40,7 +41,10 @@ class const MembershipRenderer(
|
||||||
overflow: .ellipsis,
|
overflow: .ellipsis,
|
||||||
content.displayName ?? event.stateKey!.localpart,
|
content.displayName ?? event.stateKey!.localpart,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: .new(color: event.sender.colorHash, fontWeight: .bold),
|
style: .new(
|
||||||
|
color: ref.displaynameColor(event.roomId, event.stateKey!),
|
||||||
|
fontWeight: .bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue