Skip to content

Commit

Permalink
Chore: Refactor link previews and MediaView widget (#1720)
Browse files Browse the repository at this point in the history
* feat: refactor media view, remove image scraping option

* feat: decouple MediaView from PostViewMedia, deprecate LinkPreviewCard

* feat: only apply filter to nsfw images

* fix: fix video tap handling
  • Loading branch information
hjiangsu authored Mar 3, 2025
1 parent 1d42304 commit 25c0f45
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 554 deletions.
27 changes: 14 additions & 13 deletions lib/community/pages/create_post_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import 'package:markdown_editor/markdown_editor.dart';
import 'package:thunder/account/models/account.dart';
import 'package:thunder/account/models/draft.dart';
import 'package:thunder/community/bloc/image_bloc.dart';
import 'package:thunder/core/enums/media_type.dart';
import 'package:thunder/core/models/media.dart';
import 'package:thunder/post/widgets/post_action_bottom_sheet.dart';
import 'package:thunder/core/auth/bloc/auth_bloc.dart';
import 'package:thunder/core/auth/helpers/fetch_account.dart';
Expand All @@ -32,7 +34,7 @@ import 'package:thunder/shared/cross_posts.dart';
import 'package:thunder/shared/full_name_widgets.dart';
import 'package:thunder/shared/input_dialogs.dart';
import 'package:thunder/shared/language_selector.dart';
import 'package:thunder/shared/link_preview_card.dart';
import 'package:thunder/shared/media/media_view.dart';
import 'package:thunder/shared/snackbar.dart';
import 'package:thunder/user/utils/restore_user.dart';
import 'package:thunder/user/widgets/user_selector.dart';
Expand Down Expand Up @@ -538,23 +540,22 @@ class _CreatePostPageState extends State<CreatePostPage> {
SizedBox(height: url.isNotEmpty ? 10 : 5),
Visibility(
visible: url.isNotEmpty,
child: LinkPreviewCard(
hideNsfw: false,
scrapeMissingPreviews: false,
originURL: url,
mediaURL: isImageUrl(url)
? url
: customThumbnail?.isNotEmpty == true && isImageUrl(customThumbnail!)
? customThumbnail
: null,
mediaHeight: null,
mediaWidth: null,
child: MediaView(
showFullHeightImages: false,
edgeToEdgeImages: false,
viewMode: ViewMode.comfortable,
postId: null,
markPostReadOnMediaView: false,
isUserLoggedIn: true,
media: Media(
originalUrl: url,
mediaUrl: isImageUrl(url)
? url
: customThumbnail?.isNotEmpty == true && isImageUrl(customThumbnail!)
? customThumbnail
: null,
nsfw: isNSFW,
mediaType: MediaType.link,
),
),
),
if (crossPosts.isNotEmpty && widget.postView == null) const SizedBox(height: 6),
Expand Down
3 changes: 1 addition & 2 deletions lib/community/widgets/post_card_view_comfortable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ class PostCardViewComfortable extends StatelessWidget {
final Color? readColor = indicateRead && postViewMedia.postView.read ? theme.textTheme.bodyMedium?.color?.withValues(alpha: 0.45) : theme.textTheme.bodyMedium?.color?.withValues(alpha: 0.90);

Widget mediaView = MediaView(
scrapeMissingPreviews: state.scrapeMissingPreviews,
postViewMedia: postViewMedia,
media: postViewMedia.media.first,
showFullHeightImages: showFullHeightImages,
hideNsfwPreviews: hideNsfwPreviews,
hideThumbnails: hideThumbnails,
Expand Down
3 changes: 1 addition & 2 deletions lib/community/widgets/post_card_view_compact.dart
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,7 @@ class ThumbnailPreview extends StatelessWidget {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4),
child: MediaView(
scrapeMissingPreviews: state.scrapeMissingPreviews,
postViewMedia: postViewMedia,
media: postViewMedia.media.first,
showFullHeightImages: false,
hideNsfwPreviews: hideNsfwPreviews,
markPostReadOnMediaView: markPostReadOnMediaView,
Expand Down
4 changes: 4 additions & 0 deletions lib/core/models/media.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Media {
this.originalUrl,
this.width,
this.height,
this.nsfw = false,
required this.mediaType,
});

Expand All @@ -27,6 +28,9 @@ class Media {
/// The height of the media source
double? height;

/// Indicates whether the media is NSFW
bool nsfw;

/// Indicates the type of media it holds
MediaType mediaType;

Expand Down
50 changes: 27 additions & 23 deletions lib/post/utils/post.dart
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,13 @@ Future<PostViewMedia> parsePostView(PostView postView, bool fetchImageDimensions
mediaType = MediaType.text;
}

Media media = Media(mediaType: mediaType, originalUrl: url);
Media media = Media(mediaType: mediaType, originalUrl: url, nsfw: postView.post.nsfw);

if (media.mediaType == MediaType.text) {
media.altText = postView.post.body;
} else if (media.mediaType == MediaType.image) {
media.altText = postView.post.altText;
}

// Determine the thumbnail url
if (thumbnailUrl != null && thumbnailUrl.isNotEmpty) {
Expand All @@ -382,34 +388,32 @@ Future<PostViewMedia> parsePostView(PostView postView, bool fetchImageDimensions
media.mediaUrl = videoUrl;
}

if (fetchImageDimensions && media.thumbnailUrl != null) {
Size result = Size(MediaQuery.of(GlobalContext.context).size.width, 200);

bool useImageMetadata = LemmyClient.instance.supportsFeature(LemmyFeature.imageDimension);
Size result = Size(MediaQuery.of(GlobalContext.context).size.width, 200);
bool useImageMetadata = LemmyClient.instance.supportsFeature(LemmyFeature.imageDimension);

// Finally, check to see if we need to fetch the image dimensions for the thumbnail url
if (useImageMetadata && postView.imageDetails != null) {
debugPrint('Using image metadata for ${media.thumbnailUrl ?? media.mediaUrl}');
result = Size(postView.imageDetails!.width.toDouble(), postView.imageDetails!.height.toDouble());
} else {
// If the instance does not contain image metadata, we'll do some additional checks
try {
SharedPreferences prefs = (await UserPreferences.instance).sharedPreferences;
int imageDimensionTimeout = prefs.getInt(LocalSettings.imageDimensionTimeout.name) ?? 2;
// Check to see if there is available image metadata
if (useImageMetadata && postView.imageDetails != null) {
debugPrint('Using image metadata for ${media.thumbnailUrl ?? media.mediaUrl}');
result = Size(postView.imageDetails!.width.toDouble(), postView.imageDetails!.height.toDouble());
}

result = await retrieveImageDimensions(imageUrl: media.thumbnailUrl ?? media.mediaUrl).timeout(Duration(seconds: imageDimensionTimeout));
} catch (e) {
debugPrint('${media.thumbnailUrl ?? media.originalUrl} - $e: Falling back to default image size');
}
if (fetchImageDimensions && media.thumbnailUrl != null) {
// If the instance does not contain image metadata, we'll do some additional checks
try {
SharedPreferences prefs = (await UserPreferences.instance).sharedPreferences;
int imageDimensionTimeout = prefs.getInt(LocalSettings.imageDimensionTimeout.name) ?? 2;

result = await retrieveImageDimensions(imageUrl: media.thumbnailUrl ?? media.mediaUrl).timeout(Duration(seconds: imageDimensionTimeout));
} catch (e) {
debugPrint('${media.thumbnailUrl ?? media.originalUrl} - $e: Falling back to default image size');
}
}

Size scaledSize = MediaExtension.getScaledMediaSize(width: result.width, height: result.height, offset: edgeToEdgeImages ? 0 : 24, tabletMode: tabletMode);
Size scaledSize = MediaExtension.getScaledMediaSize(width: result.width, height: result.height, offset: edgeToEdgeImages ? 0 : 24, tabletMode: tabletMode);

media.width = scaledSize.width;
media.height = scaledSize.height;
}
media.width = scaledSize.width;
media.height = scaledSize.height;

media.altText = postView.post.altText;
mediaList.add(media);

return PostViewMedia(postView: postView, media: mediaList);
Expand Down
9 changes: 4 additions & 5 deletions lib/post/widgets/post_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ class _PostSubviewState extends State<PostSubview> with SingleTickerProviderStat
],
),
),
if (thunderState.postBodyViewType != PostBodyViewType.condensed)
if (thunderState.postBodyViewType != PostBodyViewType.condensed && postViewMedia.media.first.mediaType != MediaType.text)
Expandable(
controller: expandableController,
collapsed: Container(),
expanded: MediaView(
scrapeMissingPreviews: scrapeMissingPreviews,
postViewMedia: widget.postViewMedia,
viewMode: ViewMode.comfortable,
media: postViewMedia.media.first,
showFullHeightImages: true,
allowUnconstrainedImageHeight: true,
hideNsfwPreviews: hideNsfwPreviews,
Expand Down Expand Up @@ -388,8 +388,7 @@ class _PostSubviewState extends State<PostSubview> with SingleTickerProviderStat
vertical: 4,
),
child: MediaView(
scrapeMissingPreviews: thunderState.scrapeMissingPreviews,
postViewMedia: postViewMedia,
media: postViewMedia.media.first,
showFullHeightImages: false,
hideNsfwPreviews: hideNsfwPreviews,
markPostReadOnMediaView: markPostReadOnMediaView,
Expand Down
14 changes: 9 additions & 5 deletions lib/shared/image/image_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,15 @@ class _ImagePreviewState extends State<ImagePreview> with SingleTickerProviderSt
},
);

return ImageFiltered(
enabled: widget.blur == true,
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
child: image,
);
if (widget.blur == true) {
return ImageFiltered(
enabled: true,
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
child: image,
);
}

return image;
}

IconData _getErrorIcon(MediaType? mediaType) {
Expand Down
Loading

0 comments on commit 25c0f45

Please sign in to comment.