diff --git a/lib/widgets/chat/message_item.dart b/lib/widgets/chat/message_item.dart index e08225bc..9da5c8e3 100644 --- a/lib/widgets/chat/message_item.dart +++ b/lib/widgets/chat/message_item.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:math' as math; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; @@ -10,12 +9,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/database/message.dart'; -import 'package:island/models/embed.dart'; import 'package:island/pods/chat/chat_rooms.dart'; import 'package:island/pods/chat/messages_notifier.dart'; import 'package:island/pods/translate.dart'; import 'package:island/pods/config.dart'; -import 'package:island/utils/mapping.dart'; import 'package:island/widgets/account/account_pfc.dart'; import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/chat/message_content.dart'; @@ -24,7 +21,8 @@ import 'package:island/widgets/chat/message_sender_info.dart'; import 'package:island/widgets/content/alert.native.dart'; import 'package:island/widgets/content/cloud_file_collection.dart'; import 'package:island/widgets/content/cloud_files.dart'; -import 'package:island/widgets/content/embed/link.dart'; +import 'package:island/widgets/content/embed/embed_list.dart'; +import 'package:island/widgets/post/post_shared.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:island/widgets/content/sheet.dart'; @@ -420,28 +418,16 @@ class MessageItemDisplayBubble extends HookConsumerWidget { ); }, ), - if (remoteMessage.meta['embeds'] != null) - ...((remoteMessage.meta['embeds'] as List) - .map((embed) => convertMapKeysToSnakeCase(embed)) - .where((embed) => embed['type'] == 'link') - .map((embed) => SnScrappedLink.fromJson(embed)) - .map( - (link) => LayoutBuilder( - builder: (context, constraints) { - return EmbedLinkWidget( - link: link, - maxWidth: math.min( - constraints.maxWidth, - 480, - ), - margin: const EdgeInsets.symmetric( - vertical: 4, - ), - ); - }, - ), - ) - .toList()), + if (remoteMessage.meta['embeds'] != null && + kMessageEnableEmbedTypes.contains(message.type)) + EmbedListWidget( + embeds: + remoteMessage.meta['embeds'] as List, + isInteractive: true, + isFullPost: false, + renderingPadding: EdgeInsets.zero, + maxWidth: 480, + ), if (progress != null && progress!.isNotEmpty) Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -591,23 +577,15 @@ class MessageItemDisplayIRC extends HookConsumerWidget { ); }, ), - if (remoteMessage.meta['embeds'] != null) - ...((remoteMessage.meta['embeds'] as List) - .map((embed) => convertMapKeysToSnakeCase(embed)) - .where((embed) => embed['type'] == 'link') - .map((embed) => SnScrappedLink.fromJson(embed)) - .map( - (link) => LayoutBuilder( - builder: (context, constraints) { - return EmbedLinkWidget( - link: link, - maxWidth: math.min(constraints.maxWidth, 480), - margin: const EdgeInsets.symmetric(vertical: 4), - ); - }, - ), - ) - .toList()), + if (remoteMessage.meta['embeds'] != null && + kMessageEnableEmbedTypes.contains(message.type)) + EmbedListWidget( + embeds: remoteMessage.meta['embeds'] as List, + isInteractive: true, + isFullPost: false, + renderingPadding: EdgeInsets.zero, + maxWidth: 480, + ), if (progress != null && progress!.isNotEmpty) Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -737,28 +715,15 @@ class MessageItemDisplayDiscord extends HookConsumerWidget { ); }, ), - if (remoteMessage.meta['embeds'] != null) - ...((remoteMessage.meta['embeds'] as List) - .map((embed) => convertMapKeysToSnakeCase(embed)) - .where((embed) => embed['type'] == 'link') - .map((embed) => SnScrappedLink.fromJson(embed)) - .map( - (link) => LayoutBuilder( - builder: (context, constraints) { - return EmbedLinkWidget( - link: link, - maxWidth: math.min( - constraints.maxWidth, - 480, - ), - margin: const EdgeInsets.symmetric( - vertical: 4, - ), - ); - }, - ), - ) - .toList()), + if (remoteMessage.meta['embeds'] != null && + kMessageEnableEmbedTypes.contains(message.type)) + EmbedListWidget( + embeds: remoteMessage.meta['embeds'] as List, + isInteractive: true, + isFullPost: false, + renderingPadding: EdgeInsets.zero, + maxWidth: 480, + ), if (progress != null && progress!.isNotEmpty) Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -841,25 +806,15 @@ class MessageItemDisplayDiscord extends HookConsumerWidget { ); }, ), - if (remoteMessage.meta['embeds'] != null) - ...((remoteMessage.meta['embeds'] as List) - .map((embed) => convertMapKeysToSnakeCase(embed)) - .where((embed) => embed['type'] == 'link') - .map((embed) => SnScrappedLink.fromJson(embed)) - .map( - (link) => LayoutBuilder( - builder: (context, constraints) { - return EmbedLinkWidget( - link: link, - maxWidth: math.min(constraints.maxWidth, 480), - margin: const EdgeInsets.symmetric( - vertical: 4, - ), - ); - }, - ), - ) - .toList()), + if (remoteMessage.meta['embeds'] != null && + kMessageEnableEmbedTypes.contains(message.type)) + EmbedListWidget( + embeds: remoteMessage.meta['embeds'] as List, + isInteractive: true, + isFullPost: false, + renderingPadding: EdgeInsets.zero, + maxWidth: 480, + ), if (progress != null && progress!.isNotEmpty) Column( crossAxisAlignment: CrossAxisAlignment.stretch, diff --git a/lib/widgets/content/embed/embed_list.dart b/lib/widgets/content/embed/embed_list.dart new file mode 100644 index 00000000..e1ae80dd --- /dev/null +++ b/lib/widgets/content/embed/embed_list.dart @@ -0,0 +1,76 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:island/models/embed.dart'; +import 'package:island/models/poll.dart'; +import 'package:island/services/responsive.dart'; +import 'package:island/utils/mapping.dart'; +import 'package:island/widgets/content/embed/link.dart'; +import 'package:island/widgets/poll/poll_submit.dart'; +import 'package:styled_widget/styled_widget.dart'; + +class EmbedListWidget extends StatelessWidget { + final List embeds; + final bool isInteractive; + final bool isFullPost; + final EdgeInsets renderingPadding; + final double? maxWidth; + + const EmbedListWidget({ + super.key, + required this.embeds, + this.isInteractive = true, + this.isFullPost = false, + this.renderingPadding = EdgeInsets.zero, + this.maxWidth, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: + embeds + .map((embedData) => convertMapKeysToSnakeCase(embedData)) + .map( + (embedData) => switch (embedData['type']) { + 'link' => EmbedLinkWidget( + link: SnScrappedLink.fromJson(embedData), + maxWidth: + maxWidth ?? + math.min( + MediaQuery.of(context).size.width, + kWideScreenWidth, + ), + margin: EdgeInsets.only( + top: 4, + bottom: 4, + left: renderingPadding.horizontal, + right: renderingPadding.horizontal, + ), + ), + 'poll' => Card( + margin: EdgeInsets.symmetric( + horizontal: renderingPadding.horizontal, + vertical: 8, + ), + child: + embedData['poll'] == null + ? const Text('Poll was not loaded...') + : PollSubmit( + initialAnswers: + embedData['poll']?['user_answer']?['answer'], + stats: embedData['poll']?['stats'], + poll: SnPollWithStats.fromJson(embedData['poll']), + onSubmit: (_) {}, + isReadonly: !isInteractive, + isInitiallyExpanded: isFullPost, + ).padding(horizontal: 16, vertical: 12), + ), + _ => Text('Unable show embed: ${embedData['type']}'), + }, + ) + .toList(), + ); + } +} diff --git a/lib/widgets/post/post_shared.dart b/lib/widgets/post/post_shared.dart index 729702db..d4176216 100644 --- a/lib/widgets/post/post_shared.dart +++ b/lib/widgets/post/post_shared.dart @@ -1,24 +1,18 @@ -import 'dart:math' as math; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:island/models/embed.dart'; -import 'package:island/models/poll.dart'; import 'package:island/models/post.dart'; import 'package:island/pods/network.dart'; -import 'package:island/services/responsive.dart'; import 'package:island/services/time.dart'; -import 'package:island/utils/mapping.dart'; import 'package:island/widgets/account/account_name.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/content/cloud_file_collection.dart'; import 'package:island/widgets/content/cloud_files.dart'; -import 'package:island/widgets/content/embed/link.dart'; +import 'package:island/widgets/content/embed/embed_list.dart'; import 'package:island/widgets/content/markdown.dart'; -import 'package:island/widgets/poll/poll_submit.dart'; import 'package:island/widgets/post/post_replies_sheet.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -26,6 +20,8 @@ import 'package:styled_widget/styled_widget.dart'; part 'post_shared.g.dart'; +const kMessageEnableEmbedTypes = ['text', 'messages.new']; + @riverpod Future postFeaturedReply(Ref ref, String id) async { final client = ref.watch(apiClientProvider); @@ -874,44 +870,12 @@ class PostBody extends ConsumerWidget { ], ).padding(horizontal: renderingPadding.horizontal + 4, top: 4), if (item.meta?['embeds'] != null) - ...((item.meta!['embeds'] as List) - .map((embedData) => convertMapKeysToSnakeCase(embedData)) - .map( - (embedData) => switch (embedData['type']) { - 'link' => EmbedLinkWidget( - link: SnScrappedLink.fromJson(embedData), - maxWidth: math.min( - MediaQuery.of(context).size.width, - kWideScreenWidth, - ), - margin: EdgeInsets.only( - top: 4, - bottom: 4, - left: renderingPadding.horizontal, - right: renderingPadding.horizontal, - ), - ), - 'poll' => Card( - margin: EdgeInsets.symmetric( - horizontal: renderingPadding.horizontal, - vertical: 8, - ), - child: - embedData['poll'] == null - ? const Text('Poll was not loaded...') - : PollSubmit( - initialAnswers: - embedData['poll']?['user_answer']?['answer'], - stats: embedData['poll']?['stats'], - poll: SnPollWithStats.fromJson(embedData['poll']), - onSubmit: (_) {}, - isReadonly: !isInteractive, - isInitiallyExpanded: isFullPost, - ).padding(horizontal: 16, vertical: 12), - ), - _ => Text('Unable show embed: ${embedData['type']}'), - }, - )), + EmbedListWidget( + embeds: item.meta!['embeds'] as List, + isInteractive: isInteractive, + isFullPost: isFullPost, + renderingPadding: renderingPadding, + ), ], ); }