2023-09-08 18:55:26 +03:00
|
|
|
import 'dart:io';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:flutter/material.dart';
|
2023-09-08 18:55:26 +03:00
|
|
|
import 'package:flutter/services.dart';
|
2023-10-06 20:20:43 +03:00
|
|
|
import 'package:flutter_timezone/flutter_timezone.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:geocoding/geocoding.dart';
|
|
|
|
import 'package:geolocator/geolocator.dart';
|
|
|
|
import 'package:get/get.dart';
|
2023-10-01 22:38:43 +03:00
|
|
|
import 'package:home_widget/home_widget.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:isar/isar.dart';
|
2023-10-12 11:36:18 +05:30
|
|
|
import 'package:lat_lng_to_timezone/lat_lng_to_timezone.dart' as tzmap;
|
2023-09-08 18:55:26 +03:00
|
|
|
import 'package:path_provider/path_provider.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:rain/app/api/api.dart';
|
2024-09-06 22:07:50 +03:00
|
|
|
import 'package:rain/app/data/db.dart';
|
|
|
|
import 'package:rain/app/utils/notification.dart';
|
|
|
|
import 'package:rain/app/utils/show_snack_bar.dart';
|
|
|
|
import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
|
|
|
|
import 'package:rain/app/ui/widgets/weather/status/status_weather.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:rain/main.dart';
|
2023-10-12 11:36:18 +05:30
|
|
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
2023-10-06 20:20:43 +03:00
|
|
|
import 'package:timezone/data/latest_all.dart' as tz;
|
2023-10-12 11:36:18 +05:30
|
|
|
import 'package:timezone/standalone.dart' as tz;
|
2023-10-06 20:20:43 +03:00
|
|
|
import 'package:timezone/timezone.dart' as tz;
|
2024-08-15 22:39:51 +03:00
|
|
|
import 'package:url_launcher/url_launcher.dart';
|
2023-10-03 19:23:52 +03:00
|
|
|
import 'package:workmanager/workmanager.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
|
2023-09-01 20:18:40 +03:00
|
|
|
class WeatherController extends GetxController {
|
2023-06-17 20:57:57 +03:00
|
|
|
final isLoading = true.obs;
|
|
|
|
final _district = ''.obs;
|
|
|
|
final _city = ''.obs;
|
|
|
|
final _latitude = 0.0.obs;
|
|
|
|
final _longitude = 0.0.obs;
|
|
|
|
|
|
|
|
String get district => _district.value;
|
|
|
|
String get city => _city.value;
|
|
|
|
double get latitude => _latitude.value;
|
|
|
|
double get longitude => _longitude.value;
|
|
|
|
|
|
|
|
final _mainWeather = MainWeatherCache().obs;
|
|
|
|
final _location = LocationCache().obs;
|
|
|
|
final _weatherCard = WeatherCard().obs;
|
|
|
|
|
2023-07-25 21:21:21 +03:00
|
|
|
final weatherCards = <WeatherCard>[].obs;
|
|
|
|
|
2023-06-17 20:57:57 +03:00
|
|
|
MainWeatherCache get mainWeather => _mainWeather.value;
|
|
|
|
LocationCache get location => _location.value;
|
|
|
|
WeatherCard get weatherCard => _weatherCard.value;
|
|
|
|
|
|
|
|
final hourOfDay = 0.obs;
|
|
|
|
final dayOfNow = 0.obs;
|
2023-08-04 21:19:30 +03:00
|
|
|
final itemScrollController = ItemScrollController();
|
2023-09-22 15:11:03 +03:00
|
|
|
final cacheExpiry = DateTime.now().subtract(const Duration(hours: 12));
|
2023-06-17 20:57:57 +03:00
|
|
|
|
2023-07-25 21:21:21 +03:00
|
|
|
@override
|
|
|
|
void onInit() {
|
2025-03-15 23:40:48 +03:00
|
|
|
weatherCards.assignAll(
|
|
|
|
isar.weatherCards.where().sortByIndex().findAllSync(),
|
|
|
|
);
|
2023-07-25 21:21:21 +03:00
|
|
|
super.onInit();
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
Future<Position> _determinePosition() async {
|
|
|
|
LocationPermission permission = await Geolocator.checkPermission();
|
2023-06-17 20:57:57 +03:00
|
|
|
if (permission == LocationPermission.denied) {
|
|
|
|
permission = await Geolocator.requestPermission();
|
|
|
|
if (permission == LocationPermission.denied) {
|
|
|
|
return Future.error('Location permissions are denied');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (permission == LocationPermission.deniedForever) {
|
2023-10-12 16:30:28 +03:00
|
|
|
return Future.error(
|
2025-03-15 23:40:48 +03:00
|
|
|
'Location permissions are permanently denied, we cannot request permissions.',
|
|
|
|
);
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2024-08-09 22:19:37 +03:00
|
|
|
return await Geolocator.getCurrentPosition();
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> setLocation() async {
|
|
|
|
if (settings.location) {
|
|
|
|
await getCurrentLocation();
|
|
|
|
} else {
|
2025-03-15 23:40:48 +03:00
|
|
|
final locationCity = isar.locationCaches.where().findFirstSync();
|
|
|
|
if (locationCity != null) {
|
|
|
|
await getLocation(
|
|
|
|
locationCity.lat!,
|
|
|
|
locationCity.lon!,
|
|
|
|
locationCity.district!,
|
|
|
|
locationCity.city!,
|
|
|
|
);
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> getCurrentLocation() async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2023-09-05 21:31:29 +03:00
|
|
|
showSnackBar(content: 'no_inter'.tr);
|
2023-06-17 20:57:57 +03:00
|
|
|
await readCache();
|
2023-09-09 21:15:47 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
if (!await Geolocator.isLocationServiceEnabled()) {
|
2023-09-05 21:31:29 +03:00
|
|
|
showSnackBar(
|
2023-09-09 21:15:47 +03:00
|
|
|
content: 'no_location'.tr,
|
|
|
|
onPressed: () => Geolocator.openLocationSettings(),
|
|
|
|
);
|
2023-06-17 20:57:57 +03:00
|
|
|
await readCache();
|
2023-09-09 21:15:47 +03:00
|
|
|
return;
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2023-09-09 21:15:47 +03:00
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
|
2023-09-15 15:29:45 +03:00
|
|
|
await readCache();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final position = await _determinePosition();
|
|
|
|
final placemarks = await placemarkFromCoordinates(
|
|
|
|
position.latitude,
|
|
|
|
position.longitude,
|
|
|
|
);
|
|
|
|
final place = placemarks[0];
|
2023-09-09 21:15:47 +03:00
|
|
|
|
|
|
|
_latitude.value = position.latitude;
|
|
|
|
_longitude.value = position.longitude;
|
2025-03-15 23:40:48 +03:00
|
|
|
_district.value = place.administrativeArea ?? '';
|
|
|
|
_city.value = place.locality ?? '';
|
2023-09-09 21:15:47 +03:00
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
_mainWeather.value = await WeatherAPI().getWeatherData(
|
|
|
|
_latitude.value,
|
|
|
|
_longitude.value,
|
|
|
|
);
|
2023-09-09 21:15:47 +03:00
|
|
|
|
2023-09-22 19:10:11 +03:00
|
|
|
notificationCheck();
|
2023-09-09 21:15:47 +03:00
|
|
|
await writeCache();
|
|
|
|
await readCache();
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
2024-02-11 22:00:37 +03:00
|
|
|
Future<Map> getCurrentLocationSearch() async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2024-02-11 22:00:37 +03:00
|
|
|
showSnackBar(content: 'no_inter'.tr);
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
if (!await Geolocator.isLocationServiceEnabled()) {
|
2024-02-11 22:00:37 +03:00
|
|
|
showSnackBar(
|
|
|
|
content: 'no_location'.tr,
|
|
|
|
onPressed: () => Geolocator.openLocationSettings(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final position = await _determinePosition();
|
|
|
|
final placemarks = await placemarkFromCoordinates(
|
|
|
|
position.latitude,
|
|
|
|
position.longitude,
|
|
|
|
);
|
|
|
|
final place = placemarks[0];
|
|
|
|
|
|
|
|
return {
|
|
|
|
'lat': position.latitude,
|
|
|
|
'lon': position.longitude,
|
|
|
|
'city': place.administrativeArea ?? '',
|
|
|
|
'district': place.locality ?? '',
|
|
|
|
};
|
2024-02-11 22:00:37 +03:00
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
Future<void> getLocation(
|
|
|
|
double latitude,
|
|
|
|
double longitude,
|
|
|
|
String district,
|
|
|
|
String locality,
|
|
|
|
) async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2023-09-05 21:31:29 +03:00
|
|
|
showSnackBar(content: 'no_inter'.tr);
|
2023-06-17 20:57:57 +03:00
|
|
|
await readCache();
|
2023-09-15 15:29:45 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
|
2023-09-15 15:29:45 +03:00
|
|
|
await readCache();
|
2023-09-09 21:15:47 +03:00
|
|
|
return;
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2023-09-09 21:15:47 +03:00
|
|
|
|
|
|
|
_latitude.value = latitude;
|
|
|
|
_longitude.value = longitude;
|
|
|
|
_district.value = district;
|
|
|
|
_city.value = locality;
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
_mainWeather.value = await WeatherAPI().getWeatherData(
|
|
|
|
_latitude.value,
|
|
|
|
_longitude.value,
|
|
|
|
);
|
2023-09-09 21:15:47 +03:00
|
|
|
|
2023-09-22 19:10:11 +03:00
|
|
|
notificationCheck();
|
2023-09-09 21:15:47 +03:00
|
|
|
await writeCache();
|
|
|
|
await readCache();
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> readCache() async {
|
|
|
|
MainWeatherCache? mainWeatherCache;
|
|
|
|
LocationCache? locationCache;
|
|
|
|
|
|
|
|
while (mainWeatherCache == null || locationCache == null) {
|
2023-09-18 16:26:08 +03:00
|
|
|
mainWeatherCache = isar.mainWeatherCaches.where().findFirstSync();
|
|
|
|
locationCache = isar.locationCaches.where().findFirstSync();
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
_mainWeather.value = mainWeatherCache;
|
|
|
|
_location.value = locationCache;
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
hourOfDay.value = getTime(
|
|
|
|
_mainWeather.value.time!,
|
|
|
|
_mainWeather.value.timezone!,
|
|
|
|
);
|
|
|
|
dayOfNow.value = getDay(
|
|
|
|
_mainWeather.value.timeDaily!,
|
|
|
|
_mainWeather.value.timezone!,
|
|
|
|
);
|
2023-06-17 20:57:57 +03:00
|
|
|
|
2023-10-09 11:25:06 +03:00
|
|
|
if (Platform.isAndroid) {
|
|
|
|
Workmanager().registerPeriodicTask(
|
2023-10-12 17:30:22 +03:00
|
|
|
'widgetUpdate',
|
|
|
|
'widgetBackgroundUpdate',
|
2023-10-09 11:25:06 +03:00
|
|
|
frequency: const Duration(minutes: 15),
|
|
|
|
existingWorkPolicy: ExistingWorkPolicy.update,
|
|
|
|
);
|
|
|
|
}
|
2023-10-01 22:38:43 +03:00
|
|
|
|
2023-06-17 20:57:57 +03:00
|
|
|
isLoading.value = false;
|
2023-09-09 21:15:47 +03:00
|
|
|
|
|
|
|
Future.delayed(const Duration(milliseconds: 30), () {
|
2023-06-17 20:57:57 +03:00
|
|
|
itemScrollController.scrollTo(
|
|
|
|
index: hourOfDay.value,
|
|
|
|
duration: const Duration(seconds: 2),
|
|
|
|
curve: Curves.easeInOutCubic,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> writeCache() async {
|
|
|
|
final locationCaches = LocationCache(
|
|
|
|
lat: _latitude.value,
|
|
|
|
lon: _longitude.value,
|
|
|
|
city: _city.value,
|
|
|
|
district: _district.value,
|
|
|
|
);
|
|
|
|
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.writeTxnSync(() {
|
2025-03-15 23:40:48 +03:00
|
|
|
if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.mainWeatherCaches.putSync(_mainWeather.value);
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2025-03-15 23:40:48 +03:00
|
|
|
if (isar.locationCaches.where().findAllSync().isEmpty) {
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.locationCaches.putSync(locationCaches);
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> deleteCache() async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2023-09-22 19:10:11 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
isar.writeTxnSync(() {
|
2023-10-12 16:30:28 +03:00
|
|
|
isar.mainWeatherCaches
|
|
|
|
.filter()
|
|
|
|
.timestampLessThan(cacheExpiry)
|
|
|
|
.deleteAllSync();
|
2023-09-22 19:10:11 +03:00
|
|
|
});
|
2025-03-15 23:40:48 +03:00
|
|
|
if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
|
2023-09-22 19:10:11 +03:00
|
|
|
await flutterLocalNotificationsPlugin.cancelAll();
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> deleteAll(bool changeCity) async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2023-09-09 21:15:47 +03:00
|
|
|
return;
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2023-09-09 21:15:47 +03:00
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
2023-09-22 19:10:11 +03:00
|
|
|
await flutterLocalNotificationsPlugin.cancelAll();
|
2023-09-09 21:15:47 +03:00
|
|
|
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.writeTxnSync(() {
|
2023-09-09 21:15:47 +03:00
|
|
|
if (!settings.location) {
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.mainWeatherCaches.where().deleteAllSync();
|
2023-09-09 21:15:47 +03:00
|
|
|
}
|
2025-03-15 23:40:48 +03:00
|
|
|
if (settings.location && serviceEnabled || changeCity) {
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.mainWeatherCaches.where().deleteAllSync();
|
|
|
|
isar.locationCaches.where().deleteAllSync();
|
2023-09-09 21:15:47 +03:00
|
|
|
}
|
|
|
|
});
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
2023-10-12 16:30:28 +03:00
|
|
|
Future<void> addCardWeather(
|
2025-03-15 23:40:48 +03:00
|
|
|
double latitude,
|
|
|
|
double longitude,
|
|
|
|
String city,
|
|
|
|
String district,
|
|
|
|
) async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2023-09-05 21:31:29 +03:00
|
|
|
showSnackBar(content: 'no_inter'.tr);
|
2023-09-18 18:33:43 +03:00
|
|
|
return;
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2023-09-18 18:33:43 +03:00
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final tz = tzmap.latLngToTimezoneString(latitude, longitude);
|
|
|
|
_weatherCard.value = await WeatherAPI().getWeatherCard(
|
|
|
|
latitude,
|
|
|
|
longitude,
|
|
|
|
city,
|
|
|
|
district,
|
|
|
|
tz,
|
|
|
|
);
|
2023-09-18 18:33:43 +03:00
|
|
|
isar.writeTxnSync(() {
|
|
|
|
weatherCards.add(_weatherCard.value);
|
|
|
|
isar.weatherCards.putSync(_weatherCard.value);
|
|
|
|
});
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> updateCacheCard(bool refresh) async {
|
2025-03-15 23:40:48 +03:00
|
|
|
final weatherCard =
|
|
|
|
refresh
|
|
|
|
? isar.weatherCards.where().sortByIndex().findAllSync()
|
|
|
|
: isar.weatherCards
|
|
|
|
.filter()
|
|
|
|
.timestampLessThan(cacheExpiry)
|
|
|
|
.sortByIndex()
|
|
|
|
.findAllSync();
|
|
|
|
|
|
|
|
if (!(await isOnline.value) || weatherCard.isEmpty) {
|
2023-09-22 19:10:11 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var oldCard in weatherCard) {
|
2025-03-15 23:40:48 +03:00
|
|
|
final updatedCard = await WeatherAPI().getWeatherCard(
|
|
|
|
oldCard.lat!,
|
|
|
|
oldCard.lon!,
|
|
|
|
oldCard.city!,
|
|
|
|
oldCard.district!,
|
|
|
|
oldCard.timezone!,
|
|
|
|
);
|
2023-09-22 19:10:11 +03:00
|
|
|
isar.writeTxnSync(() {
|
|
|
|
oldCard
|
|
|
|
..time = updatedCard.time
|
2023-10-15 12:29:05 +03:00
|
|
|
..weathercode = updatedCard.weathercode
|
2023-09-22 19:10:11 +03:00
|
|
|
..temperature2M = updatedCard.temperature2M
|
|
|
|
..apparentTemperature = updatedCard.apparentTemperature
|
2023-10-15 12:29:05 +03:00
|
|
|
..relativehumidity2M = updatedCard.relativehumidity2M
|
2023-09-22 19:10:11 +03:00
|
|
|
..precipitation = updatedCard.precipitation
|
|
|
|
..rain = updatedCard.rain
|
|
|
|
..surfacePressure = updatedCard.surfacePressure
|
|
|
|
..visibility = updatedCard.visibility
|
|
|
|
..evapotranspiration = updatedCard.evapotranspiration
|
|
|
|
..windspeed10M = updatedCard.windspeed10M
|
|
|
|
..winddirection10M = updatedCard.winddirection10M
|
|
|
|
..windgusts10M = updatedCard.windgusts10M
|
2023-10-15 12:29:05 +03:00
|
|
|
..cloudcover = updatedCard.cloudcover
|
|
|
|
..uvIndex = updatedCard.uvIndex
|
|
|
|
..dewpoint2M = updatedCard.dewpoint2M
|
|
|
|
..precipitationProbability = updatedCard.precipitationProbability
|
|
|
|
..shortwaveRadiation = updatedCard.shortwaveRadiation
|
2023-09-22 19:10:11 +03:00
|
|
|
..timeDaily = updatedCard.timeDaily
|
|
|
|
..weathercodeDaily = updatedCard.weathercodeDaily
|
|
|
|
..temperature2MMax = updatedCard.temperature2MMax
|
|
|
|
..temperature2MMin = updatedCard.temperature2MMin
|
|
|
|
..apparentTemperatureMax = updatedCard.apparentTemperatureMax
|
|
|
|
..apparentTemperatureMin = updatedCard.apparentTemperatureMin
|
|
|
|
..sunrise = updatedCard.sunrise
|
|
|
|
..sunset = updatedCard.sunset
|
|
|
|
..precipitationSum = updatedCard.precipitationSum
|
2023-10-12 16:30:28 +03:00
|
|
|
..precipitationProbabilityMax =
|
|
|
|
updatedCard.precipitationProbabilityMax
|
2023-09-22 19:10:11 +03:00
|
|
|
..windspeed10MMax = updatedCard.windspeed10MMax
|
|
|
|
..windgusts10MMax = updatedCard.windgusts10MMax
|
|
|
|
..uvIndexMax = updatedCard.uvIndexMax
|
|
|
|
..rainSum = updatedCard.rainSum
|
|
|
|
..winddirection10MDominant = updatedCard.winddirection10MDominant
|
|
|
|
..timestamp = DateTime.now();
|
|
|
|
|
|
|
|
isar.weatherCards.putSync(oldCard);
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final newCard = oldCard;
|
|
|
|
final oldIdx = weatherCard.indexOf(oldCard);
|
2023-09-22 19:10:11 +03:00
|
|
|
weatherCards[oldIdx] = newCard;
|
|
|
|
weatherCards.refresh();
|
|
|
|
});
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> updateCard(WeatherCard weatherCard) async {
|
2024-04-10 21:25:23 +03:00
|
|
|
if (!(await isOnline.value)) {
|
2023-09-18 18:33:43 +03:00
|
|
|
return;
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2023-09-18 18:33:43 +03:00
|
|
|
|
|
|
|
final updatedCard = await WeatherAPI().getWeatherCard(
|
2024-07-13 07:00:58 +03:00
|
|
|
weatherCard.lat!,
|
|
|
|
weatherCard.lon!,
|
2023-09-18 18:33:43 +03:00
|
|
|
weatherCard.city!,
|
|
|
|
weatherCard.district!,
|
|
|
|
weatherCard.timezone!,
|
|
|
|
);
|
|
|
|
|
|
|
|
isar.writeTxnSync(() {
|
|
|
|
weatherCard
|
|
|
|
..time = updatedCard.time
|
2023-10-15 12:29:05 +03:00
|
|
|
..weathercode = updatedCard.weathercode
|
2023-09-18 18:33:43 +03:00
|
|
|
..temperature2M = updatedCard.temperature2M
|
|
|
|
..apparentTemperature = updatedCard.apparentTemperature
|
2023-10-15 12:29:05 +03:00
|
|
|
..relativehumidity2M = updatedCard.relativehumidity2M
|
2023-09-18 18:33:43 +03:00
|
|
|
..precipitation = updatedCard.precipitation
|
|
|
|
..rain = updatedCard.rain
|
|
|
|
..surfacePressure = updatedCard.surfacePressure
|
|
|
|
..visibility = updatedCard.visibility
|
|
|
|
..evapotranspiration = updatedCard.evapotranspiration
|
|
|
|
..windspeed10M = updatedCard.windspeed10M
|
|
|
|
..winddirection10M = updatedCard.winddirection10M
|
|
|
|
..windgusts10M = updatedCard.windgusts10M
|
2023-10-15 12:29:05 +03:00
|
|
|
..cloudcover = updatedCard.cloudcover
|
|
|
|
..uvIndex = updatedCard.uvIndex
|
|
|
|
..dewpoint2M = updatedCard.dewpoint2M
|
|
|
|
..precipitationProbability = updatedCard.precipitationProbability
|
|
|
|
..shortwaveRadiation = updatedCard.shortwaveRadiation
|
2023-09-18 18:33:43 +03:00
|
|
|
..timeDaily = updatedCard.timeDaily
|
|
|
|
..weathercodeDaily = updatedCard.weathercodeDaily
|
|
|
|
..temperature2MMax = updatedCard.temperature2MMax
|
|
|
|
..temperature2MMin = updatedCard.temperature2MMin
|
|
|
|
..apparentTemperatureMax = updatedCard.apparentTemperatureMax
|
|
|
|
..apparentTemperatureMin = updatedCard.apparentTemperatureMin
|
|
|
|
..sunrise = updatedCard.sunrise
|
|
|
|
..sunset = updatedCard.sunset
|
|
|
|
..precipitationSum = updatedCard.precipitationSum
|
|
|
|
..precipitationProbabilityMax = updatedCard.precipitationProbabilityMax
|
|
|
|
..windspeed10MMax = updatedCard.windspeed10MMax
|
|
|
|
..windgusts10MMax = updatedCard.windgusts10MMax
|
|
|
|
..uvIndexMax = updatedCard.uvIndexMax
|
|
|
|
..rainSum = updatedCard.rainSum
|
|
|
|
..winddirection10MDominant = updatedCard.winddirection10MDominant
|
|
|
|
..timestamp = DateTime.now();
|
|
|
|
|
|
|
|
isar.weatherCards.putSync(weatherCard);
|
|
|
|
});
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> deleteCardWeather(WeatherCard weatherCard) async {
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.writeTxnSync(() {
|
2023-07-25 21:21:21 +03:00
|
|
|
weatherCards.remove(weatherCard);
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.weatherCards.deleteSync(weatherCard.id);
|
2023-06-17 20:57:57 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
int getTime(List<String> time, String timezone) {
|
2025-03-15 23:40:48 +03:00
|
|
|
return time.indexWhere((t) {
|
|
|
|
final dateTime = DateTime.parse(t);
|
|
|
|
return tz.TZDateTime.now(tz.getLocation(timezone)).hour ==
|
|
|
|
dateTime.hour &&
|
|
|
|
tz.TZDateTime.now(tz.getLocation(timezone)).day == dateTime.day;
|
|
|
|
});
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int getDay(List<DateTime> time, String timezone) {
|
2025-03-15 23:40:48 +03:00
|
|
|
return time.indexWhere(
|
|
|
|
(t) => tz.TZDateTime.now(tz.getLocation(timezone)).day == t.day,
|
|
|
|
);
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
2023-07-08 15:19:13 +03:00
|
|
|
|
2023-07-26 22:20:30 +03:00
|
|
|
TimeOfDay timeConvert(String normTime) {
|
2025-03-15 23:40:48 +03:00
|
|
|
final hh = normTime.endsWith('PM') ? 12 : 0;
|
|
|
|
final timeParts = normTime.split(' ')[0].split(':');
|
2023-07-26 22:20:30 +03:00
|
|
|
return TimeOfDay(
|
2025-03-15 23:40:48 +03:00
|
|
|
hour: hh + int.parse(timeParts[0]) % 24,
|
|
|
|
minute: int.parse(timeParts[1]) % 60,
|
2023-07-26 22:20:30 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-09-08 18:55:26 +03:00
|
|
|
Future<String> getLocalImagePath(String icon) async {
|
|
|
|
final directory = await getTemporaryDirectory();
|
|
|
|
final imagePath = '${directory.path}/$icon';
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final data = await rootBundle.load('assets/images/$icon');
|
|
|
|
final bytes = data.buffer.asUint8List();
|
2023-09-08 18:55:26 +03:00
|
|
|
|
|
|
|
await File(imagePath).writeAsBytes(bytes);
|
|
|
|
|
|
|
|
return imagePath;
|
|
|
|
}
|
|
|
|
|
2024-07-07 14:49:45 +03:00
|
|
|
void notification(MainWeatherCache mainWeatherCache) async {
|
2025-03-15 23:40:48 +03:00
|
|
|
final now = DateTime.now();
|
|
|
|
final startHour = timeConvert(timeStart).hour;
|
|
|
|
final endHour = timeConvert(timeEnd).hour;
|
2023-07-26 22:20:30 +03:00
|
|
|
|
|
|
|
for (var i = 0; i < mainWeatherCache.time!.length; i += timeRange) {
|
2025-03-15 23:40:48 +03:00
|
|
|
final notificationTime = DateTime.parse(mainWeatherCache.time![i]);
|
2023-07-26 22:20:30 +03:00
|
|
|
|
2023-10-12 16:30:28 +03:00
|
|
|
if (notificationTime.isAfter(now) &&
|
|
|
|
notificationTime.hour >= startHour &&
|
|
|
|
notificationTime.hour <= endHour) {
|
2024-08-09 22:19:37 +03:00
|
|
|
for (var j = 0; j < mainWeatherCache.timeDaily!.length; j++) {
|
|
|
|
if (mainWeatherCache.timeDaily![j].day == notificationTime.day) {
|
|
|
|
NotificationShow().showNotification(
|
|
|
|
UniqueKey().hashCode,
|
|
|
|
'$city: ${mainWeatherCache.temperature2M![i]}°',
|
|
|
|
'${StatusWeather().getText(mainWeatherCache.weathercode![i])} · ${StatusData().getTimeFormat(mainWeatherCache.time![i])}',
|
|
|
|
notificationTime,
|
|
|
|
StatusWeather().getImageNotification(
|
|
|
|
mainWeatherCache.weathercode![i],
|
|
|
|
mainWeatherCache.time![i],
|
|
|
|
mainWeatherCache.sunrise![j],
|
|
|
|
mainWeatherCache.sunset![j],
|
|
|
|
),
|
|
|
|
);
|
2023-09-08 18:55:26 +03:00
|
|
|
}
|
|
|
|
}
|
2023-07-08 15:19:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-05 21:31:29 +03:00
|
|
|
|
2023-09-22 19:10:11 +03:00
|
|
|
void notificationCheck() async {
|
|
|
|
if (settings.notifications) {
|
2025-03-15 23:40:48 +03:00
|
|
|
final pendingNotificationRequests =
|
2023-09-22 19:10:11 +03:00
|
|
|
await flutterLocalNotificationsPlugin.pendingNotificationRequests();
|
|
|
|
if (pendingNotificationRequests.isEmpty) {
|
2024-07-07 14:49:45 +03:00
|
|
|
notification(_mainWeather.value);
|
2023-09-22 19:10:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
void reorder(int oldIndex, int newIndex) {
|
2023-09-05 21:31:29 +03:00
|
|
|
if (newIndex > oldIndex) {
|
|
|
|
newIndex -= 1;
|
|
|
|
}
|
|
|
|
final element = weatherCards.removeAt(oldIndex);
|
|
|
|
weatherCards.insert(newIndex, element);
|
|
|
|
|
|
|
|
for (int i = 0; i < weatherCards.length; i++) {
|
|
|
|
final item = weatherCards[i];
|
|
|
|
item.index = i;
|
2023-09-18 16:26:08 +03:00
|
|
|
isar.writeTxnSync(() => isar.weatherCards.putSync(item));
|
2023-09-05 21:31:29 +03:00
|
|
|
}
|
|
|
|
}
|
2023-10-01 22:38:43 +03:00
|
|
|
|
2023-10-12 11:36:18 +05:30
|
|
|
Future<bool> updateWidgetBackgroundColor(String color) async {
|
2023-10-12 12:11:20 +05:30
|
|
|
settings.widgetBackgroundColor = color;
|
|
|
|
isar.writeTxnSync(() {
|
|
|
|
isar.settings.putSync(settings);
|
|
|
|
});
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final results = await Future.wait<bool?>([
|
|
|
|
HomeWidget.saveWidgetData('background_color', color),
|
2023-10-12 11:36:18 +05:30
|
|
|
HomeWidget.updateWidget(androidName: androidWidgetName),
|
2025-03-15 23:40:48 +03:00
|
|
|
]);
|
|
|
|
return !results.contains(false);
|
2023-10-12 11:36:18 +05:30
|
|
|
}
|
|
|
|
|
2023-10-12 20:48:23 +03:00
|
|
|
Future<bool> updateWidgetTextColor(String color) async {
|
|
|
|
settings.widgetTextColor = color;
|
|
|
|
isar.writeTxnSync(() {
|
|
|
|
isar.settings.putSync(settings);
|
|
|
|
});
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final results = await Future.wait<bool?>([
|
|
|
|
HomeWidget.saveWidgetData('text_color', color),
|
2023-10-12 20:48:23 +03:00
|
|
|
HomeWidget.updateWidget(androidName: androidWidgetName),
|
2025-03-15 23:40:48 +03:00
|
|
|
]);
|
|
|
|
return !results.contains(false);
|
2023-10-12 20:48:23 +03:00
|
|
|
}
|
|
|
|
|
2023-10-03 19:23:52 +03:00
|
|
|
Future<bool> updateWidget() async {
|
2023-10-06 20:20:43 +03:00
|
|
|
final timeZoneName = await FlutterTimezone.getLocalTimezone();
|
|
|
|
tz.initializeTimeZones();
|
|
|
|
tz.setLocalLocation(tz.getLocation(timeZoneName));
|
|
|
|
|
2023-10-07 13:50:54 +03:00
|
|
|
final isarWidget = await Isar.open([
|
2023-10-06 20:20:43 +03:00
|
|
|
SettingsSchema,
|
|
|
|
MainWeatherCacheSchema,
|
|
|
|
LocationCacheSchema,
|
|
|
|
WeatherCardSchema,
|
|
|
|
], directory: (await getApplicationSupportDirectory()).path);
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final mainWeatherCache =
|
|
|
|
isarWidget.mainWeatherCaches.where().findFirstSync();
|
2023-10-03 19:23:52 +03:00
|
|
|
if (mainWeatherCache == null) return false;
|
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!);
|
|
|
|
final day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!);
|
2023-10-03 19:23:52 +03:00
|
|
|
|
2025-03-15 23:40:48 +03:00
|
|
|
final results = await Future.wait<bool?>([
|
2023-10-03 19:23:52 +03:00
|
|
|
HomeWidget.saveWidgetData(
|
2025-03-15 23:40:48 +03:00
|
|
|
'weather_icon',
|
|
|
|
await getLocalImagePath(
|
|
|
|
StatusWeather().getImageNotification(
|
2023-10-03 19:23:52 +03:00
|
|
|
mainWeatherCache.weathercode![hour],
|
|
|
|
mainWeatherCache.time![hour],
|
|
|
|
mainWeatherCache.sunrise![day],
|
|
|
|
mainWeatherCache.sunset![day],
|
2025-03-15 23:40:48 +03:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2023-10-03 19:23:52 +03:00
|
|
|
HomeWidget.saveWidgetData(
|
|
|
|
'weather_degree',
|
|
|
|
'${mainWeatherCache.temperature2M?[hour].round()}°',
|
|
|
|
),
|
|
|
|
HomeWidget.updateWidget(androidName: androidWidgetName),
|
2025-03-15 23:40:48 +03:00
|
|
|
]);
|
|
|
|
return !results.contains(false);
|
2023-10-01 22:38:43 +03:00
|
|
|
}
|
2024-08-15 22:39:51 +03:00
|
|
|
|
|
|
|
void urlLauncher(String uri) async {
|
2025-03-15 23:40:48 +03:00
|
|
|
final url = Uri.parse(uri);
|
2024-08-15 22:39:51 +03:00
|
|
|
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
|
|
|
|
throw Exception('Could not launch $url');
|
|
|
|
}
|
|
|
|
}
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|