import 'package:flutter/material.dart';
import '../core/localization/app_localizations.dart';
import '../core/theme/app_colors.dart';
import 'remote_image.dart';
/// Reusable horizontal swipe gallery for POIs, partners and other CMS content.
/// It renders only when there are additional images.
class MediaGallery extends StatefulWidget {
const MediaGallery({
super.key,
required this.urls,
this.height = 220,
this.title,
});
final List<String> urls;
final double height;
final String? title;
@override
State<MediaGallery> createState() => _MediaGalleryState();
}
class _MediaGalleryState extends State<MediaGallery> {
final PageController _controller = PageController(viewportFraction: .88);
int _index = 0;
List<String> get _urls => widget.urls
.map((url) => url.trim())
.where((url) => url.isNotEmpty)
.toSet()
.toList(growable: false);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final urls = _urls;
if (urls.isEmpty) return const SizedBox.shrink();
final resolvedTitle =
widget.title ?? AppLocalizations.of(context).t('galleryDefault');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
resolvedTitle,
style: Theme.of(context)
.textTheme
.titleLarge
?.copyWith(fontWeight: FontWeight.w900),
),
const SizedBox(height: 12),
SizedBox(
height: widget.height,
child: PageView.builder(
controller: _controller,
itemCount: urls.length,
onPageChanged: (value) => setState(() => _index = value),
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(
right: index == urls.length - 1 ? 0 : 10,
),
child: RemoteImage(
url: urls[index],
height: widget.height,
width: double.infinity,
fit: BoxFit.cover,
borderRadius: BorderRadius.circular(22),
semanticLabel: '$resolvedTitle ${index + 1}',
),
);
},
),
),
if (urls.length > 1) ...[
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
urls.length,
(index) => AnimatedContainer(
duration: const Duration(milliseconds: 180),
width: index == _index ? 22 : 7,
height: 7,
margin: const EdgeInsets.symmetric(horizontal: 3),
decoration: BoxDecoration(
color: index == _index ? AppColors.heartRed : AppColors.line,
borderRadius: BorderRadius.circular(999),
),
),
),
),
],
],
);
}
}

