From b31a9155446b62abc7b69078f47bb5717ca35a80 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 6 Aug 2025 14:57:42 +0800 Subject: [PATCH] :bug: Bug fixes --- lib/models/embed.dart | 19 -- lib/models/embed.freezed.dart | 284 --------------------------- lib/models/embed.g.dart | 30 --- lib/utils/mapping.dart | 30 +++ lib/widgets/chat/message_item.dart | 8 +- lib/widgets/content/cloud_files.dart | 1 - lib/widgets/content/embed/link.dart | 7 +- lib/widgets/poll/poll_submit.dart | 15 -- lib/widgets/post/compose_poll.dart | 4 +- lib/widgets/post/post_item.dart | 24 ++- pubspec.yaml | 2 +- 11 files changed, 55 insertions(+), 369 deletions(-) create mode 100644 lib/utils/mapping.dart diff --git a/lib/models/embed.dart b/lib/models/embed.dart index a919ee7..c694e06 100644 --- a/lib/models/embed.dart +++ b/lib/models/embed.dart @@ -3,25 +3,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'embed.freezed.dart'; part 'embed.g.dart'; -@freezed -sealed class SnEmbedLink with _$SnEmbedLink { - const factory SnEmbedLink({ - @JsonKey(name: 'Type') required String type, - @JsonKey(name: 'Url') required String url, - @JsonKey(name: 'Title') required String title, - @JsonKey(name: 'Description') required String? description, - @JsonKey(name: 'ImageUrl') required String? imageUrl, - @JsonKey(name: 'FaviconUrl') @Default("") String faviconUrl, - @JsonKey(name: 'SiteName') @Default("") String siteName, - @JsonKey(name: 'ContentType') required String? contentType, - @JsonKey(name: 'Author') required String? author, - @JsonKey(name: 'PublishedDate') required DateTime? publishedDate, - }) = _SnEmbedLink; - - factory SnEmbedLink.fromJson(Map json) => - _$SnEmbedLinkFromJson(json); -} - @freezed sealed class SnScrappedLink with _$SnScrappedLink { const factory SnScrappedLink({ diff --git a/lib/models/embed.freezed.dart b/lib/models/embed.freezed.dart index 23ee0ae..4af123f 100644 --- a/lib/models/embed.freezed.dart +++ b/lib/models/embed.freezed.dart @@ -12,290 +12,6 @@ part of 'embed.dart'; // dart format off T _$identity(T value) => value; -/// @nodoc -mixin _$SnEmbedLink { - -@JsonKey(name: 'Type') String get type;@JsonKey(name: 'Url') String get url;@JsonKey(name: 'Title') String get title;@JsonKey(name: 'Description') String? get description;@JsonKey(name: 'ImageUrl') String? get imageUrl;@JsonKey(name: 'FaviconUrl') String get faviconUrl;@JsonKey(name: 'SiteName') String get siteName;@JsonKey(name: 'ContentType') String? get contentType;@JsonKey(name: 'Author') String? get author;@JsonKey(name: 'PublishedDate') DateTime? get publishedDate; -/// Create a copy of SnEmbedLink -/// with the given fields replaced by the non-null parameter values. -@JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -$SnEmbedLinkCopyWith get copyWith => _$SnEmbedLinkCopyWithImpl(this as SnEmbedLink, _$identity); - - /// Serializes this SnEmbedLink to a JSON map. - Map toJson(); - - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnEmbedLink&&(identical(other.type, type) || other.type == type)&&(identical(other.url, url) || other.url == url)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.imageUrl, imageUrl) || other.imageUrl == imageUrl)&&(identical(other.faviconUrl, faviconUrl) || other.faviconUrl == faviconUrl)&&(identical(other.siteName, siteName) || other.siteName == siteName)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&(identical(other.author, author) || other.author == author)&&(identical(other.publishedDate, publishedDate) || other.publishedDate == publishedDate)); -} - -@JsonKey(includeFromJson: false, includeToJson: false) -@override -int get hashCode => Object.hash(runtimeType,type,url,title,description,imageUrl,faviconUrl,siteName,contentType,author,publishedDate); - -@override -String toString() { - return 'SnEmbedLink(type: $type, url: $url, title: $title, description: $description, imageUrl: $imageUrl, faviconUrl: $faviconUrl, siteName: $siteName, contentType: $contentType, author: $author, publishedDate: $publishedDate)'; -} - - -} - -/// @nodoc -abstract mixin class $SnEmbedLinkCopyWith<$Res> { - factory $SnEmbedLinkCopyWith(SnEmbedLink value, $Res Function(SnEmbedLink) _then) = _$SnEmbedLinkCopyWithImpl; -@useResult -$Res call({ -@JsonKey(name: 'Type') String type,@JsonKey(name: 'Url') String url,@JsonKey(name: 'Title') String title,@JsonKey(name: 'Description') String? description,@JsonKey(name: 'ImageUrl') String? imageUrl,@JsonKey(name: 'FaviconUrl') String faviconUrl,@JsonKey(name: 'SiteName') String siteName,@JsonKey(name: 'ContentType') String? contentType,@JsonKey(name: 'Author') String? author,@JsonKey(name: 'PublishedDate') DateTime? publishedDate -}); - - - - -} -/// @nodoc -class _$SnEmbedLinkCopyWithImpl<$Res> - implements $SnEmbedLinkCopyWith<$Res> { - _$SnEmbedLinkCopyWithImpl(this._self, this._then); - - final SnEmbedLink _self; - final $Res Function(SnEmbedLink) _then; - -/// Create a copy of SnEmbedLink -/// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) { - return _then(_self.copyWith( -type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable -as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable -as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable -as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable -as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable -as String?,faviconUrl: null == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable -as String,siteName: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable -as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable -as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable -as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable -as DateTime?, - )); -} - -} - - -/// Adds pattern-matching-related methods to [SnEmbedLink]. -extension SnEmbedLinkPatterns on SnEmbedLink { -/// 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( _SnEmbedLink value)? $default,{required TResult orElse(),}){ -final _that = this; -switch (_that) { -case _SnEmbedLink() 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( _SnEmbedLink value) $default,){ -final _that = this; -switch (_that) { -case _SnEmbedLink(): -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( _SnEmbedLink value)? $default,){ -final _that = this; -switch (_that) { -case _SnEmbedLink() 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(@JsonKey(name: 'Type') String type, @JsonKey(name: 'Url') String url, @JsonKey(name: 'Title') String title, @JsonKey(name: 'Description') String? description, @JsonKey(name: 'ImageUrl') String? imageUrl, @JsonKey(name: 'FaviconUrl') String faviconUrl, @JsonKey(name: 'SiteName') String siteName, @JsonKey(name: 'ContentType') String? contentType, @JsonKey(name: 'Author') String? author, @JsonKey(name: 'PublishedDate') DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this; -switch (_that) { -case _SnEmbedLink() when $default != null: -return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);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(@JsonKey(name: 'Type') String type, @JsonKey(name: 'Url') String url, @JsonKey(name: 'Title') String title, @JsonKey(name: 'Description') String? description, @JsonKey(name: 'ImageUrl') String? imageUrl, @JsonKey(name: 'FaviconUrl') String faviconUrl, @JsonKey(name: 'SiteName') String siteName, @JsonKey(name: 'ContentType') String? contentType, @JsonKey(name: 'Author') String? author, @JsonKey(name: 'PublishedDate') DateTime? publishedDate) $default,) {final _that = this; -switch (_that) { -case _SnEmbedLink(): -return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);} -} -/// 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(@JsonKey(name: 'Type') String type, @JsonKey(name: 'Url') String url, @JsonKey(name: 'Title') String title, @JsonKey(name: 'Description') String? description, @JsonKey(name: 'ImageUrl') String? imageUrl, @JsonKey(name: 'FaviconUrl') String faviconUrl, @JsonKey(name: 'SiteName') String siteName, @JsonKey(name: 'ContentType') String? contentType, @JsonKey(name: 'Author') String? author, @JsonKey(name: 'PublishedDate') DateTime? publishedDate)? $default,) {final _that = this; -switch (_that) { -case _SnEmbedLink() when $default != null: -return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _: - return null; - -} -} - -} - -/// @nodoc -@JsonSerializable() - -class _SnEmbedLink implements SnEmbedLink { - const _SnEmbedLink({@JsonKey(name: 'Type') required this.type, @JsonKey(name: 'Url') required this.url, @JsonKey(name: 'Title') required this.title, @JsonKey(name: 'Description') required this.description, @JsonKey(name: 'ImageUrl') required this.imageUrl, @JsonKey(name: 'FaviconUrl') this.faviconUrl = "", @JsonKey(name: 'SiteName') this.siteName = "", @JsonKey(name: 'ContentType') required this.contentType, @JsonKey(name: 'Author') required this.author, @JsonKey(name: 'PublishedDate') required this.publishedDate}); - factory _SnEmbedLink.fromJson(Map json) => _$SnEmbedLinkFromJson(json); - -@override@JsonKey(name: 'Type') final String type; -@override@JsonKey(name: 'Url') final String url; -@override@JsonKey(name: 'Title') final String title; -@override@JsonKey(name: 'Description') final String? description; -@override@JsonKey(name: 'ImageUrl') final String? imageUrl; -@override@JsonKey(name: 'FaviconUrl') final String faviconUrl; -@override@JsonKey(name: 'SiteName') final String siteName; -@override@JsonKey(name: 'ContentType') final String? contentType; -@override@JsonKey(name: 'Author') final String? author; -@override@JsonKey(name: 'PublishedDate') final DateTime? publishedDate; - -/// Create a copy of SnEmbedLink -/// with the given fields replaced by the non-null parameter values. -@override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -_$SnEmbedLinkCopyWith<_SnEmbedLink> get copyWith => __$SnEmbedLinkCopyWithImpl<_SnEmbedLink>(this, _$identity); - -@override -Map toJson() { - return _$SnEmbedLinkToJson(this, ); -} - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnEmbedLink&&(identical(other.type, type) || other.type == type)&&(identical(other.url, url) || other.url == url)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.imageUrl, imageUrl) || other.imageUrl == imageUrl)&&(identical(other.faviconUrl, faviconUrl) || other.faviconUrl == faviconUrl)&&(identical(other.siteName, siteName) || other.siteName == siteName)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&(identical(other.author, author) || other.author == author)&&(identical(other.publishedDate, publishedDate) || other.publishedDate == publishedDate)); -} - -@JsonKey(includeFromJson: false, includeToJson: false) -@override -int get hashCode => Object.hash(runtimeType,type,url,title,description,imageUrl,faviconUrl,siteName,contentType,author,publishedDate); - -@override -String toString() { - return 'SnEmbedLink(type: $type, url: $url, title: $title, description: $description, imageUrl: $imageUrl, faviconUrl: $faviconUrl, siteName: $siteName, contentType: $contentType, author: $author, publishedDate: $publishedDate)'; -} - - -} - -/// @nodoc -abstract mixin class _$SnEmbedLinkCopyWith<$Res> implements $SnEmbedLinkCopyWith<$Res> { - factory _$SnEmbedLinkCopyWith(_SnEmbedLink value, $Res Function(_SnEmbedLink) _then) = __$SnEmbedLinkCopyWithImpl; -@override @useResult -$Res call({ -@JsonKey(name: 'Type') String type,@JsonKey(name: 'Url') String url,@JsonKey(name: 'Title') String title,@JsonKey(name: 'Description') String? description,@JsonKey(name: 'ImageUrl') String? imageUrl,@JsonKey(name: 'FaviconUrl') String faviconUrl,@JsonKey(name: 'SiteName') String siteName,@JsonKey(name: 'ContentType') String? contentType,@JsonKey(name: 'Author') String? author,@JsonKey(name: 'PublishedDate') DateTime? publishedDate -}); - - - - -} -/// @nodoc -class __$SnEmbedLinkCopyWithImpl<$Res> - implements _$SnEmbedLinkCopyWith<$Res> { - __$SnEmbedLinkCopyWithImpl(this._self, this._then); - - final _SnEmbedLink _self; - final $Res Function(_SnEmbedLink) _then; - -/// Create a copy of SnEmbedLink -/// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) { - return _then(_SnEmbedLink( -type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable -as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable -as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable -as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable -as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable -as String?,faviconUrl: null == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable -as String,siteName: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable -as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable -as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable -as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable -as DateTime?, - )); -} - - -} - - /// @nodoc mixin _$SnScrappedLink { diff --git a/lib/models/embed.g.dart b/lib/models/embed.g.dart index 26aec5f..52e7c86 100644 --- a/lib/models/embed.g.dart +++ b/lib/models/embed.g.dart @@ -6,36 +6,6 @@ part of 'embed.dart'; // JsonSerializableGenerator // ************************************************************************** -_SnEmbedLink _$SnEmbedLinkFromJson(Map json) => _SnEmbedLink( - type: json['Type'] as String, - url: json['Url'] as String, - title: json['Title'] as String, - description: json['Description'] as String?, - imageUrl: json['ImageUrl'] as String?, - faviconUrl: json['FaviconUrl'] as String? ?? "", - siteName: json['SiteName'] as String? ?? "", - contentType: json['ContentType'] as String?, - author: json['Author'] as String?, - publishedDate: - json['PublishedDate'] == null - ? null - : DateTime.parse(json['PublishedDate'] as String), -); - -Map _$SnEmbedLinkToJson(_SnEmbedLink instance) => - { - 'Type': instance.type, - 'Url': instance.url, - 'Title': instance.title, - 'Description': instance.description, - 'ImageUrl': instance.imageUrl, - 'FaviconUrl': instance.faviconUrl, - 'SiteName': instance.siteName, - 'ContentType': instance.contentType, - 'Author': instance.author, - 'PublishedDate': instance.publishedDate?.toIso8601String(), - }; - _SnScrappedLink _$SnScrappedLinkFromJson(Map json) => _SnScrappedLink( type: json['type'] as String, diff --git a/lib/utils/mapping.dart b/lib/utils/mapping.dart new file mode 100644 index 0000000..da18bd9 --- /dev/null +++ b/lib/utils/mapping.dart @@ -0,0 +1,30 @@ +String _upperCamelToLowerSnake(String input) { + final regex = RegExp(r'(?<=[a-z0-9])([A-Z])'); + return input + .replaceAllMapped(regex, (match) => '_${match.group(0)}') + .toLowerCase(); +} + +Map convertMapKeysToSnakeCase(Map input) { + final result = {}; + + input.forEach((key, value) { + final newKey = _upperCamelToLowerSnake(key); + + if (value is Map) { + result[newKey] = convertMapKeysToSnakeCase(value); + } else if (value is List) { + result[newKey] = + value.map((item) { + if (item is Map) { + return convertMapKeysToSnakeCase(item); + } + return item; + }).toList(); + } else { + result[newKey] = value; + } + }); + + return result; +} diff --git a/lib/widgets/chat/message_item.dart b/lib/widgets/chat/message_item.dart index 0835e3a..ec30dd7 100644 --- a/lib/widgets/chat/message_item.dart +++ b/lib/widgets/chat/message_item.dart @@ -14,6 +14,7 @@ import 'package:island/models/embed.dart'; import 'package:island/pods/call.dart'; import 'package:island/pods/translate.dart'; import 'package:island/screens/chat/room.dart'; +import 'package:island/utils/mapping.dart'; import 'package:island/widgets/account/account_name.dart'; import 'package:island/widgets/account/account_pfc.dart'; import 'package:island/widgets/app_scaffold.dart'; @@ -292,12 +293,11 @@ class MessageItem extends HookConsumerWidget { ), if (remoteMessage.meta['embeds'] != null) ...((remoteMessage.meta['embeds'] as List) - .where((embed) => embed['Type'] == 'link') .map( - (embed) => SnEmbedLink.fromJson( - embed as Map, - ), + (embed) => convertMapKeysToSnakeCase(embed), ) + .where((embed) => embed['type'] == 'link') + .map((embed) => SnScrappedLink.fromJson(embed)) .map( (link) => LayoutBuilder( builder: (context, constraints) { diff --git a/lib/widgets/content/cloud_files.dart b/lib/widgets/content/cloud_files.dart index 299b3ed..4c74307 100644 --- a/lib/widgets/content/cloud_files.dart +++ b/lib/widgets/content/cloud_files.dart @@ -1,5 +1,4 @@ import 'dart:math' as math; -import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/content/embed/link.dart b/lib/widgets/content/embed/link.dart index e26f68d..7a63df6 100644 --- a/lib/widgets/content/embed/link.dart +++ b/lib/widgets/content/embed/link.dart @@ -6,7 +6,7 @@ import 'package:material_symbols_icons/symbols.dart'; import 'package:url_launcher/url_launcher.dart'; class EmbedLinkWidget extends StatelessWidget { - final SnEmbedLink link; + final SnScrappedLink link; final double? maxWidth; final EdgeInsetsGeometry? margin; @@ -116,7 +116,8 @@ class EmbedLinkWidget extends StatelessWidget { ], // Description - if (link.description != null && link.description!.isNotEmpty) ...[ + if (link.description != null && + link.description!.isNotEmpty) ...[ Text( link.description!, style: theme.textTheme.bodyMedium?.copyWith( @@ -191,7 +192,7 @@ class EmbedLinkWidget extends StatelessWidget { try { final now = DateTime.now(); final difference = now.difference(date); - + if (difference.inDays == 0) { return 'Today'; } else if (difference.inDays == 1) { diff --git a/lib/widgets/poll/poll_submit.dart b/lib/widgets/poll/poll_submit.dart index db1d9d4..3255e2f 100644 --- a/lib/widgets/poll/poll_submit.dart +++ b/lib/widgets/poll/poll_submit.dart @@ -3,21 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:island/models/poll.dart'; import 'package:island/pods/network.dart'; -/// A poll answering widget that shows one question at a time and collects answers. -/// -/// Usage: -/// PollSubmit( -/// poll: poll, -/// onSubmit: (answers) { -/// // answers is Map: questionId -> answer -/// // answer types by question: -/// // - singleChoice: String optionId -/// // - multipleChoice: List optionIds -/// // - yesNo: bool -/// // - rating: int (1..5) -/// // - freeText: String -/// }, -/// ) class PollSubmit extends ConsumerStatefulWidget { const PollSubmit({ super.key, diff --git a/lib/widgets/post/compose_poll.dart b/lib/widgets/post/compose_poll.dart index 35b200a..fe5eb09 100644 --- a/lib/widgets/post/compose_poll.dart +++ b/lib/widgets/post/compose_poll.dart @@ -189,8 +189,8 @@ class ComposePollSheet extends HookConsumerWidget { Widget? _buildPollSubtitle(SnPoll poll) { try { final SnPoll dyn = poll; - final List? options = dyn.questions; - if (options == null || options.isEmpty) return null; + final List options = dyn.questions; + if (options.isEmpty) return null; final preview = options.take(3).map((e) => e.title).join(' ยท '); if (preview.trim().isEmpty) return null; return Text(preview); diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index 84ffa90..53e8f41 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -547,7 +547,9 @@ class PostItem extends HookConsumerWidget { ...((item.meta!['embeds'] as List).map( (embedData) => switch (embedData['type']) { 'link' => EmbedLinkWidget( - link: SnEmbedLink.fromJson(embedData as Map), + link: SnScrappedLink.fromJson( + embedData as Map, + ), maxWidth: math.min( MediaQuery.of(context).size.width, kWideScreenWidth, @@ -877,38 +879,40 @@ class PostReplyPreview extends HookConsumerWidget { ), ], ) - : featuredReply!.when( + : (featuredReply!).map( data: - (value) => Row( + (data) => Row( crossAxisAlignment: CrossAxisAlignment.center, spacing: 8, children: [ ProfilePictureWidget( - file: value?.publisher.picture, + file: data.value?.publisher.picture, radius: 12, ).padding(top: 4), - if (value?.content?.isNotEmpty ?? false) + if (data.value?.content?.isNotEmpty ?? false) Expanded( - child: MarkdownTextContent(content: value!.content!), + child: MarkdownTextContent( + content: data.value!.content!, + ), ) else Expanded( child: Text( 'postHasAttachments', - ).plural(value?.attachments.length ?? 0), + ).plural(data.value?.attachments.length ?? 0), ), ], ), error: - (error, _) => Row( + (e) => Row( spacing: 8, children: [ const Icon(Symbols.close, size: 18), - Text(error.toString()), + Text(e.error.toString()), ], ), loading: - () => Row( + (_) => Row( spacing: 8, children: [ SizedBox( diff --git a/pubspec.yaml b/pubspec.yaml index 024fe6c..4f2fab8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 3.1.0+117 +version: 3.1.0+116 environment: sdk: ^3.7.2