@@ -9,6 +9,7 @@ import '../../core/di/injection.dart';
99import '../../l10n/app_localizations.dart' ;
1010import '../../models/discount_type.dart' ;
1111import '../../models/fare_formula.dart' ;
12+ import '../../models/geocoding_provider.dart' ;
1213import '../../models/transport_mode.dart' ;
1314import '../../repositories/fare_repository.dart' ;
1415import '../../services/offline/offline_map_service.dart' ;
@@ -51,6 +52,7 @@ class _SettingsScreenState extends State<SettingsScreen>
5152 Locale _currentLocale = const Locale ('en' );
5253 bool _isLoading = true ;
5354
55+ GeocodingProvider _geocodingProvider = GeocodingProvider .nominatim;
5456 bool _offlineModeEnabled = false ;
5557 bool _autoCacheEnabled = true ;
5658 bool _autoCacheWifiOnly = true ;
@@ -113,6 +115,7 @@ class _SettingsScreenState extends State<SettingsScreen>
113115 final trafficFactor = await _settingsService.getTrafficFactor ();
114116 final themeMode = await _settingsService.getThemeMode ();
115117 final discountType = await _settingsService.getUserDiscountType ();
118+ final geocodingProvider = await _settingsService.getGeocodingProvider ();
116119 final hiddenModes = await _settingsService.getHiddenTransportModes ();
117120 final hasSetModePrefs = await _settingsService
118121 .hasSetTransportModePreferences ();
@@ -154,6 +157,7 @@ class _SettingsScreenState extends State<SettingsScreen>
154157 _themeMode = themeMode;
155158 _trafficFactor = trafficFactor;
156159 _discountType = discountType;
160+ _geocodingProvider = geocodingProvider;
157161 _currentLocale = locale;
158162 _hiddenTransportModes = hiddenModes;
159163 _hasSetTransportModePreferences = hasSetModePrefs;
@@ -230,6 +234,28 @@ class _SettingsScreenState extends State<SettingsScreen>
230234 ),
231235 const SizedBox (height: 24 ),
232236
237+ // Map API Provider Section
238+ _buildSectionHeader (
239+ context,
240+ icon: Icons .map_rounded,
241+ title: 'Map API Provider' ,
242+ ),
243+ const SizedBox (height: 8 ),
244+ _buildSettingsCard (
245+ context,
246+ children: [
247+ _buildGeocodingProviderTile (
248+ context, GeocodingProvider .nominatim),
249+ const Divider (height: 1 , indent: 56 ),
250+ _buildGeocodingProviderTile (
251+ context, GeocodingProvider .locationIQ),
252+ const Divider (height: 1 , indent: 56 ),
253+ _buildGeocodingProviderTile (
254+ context, GeocodingProvider .geoapify),
255+ ],
256+ ),
257+ const SizedBox (height: 24 ),
258+
233259 // Appearance Section
234260 _buildSectionHeader (
235261 context,
@@ -541,6 +567,59 @@ class _SettingsScreenState extends State<SettingsScreen>
541567 );
542568 }
543569
570+ Widget _buildGeocodingProviderTile (
571+ BuildContext context, GeocodingProvider provider) {
572+ final theme = Theme .of (context);
573+ final colorScheme = theme.colorScheme;
574+ final isSelected = _geocodingProvider == provider;
575+ final needsKey = provider.requiresApiKey;
576+ final keyMissing = (provider == GeocodingProvider .locationIQ &&
577+ AppConstants .locationIQApiKey == 'YOUR_LOCATIONIQ_API_KEY' ) ||
578+ (provider == GeocodingProvider .geoapify &&
579+ AppConstants .geoapifyApiKey == 'YOUR_GEOAPIFY_API_KEY' );
580+
581+ return ListTile (
582+ leading: Icon (
583+ Icons .language_rounded,
584+ color: isSelected ? colorScheme.primary : colorScheme.onSurfaceVariant,
585+ ),
586+ title: Text (
587+ provider.displayName,
588+ style: theme.textTheme.bodyLarge? .copyWith (
589+ fontWeight: isSelected ? FontWeight .w600 : FontWeight .normal,
590+ color: isSelected ? colorScheme.primary : colorScheme.onSurface,
591+ ),
592+ ),
593+ subtitle: Column (
594+ crossAxisAlignment: CrossAxisAlignment .start,
595+ children: [
596+ Text (
597+ provider.description,
598+ style: theme.textTheme.bodySmall
599+ ? .copyWith (color: colorScheme.onSurfaceVariant),
600+ ),
601+ if (needsKey && keyMissing)
602+ Text (
603+ 'API key required — add to AppConstants' ,
604+ style: theme.textTheme.bodySmall? .copyWith (
605+ color: colorScheme.error,
606+ fontWeight: FontWeight .w500,
607+ ),
608+ ),
609+ ],
610+ ),
611+ trailing: isSelected
612+ ? Icon (Icons .check_circle_rounded, color: colorScheme.primary)
613+ : null ,
614+ onTap: needsKey && keyMissing
615+ ? null
616+ : () async {
617+ setState (() => _geocodingProvider = provider);
618+ await _settingsService.setGeocodingProvider (provider);
619+ },
620+ );
621+ }
622+
544623 /// Builds a section header with icon and title.
545624 Widget _buildSectionHeader (
546625 BuildContext context, {
0 commit comments