diff --git a/lib/controllers/client_controller.dart b/lib/controllers/client_controller.dart index 5ccdc27..fd84f5d 100644 --- a/lib/controllers/client_controller.dart +++ b/lib/controllers/client_controller.dart @@ -15,7 +15,6 @@ import "package:nexus/controllers/top_level_spaces_controller.dart"; import "package:nexus/helpers/extensions/gomuks_buffer.dart"; import "package:nexus/main.dart"; import "package:nexus/models/client_state.dart"; -import "package:nexus/models/content/content.dart"; import "package:nexus/models/event.dart"; import "package:nexus/models/paginate.dart"; import "package:nexus/models/requests/get_event_request.dart"; @@ -79,10 +78,17 @@ class ClientController extends AsyncNotifier { break; case "send_complete": final event = Event.fromJson(decodedMuksEvent["event"]); + ref + .watch(RoomsController.provider.notifier) + .update( + { + event.roomId: Room( + events: {event.rowId: event}.toIMap(), + ), + }.toIMap(), + const ISet.empty(), + ); - if (event.type == EventType.message.type) { - // ref.watch(provider.notifier).addEvent(event); TODO - } break; case "sync_complete": final syncData = SyncData.fromJson(decodedMuksEvent); diff --git a/lib/controllers/room_chat_controller.dart b/lib/controllers/room_chat_controller.dart index 028f2a1..d8fea0c 100644 --- a/lib/controllers/room_chat_controller.dart +++ b/lib/controllers/room_chat_controller.dart @@ -44,12 +44,16 @@ class RoomChatController extends AsyncNotifier> { loadOlder(); } - return room.timeline + return IMap.fromValues( + keyMapper: (id) => 9999999 + (id ?? 0), + values: room.sticky, + ) + .addAll(room.timeline) .toEntryIList(compare: (a, b) => (b?.key ?? 0).compareTo(a?.key ?? 0)) .map((entry) { - if (entry.value == null) return null; - - final foundEvent = room.events[entry.value!]; + final foundEvent = entry.value == null + ? null + : room.events[entry.value!]; final editedEvent = foundEvent == null || foundEvent.lastEditRowId == 0 @@ -153,23 +157,17 @@ class RoomChatController extends AsyncNotifier> { ), ); - // TODO: Add new event to timeline whilst its sending - // ref - // .watch(RoomsController.provider.notifier) - // .update( - // { - // roomId: Room( - // events: [event].toIList(), - // timeline: [ - // TimelineRowTuple( - // timelineRowId: event.timelineRowId, - // eventRowId: event.rowId, - // ), - // ].toIList(), - // ), - // }.toIMap(), - // const ISet.empty(), - // ); + ref + .watch(RoomsController.provider.notifier) + .update( + { + roomId: Room( + events: {event.rowId: event}.toIMap(), + sticky: {event.rowId}.toISet(), + ), + }.toIMap(), + const ISet.empty(), + ); } Future removeReaction( diff --git a/lib/controllers/rooms_controller.dart b/lib/controllers/rooms_controller.dart index 382fac4..c4b36c1 100644 --- a/lib/controllers/rooms_controller.dart +++ b/lib/controllers/rooms_controller.dart @@ -50,6 +50,13 @@ class RoomsController extends Notifier> { roomId, existing?.copyWith( hasMore: incoming.hasMore, + sticky: + (incoming.sticky.isEmpty == true + ? existing.sticky + : existing.sticky.addAll(incoming.sticky)) + .removeWhere( + (rowId) => incoming.timeline.values.contains(rowId), + ), metadata: incoming.metadata ?? existing.metadata, events: incoming.events.isEmpty ? existing.events diff --git a/lib/models/room.dart b/lib/models/room.dart index 8aaadbe..fb21a55 100644 --- a/lib/models/room.dart +++ b/lib/models/room.dart @@ -28,11 +28,13 @@ abstract class Room with _$Room { /// [timeline] is an IMap of timelineRowId to eventRowId /// [events] is an IMap of eventRowId to event + /// [sticky] is an ISet of eventRowId const factory Room({ @JsonKey(name: "meta") RoomMetadata? metadata, @Default(IMap.empty()) @JsonKey(fromJson: Room.timelineTupleJsonToIMap) IMap timeline, + @Default(ISet.empty()) ISet sticky, @Default(IMap.empty()) @JsonKey(fromJson: Room.eventsJsonToIMap) diff --git a/lib/widgets/composer/composer.dart b/lib/widgets/composer/composer.dart index 4faa5c1..401f269 100644 --- a/lib/widgets/composer/composer.dart +++ b/lib/widgets/composer/composer.dart @@ -165,10 +165,12 @@ class Composer extends HookConsumerWidget { ), ] : [ - Padding( - padding: EdgeInsetsGeometry.all(8), - child: Text( - "You don't have permission to send messages in this room...", + Expanded( + child: Padding( + padding: EdgeInsetsGeometry.all(8), + child: Text( + "You don't have permission to send messages in this room...", + ), ), ), ], diff --git a/lib/widgets/lazy_loading/message_avatar.dart b/lib/widgets/lazy_loading/message_avatar.dart index 215bb35..11c4704 100644 --- a/lib/widgets/lazy_loading/message_avatar.dart +++ b/lib/widgets/lazy_loading/message_avatar.dart @@ -1,7 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/author_controller.dart"; -import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/get_localpart.dart"; import "package:nexus/helpers/extensions/show_user_popover.dart"; import "package:nexus/models/event.dart"; @@ -13,24 +12,22 @@ class MessageAvatar extends ConsumerWidget { const MessageAvatar(this.event, {this.height = 24, super.key}); @override - Widget build(BuildContext context, WidgetRef ref) => ref - .watch(AuthorController.provider(event)) - .betterWhen( - data: (membership) => InkWell( + Widget build(BuildContext context, WidgetRef ref) => + switch (ref.watch(AuthorController.provider(event))) { + AsyncData(:final value) || AsyncLoading(:final value?) => InkWell( onTapUp: (details) { context.showUserPopover( - membership, + value, event.sender, globalPosition: details.globalPosition, ); }, child: AvatarOrHash( - membership.avatarUrl, - membership.displayName ?? event.sender.localpart, + value.avatarUrl, + value.displayName ?? event.sender.localpart, height: height, ), ), - loading: () => - AvatarOrHash(null, event.sender.localpart, height: height), - ); + _ => AvatarOrHash(null, event.sender.localpart, height: height), + }; } diff --git a/lib/widgets/renderers/event.dart b/lib/widgets/renderers/event.dart index 217c4d3..2302156 100644 --- a/lib/widgets/renderers/event.dart +++ b/lib/widgets/renderers/event.dart @@ -446,19 +446,22 @@ class EventRenderer extends ConsumerWidget { ), ), - if (event.content is! MessageContent) - Padding( - padding: EdgeInsetsGeometry.only(left: 12), - child: ReactionRow(event), - ), + ...[ + if (event.content is! MessageContent) ReactionRow(event), - if (event.sendError != null && event.sendError != "not sent") - Text( - event.sendError!, - style: theme.textTheme.labelSmall?.copyWith( - color: theme.colorScheme.error, + if (event.sendError != null && event.sendError != "not sent") + Text( + event.sendError!, + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.error, + ), ), + ].map( + (child) => Padding( + padding: EdgeInsetsGeometry.only(left: 4), + child: child, ), + ), ] else if (textOnly) Text("Unknown event type", style: errorStyle), ],