From 8ed847d8705826db6b2b251cab03ab512ccb5097 Mon Sep 17 00:00:00 2001
From: LittleSheep <littlesheep.code@hotmail.com>
Date: Sun, 30 Mar 2025 15:31:02 +0800
Subject: [PATCH] :recycle: Use API Version 2 to load post

---
 lib/controllers/post_write_controller.dart    |  20 +-
 lib/providers/post.dart                       | 173 +++----------
 lib/screens/account/profile_edit.dart         |   2 +-
 .../account/publishers/publisher_edit.dart    |   2 +-
 lib/screens/chat.dart                         |   2 +-
 lib/types/post.dart                           |   5 +-
 lib/types/post.freezed.dart                   | 242 +++++++++++++-----
 lib/types/post.g.dart                         |  16 +-
 lib/widgets/post/post_item.dart               |  94 +++----
 9 files changed, 285 insertions(+), 271 deletions(-)

diff --git a/lib/controllers/post_write_controller.dart b/lib/controllers/post_write_controller.dart
index af39f01..e4b950e 100644
--- a/lib/controllers/post_write_controller.dart
+++ b/lib/controllers/post_write_controller.dart
@@ -241,7 +241,7 @@ class PostWriteController extends ChangeNotifier {
         contentController.text = post.body['content'] ?? '';
         aliasController.text = post.alias ?? '';
         rewardController.text = post.body['reward']?.toString() ?? '';
-        videoAttachment = post.preload?.video;
+        videoAttachment = SnAttachment.fromJson(post.body['video']);
         publishedAt = post.publishedAt;
         publishedUntil = post.publishedUntil;
         visibleUsers = List.from(post.visibleUsersList ?? [], growable: true);
@@ -252,17 +252,21 @@ class PostWriteController extends ChangeNotifier {
         categories =
             List.from(post.categories.map((ele) => ele.alias), growable: true);
         attachments.addAll(
-            post.preload?.attachments?.map((ele) => PostWriteMedia(ele)) ?? []);
-        poll = post.preload?.poll;
+          post.body['attachments']
+                  .where(SnAttachment.fromJson)
+                  ?.map(PostWriteMedia) ??
+              [],
+        );
+        poll = post.poll;
 
         editingDraft = post.isDraft;
 
-        if (post.preload?.thumbnail != null &&
-            (post.preload?.thumbnail?.rid.isNotEmpty ?? false)) {
-          thumbnail = PostWriteMedia(post.preload!.thumbnail);
+        if (post.body['thumbnail'] != null) {
+          thumbnail =
+              PostWriteMedia(SnAttachment.fromJson(post.body['thumbnail']));
         }
-        if (post.preload?.realm != null) {
-          realm = post.preload!.realm!;
+        if (post.realm != null) {
+          realm = post.realm!;
         }
 
         editingPost = post;
diff --git a/lib/providers/post.dart b/lib/providers/post.dart
index 3f0de16..d2c2867 100644
--- a/lib/providers/post.dart
+++ b/lib/providers/post.dart
@@ -1,144 +1,31 @@
+import 'package:dio/dio.dart';
 import 'package:flutter/material.dart';
 import 'package:provider/provider.dart';
-import 'package:surface/providers/sn_attachment.dart';
 import 'package:surface/providers/sn_network.dart';
-import 'package:surface/providers/sn_realm.dart';
-import 'package:surface/providers/user_directory.dart';
-import 'package:surface/types/poll.dart';
 import 'package:surface/types/post.dart';
-import 'package:surface/types/realm.dart';
 
 class SnPostContentProvider {
   late final SnNetworkProvider _sn;
-  late final UserDirectoryProvider _ud;
-  late final SnAttachmentProvider _attach;
-  late final SnRealmProvider _realm;
 
   SnPostContentProvider(BuildContext context) {
     _sn = context.read<SnNetworkProvider>();
-    _ud = context.read<UserDirectoryProvider>();
-    _attach = context.read<SnAttachmentProvider>();
-    _realm = context.read<SnRealmProvider>();
-  }
-
-  Future<SnPoll> _fetchPoll(int id) async {
-    final resp = await _sn.client.get('/cgi/co/polls/$id');
-    return SnPoll.fromJson(resp.data);
   }
 
   Future<List<SnPost>> _preloadRelatedDataInBatch(List<SnPost> out) async {
-    Set<String> rids = {};
-    Set<int> uids = {};
-    for (var i = 0; i < out.length; i++) {
-      rids.addAll(out[i].body['attachments']?.cast<String>() ?? []);
-      if (out[i].body['thumbnail'] != null) {
-        rids.add(out[i].body['thumbnail']);
-      }
-      if (out[i].body['video'] != null) {
-        rids.add(out[i].body['video']);
-      }
-      if (out[i].repostTo != null) {
-        out[i] = out[i].copyWith(
-          repostTo: await _preloadRelatedDataSingle(out[i].repostTo!),
-        );
-      }
-      if (out[i].publisher.type == 0) {
-        uids.add(out[i].publisher.accountId);
-      }
-    }
-
-    final attachments = await _attach.getMultiple(rids.toList());
-    for (var i = 0; i < out.length; i++) {
-      SnPoll? poll;
-      SnRealm? realm;
-      if (out[i].pollId != null) {
-        poll = await _fetchPoll(out[i].pollId!);
-      }
-      if (out[i].realmId != null) {
-        realm = await _realm.getRealm(out[i].realmId!);
-      }
-
-      out[i] = out[i].copyWith(
-        preload: SnPostPreload(
-          thumbnail: attachments
-              .where((ele) => ele?.rid == out[i].body['thumbnail'])
-              .firstOrNull,
-          attachments: attachments
-              .where((ele) =>
-                  out[i].body['attachments']?.contains(ele?.rid) ?? false)
-              .toList(),
-          video: attachments
-              .where((ele) => ele?.rid == out[i].body['video'])
-              .firstOrNull,
-          poll: poll,
-          realm: realm,
-        ),
-      );
-    }
-
-    uids.addAll(
-        attachments.where((ele) => ele != null).map((ele) => ele!.accountId));
-    await _ud.listAccount(uids);
-
     return out;
   }
 
   Future<SnPost> _preloadRelatedDataSingle(SnPost out) async {
-    Set<String> rids = {};
-    Set<int> uids = {};
-    rids.addAll(out.body['attachments']?.cast<String>() ?? []);
-    if (out.body['thumbnail'] != null) {
-      rids.add(out.body['thumbnail']);
-    }
-    if (out.body['video'] != null) {
-      rids.add(out.body['video']);
-    }
-    if (out.repostTo != null) {
-      out = out.copyWith(
-        repostTo: await _preloadRelatedDataSingle(out.repostTo!),
-      );
-    }
-    if (out.publisher.type == 0) {
-      uids.add(out.publisher.accountId);
-    }
-
-    final attachments = await _attach.getMultiple(rids.toList());
-
-    SnPoll? poll;
-    SnRealm? realm;
-    if (out.pollId != null) {
-      poll = await _fetchPoll(out.pollId!);
-    }
-    if (out.realmId != null) {
-      realm = await _realm.getRealm(out.realmId!);
-    }
-
-    out = out.copyWith(
-      preload: SnPostPreload(
-        thumbnail: attachments
-            .where((ele) => ele?.rid == out.body['thumbnail'])
-            .firstOrNull,
-        attachments: attachments
-            .where(
-                (ele) => out.body['attachments']?.contains(ele?.rid) ?? false)
-            .toList(),
-        video: attachments
-            .where((ele) => ele?.rid == out.body['video'])
-            .firstOrNull,
-        poll: poll,
-        realm: realm,
-      ),
-    );
-
-    uids.addAll(
-        attachments.where((ele) => ele != null).map((ele) => ele!.accountId));
-    await _ud.listAccount(uids);
-
     return out;
   }
 
   Future<List<SnPost>> listRecommendations() async {
-    final resp = await _sn.client.get('/cgi/co/recommendations');
+    final resp = await _sn.client.get(
+      '/cgi/co/recommendations',
+      options: Options(headers: {
+        'X-API-Version': '2',
+      }),
+    );
     final out = _preloadRelatedDataInBatch(
       List.from(resp.data.map((ele) => SnPost.fromJson(ele))),
     );
@@ -202,6 +89,9 @@ class SnPostContentProvider {
         if (realm != null) 'realm': realm,
         if (channel != null) 'channel': channel,
       },
+      options: Options(headers: {
+        'X-API-Version': '2',
+      }),
     );
     final List<SnPost> out = await _preloadRelatedDataInBatch(
       List.from(resp.data['data']?.map((e) => SnPost.fromJson(e)) ?? []),
@@ -215,11 +105,16 @@ class SnPostContentProvider {
     int take = 10,
     int offset = 0,
   }) async {
-    final resp = await _sn.client
-        .get('/cgi/co/posts/$parentId/replies', queryParameters: {
-      'take': take,
-      'offset': offset,
-    });
+    final resp = await _sn.client.get(
+      '/cgi/co/posts/$parentId/replies',
+      queryParameters: {
+        'take': take,
+        'offset': offset,
+      },
+      options: Options(headers: {
+        'X-API-Version': '2',
+      }),
+    );
     final List<SnPost> out = await _preloadRelatedDataInBatch(
       List.from(resp.data['data']?.map((e) => SnPost.fromJson(e)) ?? []),
     );
@@ -234,13 +129,20 @@ class SnPostContentProvider {
     Iterable<String>? tags,
     Iterable<String>? categories,
   }) async {
-    final resp = await _sn.client.get('/cgi/co/posts/search', queryParameters: {
-      'take': take,
-      'offset': offset,
-      'probe': searchTerm,
-      if (tags?.isNotEmpty ?? false) 'tags': tags!.join(','),
-      if (categories?.isNotEmpty ?? false) 'categories': categories!.join(','),
-    });
+    final resp = await _sn.client.get(
+      '/cgi/co/posts/search',
+      queryParameters: {
+        'take': take,
+        'offset': offset,
+        'probe': searchTerm,
+        if (tags?.isNotEmpty ?? false) 'tags': tags!.join(','),
+        if (categories?.isNotEmpty ?? false)
+          'categories': categories!.join(','),
+      },
+      options: Options(headers: {
+        'X-API-Version': '2',
+      }),
+    );
     final List<SnPost> out = await _preloadRelatedDataInBatch(
       List.from(resp.data['data']?.map((e) => SnPost.fromJson(e)) ?? []),
     );
@@ -249,7 +151,12 @@ class SnPostContentProvider {
   }
 
   Future<SnPost> getPost(dynamic id) async {
-    final resp = await _sn.client.get('/cgi/co/posts/$id');
+    final resp = await _sn.client.get(
+      '/cgi/co/posts/$id',
+      options: Options(headers: {
+        'X-API-Version': '2',
+      }),
+    );
     final out = _preloadRelatedDataSingle(
       SnPost.fromJson(resp.data),
     );
diff --git a/lib/screens/account/profile_edit.dart b/lib/screens/account/profile_edit.dart
index ba135a2..95289b6 100644
--- a/lib/screens/account/profile_edit.dart
+++ b/lib/screens/account/profile_edit.dart
@@ -263,7 +263,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
                     child: ClipRRect(
                       borderRadius: const BorderRadius.all(Radius.circular(8)),
                       child: AspectRatio(
-                        aspectRatio: 16 / 9,
+                        aspectRatio: 16 / 7,
                         child: Container(
                           color: Theme.of(context)
                               .colorScheme
diff --git a/lib/screens/account/publishers/publisher_edit.dart b/lib/screens/account/publishers/publisher_edit.dart
index 804b321..bbcfb4a 100644
--- a/lib/screens/account/publishers/publisher_edit.dart
+++ b/lib/screens/account/publishers/publisher_edit.dart
@@ -214,7 +214,7 @@ class _AccountPublisherEditScreenState
                     child: ClipRRect(
                       borderRadius: const BorderRadius.all(Radius.circular(8)),
                       child: AspectRatio(
-                        aspectRatio: 16 / 9,
+                        aspectRatio: 16 / 7,
                         child: Container(
                           color: Theme.of(context)
                               .colorScheme
diff --git a/lib/screens/chat.dart b/lib/screens/chat.dart
index 62714f8..fab7e68 100644
--- a/lib/screens/chat.dart
+++ b/lib/screens/chat.dart
@@ -389,7 +389,7 @@ class _ChatScreenState extends State<ChatScreen> {
                           children: [
                             if (_focusedRealm!.banner != null)
                               AspectRatio(
-                                aspectRatio: 16 / 9,
+                                aspectRatio: 16 / 7,
                                 child: AutoResizeUniversalImage(
                                   sn.getAttachmentUrl(
                                     _focusedRealm!.banner!,
diff --git a/lib/types/post.dart b/lib/types/post.dart
index c5b44d9..9428908 100644
--- a/lib/types/post.dart
+++ b/lib/types/post.dart
@@ -1,4 +1,5 @@
 import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:surface/types/account.dart';
 import 'package:surface/types/attachment.dart';
 import 'package:surface/types/poll.dart';
 import 'package:surface/types/realm.dart';
@@ -26,6 +27,7 @@ abstract class SnPost with _$SnPost {
     required int? replyId,
     required int? repostId,
     required int? realmId,
+    required SnRealm? realm,
     required SnPost? replyTo,
     required SnPost? repostTo,
     required List<int>? visibleUsersList,
@@ -43,9 +45,9 @@ abstract class SnPost with _$SnPost {
     @Default(0) int totalAggregatedViews,
     required int publisherId,
     required int? pollId,
+    required SnPoll? poll,
     required SnPublisher publisher,
     required SnMetric metric,
-    SnPostPreload? preload,
   }) = _SnPost;
 
   factory SnPost.fromJson(Map<String, Object?> json) => _$SnPostFromJson(json);
@@ -146,6 +148,7 @@ abstract class SnPublisher with _$SnPublisher {
     required int totalDownvote,
     required int? realmId,
     required int accountId,
+    required SnAccount? account,
   }) = _SnPublisher;
 
   factory SnPublisher.fromJson(Map<String, Object?> json) =>
diff --git a/lib/types/post.freezed.dart b/lib/types/post.freezed.dart
index 85e9366..29d3b44 100644
--- a/lib/types/post.freezed.dart
+++ b/lib/types/post.freezed.dart
@@ -30,6 +30,7 @@ mixin _$SnPost {
   int? get replyId;
   int? get repostId;
   int? get realmId;
+  SnRealm? get realm;
   SnPost? get replyTo;
   SnPost? get repostTo;
   List<int>? get visibleUsersList;
@@ -47,9 +48,9 @@ mixin _$SnPost {
   int get totalAggregatedViews;
   int get publisherId;
   int? get pollId;
+  SnPoll? get poll;
   SnPublisher get publisher;
   SnMetric get metric;
-  SnPostPreload? get preload;
 
   /// Create a copy of SnPost
   /// with the given fields replaced by the non-null parameter values.
@@ -88,6 +89,7 @@ mixin _$SnPost {
             (identical(other.repostId, repostId) ||
                 other.repostId == repostId) &&
             (identical(other.realmId, realmId) || other.realmId == realmId) &&
+            (identical(other.realm, realm) || other.realm == realm) &&
             (identical(other.replyTo, replyTo) || other.replyTo == replyTo) &&
             (identical(other.repostTo, repostTo) ||
                 other.repostTo == repostTo) &&
@@ -119,10 +121,10 @@ mixin _$SnPost {
             (identical(other.publisherId, publisherId) ||
                 other.publisherId == publisherId) &&
             (identical(other.pollId, pollId) || other.pollId == pollId) &&
+            (identical(other.poll, poll) || other.poll == poll) &&
             (identical(other.publisher, publisher) ||
                 other.publisher == publisher) &&
-            (identical(other.metric, metric) || other.metric == metric) &&
-            (identical(other.preload, preload) || other.preload == preload));
+            (identical(other.metric, metric) || other.metric == metric));
   }
 
   @JsonKey(includeFromJson: false, includeToJson: false)
@@ -144,6 +146,7 @@ mixin _$SnPost {
         replyId,
         repostId,
         realmId,
+        realm,
         replyTo,
         repostTo,
         const DeepCollectionEquality().hash(visibleUsersList),
@@ -161,14 +164,14 @@ mixin _$SnPost {
         totalAggregatedViews,
         publisherId,
         pollId,
+        poll,
         publisher,
-        metric,
-        preload
+        metric
       ]);
 
   @override
   String toString() {
-    return 'SnPost(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, body: $body, language: $language, alias: $alias, aliasPrefix: $aliasPrefix, tags: $tags, categories: $categories, replies: $replies, replyId: $replyId, repostId: $repostId, realmId: $realmId, replyTo: $replyTo, repostTo: $repostTo, visibleUsersList: $visibleUsersList, invisibleUsersList: $invisibleUsersList, visibility: $visibility, editedAt: $editedAt, pinnedAt: $pinnedAt, lockedAt: $lockedAt, isDraft: $isDraft, publishedAt: $publishedAt, publishedUntil: $publishedUntil, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, totalViews: $totalViews, totalAggregatedViews: $totalAggregatedViews, publisherId: $publisherId, pollId: $pollId, publisher: $publisher, metric: $metric, preload: $preload)';
+    return 'SnPost(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, body: $body, language: $language, alias: $alias, aliasPrefix: $aliasPrefix, tags: $tags, categories: $categories, replies: $replies, replyId: $replyId, repostId: $repostId, realmId: $realmId, realm: $realm, replyTo: $replyTo, repostTo: $repostTo, visibleUsersList: $visibleUsersList, invisibleUsersList: $invisibleUsersList, visibility: $visibility, editedAt: $editedAt, pinnedAt: $pinnedAt, lockedAt: $lockedAt, isDraft: $isDraft, publishedAt: $publishedAt, publishedUntil: $publishedUntil, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, totalViews: $totalViews, totalAggregatedViews: $totalAggregatedViews, publisherId: $publisherId, pollId: $pollId, poll: $poll, publisher: $publisher, metric: $metric)';
   }
 }
 
@@ -193,6 +196,7 @@ abstract mixin class $SnPostCopyWith<$Res> {
       int? replyId,
       int? repostId,
       int? realmId,
+      SnRealm? realm,
       SnPost? replyTo,
       SnPost? repostTo,
       List<int>? visibleUsersList,
@@ -210,15 +214,16 @@ abstract mixin class $SnPostCopyWith<$Res> {
       int totalAggregatedViews,
       int publisherId,
       int? pollId,
+      SnPoll? poll,
       SnPublisher publisher,
-      SnMetric metric,
-      SnPostPreload? preload});
+      SnMetric metric});
 
+  $SnRealmCopyWith<$Res>? get realm;
   $SnPostCopyWith<$Res>? get replyTo;
   $SnPostCopyWith<$Res>? get repostTo;
+  $SnPollCopyWith<$Res>? get poll;
   $SnPublisherCopyWith<$Res> get publisher;
   $SnMetricCopyWith<$Res> get metric;
-  $SnPostPreloadCopyWith<$Res>? get preload;
 }
 
 /// @nodoc
@@ -248,6 +253,7 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
     Object? replyId = freezed,
     Object? repostId = freezed,
     Object? realmId = freezed,
+    Object? realm = freezed,
     Object? replyTo = freezed,
     Object? repostTo = freezed,
     Object? visibleUsersList = freezed,
@@ -265,9 +271,9 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
     Object? totalAggregatedViews = null,
     Object? publisherId = null,
     Object? pollId = freezed,
+    Object? poll = freezed,
     Object? publisher = null,
     Object? metric = null,
-    Object? preload = freezed,
   }) {
     return _then(_self.copyWith(
       id: null == id
@@ -330,6 +336,10 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
           ? _self.realmId
           : realmId // ignore: cast_nullable_to_non_nullable
               as int?,
+      realm: freezed == realm
+          ? _self.realm
+          : realm // ignore: cast_nullable_to_non_nullable
+              as SnRealm?,
       replyTo: freezed == replyTo
           ? _self.replyTo
           : replyTo // ignore: cast_nullable_to_non_nullable
@@ -398,6 +408,10 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
           ? _self.pollId
           : pollId // ignore: cast_nullable_to_non_nullable
               as int?,
+      poll: freezed == poll
+          ? _self.poll
+          : poll // ignore: cast_nullable_to_non_nullable
+              as SnPoll?,
       publisher: null == publisher
           ? _self.publisher
           : publisher // ignore: cast_nullable_to_non_nullable
@@ -406,13 +420,23 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
           ? _self.metric
           : metric // ignore: cast_nullable_to_non_nullable
               as SnMetric,
-      preload: freezed == preload
-          ? _self.preload
-          : preload // ignore: cast_nullable_to_non_nullable
-              as SnPostPreload?,
     ));
   }
 
+  /// Create a copy of SnPost
+  /// with the given fields replaced by the non-null parameter values.
+  @override
+  @pragma('vm:prefer-inline')
+  $SnRealmCopyWith<$Res>? get realm {
+    if (_self.realm == null) {
+      return null;
+    }
+
+    return $SnRealmCopyWith<$Res>(_self.realm!, (value) {
+      return _then(_self.copyWith(realm: value));
+    });
+  }
+
   /// Create a copy of SnPost
   /// with the given fields replaced by the non-null parameter values.
   @override
@@ -441,6 +465,20 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
     });
   }
 
+  /// Create a copy of SnPost
+  /// with the given fields replaced by the non-null parameter values.
+  @override
+  @pragma('vm:prefer-inline')
+  $SnPollCopyWith<$Res>? get poll {
+    if (_self.poll == null) {
+      return null;
+    }
+
+    return $SnPollCopyWith<$Res>(_self.poll!, (value) {
+      return _then(_self.copyWith(poll: value));
+    });
+  }
+
   /// Create a copy of SnPost
   /// with the given fields replaced by the non-null parameter values.
   @override
@@ -460,20 +498,6 @@ class _$SnPostCopyWithImpl<$Res> implements $SnPostCopyWith<$Res> {
       return _then(_self.copyWith(metric: value));
     });
   }
-
-  /// Create a copy of SnPost
-  /// with the given fields replaced by the non-null parameter values.
-  @override
-  @pragma('vm:prefer-inline')
-  $SnPostPreloadCopyWith<$Res>? get preload {
-    if (_self.preload == null) {
-      return null;
-    }
-
-    return $SnPostPreloadCopyWith<$Res>(_self.preload!, (value) {
-      return _then(_self.copyWith(preload: value));
-    });
-  }
 }
 
 /// @nodoc
@@ -495,6 +519,7 @@ class _SnPost extends SnPost {
       required this.replyId,
       required this.repostId,
       required this.realmId,
+      required this.realm,
       required this.replyTo,
       required this.repostTo,
       required final List<int>? visibleUsersList,
@@ -512,9 +537,9 @@ class _SnPost extends SnPost {
       this.totalAggregatedViews = 0,
       required this.publisherId,
       required this.pollId,
+      required this.poll,
       required this.publisher,
-      required this.metric,
-      this.preload})
+      required this.metric})
       : _body = body,
         _tags = tags,
         _categories = categories,
@@ -583,6 +608,8 @@ class _SnPost extends SnPost {
   @override
   final int? realmId;
   @override
+  final SnRealm? realm;
+  @override
   final SnPost? replyTo;
   @override
   final SnPost? repostTo;
@@ -637,11 +664,11 @@ class _SnPost extends SnPost {
   @override
   final int? pollId;
   @override
+  final SnPoll? poll;
+  @override
   final SnPublisher publisher;
   @override
   final SnMetric metric;
-  @override
-  final SnPostPreload? preload;
 
   /// Create a copy of SnPost
   /// with the given fields replaced by the non-null parameter values.
@@ -685,6 +712,7 @@ class _SnPost extends SnPost {
             (identical(other.repostId, repostId) ||
                 other.repostId == repostId) &&
             (identical(other.realmId, realmId) || other.realmId == realmId) &&
+            (identical(other.realm, realm) || other.realm == realm) &&
             (identical(other.replyTo, replyTo) || other.replyTo == replyTo) &&
             (identical(other.repostTo, repostTo) ||
                 other.repostTo == repostTo) &&
@@ -716,10 +744,10 @@ class _SnPost extends SnPost {
             (identical(other.publisherId, publisherId) ||
                 other.publisherId == publisherId) &&
             (identical(other.pollId, pollId) || other.pollId == pollId) &&
+            (identical(other.poll, poll) || other.poll == poll) &&
             (identical(other.publisher, publisher) ||
                 other.publisher == publisher) &&
-            (identical(other.metric, metric) || other.metric == metric) &&
-            (identical(other.preload, preload) || other.preload == preload));
+            (identical(other.metric, metric) || other.metric == metric));
   }
 
   @JsonKey(includeFromJson: false, includeToJson: false)
@@ -741,6 +769,7 @@ class _SnPost extends SnPost {
         replyId,
         repostId,
         realmId,
+        realm,
         replyTo,
         repostTo,
         const DeepCollectionEquality().hash(_visibleUsersList),
@@ -758,14 +787,14 @@ class _SnPost extends SnPost {
         totalAggregatedViews,
         publisherId,
         pollId,
+        poll,
         publisher,
-        metric,
-        preload
+        metric
       ]);
 
   @override
   String toString() {
-    return 'SnPost(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, body: $body, language: $language, alias: $alias, aliasPrefix: $aliasPrefix, tags: $tags, categories: $categories, replies: $replies, replyId: $replyId, repostId: $repostId, realmId: $realmId, replyTo: $replyTo, repostTo: $repostTo, visibleUsersList: $visibleUsersList, invisibleUsersList: $invisibleUsersList, visibility: $visibility, editedAt: $editedAt, pinnedAt: $pinnedAt, lockedAt: $lockedAt, isDraft: $isDraft, publishedAt: $publishedAt, publishedUntil: $publishedUntil, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, totalViews: $totalViews, totalAggregatedViews: $totalAggregatedViews, publisherId: $publisherId, pollId: $pollId, publisher: $publisher, metric: $metric, preload: $preload)';
+    return 'SnPost(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, body: $body, language: $language, alias: $alias, aliasPrefix: $aliasPrefix, tags: $tags, categories: $categories, replies: $replies, replyId: $replyId, repostId: $repostId, realmId: $realmId, realm: $realm, replyTo: $replyTo, repostTo: $repostTo, visibleUsersList: $visibleUsersList, invisibleUsersList: $invisibleUsersList, visibility: $visibility, editedAt: $editedAt, pinnedAt: $pinnedAt, lockedAt: $lockedAt, isDraft: $isDraft, publishedAt: $publishedAt, publishedUntil: $publishedUntil, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, totalViews: $totalViews, totalAggregatedViews: $totalAggregatedViews, publisherId: $publisherId, pollId: $pollId, poll: $poll, publisher: $publisher, metric: $metric)';
   }
 }
 
@@ -791,6 +820,7 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
       int? replyId,
       int? repostId,
       int? realmId,
+      SnRealm? realm,
       SnPost? replyTo,
       SnPost? repostTo,
       List<int>? visibleUsersList,
@@ -808,20 +838,22 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
       int totalAggregatedViews,
       int publisherId,
       int? pollId,
+      SnPoll? poll,
       SnPublisher publisher,
-      SnMetric metric,
-      SnPostPreload? preload});
+      SnMetric metric});
 
+  @override
+  $SnRealmCopyWith<$Res>? get realm;
   @override
   $SnPostCopyWith<$Res>? get replyTo;
   @override
   $SnPostCopyWith<$Res>? get repostTo;
   @override
+  $SnPollCopyWith<$Res>? get poll;
+  @override
   $SnPublisherCopyWith<$Res> get publisher;
   @override
   $SnMetricCopyWith<$Res> get metric;
-  @override
-  $SnPostPreloadCopyWith<$Res>? get preload;
 }
 
 /// @nodoc
@@ -851,6 +883,7 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
     Object? replyId = freezed,
     Object? repostId = freezed,
     Object? realmId = freezed,
+    Object? realm = freezed,
     Object? replyTo = freezed,
     Object? repostTo = freezed,
     Object? visibleUsersList = freezed,
@@ -868,9 +901,9 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
     Object? totalAggregatedViews = null,
     Object? publisherId = null,
     Object? pollId = freezed,
+    Object? poll = freezed,
     Object? publisher = null,
     Object? metric = null,
-    Object? preload = freezed,
   }) {
     return _then(_SnPost(
       id: null == id
@@ -933,6 +966,10 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
           ? _self.realmId
           : realmId // ignore: cast_nullable_to_non_nullable
               as int?,
+      realm: freezed == realm
+          ? _self.realm
+          : realm // ignore: cast_nullable_to_non_nullable
+              as SnRealm?,
       replyTo: freezed == replyTo
           ? _self.replyTo
           : replyTo // ignore: cast_nullable_to_non_nullable
@@ -1001,6 +1038,10 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
           ? _self.pollId
           : pollId // ignore: cast_nullable_to_non_nullable
               as int?,
+      poll: freezed == poll
+          ? _self.poll
+          : poll // ignore: cast_nullable_to_non_nullable
+              as SnPoll?,
       publisher: null == publisher
           ? _self.publisher
           : publisher // ignore: cast_nullable_to_non_nullable
@@ -1009,13 +1050,23 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
           ? _self.metric
           : metric // ignore: cast_nullable_to_non_nullable
               as SnMetric,
-      preload: freezed == preload
-          ? _self.preload
-          : preload // ignore: cast_nullable_to_non_nullable
-              as SnPostPreload?,
     ));
   }
 
