import 'package:flutter/material.dart' hide Visibility; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../controls/async_value_widget.dart'; import '../controls/error_message_widget.dart'; import '../controls/login_aware_cached_network_image.dart'; import '../models/auth/profile.dart'; import '../models/gallery_data.dart'; import '../models/image_entry.dart'; import '../models/visibility.dart'; import '../riverpod_controllers/account_services.dart'; import '../riverpod_controllers/gallery_services.dart'; import '../serializers/friendica/image_entry_friendica_extensions.dart'; import 'media_viewer_screen.dart'; class ExistingImageSelectorScreen extends ConsumerStatefulWidget { final Visibility? visibilityFilter; const ExistingImageSelectorScreen({ super.key, this.visibilityFilter, }); @override ConsumerState createState() => _ExistingImageSelectorScreenState(); } class _ExistingImageSelectorScreenState extends ConsumerState { GalleryData? selectedGallery; final selectedImages = []; @override Widget build(BuildContext context) { final profile = ref.watch(activeProfileProvider); final galleryListAsyncValue = ref.watch(galleryListProvider(profile)); final title = switch (galleryListAsyncValue) { AsyncData() => selectedImages.isEmpty ? 'Select Image(s)' : '${selectedImages.length} selected', AsyncLoading() => 'Loading...', _ => 'Error loading', }; final List actions = switch (galleryListAsyncValue) { AsyncData() => [ IconButton( onPressed: selectedImages.isEmpty ? null : () { Navigator.of(context).pop(selectedImages); }, tooltip: 'Attach selected files', icon: const Icon(Icons.attach_file), ), IconButton( onPressed: selectedImages.isEmpty ? null : () { setState(() { selectedImages.clear(); }); }, tooltip: 'Clear Selection', icon: const Icon(Icons.remove_circle_outline), ), ], _ => [], }; final body = AsyncValueWidget(galleryListAsyncValue, valueBuilder: (context, ref, galleriesResult) { return galleriesResult.fold( onSuccess: (galleries) { return Center( child: Column( children: [ DropdownButton( value: selectedGallery, items: galleries .map((g) => DropdownMenuItem(value: g, child: Text(g.name))) .toList(), onChanged: (value) { setState(() { selectedGallery = value; }); }), const VerticalDivider(), selectedGallery == null ? buildInfoBody() : Expanded(child: buildGrid(context, profile)), ], )); }, onError: (error) => ErrorMessageWidget(message: 'Error getting galleries: $error')); }); return SafeArea( child: Scaffold( appBar: AppBar( title: Text(title), actions: actions, ), body: body, ), ); } Widget buildInfoBody() { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [Text('Select a gallery')], ), ); } Widget buildGrid( BuildContext context, Profile profile, ) { const thumbnailDimension = 350.0; final galleryName = selectedGallery!.name; final expectedPhotoCount = selectedGallery!.count; return AsyncValueWidget( ref.watch(galleryImagesProvider(profile, galleryName)), valueBuilder: (context, ref, imagesResult) { return imagesResult.fold( onSuccess: (images) { return GridView.builder( itemCount: images.length, padding: const EdgeInsets.all(5.0), gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: thumbnailDimension), itemBuilder: (context, index) { final image = images[index]; // TODO May need to take out since there is a count discrepency for OAuth users if (images.length < expectedPhotoCount && index == images.length - 1) { ref .read(galleryImagesProvider(profile, galleryName) .notifier) .updateGalleryImages( withNextPage: true, nextPageOnly: true, ); } final selected = selectedImages.contains(image); final tileWidget = Card( child: Stack( children: [ LoginAwareCachedNetworkImage( imageUrl: image.thumbnailUrl, ), if (selected) const Positioned( child: Icon( Icons.check_circle, color: Colors.green, )), Positioned( bottom: 5.0, right: 5.0, child: Icon( image.visibility.type == VisibilityType.public ? Icons.public : Icons.lock), ), ], ), ); return Padding( padding: const EdgeInsets.all(2.0), child: GestureDetector( onTap: () { setState(() { if (selected) { selectedImages.remove(image); } else { selectedImages.add(image); } }); }, onDoubleTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => MediaViewerScreen( attachments: [image.toMediaAttachment()], ), ), ); }, child: tileWidget, ), ); }); }, onError: (error) => ErrorMessageWidget(message: 'Error getting image list: $error')); }); } }