♻️ Update the embed rendering
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' as math;
|
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@@ -10,12 +9,10 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/database/message.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/chat_rooms.dart';
|
||||||
import 'package:island/pods/chat/messages_notifier.dart';
|
import 'package:island/pods/chat/messages_notifier.dart';
|
||||||
import 'package:island/pods/translate.dart';
|
import 'package:island/pods/translate.dart';
|
||||||
import 'package:island/pods/config.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/account/account_pfc.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/chat/message_content.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/alert.native.dart';
|
||||||
import 'package:island/widgets/content/cloud_file_collection.dart';
|
import 'package:island/widgets/content/cloud_file_collection.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.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:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
@@ -420,28 +418,16 @@ class MessageItemDisplayBubble extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (remoteMessage.meta['embeds'] != null)
|
if (remoteMessage.meta['embeds'] != null &&
|
||||||
...((remoteMessage.meta['embeds'] as List<dynamic>)
|
kMessageEnableEmbedTypes.contains(message.type))
|
||||||
.map((embed) => convertMapKeysToSnakeCase(embed))
|
EmbedListWidget(
|
||||||
.where((embed) => embed['type'] == 'link')
|
embeds:
|
||||||
.map((embed) => SnScrappedLink.fromJson(embed))
|
remoteMessage.meta['embeds'] as List<dynamic>,
|
||||||
.map(
|
isInteractive: true,
|
||||||
(link) => LayoutBuilder(
|
isFullPost: false,
|
||||||
builder: (context, constraints) {
|
renderingPadding: EdgeInsets.zero,
|
||||||
return EmbedLinkWidget(
|
maxWidth: 480,
|
||||||
link: link,
|
|
||||||
maxWidth: math.min(
|
|
||||||
constraints.maxWidth,
|
|
||||||
480,
|
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList()),
|
|
||||||
if (progress != null && progress!.isNotEmpty)
|
if (progress != null && progress!.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -591,23 +577,15 @@ class MessageItemDisplayIRC extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (remoteMessage.meta['embeds'] != null)
|
if (remoteMessage.meta['embeds'] != null &&
|
||||||
...((remoteMessage.meta['embeds'] as List<dynamic>)
|
kMessageEnableEmbedTypes.contains(message.type))
|
||||||
.map((embed) => convertMapKeysToSnakeCase(embed))
|
EmbedListWidget(
|
||||||
.where((embed) => embed['type'] == 'link')
|
embeds: remoteMessage.meta['embeds'] as List<dynamic>,
|
||||||
.map((embed) => SnScrappedLink.fromJson(embed))
|
isInteractive: true,
|
||||||
.map(
|
isFullPost: false,
|
||||||
(link) => LayoutBuilder(
|
renderingPadding: EdgeInsets.zero,
|
||||||
builder: (context, constraints) {
|
maxWidth: 480,
|
||||||
return EmbedLinkWidget(
|
|
||||||
link: link,
|
|
||||||
maxWidth: math.min(constraints.maxWidth, 480),
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.toList()),
|
|
||||||
if (progress != null && progress!.isNotEmpty)
|
if (progress != null && progress!.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -737,28 +715,15 @@ class MessageItemDisplayDiscord extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (remoteMessage.meta['embeds'] != null)
|
if (remoteMessage.meta['embeds'] != null &&
|
||||||
...((remoteMessage.meta['embeds'] as List<dynamic>)
|
kMessageEnableEmbedTypes.contains(message.type))
|
||||||
.map((embed) => convertMapKeysToSnakeCase(embed))
|
EmbedListWidget(
|
||||||
.where((embed) => embed['type'] == 'link')
|
embeds: remoteMessage.meta['embeds'] as List<dynamic>,
|
||||||
.map((embed) => SnScrappedLink.fromJson(embed))
|
isInteractive: true,
|
||||||
.map(
|
isFullPost: false,
|
||||||
(link) => LayoutBuilder(
|
renderingPadding: EdgeInsets.zero,
|
||||||
builder: (context, constraints) {
|
maxWidth: 480,
|
||||||
return EmbedLinkWidget(
|
|
||||||
link: link,
|
|
||||||
maxWidth: math.min(
|
|
||||||
constraints.maxWidth,
|
|
||||||
480,
|
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList()),
|
|
||||||
if (progress != null && progress!.isNotEmpty)
|
if (progress != null && progress!.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -841,25 +806,15 @@ class MessageItemDisplayDiscord extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (remoteMessage.meta['embeds'] != null)
|
if (remoteMessage.meta['embeds'] != null &&
|
||||||
...((remoteMessage.meta['embeds'] as List<dynamic>)
|
kMessageEnableEmbedTypes.contains(message.type))
|
||||||
.map((embed) => convertMapKeysToSnakeCase(embed))
|
EmbedListWidget(
|
||||||
.where((embed) => embed['type'] == 'link')
|
embeds: remoteMessage.meta['embeds'] as List<dynamic>,
|
||||||
.map((embed) => SnScrappedLink.fromJson(embed))
|
isInteractive: true,
|
||||||
.map(
|
isFullPost: false,
|
||||||
(link) => LayoutBuilder(
|
renderingPadding: EdgeInsets.zero,
|
||||||
builder: (context, constraints) {
|
maxWidth: 480,
|
||||||
return EmbedLinkWidget(
|
|
||||||
link: link,
|
|
||||||
maxWidth: math.min(constraints.maxWidth, 480),
|
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList()),
|
|
||||||
if (progress != null && progress!.isNotEmpty)
|
if (progress != null && progress!.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
76
lib/widgets/content/embed/embed_list.dart
Normal file
76
lib/widgets/content/embed/embed_list.dart
Normal file
@@ -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<dynamic> 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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,24 +1,18 @@
|
|||||||
import 'dart:math' as math;
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/models/post.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
|
||||||
import 'package:island/services/time.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/account/account_name.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/cloud_file_collection.dart';
|
import 'package:island/widgets/content/cloud_file_collection.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.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/content/markdown.dart';
|
||||||
import 'package:island/widgets/poll/poll_submit.dart';
|
|
||||||
import 'package:island/widgets/post/post_replies_sheet.dart';
|
import 'package:island/widgets/post/post_replies_sheet.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
@@ -26,6 +20,8 @@ import 'package:styled_widget/styled_widget.dart';
|
|||||||
|
|
||||||
part 'post_shared.g.dart';
|
part 'post_shared.g.dart';
|
||||||
|
|
||||||
|
const kMessageEnableEmbedTypes = ['text', 'messages.new'];
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<SnPost?> postFeaturedReply(Ref ref, String id) async {
|
Future<SnPost?> postFeaturedReply(Ref ref, String id) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
@@ -874,44 +870,12 @@ class PostBody extends ConsumerWidget {
|
|||||||
],
|
],
|
||||||
).padding(horizontal: renderingPadding.horizontal + 4, top: 4),
|
).padding(horizontal: renderingPadding.horizontal + 4, top: 4),
|
||||||
if (item.meta?['embeds'] != null)
|
if (item.meta?['embeds'] != null)
|
||||||
...((item.meta!['embeds'] as List<dynamic>)
|
EmbedListWidget(
|
||||||
.map((embedData) => convertMapKeysToSnakeCase(embedData))
|
embeds: item.meta!['embeds'] as List<dynamic>,
|
||||||
.map(
|
isInteractive: isInteractive,
|
||||||
(embedData) => switch (embedData['type']) {
|
isFullPost: isFullPost,
|
||||||
'link' => EmbedLinkWidget(
|
renderingPadding: renderingPadding,
|
||||||
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']}'),
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user