+  /// Create a copy of SnPost
+  /// with the given fields replaced by the non-null parameter values.
+  @override
+  @pragma('vm:prefer-inline')
+  $SnRealmCopyWith<$Res>? get realm {
+    if (_self.realm == null) {
+      return null;
+    }
+
+    return $SnRealmCopyWith<$Res>(_self.realm!, (value) {
+      return _then(_self.copyWith(realm: value));
+    });
+  }
+
   /// Create a copy of SnPost
   /// with the given fields replaced by the non-null parameter values.
   @override
@@ -1044,6 +1095,20 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
     });
   }
 
+  /// Create a copy of SnPost
+  /// with the given fields replaced by the non-null parameter values.
+  @override
+  @pragma('vm:prefer-inline')
+  $SnPollCopyWith<$Res>? get poll {
+    if (_self.poll == null) {
+      return null;
+    }
+
+    return $SnPollCopyWith<$Res>(_self.poll!, (value) {
+      return _then(_self.copyWith(poll: value));
+    });
+  }
+
   /// Create a copy of SnPost
   /// with the given fields replaced by the non-null parameter values.
   @override
@@ -1063,20 +1128,6 @@ class __$SnPostCopyWithImpl<$Res> implements _$SnPostCopyWith<$Res> {
       return _then(_self.copyWith(metric: value));
     });
   }
