import 'dart:convert'; import 'dart:math'; import 'package:http/http.dart' as http; /// Fetches public web API data used to build question text and answers. class ExternalDataFetcher { ExternalDataFetcher({http.Client? client}) : _client = client ?? http.Client(); final http.Client _client; final Random _random = Random(); /// Random country with population (millions) and capital for trivia questions. Future fetchRandomCountry() async { final http.Response response = await _client.get( Uri.parse( 'https://restcountries.com/v3.1/all?fields=name,population,capital', ), ); if (response.statusCode != 200) { return null; } final List countries = jsonDecode(response.body) as List; if (countries.isEmpty) { return null; } for (int attempt = 0; attempt < 8; attempt++) { final Map raw = countries[_random.nextInt(countries.length)] as Map; final int? population = raw['population'] as int?; final List? capitals = raw['capital'] as List?; final Map? nameMap = raw['name'] as Map?; final String? commonName = nameMap?['common'] as String?; if (population == null || population < 500_000 || capitals == null || capitals.isEmpty || commonName == null) { continue; } return CountryFacts( name: commonName, populationMillions: (population / 1_000_000).round(), capital: capitals.first as String, ); } return null; } /// Current temperature (°C, rounded) for a European city via Open-Meteo. Future fetchRandomCityWeather() async { const List<({String city, double lat, double lon})> cities = <({String city, double lat, double lon})>[ (city: 'Berlin', lat: 52.52, lon: 13.41), (city: 'Paris', lat: 48.86, lon: 2.35), (city: 'Madrid', lat: 40.42, lon: -3.70), (city: 'Rome', lat: 41.90, lon: 12.50), (city: 'Amsterdam', lat: 52.37, lon: 4.90), ]; final ({String city, double lat, double lon}) pick = cities[_random.nextInt(cities.length)]; final Uri uri = Uri.parse( 'https://api.open-meteo.com/v1/forecast' '?latitude=${pick.lat}&longitude=${pick.lon}' '¤t=temperature_2m&timezone=auto', ); final http.Response response = await _client.get(uri); if (response.statusCode != 200) { return null; } final Map json = jsonDecode(response.body) as Map; final Map? current = json['current'] as Map?; final num? temp = current?['temperature_2m'] as num?; if (temp == null) { return null; } return WeatherFacts( city: pick.city, temperatureCelsius: temp.round(), ); } void close() => _client.close(); } class CountryFacts { CountryFacts({ required this.name, required this.populationMillions, required this.capital, }); final String name; final int populationMillions; final String capital; } class WeatherFacts { WeatherFacts({ required this.city, required this.temperatureCelsius, }); final String city; final int temperatureCelsius; }