diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json
index d6bd22c..7c90156 100644
--- a/assets/i18n/en-US.json
+++ b/assets/i18n/en-US.json
@@ -80,6 +80,9 @@
   "deleteChatRoom": "Delete Room",
   "deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.",
   "chat": "Chat",
+  "chatTabAll": "All",
+  "chatTabDirect": "Direct Messages",
+  "chatTabGroup": "Group Chats",
   "chatMessageHint": "Message in {}",
   "chatDirectMessageHint": "Message to {}",
   "directMessage": "Direct Message",
diff --git a/assets/i18n/zh-CN.json b/assets/i18n/zh-CN.json
index 9e26dfe..8cc3ede 100644
--- a/assets/i18n/zh-CN.json
+++ b/assets/i18n/zh-CN.json
@@ -1 +1,8 @@
-{}
\ No newline at end of file
+{
+  "chat": "聊天",
+  "chatTabAll": "全部",
+  "chatTabDirect": "私聊",
+  "chatTabGroup": "群聊",
+  "chatMessageHint": "在 {} 中发送消息",
+  "chatDirectMessageHint": "发送消息给 {}"
+}
\ No newline at end of file
diff --git a/lib/database/message_repository.dart b/lib/database/message_repository.dart
index 37bdc26..2c202fd 100644
--- a/lib/database/message_repository.dart
+++ b/lib/database/message_repository.dart
@@ -15,6 +15,7 @@ class MessageRepository {
 
   final Map<String, LocalChatMessage> pendingMessages = {};
   final Map<String, Map<int, double>> fileUploadProgress = {};
+  int? _totalCount;
 
   MessageRepository(this.room, this.identity, this._apiClient, this._database);
 
@@ -141,12 +142,27 @@ class MessageRepository {
     int offset = 0,
     int take = 20,
   }) async {
+    // Use cached total count if available, otherwise fetch it
+    if (_totalCount == null) {
+      final response = await _apiClient.get(
+        '/chat/$roomId/messages',
+        queryParameters: {'offset': 0, 'take': 1},
+      );
+      _totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
+    }
+
+    if (offset >= _totalCount!) {
+      return [];
+    }
+
     final response = await _apiClient.get(
       '/chat/$roomId/messages',
       queryParameters: {'offset': offset, 'take': take},
     );
 
     final List<dynamic> data = response.data;
+    // Update total count from response headers
+    _totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
 
     final messages =
         data.map((json) {
diff --git a/lib/pods/config.dart b/lib/pods/config.dart
index 3d5377c..9751a45 100644
--- a/lib/pods/config.dart
+++ b/lib/pods/config.dart
@@ -1,6 +1,5 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:responsive_framework/responsive_framework.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 
 const kTokenPairStoreKey = 'dyn_user_tk';
@@ -147,24 +146,3 @@ class UpdateInfoNotifier extends StateNotifier<(String?, String?)> {
     state = (newVersion, newChangelog);
   }
 }
-
-final drawerCollapsedProvider = StateProvider<bool>((ref) => false);
-
-void calcDrawerSize(
-  WidgetRef ref,
-  BuildContext context, {
-  bool withMediaQuery = false,
-}) {
-  bool newDrawerIsCollapsed;
-  if (withMediaQuery) {
-    newDrawerIsCollapsed = MediaQuery.of(context).size.width < 600;
-  } else {
-    final rpb = ResponsiveBreakpoints.of(context);
-    newDrawerIsCollapsed = rpb.smallerOrEqualTo(MOBILE);
-  }
-
-  final current = ref.read(drawerCollapsedProvider);
-  if (newDrawerIsCollapsed != current) {
-    ref.read(drawerCollapsedProvider.notifier).state = newDrawerIsCollapsed;
-  }
-}
diff --git a/lib/screens/account.dart b/lib/screens/account.dart
index 06a0843..b9665fc 100644
--- a/lib/screens/account.dart
+++ b/lib/screens/account.dart
@@ -27,16 +27,19 @@ class AccountShellScreen extends HookConsumerWidget {
     final isWide = isWideScreen(context);
 
     if (isWide) {
-      return Row(
-        children: [
-          SizedBox(width: 360, child: AccountScreen(isAside: true)),
-          VerticalDivider(width: 1),
-          Expanded(child: AutoRouter()),
-        ],
+      return AppBackground(
+        isRoot: true,
+        child: Row(
+          children: [
+            SizedBox(width: 360, child: AccountScreen(isAside: true)),
+            VerticalDivider(width: 1),
+            Expanded(child: AutoRouter()),
+          ],
+        ),
       );
     }
 
-    return AutoRouter();
+    return AppBackground(isRoot: true, child: AutoRouter());
   }
 }
 
@@ -49,7 +52,7 @@ class AccountScreen extends HookConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     final isWide = isWideScreen(context);
     if (isWide && !isAside) {
-      return Container(color: Theme.of(context).scaffoldBackgroundColor);
+      return const EmptyPageHolder();
     }
 
     final user = ref.watch(userInfoProvider);
@@ -62,6 +65,7 @@ class AccountScreen extends HookConsumerWidget {
     }
 
     return AppScaffold(
+      noBackground: isWide,
       appBar: AppBar(title: const Text('account').tr()),
       body: SingleChildScrollView(
         child: Column(
diff --git a/lib/screens/chat/chat.dart b/lib/screens/chat/chat.dart
index 5fd1c71..aa44cba 100644
--- a/lib/screens/chat/chat.dart
+++ b/lib/screens/chat/chat.dart
@@ -85,9 +85,12 @@ class ChatRoomListTile extends HookConsumerWidget {
                   ),
                   Expanded(
                     child: Text(
-                      data.lastMessage.content ?? 'messageNone'.tr(),
+                      (data.lastMessage.content?.isNotEmpty ?? false)
+                          ? data.lastMessage.content!
+                          : 'messageNone'.tr(),
                       maxLines: 1,
                       overflow: TextOverflow.ellipsis,
+                      style: Theme.of(context).textTheme.bodySmall,
                     ),
                   ),
                   Text(
@@ -182,16 +185,19 @@ class ChatShellScreen extends HookConsumerWidget {
     final isWide = isWideScreen(context);
 
     if (isWide) {
-      return Row(
-        children: [
-          Flexible(flex: 2, child: ChatListScreen(isAside: true)),
-          VerticalDivider(width: 1),
-          Flexible(flex: 4, child: AutoRouter()),
-        ],
+      return AppBackground(
+        isRoot: true,
+        child: Row(
+          children: [
+            Flexible(flex: 2, child: ChatListScreen(isAside: true)),
+            VerticalDivider(width: 1),
+            Flexible(flex: 4, child: AutoRouter()),
+          ],
+        ),
       );
     }
 
-    return AutoRouter();
+    return AppBackground(isRoot: true, child: AutoRouter());
   }
 }
 
@@ -204,11 +210,22 @@ class ChatListScreen extends HookConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     final isWide = isWideScreen(context);
     if (isWide && !isAside) {
-      return Container(color: Theme.of(context).scaffoldBackgroundColor);
+      return const EmptyPageHolder();
     }
 
     final chats = ref.watch(chatroomsJoinedProvider);
     final chatInvites = ref.watch(chatroomInvitesProvider);
+    final tabController = useTabController(initialLength: 3);
+    final selectedTab = useState(
+      0,
+    ); // 0 for All, 1 for Direct Messages, 2 for Group Chats
+
+    useEffect(() {
+      tabController.addListener(() {
+        selectedTab.value = tabController.index;
+      });
+      return null;
+    }, [tabController]);
 
     Future<void> createDirectMessage() async {
       final result = await showModalBottomSheet(
@@ -228,6 +245,14 @@ class ChatListScreen extends HookConsumerWidget {
     return AppScaffold(
       appBar: AppBar(
         title: Text('chat').tr(),
+        bottom: TabBar(
+          controller: tabController,
+          tabs: [
+            Tab(text: 'chatTabAll'.tr()),
+            Tab(text: 'chatTabDirect'.tr()),
+            Tab(text: 'chatTabGroup'.tr()),
+          ],
+        ),
         actions: [
           IconButton(
             icon: Badge(
@@ -301,9 +326,26 @@ class ChatListScreen extends HookConsumerWidget {
                   }),
               child: ListView.builder(
                 padding: EdgeInsets.zero,
-                itemCount: items.length,
+                itemCount:
+                    items
+                        .where(
+                          (item) =>
+                              selectedTab.value == 0 ||
+                              (selectedTab.value == 1 && item.type == 1) ||
+                              (selectedTab.value == 2 && item.type != 1),
+                        )
+                        .length,
                 itemBuilder: (context, index) {
-                  final item = items[index];
+                  final filteredItems =
+                      items
+                          .where(
+                            (item) =>
+                                selectedTab.value == 0 ||
+                                (selectedTab.value == 1 && item.type == 1) ||
+                                (selectedTab.value == 2 && item.type != 1),
+                          )
+                          .toList();
+                  final item = filteredItems[index];
                   return ChatRoomListTile(
                     room: item,
                     isDirect: item.type == 1,
diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart
index 91d7004..d685fef 100644
--- a/lib/screens/chat/room.dart
+++ b/lib/screens/chat/room.dart
@@ -25,6 +25,7 @@ import 'package:island/widgets/content/cloud_files.dart';
 import 'package:island/widgets/response.dart';
 import 'package:material_symbols_icons/material_symbols_icons.dart';
 import 'package:styled_widget/styled_widget.dart';
+import 'package:super_sliver_list/super_sliver_list.dart';
 import 'package:uuid/uuid.dart';
 import 'package:material_symbols_icons/symbols.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -321,12 +322,16 @@ class ChatRoomScreen extends HookConsumerWidget {
       );
     }
 
+    var isLoading = false;
+
     // Add scroll listener for pagination
     useEffect(() {
       void onScroll() {
         if (scrollController.position.pixels >=
             scrollController.position.maxScrollExtent - 200) {
-          messagesNotifier.loadMore();
+          if (isLoading) return;
+          isLoading = true;
+          messagesNotifier.loadMore().then((_) => isLoading = false);
         }
       }
 
@@ -338,6 +343,7 @@ class ChatRoomScreen extends HookConsumerWidget {
     useEffect(() {
       void onMessage(WebSocketPacket pkt) {
         if (!pkt.type.startsWith('messages')) return;
+        if (['messages.read'].contains(pkt.type)) return;
         final message = SnChatMessage.fromJson(pkt.data!);
         if (message.chatRoomId != chatRoom.value?.id) return;
         switch (pkt.type) {
@@ -384,19 +390,21 @@ class ChatRoomScreen extends HookConsumerWidget {
     void sendMessage() {
       if (messageController.text.trim().isNotEmpty ||
           attachments.value.isNotEmpty) {
-        messagesNotifier.sendMessage(
-          messageController.text.trim(),
-          attachments.value,
-          editingTo: messageEditingTo.value,
-          forwardingTo: messageForwardingTo.value,
-          replyingTo: messageReplyingTo.value,
-          onProgress: (messageId, progress) {
-            attachmentProgress.value = {
-              ...attachmentProgress.value,
-              messageId: progress,
-            };
-          },
-        );
+        messagesNotifier
+            .sendMessage(
+              messageController.text.trim(),
+              attachments.value,
+              editingTo: messageEditingTo.value,
+              forwardingTo: messageForwardingTo.value,
+              replyingTo: messageReplyingTo.value,
+              onProgress: (messageId, progress) {
+                attachmentProgress.value = {
+                  ...attachmentProgress.value,
+                  messageId: progress,
+                };
+              },
+            )
+            .then((_) => sendReadReceipt());
         messageController.clear();
         messageEditingTo.value = null;
         messageReplyingTo.value = null;
@@ -407,7 +415,7 @@ class ChatRoomScreen extends HookConsumerWidget {
 
     final compactHeader = isWideScreen(context);
 
-    return Scaffold(
+    return AppScaffold(
       appBar: AppBar(
         leading: !compactHeader ? const Center(child: PageBackButton()) : null,
         automaticallyImplyLeading: false,
@@ -526,7 +534,7 @@ class ChatRoomScreen extends HookConsumerWidget {
                   (messageList) =>
                       messageList.isEmpty
                           ? Center(child: Text('No messages yet'.tr()))
-                          : ListView.builder(
+                          : SuperListView.builder(
                             padding: EdgeInsets.symmetric(vertical: 16),
                             controller: scrollController,
                             reverse: true, // Show newest messages at the bottom
@@ -539,7 +547,12 @@ class ChatRoomScreen extends HookConsumerWidget {
                                       : null;
                               final isLastInGroup =
                                   nextMessage == null ||
-                                  nextMessage.senderId != message.senderId;
+                                  nextMessage.senderId != message.senderId ||
+                                  nextMessage.createdAt
+                                          .difference(message.createdAt)
+                                          .inMinutes
+                                          .abs() >
+                                      3;
 
                               return chatIdentity.when(
                                 skipError: true,
diff --git a/lib/screens/notification.dart b/lib/screens/notification.dart
index 88930d9..d10299b 100644
--- a/lib/screens/notification.dart
+++ b/lib/screens/notification.dart
@@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:island/models/user.dart';
 import 'package:island/pods/network.dart';
 import 'package:island/widgets/alert.dart';
+import 'package:island/widgets/app_scaffold.dart';
 import 'package:island/widgets/content/markdown.dart';
 import 'package:relative_time/relative_time.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -85,7 +86,7 @@ class NotificationScreen extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    return Scaffold(
+    return AppScaffold(
       appBar: AppBar(title: const Text('notifications').tr()),
       body: PagingHelperView(
         provider: notificationListNotifierProvider,
diff --git a/lib/screens/realm/detail.dart b/lib/screens/realm/detail.dart
index 4b147f0..349a296 100644
--- a/lib/screens/realm/detail.dart
+++ b/lib/screens/realm/detail.dart
@@ -165,8 +165,9 @@ class _RealmActionMenu extends HookConsumerWidget {
                                   final client = ref.watch(apiClientProvider);
                                   client.delete('/realms/$realmSlug');
                                   ref.invalidate(realmsJoinedProvider);
-                                  if (context.mounted)
+                                  if (context.mounted) {
                                     context.router.maybePop(true);
+                                  }
                                 }
                               });
                             },
diff --git a/lib/screens/realm/realms.dart b/lib/screens/realm/realms.dart
index a1cc4dd..2a03db2 100644
--- a/lib/screens/realm/realms.dart
+++ b/lib/screens/realm/realms.dart
@@ -40,6 +40,7 @@ class RealmListScreen extends HookConsumerWidget {
     final realmInvites = ref.watch(realmInvitesProvider);
 
     return AppScaffold(
+      noBackground: false,
       appBar: AppBar(
         title: const Text('realms').tr(),
         actions: [
diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart
index 6b15d4b..6b55517 100644
--- a/lib/screens/settings.dart
+++ b/lib/screens/settings.dart
@@ -37,6 +37,7 @@ class SettingsScreen extends HookConsumerWidget {
     }, []);
 
     return AppScaffold(
+      noBackground: false,
       appBar: AppBar(title: const Text('Settings')),
       body: SingleChildScrollView(
         child: Column(
diff --git a/lib/widgets/app_scaffold.dart b/lib/widgets/app_scaffold.dart
index d76ffae..bf21831 100644
--- a/lib/widgets/app_scaffold.dart
+++ b/lib/widgets/app_scaffold.dart
@@ -9,9 +9,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:island/pods/userinfo.dart';
 import 'package:island/pods/websocket.dart';
 import 'package:island/route.dart';
+import 'package:island/services/responsive.dart';
 import 'package:material_symbols_icons/material_symbols_icons.dart';
 import 'package:path_provider/path_provider.dart';
-import 'package:responsive_framework/responsive_framework.dart';
 import 'package:styled_widget/styled_widget.dart';
 
 class WindowScaffold extends HookConsumerWidget {
@@ -109,7 +109,7 @@ class AppScaffold extends StatelessWidget {
   final AppBar? appBar;
   final DrawerCallback? onDrawerChanged;
   final DrawerCallback? onEndDrawerChanged;
-  final bool noBackground;
+  final bool? noBackground;
 
   const AppScaffold({
     super.key,
@@ -124,7 +124,7 @@ class AppScaffold extends StatelessWidget {
     this.endDrawer,
     this.onDrawerChanged,
     this.onEndDrawerChanged,
-    this.noBackground = false,
+    this.noBackground,
   });
 
   @override
@@ -132,6 +132,8 @@ class AppScaffold extends StatelessWidget {
     final appBarHeight = appBar?.preferredSize.height ?? 0;
     final safeTop = MediaQuery.of(context).padding.top;
 
+    final noBackground = this.noBackground ?? isWideScreen(context);
+
     final content = Column(
       children: [
         IgnorePointer(
@@ -208,7 +210,7 @@ class AppBackground extends ConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     final imageFileAsync = ref.watch(backgroundImageFileProvider);
 
-    if (isRoot || ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)) {
+    if (isRoot || !isWideScreen(context)) {
       return imageFileAsync.when(
         data: (file) {
           if (file != null) {
@@ -254,6 +256,20 @@ class AppBackground extends ConsumerWidget {
   }
 }
 
+class EmptyPageHolder extends HookConsumerWidget {
+  const EmptyPageHolder({super.key});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final hasBackground =
+        ref.watch(backgroundImageFileProvider).valueOrNull != null;
+    if (hasBackground) {
+      return const SizedBox.shrink();
+    }
+    return Container(color: Theme.of(context).scaffoldBackgroundColor);
+  }
+}
+
 class _WebSocketIndicator extends HookConsumerWidget {
   const _WebSocketIndicator();
 
diff --git a/lib/widgets/chat/message_item.dart b/lib/widgets/chat/message_item.dart
index f32690a..6e32352 100644
--- a/lib/widgets/chat/message_item.dart
+++ b/lib/widgets/chat/message_item.dart
@@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:island/database/message.dart';
 import 'package:island/models/chat.dart';
 import 'package:island/screens/chat/room.dart';
+import 'package:island/widgets/app_scaffold.dart';
 import 'package:island/widgets/content/cloud_file_collection.dart';
 import 'package:island/widgets/content/cloud_files.dart';
 import 'package:island/widgets/content/markdown.dart';
@@ -50,6 +51,9 @@ class MessageItem extends HookConsumerWidget {
       containerColor,
     );
 
+    final hasBackground =
+        ref.watch(backgroundImageFileProvider).valueOrNull != null;
+
     final remoteMessage = message.toRemoteMessage();
     final sender = remoteMessage.sender;
 
@@ -93,7 +97,10 @@ class MessageItem extends HookConsumerWidget {
         );
       },
       child: Material(
-        color: Theme.of(context).colorScheme.surface,
+        color:
+            hasBackground
+                ? Colors.transparent
+                : Theme.of(context).colorScheme.surface,
         child: Padding(
           padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
           child: Column(
@@ -115,7 +122,21 @@ class MessageItem extends HookConsumerWidget {
                       spacing: 2,
                       children: [
                         Text(
-                          DateFormat.Hm().format(message.createdAt.toLocal()),
+                          DateTime.now().difference(message.createdAt).inDays >
+                                  365
+                              ? DateFormat(
+                                'yyyy/MM/dd HH:mm',
+                              ).format(message.createdAt.toLocal())
+                              : DateTime.now()
+                                      .difference(message.createdAt)
+                                      .inDays >
+                                  0
+                              ? DateFormat(
+                                'MM/dd HH:mm',
+                              ).format(message.createdAt.toLocal())
+                              : DateFormat(
+                                'HH:mm',
+                              ).format(message.createdAt.toLocal()),
                           style: TextStyle(fontSize: 10, color: textColor),
                         ),
                         Row(
@@ -151,77 +172,96 @@ class MessageItem extends HookConsumerWidget {
                 crossAxisAlignment: CrossAxisAlignment.end,
                 children: [
                   Flexible(
-                    child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.start,
-                      children: [
-                        if (remoteMessage.repliedMessageId != null)
-                          MessageQuoteWidget(
-                            message: message,
-                            textColor: textColor,
-                            isReply: true,
-                          ),
-                        if (remoteMessage.forwardedMessageId != null)
-                          MessageQuoteWidget(
-                            message: message,
-                            textColor: textColor,
-                            isReply: false,
-                          ),
-                        if (remoteMessage.content?.isNotEmpty ?? false)
-                          MarkdownTextContent(
-                            content: remoteMessage.content!,
-                            isSelectable: true,
-                            linkStyle: TextStyle(color: linkColor),
-                            textStyle: TextStyle(
-                              color: textColor,
-                              fontSize: 14,
+                    child: Container(
+                      decoration: BoxDecoration(
+                        color: containerColor,
+                        borderRadius: BorderRadius.circular(16),
+                      ),
+                      padding: const EdgeInsets.symmetric(
+                        horizontal: 12,
+                        vertical: 6,
+                      ),
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          if (remoteMessage.repliedMessageId != null)
+                            MessageQuoteWidget(
+                              message: message,
+                              textColor: textColor,
+                              isReply: true,
+                            ).padding(vertical: 4),
+                          if (remoteMessage.forwardedMessageId != null)
+                            MessageQuoteWidget(
+                              message: message,
+                              textColor: textColor,
+                              isReply: false,
+                            ).padding(vertical: 4),
+                          if (remoteMessage.content?.isNotEmpty ?? false)
+                            MarkdownTextContent(
+                              content: remoteMessage.content!,
+                              isSelectable: true,
+                              linkStyle: TextStyle(color: linkColor),
+                              textStyle: TextStyle(
+                                color: textColor,
+                                fontSize: 14,
+                              ),
                             ),
-                          ),
-                        if (remoteMessage.attachments.isNotEmpty)
-                          CloudFileList(
-                            files: remoteMessage.attachments,
-                            maxWidth: MediaQuery.of(context).size.width * 0.8,
-                          ).padding(top: 4),
-                        if (progress != null && progress!.isNotEmpty)
-                          Column(
-                            crossAxisAlignment: CrossAxisAlignment.stretch,
-                            spacing: 8,
-                            children: [
-                              if ((remoteMessage.content?.isNotEmpty ?? false))
+                          if (remoteMessage.attachments.isNotEmpty)
+                            LayoutBuilder(
+                              builder: (context, constraints) {
+                                return CloudFileList(
+                                  files: remoteMessage.attachments,
+                                  maxWidth: constraints.maxWidth,
+                                ).padding(vertical: 4);
+                              },
+                            ),
+                          if (progress != null && progress!.isNotEmpty)
+                            Column(
+                              crossAxisAlignment: CrossAxisAlignment.stretch,
+                              spacing: 8,
+                              children: [
+                                if ((remoteMessage.content?.isNotEmpty ??
+                                    false))
+                                  const Gap(0),
+                                for (var entry in progress!.entries)
+                                  Column(
+                                    crossAxisAlignment:
+                                        CrossAxisAlignment.start,
+                                    children: [
+                                      Text(
+                                        'fileUploadingProgress'.tr(
+                                          args: [
+                                            (entry.key + 1).toString(),
+                                            entry.value.toStringAsFixed(1),
+                                          ],
+                                        ),
+                                        style: TextStyle(
+                                          fontSize: 12,
+                                          color: textColor.withOpacity(0.8),
+                                        ),
+                                      ),
+                                      const Gap(4),
+                                      LinearProgressIndicator(
+                                        value: entry.value / 100,
+                                        backgroundColor:
+                                            Theme.of(
+                                              context,
+                                            ).colorScheme.surfaceVariant,
+                                        valueColor:
+                                            AlwaysStoppedAnimation<Color>(
+                                              Theme.of(
+                                                context,
+                                              ).colorScheme.primary,
+                                            ),
+                                      ),
+                                    ],
+                                  ),
                                 const Gap(0),
-                              for (var entry in progress!.entries)
-                                Column(
-                                  crossAxisAlignment: CrossAxisAlignment.start,
-                                  children: [
-                                    Text(
-                                      'fileUploadingProgress'.tr(
-                                        args: [
-                                          (entry.key + 1).toString(),
-                                          entry.value.toStringAsFixed(1),
-                                        ],
-                                      ),
-                                      style: TextStyle(
-                                        fontSize: 12,
-                                        color: textColor.withOpacity(0.8),
-                                      ),
-                                    ),
-                                    const Gap(4),
-                                    LinearProgressIndicator(
-                                      value: entry.value / 100,
-                                      backgroundColor:
-                                          Theme.of(
-                                            context,
-                                          ).colorScheme.surfaceVariant,
-                                      valueColor: AlwaysStoppedAnimation<Color>(
-                                        Theme.of(context).colorScheme.primary,
-                                      ),
-                                    ),
-                                  ],
-                                ),
-                              const Gap(0),
-                            ],
-                          ),
-                      ],
-                    ).padding(left: 40),
+                              ],
+                            ),
+                        ],
+                      ),
+                    ),
                   ),
                   _buildMessageIndicators(
                     context,
@@ -333,6 +373,7 @@ class MessageQuoteWidget extends HookConsumerWidget {
                 children: [
                   if (isReply)
                     Row(
+                      mainAxisSize: MainAxisSize.min,
                       spacing: 4,
                       children: [
                         Icon(Symbols.reply, size: 16, color: textColor),
@@ -340,9 +381,10 @@ class MessageQuoteWidget extends HookConsumerWidget {
                           'Replying to ${snapshot.data!.toRemoteMessage().sender.account.nick}',
                         ).textColor(textColor).bold(),
                       ],
-                    )
+                    ).padding(right: 8)
                   else
                     Row(
+                      mainAxisSize: MainAxisSize.min,
                       spacing: 4,
                       children: [
                         Icon(Symbols.forward, size: 16, color: textColor),
@@ -350,7 +392,7 @@ class MessageQuoteWidget extends HookConsumerWidget {
                           'Forwarded from ${snapshot.data!.toRemoteMessage().sender.account.nick}',
                         ).textColor(textColor).bold(),
                       ],
-                    ),
+                    ).padding(right: 8),
                   if (snapshot.data!.toRemoteMessage().content?.isNotEmpty ??
                       false)
                     Text(
diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart
index 08da12c..986d6dc 100644
--- a/lib/widgets/post/post_item.dart
+++ b/lib/widgets/post/post_item.dart
@@ -12,6 +12,7 @@ import 'package:island/pods/userinfo.dart';
 import 'package:island/route.gr.dart';
 import 'package:island/services/responsive.dart';
 import 'package:island/widgets/alert.dart';
+import 'package:island/widgets/app_scaffold.dart';
 import 'package:island/widgets/content/cloud_file_collection.dart';
 import 'package:island/widgets/content/cloud_files.dart';
 import 'package:island/widgets/content/markdown.dart';
@@ -47,6 +48,9 @@ class PostItem extends HookConsumerWidget {
       [user],
     );
 
+    final hasBackground =
+        ref.watch(backgroundImageFileProvider).valueOrNull != null;
+
     return ContextMenuWidget(
       menuProvider: (_) {
         return Menu(
@@ -101,7 +105,7 @@ class PostItem extends HookConsumerWidget {
         );
       },
       child: Material(
-        color: backgroundColor,
+        color: hasBackground ? Colors.transparent : backgroundColor,
         child: Padding(
           padding: renderingPadding,
           child: Column(
diff --git a/pubspec.lock b/pubspec.lock
index a46fd14..28b1be2 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1477,14 +1477,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "5.0.0"
-  responsive_framework:
-    dependency: "direct main"
-    description:
-      name: responsive_framework
-      sha256: a8e1c13d4ba980c60cbf6fa1e9907cd60662bf2585184d7c96ca46c43de91552
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.5.1"
   riverpod:
     dependency: transitive
     description:
@@ -1826,6 +1818,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.9.0-dev.6"
+  super_sliver_list:
+    dependency: "direct main"
+    description:
+      name: super_sliver_list
+      sha256: b1e1e64d08ce40e459b9bb5d9f8e361617c26b8c9f3bb967760b0f436b6e3f56
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.4.1"
   sync:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 7fc67ff..c828152 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -40,7 +40,6 @@ dependencies:
   auto_route: ^10.0.1
   styled_widget: ^0.4.1
   shared_preferences: ^2.5.3
-  responsive_framework: ^1.5.1
   flutter_riverpod: ^2.6.1
   path_provider: ^2.1.5
   dio: ^5.8.0+1
@@ -100,6 +99,7 @@ dependencies:
   flutter_native_splash: ^2.4.6
   photo_view: ^0.15.0
   dismissible_page: ^1.0.2
+  super_sliver_list: ^0.4.1
 
 dev_dependencies:
   flutter_test: