AtmoSphere/lib/providers/city_provider.dart
2026-01-16 18:22:32 +08:00

181 lines
5.0 KiB
Dart

import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/city_model.dart';
import '../constants.dart';
// SharedPreferences Provider
final sharedPreferencesProvider = Provider<Future<SharedPreferences>>((
ref,
) async {
return SharedPreferences.getInstance();
});
// 城市列表 Provider
final cityListProvider = NotifierProvider<CityListNotifier, List<CityModel>>(
() {
final notifier = CityListNotifier();
notifier._initialize();
return notifier;
},
);
class CityListNotifier extends Notifier<List<CityModel>> {
static const String _citiesKey = 'saved_cities';
static const String _currentCityKey = 'current_city';
bool _initialized = false;
@override
List<CityModel> build() {
if (!_initialized) {
_initialize();
}
return [];
}
// 初始化加载城市列表
Future<void> _initialize() async {
if (_initialized) return;
_initialized = true;
await _loadCities();
}
// 加载保存的城市列表
Future<void> _loadCities() async {
final prefs = await SharedPreferences.getInstance();
final citiesJson = prefs.getStringList(_citiesKey);
if (citiesJson != null && citiesJson.isNotEmpty) {
final cities = citiesJson
.map((json) => CityModel.fromJson(jsonDecode(json)))
.toList();
state = cities;
} else {
// 如果没有保存的城市,添加默认城市
final defaultCityModel = CityModel(
name: defaultCity.split(',').first.trim(),
query: defaultCity,
isDefault: true,
);
state = [defaultCityModel];
await _saveCities();
}
}
// 保存城市列表
Future<void> _saveCities() async {
final prefs = await SharedPreferences.getInstance();
final citiesJson = state.map((city) => jsonEncode(city.toJson())).toList();
await prefs.setStringList(_citiesKey, citiesJson);
}
// 添加城市
Future<bool> addCity(CityModel city) async {
// 检查是否已存在
if (state.any((c) => c.query.toLowerCase() == city.query.toLowerCase())) {
return false; // 城市已存在
}
// 如果这是第一个城市,设为默认
final newCity = state.isEmpty
? city.copyWith(isDefault: true)
: city.copyWith(isDefault: false);
state = [...state, newCity];
await _saveCities();
return true;
}
// 获取当前状态
List<CityModel> get currentState => state;
// 删除城市
Future<void> removeCity(String query) async {
if (state.length <= 1) {
return; // 至少保留一个城市
}
final cityToRemove = state.firstWhere((c) => c.query == query);
final wasDefault = cityToRemove.isDefault;
state = state.where((c) => c.query != query).toList();
// 如果删除的是默认城市,将第一个城市设为默认
if (wasDefault && state.isNotEmpty) {
state = [state.first.copyWith(isDefault: true), ...state.skip(1)];
await setCurrentCity(state.first.query);
}
await _saveCities();
}
// 设置当前城市
Future<void> setCurrentCity(String query) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_currentCityKey, query);
// 更新默认标记
state = state.map((city) {
return city.copyWith(isDefault: city.query == query);
}).toList();
await _saveCities();
}
// 获取当前城市
Future<String> getCurrentCity() async {
// 确保已初始化
if (!_initialized) {
await _initialize();
}
// 如果 state 为空,等待加载完成
if (state.isEmpty) {
await _loadCities();
}
final prefs = await SharedPreferences.getInstance();
final currentCityQuery = prefs.getString(_currentCityKey);
if (currentCityQuery != null &&
state.any((c) => c.query == currentCityQuery)) {
return currentCityQuery;
}
// 如果没有当前城市或当前城市不在列表中,返回默认城市
if (state.isEmpty) {
// 如果仍然为空,返回默认城市查询字符串
return defaultCity;
}
final defaultCityModel = state.firstWhere(
(c) => c.isDefault,
orElse: () => state.first,
);
return defaultCityModel.query;
}
// 通过查询字符串查找城市
CityModel? findCityByQuery(String query) {
try {
return state.firstWhere(
(c) => c.query.toLowerCase() == query.toLowerCase(),
);
} catch (e) {
return null;
}
}
}
// 当前城市 Provider
final currentCityProvider = FutureProvider<String>((ref) async {
final cityListNotifier = ref.read(cityListProvider.notifier);
return await cityListNotifier.getCurrentCity();
});
// 城市列表 Notifier 扩展方法
extension CityListNotifierExtension on CityListNotifier {
Future<void> addCityAsync(CityModel city) => addCity(city);
Future<void> removeCityAsync(String query) => removeCity(query);
Future<void> setCurrentCityAsync(String query) => setCurrentCity(query);
}