forked from Henry-Hiles/nexus
make members controller an asyncnotifier
makes loading smoother and more responsive
This commit is contained in:
parent
95a4e03f00
commit
237886971c
4 changed files with 92 additions and 81 deletions
|
|
@ -12,8 +12,8 @@ class AuthorController extends AsyncNotifier<Membership> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Membership> build() async {
|
Future<Membership> build() async {
|
||||||
var member = ref.watch(
|
var member = await ref.watch(
|
||||||
MembersController.provider(config.room).select(
|
MembersController.provider(config.room).selectAsync(
|
||||||
(value) => value.firstWhereOrNull(
|
(value) => value.firstWhereOrNull(
|
||||||
(membership) => membership.userId == config.message.authorId,
|
(membership) => membership.userId == config.message.authorId,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -7,47 +7,35 @@ import "package:nexus/models/membership.dart";
|
||||||
import "package:nexus/models/requests/get_room_state_request.dart";
|
import "package:nexus/models/requests/get_room_state_request.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
|
|
||||||
class MembersController extends Notifier<IList<Membership>> {
|
class MembersController extends AsyncNotifier<IList<Membership>> {
|
||||||
final Room room;
|
final Room room;
|
||||||
MembersController(this.room);
|
MembersController(this.room);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
IList<Membership> build() {
|
Future<IList<Membership>> build() async {
|
||||||
IList<Membership> membersFromState(IList<Event> members) => members.nonNulls
|
if (room.metadata == null) return const IList.empty();
|
||||||
|
|
||||||
|
final state = await ref
|
||||||
|
.watch(ClientController.provider.notifier)
|
||||||
|
.getRoomState(
|
||||||
|
GetRoomStateRequest(
|
||||||
|
roomId: room.metadata!.id,
|
||||||
|
fetchMembers: room.metadata!.hasMemberList == false,
|
||||||
|
includeMembers: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return state.nonNulls
|
||||||
.where((member) => member.content["membership"] == "join")
|
.where((member) => member.content["membership"] == "join")
|
||||||
.map(
|
.map(
|
||||||
(membership) =>
|
(membership) =>
|
||||||
Membership.fromContent(membership.content, membership.stateKey!),
|
Membership.fromContent(membership.content, membership.stateKey!),
|
||||||
)
|
)
|
||||||
.toIList();
|
.toIList();
|
||||||
|
|
||||||
if (room.metadata != null) {
|
|
||||||
ref
|
|
||||||
.watch(ClientController.provider.notifier)
|
|
||||||
.getRoomState(
|
|
||||||
GetRoomStateRequest(
|
|
||||||
roomId: room.metadata!.id,
|
|
||||||
fetchMembers: room.metadata!.hasMemberList == false,
|
|
||||||
includeMembers: true,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.then((value) => state = membersFromState(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return membersFromState(
|
|
||||||
(room.state["m.room.members"]?.values ?? [])
|
|
||||||
.map(
|
|
||||||
(eventRowId) => room.events.firstWhereOrNull(
|
|
||||||
(event) => event.rowId == eventRowId,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.nonNulls
|
|
||||||
.toIList(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static final provider =
|
static final provider =
|
||||||
NotifierProvider.family<MembersController, IList<Membership>, Room>(
|
AsyncNotifierProvider.family<MembersController, IList<Membership>, Room>(
|
||||||
MembersController.new,
|
MembersController.new,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import "package:flutter/material.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
import "package:nexus/controllers/rooms_controller.dart";
|
import "package:nexus/controllers/rooms_controller.dart";
|
||||||
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
@ -31,45 +32,47 @@ class MentionOverlay extends ConsumerWidget {
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
padding: EdgeInsets.all(8),
|
padding: EdgeInsets.all(8),
|
||||||
child: switch (triggerCharacter) {
|
child: switch (triggerCharacter) {
|
||||||
"@" => Consumer(
|
"@" =>
|
||||||
builder: (_, ref, _) {
|
ref
|
||||||
final members = ref.watch(MembersController.provider(room));
|
.watch(MembersController.provider(room))
|
||||||
return ListView(
|
.betterWhen(
|
||||||
children:
|
data: (members) => ListView(
|
||||||
(query.isEmpty
|
children:
|
||||||
? members
|
(query.isEmpty
|
||||||
: members.where(
|
? members
|
||||||
(member) =>
|
: members.where(
|
||||||
member.userId.toLowerCase().contains(
|
(member) =>
|
||||||
query.toLowerCase(),
|
member.userId.toLowerCase().contains(
|
||||||
) ==
|
query.toLowerCase(),
|
||||||
true ||
|
) ==
|
||||||
member.displayName.toLowerCase().contains(
|
true ||
|
||||||
query.toLowerCase(),
|
member.displayName
|
||||||
) ==
|
.toLowerCase()
|
||||||
true,
|
.contains(
|
||||||
))
|
query.toLowerCase(),
|
||||||
.map(
|
) ==
|
||||||
(member) => ListTile(
|
true,
|
||||||
leading: AvatarOrHash(
|
))
|
||||||
member.avatarUrl,
|
.map(
|
||||||
member.displayName,
|
(member) => ListTile(
|
||||||
),
|
leading: AvatarOrHash(
|
||||||
title: Text(member.displayName),
|
member.avatarUrl,
|
||||||
subtitle: Text(member.userId),
|
member.displayName,
|
||||||
onTap: () => addTag(
|
),
|
||||||
id: "[@${member.displayName}](https://matrix.to/#/${member.userId})",
|
title: Text(member.displayName),
|
||||||
name: member.userId
|
subtitle: Text(member.userId),
|
||||||
.substring(1)
|
onTap: () => addTag(
|
||||||
.split(":")
|
id: "[@${member.displayName}](https://matrix.to/#/${member.userId})",
|
||||||
.first,
|
name: member.userId
|
||||||
),
|
.substring(1)
|
||||||
),
|
.split(":")
|
||||||
)
|
.first,
|
||||||
.toList(),
|
),
|
||||||
);
|
),
|
||||||
},
|
)
|
||||||
),
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
"#" => ListView(
|
"#" => ListView(
|
||||||
children:
|
children:
|
||||||
(query.isEmpty
|
(query.isEmpty
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
|
|
||||||
|
|
@ -10,15 +11,17 @@ class MemberList extends ConsumerWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final members = ref.watch(MembersController.provider(room));
|
final membersProvider = ref.watch(MembersController.provider(room));
|
||||||
return Drawer(
|
return Drawer(
|
||||||
shape: Border(),
|
shape: Border(),
|
||||||
child: ListView(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
AppBar(
|
AppBar(
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
leading: Icon(Icons.people),
|
leading: Icon(Icons.people),
|
||||||
title: Text("Members (${members.length})"),
|
title: Text(
|
||||||
|
"Members ${membersProvider.when(data: (members) => "${members.length}", error: (_, _) => "", loading: () => "")}",
|
||||||
|
),
|
||||||
actionsPadding: EdgeInsets.only(right: 4),
|
actionsPadding: EdgeInsets.only(right: 4),
|
||||||
actions: [
|
actions: [
|
||||||
if (Scaffold.of(context).hasEndDrawer)
|
if (Scaffold.of(context).hasEndDrawer)
|
||||||
|
|
@ -29,16 +32,33 @@ class MemberList extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
...members.map(
|
membersProvider.betterWhen(
|
||||||
(member) => ListTile(
|
data: (members) => Expanded(
|
||||||
onTap: () => showDialog(
|
child: ListView(
|
||||||
context: context,
|
children: members
|
||||||
builder: (context) =>
|
.map(
|
||||||
Dialog(child: Text("TODO: Open member popover")),
|
(member) => ListTile(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) =>
|
||||||
|
Dialog(child: Text("TODO: Open member popover")),
|
||||||
|
),
|
||||||
|
leading: AvatarOrHash(
|
||||||
|
member.avatarUrl,
|
||||||
|
member.displayName,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
member.displayName,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
member.userId,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
leading: AvatarOrHash(member.avatarUrl, member.displayName),
|
|
||||||
title: Text(member.displayName, overflow: TextOverflow.ellipsis),
|
|
||||||
subtitle: Text(member.userId, overflow: TextOverflow.ellipsis),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue