@@ -3,35 +3,33 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
33import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' ;
44import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_stack.provider.dart' ;
55import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart' ;
6- import 'package:immich_mobile/presentation/widgets/images/image_provider .dart' ;
6+ import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget .dart' ;
77import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart' ;
88
99class AssetStackRow extends ConsumerWidget {
1010 const AssetStackRow ({super .key});
1111
1212 @override
1313 Widget build (BuildContext context, WidgetRef ref) {
14- int opacity = ref.watch (assetViewerProvider.select ((state) => state.backgroundOpacity));
15- final showControls = ref.watch (assetViewerProvider.select ((s) => s.showingControls));
14+ final asset = ref.watch (assetViewerProvider.select ((state) => state.currentAsset));
15+ if (asset == null ) {
16+ return const SizedBox .shrink ();
17+ }
1618
17- if (! showControls) {
18- opacity = 0 ;
19+ final stackChildren = ref.watch (stackChildrenNotifier (asset)).valueOrNull;
20+ if (stackChildren == null || stackChildren.isEmpty) {
21+ return const SizedBox .shrink ();
1922 }
2023
21- final asset = ref.watch (assetViewerProvider.select ((s) => s.currentAsset));
24+ final showControls = ref.watch (assetViewerProvider.select ((s) => s.showingControls));
25+ final opacity = showControls ? ref.watch (assetViewerProvider.select ((state) => state.backgroundOpacity)) : 0 ;
2226
2327 return IgnorePointer (
2428 ignoring: opacity < 255 ,
2529 child: AnimatedOpacity (
2630 opacity: opacity / 255 ,
2731 duration: Durations .short2,
28- child: ref
29- .watch (stackChildrenNotifier (asset))
30- .when (
31- data: (state) => SizedBox .square (dimension: 80 , child: _StackList (stack: state)),
32- error: (_, __) => const SizedBox .shrink (),
33- loading: () => const SizedBox .shrink (),
34- ),
32+ child: _StackList (stack: stackChildren),
3533 ),
3634 );
3735 }
@@ -44,58 +42,77 @@ class _StackList extends ConsumerWidget {
4442
4543 @override
4644 Widget build (BuildContext context, WidgetRef ref) {
47- return ListView .builder (
48- scrollDirection: Axis .horizontal,
49- padding: const EdgeInsets .only (left: 5 , right: 5 , bottom: 30 ),
50- itemCount: stack.length,
51- itemBuilder: (ctx, index) {
52- final asset = stack[index];
53- return Padding (
54- padding: const EdgeInsets .only (right: 5 ),
55- child: GestureDetector (
56- onTap: () {
57- ref.read (assetViewerProvider.notifier).setStackIndex (index);
58- ref.read (currentAssetNotifier.notifier).setAsset (asset);
59- },
60- child: Container (
61- height: 60 ,
62- width: 60 ,
63- decoration: index == ref.watch (assetViewerProvider.select ((s) => s.stackIndex))
64- ? const BoxDecoration (
65- color: Colors .white,
66- borderRadius: BorderRadius .all (Radius .circular (6 )),
67- border: Border .fromBorderSide (BorderSide (color: Colors .white, width: 2 )),
68- )
69- : const BoxDecoration (
70- color: Colors .white,
71- borderRadius: BorderRadius .all (Radius .circular (6 )),
72- border: null ,
73- ),
74- child: ClipRRect (
75- borderRadius: const BorderRadius .all (Radius .circular (4 )),
76- child: Stack (
77- fit: StackFit .expand,
78- children: [
79- Image (
80- fit: BoxFit .cover,
81- image: getThumbnailImageProvider (remoteId: asset.id, size: const Size .square (60 )),
82- ),
83- if (asset.isVideo)
84- const Icon (
85- Icons .play_circle_outline_rounded,
86- color: Colors .white,
87- size: 16 ,
88- shadows: [
89- Shadow (blurRadius: 5.0 , color: Color .fromRGBO (0 , 0 , 0 , 0.6 ), offset: Offset (0.0 , 0.0 )),
90- ],
91- ),
92- ],
93- ),
94- ),
95- ),
45+ return Center (
46+ child: SingleChildScrollView (
47+ scrollDirection: Axis .horizontal,
48+ child: Padding (
49+ padding: const EdgeInsets .only (left: 10.0 , right: 10.0 , bottom: 20.0 ),
50+ child: Row (
51+ mainAxisAlignment: MainAxisAlignment .center,
52+ spacing: 5.0 ,
53+ children: List .generate (stack.length, (i) {
54+ final asset = stack[i];
55+ return _StackItem (key: ValueKey (asset.heroTag), asset: asset, index: i);
56+ }),
9657 ),
97- );
98- },
58+ ),
59+ ),
60+ );
61+ }
62+ }
63+
64+ class _StackItem extends ConsumerStatefulWidget {
65+ final RemoteAsset asset;
66+ final int index;
67+
68+ const _StackItem ({super .key, required this .asset, required this .index});
69+
70+ @override
71+ ConsumerState <_StackItem > createState () => _StackItemState ();
72+ }
73+
74+ class _StackItemState extends ConsumerState <_StackItem > {
75+ void _onTap () {
76+ ref.read (currentAssetNotifier.notifier).setAsset (widget.asset);
77+ ref.read (assetViewerProvider.notifier).setStackIndex (widget.index);
78+ }
79+
80+ @override
81+ Widget build (BuildContext context) {
82+ const playIcon = Center (
83+ child: Icon (
84+ Icons .play_circle_outline_rounded,
85+ color: Colors .white,
86+ size: 16 ,
87+ shadows: [Shadow (blurRadius: 5.0 , color: Color .fromRGBO (0 , 0 , 0 , 0.6 ), offset: Offset (0.0 , 0.0 ))],
88+ ),
89+ );
90+ const selectedDecoration = BoxDecoration (
91+ border: Border .fromBorderSide (BorderSide (color: Colors .white, width: 2 )),
92+ borderRadius: BorderRadius .all (Radius .circular (10 )),
93+ );
94+ const unselectedDecoration = BoxDecoration (
95+ border: Border .fromBorderSide (BorderSide (color: Colors .grey, width: 0.5 )),
96+ borderRadius: BorderRadius .all (Radius .circular (10 )),
97+ );
98+
99+ Widget thumbnail = Thumbnail .fromAsset (asset: widget.asset, size: const Size (60 , 40 ));
100+ if (widget.asset.isVideo) {
101+ thumbnail = Stack (children: [thumbnail, playIcon]);
102+ }
103+ thumbnail = ClipRRect (borderRadius: const BorderRadius .all (Radius .circular (10 )), child: thumbnail);
104+ final isSelected = ref.watch (assetViewerProvider.select ((s) => s.stackIndex == widget.index));
105+ return SizedBox (
106+ width: 60 ,
107+ height: 40 ,
108+ child: GestureDetector (
109+ onTap: _onTap,
110+ child: DecoratedBox (
111+ decoration: isSelected ? selectedDecoration : unselectedDecoration,
112+ position: DecorationPosition .foreground,
113+ child: thumbnail,
114+ ),
115+ ),
99116 );
100117 }
101118}
0 commit comments