-
-  /// Create a copy of SnPost
-  /// with the given fields replaced by the non-null parameter values.
-  @override
-  @pragma('vm:prefer-inline')
-  $SnPostPreloadCopyWith<$Res>? get preload {
-    if (_self.preload == null) {
-      return null;
-    }
-
-    return $SnPostPreloadCopyWith<$Res>(_self.preload!, (value) {
-      return _then(_self.copyWith(preload: value));
-    });
-  }
 }
 
 /// @nodoc
@@ -2465,6 +2516,7 @@ mixin _$SnPublisher {
   int get totalDownvote;
   int? get realmId;
   int get accountId;
+  SnAccount? get account;
 
   /// Create a copy of SnPublisher
   /// with the given fields replaced by the non-null parameter values.
@@ -2501,7 +2553,8 @@ mixin _$SnPublisher {
                 other.totalDownvote == totalDownvote) &&
             (identical(other.realmId, realmId) || other.realmId == realmId) &&
             (identical(other.accountId, accountId) ||
-                other.accountId == accountId));
+                other.accountId == accountId) &&
+            (identical(other.account, account) || other.account == account));
   }
 
   @JsonKey(includeFromJson: false, includeToJson: false)
@@ -2521,11 +2574,12 @@ mixin _$SnPublisher {
       totalUpvote,
       totalDownvote,
       realmId,
-      accountId);
+      accountId,
+      account);
 
   @override
   String toString() {
-    return 'SnPublisher(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, name: $name, nick: $nick, description: $description, avatar: $avatar, banner: $banner, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, realmId: $realmId, accountId: $accountId)';
+    return 'SnPublisher(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, name: $name, nick: $nick, description: $description, avatar: $avatar, banner: $banner, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, realmId: $realmId, accountId: $accountId, account: $account)';
   }
 }
 
