showNewsListDialog function
- required BuildContext context,
- required List<
NewsMarker> visibleNewsMarkers, - required VoidCallback onCloseNews,
- required void onNewsMarkerTap(
- NewsMarker newsMarker
Shows a dialog with the list of all news in current view.
Implementation
Future<void> showNewsListDialog({
required BuildContext context,
required List<NewsMarker> visibleNewsMarkers,
required VoidCallback onCloseNews,
required void Function(NewsMarker newsMarker) onNewsMarkerTap,
}) async {
await showDialog(
context: context,
builder: (dialogContext) => Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Container(
width: 500,
height: 600,
padding: const EdgeInsets.all(20),
child: Column(
children: [
// Header.
Row(
children: [
Icon(Icons.article, color: Colors.blue.shade700, size: 28),
const SizedBox(width: 12),
Expanded(
child: Text(
'News in Current View',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
// Only close dialog, keep news markers visible.
Navigator.of(dialogContext).pop();
},
),
],
),
const Divider(height: 20),
Text(
'${visibleNewsMarkers.length} news items in current view',
style: TextStyle(color: Colors.grey.shade600),
),
const SizedBox(height: 12),
// News list.
Expanded(
child: visibleNewsMarkers.isEmpty
? Center(
child: Text(
'No news found in this area',
style: TextStyle(color: Colors.grey.shade600),
),
)
: ListView.builder(
itemCount: visibleNewsMarkers.length,
itemBuilder: (context, index) {
final news = visibleNewsMarkers[index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 8),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue.shade700,
child: const Icon(
Icons.article,
color: Colors.white,
size: 20,
),
),
title: Text(
news.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontWeight: FontWeight.w600,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 4),
if (news.source != null)
Row(
children: [
Icon(
Icons.public,
size: 14,
color: Colors.grey.shade600,
),
const SizedBox(width: 4),
Expanded(
child: Text(
news.source!,
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 12,
),
),
),
],
),
const SizedBox(height: 2),
Row(
children: [
Icon(
Icons.location_on,
size: 14,
color: Colors.grey.shade600,
),
const SizedBox(width: 4),
Text(
'${news.location.latitude.toStringAsFixed(2)}, ${news.location.longitude.toStringAsFixed(2)}',
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 12,
),
),
],
),
],
),
trailing: news.url != null
? IconButton(
icon: const Icon(Icons.open_in_new),
onPressed: () => _launchUrl(news.url!),
tooltip: 'Read Article',
)
: null,
onTap: () {
Navigator.of(dialogContext).pop();
onNewsMarkerTap(news);
},
),
);
},
),
),
const SizedBox(height: 12),
// Close button.
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () {
Navigator.of(dialogContext).pop();
onCloseNews();
},
icon: const Icon(Icons.close),
label: const Text('Close News'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: Colors.red.shade600,
foregroundColor: Colors.white,
),
),
),
],
),
),
),
);
}