mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:29:32 -05:00 
			
		
		
		
	fix(mobile): rework album detail page header (#3035)
This commit is contained in:
		
							parent
							
								
									621fa5ba54
								
							
						
					
					
						commit
						b7ae3be394
					
				@ -21,6 +21,8 @@ class AlbumViewerAppbar extends HookConsumerWidget
 | 
			
		||||
    required this.selected,
 | 
			
		||||
    required this.selectionDisabled,
 | 
			
		||||
    required this.titleFocusNode,
 | 
			
		||||
    this.onAddPhotos,
 | 
			
		||||
    this.onAddUsers,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  final Album album;
 | 
			
		||||
@ -28,6 +30,8 @@ class AlbumViewerAppbar extends HookConsumerWidget
 | 
			
		||||
  final Set<Asset> selected;
 | 
			
		||||
  final void Function() selectionDisabled;
 | 
			
		||||
  final FocusNode titleFocusNode;
 | 
			
		||||
  final Function(Album album)? onAddPhotos;
 | 
			
		||||
  final Function(Album album)? onAddUsers;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
@ -157,6 +161,32 @@ class AlbumViewerAppbar extends HookConsumerWidget
 | 
			
		||||
              mainAxisSize: MainAxisSize.min,
 | 
			
		||||
              children: [
 | 
			
		||||
                buildBottomSheetActionButton(),
 | 
			
		||||
                if (selected.isEmpty && onAddPhotos != null)
 | 
			
		||||
                  ListTile(
 | 
			
		||||
                    leading: const Icon(Icons.add_photo_alternate_outlined),
 | 
			
		||||
                    onTap: () {
 | 
			
		||||
                      Navigator.pop(context);
 | 
			
		||||
                      onAddPhotos!(album);
 | 
			
		||||
                    },
 | 
			
		||||
                    title: const Text(
 | 
			
		||||
                      "share_add_photos",
 | 
			
		||||
                      style: TextStyle(fontWeight: FontWeight.bold),
 | 
			
		||||
                    ).tr(),
 | 
			
		||||
                  ),
 | 
			
		||||
                if (selected.isEmpty &&
 | 
			
		||||
                    onAddPhotos != null &&
 | 
			
		||||
                    userId == album.ownerId)
 | 
			
		||||
                  ListTile(
 | 
			
		||||
                    leading: const Icon(Icons.person_add_alt_rounded),
 | 
			
		||||
                    onTap: () {
 | 
			
		||||
                      Navigator.pop(context);
 | 
			
		||||
                      onAddUsers!(album);
 | 
			
		||||
                    },
 | 
			
		||||
                    title: const Text(
 | 
			
		||||
                      "album_viewer_page_share_add_users",
 | 
			
		||||
                      style: TextStyle(fontWeight: FontWeight.bold),
 | 
			
		||||
                    ).tr(),
 | 
			
		||||
                  ),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,6 @@ import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/models/album.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/models/asset.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_sliver_persistent_app_bar_delegate.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
 | 
			
		||||
 | 
			
		||||
class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
@ -33,7 +32,6 @@ class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
    final userId = ref.watch(authenticationProvider).userId;
 | 
			
		||||
    final selection = useState<Set<Asset>>({});
 | 
			
		||||
    final multiSelectEnabled = useState(false);
 | 
			
		||||
    bool? isTop;
 | 
			
		||||
 | 
			
		||||
    Future<bool> onWillPop() async {
 | 
			
		||||
      if (multiSelectEnabled.value) {
 | 
			
		||||
@ -219,8 +217,6 @@ class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final scroll = ScrollController();
 | 
			
		||||
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      appBar: album.when(
 | 
			
		||||
        data: (data) => AlbumViewerAppbar(
 | 
			
		||||
@ -229,6 +225,8 @@ class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
          userId: userId,
 | 
			
		||||
          selected: selection.value,
 | 
			
		||||
          selectionDisabled: disableSelection,
 | 
			
		||||
          onAddPhotos: onAddPhotosPressed,
 | 
			
		||||
          onAddUsers: onAddUsersPressed,
 | 
			
		||||
        ),
 | 
			
		||||
        error: (error, stackTrace) => AppBar(title: const Text("Error")),
 | 
			
		||||
        loading: () => AppBar(),
 | 
			
		||||
@ -240,41 +238,17 @@ class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
            onTap: () {
 | 
			
		||||
              titleFocusNode.unfocus();
 | 
			
		||||
            },
 | 
			
		||||
            child: NestedScrollView(
 | 
			
		||||
              controller: scroll,
 | 
			
		||||
              floatHeaderSlivers: true,
 | 
			
		||||
              headerSliverBuilder: (context, innerBoxIsScrolled) => [
 | 
			
		||||
                SliverToBoxAdapter(child: buildHeader(data)),
 | 
			
		||||
                SliverPersistentHeader(
 | 
			
		||||
                  pinned: true,
 | 
			
		||||
                  delegate: ImmichSliverPersistentAppBarDelegate(
 | 
			
		||||
                    minHeight: 50,
 | 
			
		||||
                    maxHeight: 50,
 | 
			
		||||
                    child: Container(
 | 
			
		||||
                      color: Theme.of(context).scaffoldBackgroundColor,
 | 
			
		||||
                      child: buildControlButton(data),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                )
 | 
			
		||||
              ],
 | 
			
		||||
              body: ImmichAssetGrid(
 | 
			
		||||
                renderList: data.renderList,
 | 
			
		||||
                listener: selectionListener,
 | 
			
		||||
                selectionActive: multiSelectEnabled.value,
 | 
			
		||||
                showMultiSelectIndicator: false,
 | 
			
		||||
                visibleItemsListener: (start, end) {
 | 
			
		||||
                  final top = start.index == 0 && start.itemLeadingEdge == 0.0;
 | 
			
		||||
                  if (top != isTop) {
 | 
			
		||||
                    isTop = top;
 | 
			
		||||
                    scroll.animateTo(
 | 
			
		||||
                      top
 | 
			
		||||
                          ? scroll.position.minScrollExtent
 | 
			
		||||
                          : scroll.position.maxScrollExtent,
 | 
			
		||||
                      duration: const Duration(milliseconds: 500),
 | 
			
		||||
                      curve: top ? Curves.easeOut : Curves.easeIn,
 | 
			
		||||
                    );
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
            child: ImmichAssetGrid(
 | 
			
		||||
              renderList: data.renderList,
 | 
			
		||||
              listener: selectionListener,
 | 
			
		||||
              selectionActive: multiSelectEnabled.value,
 | 
			
		||||
              showMultiSelectIndicator: false,
 | 
			
		||||
              topWidget: Column(
 | 
			
		||||
                crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
                children: [
 | 
			
		||||
                  buildHeader(data),
 | 
			
		||||
                  if (data.isRemote) buildControlButton(data),
 | 
			
		||||
                ],
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
class ImmichSliverPersistentAppBarDelegate
 | 
			
		||||
    extends SliverPersistentHeaderDelegate {
 | 
			
		||||
  final double minHeight;
 | 
			
		||||
  final double maxHeight;
 | 
			
		||||
  final Widget child;
 | 
			
		||||
 | 
			
		||||
  ImmichSliverPersistentAppBarDelegate({
 | 
			
		||||
    required this.minHeight,
 | 
			
		||||
    required this.maxHeight,
 | 
			
		||||
    required this.child,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  double get minExtent => minHeight;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  double get maxExtent => max(maxHeight, minHeight);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(
 | 
			
		||||
    BuildContext context,
 | 
			
		||||
    double shrinkOffset,
 | 
			
		||||
    bool overlapsContent,
 | 
			
		||||
  ) {
 | 
			
		||||
    return SizedBox.expand(child: child);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool shouldRebuild(ImmichSliverPersistentAppBarDelegate oldDelegate) {
 | 
			
		||||
    return maxHeight != oldDelegate.maxHeight ||
 | 
			
		||||
        minHeight != oldDelegate.minHeight ||
 | 
			
		||||
        child != oldDelegate.child;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user