parent
e59505bd6e
commit
0653961f9c
6 changed files with 82 additions and 45 deletions
|
|
@ -11,7 +11,9 @@ class EventController extends AsyncNotifier<Event?> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Event?> build() async {
|
Future<Event?> build() async {
|
||||||
final room = ref.watch(RoomsController.provider)[request.roomId];
|
final room = ref.watch(
|
||||||
|
RoomsController.provider.select((value) => value[request.roomId]),
|
||||||
|
);
|
||||||
final event = room?.events.firstWhereOrNull(
|
final event = room?.events.firstWhereOrNull(
|
||||||
(event) => event.eventId == request.eventId,
|
(event) => event.eventId == request.eventId,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
import "package:collection/collection.dart";
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
|
import "package:nexus/controllers/rooms_controller.dart";
|
||||||
import "package:nexus/controllers/selected_room_controller.dart";
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
import "package:nexus/models/content/content.dart";
|
import "package:nexus/models/content/content.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
|
|
@ -13,12 +15,17 @@ class MembersController extends AsyncNotifier<IList<Event>> {
|
||||||
SelectedRoomController.provider.select(
|
SelectedRoomController.provider.select(
|
||||||
(value) => value?.metadata == null
|
(value) => value?.metadata == null
|
||||||
? null
|
? null
|
||||||
: (value!.metadata!.id, value.metadata!.hasMemberList),
|
: (
|
||||||
|
value!.metadata!.id,
|
||||||
|
value.metadata!.hasMemberList,
|
||||||
|
value.hasFetchedMembers,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (data == null) return const IList.empty();
|
if (data == null) return const IList.empty();
|
||||||
|
|
||||||
final state = await ref
|
if (!data.$3) {
|
||||||
|
final fetchedState = await ref
|
||||||
.watch(ClientController.provider.notifier)
|
.watch(ClientController.provider.notifier)
|
||||||
.getRoomState(
|
.getRoomState(
|
||||||
GetRoomStateRequest(
|
GetRoomStateRequest(
|
||||||
|
|
@ -28,13 +35,27 @@ class MembersController extends AsyncNotifier<IList<Event>> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return state
|
ref
|
||||||
.where((state) => state.type == EventType.membership.type)
|
.read(RoomsController.provider.notifier)
|
||||||
.toIList();
|
.addState(data.$1, fetchedState, isMembers: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final room = ref.watch(
|
||||||
|
RoomsController.provider.select((value) => value[data.$1]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return room?.state[EventType.membership.type]?.values
|
||||||
|
.map(
|
||||||
|
(rowId) =>
|
||||||
|
room.events.firstWhereOrNull((event) => event.rowId == rowId),
|
||||||
|
)
|
||||||
|
.nonNulls
|
||||||
|
.toIList() ??
|
||||||
|
const IList.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static final provider =
|
static final provider =
|
||||||
AsyncNotifierProvider<MembersController, IList<Event>>(
|
AsyncNotifierProvider.autoDispose<MembersController, IList<Event>>(
|
||||||
MembersController.new,
|
MembersController.new,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,39 +23,19 @@ class RoomChatController extends AsyncNotifier<IList<Event>> {
|
||||||
@override
|
@override
|
||||||
Future<IList<Event>> build() async {
|
Future<IList<Event>> build() async {
|
||||||
final client = ref.watch(ClientController.provider.notifier);
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
|
|
||||||
final state = await client.getRoomState(
|
|
||||||
GetRoomStateRequest(roomId: roomId),
|
|
||||||
);
|
|
||||||
|
|
||||||
ref
|
|
||||||
.read(RoomsController.provider.notifier)
|
|
||||||
.update(
|
|
||||||
{
|
|
||||||
roomId: Room(
|
|
||||||
events: state,
|
|
||||||
state: state.fold(
|
|
||||||
const IMap.empty(),
|
|
||||||
(previousValue, stateEvent) => previousValue.add(
|
|
||||||
stateEvent.type,
|
|
||||||
(previousValue[stateEvent.type] ?? const IMap.empty()).addAll(
|
|
||||||
IMap({
|
|
||||||
if (stateEvent.stateKey != null)
|
|
||||||
stateEvent.stateKey!: stateEvent.rowId,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}.toIMap(),
|
|
||||||
const ISet.empty(),
|
|
||||||
);
|
|
||||||
|
|
||||||
final room = ref.watch(
|
final room = ref.watch(
|
||||||
RoomsController.provider.select((rooms) => rooms[roomId]),
|
RoomsController.provider.select((rooms) => rooms[roomId]),
|
||||||
);
|
);
|
||||||
if (room == null) return const IList.empty();
|
if (room == null) return const IList.empty();
|
||||||
|
|
||||||
|
if (!room.hasFetchedState) {
|
||||||
|
final state = await client.getRoomState(
|
||||||
|
GetRoomStateRequest(roomId: roomId),
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(RoomsController.provider.notifier).addState(roomId, state);
|
||||||
|
}
|
||||||
|
|
||||||
// While there are under 30 messages, try up to load more messages until there's no more or we have 20 messages.
|
// While there are under 30 messages, try up to load more messages until there's no more or we have 20 messages.
|
||||||
if (room.hasMore && room.timeline.length < 30) {
|
if (room.hasMore && room.timeline.length < 30) {
|
||||||
loadOlder();
|
loadOlder();
|
||||||
|
|
@ -98,7 +78,7 @@ class RoomChatController extends AsyncNotifier<IList<Event>> {
|
||||||
PaginateRequest(
|
PaginateRequest(
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
maxTimelineId: ref
|
maxTimelineId: ref
|
||||||
.read(RoomsController.provider)[roomId]
|
.read(RoomsController.provider.select((value) => value[roomId]))
|
||||||
?.timeline
|
?.timeline
|
||||||
.firstOrNull
|
.firstOrNull
|
||||||
?.timelineRowId,
|
?.timelineRowId,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import "package:collection/collection.dart";
|
import "package:collection/collection.dart";
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/read_receipt.dart";
|
import "package:nexus/models/read_receipt.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
|
|
||||||
|
|
@ -8,6 +9,30 @@ class RoomsController extends Notifier<IMap<String, Room>> {
|
||||||
@override
|
@override
|
||||||
IMap<String, Room> build() => const IMap.empty();
|
IMap<String, Room> build() => const IMap.empty();
|
||||||
|
|
||||||
|
void addState(String roomId, IList<Event> state, {bool isMembers = false}) =>
|
||||||
|
update(
|
||||||
|
{
|
||||||
|
roomId: Room(
|
||||||
|
events: state,
|
||||||
|
hasFetchedState: true,
|
||||||
|
hasFetchedMembers: isMembers,
|
||||||
|
state: state.fold(
|
||||||
|
const IMap.empty(),
|
||||||
|
(previousValue, stateEvent) => previousValue.add(
|
||||||
|
stateEvent.type,
|
||||||
|
(previousValue[stateEvent.type] ?? const IMap.empty()).addAll(
|
||||||
|
IMap({
|
||||||
|
if (stateEvent.stateKey != null)
|
||||||
|
stateEvent.stateKey!: stateEvent.rowId,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}.toIMap(),
|
||||||
|
const ISet.empty(),
|
||||||
|
);
|
||||||
|
|
||||||
void update(IMap<String, Room> rooms, ISet<String> leftRooms) {
|
void update(IMap<String, Room> rooms, ISet<String> leftRooms) {
|
||||||
final merged = rooms.entries.fold(state, (acc, entry) {
|
final merged = rooms.entries.fold(state, (acc, entry) {
|
||||||
final roomId = entry.key;
|
final roomId = entry.key;
|
||||||
|
|
@ -34,6 +59,11 @@ class RoomsController extends Notifier<IMap<String, Room>> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
reset: false,
|
||||||
|
hasFetchedMembers:
|
||||||
|
incoming.hasFetchedMembers || existing.hasFetchedMembers,
|
||||||
|
hasFetchedState:
|
||||||
|
incoming.hasFetchedState || existing.hasFetchedState,
|
||||||
timeline:
|
timeline:
|
||||||
(incoming.reset
|
(incoming.reset
|
||||||
? incoming.timeline
|
? incoming.timeline
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ abstract class Room with _$Room {
|
||||||
@JsonKey(name: "meta") RoomMetadata? metadata,
|
@JsonKey(name: "meta") RoomMetadata? metadata,
|
||||||
@Default(IList.empty()) IList<TimelineRowTuple> timeline,
|
@Default(IList.empty()) IList<TimelineRowTuple> timeline,
|
||||||
@Default(false) bool reset,
|
@Default(false) bool reset,
|
||||||
|
@Default(false) bool hasFetchedState,
|
||||||
|
@Default(false) bool hasFetchedMembers,
|
||||||
@Default(IMap.empty()) IMap<String, IMap<String, int>> state,
|
@Default(IMap.empty()) IMap<String, IMap<String, int>> state,
|
||||||
// required IMap<String, AccountData> accountData,
|
// required IMap<String, AccountData> accountData,
|
||||||
@Default(IList.empty()) IList<Event> events,
|
@Default(IList.empty()) IList<Event> events,
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,9 @@ class RoomChat extends HookConsumerWidget {
|
||||||
if (!scrollController.position.atEdge) return;
|
if (!scrollController.position.atEdge) return;
|
||||||
|
|
||||||
if (scrollController.position.pixels == 0) {
|
if (scrollController.position.pixels == 0) {
|
||||||
final room = ref.watch(RoomsController.provider)[roomId];
|
final room = ref.watch(
|
||||||
|
RoomsController.provider.select((value) => value[roomId]),
|
||||||
|
);
|
||||||
if (room != null) client.markRead(room);
|
if (room != null) client.markRead(room);
|
||||||
} else {
|
} else {
|
||||||
await notifier.loadOlder();
|
await notifier.loadOlder();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue