improvements in ui 2

master
gitea 2 months ago
parent 9061470e9b
commit 374a968546

@ -765,7 +765,10 @@ class _RecipeCard extends StatelessWidget {
Widget _buildRecipeImage(String imageUrl) { Widget _buildRecipeImage(String imageUrl) {
final mediaService = ServiceLocator.instance.mediaService; final mediaService = ServiceLocator.instance.mediaService;
if (mediaService == null) { if (mediaService == null) {
return Image.network(imageUrl, fit: BoxFit.cover); return _FadeInImageWidget(
imageUrl: imageUrl,
isNetwork: true,
);
} }
// Try to extract asset ID from Immich URL (format: .../api/assets/{id}/original) // Try to extract asset ID from Immich URL (format: .../api/assets/{id}/original)
@ -799,18 +802,96 @@ class _RecipeCard extends StatelessWidget {
); );
} }
return Image.memory( return _FadeInImageWidget(
snapshot.data!, imageBytes: snapshot.data!,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
); );
}, },
); );
} }
return Image.network( return _FadeInImageWidget(
imageUrl, imageUrl: imageUrl,
isNetwork: true,
);
}
Widget _buildVideoThumbnail(String videoUrl) {
return _VideoThumbnailPreview(videoUrl: videoUrl);
}
}
/// Widget that displays an image with a smooth fade-in animation.
class _FadeInImageWidget extends StatefulWidget {
final String? imageUrl;
final Uint8List? imageBytes;
final bool isNetwork;
const _FadeInImageWidget({
this.imageUrl,
this.imageBytes,
this.isNetwork = false,
}) : assert(imageUrl != null || imageBytes != null, 'Either imageUrl or imageBytes must be provided');
@override
State<_FadeInImageWidget> createState() => _FadeInImageWidgetState();
}
class _FadeInImageWidgetState extends State<_FadeInImageWidget>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _fadeAnimation;
bool _imageLoaded = false;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_fadeAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
);
// Start with opacity 0
_controller.value = 0.0;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _onImageLoaded() {
if (!_imageLoaded && mounted) {
_imageLoaded = true;
_controller.forward();
}
}
@override
Widget build(BuildContext context) {
Widget imageWidget;
if (widget.imageBytes != null) {
// For memory images, use frameBuilder to detect when image is ready
imageWidget = Image.memory(
widget.imageBytes!,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
if ((wasSynchronouslyLoaded || frame != null) && !_imageLoaded) {
WidgetsBinding.instance.addPostFrameCallback((_) => _onImageLoaded());
}
return child;
},
);
} else if (widget.imageUrl != null) {
// For network images, use frameBuilder to detect when image is ready
imageWidget = Image.network(
widget.imageUrl!,
fit: BoxFit.cover, fit: BoxFit.cover,
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
@ -821,7 +902,10 @@ class _RecipeCard extends StatelessWidget {
); );
}, },
loadingBuilder: (context, child, loadingProgress) { loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child; if (loadingProgress == null) {
// Image is loaded, return child and let frameBuilder handle fade-in
return child;
}
return Container( return Container(
color: Colors.grey.shade200, color: Colors.grey.shade200,
child: Center( child: Center(
@ -834,11 +918,24 @@ class _RecipeCard extends StatelessWidget {
), ),
); );
}, },
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
if ((wasSynchronouslyLoaded || frame != null) && !_imageLoaded) {
WidgetsBinding.instance.addPostFrameCallback((_) => _onImageLoaded());
}
return child;
},
);
} else {
return Container(
color: Colors.grey.shade200,
child: const Icon(Icons.broken_image, size: 48),
); );
} }
Widget _buildVideoThumbnail(String videoUrl) { return FadeTransition(
return _VideoThumbnailPreview(videoUrl: videoUrl); opacity: _fadeAnimation,
child: imageWidget,
);
} }
} }

Loading…
Cancel
Save

Powered by TurnKey Linux.