feat: Display file description on all file events

This commit is contained in:
Krille 2025-01-10 15:19:48 +01:00
commit f68a9de6bf
No known key found for this signature in database
GPG key ID: E067ECD60F1A0652
7 changed files with 213 additions and 142 deletions

View file

@ -4,17 +4,16 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:opus_caf_converter_dart/opus_caf_converter_dart.dart'; import 'package:opus_caf_converter_dart/opus_caf_converter_dart.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/events/html_message.dart';
import 'package:fluffychat/utils/error_reporter.dart'; import 'package:fluffychat/utils/error_reporter.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import '../../../utils/matrix_sdk_extensions/event_extension.dart'; import '../../../utils/matrix_sdk_extensions/event_extension.dart';
class AudioPlayerWidget extends StatefulWidget { class AudioPlayerWidget extends StatefulWidget {
@ -240,17 +239,11 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
final statusText = this.statusText ??= _durationString ?? '00:00'; final statusText = this.statusText ??= _durationString ?? '00:00';
final audioPlayer = this.audioPlayer; final audioPlayer = this.audioPlayer;
final body = widget.event.content.tryGet<String>('body') ?? final fileDescription = widget.event.fileDescription;
widget.event.content.tryGet<String>('filename');
final displayBody = body != null &&
body.isNotEmpty &&
widget.event.content['org.matrix.msc1767.audio'] == null;
final wavePosition = final wavePosition =
(currentPosition / maxPosition) * AudioPlayerWidget.wavesCount; (currentPosition / maxPosition) * AudioPlayerWidget.wavesCount;
final fontSize = 12 * AppConfig.fontSizeFactor;
return Padding( return Padding(
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
child: Column( child: Column(
@ -380,22 +373,12 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
], ],
), ),
), ),
if (displayBody) ...[ if (fileDescription != null) ...[
const SizedBox(height: 8), const SizedBox(height: 8),
Linkify( HtmlMessage(
text: body, html: fileDescription,
style: TextStyle( textColor: widget.color,
color: widget.color, room: widget.event.room,
fontSize: fontSize,
),
options: const LinkifyOptions(humanize: false),
linkStyle: TextStyle(
color: widget.color.withAlpha(150),
fontSize: fontSize,
decoration: TextDecoration.underline,
decorationColor: widget.color.withAlpha(150),
),
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
), ),
], ],
], ],

View file

@ -3,7 +3,9 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/events/html_message.dart';
import 'package:fluffychat/pages/image_viewer/image_viewer.dart'; import 'package:fluffychat/pages/image_viewer/image_viewer.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/widgets/mxc_image.dart'; import 'package:fluffychat/widgets/mxc_image.dart';
import '../../../widgets/blur_hash.dart'; import '../../../widgets/blur_hash.dart';
@ -13,6 +15,7 @@ class ImageBubble extends StatelessWidget {
final BoxFit fit; final BoxFit fit;
final bool maxSize; final bool maxSize;
final Color? backgroundColor; final Color? backgroundColor;
final Color? textColor;
final bool thumbnailOnly; final bool thumbnailOnly;
final bool animated; final bool animated;
final double width; final double width;
@ -34,6 +37,7 @@ class ImageBubble extends StatelessWidget {
this.onTap, this.onTap,
this.borderRadius, this.borderRadius,
this.timeline, this.timeline,
this.textColor,
super.key, super.key,
}); });
@ -76,7 +80,15 @@ class ImageBubble extends StatelessWidget {
final borderRadius = final borderRadius =
this.borderRadius ?? BorderRadius.circular(AppConfig.borderRadius); this.borderRadius ?? BorderRadius.circular(AppConfig.borderRadius);
return Material(
final fileDescription = event.fileDescription;
final textColor = this.textColor;
return Column(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
Material(
color: Colors.transparent, color: Colors.transparent,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -105,6 +117,17 @@ class ImageBubble extends StatelessWidget {
), ),
), ),
), ),
),
if (fileDescription != null && textColor != null)
SizedBox(
width: width,
child: HtmlMessage(
html: fileDescription,
textColor: textColor,
room: event.room,
),
),
],
); );
} }
} }

View file

@ -8,6 +8,7 @@ import 'package:swipe_to_action/swipe_to_action.dart';
import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart'; import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart';
import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/utils/string_color.dart';
import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
@ -130,6 +131,7 @@ class Message extends StatelessWidget {
MessageTypes.Image, MessageTypes.Image,
MessageTypes.Sticker, MessageTypes.Sticker,
}.contains(event.messageType) && }.contains(event.messageType) &&
event.fileDescription == null &&
!event.redacted) || !event.redacted) ||
(event.messageType == MessageTypes.Text && (event.messageType == MessageTypes.Text &&
event.relationshipType == null && event.relationshipType == null &&

View file

@ -140,6 +140,7 @@ class MessageContent extends StatelessWidget {
fit: fit, fit: fit,
borderRadius: borderRadius, borderRadius: borderRadius,
timeline: timeline, timeline: timeline,
textColor: textColor,
); );
case CuteEventContent.eventType: case CuteEventContent.eventType:
return CuteContent(event); return CuteContent(event);
@ -159,7 +160,7 @@ class MessageContent extends StatelessWidget {
} }
return MessageDownloadContent(event, textColor); return MessageDownloadContent(event, textColor);
case MessageTypes.Video: case MessageTypes.Video:
return EventVideoPlayer(event); return EventVideoPlayer(event, textColor: textColor);
case MessageTypes.File: case MessageTypes.File:
return MessageDownloadContent(event, textColor); return MessageDownloadContent(event, textColor);

