From ec4ceae1fb91261213e7939172e1757df391a489 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 23 Jul 2024 18:14:31 +0545 Subject: [PATCH] fix: Fix image and add photo viewer #2771 --- lib/chat_room/chat_room.dart | 2 +- lib/chat_room/cubit/chat_room_cubit.dart | 6 +- .../matrix_chat/matrix_chat_impl.dart | 14 ++++- .../matrix_chat/matrix_chat_interface.dart | 2 +- lib/chat_room/view/chat_room_view.dart | 45 +++++++++----- lib/chat_room/view/photo_viewer.dart | 61 +++++++++++++++++++ 6 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 lib/chat_room/view/photo_viewer.dart diff --git a/lib/chat_room/chat_room.dart b/lib/chat_room/chat_room.dart index 66ad7d752..ae593b6e3 100644 --- a/lib/chat_room/chat_room.dart +++ b/lib/chat_room/chat_room.dart @@ -1,4 +1,4 @@ export 'cubit/chat_room_cubit.dart'; export 'matrix_chat/matrix_chat.dart'; export 'view/chat_room_view.dart'; -export 'widget/mxc_image.dart'; +export 'view/photo_viewer.dart'; diff --git a/lib/chat_room/cubit/chat_room_cubit.dart b/lib/chat_room/cubit/chat_room_cubit.dart index fb2daa104..c5361d750 100644 --- a/lib/chat_room/cubit/chat_room_cubit.dart +++ b/lib/chat_room/cubit/chat_room_cubit.dart @@ -192,7 +192,7 @@ abstract class ChatRoomCubit extends Cubit { await _onEventSubscription?.cancel(); _onEventSubscription = - matrixChat.client!.onRoomState.stream.listen((Event event) { + matrixChat.client!.onRoomState.stream.listen((Event event) async { if (event.roomId == _roomId && event.type == 'm.room.message') { final txId = event.unsigned?['transaction_id'] as String?; if (state.messages.any( @@ -208,7 +208,7 @@ abstract class ChatRoomCubit extends Cubit { newMessages[index] = updatedMessage; emit(state.copyWith(messages: newMessages)); } else { - final Message message = matrixChat.mapEventToMessage(event); + final Message message = await matrixChat.mapEventToMessage(event); emit( state.copyWith( messages: [message, ...state.messages], @@ -218,7 +218,7 @@ abstract class ChatRoomCubit extends Cubit { setMessagesAsRead(); - Future.delayed(const Duration(seconds: 1)) + await Future.delayed(const Duration(seconds: 1)) .then((val) => _getUnreadMessageCount()); } }); diff --git a/lib/chat_room/matrix_chat/matrix_chat_impl.dart b/lib/chat_room/matrix_chat/matrix_chat_impl.dart index 12c9953db..e5179ec98 100644 --- a/lib/chat_room/matrix_chat/matrix_chat_impl.dart +++ b/lib/chat_room/matrix_chat/matrix_chat_impl.dart @@ -172,11 +172,18 @@ class MatrixChatImpl extends MatrixChatInterface { ..sort( (e1, e2) => e2.originServerTs.compareTo(e1.originServerTs), ); - return messageEvents.map(mapEventToMessage).toList(); + + final List messages = []; + + for (final event in messageEvents) { + final a = await mapEventToMessage(event); + messages.add(a); + } + return messages; } @override - Message mapEventToMessage(Event event) { + Future mapEventToMessage(Event event) async { late final Message message; num size = 0; if (event.content['info'] != null) { @@ -205,12 +212,15 @@ class MatrixChatImpl extends MatrixChatInterface { final url = (file != null && file is Map) ? file['url'] : ''; + final data = await event.downloadAndDecryptAttachment(); + message = ImageMessage( id: const Uuid().v4(), remoteId: event.eventId, name: event.plaintextBody, size: size, uri: url.toString(), + metadata: {'bytes': data.bytes}, status: mapEventStatusToMessageStatus(event.status), createdAt: event.originServerTs.millisecondsSinceEpoch, author: User(id: event.senderId), diff --git a/lib/chat_room/matrix_chat/matrix_chat_interface.dart b/lib/chat_room/matrix_chat/matrix_chat_interface.dart index 97a5169e8..abd0b3b96 100644 --- a/lib/chat_room/matrix_chat/matrix_chat_interface.dart +++ b/lib/chat_room/matrix_chat/matrix_chat_interface.dart @@ -26,7 +26,7 @@ abstract class MatrixChatInterface { Future handleFileSelection({ required OnMessageCreated onMessageCreated, }); - Message mapEventToMessage(Event event); + Future mapEventToMessage(Event event); Status mapEventStatusToMessageStatus(EventStatus status); String getThumbnail({ required String url, diff --git a/lib/chat_room/view/chat_room_view.dart b/lib/chat_room/view/chat_room_view.dart index 38b00a782..81e069451 100644 --- a/lib/chat_room/view/chat_room_view.dart +++ b/lib/chat_room/view/chat_room_view.dart @@ -1,14 +1,17 @@ import 'dart:io'; +import 'dart:typed_data'; import 'package:altme/app/app.dart'; import 'package:altme/chat_room/chat_room.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/l10n/l10n.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart'; -import 'package:flutter_chat_ui/flutter_chat_ui.dart' hide Message; +import 'package:flutter_chat_ui/flutter_chat_ui.dart' + hide ImageMessage, Message; import 'package:visibility_detector/visibility_detector.dart'; class ChatRoomView extends StatefulWidget { @@ -179,6 +182,7 @@ class _ChatRoomViewState extends State { ), ), messages: state.messages, + disableImageGallery: true, imageMessageBuilder: (p0, {required messageWidth}) { final link = p0.uri; @@ -188,21 +192,12 @@ class _ChatRoomViewState extends State { return CachedImageFromNetwork( link, fit: BoxFit.contain, - width: 500, - height: 500, ); - } - if (link.startsWith('mxc')) { - return MxcImage( - client: context - .read() - .matrixChat - .client!, + } else if (link.startsWith('mxc')) { + final data = p0.metadata!['bytes'] as Uint8List; + return Image.memory( + data, fit: BoxFit.contain, - width: 500, - height: 500, - uri: Uri.parse(link), - isThumbnail: false, ); } else { return Image.file( @@ -322,6 +317,26 @@ class _ChatRoomViewState extends State { } Future _handleMessageTap(BuildContext _, Message message) async { - await liveChatCubit!.handleMessageTap(message); + if (message is ImageMessage) { + final link = message.uri; + + late ImageProvider imageProvider; + if (link.startsWith('http')) { + imageProvider = CachedNetworkImageProvider(link); + } else if (link.startsWith('mxc')) { + final data = message.metadata!['bytes'] as Uint8List; + imageProvider = MemoryImage(data); + } else { + imageProvider = AssetImage(link); + } + + await Navigator.of(context).push( + PhotoViewer.route( + imageProvider: imageProvider, + ), + ); + } else { + await liveChatCubit!.handleMessageTap(message); + } } } diff --git a/lib/chat_room/view/photo_viewer.dart b/lib/chat_room/view/photo_viewer.dart new file mode 100644 index 000000000..d390ceeed --- /dev/null +++ b/lib/chat_room/view/photo_viewer.dart @@ -0,0 +1,61 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:photo_view/photo_view.dart'; + +class PhotoViewer extends StatelessWidget { + const PhotoViewer({ + super.key, + required this.imageProvider, + }); + + final ImageProvider imageProvider; + + static Route route({required ImageProvider imageProvider}) { + return MaterialPageRoute( + settings: const RouteSettings(name: '/PhotoViewer'), + builder: (_) => PhotoViewer(imageProvider: imageProvider), + ); + } + + @override + Widget build(BuildContext context) { + return BasePage( + useSafeArea: false, + scrollView: false, + body: Dismissible( + key: const Key('photo_view_gallery'), + direction: DismissDirection.down, + onDismissed: (direction) { + Navigator.of(context).pop(); + }, + child: Stack( + children: [ + Center( + child: PhotoView( + imageProvider: imageProvider, + loadingBuilder: (context, event) => const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(), + ), + ), + ), + ), + Positioned.directional( + end: 16, + textDirection: Directionality.of(context), + top: 56, + child: CloseButton( + color: Theme.of(context).colorScheme.onPrimary, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + ], + ), + ), + ); + } +}