@@ -2549,7 +2603,10 @@ abstract mixin class $SnPublisherCopyWith<$Res> {
       int totalUpvote,
       int totalDownvote,
       int? realmId,
-      int accountId});
+      int accountId,
+      SnAccount? account});
+
+  $SnAccountCopyWith<$Res>? get account;
 }
 
 /// @nodoc
@@ -2578,6 +2635,7 @@ class _$SnPublisherCopyWithImpl<$Res> implements $SnPublisherCopyWith<$Res> {
     Object? totalDownvote = null,
     Object? realmId = freezed,
     Object? accountId = null,
+    Object? account = freezed,
   }) {
     return _then(_self.copyWith(
       id: null == id
@@ -2636,8 +2694,26 @@ class _$SnPublisherCopyWithImpl<$Res> implements $SnPublisherCopyWith<$Res> {
           ? _self.accountId
           : accountId // ignore: cast_nullable_to_non_nullable
               as int,
+      account: freezed == account
+          ? _self.account
+          : account // ignore: cast_nullable_to_non_nullable
+              as SnAccount?,
     ));
   }
+
+  /// Create a copy of SnPublisher
+  /// with the given fields replaced by the non-null parameter values.
+  @override
+  @pragma('vm:prefer-inline')
+  $SnAccountCopyWith<$Res>? get account {
+    if (_self.account == null) {
+      return null;
+    }
+
+    return $SnAccountCopyWith<$Res>(_self.account!, (value) {
+      return _then(_self.copyWith(account: value));
+    });
+  }
 }
 
 /// @nodoc
