122 lines
3.6 KiB
Dart
122 lines
3.6 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:geolocator/geolocator.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import '../models/weather.dart';
|
|
|
|
class WeatherService {
|
|
static const String _apiKey = 'f4ae82990f834955a0385536251808';
|
|
static const String _baseUrl = 'https://api.weatherapi.com/v1';
|
|
|
|
// 获取当前天气
|
|
Future<Weather?> getCurrentWeather({String? location}) async {
|
|
try {
|
|
String query = location ?? await _getCurrentLocation();
|
|
|
|
final url = Uri.parse(
|
|
'$_baseUrl/current.json?key=$_apiKey&q=$query&aqi=yes',
|
|
);
|
|
final response = await http.get(url);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body);
|
|
return Weather.fromJson(data);
|
|
} else {
|
|
debugPrint('天气API错误: ${response.statusCode} - ${response.body}');
|
|
return null;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('获取天气数据失败: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 获取天气预报
|
|
Future<List<WeatherForecast>> getWeatherForecast({
|
|
String? location,
|
|
int days = 3,
|
|
}) async {
|
|
try {
|
|
String query = location ?? await _getCurrentLocation();
|
|
|
|
final url = Uri.parse(
|
|
'$_baseUrl/forecast.json?key=$_apiKey&q=$query&days=$days&aqi=no&alerts=no',
|
|
);
|
|
final response = await http.get(url);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body);
|
|
final forecastDays = data['forecast']['forecastday'] as List;
|
|
|
|
return forecastDays
|
|
.map((day) => WeatherForecast.fromJson(day))
|
|
.toList();
|
|
} else {
|
|
debugPrint('天气预报API错误: ${response.statusCode} - ${response.body}');
|
|
return [];
|
|
}
|
|
} catch (e) {
|
|
debugPrint('获取天气预报失败: $e');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// 搜索城市
|
|
Future<List<Map<String, dynamic>>> searchLocations(String query) async {
|
|
try {
|
|
final url = Uri.parse('$_baseUrl/search.json?key=$_apiKey&q=$query');
|
|
final response = await http.get(url);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body) as List;
|
|
return data.cast<Map<String, dynamic>>();
|
|
} else {
|
|
debugPrint('城市搜索API错误: ${response.statusCode} - ${response.body}');
|
|
return [];
|
|
}
|
|
} catch (e) {
|
|
debugPrint('搜索城市失败: $e');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// 获取当前位置
|
|
Future<String> _getCurrentLocation() async {
|
|
try {
|
|
// 检查位置权限
|
|
final permission = await Permission.location.request();
|
|
if (permission != PermissionStatus.granted) {
|
|
return 'London'; // 默认位置
|
|
}
|
|
|
|
// 检查位置服务是否启用
|
|
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
|
if (!serviceEnabled) {
|
|
return 'New York'; // 默认位置
|
|
}
|
|
|
|
// 获取当前位置
|
|
Position position = await Geolocator.getCurrentPosition(
|
|
desiredAccuracy: LocationAccuracy.low,
|
|
timeLimit: const Duration(seconds: 10),
|
|
);
|
|
|
|
return '${position.latitude},${position.longitude}';
|
|
} catch (e) {
|
|
debugPrint('获取位置失败: $e');
|
|
return 'New York'; // 默认位置
|
|
}
|
|
}
|
|
|
|
// 根据城市名获取天气
|
|
Future<Weather?> getWeatherByCity(String cityName) async {
|
|
return await getCurrentWeather(location: cityName);
|
|
}
|
|
|
|
// 根据坐标获取天气
|
|
Future<Weather?> getWeatherByCoordinates(double lat, double lon) async {
|
|
return await getCurrentWeather(location: '$lat,$lon');
|
|
}
|
|
}
|