Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import 'package:fluffychat/pages/chat/chat_report_message_additional_reason_dial
import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat/context_item_chat_action.dart';
import 'package:fluffychat/pages/chat/dialog_reject_invite_widget.dart';
import 'package:fluffychat/presentation/mixins/grouped_events_mixin.dart';
import 'package:fluffychat/pages/chat/events/message_content_mixin.dart';
import 'package:fluffychat/pages/chat/input_bar/focus_suggestion_controller.dart';
import 'package:fluffychat/presentation/enum/chat/right_column_type_enum.dart';
Expand Down Expand Up @@ -141,7 +142,8 @@ class ChatController extends State<Chat>
LeaveChatMixin,
DeleteEventMixin,
UnblockUserMixin,
AudioMixin {
AudioMixin,
EventGrouperMixin {
final NetworkConnectionService networkConnectionService =
getIt.get<NetworkConnectionService>();

Expand Down Expand Up @@ -1211,17 +1213,22 @@ class ChatController extends State<Chat>
return eventIndex + addedHeadItemsInChat;
}

List<GroupedEvents> get groupedEvents => groupEvents(timeline?.events ?? []);

int _getEventIndex(String eventId) {
final foundEvent =
timeline!.events.firstWhereOrNull((event) => event.eventId == eventId);
// Find the group that contains the eventId (in main or additional events)
final foundGroup = groupedEvents.firstWhereOrNull(
(group) => group.allEvents.any((event) => event.eventId == eventId),
);

final eventIndex = foundEvent == null
? -1
: timeline!.events.indexWhere(
(event) => event.eventId == foundEvent.eventId,
);
if (foundGroup == null) {
return -1;
}

return eventIndex;
// Return the index of the main event in the original timeline
return timeline!.events.indexWhere(
(event) => event.eventId == foundGroup.mainEvent.eventId,
);
}

Future<void> scrollToEventId(String eventId, {bool highlight = true}) async {
Expand Down
39 changes: 26 additions & 13 deletions lib/pages/chat/chat_event_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,20 @@ class ChatEventList extends StatelessWidget {
Widget build(BuildContext context) {
final horizontalPadding = TwakeThemes.isColumnMode(context) ? 16.0 : 0.0;

final events = controller.timeline!.events;
// create a map of eventId --> index to greatly improve performance of
// Group consecutive image events
final groupedEvents = controller.groupedEvents;

// create a map of eventId --> grouped index to greatly improve performance of
// ListView's findChildIndexCallback
// This maps all event IDs (including those in groups) to their group's index
final thisEventsKeyMap = <String, int>{};
for (var i = 0; i < events.length; i++) {
thisEventsKeyMap[events[i].eventId] = i;
for (var i = 0; i < groupedEvents.length; i++) {
final group = groupedEvents[i];
// Map the main event and all additional events to the same group index
for (final event in group.allEvents) {
// Add 1 to account for the first item (footer)
thisEventsKeyMap[event.eventId] = i + 1;
}
}

if (controller.hasNoMessageEvents) {
Expand Down Expand Up @@ -117,7 +125,7 @@ class ChatEventList extends StatelessWidget {
return const SizedBox.shrink();
}
// Request history button or progress indicator:
if (index == events.length + 1) {
if (index == groupedEvents.length + 1) {
if (controller.timeline!.isRequestingHistory) {
return const Center(
child: CupertinoActivityIndicator(),
Expand All @@ -133,14 +141,18 @@ class ChatEventList extends StatelessWidget {
}
return const SizedBox.shrink();
}
final currentEventIndex = index - 1;
final event = events[currentEventIndex];
final previousEvent = currentEventIndex > 0
? events[currentEventIndex - 1]
: null;
final nextEvent = index < events.length
? events[currentEventIndex + 1]

final currentGroupIndex = index - 1;
final group = groupedEvents[currentGroupIndex];
final event = group.mainEvent;

final previousEvent = currentGroupIndex > 0
? groupedEvents[currentGroupIndex - 1].mainEvent
: null;
final nextEvent =
currentGroupIndex < groupedEvents.length - 1
? groupedEvents[currentGroupIndex + 1].mainEvent
: null;
return event.isVisibleInGui
? AutoScrollTag(
key: ValueKey(event.eventId),
Expand Down Expand Up @@ -237,11 +249,12 @@ class ChatEventList extends StatelessWidget {
.getRecentReactionsInteractor
.execute(),
onReport: controller.reportEventAction,
groupedEvents: group.isGrouped ? group : null,
),
)
: const SizedBox.shrink();
},
childCount: events.length + 2,
childCount: groupedEvents.length + 2,
findChildIndexCallback: (key) => controller
.findChildIndexCallback(key, thisEventsKeyMap),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ class MessageImageBuilder extends StatelessWidget {

final double? maxWidth;

final bool rounded;

const MessageImageBuilder({
super.key,
required this.event,
this.onTapPreview,
this.onTapSelectMode,
this.maxWidth,
this.rounded = true,
});

@override
Expand All @@ -44,6 +47,7 @@ class MessageImageBuilder extends StatelessWidget {
event: event,
onTapPreview: onTapPreview,
displayImageInfo: displayImageInfo,
rounded: rounded,
);
}
displayImageInfo ??= DisplayImageInfo(
Expand All @@ -65,6 +69,7 @@ class MessageImageBuilder extends StatelessWidget {
event: event,
onTapPreview: onTapPreview,
displayImageInfo: displayImageInfo,
rounded: rounded,
);
}
return ImageBubble(
Expand All @@ -76,6 +81,8 @@ class MessageImageBuilder extends StatelessWidget {
onTapPreview: onTapPreview,
animated: true,
thumbnailOnly: true,
thumbnailCacheKey: event.eventId,
rounded: rounded,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SendingImageInfoWidget extends StatefulWidget {
required this.event,
required this.displayImageInfo,
this.onTapPreview,
this.rounded = true,
});

final MatrixImageFile matrixFile;
Expand All @@ -32,6 +33,8 @@ class SendingImageInfoWidget extends StatefulWidget {

final DisplayImageInfo displayImageInfo;

final bool rounded;

@override
State<SendingImageInfoWidget> createState() => _SendingImageInfoWidgetState();
}
Expand All @@ -44,7 +47,6 @@ class _SendingImageInfoWidgetState extends State<SendingImageInfoWidget>
@override
void dispose() {
sendingFileProgressNotifier.dispose();
uploadFileStateNotifier.dispose();
super.dispose();
}

Expand Down Expand Up @@ -112,11 +114,14 @@ class _SendingImageInfoWidgetState extends State<SendingImageInfoWidget>
);
},
child: Material(
borderRadius: MessageContentStyle.borderRadiusBubble,
borderRadius:
widget.rounded ? MessageContentStyle.borderRadiusBubble : null,
child: InkWell(
onTap: () => _onTap(context),
child: ClipRRect(
borderRadius: MessageContentStyle.borderRadiusBubble,
borderRadius: widget.rounded
? MessageContentStyle.borderRadiusBubble
: BorderRadius.zero,
child: Stack(
alignment: Alignment.center,
children: [
Expand Down
Loading
Loading