Solian/lib/widgets/chat/chat_event_list.dart

144 lines
4.6 KiB
Dart
Raw Normal View History

import 'package:flutter/gestures.dart';
2024-07-06 09:12:57 +00:00
import 'package:flutter/material.dart';
2024-10-06 09:31:44 +00:00
import 'package:flutter_animate/flutter_animate.dart';
2024-07-06 09:12:57 +00:00
import 'package:get/get.dart';
import 'package:solian/controllers/chat_events_controller.dart';
import 'package:solian/models/channel.dart';
import 'package:solian/models/event.dart';
2024-09-03 15:07:20 +00:00
import 'package:solian/providers/last_read.dart';
2024-07-06 09:12:57 +00:00
import 'package:solian/widgets/chat/chat_event.dart';
import 'package:solian/widgets/chat/chat_event_action.dart';
2024-09-15 02:55:27 +00:00
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
2024-07-06 09:12:57 +00:00
class ChatEventList extends StatelessWidget {
2024-10-06 09:31:44 +00:00
final bool noAnimated;
2024-07-06 09:12:57 +00:00
final String scope;
final Channel channel;
final ChatEventController chatController;
final Function(Event) onEdit;
final Function(Event) onReply;
const ChatEventList({
super.key,
this.scope = 'global',
required this.channel,
required this.chatController,
required this.onEdit,
required this.onReply,
2024-10-06 09:31:44 +00:00
this.noAnimated = false,
2024-07-06 09:12:57 +00:00
});
bool _checkMessageMergeable(Event? a, Event? b) {
2024-07-06 09:12:57 +00:00
if (a == null || b == null) return false;
if (a.sender.account.id != b.sender.account.id) return false;
return a.createdAt.difference(b.createdAt).inMinutes <= 3;
}
void _openActions(BuildContext context, Event item) {
showModalBottomSheet(
useRootNavigator: true,
context: context,
builder: (context) => ChatEventAction(
channel: channel,
realm: channel.realm,
item: item,
onEdit: () {
onEdit(item);
},
onReply: () {
onReply(item);
},
),
);
}
2024-07-06 09:12:57 +00:00
@override
Widget build(BuildContext context) {
return CustomScrollView(
cacheExtent: 100,
2024-07-06 09:12:57 +00:00
reverse: true,
slivers: [
Obx(() {
2024-09-15 02:55:27 +00:00
return SliverInfiniteList(
2024-07-06 09:12:57 +00:00
key: Key('chat-history#${channel.id}'),
2024-09-15 02:55:27 +00:00
isLoading: chatController.isLoading.value,
2024-07-06 09:12:57 +00:00
itemCount: chatController.currentEvents.length,
itemBuilder: (context, index) {
2024-09-03 15:07:20 +00:00
Get.find<LastReadProvider>().messagesLastReadAt =
chatController.currentEvents[index].id;
2024-07-06 09:12:57 +00:00
bool isMerged = false, hasMerged = false;
if (index > 0) {
hasMerged = _checkMessageMergeable(
2024-07-06 09:12:57 +00:00
chatController.currentEvents[index - 1].data,
chatController.currentEvents[index].data,
);
}
if (index + 1 < chatController.currentEvents.length) {
isMerged = _checkMessageMergeable(
2024-07-06 09:12:57 +00:00
chatController.currentEvents[index].data,
chatController.currentEvents[index + 1].data,
);
}
final item = chatController.currentEvents[index].data;
return TapRegion(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
child: Builder(builder: (context) {
final widget = ChatEvent(
key: Key('m${item!.uuid}'),
item: item,
isMerged: isMerged,
chatController: chatController,
).paddingOnly(
top: !isMerged ? 8 : 0,
bottom: !hasMerged ? 8 : 0,
);
2024-10-06 09:31:44 +00:00
if (noAnimated) {
return widget;
} else {
return widget
.animate(
key: Key('animated-m${item.uuid}'),
)
.slideY(
curve: Curves.fastLinearToSlowEaseIn,
duration: 250.ms,
begin: 0.5,
end: 0,
);
}
}),
onLongPress: () {
_openActions(context, item!);
},
),
onTapInside: (event) {
if (event.buttons == kSecondaryMouseButton) {
_openActions(context, item!);
} else if (event.buttons == kMiddleMouseButton) {
onReply(item!);
2024-10-06 09:31:44 +00:00
}
2024-07-06 09:12:57 +00:00
},
);
2024-07-06 09:12:57 +00:00
},
2024-09-15 02:55:27 +00:00
onFetchData: () {
2024-09-16 11:50:49 +00:00
if (chatController.currentEvents.length <
chatController.totalEvents.value) {
chatController.loadEvents(
chatController.channel!,
chatController.scope!,
);
}
2024-09-15 02:55:27 +00:00
},
2024-07-06 09:12:57 +00:00
);
}),
],
);
}
}