Compare commits
6 changed files with 54 additions and 71 deletions
|
|
@ -17,13 +17,13 @@ import "package:nexus/models/requests/send_message.dart";
|
|||
import "package:nexus/models/room.dart";
|
||||
import "package:nexus/models/room_chat.dart";
|
||||
|
||||
class RoomChatController(final (String roomId, String? contextualEvent) info)
|
||||
class RoomChatController(final (String roomId, String? withEventId) info)
|
||||
extends AsyncNotifier<RoomChat?> {
|
||||
@override
|
||||
Future<RoomChat?> build() async {
|
||||
final (roomId, eventId) = info;
|
||||
final client = ref.read(ClientController.provider.notifier);
|
||||
final room = ref.read(
|
||||
final room = ref.watch(
|
||||
RoomsController.provider.select((rooms) => rooms[roomId]),
|
||||
);
|
||||
|
||||
|
|
@ -34,7 +34,8 @@ class RoomChatController(final (String roomId, String? contextualEvent) info)
|
|||
await ref.read(RoomsController.provider.notifier).addState(roomId, state);
|
||||
}
|
||||
|
||||
final timeline = room.timeline
|
||||
return .new(
|
||||
events: room.timeline
|
||||
.toEntryIList(compare: (a, b) => (a?.key ?? 0).compareTo(b?.key ?? 0))
|
||||
.map((element) => element.value)
|
||||
.toIList()
|
||||
|
|
@ -55,22 +56,9 @@ class RoomChatController(final (String roomId, String? contextualEvent) info)
|
|||
);
|
||||
})
|
||||
.nonNulls
|
||||
.toIList();
|
||||
|
||||
if (info.$2 == null || timeline.map((e) => e.eventId).contains(info.$2)) {
|
||||
ref.watch(RoomsController.provider.select((rooms) => rooms[roomId]));
|
||||
|
||||
return .new(timeline: timeline, hasMore: room.hasMore);
|
||||
} else {
|
||||
final context = await client.getEventContext(
|
||||
.new(roomId: roomId, eventId: info.$2!, limit: 20),
|
||||
.toIList(),
|
||||
hasMore: room.hasMore,
|
||||
);
|
||||
return .new(
|
||||
timeline: context.before.add(context.event).addAll(context.after),
|
||||
hasMore: true,
|
||||
historicalData: .new(start: context.start, end: context.end),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteMessage(Event event, {String? reason}) => ref
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ final class ChatScroll({
|
|||
useEffect(() {
|
||||
if (anchorId.value == null) {
|
||||
if (controllerData case AsyncData(:final value?)
|
||||
when value.timeline.isNotEmpty) {
|
||||
anchorId.value = value.timeline.last.eventId;
|
||||
when value.events.isNotEmpty) {
|
||||
anchorId.value = value.events.last.eventId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ final class ChatScroll({
|
|||
}, [controllerData]);
|
||||
|
||||
final ({IList<Event> history, IList<Event> live}) split = useMemoized(() {
|
||||
final items = controllerData.value?.timeline;
|
||||
final items = controllerData.value?.events;
|
||||
final anchor = anchorIdValue;
|
||||
|
||||
if (items == null || anchor == null) {
|
||||
|
|
@ -92,14 +92,19 @@ final class ChatScroll({
|
|||
(item) => item.eventId == itemId,
|
||||
);
|
||||
|
||||
double? offset;
|
||||
if (historyIndex != -1) {
|
||||
// TODO: Replace SuperSliverView because of the bug that requires this: #94
|
||||
// ignore: invalid_use_of_visible_for_testing_member
|
||||
offset = historyListController.value.getOffsetToReveal(
|
||||
final offset = historyListController.value.getOffsetToReveal(
|
||||
historyIndex,
|
||||
0.5,
|
||||
);
|
||||
|
||||
await scrollController.animateTo(
|
||||
offset,
|
||||
duration: const Duration(milliseconds: 700),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
} else {
|
||||
final liveIndex = split.live.indexWhere(
|
||||
(item) => item.eventId == itemId,
|
||||
|
|
@ -107,15 +112,11 @@ final class ChatScroll({
|
|||
|
||||
if (liveIndex != -1) {
|
||||
// ignore: invalid_use_of_visible_for_testing_member
|
||||
offset = liveListController.value.getOffsetToReveal(liveIndex, 0.5);
|
||||
}
|
||||
}
|
||||
final offset = liveListController.value.getOffsetToReveal(
|
||||
liveIndex,
|
||||
0.5,
|
||||
);
|
||||
|
||||
if (offset == null) {
|
||||
// not in current timeline
|
||||
}
|
||||
|
||||
if (offset != null) {
|
||||
await scrollController.animateTo(
|
||||
offset,
|
||||
duration: const Duration(milliseconds: 700),
|
||||
|
|
@ -123,6 +124,7 @@ final class ChatScroll({
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .new(
|
||||
historyItems: split.history,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ part "event_context.g.dart";
|
|||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
class const EventContext({
|
||||
required final Event event,
|
||||
required final IList<Event> events,
|
||||
required final IList<Event> before,
|
||||
required final IList<Event> after,
|
||||
required final String start,
|
||||
|
|
|
|||
|
|
@ -12,26 +12,17 @@ part "room.g.dart";
|
|||
class const Room({
|
||||
@JsonKey(name: "meta") final RoomMetadata? metadata,
|
||||
|
||||
/// [timeline] is an IMap of timelineRowId to eventRowId
|
||||
@JsonKey(fromJson: Room.timelineTupleJsonToIMap)
|
||||
final IMap<int, int?> timeline = const IMap.empty(),
|
||||
|
||||
/// [clientSticky] is an ISet of eventRowId
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final ISet<int> clientSticky = const ISet.empty(),
|
||||
|
||||
/// [events] is an IMap of eventRowId to event
|
||||
@JsonKey(fromJson: Room.eventsJsonToIMap)
|
||||
final IMap<int, Event> events = const IMap.empty(),
|
||||
|
||||
final bool reset = false,
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final bool hasFetchedState = false,
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final bool hasFetchedMembers = false,
|
||||
|
||||
final IMap<String, IMap<String, int>> state = const IMap.empty(),
|
||||
|
||||
final IMap<String, IList<ReadReceipt>> receipts = const IMap.empty(),
|
||||
|
|
@ -41,6 +32,9 @@ class const Room({
|
|||
// IMap<String, AccountData> accountData,
|
||||
// IList<Notification> notifications,
|
||||
}) with _$Room {
|
||||
/// [timeline] is an IMap of timelineRowId to eventRowId
|
||||
/// [events] is an IMap of eventRowId to event
|
||||
/// [clientSticky] is an ISet of eventRowId
|
||||
static IMap<int, int?> timelineTupleJsonToIMap(List<dynamic> json) =>
|
||||
IMap.fromEntries(
|
||||
json.map(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ part "room_chat.g.dart";
|
|||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
class const RoomChat({
|
||||
required final IList<Event> timeline,
|
||||
required final IList<Event> events,
|
||||
required final bool hasMore,
|
||||
final HistoricalData? historicalData,
|
||||
}) with _$RoomChat {
|
||||
|
|
@ -21,8 +21,8 @@ class const RoomChat({
|
|||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
class const HistoricalData({
|
||||
required final String start,
|
||||
required final String end,
|
||||
required final String start,
|
||||
}) with _$HistoricalData {
|
||||
Map<String, Object?> toJson() => _$HistoricalDataToJson(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ final class const RoomChat({
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final relatedEvent = useState<Event?>(null);
|
||||
final relationType = useState(RelationType.reply);
|
||||
final contextualEvent = useState<String?>(initialHighlightedEvent);
|
||||
final highlightedEvent = useState<String?>(initialHighlightedEvent);
|
||||
|
||||
final composerSize = useState<double>(64);
|
||||
|
|
@ -63,7 +62,7 @@ final class const RoomChat({
|
|||
|
||||
final controllerProvider = RoomChatController.provider((
|
||||
roomId,
|
||||
contextualEvent.value,
|
||||
initialHighlightedEvent,
|
||||
));
|
||||
final notifier = ref.watch(controllerProvider.notifier);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue