diff --git a/lib/widgets/chat_page/image_message.dart b/lib/widgets/chat_page/image_message.dart new file mode 100644 index 0000000..103fdd2 --- /dev/null +++ b/lib/widgets/chat_page/image_message.dart @@ -0,0 +1,58 @@ +import "dart:math"; +import "package:cross_cache/cross_cache.dart"; +import "package:flutter/material.dart"; +import "package:flutter_chat_core/flutter_chat_core.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:flyer_chat_image_message/flyer_chat_image_message.dart"; +import "package:nexus/controllers/cross_cache_controller.dart"; +import "package:nexus/helpers/extensions/get_headers.dart"; + +class ExpandableImageMessage extends ConsumerWidget { + final ImageMessage message; + final int index; + + const ExpandableImageMessage(this.message, {required this.index, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) => InkWell( + onTap: () => showDialog( + context: context, + builder: (_) => LayoutBuilder( + builder: (context, constraints) => Dialog( + backgroundColor: Colors.transparent, + insetPadding: EdgeInsets.all(constraints.maxWidth / 100), + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: min(constraints.maxWidth, 1000), + ), + child: InteractiveViewer( + child: Image( + fit: BoxFit.contain, + image: CachedNetworkImage( + message.source, + ref.watch(CrossCacheController.provider), + headers: ref.headers, + ), + ), + ), + ), + ), + ), + ), + child: FlyerChatImageMessage( + customImageProvider: CachedNetworkImage( + message.source, + ref.watch(CrossCacheController.provider), + headers: ref.headers, + ), + errorBuilder: (context, error, stackTrace) => Center( + child: Text( + "Image Failed to Load", + style: TextStyle(color: Theme.of(context).colorScheme.error), + ), + ), + message: message, + index: index, + ), + ); +} diff --git a/lib/widgets/chat_page/room_chat.dart b/lib/widgets/chat_page/room_chat.dart index 011f359..4bd4263 100644 --- a/lib/widgets/chat_page/room_chat.dart +++ b/lib/widgets/chat_page/room_chat.dart @@ -19,6 +19,7 @@ import "package:nexus/helpers/extensions/show_context_menu.dart"; import "package:nexus/models/relation_type.dart"; import "package:nexus/models/requests/report_request.dart"; import "package:nexus/widgets/chat_page/chat_box.dart"; +import "package:nexus/widgets/chat_page/image_message.dart"; import "package:nexus/widgets/chat_page/member_list.dart"; import "package:nexus/widgets/chat_page/message_wrapper.dart"; import "package:nexus/widgets/chat_page/room_appbar.dart"; @@ -238,6 +239,7 @@ class RoomChat extends HookConsumerWidget { ), builders: Builders( loadMoreBuilder: (_) => Loading(), + chatAnimatedListBuilder: (_, itemBuilder) => ChatAnimatedList( itemBuilder: itemBuilder, @@ -247,6 +249,7 @@ class RoomChat extends HookConsumerWidget { onStartReached: () => client.markRead(room), bottomPadding: 72, ), + composerBuilder: (_) => ChatBox( relationType: relationType.value, relatedMessage: replyToMessage.value, @@ -254,104 +257,6 @@ class RoomChat extends HookConsumerWidget { room: room, ), - // TODO: Polls - // customMessageBuilder: - // ( - // context, - // message, - // index, { - // required bool isSentByMe, - // MessageGroupStatus? groupStatus, - // }) { - // final poll = - // message.metadata?["poll"] - // as PollStartContent; - // final responses = - // (message.metadata?["responses"] - // as Map< - // String, - // Set - // >) - // .values - // .expand((set) => set) - // .fold({}, ( - // acc, - // value, - // ) { - // acc[value] = - // (acc[value] ?? 0) + 1; - // return acc; - // }); - - // return Column( - // crossAxisAlignment: - // CrossAxisAlignment.start, - // spacing: 4, - // children: [ - // TopWidget( - // message, - // headers: room - // .roomData - // .client - // .headers, - // groupStatus: groupStatus, - // ), - - // DynamicPolls( - // startDate: DateTime.now(), - // endDate: DateTime.now(), - // private: - // poll.kind == - // PollKind.undisclosed, - // allowReselection: true, - // backgroundDecoration: - // BoxDecoration( - // borderRadius: - // BorderRadius.all( - // Radius.circular(16), - // ), - // border: Border.all( - // color: theme - // .colorScheme - // .primaryContainer, - // width: 4, - // ), - // ), - // allStyle: Styles( - // titleStyle: TitleStyle( - // style: theme - // .textTheme - // .headlineSmall, - // ), - // optionStyle: OptionStyle( - // fillColor: theme - // .colorScheme - // .primaryContainer, - // selectedBorderColor: theme - // .colorScheme - // .primary, - // borderColor: theme - // .colorScheme - // .primary, - // unselectedBorderColor: - // Colors.transparent, - // textSelectColor: theme - // .colorScheme - // .primary, - // ), - // ), - // onOptionSelected: - // (int index) {}, - // title: poll.question.mText, - // options: poll.answers - // .map( - // (option) => option.mText, - // ) - // .toList(), - // ), - // ], - // ); - // }, textMessageBuilder: ( context, @@ -372,6 +277,7 @@ class RoomChat extends HookConsumerWidget { groupStatus, ), + imageMessageBuilder: ( context, @@ -379,103 +285,30 @@ class RoomChat extends HookConsumerWidget { index, { required bool isSentByMe, MessageGroupStatus? groupStatus, - }) { - final text = - message.metadata?["text"] as TextMessage?; - return MessageWrapper( - text ?? message, - Column( - spacing: 4, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - TextMessageWrapper( + }) => MessageWrapper( + message, + Column( + spacing: 4, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + TextMessageWrapper( + message, + content: message.text, + groupStatus: groupStatus, + onTapReply: notifier.scrollToMessage, + updateMessage: controller.updateMessage, + isSentByMe: isSentByMe, + extra: ExpandableImageMessage( message, - content: message.text, - groupStatus: groupStatus, - onTapReply: notifier.scrollToMessage, - updateMessage: - controller.updateMessage, - isSentByMe: isSentByMe, - extra: InkWell( - onTap: () => showDialog( - context: context, - builder: (_) => LayoutBuilder( - builder: - ( - context, - constraints, - ) => Dialog( - backgroundColor: - Colors.transparent, - insetPadding: - EdgeInsets.all( - constraints - .maxWidth / - 100, - ), - child: ConstrainedBox( - constraints: - BoxConstraints( - minWidth: min( - constraints - .maxWidth, - 1000, - ), - ), - child: InteractiveViewer( - child: Image( - fit: BoxFit.contain, - image: CachedNetworkImage( - message.source, - ref.watch( - CrossCacheController - .provider, - ), - headers: - ref.headers, - ), - ), - ), - ), - ), - ), - ), - child: FlyerChatImageMessage( - customImageProvider: - CachedNetworkImage( - message.source, - ref.watch( - CrossCacheController - .provider, - ), - headers: ref.headers, - ), - errorBuilder: - ( - context, - error, - stackTrace, - ) => Center( - child: Text( - "Image Failed to Load", - style: TextStyle( - color: Theme.of( - context, - ).colorScheme.error, - ), - ), - ), - message: message, - index: index, - ), - ), + index: index, ), - ], - ), - groupStatus, - ); - }, + ), + ], + ), + groupStatus, + ), + fileMessageBuilder: ( _, @@ -506,6 +339,7 @@ class RoomChat extends HookConsumerWidget { ), groupStatus, ), + systemMessageBuilder: ( _, @@ -517,6 +351,7 @@ class RoomChat extends HookConsumerWidget { message: message, index: index, ), + unsupportedMessageBuilder: ( _,