diff --git a/lib/screens/account.dart b/lib/screens/account.dart
index 5bc6b67..e37c4cd 100644
--- a/lib/screens/account.dart
+++ b/lib/screens/account.dart
@@ -15,7 +15,6 @@ import 'package:surface/providers/websocket.dart';
 import 'package:surface/types/account.dart';
 import 'package:surface/widgets/account/account_image.dart';
 import 'package:surface/widgets/account/account_status.dart';
-import 'package:surface/widgets/app_bar_leading.dart';
 import 'package:surface/widgets/dialog.dart';
 import 'package:surface/widgets/navigation/app_scaffold.dart';
 import 'package:surface/widgets/universal_image.dart';
@@ -112,7 +111,7 @@ class AccountScreen extends StatelessWidget {
     return AppScaffold(
       noBackground: ResponsiveScaffold.getIsExpand(context),
       appBar: AppBar(
-        leading: AutoAppBarLeading(),
+        leading: const PageBackButton(),
         title: Text("screenAccount").tr(),
         flexibleSpace: ua.user != null && ua.user!.banner.isNotEmpty
             ? Stack(
diff --git a/lib/screens/album.dart b/lib/screens/album.dart
index 585fe43..a6aea47 100644
--- a/lib/screens/album.dart
+++ b/lib/screens/album.dart
@@ -1,19 +1,21 @@
 import 'package:dismissible_page/dismissible_page.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
 import 'package:gap/gap.dart';
 import 'package:google_fonts/google_fonts.dart';
 import 'package:material_symbols_icons/symbols.dart';
+import 'package:path/path.dart' show withoutExtension;
 import 'package:provider/provider.dart';
 import 'package:styled_widget/styled_widget.dart';
 import 'package:surface/providers/sn_network.dart';
+import 'package:surface/providers/userinfo.dart';
 import 'package:surface/types/attachment.dart';
-import 'package:surface/widgets/attachment/attachment_zoom.dart';
 import 'package:surface/widgets/attachment/attachment_item.dart';
+import 'package:surface/widgets/attachment/attachment_zoom.dart';
 import 'package:surface/widgets/dialog.dart';
 import 'package:surface/widgets/navigation/app_scaffold.dart';
 import 'package:uuid/uuid.dart';
+import 'package:very_good_infinite_list/very_good_infinite_list.dart';
 
 class AlbumScreen extends StatefulWidget {
   const AlbumScreen({super.key});
@@ -48,6 +50,8 @@ class _AlbumScreenState extends State<AlbumScreen> {
   Future<void> _fetchAttachments() async {
     setState(() => _isBusy = true);
 
+    final ua = context.read<UserProvider>();
+
     const uuid = Uuid();
 
     try {
@@ -55,10 +59,11 @@ class _AlbumScreenState extends State<AlbumScreen> {
       final resp = await sn.client.get('/cgi/uc/attachments', queryParameters: {
         'take': 10,
         'offset': _attachments.length,
+        'author': ua.user?.name,
       });
       final attachments = List<SnAttachment>.from(
         resp.data['data']?.map((e) => SnAttachment.fromJson(e)) ?? [],
-      ).where((e) => e.mimetype.startsWith('image')).toList();
+      );
       _attachments.addAll(attachments);
       _heroTags.addAll(_attachments.map((_) => uuid.v4()));
 
@@ -97,94 +102,127 @@ class _AlbumScreenState extends State<AlbumScreen> {
   @override
   Widget build(BuildContext context) {
     return AppScaffold(
-      body: CustomScrollView(
-        controller: _scrollController,
-        slivers: [
-          SliverAppBar(
-            leading: PageBackButton(),
-            title: Text('screenAlbum').tr(),
-          ),
-          SliverToBoxAdapter(
-            child: Card(
-              child: Row(
-                children: [
-                  SizedBox(
-                    width: 80,
-                    height: 80,
-                    child: CircularProgressIndicator(
-                      value: _billing?.includedRatio ?? 0,
-                      strokeWidth: 8,
-                      backgroundColor:
-                          Theme.of(context).colorScheme.surfaceContainerHigh,
+      appBar: AppBar(
+        leading: PageBackButton(),
+        title: Text('screenAlbum').tr(),
+      ),
+      body: Column(
+        children: [
+          Card(
+            margin: EdgeInsets.zero,
+            child: Row(
+              children: [
+                SizedBox(
+                  width: 80,
+                  height: 80,
+                  child: CircularProgressIndicator(
+                    value: _billing?.includedRatio ?? 0,
+                    strokeWidth: 8,
+                    backgroundColor:
+                        Theme.of(context).colorScheme.surfaceContainerHigh,
+                  ),
+                ).padding(all: 12),
+                const Gap(24),
+                Expanded(
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      Text('attachmentBillingUploaded').tr().bold(),
+                      Text(
+                        (_billing?.currentBytes ?? 0).formatBytes(decimals: 4),
+                        style: GoogleFonts.robotoMono(),
+                      ),
+                      Text('attachmentBillingDiscount').tr().bold(),
+                      Text(
+                        '${(_billing?.discountFileSize ?? 0).formatBytes(decimals: 2)} · ${((_billing?.includedRatio ?? 0) * 100).toStringAsFixed(2)}%',
+                        style: GoogleFonts.robotoMono(),
+                      ),
+                    ],
+                  ),
+                ),
+                Tooltip(
+                  message: 'attachmentBillingHint'.tr(),
+                  child: IconButton(
+                    icon: const Icon(Symbols.info),
+                    onPressed: () {},
+                  ),
+                ),
+              ],
+            ).padding(horizontal: 24, vertical: 8),
+          ).padding(horizontal: 8, top: 8),
+          Expanded(
+            child: InfiniteList(
+              padding: EdgeInsets.only(top: 8),
+              itemCount: _attachments.length,
+              isLoading: _isBusy,
+              hasReachedMax:
+                  _totalCount != null && _attachments.length >= _totalCount!,
+              onFetchData: _fetchAttachments,
+              itemBuilder: (context, index) {
+                final ele = _attachments[index];
+                return Column(
+                  mainAxisSize: MainAxisSize.min,
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    ClipRRect(
+                      child: AspectRatio(
+                        aspectRatio: (ele.data['ratio'] ?? 1).toDouble(),
+                        child: AttachmentItem(
+                          data: ele,
+                          heroTag: _heroTags[index],
+                          onZoom: () {
+                            context.pushTransparentRoute(
+                              AttachmentZoomView(
+                                data: [ele],
+                              ),
+                              backgroundColor: Colors.black.withOpacity(0.7),
+                              rootNavigator: true,
+                            );
+                          },
+                        ),
+                      ),
                     ),
-                  ).padding(all: 12),
-                  const Gap(24),
-                  Expanded(
-                    child: Column(
+                    Row(
                       crossAxisAlignment: CrossAxisAlignment.start,
                       children: [
-                        Text('attachmentBillingUploaded').tr().bold(),
-                        Text(
-                          (_billing?.currentBytes ?? 0)
-                              .formatBytes(decimals: 4),
-                          style: GoogleFonts.robotoMono(),
+                        Expanded(
+                          child: Column(
+                            mainAxisSize: MainAxisSize.min,
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              Text(ele.name),
+                              if (ele.alt != withoutExtension(ele.name))
+                                Text(ele.alt),
+                              Text(DateFormat().format(ele.createdAt)),
+                              const Gap(4),
+                              Text(ele.size.formatBytes()).fontSize(12),
+                            ],
+                          ).padding(horizontal: 16, vertical: 12),
                         ),
-                        Text('attachmentBillingDiscount').tr().bold(),
-                        Text(
-                          '${(_billing?.discountFileSize ?? 0).formatBytes(decimals: 2)} · ${((_billing?.includedRatio ?? 0) * 100).toStringAsFixed(2)}%',
-                          style: GoogleFonts.robotoMono(),
+                        Padding(
+                          padding: EdgeInsets.only(left: 12, right: 12, top: 4),
+                          child: IconButton(
+                            padding: EdgeInsets.zero,
+                            visualDensity: VisualDensity.compact,
+                            icon: const Icon(Symbols.info),
+                            onPressed: () {
+                              showModalBottomSheet(
+                                context: context,
+                                builder: (context) => AttachmentZoomDetailPopup(
+                                  data: ele,
+                                ),
+                              );
+                            },
+                          ),
                         ),
                       ],
                     ),
-                  ),
-                  Tooltip(
-                    message: 'attachmentBillingHint'.tr(),
-                    child: IconButton(
-                      icon: const Icon(Symbols.info),
-                      onPressed: () {},
-                    ),
-                  ),
-                ],
-              ).padding(horizontal: 24, vertical: 8),
-            ),
-          ),
-          SliverMasonryGrid.extent(
-            childCount: _attachments.length,
-            maxCrossAxisExtent: 320,
-            mainAxisSpacing: 4,
-            crossAxisSpacing: 4,
-            itemBuilder: (context, idx) {
-              final attachment = _attachments[idx];
-              return GestureDetector(
-                child: ClipRRect(
-                  child: AspectRatio(
-                    aspectRatio: attachment.metadata['ratio']?.toDouble() ?? 1,
-                    child: AttachmentItem(
-                      data: attachment,
-                      heroTag: _heroTags[idx],
-                    ),
-                  ),
-                ),
-                onTap: () {
-                  context.pushTransparentRoute(
-                    AttachmentZoomView(
-                      data: [attachment],
-                      heroTags: [_heroTags[idx]],
-                    ),
-                    backgroundColor: Colors.black.withOpacity(0.7),
-                    rootNavigator: true,
-                  );
-                },
-              );
-            },
-          ),
-          if (_isBusy)
-            SliverToBoxAdapter(
-              child: Padding(
-                padding: const EdgeInsets.all(24),
-                child: const CircularProgressIndicator(),
-              ).center(),
+                  ],
+                );
+              },
+              separatorBuilder: (_, __) => const Gap(8),
             ),
+          )
         ],
       ),
     );
diff --git a/lib/screens/post/publisher_page.dart b/lib/screens/post/publisher_page.dart
index 770bce2..3138fe6 100644
--- a/lib/screens/post/publisher_page.dart
+++ b/lib/screens/post/publisher_page.dart
@@ -303,6 +303,7 @@ class _PostPublisherScreenState extends State<PostPublisherScreen>
                     ),
                     child: SliverAppBar(
                       expandedHeight: _appBarHeight,
+                      leading: const PageBackButton(),
                       title: _publisher == null
                           ? Text('loading').tr()
                           : RichText(
diff --git a/lib/widgets/attachment/attachment_zoom.dart b/lib/widgets/attachment/attachment_zoom.dart
index 9682c44..8c13747 100644
--- a/lib/widgets/attachment/attachment_zoom.dart
+++ b/lib/widgets/attachment/attachment_zoom.dart
@@ -373,7 +373,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
                             _showDetail = true;
                             showModalBottomSheet(
                               context: context,
-                              builder: (context) => _AttachmentZoomDetailPopup(
+                              builder: (context) => AttachmentZoomDetailPopup(
                                 data: widget.data.elementAt(_page),
                               ),
                             ).then((_) {
@@ -403,7 +403,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
             _showDetail = true;
             showModalBottomSheet(
               context: context,
-              builder: (context) => _AttachmentZoomDetailPopup(
+              builder: (context) => AttachmentZoomDetailPopup(
                 data: widget.data.elementAt(_page),
               ),
             ).then((_) {
@@ -416,10 +416,10 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
   }
 }
 
-class _AttachmentZoomDetailPopup extends StatelessWidget {
+class AttachmentZoomDetailPopup extends StatelessWidget {
   final SnAttachment data;
 
-  const _AttachmentZoomDetailPopup({required this.data});
+  const AttachmentZoomDetailPopup({required this.data});
 
   @override
   Widget build(BuildContext context) {