mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat: manual stack assets (#4198)
This commit is contained in:
		@@ -32,6 +32,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
 | 
			
		||||
  final Widget? topWidget;
 | 
			
		||||
  final bool shrinkWrap;
 | 
			
		||||
  final bool showDragScroll;
 | 
			
		||||
  final bool showStack;
 | 
			
		||||
 | 
			
		||||
  const ImmichAssetGrid({
 | 
			
		||||
    super.key,
 | 
			
		||||
@@ -51,6 +52,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
 | 
			
		||||
    this.topWidget,
 | 
			
		||||
    this.shrinkWrap = false,
 | 
			
		||||
    this.showDragScroll = true,
 | 
			
		||||
    this.showStack = false,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@@ -114,6 +116,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
 | 
			
		||||
          heroOffset: heroOffset(),
 | 
			
		||||
          shrinkWrap: shrinkWrap,
 | 
			
		||||
          showDragScroll: showDragScroll,
 | 
			
		||||
          showStack: showStack,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ class ImmichAssetGridView extends StatefulWidget {
 | 
			
		||||
  final int heroOffset;
 | 
			
		||||
  final bool shrinkWrap;
 | 
			
		||||
  final bool showDragScroll;
 | 
			
		||||
  final bool showStack;
 | 
			
		||||
 | 
			
		||||
  const ImmichAssetGridView({
 | 
			
		||||
    super.key,
 | 
			
		||||
@@ -56,6 +57,7 @@ class ImmichAssetGridView extends StatefulWidget {
 | 
			
		||||
    this.heroOffset = 0,
 | 
			
		||||
    this.shrinkWrap = false,
 | 
			
		||||
    this.showDragScroll = true,
 | 
			
		||||
    this.showStack = false,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@@ -71,7 +73,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
 | 
			
		||||
 | 
			
		||||
  bool _scrolling = false;
 | 
			
		||||
  final Set<Asset> _selectedAssets =
 | 
			
		||||
      HashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id);
 | 
			
		||||
      LinkedHashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id);
 | 
			
		||||
 | 
			
		||||
  Set<Asset> _getSelectedAssets() {
 | 
			
		||||
    return Set.from(_selectedAssets);
 | 
			
		||||
@@ -90,7 +92,13 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
 | 
			
		||||
 | 
			
		||||
  void _deselectAssets(List<Asset> assets) {
 | 
			
		||||
    setState(() {
 | 
			
		||||
      _selectedAssets.removeAll(assets);
 | 
			
		||||
      _selectedAssets.removeAll(
 | 
			
		||||
        assets.where(
 | 
			
		||||
          (a) =>
 | 
			
		||||
              widget.canDeselect ||
 | 
			
		||||
              !(widget.preselectedAssets?.contains(a) ?? false),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      _callSelectionListener(_selectedAssets.isNotEmpty);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
@@ -129,6 +137,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
 | 
			
		||||
      useGrayBoxPlaceholder: true,
 | 
			
		||||
      showStorageIndicator: widget.showStorageIndicator,
 | 
			
		||||
      heroOffset: widget.heroOffset,
 | 
			
		||||
      showStack: widget.showStack,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -377,10 +386,6 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        _selectedAssets.clear();
 | 
			
		||||
      });
 | 
			
		||||
    } else if (widget.preselectedAssets != null) {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        _selectedAssets.addAll(widget.preselectedAssets!);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ class ThumbnailImage extends StatelessWidget {
 | 
			
		||||
  final Asset Function(int index) loadAsset;
 | 
			
		||||
  final int totalAssets;
 | 
			
		||||
  final bool showStorageIndicator;
 | 
			
		||||
  final bool showStack;
 | 
			
		||||
  final bool useGrayBoxPlaceholder;
 | 
			
		||||
  final bool isSelected;
 | 
			
		||||
  final bool multiselectEnabled;
 | 
			
		||||
@@ -26,6 +27,7 @@ class ThumbnailImage extends StatelessWidget {
 | 
			
		||||
    required this.loadAsset,
 | 
			
		||||
    required this.totalAssets,
 | 
			
		||||
    this.showStorageIndicator = true,
 | 
			
		||||
    this.showStack = false,
 | 
			
		||||
    this.useGrayBoxPlaceholder = false,
 | 
			
		||||
    this.isSelected = false,
 | 
			
		||||
    this.multiselectEnabled = false,
 | 
			
		||||
@@ -93,6 +95,35 @@ class ThumbnailImage extends StatelessWidget {
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Widget buildStackIcon() {
 | 
			
		||||
      return Positioned(
 | 
			
		||||
        top: 5,
 | 
			
		||||
        right: 5,
 | 
			
		||||
        child: Row(
 | 
			
		||||
          children: [
 | 
			
		||||
            if (asset.stackCount > 1)
 | 
			
		||||
              Text(
 | 
			
		||||
                "${asset.stackCount}",
 | 
			
		||||
                style: const TextStyle(
 | 
			
		||||
                  color: Colors.white,
 | 
			
		||||
                  fontSize: 10,
 | 
			
		||||
                  fontWeight: FontWeight.bold,
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            if (asset.stackCount > 1)
 | 
			
		||||
              const SizedBox(
 | 
			
		||||
                width: 3,
 | 
			
		||||
              ),
 | 
			
		||||
            const Icon(
 | 
			
		||||
              Icons.burst_mode_rounded,
 | 
			
		||||
              color: Colors.white,
 | 
			
		||||
              size: 18,
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Widget buildImage() {
 | 
			
		||||
      final image = SizedBox(
 | 
			
		||||
        width: 300,
 | 
			
		||||
@@ -113,9 +144,9 @@ class ThumbnailImage extends StatelessWidget {
 | 
			
		||||
        decoration: BoxDecoration(
 | 
			
		||||
          border: Border.all(
 | 
			
		||||
            width: 0,
 | 
			
		||||
            color: assetContainerColor,
 | 
			
		||||
            color: onDeselect == null ? Colors.grey : assetContainerColor,
 | 
			
		||||
          ),
 | 
			
		||||
          color: assetContainerColor,
 | 
			
		||||
          color: onDeselect == null ? Colors.grey : assetContainerColor,
 | 
			
		||||
        ),
 | 
			
		||||
        child: ClipRRect(
 | 
			
		||||
          borderRadius: const BorderRadius.only(
 | 
			
		||||
@@ -144,6 +175,7 @@ class ThumbnailImage extends StatelessWidget {
 | 
			
		||||
              loadAsset: loadAsset,
 | 
			
		||||
              totalAssets: totalAssets,
 | 
			
		||||
              heroOffset: heroOffset,
 | 
			
		||||
              showStack: showStack,
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
@@ -196,6 +228,7 @@ class ThumbnailImage extends StatelessWidget {
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          if (!asset.isImage) buildVideoIcon(),
 | 
			
		||||
          if (asset.isImage && asset.stackCount > 0) buildStackIcon(),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user