View file

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/chat/events/html_message.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
class MessageDownloadContent extends StatelessWidget { class MessageDownloadContent extends StatelessWidget {
@ -21,7 +23,12 @@ class MessageDownloadContent extends StatelessWidget {
?.toUpperCase() ?? ?.toUpperCase() ??
'UNKNOWN'); 'UNKNOWN');
final sizeString = event.sizeString; final sizeString = event.sizeString;
return InkWell( final fileDescription = event.fileDescription;
return Column(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
InkWell(
onTap: () => event.saveFile(context), onTap: () => event.saveFile(context),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -52,7 +59,8 @@ class MessageDownloadContent extends StatelessWidget {
), ),
const Divider(height: 1), const Divider(height: 1),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
child: Row( child: Row(
children: [ children: [
Text( Text(
@ -74,6 +82,14 @@ class MessageDownloadContent extends StatelessWidget {
), ),
], ],
), ),
),
if (fileDescription != null)
HtmlMessage(
html: fileDescription,
textColor: textColor,
room: event.room,
),
],
); );
} }
} }

View file

@ -11,7 +11,9 @@ import 'package:universal_html/html.dart' as html;
import 'package:video_player/video_player.dart'; import 'package:video_player/video_player.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/events/html_message.dart';
import 'package:fluffychat/pages/chat/events/image_bubble.dart'; import 'package:fluffychat/pages/chat/events/image_bubble.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
@ -20,7 +22,8 @@ import '../../../utils/error_reporter.dart';
class EventVideoPlayer extends StatefulWidget { class EventVideoPlayer extends StatefulWidget {
final Event event; final Event event;
const EventVideoPlayer(this.event, {super.key}); final Color? textColor;
const EventVideoPlayer(this.event, {this.textColor, super.key});
@override @override
EventVideoPlayerState createState() => EventVideoPlayerState(); EventVideoPlayerState createState() => EventVideoPlayerState();
@ -102,13 +105,21 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
final blurHash = (widget.event.infoMap as Map<String, dynamic>) final blurHash = (widget.event.infoMap as Map<String, dynamic>)
.tryGet<String>('xyz.amorgan.blurhash') ?? .tryGet<String>('xyz.amorgan.blurhash') ??
fallbackBlurHash; fallbackBlurHash;
final fileDescription = widget.event.fileDescription;
final textColor = widget.textColor;
const width = 300.0;
final chewieManager = _chewieManager; final chewieManager = _chewieManager;
return Material( return Column(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
Material(
color: Colors.black, color: Colors.black,
borderRadius: BorderRadius.circular(AppConfig.borderRadius), borderRadius: BorderRadius.circular(AppConfig.borderRadius),
child: SizedBox( child: SizedBox(
height: 300, height: width,
child: chewieManager != null child: chewieManager != null
? Center(child: Chewie(controller: chewieManager)) ? Center(child: Chewie(controller: chewieManager))
: Stack( : Stack(
@ -118,10 +129,15 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
child: ImageBubble( child: ImageBubble(
widget.event, widget.event,
tapToView: false, tapToView: false,
textColor: widget.textColor,
), ),
) )
else else
BlurHash(blurhash: blurHash, width: 300, height: 300), BlurHash(
blurhash: blurHash,
width: width,
height: width,
),
Center( Center(
child: IconButton( child: IconButton(
style: IconButton.styleFrom( style: IconButton.styleFrom(
@ -147,6 +163,17 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
], ],
), ),
), ),
),
if (fileDescription != null && textColor != null)
SizedBox(
width: width,
child: HtmlMessage(
html: fileDescription,
textColor: textColor,
room: widget.event.room,
),
),
],
); );
} }
} }

View file

@ -0,0 +1,19 @@
import 'package:matrix/matrix.dart';
extension FileDescriptionExtension on Event {
String? get fileDescription {
if (!{
MessageTypes.File,
MessageTypes.Image,
}.contains(messageType)) {
return null;
}
final formattedBody = content.tryGet<String>('formatted_body');
if (formattedBody != null) return formattedBody;
final filename = content.tryGet<String>('filename');
final body = content.tryGet<String>('body');
if (filename != body && body != null) return body;
return null;
}
}