feat: Enhance gallery editing by managing loading states and disabling actions during deletions

Changed files
+43 -21
lib
+43 -21
lib/screens/gallery_edit_photos_sheet.dart
··· 30 class _GalleryEditPhotosSheetState extends ConsumerState<GalleryEditPhotosSheet> { 31 late List<GalleryPhoto> _photos; 32 bool _loading = false; 33 34 @override 35 void initState() { ··· 40 @override 41 Widget build(BuildContext context) { 42 final theme = Theme.of(context); 43 - // ...existing code... 44 return CupertinoPageScaffold( 45 backgroundColor: theme.colorScheme.surface, 46 navigationBar: CupertinoNavigationBar( ··· 52 ), 53 leading: CupertinoButton( 54 padding: EdgeInsets.zero, 55 - onPressed: _loading ? null : () => Navigator.of(context).maybePop(), 56 child: Text( 57 'Cancel', 58 - style: TextStyle(color: theme.colorScheme.primary, fontWeight: FontWeight.w600), 59 ), 60 ), 61 ), ··· 80 ), 81 itemBuilder: (context, index) { 82 final photo = _photos[index]; 83 return Stack( 84 fit: StackFit.expand, 85 children: [ ··· 97 top: 8, 98 right: 8, 99 child: GestureDetector( 100 - onTap: _loading 101 ? null 102 : () async { 103 final confirm = await showDialog<bool>( ··· 120 ), 121 ); 122 if (confirm == true && photo.gallery?.item != null) { 123 await ref 124 .read(galleryCacheProvider.notifier) 125 .removePhotoFromGallery( 126 widget.galleryUri, 127 photo.gallery!.item, 128 ); 129 setState(() { 130 _photos.removeAt(index); 131 }); 132 } 133 }, ··· 137 shape: BoxShape.circle, 138 ), 139 padding: const EdgeInsets.all(4), 140 - child: const Icon(Icons.close, color: Colors.white, size: 20), 141 ), 142 ), 143 ), ··· 155 child: AppButton( 156 label: 'Upload photos', 157 loading: _loading, 158 - onPressed: _loading 159 ? null 160 : () async { 161 final picker = ImagePicker(); ··· 186 child: AppButton( 187 label: 'Add from library', 188 variant: AppButtonVariant.secondary, 189 - onPressed: () async { 190 - if (_loading) return; 191 - final actorDid = apiService.currentUser?.did; 192 - if (actorDid == null) return; 193 - await showLibraryPhotosSelectSheet( 194 - context, 195 - actorDid: actorDid, 196 - galleryUri: widget.galleryUri, 197 - onSelect: (photos) { 198 - setState(() { 199 - _photos.addAll(photos); 200 - }); 201 - }, 202 - ); 203 - }, 204 ), 205 ), 206 ],
··· 30 class _GalleryEditPhotosSheetState extends ConsumerState<GalleryEditPhotosSheet> { 31 late List<GalleryPhoto> _photos; 32 bool _loading = false; 33 + int? _deletingPhotoIndex; 34 35 @override 36 void initState() { ··· 41 @override 42 Widget build(BuildContext context) { 43 final theme = Theme.of(context); 44 return CupertinoPageScaffold( 45 backgroundColor: theme.colorScheme.surface, 46 navigationBar: CupertinoNavigationBar( ··· 52 ), 53 leading: CupertinoButton( 54 padding: EdgeInsets.zero, 55 + onPressed: (_loading || _deletingPhotoIndex != null) 56 + ? null 57 + : () => Navigator.of(context).maybePop(), 58 child: Text( 59 'Cancel', 60 + style: TextStyle( 61 + color: _deletingPhotoIndex != null ? theme.disabledColor : theme.colorScheme.primary, 62 + fontWeight: FontWeight.w600, 63 + ), 64 ), 65 ), 66 ), ··· 85 ), 86 itemBuilder: (context, index) { 87 final photo = _photos[index]; 88 + final isDeleting = _deletingPhotoIndex == index; 89 return Stack( 90 fit: StackFit.expand, 91 children: [ ··· 103 top: 8, 104 right: 8, 105 child: GestureDetector( 106 + onTap: (_loading || _deletingPhotoIndex != null || isDeleting) 107 ? null 108 : () async { 109 final confirm = await showDialog<bool>( ··· 126 ), 127 ); 128 if (confirm == true && photo.gallery?.item != null) { 129 + if (!mounted) return; 130 + setState(() { 131 + _deletingPhotoIndex = index; 132 + }); 133 await ref 134 .read(galleryCacheProvider.notifier) 135 .removePhotoFromGallery( 136 widget.galleryUri, 137 photo.gallery!.item, 138 ); 139 + if (!mounted) return; 140 setState(() { 141 _photos.removeAt(index); 142 + _deletingPhotoIndex = null; 143 }); 144 } 145 }, ··· 149 shape: BoxShape.circle, 150 ), 151 padding: const EdgeInsets.all(4), 152 + child: isDeleting 153 + ? SizedBox( 154 + width: 20, 155 + height: 20, 156 + child: CircularProgressIndicator( 157 + strokeWidth: 2, 158 + valueColor: AlwaysStoppedAnimation<Color>(Colors.white), 159 + ), 160 + ) 161 + : const Icon(Icons.close, color: Colors.white, size: 20), 162 ), 163 ), 164 ), ··· 176 child: AppButton( 177 label: 'Upload photos', 178 loading: _loading, 179 + onPressed: (_loading || _deletingPhotoIndex != null) 180 ? null 181 : () async { 182 final picker = ImagePicker(); ··· 207 child: AppButton( 208 label: 'Add from library', 209 variant: AppButtonVariant.secondary, 210 + onPressed: (_loading || _deletingPhotoIndex != null) 211 + ? null 212 + : () async { 213 + final actorDid = apiService.currentUser?.did; 214 + if (actorDid == null) return; 215 + await showLibraryPhotosSelectSheet( 216 + context, 217 + actorDid: actorDid, 218 + galleryUri: widget.galleryUri, 219 + onSelect: (photos) { 220 + setState(() { 221 + _photos.addAll(photos); 222 + }); 223 + }, 224 + ); 225 + }, 226 ), 227 ), 228 ],