diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index aab172fd..36102ecb 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -1002,5 +1002,17 @@ "toggleFilters": "Toggle filters", "notableDayNext": "{} is in", "expandPoll": "Expand Poll", - "collapsePoll": "Collapse Poll" + "collapsePoll": "Collapse Poll", + "embedView": "Embed View", + "embedUri": "Embed URI", + "aspectRatio": "Aspect Ratio", + "renderer": "Renderer", + "addEmbed": "Add Embed", + "editEmbed": "Edit Embed", + "deleteEmbed": "Delete Embed", + "deleteEmbedConfirm": "Are you sure you want to delete this embed?", + "currentEmbed": "Current Embed", + "noEmbed": "No embed yet", + "save": "Save", + "webView": "Web View" } diff --git a/lib/models/post.dart b/lib/models/post.dart index 17b4615e..95f0f65c 100644 --- a/lib/models/post.dart +++ b/lib/models/post.dart @@ -22,6 +22,7 @@ sealed class SnPost with _$SnPost { String? slug, @Default(0) int type, Map? meta, + SnPostEmbedView? embedView, @Default(0) int viewsUnique, @Default(0) int viewsTotal, @Default(0) int upvotes, @@ -105,3 +106,20 @@ const Map kReactionTemplates = { 'pray': ReactInfo(icon: '🙏', attitude: 0), 'heart': ReactInfo(icon: '❤️', attitude: 0), }; + +enum PostEmbedViewRenderer { + @JsonValue(0) + webView, +} + +@freezed +sealed class SnPostEmbedView with _$SnPostEmbedView { + const factory SnPostEmbedView({ + required String uri, + double? aspectRatio, + @Default(PostEmbedViewRenderer.webView) PostEmbedViewRenderer renderer, + }) = _SnPostEmbedView; + + factory SnPostEmbedView.fromJson(Map json) => + _$SnPostEmbedViewFromJson(json); +} diff --git a/lib/models/post.freezed.dart b/lib/models/post.freezed.dart index 6ba78a32..e4de851c 100644 --- a/lib/models/post.freezed.dart +++ b/lib/models/post.freezed.dart @@ -15,7 +15,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$SnPost { - String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List get attachments; SnPublisher get publisher; Map get reactionsCount; Map get reactionsMade; List get reactions; List get tags; List get categories; List get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated; + String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map? get meta; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List get attachments; SnPublisher get publisher; Map get reactionsCount; Map get reactionsMade; List get reactions; List get tags; List get categories; List get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated; /// Create a copy of SnPost /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -28,16 +28,16 @@ $SnPostCopyWith get copyWith => _$SnPostCopyWithImpl(this as SnP @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]); +int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]); @override String toString() { - return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; + return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; } @@ -48,11 +48,11 @@ abstract mixin class $SnPostCopyWith<$Res> { factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl; @useResult $Res call({ - String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated + String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated }); -$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher; +$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher; } /// @nodoc @@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res> /// Create a copy of SnPost /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable @@ -78,7 +78,8 @@ as int,content: freezed == content ? _self.content : content // ignore: cast_nul as String?,slug: freezed == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable -as Map?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable +as Map?,embedView: freezed == embedView ? _self.embedView : embedView // ignore: cast_nullable_to_non_nullable +as SnPostEmbedView?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore: cast_nullable_to_non_nullable as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable @@ -111,6 +112,18 @@ as bool, /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') +$SnPostEmbedViewCopyWith<$Res>? get embedView { + if (_self.embedView == null) { + return null; + } + + return $SnPostEmbedViewCopyWith<$Res>(_self.embedView!, (value) { + return _then(_self.copyWith(embedView: value)); + }); +}/// Create a copy of SnPost +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') $SnPostCopyWith<$Res>? get threadedPost { if (_self.threadedPost == null) { return null; @@ -243,10 +256,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _SnPost() when $default != null: -return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: +return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: return orElse(); } @@ -264,10 +277,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this; switch (_that) { case _SnPost(): -return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);} +return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);} } /// A variant of `when` that fallback to returning `null` /// @@ -281,10 +294,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this; switch (_that) { case _SnPost() when $default != null: -return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: +return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: return null; } @@ -296,7 +309,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit @JsonSerializable() class _SnPost implements SnPost { - const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final List attachments = const [], required this.publisher, final Map reactionsCount = const {}, final Map reactionsMade = const {}, final List reactions = const [], final List tags = const [], final List categories = const [], final List collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; + const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map? meta, this.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final List attachments = const [], required this.publisher, final Map reactionsCount = const {}, final Map reactionsMade = const {}, final List reactions = const [], final List tags = const [], final List categories = const [], final List collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; factory _SnPost.fromJson(Map json) => _$SnPostFromJson(json); @override final String id; @@ -318,6 +331,7 @@ class _SnPost implements SnPost { return EqualUnmodifiableMapView(value); } +@override final SnPostEmbedView? embedView; @override@JsonKey() final int viewsUnique; @override@JsonKey() final int viewsTotal; @override@JsonKey() final int upvotes; @@ -400,16 +414,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]); +int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]); @override String toString() { - return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; + return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; } @@ -420,11 +434,11 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> { factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl; @override @useResult $Res call({ - String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated + String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List attachments, SnPublisher publisher, Map reactionsCount, Map reactionsMade, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated }); -@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res> get publisher; +@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res> get publisher; } /// @nodoc @@ -437,7 +451,7 @@ class __$SnPostCopyWithImpl<$Res> /// Create a copy of SnPost /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { return _then(_SnPost( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable @@ -450,7 +464,8 @@ as int,content: freezed == content ? _self.content : content // ignore: cast_nul as String?,slug: freezed == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,meta: freezed == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable -as Map?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable +as Map?,embedView: freezed == embedView ? _self.embedView : embedView // ignore: cast_nullable_to_non_nullable +as SnPostEmbedView?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore: cast_nullable_to_non_nullable as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable @@ -484,6 +499,18 @@ as bool, /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') +$SnPostEmbedViewCopyWith<$Res>? get embedView { + if (_self.embedView == null) { + return null; + } + + return $SnPostEmbedViewCopyWith<$Res>(_self.embedView!, (value) { + return _then(_self.copyWith(embedView: value)); + }); +}/// Create a copy of SnPost +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') $SnPostCopyWith<$Res>? get threadedPost { if (_self.threadedPost == null) { return null; @@ -1324,6 +1351,269 @@ as int, } +} + + +/// @nodoc +mixin _$SnPostEmbedView { + + String get uri; double? get aspectRatio; PostEmbedViewRenderer get renderer; +/// Create a copy of SnPostEmbedView +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SnPostEmbedViewCopyWith get copyWith => _$SnPostEmbedViewCopyWithImpl(this as SnPostEmbedView, _$identity); + + /// Serializes this SnPostEmbedView to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostEmbedView&&(identical(other.uri, uri) || other.uri == uri)&&(identical(other.aspectRatio, aspectRatio) || other.aspectRatio == aspectRatio)&&(identical(other.renderer, renderer) || other.renderer == renderer)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,uri,aspectRatio,renderer); + +@override +String toString() { + return 'SnPostEmbedView(uri: $uri, aspectRatio: $aspectRatio, renderer: $renderer)'; +} + + +} + +/// @nodoc +abstract mixin class $SnPostEmbedViewCopyWith<$Res> { + factory $SnPostEmbedViewCopyWith(SnPostEmbedView value, $Res Function(SnPostEmbedView) _then) = _$SnPostEmbedViewCopyWithImpl; +@useResult +$Res call({ + String uri, double? aspectRatio, PostEmbedViewRenderer renderer +}); + + + + +} +/// @nodoc +class _$SnPostEmbedViewCopyWithImpl<$Res> + implements $SnPostEmbedViewCopyWith<$Res> { + _$SnPostEmbedViewCopyWithImpl(this._self, this._then); + + final SnPostEmbedView _self; + final $Res Function(SnPostEmbedView) _then; + +/// Create a copy of SnPostEmbedView +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? uri = null,Object? aspectRatio = freezed,Object? renderer = null,}) { + return _then(_self.copyWith( +uri: null == uri ? _self.uri : uri // ignore: cast_nullable_to_non_nullable +as String,aspectRatio: freezed == aspectRatio ? _self.aspectRatio : aspectRatio // ignore: cast_nullable_to_non_nullable +as double?,renderer: null == renderer ? _self.renderer : renderer // ignore: cast_nullable_to_non_nullable +as PostEmbedViewRenderer, + )); +} + +} + + +/// Adds pattern-matching-related methods to [SnPostEmbedView]. +extension SnPostEmbedViewPatterns on SnPostEmbedView { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _SnPostEmbedView value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _SnPostEmbedView() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _SnPostEmbedView value) $default,){ +final _that = this; +switch (_that) { +case _SnPostEmbedView(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SnPostEmbedView value)? $default,){ +final _that = this; +switch (_that) { +case _SnPostEmbedView() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String uri, double? aspectRatio, PostEmbedViewRenderer renderer)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SnPostEmbedView() when $default != null: +return $default(_that.uri,_that.aspectRatio,_that.renderer);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String uri, double? aspectRatio, PostEmbedViewRenderer renderer) $default,) {final _that = this; +switch (_that) { +case _SnPostEmbedView(): +return $default(_that.uri,_that.aspectRatio,_that.renderer);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String uri, double? aspectRatio, PostEmbedViewRenderer renderer)? $default,) {final _that = this; +switch (_that) { +case _SnPostEmbedView() when $default != null: +return $default(_that.uri,_that.aspectRatio,_that.renderer);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _SnPostEmbedView implements SnPostEmbedView { + const _SnPostEmbedView({required this.uri, this.aspectRatio, this.renderer = PostEmbedViewRenderer.webView}); + factory _SnPostEmbedView.fromJson(Map json) => _$SnPostEmbedViewFromJson(json); + +@override final String uri; +@override final double? aspectRatio; +@override@JsonKey() final PostEmbedViewRenderer renderer; + +/// Create a copy of SnPostEmbedView +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SnPostEmbedViewCopyWith<_SnPostEmbedView> get copyWith => __$SnPostEmbedViewCopyWithImpl<_SnPostEmbedView>(this, _$identity); + +@override +Map toJson() { + return _$SnPostEmbedViewToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostEmbedView&&(identical(other.uri, uri) || other.uri == uri)&&(identical(other.aspectRatio, aspectRatio) || other.aspectRatio == aspectRatio)&&(identical(other.renderer, renderer) || other.renderer == renderer)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,uri,aspectRatio,renderer); + +@override +String toString() { + return 'SnPostEmbedView(uri: $uri, aspectRatio: $aspectRatio, renderer: $renderer)'; +} + + +} + +/// @nodoc +abstract mixin class _$SnPostEmbedViewCopyWith<$Res> implements $SnPostEmbedViewCopyWith<$Res> { + factory _$SnPostEmbedViewCopyWith(_SnPostEmbedView value, $Res Function(_SnPostEmbedView) _then) = __$SnPostEmbedViewCopyWithImpl; +@override @useResult +$Res call({ + String uri, double? aspectRatio, PostEmbedViewRenderer renderer +}); + + + + +} +/// @nodoc +class __$SnPostEmbedViewCopyWithImpl<$Res> + implements _$SnPostEmbedViewCopyWith<$Res> { + __$SnPostEmbedViewCopyWithImpl(this._self, this._then); + + final _SnPostEmbedView _self; + final $Res Function(_SnPostEmbedView) _then; + +/// Create a copy of SnPostEmbedView +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? uri = null,Object? aspectRatio = freezed,Object? renderer = null,}) { + return _then(_SnPostEmbedView( +uri: null == uri ? _self.uri : uri // ignore: cast_nullable_to_non_nullable +as String,aspectRatio: freezed == aspectRatio ? _self.aspectRatio : aspectRatio // ignore: cast_nullable_to_non_nullable +as double?,renderer: null == renderer ? _self.renderer : renderer // ignore: cast_nullable_to_non_nullable +as PostEmbedViewRenderer, + )); +} + + } // dart format on diff --git a/lib/models/post.g.dart b/lib/models/post.g.dart index faa3294a..d18affd8 100644 --- a/lib/models/post.g.dart +++ b/lib/models/post.g.dart @@ -24,6 +24,12 @@ _SnPost _$SnPostFromJson(Map json) => _SnPost( slug: json['slug'] as String?, type: (json['type'] as num?)?.toInt() ?? 0, meta: json['meta'] as Map?, + embedView: + json['embed_view'] == null + ? null + : SnPostEmbedView.fromJson( + json['embed_view'] as Map, + ), viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0, viewsTotal: (json['views_total'] as num?)?.toInt() ?? 0, upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, @@ -105,6 +111,7 @@ Map _$SnPostToJson(_SnPost instance) => { 'slug': instance.slug, 'type': instance.type, 'meta': instance.meta, + 'embed_view': instance.embedView?.toJson(), 'views_unique': instance.viewsUnique, 'views_total': instance.viewsTotal, 'upvotes': instance.upvotes, @@ -166,3 +173,24 @@ Map _$SnSubscriptionStatusToJson( 'publisher_id': instance.publisherId, 'publisher_name': instance.publisherName, }; + +_SnPostEmbedView _$SnPostEmbedViewFromJson(Map json) => + _SnPostEmbedView( + uri: json['uri'] as String, + aspectRatio: (json['aspect_ratio'] as num?)?.toDouble(), + renderer: + $enumDecodeNullable( + _$PostEmbedViewRendererEnumMap, + json['renderer'], + ) ?? + PostEmbedViewRenderer.webView, + ); + +Map _$SnPostEmbedViewToJson(_SnPostEmbedView instance) => + { + 'uri': instance.uri, + 'aspect_ratio': instance.aspectRatio, + 'renderer': _$PostEmbedViewRendererEnumMap[instance.renderer]!, + }; + +const _$PostEmbedViewRendererEnumMap = {PostEmbedViewRenderer.webView: 0}; diff --git a/lib/screens/chat/room_detail.dart b/lib/screens/chat/room_detail.dart index 2862a5e8..cac061ce 100644 --- a/lib/screens/chat/room_detail.dart +++ b/lib/screens/chat/room_detail.dart @@ -727,7 +727,11 @@ class _ChatMemberListSheet extends HookConsumerWidget { children: [ Flexible(child: Text(member.account.nick)), if (member.status != null) - AccountStatusLabel(status: member.status!), + AccountStatusLabel( + status: member.status!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), if (member.joinedAt == null) const Icon(Symbols.pending_actions, size: 20), ], diff --git a/lib/screens/posts/post_search.dart b/lib/screens/posts/post_search.dart index 4796324e..19ff6253 100644 --- a/lib/screens/posts/post_search.dart +++ b/lib/screens/posts/post_search.dart @@ -277,8 +277,6 @@ class PostSearchScreen extends HookConsumerWidget { Text('pinned'.tr()), ], ), - // TODO: Add dropdown for type selection - // TODO: Add multi-select for categories and tags ], ), ), diff --git a/lib/screens/realm/realm_detail.dart b/lib/screens/realm/realm_detail.dart index 71304923..de57f731 100644 --- a/lib/screens/realm/realm_detail.dart +++ b/lib/screens/realm/realm_detail.dart @@ -668,7 +668,13 @@ class _RealmMemberListSheet extends HookConsumerWidget { title: Row( spacing: 6, children: [ - Flexible(child: Text(member.account!.nick)), + Flexible( + child: Text( + member.account!.nick, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), if (member.status != null) AccountStatusLabel(status: member.status!), if (member.joinedAt == null) diff --git a/lib/widgets/post/compose_embed_sheet.dart b/lib/widgets/post/compose_embed_sheet.dart new file mode 100644 index 00000000..8b6c12aa --- /dev/null +++ b/lib/widgets/post/compose_embed_sheet.dart @@ -0,0 +1,287 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:island/models/post.dart'; +import 'package:island/widgets/content/sheet.dart'; +import 'package:island/widgets/post/compose_shared.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:styled_widget/styled_widget.dart'; + +class ComposeEmbedSheet extends HookConsumerWidget { + final ComposeState state; + + const ComposeEmbedSheet({super.key, required this.state}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + // Listen to embed view changes + final currentEmbedView = useValueListenable(state.embedView); + + // Form state + final uriController = useTextEditingController(); + final aspectRatioController = useTextEditingController(); + final selectedRenderer = useState( + PostEmbedViewRenderer.webView, + ); + + void clearForm() { + uriController.clear(); + aspectRatioController.clear(); + selectedRenderer.value = PostEmbedViewRenderer.webView; + } + + // Populate form when embed view changes + useEffect(() { + if (currentEmbedView != null) { + uriController.text = currentEmbedView.uri; + aspectRatioController.text = + currentEmbedView.aspectRatio?.toString() ?? ''; + selectedRenderer.value = currentEmbedView.renderer; + } else { + clearForm(); + } + return null; + }, [currentEmbedView]); + + void saveEmbedView() { + final uri = uriController.text.trim(); + if (uri.isEmpty) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('embedUriRequired'.tr()))); + return; + } + + final aspectRatio = + aspectRatioController.text.trim().isNotEmpty + ? double.tryParse(aspectRatioController.text.trim()) + : null; + + final embedView = SnPostEmbedView( + uri: uri, + aspectRatio: aspectRatio, + renderer: selectedRenderer.value, + ); + + if (currentEmbedView != null) { + ComposeLogic.updateEmbedView(state, embedView); + } else { + ComposeLogic.setEmbedView(state, embedView); + } + } + + return SheetScaffold( + titleText: 'embedView'.tr(), + heightFactor: 0.7, + child: Column( + children: [ + // Header with save button when editing + if (currentEmbedView != null) + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + child: Row( + children: [ + Expanded( + child: Text( + 'editEmbed'.tr(), + style: theme.textTheme.titleMedium, + ), + ), + TextButton( + onPressed: saveEmbedView, + child: Text('save'.tr()), + ), + ], + ), + ), + + // Content area + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Form fields + TextField( + controller: uriController, + decoration: InputDecoration( + labelText: 'embedUri'.tr(), + hintText: 'https://example.com', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + keyboardType: TextInputType.url, + ), + const Gap(16), + TextField( + controller: aspectRatioController, + decoration: InputDecoration( + labelText: 'aspectRatio'.tr(), + hintText: '16/9 = 1.777', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + keyboardType: TextInputType.numberWithOptions( + decimal: true, + ), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$')), + ], + ), + const Gap(16), + DropdownButtonFormField2( + value: selectedRenderer.value, + decoration: InputDecoration( + labelText: 'renderer'.tr(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: + PostEmbedViewRenderer.values.map((renderer) { + return DropdownMenuItem( + value: renderer, + child: Text(renderer.name).tr(), + ); + }).toList(), + onChanged: (value) { + if (value != null) { + selectedRenderer.value = value; + } + }, + ), + + // Current embed view display (when exists) + if (currentEmbedView != null) ...[ + const Gap(32), + Text( + 'currentEmbed'.tr(), + style: theme.textTheme.titleMedium, + ).padding(horizontal: 4), + const Gap(8), + Card( + margin: EdgeInsets.zero, + color: Theme.of(context).colorScheme.surfaceContainerHigh, + child: Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 12, + top: 4, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + currentEmbedView.renderer == + PostEmbedViewRenderer.webView + ? Symbols.web + : Symbols.web, + color: colorScheme.primary, + ), + const Gap(12), + Expanded( + child: Text( + currentEmbedView.uri, + style: theme.textTheme.bodyMedium, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + IconButton( + icon: const Icon(Symbols.delete), + onPressed: () { + showDialog( + context: context, + builder: + (dialogContext) => AlertDialog( + title: Text('deleteEmbed').tr(), + content: + Text('deleteEmbedConfirm').tr(), + actions: [ + TextButton( + onPressed: + () => + Navigator.of( + dialogContext, + ).pop(), + child: Text('cancel'.tr()), + ), + TextButton( + onPressed: () { + ComposeLogic.deleteEmbedView( + state, + ); + clearForm(); + Navigator.of( + dialogContext, + ).pop(); + }, + style: TextButton.styleFrom( + foregroundColor: + colorScheme.error, + ), + child: Text('delete').tr(), + ), + ], + ), + ); + }, + tooltip: 'delete'.tr(), + color: colorScheme.error, + ), + ], + ), + const Gap(12), + Text( + 'aspectRatio'.tr(), + style: theme.textTheme.labelMedium?.copyWith( + color: colorScheme.onSurfaceVariant, + ), + ), + const Gap(4), + Text( + currentEmbedView.aspectRatio != null + ? currentEmbedView.aspectRatio! + .toStringAsFixed(2) + : 'notSet'.tr(), + style: theme.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ] else ...[ + // Save button for new embed + const Gap(16), + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: saveEmbedView, + icon: const Icon(Symbols.add), + label: Text('addEmbed'.tr()), + ), + ), + ], + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/post/compose_shared.dart b/lib/widgets/post/compose_shared.dart index 8e5253c2..0eaa45f4 100644 --- a/lib/widgets/post/compose_shared.dart +++ b/lib/widgets/post/compose_shared.dart @@ -37,6 +37,7 @@ class ComposeState { final ValueNotifier> categories; StringTagController tagsController; final ValueNotifier realm; + final ValueNotifier embedView; final String draftId; int postType; // Linked poll id for this compose session (nullable) @@ -56,6 +57,7 @@ class ComposeState { required this.tagsController, required this.categories, required this.realm, + required this.embedView, required this.draftId, this.postType = 0, String? pollId, @@ -120,6 +122,7 @@ class ComposeLogic { originalPost?.categories ?? [], ), realm: ValueNotifier(originalPost?.realm), + embedView: ValueNotifier(originalPost?.embedView), draftId: id, postType: postType, // initialize without poll by default @@ -151,6 +154,7 @@ class ComposeLogic { tagsController: tagsController, categories: ValueNotifier>([]), realm: ValueNotifier(null), + embedView: ValueNotifier(draft.embedView), draftId: draft.id, postType: postType, pollId: null, @@ -253,6 +257,7 @@ class ComposeLogic { tags: [], categories: [], collections: [], + embedView: state.embedView.value, createdAt: DateTime.now(), updatedAt: DateTime.now(), deletedAt: null, @@ -329,6 +334,7 @@ class ComposeLogic { tags: [], categories: [], collections: [], + embedView: state.embedView.value, createdAt: DateTime.now(), updatedAt: DateTime.now(), deletedAt: null, @@ -577,6 +583,18 @@ class ComposeLogic { ); } + static void setEmbedView(ComposeState state, SnPostEmbedView embedView) { + state.embedView.value = embedView; + } + + static void updateEmbedView(ComposeState state, SnPostEmbedView embedView) { + state.embedView.value = embedView; + } + + static void deleteEmbedView(ComposeState state) { + state.embedView.value = null; + } + static Future pickPoll( WidgetRef ref, ComposeState state, @@ -660,6 +678,8 @@ class ComposeLogic { 'categories': state.categories.value.map((e) => e.slug).toList(), if (state.realm.value != null) 'realm_id': state.realm.value?.id, if (state.pollId.value != null) 'poll_id': state.pollId.value, + if (state.embedView.value != null) + 'embed_view': state.embedView.value!.toJson(), }; // Send request @@ -753,6 +773,7 @@ class ComposeLogic { state.tagsController.dispose(); state.categories.dispose(); state.realm.dispose(); + state.embedView.dispose(); state.pollId.dispose(); } } diff --git a/lib/widgets/post/compose_toolbar.dart b/lib/widgets/post/compose_toolbar.dart index a2701391..6754ca82 100644 --- a/lib/widgets/post/compose_toolbar.dart +++ b/lib/widgets/post/compose_toolbar.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/post.dart'; import 'package:island/services/compose_storage_db.dart'; +import 'package:island/widgets/post/compose_embed_sheet.dart'; import 'package:island/widgets/post/compose_shared.dart'; import 'package:island/widgets/post/draft_manager.dart'; import 'package:material_symbols_icons/symbols.dart'; @@ -40,6 +41,14 @@ class ComposeToolbar extends HookConsumerWidget { ComposeLogic.pickPoll(ref, state, context); } + void showEmbedSheet() { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => ComposeEmbedSheet(state: state), + ); + } + void showDraftManager() { showModalBottomSheet( context: context, @@ -112,6 +121,25 @@ class ComposeToolbar extends HookConsumerWidget { ); }, ), + // Embed button with visual state when embed is present + ListenableBuilder( + listenable: state.embedView, + builder: (context, _) { + return IconButton( + onPressed: showEmbedSheet, + icon: const Icon(Symbols.web), + tooltip: 'embedView'.tr(), + color: colorScheme.primary, + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll( + state.embedView.value != null + ? colorScheme.primary.withOpacity(0.15) + : null, + ), + ), + ); + }, + ), const Spacer(), if (originalPost == null && state.isEmpty) IconButton(