import 'package:flutter/material.dart'; import '../../core/region/region_config.dart'; import '../../l10n/app_localizations.dart'; import '../sources/sources_screen.dart'; /// Always-visible credits for whatever is currently drawn on the map. /// /// This is a licence obligation, not decoration: OpenStreetMap's ODbL and /// Radar-DPC's CC BY-SA both require the credit to be shown wherever the data /// is. It is therefore never collapsed, hidden behind a gesture, or covered by /// another control, and it lists only the sources actually on screen — crediting /// OpenStreetMap while showing the offline fallback would be a false claim. class AttributionBar extends StatelessWidget { const AttributionBar({ required this.region, required this.activeSourceIds, this.additionalCredits = const [], this.showBaseMapNotice = false, super.key, }); final RegionConfig region; /// Attribution ids, matching `attributions[].id` in the region config, for /// the data currently rendered. final Set activeSourceIds; /// Credits that travel with the data rather than with the region, such as the /// attribution line inside a radar manifest. Whoever published those frames /// states there who to credit for them, which is more current than anything /// baked into the app. final List additionalCredits; /// Whether to say that no base map is configured. True when the offline /// fallback style is in use, so the placeholder is never mistaken for a map. final bool showBaseMapNotice; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final theme = Theme.of(context); final credits = region.attributions .where((attribution) => activeSourceIds.contains(attribution.id)) .map((attribution) => attribution.text) .toList(growable: false); final parts = [ if (showBaseMapNotice) l10n.baseMapNotConfigured, ...credits, ...additionalCredits.where((credit) => credit.isNotEmpty), ]; return Material( color: theme.colorScheme.surface.withValues(alpha: 0.85), child: InkWell( onTap: () => Navigator.of( context, ).push(MaterialPageRoute(builder: (_) => const SourcesScreen())), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), child: Row( children: [ Expanded( child: Text( parts.join(' · '), style: theme.textTheme.bodySmall, maxLines: 2, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), Text( l10n.sourcesLink, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.primary, fontWeight: FontWeight.w600, ), ), Icon( Icons.chevron_right, size: 16, color: theme.colorScheme.primary, ), ], ), ), ), ); } }