@@ -2657,7 +2733,8 @@ class _SnPublisher implements SnPublisher {
       required this.totalUpvote,
       required this.totalDownvote,
       required this.realmId,
-      required this.accountId});
+      required this.accountId,
+      required this.account});
   factory _SnPublisher.fromJson(Map<String, dynamic> json) =>
       _$SnPublisherFromJson(json);
 
@@ -2689,6 +2766,8 @@ class _SnPublisher implements SnPublisher {
   final int? realmId;
   @override
   final int accountId;
+  @override
+  final SnAccount? account;
 
   /// Create a copy of SnPublisher
   /// with the given fields replaced by the non-null parameter values.
@@ -2730,7 +2809,8 @@ class _SnPublisher implements SnPublisher {
                 other.totalDownvote == totalDownvote) &&
             (identical(other.realmId, realmId) || other.realmId == realmId) &&
             (identical(other.accountId, accountId) ||
-                other.accountId == accountId));
+                other.accountId == accountId) &&
+            (identical(other.account, account) || other.account == account));
   }
 
   @JsonKey(includeFromJson: false, includeToJson: false)
@@ -2750,11 +2830,12 @@ class _SnPublisher implements SnPublisher {
       totalUpvote,
       totalDownvote,
       realmId,
-      accountId);
+      accountId,
+      account);
 
   @override
   String toString() {
-    return 'SnPublisher(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, name: $name, nick: $nick, description: $description, avatar: $avatar, banner: $banner, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, realmId: $realmId, accountId: $accountId)';
+    return 'SnPublisher(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, name: $name, nick: $nick, description: $description, avatar: $avatar, banner: $banner, totalUpvote: $totalUpvote, totalDownvote: $totalDownvote, realmId: $realmId, accountId: $accountId, account: $account)';
   }
 }
 
@@ -2780,7 +2861,11 @@ abstract mixin class _$SnPublisherCopyWith<$Res>
       int totalUpvote,
       int totalDownvote,
       int? realmId,
-      int accountId});
+      int accountId,
+      SnAccount? account});
+
+  @override
+  $SnAccountCopyWith<$Res>? get account;
 }
 
 /// @nodoc
@@ -2809,6 +2894,7 @@ class __$SnPublisherCopyWithImpl<$Res> implements _$SnPublisherCopyWith<$Res> {
     Object? totalDownvote = null,
     Object? realmId = freezed,
     Object? accountId = null,
+    Object? account = freezed,
   }) {
     return _then(_SnPublisher(
       id: null == id
@@ -2867,8 +2953,26 @@ class __$SnPublisherCopyWithImpl<$Res> implements _$SnPublisherCopyWith<$Res> {
           ? _self.accountId
           : accountId // ignore: cast_nullable_to_non_nullable
               as int,
+      account: freezed == account
+          ? _self.account
+          : account // ignore: cast_nullable_to_non_nullable
+              as SnAccount?,
     ));
   }
+
+  /// Create a copy of SnPublisher
+  /// with the given fields replaced by the non-null parameter values.
+  @override
+  @pragma('vm:prefer-inline')
+  $SnAccountCopyWith<$Res>? get account {
+    if (_self.account == null) {
+      return null;
+    }
+
+    return $SnAccountCopyWith<$Res>(_self.account!, (value) {
+      return _then(_self.copyWith(account: value));
+    });
+  }
 }
 
 /// @nodoc
diff --git a/lib/types/post.g.dart b/lib/types/post.g.dart
index 8dc28c2..7d25773 100644
--- a/lib/types/post.g.dart
+++ b/lib/types/post.g.dart
@@ -32,6 +32,9 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
       replyId: (json['reply_id'] as num?)?.toInt(),
       repostId: (json['repost_id'] as num?)?.toInt(),
       realmId: (json['realm_id'] as num?)?.toInt(),
+      realm: json['realm'] == null
+          ? null
+          : SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
       replyTo: json['reply_to'] == null
           ? null
           : SnPost.fromJson(json['reply_to'] as Map<String, dynamic>),
@@ -68,12 +71,12 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
           (json['total_aggregated_views'] as num?)?.toInt() ?? 0,
       publisherId: (json['publisher_id'] as num).toInt(),
       pollId: (json['poll_id'] as num?)?.toInt(),
