Files
tuiche/lib/controller/weather/weather_controller.dart
2025-11-14 12:01:07 +08:00

724 lines
25 KiB
Dart
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// import 'dart:async';
// import 'package:EasyDartModule/EasyDartModule.dart';
// import 'package:ef/ef.dart';
// import 'package:flutter/material.dart';
// import 'package:geocoding/geocoding.dart';
// import 'package:geolocator/geolocator.dart';
// import 'package:json_annotation/json_annotation.dart';
// import 'package:path/path.dart';
// import 'package:vbvs_app/common/color/ServiceConstant.dart';
// import 'package:vbvs_app/common/color/appConstants.dart';
// import 'package:vbvs_app/common/util/CommonVariables.dart';
// import 'package:vbvs_app/common/util/MyUtils.dart';
// import 'package:vbvs_app/common/util/requestWithLog.dart';
// import 'package:vbvs_app/controller/setting/language/language_controller.dart';
// import 'package:vbvs_app/controller/user_info_controller.dart';
// import 'package:vbvs_app/enum/APPPackageType.dart';
// import 'package:vbvs_app/pages/common/selectDialog.dart';
// import 'package:weather/weather.dart';
// part 'weather_controller.g.dart';
// @JsonSerializable()
// class WeatherModel {
// double? longitude; // 经度
// double? latitude; // 纬度
// String? weather_info = ''; // 天气
// int? current_temperature; // 温度
// int? min_temperature; // 最低温度
// int? max_temperature; // 最高温度
// String? wind_direction; // 风向
// int? wind_speed; // 风速等级
// String? cityName; // 城市名
// String? weatherIcon; // 天气图标
// String? weatherIconurl; // 天气图标url
// WeatherModel();
// static WeatherModel fromJson(Map<String, dynamic> json) =>
// _$WeatherModelFromJson(json);
// Map<String, dynamic> toJson() => _$WeatherModelToJson(this);
// }
// class WeatherModelController extends GetControllerEx<WeatherModel> {
// LanguageController languageController = Get.find();
// WeatherModelController() {
// attr = GetModel(WeatherModel()).obs;
// weatherFactory = WeatherFactory(CommonVariables.weather_apiKey,
// language: Language.CHINESE_SIMPLIFIED);
// }
// Timer? _weatherTimer;
// Timer? _locationTimer;
// late WeatherFactory weatherFactory;
// @override
// Future<void> onInit() async {
// super.onInit();
// try {
// await getCurrentLocation();
// _weatherTimer = Timer.periodic(Duration(minutes: 10), (timer) {
// getCurrentWeather(); // 每 60 秒更新一次天气
// });
// _locationTimer = Timer.periodic(Duration(minutes: 10), (timer) {
// getCurrentLocation(); // 每 10 分钟更新一次位置
// });
// } catch (e) {
// ef.log("[天气和定位请求失败]");
// }
// }
// @override
// void onClose() {
// _weatherTimer?.cancel(); // 取消天气更新定时器
// _locationTimer?.cancel(); // 取消位置更新定时器
// super.onClose();
// }
// // 获取当前位置并存储到 model
// Future<void> getCurrentLocation() async {
// try {
// UserInfoController userInfoController = Get.find();
// if (userInfoController.model.login == null ||
// userInfoController.model.login != 1) {
// return;
// }
// Position position = await determinePosition();
// if (position == null) {
// throw Exception("获取位置失败");
// }
// String? language = "zh_CN";
// if (AppConstants().ent_type == APPPackageType.MHT.code) {
// if (mhLanguageController.selectLanguage != null) {
// language = mhLanguageController.selectLanguage.value!.language_code;
// }
// } else {
// if (languageController.selectLanguage != null) {
// language = languageController.selectLanguage.value!.language_code;
// }
// }
// List<Placemark> placemarks = [];
// // placemarks = await placemarkFromCoordinates(position.latitude, position.longitude,
// // localeIdentifier: language);
// placemarks = await placemarkFromCoordinates(
// position.latitude,
// position.longitude,
// );
// if (placemarks.isNotEmpty) {
// // model.cityName = placemarks[0].locality ?? "未知数据".tr;
// model.latitude = position.latitude;
// model.longitude = position.longitude;
// }
// // 调用获取天气方法
// // getCurrentWeather();
// } catch (e) {
// print(e);
// EasyDartModule.logger.error("获取位置失败: $e");
// }
// }
// // 获取当前位置
// // Future<Position> determinePosition() async {
// // bool serviceEnabled;
// // LocationPermission permission;
// // serviceEnabled = await Geolocator.isLocationServiceEnabled();
// // if (!serviceEnabled) {
// // return Future.error('位置服务未启用');
// // }
// // try {
// // showPermissionInfoDialog(
// // Get.context!, CommonVariables().locationpermissionInfo);
// // } catch (e) {
// // ef.log("$e");
// // }
// // try {
// // // 2⃣ 检查权限(系统弹窗)—— 此时你的提示框仍然显示
// // permission = await Geolocator.checkPermission();
// // if (permission == LocationPermission.denied) {
// // permission = await Geolocator.requestPermission();
// // }
// // } finally {
// // // 3⃣ 无论如何都关闭你的提示弹窗
// // Navigator.of(Get.context!, rootNavigator: true).pop();
// // }
// // if (permission == LocationPermission.denied) {
// // return Future.error('位置权限被拒绝');
// // }
// // if (permission == LocationPermission.deniedForever) {
// // return Future.error('位置权限被永久拒绝');
// // }
// // return await Geolocator.getCurrentPosition(
// // forceAndroidLocationManager: true,
// // locationSettings: const LocationSettings(
// // accuracy: LocationAccuracy.best,
// // distanceFilter: 1000, // 设置最小距离过滤
// // timeLimit: Duration(seconds: 10), // 设置获取位置的最大等待时间
// // ),
// // );
// // }
// Future<Position> determinePosition({int retryCount = 1}) async {
// bool serviceEnabled;
// LocationPermission permission;
// int attempt = 0;
// bool dialogShown = false;
// // 检查定位服务是否启用
// serviceEnabled = await Geolocator.isLocationServiceEnabled();
// if (!serviceEnabled) {
// return Future.error('位置服务未启用');
// }
// try {
// // 弹出自定义提示
// // 检查和请求位置权限
// permission = await Geolocator.checkPermission();
// if (permission == LocationPermission.denied) {
// showPermissionInfoDialog(
// Get.context!, CommonVariables().locationpermissionInfo);
// dialogShown = true;
// await Future.delayed(const Duration(milliseconds: 300));
// // 系统权限弹窗
// permission = await Geolocator.requestPermission();
// }
// } catch (e) {
// ef.log("申请位置权限出错: $e");
// rethrow;
// } finally {
// if (dialogShown) {
// if (Get.isDialogOpen ?? false) {
// Get.back(); // 关闭弹窗
// }
// }
// }
// // 如果权限被拒绝,直接返回错误
// if (permission == LocationPermission.denied) {
// return Future.error('位置权限被拒绝');
// }
// // 如果权限被永久拒绝,直接返回错误
// if (permission == LocationPermission.deniedForever) {
// return Future.error('位置权限被永久拒绝');
// }
// // 开始获取位置,最多重试 retryCount 次
// while (attempt < retryCount) {
// attempt++;
// try {
// // 设置定位精度
// LocationAccuracy accuracy = attempt == 1
// ? LocationAccuracy.medium // 初次尝试用中等精度
// : LocationAccuracy.best; // 如果第一次失败,尝试高精度定位
// return await Geolocator.getCurrentPosition(
// forceAndroidLocationManager: true,
// locationSettings: LocationSettings(
// accuracy: accuracy,
// distanceFilter: 1000,
// timeLimit: Duration(seconds: 10),
// ),
// );
// } catch (e) {
// if (attempt >= retryCount) {
// return Future.error('获取位置失败: $e');
// }
// await Future.delayed(Duration(seconds: 2)); // 重试前等待
// }
// }
// return Future.error('获取位置失败,已重试 $retryCount 次');
// }
// // 获取天气信息
// // Future<void> getCurrentWeather() async {
// // await getCurrentLocation();
// // if (model.latitude == null || model.longitude == null) {
// // EasyDartModule.logger.error("获取天气失败:位置数据获取失败");
// // return; // 如果位置数据没有获取到,则不更新天气
// // }
// // try {
// // weatherFactory.language = Language.CHINESE_SIMPLIFIED;
// // String? language = "zh_CN";
// // if (AppConstants().ent_type == APPPackageType.MHT.code) {
// // if (mhLanguageController.selectLanguage != null) {
// // language = mhLanguageController.selectLanguage.value!.language_code;
// // }
// // } else {
// // if (languageController.selectLanguage != null) {
// // language = languageController.selectLanguage.value!.language_code;
// // }
// // }
// // if (language == "zh_CN") {
// // weatherFactory.language = Language.CHINESE_SIMPLIFIED;
// // } else {
// // weatherFactory.language = Language.ENGLISH;
// // }
// // // Weather weather = await weatherFactory.currentWeatherByLocation(
// // // model.latitude!, model.longitude!);
// // String location = "${model.longitude},${model.latitude}";
// // String serviceAddress = ServiceConstant.service_address;
// // String serviceName = ServiceConstant.server_service;
// // String serviceApi = ServiceConstant.weather_url;
// // String queryUrl =
// // "${serviceAddress}${serviceName}${serviceApi}?location=$location";
// // await requestWithLog(
// // logTitle: "获取天气信息",
// // method: MyHttpMethod.get,
// // queryUrl: queryUrl,
// // onSuccess: (res) {
// // print(res.data);
// // model.weather_info = res.data["info"];
// // model.current_temperature = int.parse(res.data["temp"]);
// // if (res.data['icon'] != null) {
// // model.weatherIconurl = "${res.data['icon']}";
// // }
// // model.cityName = res.data["city"];
// // },
// // onFailure: (res) {
// // print(res.data);
// // });
// // updateAll(); // 更新 UI
// // } catch (e) {
// // EasyDartModule.logger.error("获取天气失败: $e");
// // print('获取天气失败: $e');
// // }
// // }
// Future<void> getCurrentWeather({int retryCount = 1}) async {
// int attempt = 0;
// bool success = false;
// while (attempt < retryCount && success == false) {
// attempt++;
// try {
// // 先尝试获取定位
// await getCurrentLocation();
// if (model.latitude == null || model.longitude == null) {
// EasyDartModule.logger.error("获取天气失败: 位置数据获取失败 (第$attempt次)");
// if (attempt >= retryCount) return; // 重试到上限退出
// await Future.delayed(Duration(seconds: 2)); // 延时再试
// continue;
// }
// // 设置语言
// String? language = "zh_CN";
// if (AppConstants().ent_type == APPPackageType.MHT.code) {
// if (mhLanguageController.selectLanguage != null) {
// language = mhLanguageController.selectLanguage.value!.language_code;
// }
// } else {
// if (languageController.selectLanguage != null) {
// language = languageController.selectLanguage.value!.language_code;
// }
// }
// weatherFactory.language = (language == "zh_CN")
// ? Language.CHINESE_SIMPLIFIED
// : Language.ENGLISH;
// // 拼接天气请求地址
// String location = "${model.longitude},${model.latitude}";
// String serviceAddress = ServiceConstant.service_address;
// String serviceName = ServiceConstant.server_service;
// String serviceApi = ServiceConstant.weather_url;
// String queryUrl =
// "$serviceAddress$serviceName$serviceApi?location=$location";
// await requestWithLog(
// logTitle: "获取天气信息 (第$attempt次)",
// method: MyHttpMethod.get,
// queryUrl: queryUrl,
// onSuccess: (res) {
// try {
// print(res.data);
// model.weather_info = res.data["info"];
// model.current_temperature = int.parse(res.data["temp"]);
// if (res.data['icon'] != null) {
// model.weatherIconurl = "${res.data['icon']}";
// }
// model.cityName = res.data["city"];
// success = true;
// } catch (e) {
// EasyDartModule.logger.error("天气数据解析失败: $e");
// }
// },
// onFailure: (res) {
// EasyDartModule.logger.error("获取天气接口失败: ${res.data}");
// },
// );
// if (success) {
// updateAll(); // 更新 UI
// return; // ✅ 成功了直接返回
// }
// } catch (e) {
// EasyDartModule.logger.error("获取天气异常 (第$attempt次): $e");
// }
// // 如果还没成功,延迟后重试
// if (attempt < retryCount) {
// await Future.delayed(Duration(seconds: 2));
// }
// }
// EasyDartModule.logger.error("获取天气失败: 已重试 $retryCount 次仍然失败");
// }
// // 获取 5 天天气预报
// Future<List<Weather>> getWeatherForecast(
// double latitude, double longitude) async {
// try {
// return await weatherFactory.fiveDayForecastByLocation(
// latitude, longitude);
// } catch (e) {
// print('获取天气预报失败: $e');
// rethrow;
// }
// }
// }
import 'dart:async';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:path/path.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/common/util/requestWithLog.dart';
import 'package:vbvs_app/controller/setting/language/language_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/enum/APPPackageType.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
import 'package:weather/weather.dart';
part 'weather_controller.g.dart';
@JsonSerializable()
class WeatherModel {
double? longitude; // 经度
double? latitude; // 纬度
String? weather_info = ''; // 天气
int? current_temperature; // 温度
int? min_temperature; // 最低温度
int? max_temperature; // 最高温度
String? wind_direction; // 风向
int? wind_speed; // 风速等级
String? cityName; // 城市名
String? weatherIcon; // 天气图标
String? weatherIconurl; // 天气图标url
WeatherModel();
static WeatherModel fromJson(Map<String, dynamic> json) =>
_$WeatherModelFromJson(json);
Map<String, dynamic> toJson() => _$WeatherModelToJson(this);
}
class WeatherModelController extends GetControllerEx<WeatherModel> {
LanguageController languageController = Get.find();
WeatherModelController() {
attr = GetModel(WeatherModel()).obs;
weatherFactory = WeatherFactory(CommonVariables.weather_apiKey,
language: Language.CHINESE_SIMPLIFIED);
}
Timer? _weatherTimer;
Timer? _locationTimer;
// 添加状态变量来跟踪权限请求状态
bool _isRequestingPermission = false;
bool _hasShownPermissionDialog = false;
late WeatherFactory weatherFactory;
@override
Future<void> onInit() async {
super.onInit();
//去掉天气
// try {
// await getCurrentLocation();
// _weatherTimer = Timer.periodic(Duration(minutes: 10), (timer) {
// getCurrentWeather(); // 每 60 秒更新一次天气
// });
// _locationTimer = Timer.periodic(Duration(minutes: 10), (timer) {
// getCurrentLocation(); // 每 10 分钟更新一次位置
// });
// } catch (e) {
// ef.log("[天气和定位请求失败]");
// }
}
@override
void onClose() {
_weatherTimer?.cancel(); // 取消天气更新定时器
_locationTimer?.cancel(); // 取消位置更新定时器
super.onClose();
}
// 获取当前位置并存储到 model
Future<void> getCurrentLocation() async {
try {
UserInfoController userInfoController = Get.find();
if (userInfoController.model.login == null ||
userInfoController.model.login != 1) {
return;
}
Position position = await determinePosition();
if (position == null) {
throw Exception("获取位置失败");
}
String? language = "zh_CN";
if (AppConstants().ent_type == APPPackageType.MHT.code) {
if (mhLanguageController.selectLanguage != null) {
language = mhLanguageController.selectLanguage.value!.language_code;
}
} else {
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
}
List<Placemark> placemarks = [];
// placemarks = await placemarkFromCoordinates(position.latitude, position.longitude,
// localeIdentifier: language);
placemarks = await placemarkFromCoordinates(
position.latitude,
position.longitude,
);
if (placemarks.isNotEmpty) {
// model.cityName = placemarks[0].locality ?? "未知数据".tr;
model.latitude = position.latitude;
model.longitude = position.longitude;
}
// 调用获取天气方法
// getCurrentWeather();
} catch (e) {
print(e);
EasyDartModule.logger.error("获取位置失败: $e");
}
}
// 获取当前位置
Future<Position> determinePosition({int retryCount = 1}) async {
bool serviceEnabled;
LocationPermission permission;
int attempt = 0;
bool dialogShown = false;
Completer<void>? dialogCompleter;
// 检查定位服务是否启用
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('位置服务未启用');
}
// 检查当前权限状态
permission = await Geolocator.checkPermission();
// 如果权限已经被授予,直接获取位置
if (permission == LocationPermission.always ||
permission == LocationPermission.whileInUse) {
return await _getPositionWithRetry(retryCount);
}
// 如果权限被永久拒绝,直接返回错误
if (permission == LocationPermission.deniedForever) {
return Future.error('位置权限被永久拒绝');
}
// 如果正在请求权限,避免重复请求
if (_isRequestingPermission) {
return Future.error('权限请求正在进行中');
}
// 权限被拒绝或未请求过,需要请求权限
try {
_isRequestingPermission = true;
if (!_hasShownPermissionDialog) {
showPermissionInfoDialog(
Get.context!,
CommonVariables().locationpermissionInfo,
);
_hasShownPermissionDialog = true;
}
// 等待系统弹窗结果(期间自定义弹窗仍显示在屏幕上)
permission = await Geolocator.requestPermission();
// 系统弹窗关闭后继续执行,关闭自定义弹窗
if (_hasShownPermissionDialog) {
Get.back();
}
} catch (e) {
ef.log("申请位置权限出错: $e");
rethrow;
} finally {
_isRequestingPermission = false;
}
// 检查请求后的权限状态
if (permission == LocationPermission.denied) {
return Future.error('位置权限被拒绝');
}
if (permission == LocationPermission.deniedForever) {
return Future.error('位置权限被永久拒绝');
}
// 权限已授予,获取位置
return await _getPositionWithRetry(retryCount);
}
// 提取获取位置的重复代码到单独的方法
Future<Position> _getPositionWithRetry(int retryCount) async {
int attempt = 0;
while (attempt < retryCount) {
attempt++;
try {
// 设置定位精度
LocationAccuracy accuracy = attempt == 1
? LocationAccuracy.medium // 初次尝试用中等精度
: LocationAccuracy.best; // 如果第一次失败,尝试高精度定位
return await Geolocator.getCurrentPosition(
forceAndroidLocationManager: true,
locationSettings: LocationSettings(
accuracy: accuracy,
distanceFilter: 1000,
timeLimit: Duration(seconds: 10),
),
);
} catch (e) {
if (attempt >= retryCount) {
return Future.error('获取位置失败: $e');
}
await Future.delayed(Duration(seconds: 2)); // 重试前等待
}
}
return Future.error('获取位置失败,已重试 $retryCount');
}
// 获取天气信息
Future<void> getCurrentWeather({int retryCount = 1}) async {
int attempt = 0;
bool success = false;
while (attempt < retryCount && success == false) {
attempt++;
try {
// 先尝试获取定位
await getCurrentLocation();
if (model.latitude == null || model.longitude == null) {
EasyDartModule.logger.error("获取天气失败: 位置数据获取失败 (第$attempt次)");
if (attempt >= retryCount) return; // 重试到上限退出
await Future.delayed(Duration(seconds: 2)); // 延时再试
continue;
}
// 设置语言
String? language = "zh_CN";
if (AppConstants().ent_type == APPPackageType.MHT.code) {
if (mhLanguageController.selectLanguage != null) {
language = mhLanguageController.selectLanguage.value!.language_code;
}
} else {
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
}
weatherFactory.language = (language == "zh_CN")
? Language.CHINESE_SIMPLIFIED
: Language.ENGLISH;
// 拼接天气请求地址
String location = "${model.longitude},${model.latitude}";
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.weather_url;
String queryUrl =
"$serviceAddress$serviceName$serviceApi?location=$location";
await requestWithLog(
logTitle: "获取天气信息 (第$attempt次)",
method: MyHttpMethod.get,
queryUrl: queryUrl,
onSuccess: (res) {
try {
print(res.data);
model.weather_info = res.data["info"];
model.current_temperature = int.parse(res.data["temp"]);
if (res.data['icon'] != null) {
model.weatherIconurl = "${res.data['icon']}";
}
model.cityName = res.data["city"];
success = true;
} catch (e) {
EasyDartModule.logger.error("天气数据解析失败: $e");
}
},
onFailure: (res) {
EasyDartModule.logger.error("获取天气接口失败: ${res.data}");
},
);
if (success) {
updateAll(); // 更新 UI
return; // ✅ 成功了直接返回
}
} catch (e) {
EasyDartModule.logger.error("获取天气异常 (第$attempt次): $e");
}
// 如果还没成功,延迟后重试
if (attempt < retryCount) {
await Future.delayed(Duration(seconds: 2));
}
}
EasyDartModule.logger.error("获取天气失败: 已重试 $retryCount 次仍然失败");
}
// 获取 5 天天气预报
Future<List<Weather>> getWeatherForecast(
double latitude, double longitude) async {
try {
return await weatherFactory.fiveDayForecastByLocation(
latitude, longitude);
} catch (e) {
print('获取天气预报失败: $e');
rethrow;
}
}
// 重置权限状态(可选,用于测试或特定场景)
void resetPermissionState() {
_isRequestingPermission = false;
_hasShownPermissionDialog = false;
}
}