diff --git a/mobile/lib/screens/exhibit_detail_screen.dart b/mobile/lib/screens/exhibit_detail_screen.dart index 75cb1e6..900b49b 100644 --- a/mobile/lib/screens/exhibit_detail_screen.dart +++ b/mobile/lib/screens/exhibit_detail_screen.dart @@ -6,6 +6,7 @@ import 'package:mobile/providers/navigate_provider.dart'; import 'package:mobile/screens/creator_detail_screen.dart'; import 'package:mobile/screens/map_screen.dart'; import 'package:mobile/widgets/link_text.dart'; +import 'package:mobile/widgets/thumb_interlace_image.dart'; class ExhibitDetailScreen extends StatefulWidget { const ExhibitDetailScreen({ @@ -36,7 +37,10 @@ class _ExhibitDetailScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.network(exhibit.imageUrl), + ThumbInterlaceImage( + thumbURL: exhibit.thumbUrl, + imageURL: exhibit.imageUrl, + ), const Gap(8), Text(exhibit.displayDate), LinkText( diff --git a/mobile/lib/screens/product_detail_screen.dart b/mobile/lib/screens/product_detail_screen.dart index e9862ba..1d4aaf2 100644 --- a/mobile/lib/screens/product_detail_screen.dart +++ b/mobile/lib/screens/product_detail_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:intersperse/intersperse.dart'; import 'package:mobile/models/product.dart'; +import 'package:mobile/widgets/thumb_interlace_image.dart'; class ProductDetailScreen extends StatefulWidget { const ProductDetailScreen({ @@ -27,7 +28,10 @@ class _ProductDetailScreenState extends State { body: ListView( padding: const EdgeInsets.all(16), children: [ - Image.network(product.imageUrl), + ThumbInterlaceImage( + thumbURL: product.thumbUrl, + imageURL: product.imageUrl, + ), const Gap(8), Text(product.detail), ].intersperse(const Gap(8)).toList(), diff --git a/mobile/lib/widgets/thumb_interlace_image.dart b/mobile/lib/widgets/thumb_interlace_image.dart new file mode 100644 index 0000000..d01c500 --- /dev/null +++ b/mobile/lib/widgets/thumb_interlace_image.dart @@ -0,0 +1,50 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:mobile/widgets/thumb_image.dart'; + +class ThumbInterlaceImage extends StatelessWidget { + final String? thumbURL; + final String imageURL; + + const ThumbInterlaceImage({ + required this.thumbURL, + required this.imageURL, + super.key, + }); + + @override + Widget build(BuildContext context) { + final availThumb = thumbURL != null && thumbURL!.isNotEmpty; + final blurColor = Theme.of(context).colorScheme.surface; + + return CachedNetworkImage( + imageUrl: imageURL, + placeholder: (context, url) => availThumb + ? FittedBox( + child: Stack(children: [ + ThumbImage( + thumbURL: thumbURL, + imageURL: imageURL, + ), + Positioned.fill( + child: Stack(children: [ + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 1, sigmaY: 1), + child: Container(color: blurColor.withOpacity(0.2)), + ), + Center(child: CircularProgressIndicator()), + ]), + ), + ]), + ) + : Container( + color: Colors.grey[300]?.withOpacity(0.5), // プレースホルダーの背景色 + padding: const EdgeInsets.all(16), + child: Center(child: CircularProgressIndicator()), + ), + errorWidget: (context, url, error) => const Icon(Icons.error), + ); + } +}