+      poll: json['poll'] == null
+          ? null
+          : SnPoll.fromJson(json['poll'] as Map<String, dynamic>),
       publisher:
           SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
       metric: SnMetric.fromJson(json['metric'] as Map<String, dynamic>),
-      preload: json['preload'] == null
-          ? null
-          : SnPostPreload.fromJson(json['preload'] as Map<String, dynamic>),
     );
 
 Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
@@ -92,6 +95,7 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
       'reply_id': instance.replyId,
       'repost_id': instance.repostId,
       'realm_id': instance.realmId,
+      'realm': instance.realm?.toJson(),
       'reply_to': instance.replyTo?.toJson(),
       'repost_to': instance.repostTo?.toJson(),
       'visible_users_list': instance.visibleUsersList,
@@ -109,9 +113,9 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
       'total_aggregated_views': instance.totalAggregatedViews,
       'publisher_id': instance.publisherId,
       'poll_id': instance.pollId,
+      'poll': instance.poll?.toJson(),
       'publisher': instance.publisher.toJson(),
       'metric': instance.metric.toJson(),
-      'preload': instance.preload?.toJson(),
     };
 
 _SnPostTag _$SnPostTagFromJson(Map<String, dynamic> json) => _SnPostTag(
@@ -241,6 +245,9 @@ _SnPublisher _$SnPublisherFromJson(Map<String, dynamic> json) => _SnPublisher(
       totalDownvote: (json['total_downvote'] as num).toInt(),
       realmId: (json['realm_id'] as num?)?.toInt(),
       accountId: (json['account_id'] as num).toInt(),
+      account: json['account'] == null
+          ? null
+          : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
     );
 
 Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) =>
@@ -259,6 +266,7 @@ Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) =>
       'total_downvote': instance.totalDownvote,
       'realm_id': instance.realmId,
       'account_id': instance.accountId,
+      'account': instance.account?.toJson(),
     };
 
 _SnSubscription _$SnSubscriptionFromJson(Map<String, dynamic> json) =>
diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart
index cd08ccf..c0058eb 100644
--- a/lib/widgets/post/post_item.dart
+++ b/lib/widgets/post/post_item.dart
@@ -274,8 +274,10 @@ class _PostItemState extends State<PostItem> {
     final isParentAuthor = ua.isAuthorized &&
         widget.data.replyTo?.publisher.accountId == ua.user?.id;
 
-    final displayableAttachments = widget.data.preload?.attachments
-        ?.where((ele) =>
+    final displayableAttachments = widget.data.body['attachments']
+        ?.map((e) => SnAttachment.fromJson(e))
+        .cast<SnAttachment>()
+        .where((ele) =>
             ele?.mediaType != SnMediaType.image ||
             widget.data.type != 'article')
         .toList();
@@ -284,7 +286,7 @@ class _PostItemState extends State<PostItem> {
 
     var attachmentSize = math.min(
         MediaQuery.of(context).size.width, widget.maxWidth ?? double.infinity);
-    if ((widget.data.preload?.attachments?.length ?? 0) > 1) {
+    if ((widget.data.body['attachments']?.length ?? 0) > 1) {
       attachmentSize -= 80;
     }
 
@@ -341,7 +343,7 @@ class _PostItemState extends State<PostItem> {
                   ],
                 ),
                 const Gap(8),
-                if (widget.data.preload?.thumbnail != null)
+                if (widget.data.body['thumbnail'] != null)
                   Container(
                     margin: const EdgeInsets.only(bottom: 8),
                     decoration: BoxDecoration(
@@ -361,14 +363,14 @@ class _PostItemState extends State<PostItem> {
                         ),
                         child: AutoResizeUniversalImage(
                           sn.getAttachmentUrl(
-                            widget.data.preload!.thumbnail!.rid,
+                            widget.data.body['thumbnail']['rid'],
                           ),
                           fit: BoxFit.cover,
                         ),
                       ),
                     ),
                   ),
-                if (widget.data.preload?.video != null)
+                if (widget.data.body['video'] != null)
                   _PostVideoPlayer(data: widget.data).padding(bottom: 8),
                 if (widget.data.type == 'question')
                   _PostQuestionHint(data: widget.data).padding(bottom: 8),
@@ -455,10 +457,10 @@ class _PostItemState extends State<PostItem> {
                     if (widget.data.repostTo != null)
                       _PostQuoteContent(child: widget.data.repostTo!).padding(
                         top: 4,
-                        bottom: widget.data.preload?.attachments?.isNotEmpty ??
-                                false
-                            ? 12
-                            : 0,
+                        bottom:
+                            widget.data.body['attachments'].isNotEmpty ?? false
+                                ? 12
+                                : 0,
                       ),
                   ],
                 ).padding(
@@ -479,11 +481,11 @@ class _PostItemState extends State<PostItem> {
               fit: widget.showFullPost ? BoxFit.cover : BoxFit.contain,
               padding: EdgeInsets.only(left: 12, right: 12),
             ),
-          if (widget.data.preload?.poll != null)
+          if (widget.data.poll != null)
             StyledWidget(Container(
               constraints:
                   BoxConstraints(maxWidth: widget.maxWidth ?? double.infinity),
-              child: PostPoll(poll: widget.data.preload!.poll!),
+              child: PostPoll(poll: widget.data.poll!),
             ))
                 .padding(
                   left: 12,
@@ -585,7 +587,7 @@ class _PostItemState extends State<PostItem> {
                             ),
                           ],
                         ).padding(bottom: widget.showCompactAvatar ? 4 : 0),
-                        if (widget.data.preload?.thumbnail != null)
+                        if (widget.data.body['thumbnail'] != null)
                           Container(
                             margin: const EdgeInsets.only(bottom: 8),
                             decoration: BoxDecoration(
@@ -605,14 +607,14 @@ class _PostItemState extends State<PostItem> {
                                 ),
                                 child: AutoResizeUniversalImage(
                                   sn.getAttachmentUrl(
-                                    widget.data.preload!.thumbnail!.rid,
+                                    widget.data.body['thumbnail']['rid'],
                                   ),
                                   fit: BoxFit.cover,
                                 ),
                               ),
                             ),
                           ),
-                        if (widget.data.preload?.video != null)
+                        if (widget.data.body['video'] != null)
                           _PostVideoPlayer(data: widget.data)
                               .padding(bottom: 8),
                         if (widget.data.type == 'question')
