feat(personalized_feed): added fixtures for new feed, added new feed parsing and layout, added webview player for post videos

This commit is contained in:
misha
2026-07-20 16:47:19 +03:00
parent bd2de07b8f
commit 48a984f5e9
23 changed files with 1330 additions and 903 deletions

View File

@@ -1,4 +1,5 @@
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/models/post_feed_pagination_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'feed_blog_post_model.freezed.dart';
@@ -20,6 +21,9 @@ abstract class FeedBlogPostModel with _$FeedBlogPostModel {
@JsonKey(name: "total_views") required int totalViews,
@JsonKey(name: "total_comments") required int totalComments,
@JsonKey(name: "was_liked_by_me") required bool wasLikedByMe,
@Default([]) List<FeedGalleryImage> images,
@JsonKey(name: "video_embed_url") String? videoEmbedUrl,
@JsonKey(name: "video_url_thumb") String? videoUrlThumb,
}) = _FeedBlogPostModel;
factory FeedBlogPostModel.fromJson(Map<String, Object?> json) => _$FeedBlogPostModelFromJson(json);

View File

@@ -0,0 +1,41 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
import 'package:eatvio_app/features/feed/models/post_feed_pagination_model.dart';
class PostFeedMapper {
static FeedBlogPostModel fromPostFeedItem(PostFeedItemModel item, {int? currentUserId}) {
return FeedBlogPostModel(
id: item.postId,
state: item.postState,
image: resolveMediaUrl(item.postImageUrl),
description: item.postTextMd ?? item.postShortDescription ?? '',
author: Author(
authorSlug: item.postAuthorDetails?.slug ?? '',
authorName: item.postAuthorName,
authorProfileIcon: resolveMediaUrl(item.postAuthorImageUrl),
authorIsMe: currentUserId != null && item.postAuthorId == currentUserId,
isEntitySubscribedByMe: item.isEntitySubscribedByMe,
),
videoUrl: '',
createdAt: item.postCreatedAt,
updatedAt: item.updatedAt,
title: item.postTitle,
totalLikes: item.postLikesCount,
totalViews: item.postViewsCount,
totalComments: item.postCommentsCount,
wasLikedByMe: item.postIsLikedByUser,
images: item.images,
videoEmbedUrl: item.videoEmbedUrl,
videoUrlThumb: item.videoUrlThumb,
);
}
static String resolveMediaUrl(String? url) {
if (url == null || url.isEmpty) return '';
if (url.startsWith('http://') || url.startsWith('https://')) return url;
if (url.startsWith('/')) return '${sl<AppConfig>().baseUrl}$url';
return '${sl<AppConfig>().baseUrl}/storage/$url';
}
}

View File

@@ -0,0 +1,93 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'post_feed_pagination_model.freezed.dart';
part 'post_feed_pagination_model.g.dart';
@freezed
abstract class PostFeedPaginationModel with _$PostFeedPaginationModel {
const factory PostFeedPaginationModel({
@JsonKey(name: 'data') required List<PostFeedItemModel> data,
required CursorLinks links,
required CursorMeta meta,
}) = _PostFeedPaginationModel;
factory PostFeedPaginationModel.fromJson(Map<String, Object?> json) => _$PostFeedPaginationModelFromJson(json);
}
@freezed
abstract class PostFeedItemModel with _$PostFeedItemModel {
const factory PostFeedItemModel({
required int id,
@JsonKey(name: 'post_id') required int postId,
@JsonKey(name: 'post_author_id') required int postAuthorId,
@JsonKey(name: 'post_author_name') required String postAuthorName,
@JsonKey(name: 'post_author_image_url') String? postAuthorImageUrl,
@JsonKey(name: 'post_author_profile_url') String? postAuthorProfileUrl,
@JsonKey(name: 'post_created_at', fromJson: parseDateTime) required DateTime postCreatedAt,
@JsonKey(name: 'post_title') required String postTitle,
@JsonKey(name: 'post_short_description') String? postShortDescription,
@JsonKey(name: 'post_text_md') String? postTextMd,
@JsonKey(name: 'post_image_url') String? postImageUrl,
@Default([]) List<FeedGalleryImage> images,
@JsonKey(name: 'video_embed_url') String? videoEmbedUrl,
@JsonKey(name: 'post_views_count') required int postViewsCount,
@JsonKey(name: 'post_likes_count') required int postLikesCount,
@JsonKey(name: 'post_comments_count') required int postCommentsCount,
@JsonKey(name: 'post_is_liked_by_user') required bool postIsLikedByUser,
@JsonKey(name: 'is_entity_subscribed_by_me') bool? isEntitySubscribedByMe,
@JsonKey(name: 'post_url') String? postUrl,
@JsonKey(name: 'post_state') required String postState,
@JsonKey(name: 'post_author_detailz') PostAuthorDetails? postAuthorDetails,
@JsonKey(name: "video_url_thumb") String? videoUrlThumb,
@JsonKey(name: 'created_at', fromJson: parseDateTime) required DateTime createdAt,
@JsonKey(name: 'updated_at', fromJson: parseDateTime) required DateTime updatedAt,
}) = _PostFeedItemModel;
factory PostFeedItemModel.fromJson(Map<String, Object?> json) => _$PostFeedItemModelFromJson(json);
}
@freezed
abstract class FeedGalleryImage with _$FeedGalleryImage {
const factory FeedGalleryImage({
required String url,
required String orientation,
}) = _FeedGalleryImage;
factory FeedGalleryImage.fromJson(Map<String, Object?> json) => _$FeedGalleryImageFromJson(json);
}
@freezed
abstract class PostAuthorDetails with _$PostAuthorDetails {
const factory PostAuthorDetails({
required String slug,
@JsonKey(name: 'is_consultant') required bool isConsultant,
}) = _PostAuthorDetails;
factory PostAuthorDetails.fromJson(Map<String, Object?> json) => _$PostAuthorDetailsFromJson(json);
}
@freezed
abstract class CursorLinks with _$CursorLinks {
const factory CursorLinks({
required String? first,
required String? last,
required String? prev,
required String? next,
}) = _CursorLinks;
factory CursorLinks.fromJson(Map<String, Object?> json) => _$CursorLinksFromJson(json);
}
@freezed
abstract class CursorMeta with _$CursorMeta {
const factory CursorMeta({
required String path,
@JsonKey(name: 'per_page') required int perPage,
@JsonKey(name: 'next_cursor') String? nextCursor,
@JsonKey(name: 'prev_cursor') String? prevCursor,
}) = _CursorMeta;
factory CursorMeta.fromJson(Map<String, Object?> json) => _$CursorMetaFromJson(json);
}
DateTime parseDateTime(String date) => DateTime.parse(date).toLocal();