@@ -712,7 +714,7 @@ class _PostItemState extends State<PostItem> {
                                       _isTranslated ||
                                       _isTranslating) &&
                                   (widget.data.repostTo != null ||
-                                      (widget.data.preload?.attachments
+                                      (widget.data.body['attachments']
                                               ?.isNotEmpty ??
                                           false))
                               ? 8
@@ -722,7 +724,7 @@ class _PostItemState extends State<PostItem> {
                           _PostQuoteContent(child: widget.data.repostTo!)
                               .padding(
                             bottom:
-                                (widget.data.preload?.attachments?.isNotEmpty ??
+                                (widget.data.body['attachments']?.isNotEmpty ??
                                         false)
                                     ? 8
                                     : 0,
@@ -746,8 +748,8 @@ class _PostItemState extends State<PostItem> {
             padding:
                 EdgeInsets.only(left: widget.showAvatar ? 60 : 12, right: 12),
           ),
-        if (widget.data.preload?.poll != null)
-          PostPoll(poll: widget.data.preload!.poll!).padding(
+        if (widget.data.poll != null)
+          PostPoll(poll: widget.data.poll!).padding(
             left: widget.showAvatar ? 60 : 12,
             right: 12,
             top: 12,
@@ -808,7 +810,7 @@ class PostShareImageWidget extends StatelessWidget {
         crossAxisAlignment: CrossAxisAlignment.start,
         mainAxisSize: MainAxisSize.min,
         children: [
-          if (data.preload?.thumbnail != null)
+          if (data.body['thumbnail'] != null)
             AspectRatio(
               aspectRatio: 16 / 9,
               child: ClipRRect(
@@ -817,7 +819,7 @@ class PostShareImageWidget extends StatelessWidget {
                   topRight: Radius.circular(8),
                 ),
                 child: AutoResizeUniversalImage(
-                  sn.getAttachmentUrl(data.preload!.thumbnail!.rid),
+                  sn.getAttachmentUrl(data.body['thumbnail']['rid']),
                   fit: BoxFit.cover,
                   filterQuality: FilterQuality.high,
                 ),
@@ -855,9 +857,13 @@ class PostShareImageWidget extends StatelessWidget {
               isRelativeDate: false,
             ).padding(horizontal: 16, bottom: 8),
           if (data.type != 'article' &&
-              (data.preload?.attachments?.isNotEmpty ?? false))
+              (data.body['attachments']?.isNotEmpty ?? false))
             StyledWidget(AttachmentList(
-              data: data.preload!.attachments!,
+              data: data.body['attachments']
+                      ?.map((e) => SnAttachment.fromJson(e))
+                      .cast<SnAttachment>()
+                      .toList() ??
+                  [],
               columned: true,
               fit: BoxFit.contain,
               filterQuality: FilterQuality.high,
@@ -1146,31 +1152,9 @@ class _PostHeadline extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     if (isEnlarge) {
-      final sn = context.read<SnNetworkProvider>();
       return Column(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
-          if (data.preload?.thumbnail != null)
-            Container(
-              margin: const EdgeInsets.only(bottom: 8),
-              decoration: BoxDecoration(
-                borderRadius: const BorderRadius.all(Radius.circular(8)),
-                border: Border.all(
-                  color: Theme.of(context).dividerColor,
-                  width: 1,
-                ),
-              ),
-              child: AspectRatio(
-                aspectRatio: 16 / 9,
-                child: ClipRRect(
-                  borderRadius: const BorderRadius.all(Radius.circular(8)),
-                  child: AutoResizeUniversalImage(
-                    sn.getAttachmentUrl(data.preload!.thumbnail!.rid),
-                    fit: BoxFit.cover,
-                  ),
-                ),
-              ),
-            ),
           if (data.body['title'] != null || (title?.isNotEmpty ?? false))
             Text(
               title ?? data.body['title'],
@@ -1255,7 +1239,7 @@ class _PostAvatar extends StatelessWidget {
         : null;
 
     return GestureDetector(
-      child: data.preload?.realm == null
+      child: data.realm == null
           ? AccountImage(
               filterQuality: filterQuality,
               content: data.publisher.avatar,
@@ -1271,7 +1255,7 @@ class _PostAvatar extends StatelessWidget {
             )
           : AccountImage(
               filterQuality: filterQuality,
-              content: data.preload!.realm!.avatar,
+              content: data.realm!.avatar,
               radius: isCompact ? 12 : 20,
               borderRadius: isCompact ? 4 : 8,
               badgeOffset: Offset(-6, -4),
@@ -1596,11 +1580,11 @@ class _PostContentHeader extends StatelessWidget {
           Row(
             children: [
               Text(data.publisher.nick).bold(),
-              if (data.preload?.realm != null)
+              if (data.realm != null)
                 const Icon(Symbols.arrow_right, size: 16)
                     .padding(horizontal: 2)
                     .opacity(0.5),
-              if (data.preload?.realm != null) Text(data.preload!.realm!.name),
+              if (data.realm != null) Text(data.realm!.name),
             ],
           ),
           Row(
@@ -1648,7 +1632,11 @@ class _PostContentBody extends StatelessWidget {
           RegExp(r"^:([-\w]+):$").hasMatch(data.body['content'] ?? ''),
       textScaler: isEnlarge ? TextScaler.linear(1.1) : null,
       content: text,
-      attachments: data.preload?.attachments,
+      attachments: data.body['attachments']
+              ?.map((e) => SnAttachment.fromJson(e))
+              .cast<SnAttachment>()
+              .toList() ??
+          [],
     );
 
     if (isSelectable) {
@@ -1706,14 +1694,14 @@ class _PostQuoteContent extends StatelessWidget {
               ],
             ).padding(horizontal: 16),
             if (child.type != 'article' &&
-                (child.preload?.attachments?.isNotEmpty ?? false))
+                (child.body['attachments']?.isNotEmpty ?? false))
               ClipRRect(
                 borderRadius: const BorderRadius.only(
                   bottomLeft: Radius.circular(8),
                   bottomRight: Radius.circular(8),
                 ),
                 child: AttachmentList(
-                  data: child.preload!.attachments!,
+                  data: child.body['attachments']!,
                   maxHeight: 360,
                   minWidth: 640,
                   fit: BoxFit.contain,
@@ -2352,7 +2340,7 @@ class _PostVideoPlayer extends StatelessWidget {
         child: ClipRRect(
           borderRadius: const BorderRadius.all(Radius.circular(8)),
           child: AttachmentItem(
-            data: data.preload!.video!,
+            data: data.body['video'],
             heroTag: 'post-video-${data.id}',
           ),
         ),