mirror of
https://github.com/darkmoonight/Rain.git
synced 2025-06-28 20:19:58 +00:00
Fix bugs
This commit is contained in:
parent
d169f6237f
commit
fb150421a6
62 changed files with 5006 additions and 4901 deletions
|
@ -7,8 +7,8 @@ import 'package:rain/app/data/db.dart';
|
||||||
import 'package:rain/main.dart';
|
import 'package:rain/main.dart';
|
||||||
|
|
||||||
class WeatherAPI {
|
class WeatherAPI {
|
||||||
final Dio dio = Dio()
|
final Dio dio =
|
||||||
..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
|
Dio()..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
|
||||||
final Dio dioLocation = Dio();
|
final Dio dioLocation = Dio();
|
||||||
|
|
||||||
static const String _weatherParams =
|
static const String _weatherParams =
|
||||||
|
@ -41,14 +41,25 @@ class WeatherAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<WeatherCard> getWeatherCard(double lat, double lon, String city,
|
Future<WeatherCard> getWeatherCard(
|
||||||
String district, String timezone) async {
|
double lat,
|
||||||
|
double lon,
|
||||||
|
String city,
|
||||||
|
String district,
|
||||||
|
String timezone,
|
||||||
|
) async {
|
||||||
final String urlWeather = _buildWeatherUrl(lat, lon);
|
final String urlWeather = _buildWeatherUrl(lat, lon);
|
||||||
try {
|
try {
|
||||||
Response response = await dio.get(urlWeather);
|
Response response = await dio.get(urlWeather);
|
||||||
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
|
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
|
||||||
return _mapWeatherDataToCard(
|
return _mapWeatherDataToCard(
|
||||||
weatherData, lat, lon, city, district, timezone);
|
weatherData,
|
||||||
|
lat,
|
||||||
|
lon,
|
||||||
|
city,
|
||||||
|
district,
|
||||||
|
timezone,
|
||||||
|
);
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
|
@ -124,8 +135,14 @@ class WeatherAPI {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherCard _mapWeatherDataToCard(WeatherDataApi weatherData, double lat,
|
WeatherCard _mapWeatherDataToCard(
|
||||||
double lon, String city, String district, String timezone) {
|
WeatherDataApi weatherData,
|
||||||
|
double lat,
|
||||||
|
double lon,
|
||||||
|
String city,
|
||||||
|
String district,
|
||||||
|
String timezone,
|
||||||
|
) {
|
||||||
return WeatherCard(
|
return WeatherCard(
|
||||||
time: weatherData.hourly.time,
|
time: weatherData.hourly.time,
|
||||||
temperature2M: weatherData.hourly.temperature2M,
|
temperature2M: weatherData.hourly.temperature2M,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
class CityApi {
|
class CityApi {
|
||||||
CityApi({
|
CityApi({required this.results});
|
||||||
required this.results,
|
|
||||||
});
|
|
||||||
|
|
||||||
List<Result> results;
|
List<Result> results;
|
||||||
|
|
||||||
factory CityApi.fromJson(Map<String, dynamic> json) => CityApi(
|
factory CityApi.fromJson(Map<String, dynamic> json) => CityApi(
|
||||||
results: json['results'] == null
|
results:
|
||||||
|
json['results'] == null
|
||||||
? List<Result>.empty()
|
? List<Result>.empty()
|
||||||
: List<Result>.from(json['results'].map((x) => Result.fromJson(x))),
|
: List<Result>.from(json['results'].map((x) => Result.fromJson(x))),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
||||||
import 'package:flutter_timezone/flutter_timezone.dart';
|
import 'package:flutter_timezone/flutter_timezone.dart';
|
||||||
import 'package:geocoding/geocoding.dart';
|
import 'package:geocoding/geocoding.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
@ -53,15 +52,14 @@ class WeatherController extends GetxController {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
weatherCards
|
weatherCards.assignAll(
|
||||||
.assignAll(isar.weatherCards.where().sortByIndex().findAllSync());
|
isar.weatherCards.where().sortByIndex().findAllSync(),
|
||||||
|
);
|
||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Position> determinePosition() async {
|
Future<Position> _determinePosition() async {
|
||||||
LocationPermission permission;
|
LocationPermission permission = await Geolocator.checkPermission();
|
||||||
|
|
||||||
permission = await Geolocator.checkPermission();
|
|
||||||
if (permission == LocationPermission.denied) {
|
if (permission == LocationPermission.denied) {
|
||||||
permission = await Geolocator.requestPermission();
|
permission = await Geolocator.requestPermission();
|
||||||
if (permission == LocationPermission.denied) {
|
if (permission == LocationPermission.denied) {
|
||||||
|
@ -71,7 +69,8 @@ class WeatherController extends GetxController {
|
||||||
|
|
||||||
if (permission == LocationPermission.deniedForever) {
|
if (permission == LocationPermission.deniedForever) {
|
||||||
return Future.error(
|
return Future.error(
|
||||||
'Location permissions are permanently denied, we cannot request permissions.');
|
'Location permissions are permanently denied, we cannot request permissions.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return await Geolocator.getCurrentPosition();
|
return await Geolocator.getCurrentPosition();
|
||||||
}
|
}
|
||||||
|
@ -80,25 +79,26 @@ class WeatherController extends GetxController {
|
||||||
if (settings.location) {
|
if (settings.location) {
|
||||||
await getCurrentLocation();
|
await getCurrentLocation();
|
||||||
} else {
|
} else {
|
||||||
if ((isar.locationCaches.where().findAllSync()).isNotEmpty) {
|
final locationCity = isar.locationCaches.where().findFirstSync();
|
||||||
LocationCache locationCity =
|
if (locationCity != null) {
|
||||||
(isar.locationCaches.where().findFirstSync())!;
|
await getLocation(
|
||||||
await getLocation(locationCity.lat!, locationCity.lon!,
|
locationCity.lat!,
|
||||||
locationCity.district!, locationCity.city!);
|
locationCity.lon!,
|
||||||
|
locationCity.district!,
|
||||||
|
locationCity.city!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getCurrentLocation() async {
|
Future<void> getCurrentLocation() async {
|
||||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
|
||||||
|
|
||||||
if (!(await isOnline.value)) {
|
if (!(await isOnline.value)) {
|
||||||
showSnackBar(content: 'no_inter'.tr);
|
showSnackBar(content: 'no_inter'.tr);
|
||||||
await readCache();
|
await readCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serviceEnabled) {
|
if (!await Geolocator.isLocationServiceEnabled()) {
|
||||||
showSnackBar(
|
showSnackBar(
|
||||||
content: 'no_location'.tr,
|
content: 'no_location'.tr,
|
||||||
onPressed: () => Geolocator.openLocationSettings(),
|
onPressed: () => Geolocator.openLocationSettings(),
|
||||||
|
@ -107,70 +107,73 @@ class WeatherController extends GetxController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) {
|
if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
|
||||||
await readCache();
|
await readCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Position position = await determinePosition();
|
final position = await _determinePosition();
|
||||||
List<Placemark> placemarks =
|
final placemarks = await placemarkFromCoordinates(
|
||||||
await placemarkFromCoordinates(position.latitude, position.longitude);
|
position.latitude,
|
||||||
Placemark place = placemarks[0];
|
position.longitude,
|
||||||
|
);
|
||||||
|
final place = placemarks[0];
|
||||||
|
|
||||||
_latitude.value = position.latitude;
|
_latitude.value = position.latitude;
|
||||||
_longitude.value = position.longitude;
|
_longitude.value = position.longitude;
|
||||||
_district.value = '${place.administrativeArea}';
|
_district.value = place.administrativeArea ?? '';
|
||||||
_city.value = '${place.locality}';
|
_city.value = place.locality ?? '';
|
||||||
|
|
||||||
_mainWeather.value =
|
_mainWeather.value = await WeatherAPI().getWeatherData(
|
||||||
await WeatherAPI().getWeatherData(_latitude.value, _longitude.value);
|
_latitude.value,
|
||||||
|
_longitude.value,
|
||||||
|
);
|
||||||
|
|
||||||
notificationCheck();
|
notificationCheck();
|
||||||
|
|
||||||
await writeCache();
|
await writeCache();
|
||||||
await readCache();
|
await readCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map> getCurrentLocationSearch() async {
|
Future<Map> getCurrentLocationSearch() async {
|
||||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
|
||||||
double lat, lon;
|
|
||||||
String city, district;
|
|
||||||
|
|
||||||
if (!(await isOnline.value)) {
|
if (!(await isOnline.value)) {
|
||||||
showSnackBar(content: 'no_inter'.tr);
|
showSnackBar(content: 'no_inter'.tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serviceEnabled) {
|
if (!await Geolocator.isLocationServiceEnabled()) {
|
||||||
showSnackBar(
|
showSnackBar(
|
||||||
content: 'no_location'.tr,
|
content: 'no_location'.tr,
|
||||||
onPressed: () => Geolocator.openLocationSettings(),
|
onPressed: () => Geolocator.openLocationSettings(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Position position = await determinePosition();
|
final position = await _determinePosition();
|
||||||
List<Placemark> placemarks =
|
final placemarks = await placemarkFromCoordinates(
|
||||||
await placemarkFromCoordinates(position.latitude, position.longitude);
|
position.latitude,
|
||||||
Placemark place = placemarks[0];
|
position.longitude,
|
||||||
|
);
|
||||||
|
final place = placemarks[0];
|
||||||
|
|
||||||
lat = position.latitude;
|
return {
|
||||||
lon = position.longitude;
|
'lat': position.latitude,
|
||||||
city = '${place.administrativeArea}';
|
'lon': position.longitude,
|
||||||
district = '${place.locality}';
|
'city': place.administrativeArea ?? '',
|
||||||
|
'district': place.locality ?? '',
|
||||||
Map location = {'lat': lat, 'lon': lon, 'city': city, 'district': district};
|
};
|
||||||
|
|
||||||
return location;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getLocation(double latitude, double longitude, String district,
|
Future<void> getLocation(
|
||||||
String locality) async {
|
double latitude,
|
||||||
|
double longitude,
|
||||||
|
String district,
|
||||||
|
String locality,
|
||||||
|
) async {
|
||||||
if (!(await isOnline.value)) {
|
if (!(await isOnline.value)) {
|
||||||
showSnackBar(content: 'no_inter'.tr);
|
showSnackBar(content: 'no_inter'.tr);
|
||||||
await readCache();
|
await readCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) {
|
if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
|
||||||
await readCache();
|
await readCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -180,11 +183,12 @@ class WeatherController extends GetxController {
|
||||||
_district.value = district;
|
_district.value = district;
|
||||||
_city.value = locality;
|
_city.value = locality;
|
||||||
|
|
||||||
_mainWeather.value =
|
_mainWeather.value = await WeatherAPI().getWeatherData(
|
||||||
await WeatherAPI().getWeatherData(_latitude.value, _longitude.value);
|
_latitude.value,
|
||||||
|
_longitude.value,
|
||||||
|
);
|
||||||
|
|
||||||
notificationCheck();
|
notificationCheck();
|
||||||
|
|
||||||
await writeCache();
|
await writeCache();
|
||||||
await readCache();
|
await readCache();
|
||||||
}
|
}
|
||||||
|
@ -201,10 +205,14 @@ class WeatherController extends GetxController {
|
||||||
_mainWeather.value = mainWeatherCache;
|
_mainWeather.value = mainWeatherCache;
|
||||||
_location.value = locationCache;
|
_location.value = locationCache;
|
||||||
|
|
||||||
hourOfDay.value =
|
hourOfDay.value = getTime(
|
||||||
getTime(_mainWeather.value.time!, _mainWeather.value.timezone!);
|
_mainWeather.value.time!,
|
||||||
dayOfNow.value =
|
_mainWeather.value.timezone!,
|
||||||
getDay(_mainWeather.value.timeDaily!, _mainWeather.value.timezone!);
|
);
|
||||||
|
dayOfNow.value = getDay(
|
||||||
|
_mainWeather.value.timeDaily!,
|
||||||
|
_mainWeather.value.timezone!,
|
||||||
|
);
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
Workmanager().registerPeriodicTask(
|
Workmanager().registerPeriodicTask(
|
||||||
|
@ -235,16 +243,10 @@ class WeatherController extends GetxController {
|
||||||
);
|
);
|
||||||
|
|
||||||
isar.writeTxnSync(() {
|
isar.writeTxnSync(() {
|
||||||
final mainWeatherCachesIsEmpty =
|
if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
|
||||||
(isar.mainWeatherCaches.where().findAllSync()).isEmpty;
|
|
||||||
final locationCachesIsEmpty =
|
|
||||||
(isar.locationCaches.where().findAllSync()).isEmpty;
|
|
||||||
|
|
||||||
if (mainWeatherCachesIsEmpty) {
|
|
||||||
isar.mainWeatherCaches.putSync(_mainWeather.value);
|
isar.mainWeatherCaches.putSync(_mainWeather.value);
|
||||||
}
|
}
|
||||||
|
if (isar.locationCaches.where().findAllSync().isEmpty) {
|
||||||
if (locationCachesIsEmpty) {
|
|
||||||
isar.locationCaches.putSync(locationCaches);
|
isar.locationCaches.putSync(locationCaches);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -261,7 +263,7 @@ class WeatherController extends GetxController {
|
||||||
.timestampLessThan(cacheExpiry)
|
.timestampLessThan(cacheExpiry)
|
||||||
.deleteAllSync();
|
.deleteAllSync();
|
||||||
});
|
});
|
||||||
if ((isar.mainWeatherCaches.where().findAllSync()).isEmpty) {
|
if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
|
||||||
await flutterLocalNotificationsPlugin.cancelAll();
|
await flutterLocalNotificationsPlugin.cancelAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,31 +273,39 @@ class WeatherController extends GetxController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||||
await flutterLocalNotificationsPlugin.cancelAll();
|
await flutterLocalNotificationsPlugin.cancelAll();
|
||||||
|
|
||||||
isar.writeTxnSync(() {
|
isar.writeTxnSync(() {
|
||||||
if (!settings.location) {
|
if (!settings.location) {
|
||||||
isar.mainWeatherCaches.where().deleteAllSync();
|
isar.mainWeatherCaches.where().deleteAllSync();
|
||||||
}
|
}
|
||||||
if ((settings.location && serviceEnabled) || changeCity) {
|
if (settings.location && serviceEnabled || changeCity) {
|
||||||
isar.mainWeatherCaches.where().deleteAllSync();
|
isar.mainWeatherCaches.where().deleteAllSync();
|
||||||
isar.locationCaches.where().deleteAllSync();
|
isar.locationCaches.where().deleteAllSync();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Card Weather
|
|
||||||
Future<void> addCardWeather(
|
Future<void> addCardWeather(
|
||||||
double latitude, double longitude, String city, String district) async {
|
double latitude,
|
||||||
|
double longitude,
|
||||||
|
String city,
|
||||||
|
String district,
|
||||||
|
) async {
|
||||||
if (!(await isOnline.value)) {
|
if (!(await isOnline.value)) {
|
||||||
showSnackBar(content: 'no_inter'.tr);
|
showSnackBar(content: 'no_inter'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String tz = tzmap.latLngToTimezoneString(latitude, longitude);
|
final tz = tzmap.latLngToTimezoneString(latitude, longitude);
|
||||||
_weatherCard.value = await WeatherAPI()
|
_weatherCard.value = await WeatherAPI().getWeatherCard(
|
||||||
.getWeatherCard(latitude, longitude, city, district, tz);
|
latitude,
|
||||||
|
longitude,
|
||||||
|
city,
|
||||||
|
district,
|
||||||
|
tz,
|
||||||
|
);
|
||||||
isar.writeTxnSync(() {
|
isar.writeTxnSync(() {
|
||||||
weatherCards.add(_weatherCard.value);
|
weatherCards.add(_weatherCard.value);
|
||||||
isar.weatherCards.putSync(_weatherCard.value);
|
isar.weatherCards.putSync(_weatherCard.value);
|
||||||
|
@ -303,7 +313,8 @@ class WeatherController extends GetxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateCacheCard(bool refresh) async {
|
Future<void> updateCacheCard(bool refresh) async {
|
||||||
List<WeatherCard> weatherCard = refresh
|
final weatherCard =
|
||||||
|
refresh
|
||||||
? isar.weatherCards.where().sortByIndex().findAllSync()
|
? isar.weatherCards.where().sortByIndex().findAllSync()
|
||||||
: isar.weatherCards
|
: isar.weatherCards
|
||||||
.filter()
|
.filter()
|
||||||
|
@ -311,13 +322,18 @@ class WeatherController extends GetxController {
|
||||||
.sortByIndex()
|
.sortByIndex()
|
||||||
.findAllSync();
|
.findAllSync();
|
||||||
|
|
||||||
if ((!(await isOnline.value)) || weatherCard.isEmpty) {
|
if (!(await isOnline.value) || weatherCard.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var oldCard in weatherCard) {
|
for (var oldCard in weatherCard) {
|
||||||
var updatedCard = await WeatherAPI().getWeatherCard(oldCard.lat!,
|
final updatedCard = await WeatherAPI().getWeatherCard(
|
||||||
oldCard.lon!, oldCard.city!, oldCard.district!, oldCard.timezone!);
|
oldCard.lat!,
|
||||||
|
oldCard.lon!,
|
||||||
|
oldCard.city!,
|
||||||
|
oldCard.district!,
|
||||||
|
oldCard.timezone!,
|
||||||
|
);
|
||||||
isar.writeTxnSync(() {
|
isar.writeTxnSync(() {
|
||||||
oldCard
|
oldCard
|
||||||
..time = updatedCard.time
|
..time = updatedCard.time
|
||||||
|
@ -358,8 +374,8 @@ class WeatherController extends GetxController {
|
||||||
|
|
||||||
isar.weatherCards.putSync(oldCard);
|
isar.weatherCards.putSync(oldCard);
|
||||||
|
|
||||||
var newCard = oldCard;
|
final newCard = oldCard;
|
||||||
int oldIdx = weatherCard.indexOf(oldCard);
|
final oldIdx = weatherCard.indexOf(oldCard);
|
||||||
weatherCards[oldIdx] = newCard;
|
weatherCards[oldIdx] = newCard;
|
||||||
weatherCards.refresh();
|
weatherCards.refresh();
|
||||||
});
|
});
|
||||||
|
@ -428,35 +444,26 @@ class WeatherController extends GetxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTime(List<String> time, String timezone) {
|
int getTime(List<String> time, String timezone) {
|
||||||
int getTime = 0;
|
return time.indexWhere((t) {
|
||||||
for (var i = 0; i < time.length; i++) {
|
final dateTime = DateTime.parse(t);
|
||||||
if (tz.TZDateTime.now(tz.getLocation(timezone)).hour ==
|
return tz.TZDateTime.now(tz.getLocation(timezone)).hour ==
|
||||||
DateTime.parse(time[i]).hour &&
|
dateTime.hour &&
|
||||||
tz.TZDateTime.now(tz.getLocation(timezone)).day ==
|
tz.TZDateTime.now(tz.getLocation(timezone)).day == dateTime.day;
|
||||||
DateTime.parse(time[i]).day) {
|
});
|
||||||
getTime = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDay(List<DateTime> time, String timezone) {
|
int getDay(List<DateTime> time, String timezone) {
|
||||||
int getDay = 0;
|
return time.indexWhere(
|
||||||
for (var i = 0; i < time.length; i++) {
|
(t) => tz.TZDateTime.now(tz.getLocation(timezone)).day == t.day,
|
||||||
if (tz.TZDateTime.now(tz.getLocation(timezone)).day == time[i].day) {
|
);
|
||||||
getDay = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getDay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeOfDay timeConvert(String normTime) {
|
TimeOfDay timeConvert(String normTime) {
|
||||||
int hh = 0;
|
final hh = normTime.endsWith('PM') ? 12 : 0;
|
||||||
if (normTime.endsWith('PM')) hh = 12;
|
final timeParts = normTime.split(' ')[0].split(':');
|
||||||
normTime = normTime.split(' ')[0];
|
|
||||||
return TimeOfDay(
|
return TimeOfDay(
|
||||||
hour: hh + int.parse(normTime.split(':')[0]) % 24,
|
hour: hh + int.parse(timeParts[0]) % 24,
|
||||||
minute: int.parse(normTime.split(':')[1]) % 60,
|
minute: int.parse(timeParts[1]) % 60,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,8 +471,8 @@ class WeatherController extends GetxController {
|
||||||
final directory = await getTemporaryDirectory();
|
final directory = await getTemporaryDirectory();
|
||||||
final imagePath = '${directory.path}/$icon';
|
final imagePath = '${directory.path}/$icon';
|
||||||
|
|
||||||
final ByteData data = await rootBundle.load('assets/images/$icon');
|
final data = await rootBundle.load('assets/images/$icon');
|
||||||
final List<int> bytes = data.buffer.asUint8List();
|
final bytes = data.buffer.asUint8List();
|
||||||
|
|
||||||
await File(imagePath).writeAsBytes(bytes);
|
await File(imagePath).writeAsBytes(bytes);
|
||||||
|
|
||||||
|
@ -473,12 +480,12 @@ class WeatherController extends GetxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification(MainWeatherCache mainWeatherCache) async {
|
void notification(MainWeatherCache mainWeatherCache) async {
|
||||||
DateTime now = DateTime.now();
|
final now = DateTime.now();
|
||||||
int startHour = timeConvert(timeStart).hour;
|
final startHour = timeConvert(timeStart).hour;
|
||||||
int endHour = timeConvert(timeEnd).hour;
|
final endHour = timeConvert(timeEnd).hour;
|
||||||
|
|
||||||
for (var i = 0; i < mainWeatherCache.time!.length; i += timeRange) {
|
for (var i = 0; i < mainWeatherCache.time!.length; i += timeRange) {
|
||||||
DateTime notificationTime = DateTime.parse(mainWeatherCache.time![i]);
|
final notificationTime = DateTime.parse(mainWeatherCache.time![i]);
|
||||||
|
|
||||||
if (notificationTime.isAfter(now) &&
|
if (notificationTime.isAfter(now) &&
|
||||||
notificationTime.hour >= startHour &&
|
notificationTime.hour >= startHour &&
|
||||||
|
@ -505,7 +512,7 @@ class WeatherController extends GetxController {
|
||||||
|
|
||||||
void notificationCheck() async {
|
void notificationCheck() async {
|
||||||
if (settings.notifications) {
|
if (settings.notifications) {
|
||||||
final List<PendingNotificationRequest> pendingNotificationRequests =
|
final pendingNotificationRequests =
|
||||||
await flutterLocalNotificationsPlugin.pendingNotificationRequests();
|
await flutterLocalNotificationsPlugin.pendingNotificationRequests();
|
||||||
if (pendingNotificationRequests.isEmpty) {
|
if (pendingNotificationRequests.isEmpty) {
|
||||||
notification(_mainWeather.value);
|
notification(_mainWeather.value);
|
||||||
|
@ -513,7 +520,7 @@ class WeatherController extends GetxController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reorder(oldIndex, newIndex) {
|
void reorder(int oldIndex, int newIndex) {
|
||||||
if (newIndex > oldIndex) {
|
if (newIndex > oldIndex) {
|
||||||
newIndex -= 1;
|
newIndex -= 1;
|
||||||
}
|
}
|
||||||
|
@ -533,15 +540,11 @@ class WeatherController extends GetxController {
|
||||||
isar.settings.putSync(settings);
|
isar.settings.putSync(settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Future.wait<bool?>([
|
final results = await Future.wait<bool?>([
|
||||||
HomeWidget.saveWidgetData(
|
HomeWidget.saveWidgetData('background_color', color),
|
||||||
'background_color',
|
|
||||||
color,
|
|
||||||
),
|
|
||||||
HomeWidget.updateWidget(androidName: androidWidgetName),
|
HomeWidget.updateWidget(androidName: androidWidgetName),
|
||||||
]).then((value) {
|
]);
|
||||||
return !value.contains(false);
|
return !results.contains(false);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateWidgetTextColor(String color) async {
|
Future<bool> updateWidgetTextColor(String color) async {
|
||||||
|
@ -550,15 +553,11 @@ class WeatherController extends GetxController {
|
||||||
isar.settings.putSync(settings);
|
isar.settings.putSync(settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Future.wait<bool?>([
|
final results = await Future.wait<bool?>([
|
||||||
HomeWidget.saveWidgetData(
|
HomeWidget.saveWidgetData('text_color', color),
|
||||||
'text_color',
|
|
||||||
color,
|
|
||||||
),
|
|
||||||
HomeWidget.updateWidget(androidName: androidWidgetName),
|
HomeWidget.updateWidget(androidName: androidWidgetName),
|
||||||
]).then((value) {
|
]);
|
||||||
return !value.contains(false);
|
return !results.contains(false);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateWidget() async {
|
Future<bool> updateWidget() async {
|
||||||
|
@ -573,34 +572,36 @@ class WeatherController extends GetxController {
|
||||||
WeatherCardSchema,
|
WeatherCardSchema,
|
||||||
], directory: (await getApplicationSupportDirectory()).path);
|
], directory: (await getApplicationSupportDirectory()).path);
|
||||||
|
|
||||||
MainWeatherCache? mainWeatherCache;
|
final mainWeatherCache =
|
||||||
mainWeatherCache = isarWidget.mainWeatherCaches.where().findFirstSync();
|
isarWidget.mainWeatherCaches.where().findFirstSync();
|
||||||
if (mainWeatherCache == null) return false;
|
if (mainWeatherCache == null) return false;
|
||||||
|
|
||||||
int hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!);
|
final hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!);
|
||||||
int day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!);
|
final day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!);
|
||||||
|
|
||||||
return Future.wait<bool?>([
|
final results = await Future.wait<bool?>([
|
||||||
HomeWidget.saveWidgetData(
|
HomeWidget.saveWidgetData(
|
||||||
'weather_icon',
|
'weather_icon',
|
||||||
await getLocalImagePath(StatusWeather().getImageNotification(
|
await getLocalImagePath(
|
||||||
|
StatusWeather().getImageNotification(
|
||||||
mainWeatherCache.weathercode![hour],
|
mainWeatherCache.weathercode![hour],
|
||||||
mainWeatherCache.time![hour],
|
mainWeatherCache.time![hour],
|
||||||
mainWeatherCache.sunrise![day],
|
mainWeatherCache.sunrise![day],
|
||||||
mainWeatherCache.sunset![day],
|
mainWeatherCache.sunset![day],
|
||||||
))),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
HomeWidget.saveWidgetData(
|
HomeWidget.saveWidgetData(
|
||||||
'weather_degree',
|
'weather_degree',
|
||||||
'${mainWeatherCache.temperature2M?[hour].round()}°',
|
'${mainWeatherCache.temperature2M?[hour].round()}°',
|
||||||
),
|
),
|
||||||
HomeWidget.updateWidget(androidName: androidWidgetName),
|
HomeWidget.updateWidget(androidName: androidWidgetName),
|
||||||
]).then((value) {
|
]);
|
||||||
return !value.contains(false);
|
return !results.contains(false);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void urlLauncher(String uri) async {
|
void urlLauncher(String uri) async {
|
||||||
final Uri url = Uri.parse(uri);
|
final url = Uri.parse(uri);
|
||||||
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
|
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
|
||||||
throw Exception('Could not launch $url');
|
throw Exception('Could not launch $url');
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,12 +152,7 @@ class LocationCache {
|
||||||
String? city;
|
String? city;
|
||||||
String? district;
|
String? district;
|
||||||
|
|
||||||
LocationCache({
|
LocationCache({this.lat, this.lon, this.city, this.district});
|
||||||
this.lat,
|
|
||||||
this.lon,
|
|
||||||
this.city,
|
|
||||||
this.district,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
|
@ -304,8 +299,9 @@ class WeatherCard {
|
||||||
time: List<String>.from(json['time'] ?? []),
|
time: List<String>.from(json['time'] ?? []),
|
||||||
weathercode: List<int>.from(json['weathercode'] ?? []),
|
weathercode: List<int>.from(json['weathercode'] ?? []),
|
||||||
temperature2M: List<double>.from(json['temperature2M'] ?? []),
|
temperature2M: List<double>.from(json['temperature2M'] ?? []),
|
||||||
apparentTemperature:
|
apparentTemperature: List<double?>.from(
|
||||||
List<double?>.from(json['apparentTemperature'] ?? []),
|
json['apparentTemperature'] ?? [],
|
||||||
|
),
|
||||||
relativehumidity2M: List<int?>.from(json['relativehumidity2M'] ?? []),
|
relativehumidity2M: List<int?>.from(json['relativehumidity2M'] ?? []),
|
||||||
precipitation: List<double>.from(json['precipitation'] ?? []),
|
precipitation: List<double>.from(json['precipitation'] ?? []),
|
||||||
rain: List<double?>.from(json['rain'] ?? []),
|
rain: List<double?>.from(json['rain'] ?? []),
|
||||||
|
@ -318,26 +314,31 @@ class WeatherCard {
|
||||||
cloudcover: List<int?>.from(json['cloudcover'] ?? []),
|
cloudcover: List<int?>.from(json['cloudcover'] ?? []),
|
||||||
uvIndex: List<double?>.from(json['uvIndex'] ?? []),
|
uvIndex: List<double?>.from(json['uvIndex'] ?? []),
|
||||||
dewpoint2M: List<double?>.from(json['dewpoint2M'] ?? []),
|
dewpoint2M: List<double?>.from(json['dewpoint2M'] ?? []),
|
||||||
precipitationProbability:
|
precipitationProbability: List<int?>.from(
|
||||||
List<int?>.from(json['precipitationProbability'] ?? []),
|
json['precipitationProbability'] ?? [],
|
||||||
|
),
|
||||||
shortwaveRadiation: List<double?>.from(json['shortwaveRadiation'] ?? []),
|
shortwaveRadiation: List<double?>.from(json['shortwaveRadiation'] ?? []),
|
||||||
timeDaily: List<DateTime>.from(json['timeDaily'] ?? []),
|
timeDaily: List<DateTime>.from(json['timeDaily'] ?? []),
|
||||||
weathercodeDaily: List<int?>.from(json['weathercodeDaily'] ?? []),
|
weathercodeDaily: List<int?>.from(json['weathercodeDaily'] ?? []),
|
||||||
temperature2MMax: List<double?>.from(json['temperature2MMax'] ?? []),
|
temperature2MMax: List<double?>.from(json['temperature2MMax'] ?? []),
|
||||||
temperature2MMin: List<double?>.from(json['temperature2MMin'] ?? []),
|
temperature2MMin: List<double?>.from(json['temperature2MMin'] ?? []),
|
||||||
apparentTemperatureMax:
|
apparentTemperatureMax: List<double?>.from(
|
||||||
List<double?>.from(json['apparentTemperatureMax'] ?? []),
|
json['apparentTemperatureMax'] ?? [],
|
||||||
apparentTemperatureMin:
|
),
|
||||||
List<double?>.from(json['apparentTemperatureMin'] ?? []),
|
apparentTemperatureMin: List<double?>.from(
|
||||||
|
json['apparentTemperatureMin'] ?? [],
|
||||||
|
),
|
||||||
windspeed10MMax: List<double?>.from(json['windspeed10MMax'] ?? []),
|
windspeed10MMax: List<double?>.from(json['windspeed10MMax'] ?? []),
|
||||||
windgusts10MMax: List<double?>.from(json['windgusts10MMax'] ?? []),
|
windgusts10MMax: List<double?>.from(json['windgusts10MMax'] ?? []),
|
||||||
uvIndexMax: List<double?>.from(json['uvIndexMax'] ?? []),
|
uvIndexMax: List<double?>.from(json['uvIndexMax'] ?? []),
|
||||||
rainSum: List<double?>.from(json['rainSum'] ?? []),
|
rainSum: List<double?>.from(json['rainSum'] ?? []),
|
||||||
winddirection10MDominant:
|
winddirection10MDominant: List<int?>.from(
|
||||||
List<int?>.from(json['winddirection10MDominant'] ?? []),
|
json['winddirection10MDominant'] ?? [],
|
||||||
|
),
|
||||||
precipitationSum: List<double?>.from(json['precipitationSum'] ?? []),
|
precipitationSum: List<double?>.from(json['precipitationSum'] ?? []),
|
||||||
precipitationProbabilityMax:
|
precipitationProbabilityMax: List<int?>.from(
|
||||||
List<int?>.from(json['precipitationProbabilityMax'] ?? []),
|
json['precipitationProbabilityMax'] ?? [],
|
||||||
|
),
|
||||||
sunrise: List<String>.from(json['sunrise'] ?? []),
|
sunrise: List<String>.from(json['sunrise'] ?? []),
|
||||||
sunset: List<String>.from(json['sunset'] ?? []),
|
sunset: List<String>.from(json['sunset'] ?? []),
|
||||||
lat: json['lat'],
|
lat: json['lat'],
|
||||||
|
|
|
@ -15,10 +15,7 @@ import 'package:rain/app/ui/widgets/text_form.dart';
|
||||||
import 'package:rain/main.dart';
|
import 'package:rain/main.dart';
|
||||||
|
|
||||||
class SelectGeolocation extends StatefulWidget {
|
class SelectGeolocation extends StatefulWidget {
|
||||||
const SelectGeolocation({
|
const SelectGeolocation({super.key, required this.isStart});
|
||||||
super.key,
|
|
||||||
required this.isStart,
|
|
||||||
});
|
|
||||||
final bool isStart;
|
final bool isStart;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -94,16 +91,14 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
resizeToAvoidBottomInset: true,
|
resizeToAvoidBottomInset: true,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
leading: widget.isStart
|
leading:
|
||||||
|
widget.isStart
|
||||||
? null
|
? null
|
||||||
: IconButton(
|
: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
|
||||||
IconsaxPlusLinear.arrow_left_3,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
|
@ -131,7 +126,8 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10),
|
horizontal: 10,
|
||||||
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(
|
||||||
Radius.circular(20),
|
Radius.circular(20),
|
||||||
|
@ -150,7 +146,8 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
initialZoom: 3,
|
initialZoom: 3,
|
||||||
interactionOptions:
|
interactionOptions:
|
||||||
const InteractionOptions(
|
const InteractionOptions(
|
||||||
flags: InteractiveFlag.all &
|
flags:
|
||||||
|
InteractiveFlag.all &
|
||||||
~InteractiveFlag.rotate,
|
~InteractiveFlag.rotate,
|
||||||
),
|
),
|
||||||
cameraConstraint:
|
cameraConstraint:
|
||||||
|
@ -160,9 +157,11 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
const LatLng(90, 180),
|
const LatLng(90, 180),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onLongPress: (tapPosition, point) =>
|
onLongPress:
|
||||||
fillMap(point.latitude,
|
(tapPosition, point) => fillMap(
|
||||||
point.longitude),
|
point.latitude,
|
||||||
|
point.longitude,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
if (_isDarkMode)
|
if (_isDarkMode)
|
||||||
|
@ -177,9 +176,11 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
attributions: [
|
attributions: [
|
||||||
TextSourceAttribution(
|
TextSourceAttribution(
|
||||||
'OpenStreetMap contributors',
|
'OpenStreetMap contributors',
|
||||||
onTap: () => weatherController
|
onTap:
|
||||||
|
() => weatherController
|
||||||
.urlLauncher(
|
.urlLauncher(
|
||||||
'https://openstreetmap.org/copyright'),
|
'https://openstreetmap.org/copyright',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -189,8 +190,12 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.fromLTRB(
|
||||||
const EdgeInsets.fromLTRB(10, 15, 10, 5),
|
10,
|
||||||
|
15,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'searchMethod'.tr,
|
'searchMethod'.tr,
|
||||||
style: context.theme.textTheme.bodyLarge
|
style: context.theme.textTheme.bodyLarge
|
||||||
|
@ -204,42 +209,54 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
child: RawAutocomplete<Result>(
|
child: RawAutocomplete<Result>(
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
textEditingController: _controller,
|
textEditingController: _controller,
|
||||||
fieldViewBuilder: (BuildContext context,
|
fieldViewBuilder: (
|
||||||
|
BuildContext context,
|
||||||
TextEditingController
|
TextEditingController
|
||||||
fieldTextEditingController,
|
fieldTextEditingController,
|
||||||
FocusNode fieldFocusNode,
|
FocusNode fieldFocusNode,
|
||||||
VoidCallback onFieldSubmitted) {
|
VoidCallback onFieldSubmitted,
|
||||||
|
) {
|
||||||
return MyTextForm(
|
return MyTextForm(
|
||||||
elevation: kTextFieldElevation,
|
elevation: kTextFieldElevation,
|
||||||
labelText: 'search'.tr,
|
labelText: 'search'.tr,
|
||||||
type: TextInputType.text,
|
type: TextInputType.text,
|
||||||
icon: const Icon(IconsaxPlusLinear
|
icon: const Icon(
|
||||||
.global_search),
|
IconsaxPlusLinear.global_search,
|
||||||
|
),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
margin: const EdgeInsets.only(
|
margin: const EdgeInsets.only(
|
||||||
left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
optionsBuilder: (TextEditingValue
|
optionsBuilder: (
|
||||||
textEditingValue) {
|
TextEditingValue textEditingValue,
|
||||||
|
) {
|
||||||
if (textEditingValue.text.isEmpty) {
|
if (textEditingValue.text.isEmpty) {
|
||||||
return const Iterable<
|
return const Iterable<
|
||||||
Result>.empty();
|
Result
|
||||||
|
>.empty();
|
||||||
}
|
}
|
||||||
return WeatherAPI().getCity(
|
return WeatherAPI().getCity(
|
||||||
textEditingValue.text, locale);
|
textEditingValue.text,
|
||||||
|
locale,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onSelected: (Result selection) =>
|
onSelected:
|
||||||
|
(Result selection) =>
|
||||||
fillController(selection),
|
fillController(selection),
|
||||||
displayStringForOption: (Result
|
displayStringForOption:
|
||||||
option) =>
|
(Result option) =>
|
||||||
'${option.name}, ${option.admin1}',
|
'${option.name}, ${option.admin1}',
|
||||||
optionsViewBuilder:
|
optionsViewBuilder: (
|
||||||
(BuildContext context,
|
BuildContext context,
|
||||||
AutocompleteOnSelected<Result>
|
AutocompleteOnSelected<Result>
|
||||||
onSelected,
|
onSelected,
|
||||||
Iterable<Result> options) {
|
Iterable<Result> options,
|
||||||
|
) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
|
@ -255,19 +272,24 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: options.length,
|
itemCount: options.length,
|
||||||
itemBuilder:
|
itemBuilder: (
|
||||||
(BuildContext context,
|
BuildContext context,
|
||||||
int index) {
|
int index,
|
||||||
|
) {
|
||||||
final Result option =
|
final Result option =
|
||||||
options
|
options.elementAt(
|
||||||
.elementAt(index);
|
index,
|
||||||
|
);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () =>
|
onTap:
|
||||||
onSelected(option),
|
() => onSelected(
|
||||||
|
option,
|
||||||
|
),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
'${option.name}, ${option.admin1}',
|
'${option.name}, ${option.admin1}',
|
||||||
style: context
|
style:
|
||||||
|
context
|
||||||
.textTheme
|
.textTheme
|
||||||
.labelLarge,
|
.labelLarge,
|
||||||
),
|
),
|
||||||
|
@ -292,47 +314,53 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
bool serviceEnabled =
|
bool serviceEnabled =
|
||||||
await Geolocator
|
await Geolocator.isLocationServiceEnabled();
|
||||||
.isLocationServiceEnabled();
|
|
||||||
if (!serviceEnabled) {
|
if (!serviceEnabled) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await showAdaptiveDialog(
|
await showAdaptiveDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (
|
||||||
(BuildContext context) {
|
BuildContext context,
|
||||||
|
) {
|
||||||
return AlertDialog.adaptive(
|
return AlertDialog.adaptive(
|
||||||
title: Text(
|
title: Text(
|
||||||
'location'.tr,
|
'location'.tr,
|
||||||
style: context
|
style:
|
||||||
.textTheme.titleLarge,
|
context
|
||||||
|
.textTheme
|
||||||
|
.titleLarge,
|
||||||
),
|
),
|
||||||
content: Text(
|
content: Text(
|
||||||
'no_location'.tr,
|
'no_location'.tr,
|
||||||
style: context.textTheme
|
style:
|
||||||
|
context
|
||||||
|
.textTheme
|
||||||
.titleMedium,
|
.titleMedium,
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () =>
|
onPressed:
|
||||||
Get.back(
|
() => Get.back(
|
||||||
result: false),
|
result: false,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'cancel'.tr,
|
'cancel'.tr,
|
||||||
style: context
|
style: context
|
||||||
.textTheme
|
.textTheme
|
||||||
.titleMedium
|
.titleMedium
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
color: Colors
|
color:
|
||||||
|
Colors
|
||||||
.blueAccent,
|
.blueAccent,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Geolocator
|
Geolocator.openLocationSettings();
|
||||||
.openLocationSettings();
|
|
||||||
Get.back(
|
Get.back(
|
||||||
result: true);
|
result: true,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'settings'.tr,
|
'settings'.tr,
|
||||||
|
@ -340,8 +368,10 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
.textTheme
|
.textTheme
|
||||||
.titleMedium
|
.titleMedium
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
color: Colors
|
color:
|
||||||
.green),
|
Colors
|
||||||
|
.green,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -380,8 +410,9 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateValue'.tr;
|
return 'validateValue'.tr;
|
||||||
}
|
}
|
||||||
double? numericValue =
|
double? numericValue = double.tryParse(
|
||||||
double.tryParse(value);
|
value,
|
||||||
|
);
|
||||||
if (numericValue == null) {
|
if (numericValue == null) {
|
||||||
return 'validateNumber'.tr;
|
return 'validateNumber'.tr;
|
||||||
}
|
}
|
||||||
|
@ -407,8 +438,9 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateValue'.tr;
|
return 'validateValue'.tr;
|
||||||
}
|
}
|
||||||
double? numericValue =
|
double? numericValue = double.tryParse(
|
||||||
double.tryParse(value);
|
value,
|
||||||
|
);
|
||||||
if (numericValue == null) {
|
if (numericValue == null) {
|
||||||
return 'validateNumber'.tr;
|
return 'validateNumber'.tr;
|
||||||
}
|
}
|
||||||
|
@ -424,10 +456,14 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
controller: _controllerCity,
|
controller: _controllerCity,
|
||||||
labelText: 'city'.tr,
|
labelText: 'city'.tr,
|
||||||
type: TextInputType.name,
|
type: TextInputType.name,
|
||||||
icon:
|
icon: const Icon(
|
||||||
const Icon(IconsaxPlusLinear.building_3),
|
IconsaxPlusLinear.building_3,
|
||||||
|
),
|
||||||
margin: const EdgeInsets.only(
|
margin: const EdgeInsets.only(
|
||||||
left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateName'.tr;
|
return 'validateName'.tr;
|
||||||
|
@ -442,7 +478,10 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
type: TextInputType.streetAddress,
|
type: TextInputType.streetAddress,
|
||||||
icon: const Icon(IconsaxPlusLinear.global),
|
icon: const Icon(IconsaxPlusLinear.global),
|
||||||
margin: const EdgeInsets.only(
|
margin: const EdgeInsets.only(
|
||||||
left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const Gap(20),
|
const Gap(20),
|
||||||
],
|
],
|
||||||
|
@ -453,8 +492,10 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
horizontal: 10,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
child: MyTextButton(
|
child: MyTextButton(
|
||||||
buttonName: 'done'.tr,
|
buttonName: 'done'.tr,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
@ -472,8 +513,10 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
_controllerCity.text,
|
_controllerCity.text,
|
||||||
);
|
);
|
||||||
widget.isStart
|
widget.isStart
|
||||||
? Get.off(() => const HomePage(),
|
? Get.off(
|
||||||
transition: Transition.downToUp)
|
() => const HomePage(),
|
||||||
|
transition: Transition.downToUp,
|
||||||
|
)
|
||||||
: Get.back();
|
: Get.back();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Future.error(error);
|
Future.error(error);
|
||||||
|
@ -487,9 +530,7 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
||||||
if (isLoading)
|
if (isLoading)
|
||||||
BackdropFilter(
|
BackdropFilter(
|
||||||
filter: ImageFilter.blur(sigmaY: 3, sigmaX: 3),
|
filter: ImageFilter.blur(sigmaY: 3, sigmaX: 3),
|
||||||
child: const Center(
|
child: const Center(child: CircularProgressIndicator()),
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -103,18 +103,18 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
leading: switch (tabIndex) {
|
leading: switch (tabIndex) {
|
||||||
0 => IconButton(
|
0 => IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.to(() => const SelectGeolocation(isStart: false),
|
Get.to(
|
||||||
transition: Transition.downToUp);
|
() => const SelectGeolocation(isStart: false),
|
||||||
|
transition: Transition.downToUp,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(IconsaxPlusLinear.global_search, size: 18),
|
||||||
IconsaxPlusLinear.global_search,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
int() => null,
|
int() => null,
|
||||||
},
|
},
|
||||||
title: switch (tabIndex) {
|
title: switch (tabIndex) {
|
||||||
0 => visible
|
0 =>
|
||||||
|
visible
|
||||||
? RawAutocomplete<Result>(
|
? RawAutocomplete<Result>(
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
textEditingController: _controller,
|
textEditingController: _controller,
|
||||||
|
@ -123,17 +123,17 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
style: labelLarge?.copyWith(fontSize: 16),
|
style: labelLarge?.copyWith(fontSize: 16),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(hintText: 'search'.tr),
|
||||||
hintText: 'search'.tr,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||||
if (textEditingValue.text.isEmpty) {
|
if (textEditingValue.text.isEmpty) {
|
||||||
return const Iterable<Result>.empty();
|
return const Iterable<Result>.empty();
|
||||||
}
|
}
|
||||||
return WeatherAPI()
|
return WeatherAPI().getCity(
|
||||||
.getCity(textEditingValue.text, locale);
|
textEditingValue.text,
|
||||||
|
locale,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onSelected: (Result selection) async {
|
onSelected: (Result selection) async {
|
||||||
await weatherController.deleteAll(true);
|
await weatherController.deleteAll(true);
|
||||||
|
@ -148,11 +148,13 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
_focusNode.unfocus();
|
_focusNode.unfocus();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
displayStringForOption: (Result option) =>
|
displayStringForOption:
|
||||||
'${option.name}, ${option.admin1}',
|
(Result option) => '${option.name}, ${option.admin1}',
|
||||||
optionsViewBuilder: (BuildContext context,
|
optionsViewBuilder: (
|
||||||
|
BuildContext context,
|
||||||
AutocompleteOnSelected<Result> onSelected,
|
AutocompleteOnSelected<Result> onSelected,
|
||||||
Iterable<Result> options) {
|
Iterable<Result> options,
|
||||||
|
) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
child: Material(
|
child: Material(
|
||||||
|
@ -165,8 +167,9 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: options.length,
|
itemCount: options.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final Result option =
|
final Result option = options.elementAt(
|
||||||
options.elementAt(index);
|
index,
|
||||||
|
);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => onSelected(option),
|
onTap: () => onSelected(option),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
@ -183,8 +186,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: Obx(
|
: Obx(() {
|
||||||
() {
|
|
||||||
final location = weatherController.location;
|
final location = weatherController.location;
|
||||||
final city = location.city;
|
final city = location.city;
|
||||||
final district = location.district;
|
final district = location.district;
|
||||||
|
@ -196,7 +198,8 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
? district
|
? district
|
||||||
: city == district
|
: city == district
|
||||||
? city
|
? city
|
||||||
: '$city' ', $district'
|
: '$city'
|
||||||
|
', $district'
|
||||||
: settings.location
|
: settings.location
|
||||||
? 'search'.tr
|
? 'search'.tr
|
||||||
: (isar.locationCaches.where().findAllSync())
|
: (isar.locationCaches.where().findAllSync())
|
||||||
|
@ -205,25 +208,13 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
: 'searchCity'.tr,
|
: 'searchCity'.tr,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
),
|
1 => Text('cities'.tr, style: textStyle),
|
||||||
1 => Text(
|
2 =>
|
||||||
'cities'.tr,
|
settings.hideMap
|
||||||
style: textStyle,
|
? Text('settings_full'.tr, style: textStyle)
|
||||||
),
|
: Text('map'.tr, style: textStyle),
|
||||||
2 => settings.hideMap
|
3 => Text('settings_full'.tr, style: textStyle),
|
||||||
? Text(
|
|
||||||
'settings_full'.tr,
|
|
||||||
style: textStyle,
|
|
||||||
)
|
|
||||||
: Text(
|
|
||||||
'map'.tr,
|
|
||||||
style: textStyle,
|
|
||||||
),
|
|
||||||
3 => Text(
|
|
||||||
'settings_full'.tr,
|
|
||||||
style: textStyle,
|
|
||||||
),
|
|
||||||
int() => null,
|
int() => null,
|
||||||
},
|
},
|
||||||
actions: switch (tabIndex) {
|
actions: switch (tabIndex) {
|
||||||
|
@ -245,16 +236,13 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
: IconsaxPlusLinear.search_normal_1,
|
: IconsaxPlusLinear.search_normal_1,
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
int() => null,
|
int() => null,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: TabBarView(
|
child: TabBarView(controller: tabController, children: pages),
|
||||||
controller: tabController,
|
|
||||||
children: pages,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
onDestinationSelected: (int index) => changeTabIndex(index),
|
onDestinationSelected: (int index) => changeTabIndex(index),
|
||||||
|
@ -283,17 +271,18 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: tabIndex == 1
|
floatingActionButton:
|
||||||
|
tabIndex == 1
|
||||||
? FloatingActionButton(
|
? FloatingActionButton(
|
||||||
onPressed: () => showModalBottomSheet(
|
onPressed:
|
||||||
|
() => showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
enableDrag: false,
|
enableDrag: false,
|
||||||
builder: (BuildContext context) => const CreatePlace(),
|
builder:
|
||||||
),
|
(BuildContext context) => const CreatePlace(),
|
||||||
child: const Icon(
|
|
||||||
IconsaxPlusLinear.add,
|
|
||||||
),
|
),
|
||||||
|
child: const Icon(IconsaxPlusLinear.add),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
|
|
|
@ -35,9 +35,7 @@ class _MainPageState extends State<MainPage> {
|
||||||
if (weatherController.isLoading.isTrue) {
|
if (weatherController.isLoading.isTrue) {
|
||||||
return ListView(
|
return ListView(
|
||||||
children: const [
|
children: const [
|
||||||
MyShimmer(
|
MyShimmer(hight: 200),
|
||||||
hight: 200,
|
|
||||||
),
|
|
||||||
MyShimmer(
|
MyShimmer(
|
||||||
hight: 130,
|
hight: 130,
|
||||||
edgeInsetsMargin: EdgeInsets.symmetric(vertical: 15),
|
edgeInsetsMargin: EdgeInsets.symmetric(vertical: 15),
|
||||||
|
@ -53,7 +51,7 @@ class _MainPageState extends State<MainPage> {
|
||||||
MyShimmer(
|
MyShimmer(
|
||||||
hight: 450,
|
hight: 450,
|
||||||
edgeInsetsMargin: EdgeInsets.only(bottom: 15),
|
edgeInsetsMargin: EdgeInsets.only(bottom: 15),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -82,8 +80,10 @@ class _MainPageState extends State<MainPage> {
|
||||||
Card(
|
Card(
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
horizontal: 10,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 135,
|
height: 135,
|
||||||
child: ScrollablePositionedList.separated(
|
child: ScrollablePositionedList.separated(
|
||||||
|
@ -115,8 +115,12 @@ class _MainPageState extends State<MainPage> {
|
||||||
vertical: 5,
|
vertical: 5,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: i == hourOfDay
|
color:
|
||||||
? context.theme.colorScheme.secondaryContainer
|
i == hourOfDay
|
||||||
|
? context
|
||||||
|
.theme
|
||||||
|
.colorScheme
|
||||||
|
.secondaryContainer
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(
|
||||||
Radius.circular(20),
|
Radius.circular(20),
|
||||||
|
@ -136,10 +140,7 @@ class _MainPageState extends State<MainPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SunsetSunrise(
|
SunsetSunrise(timeSunrise: sunrise, timeSunset: sunset),
|
||||||
timeSunrise: sunrise,
|
|
||||||
timeSunset: sunset,
|
|
||||||
),
|
|
||||||
DescContainer(
|
DescContainer(
|
||||||
humidity: mainWeather.relativehumidity2M?[hourOfDay],
|
humidity: mainWeather.relativehumidity2M?[hourOfDay],
|
||||||
wind: mainWeather.windspeed10M?[hourOfDay],
|
wind: mainWeather.windspeed10M?[hourOfDay],
|
||||||
|
@ -162,13 +163,12 @@ class _MainPageState extends State<MainPage> {
|
||||||
),
|
),
|
||||||
DailyContainer(
|
DailyContainer(
|
||||||
weatherData: weatherCard,
|
weatherData: weatherCard,
|
||||||
onTap: () => Get.to(
|
onTap:
|
||||||
() => DailyCardList(
|
() => Get.to(
|
||||||
weatherData: weatherCard,
|
() => DailyCardList(weatherData: weatherCard),
|
||||||
),
|
|
||||||
transition: Transition.downToUp,
|
transition: Transition.downToUp,
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -66,10 +66,9 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
_offsetAnimation = Tween<Offset>(
|
_offsetAnimation = Tween<Offset>(
|
||||||
begin: const Offset(0.0, 1.0),
|
begin: const Offset(0.0, 1.0),
|
||||||
end: Offset.zero,
|
end: Offset.zero,
|
||||||
).animate(CurvedAnimation(
|
).animate(
|
||||||
parent: _animationController,
|
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
|
||||||
curve: Curves.easeInOut,
|
);
|
||||||
));
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,25 +113,26 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
_focusNode.unfocus();
|
_focusNode.unfocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buidStyleMarkers(int weathercode, String time, String sunrise,
|
Widget _buidStyleMarkers(
|
||||||
String sunset, double temperature2M) {
|
int weathercode,
|
||||||
|
String time,
|
||||||
|
String sunrise,
|
||||||
|
String sunset,
|
||||||
|
double temperature2M,
|
||||||
|
) {
|
||||||
return Card(
|
return Card(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset(
|
||||||
statusWeather.getImageNow(
|
statusWeather.getImageNow(weathercode, time, sunrise, sunset),
|
||||||
weathercode,
|
|
||||||
time,
|
|
||||||
sunrise,
|
|
||||||
sunset,
|
|
||||||
),
|
|
||||||
scale: 18,
|
scale: 18,
|
||||||
),
|
),
|
||||||
const MaxGap(5),
|
const MaxGap(5),
|
||||||
Text(
|
Text(
|
||||||
statusData
|
statusData.getDegree(
|
||||||
.getDegree(roundDegree ? temperature2M.round() : temperature2M),
|
roundDegree ? temperature2M.round() : temperature2M,
|
||||||
|
),
|
||||||
style: context.textTheme.labelLarge?.copyWith(
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
@ -144,7 +144,10 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
}
|
}
|
||||||
|
|
||||||
Marker _buildMainLocationMarker(
|
Marker _buildMainLocationMarker(
|
||||||
WeatherCard weatherCard, int hourOfDay, int dayOfNow) {
|
WeatherCard weatherCard,
|
||||||
|
int hourOfDay,
|
||||||
|
int dayOfNow,
|
||||||
|
) {
|
||||||
return Marker(
|
return Marker(
|
||||||
height: 50,
|
height: 50,
|
||||||
width: 100,
|
width: 100,
|
||||||
|
@ -171,15 +174,25 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
onTap: () => _onMarkerTap(weatherCardList),
|
onTap: () => _onMarkerTap(weatherCardList),
|
||||||
child: _buidStyleMarkers(
|
child: _buidStyleMarkers(
|
||||||
weatherCardList.weathercode![weatherController.getTime(
|
weatherCardList.weathercode![weatherController.getTime(
|
||||||
weatherCardList.time!, weatherCardList.timezone!)],
|
weatherCardList.time!,
|
||||||
|
weatherCardList.timezone!,
|
||||||
|
)],
|
||||||
weatherCardList.time![weatherController.getTime(
|
weatherCardList.time![weatherController.getTime(
|
||||||
weatherCardList.time!, weatherCardList.timezone!)],
|
weatherCardList.time!,
|
||||||
|
weatherCardList.timezone!,
|
||||||
|
)],
|
||||||
weatherCardList.sunrise![weatherController.getDay(
|
weatherCardList.sunrise![weatherController.getDay(
|
||||||
weatherCardList.timeDaily!, weatherCardList.timezone!)],
|
weatherCardList.timeDaily!,
|
||||||
|
weatherCardList.timezone!,
|
||||||
|
)],
|
||||||
weatherCardList.sunset![weatherController.getDay(
|
weatherCardList.sunset![weatherController.getDay(
|
||||||
weatherCardList.timeDaily!, weatherCardList.timezone!)],
|
weatherCardList.timeDaily!,
|
||||||
|
weatherCardList.timezone!,
|
||||||
|
)],
|
||||||
weatherCardList.temperature2M![weatherController.getTime(
|
weatherCardList.temperature2M![weatherController.getTime(
|
||||||
weatherCardList.time!, weatherCardList.timezone!)],
|
weatherCardList.time!,
|
||||||
|
weatherCardList.timezone!,
|
||||||
|
)],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -201,7 +214,8 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
? SlideTransition(
|
? SlideTransition(
|
||||||
position: _offsetAnimation,
|
position: _offsetAnimation,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => Get.to(
|
onTap:
|
||||||
|
() => Get.to(
|
||||||
() => PlaceInfo(weatherCard: _selectedWeatherCard!),
|
() => PlaceInfo(weatherCard: _selectedWeatherCard!),
|
||||||
transition: Transition.downToUp,
|
transition: Transition.downToUp,
|
||||||
),
|
),
|
||||||
|
@ -261,11 +275,13 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: (_, __) => _hideCard(),
|
onTap: (_, __) => _hideCard(),
|
||||||
onLongPress: (tapPosition, point) => showModalBottomSheet(
|
onLongPress:
|
||||||
|
(tapPosition, point) => showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
enableDrag: false,
|
enableDrag: false,
|
||||||
builder: (BuildContext context) => CreatePlace(
|
builder:
|
||||||
|
(BuildContext context) => CreatePlace(
|
||||||
latitude: '${point.latitude}',
|
latitude: '${point.latitude}',
|
||||||
longitude: '${point.longitude}',
|
longitude: '${point.longitude}',
|
||||||
),
|
),
|
||||||
|
@ -290,8 +306,10 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
attributions: [
|
attributions: [
|
||||||
TextSourceAttribution(
|
TextSourceAttribution(
|
||||||
'OpenStreetMap contributors',
|
'OpenStreetMap contributors',
|
||||||
onTap: () => weatherController
|
onTap:
|
||||||
.urlLauncher('https://openstreetmap.org/copyright'),
|
() => weatherController.urlLauncher(
|
||||||
|
'https://openstreetmap.org/copyright',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -305,14 +323,15 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
dayOfNow,
|
dayOfNow,
|
||||||
);
|
);
|
||||||
|
|
||||||
final cardMarkers = weatherController.weatherCards
|
final cardMarkers =
|
||||||
.map((weatherCardList) =>
|
weatherController.weatherCards
|
||||||
_buildCardMarker(weatherCardList))
|
.map(
|
||||||
|
(weatherCardList) =>
|
||||||
|
_buildCardMarker(weatherCardList),
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return MarkerLayer(
|
return MarkerLayer(markers: [mainMarker, ...cardMarkers]);
|
||||||
markers: [mainMarker, ...cardMarkers],
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
ExpandableFab(
|
ExpandableFab(
|
||||||
key: _fabKey,
|
key: _fabKey,
|
||||||
|
@ -331,23 +350,31 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: null,
|
heroTag: null,
|
||||||
child: const Icon(IconsaxPlusLinear.home_2),
|
child: const Icon(IconsaxPlusLinear.home_2),
|
||||||
onPressed: () => _resetMapOrientation(
|
onPressed:
|
||||||
center:
|
() => _resetMapOrientation(
|
||||||
LatLng(mainLocation.lat!, mainLocation.lon!),
|
center: LatLng(
|
||||||
zoom: 8),
|
mainLocation.lat!,
|
||||||
|
mainLocation.lon!,
|
||||||
|
),
|
||||||
|
zoom: 8,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: null,
|
heroTag: null,
|
||||||
child: const Icon(IconsaxPlusLinear.search_zoom_out_1),
|
child: const Icon(IconsaxPlusLinear.search_zoom_out_1),
|
||||||
onPressed: () => _animatedMapController.animatedZoomOut(
|
onPressed:
|
||||||
customId: _useTransformer ? _useTransformerId : null,
|
() => _animatedMapController.animatedZoomOut(
|
||||||
|
customId:
|
||||||
|
_useTransformer ? _useTransformerId : null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: null,
|
heroTag: null,
|
||||||
child: const Icon(IconsaxPlusLinear.search_zoom_in),
|
child: const Icon(IconsaxPlusLinear.search_zoom_in),
|
||||||
onPressed: () => _animatedMapController.animatedZoomIn(
|
onPressed:
|
||||||
customId: _useTransformer ? _useTransformerId : null,
|
() => _animatedMapController.animatedZoomIn(
|
||||||
|
customId:
|
||||||
|
_useTransformer ? _useTransformerId : null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -363,10 +390,12 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
RawAutocomplete<Result>(
|
RawAutocomplete<Result>(
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
textEditingController: _controllerSearch,
|
textEditingController: _controllerSearch,
|
||||||
fieldViewBuilder: (BuildContext context,
|
fieldViewBuilder: (
|
||||||
|
BuildContext context,
|
||||||
TextEditingController fieldTextEditingController,
|
TextEditingController fieldTextEditingController,
|
||||||
FocusNode fieldFocusNode,
|
FocusNode fieldFocusNode,
|
||||||
VoidCallback onFieldSubmitted) {
|
VoidCallback onFieldSubmitted,
|
||||||
|
) {
|
||||||
return MyTextForm(
|
return MyTextForm(
|
||||||
labelText: 'search'.tr,
|
labelText: 'search'.tr,
|
||||||
type: TextInputType.text,
|
type: TextInputType.text,
|
||||||
|
@ -375,7 +404,8 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
|
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
onChanged: (value) => setState(() {}),
|
onChanged: (value) => setState(() {}),
|
||||||
iconButton: _controllerSearch.text.isNotEmpty
|
iconButton:
|
||||||
|
_controllerSearch.text.isNotEmpty
|
||||||
? IconButton(
|
? IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_controllerSearch.clear();
|
_controllerSearch.clear();
|
||||||
|
@ -397,18 +427,24 @@ class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
|
||||||
},
|
},
|
||||||
onSelected: (Result selection) {
|
onSelected: (Result selection) {
|
||||||
_animatedMapController.mapController.move(
|
_animatedMapController.mapController.move(
|
||||||
LatLng(selection.latitude, selection.longitude), 14);
|
LatLng(selection.latitude, selection.longitude),
|
||||||
|
14,
|
||||||
|
);
|
||||||
_controllerSearch.clear();
|
_controllerSearch.clear();
|
||||||
_focusNode.unfocus();
|
_focusNode.unfocus();
|
||||||
},
|
},
|
||||||
displayStringForOption: (Result option) =>
|
displayStringForOption:
|
||||||
'${option.name}, ${option.admin1}',
|
(Result option) => '${option.name}, ${option.admin1}',
|
||||||
optionsViewBuilder: (BuildContext context,
|
optionsViewBuilder: (
|
||||||
|
BuildContext context,
|
||||||
AutocompleteOnSelected<Result> onSelected,
|
AutocompleteOnSelected<Result> onSelected,
|
||||||
Iterable<Result> options) {
|
Iterable<Result> options,
|
||||||
|
) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
horizontal: 10,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: Material(
|
child: Material(
|
||||||
|
|
|
@ -32,8 +32,10 @@ class _OnBordingState extends State<OnBording> {
|
||||||
void onBoardHome() {
|
void onBoardHome() {
|
||||||
settings.onboard = true;
|
settings.onboard = true;
|
||||||
isar.writeTxnSync(() => isar.settings.putSync(settings));
|
isar.writeTxnSync(() => isar.settings.putSync(settings));
|
||||||
Get.off(() => const SelectGeolocation(isStart: true),
|
Get.off(
|
||||||
transition: Transition.downToUp);
|
() => const SelectGeolocation(isStart: true),
|
||||||
|
transition: Transition.downToUp,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -52,7 +54,8 @@ class _OnBordingState extends State<OnBording> {
|
||||||
pageIndex = index;
|
pageIndex = index;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
itemBuilder: (context, index) => OnboardContent(
|
itemBuilder:
|
||||||
|
(context, index) => OnboardContent(
|
||||||
image: data[index].image,
|
image: data[index].image,
|
||||||
title: data[index].title,
|
title: data[index].title,
|
||||||
description: data[index].description,
|
description: data[index].description,
|
||||||
|
@ -67,7 +70,8 @@ class _OnBordingState extends State<OnBording> {
|
||||||
(index) => Padding(
|
(index) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||||
child: DotIndicator(isActive: index == pageIndex),
|
child: DotIndicator(isActive: index == pageIndex),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -84,7 +88,7 @@ class _OnBordingState extends State<OnBording> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -93,10 +97,7 @@ class _OnBordingState extends State<OnBording> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DotIndicator extends StatelessWidget {
|
class DotIndicator extends StatelessWidget {
|
||||||
const DotIndicator({
|
const DotIndicator({super.key, this.isActive = false});
|
||||||
super.key,
|
|
||||||
this.isActive = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
final bool isActive;
|
final bool isActive;
|
||||||
|
|
||||||
|
@ -107,7 +108,8 @@ class DotIndicator extends StatelessWidget {
|
||||||
height: 8,
|
height: 8,
|
||||||
width: 8,
|
width: 8,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isActive
|
color:
|
||||||
|
isActive
|
||||||
? context.theme.colorScheme.secondary
|
? context.theme.colorScheme.secondary
|
||||||
: context.theme.colorScheme.secondaryContainer,
|
: context.theme.colorScheme.secondaryContainer,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
|
@ -130,15 +132,18 @@ final List<Onboard> data = [
|
||||||
Onboard(
|
Onboard(
|
||||||
image: 'assets/icons/Rain.png',
|
image: 'assets/icons/Rain.png',
|
||||||
title: 'name'.tr,
|
title: 'name'.tr,
|
||||||
description: 'description'.tr),
|
description: 'description'.tr,
|
||||||
|
),
|
||||||
Onboard(
|
Onboard(
|
||||||
image: 'assets/icons/Design.png',
|
image: 'assets/icons/Design.png',
|
||||||
title: 'name2'.tr,
|
title: 'name2'.tr,
|
||||||
description: 'description2'.tr),
|
description: 'description2'.tr,
|
||||||
|
),
|
||||||
Onboard(
|
Onboard(
|
||||||
image: 'assets/icons/Team.png',
|
image: 'assets/icons/Team.png',
|
||||||
title: 'name3'.tr,
|
title: 'name3'.tr,
|
||||||
description: 'description3'.tr),
|
description: 'description3'.tr,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
class OnboardContent extends StatelessWidget {
|
class OnboardContent extends StatelessWidget {
|
||||||
|
@ -158,14 +163,12 @@ class OnboardContent extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset(image, scale: 5),
|
||||||
image,
|
|
||||||
scale: 5,
|
|
||||||
),
|
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: context.textTheme.titleLarge
|
style: context.textTheme.titleLarge?.copyWith(
|
||||||
?.copyWith(fontWeight: FontWeight.w600),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const Gap(10),
|
const Gap(10),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
|
|
@ -12,10 +12,7 @@ import 'package:rain/app/ui/widgets/weather/sunset_sunrise.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
|
||||||
class PlaceInfo extends StatefulWidget {
|
class PlaceInfo extends StatefulWidget {
|
||||||
const PlaceInfo({
|
const PlaceInfo({super.key, required this.weatherCard});
|
||||||
super.key,
|
|
||||||
required this.weatherCard,
|
|
||||||
});
|
|
||||||
final WeatherCard weatherCard;
|
final WeatherCard weatherCard;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -37,10 +34,14 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
void getTime() {
|
void getTime() {
|
||||||
final weatherCard = widget.weatherCard;
|
final weatherCard = widget.weatherCard;
|
||||||
|
|
||||||
timeNow =
|
timeNow = weatherController.getTime(
|
||||||
weatherController.getTime(weatherCard.time!, weatherCard.timezone!);
|
weatherCard.time!,
|
||||||
dayNow =
|
weatherCard.timezone!,
|
||||||
weatherController.getDay(weatherCard.timeDaily!, weatherCard.timezone!);
|
);
|
||||||
|
dayNow = weatherController.getDay(
|
||||||
|
weatherCard.timeDaily!,
|
||||||
|
weatherCard.timezone!,
|
||||||
|
);
|
||||||
Future.delayed(const Duration(milliseconds: 30), () {
|
Future.delayed(const Duration(milliseconds: 30), () {
|
||||||
itemScrollController.scrollTo(
|
itemScrollController.scrollTo(
|
||||||
index: timeNow,
|
index: timeNow,
|
||||||
|
@ -66,10 +67,7 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () => Get.back(),
|
onPressed: () => Get.back(),
|
||||||
icon: const Icon(
|
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
|
||||||
IconsaxPlusLinear.arrow_left_3,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
weatherCard.district!.isNotEmpty
|
weatherCard.district!.isNotEmpty
|
||||||
|
@ -100,8 +98,10 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
Card(
|
Card(
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
horizontal: 10,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 135,
|
height: 135,
|
||||||
child: ScrollablePositionedList.separated(
|
child: ScrollablePositionedList.separated(
|
||||||
|
@ -116,7 +116,8 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemScrollController: itemScrollController,
|
itemScrollController: itemScrollController,
|
||||||
itemCount: weatherCard.time!.length,
|
itemCount: weatherCard.time!.length,
|
||||||
itemBuilder: (ctx, i) => GestureDetector(
|
itemBuilder:
|
||||||
|
(ctx, i) => GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
timeNow = i;
|
timeNow = i;
|
||||||
dayNow = (i / 24).floor();
|
dayNow = (i / 24).floor();
|
||||||
|
@ -129,8 +130,12 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
vertical: 5,
|
vertical: 5,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: i == timeNow
|
color:
|
||||||
? context.theme.colorScheme.secondaryContainer
|
i == timeNow
|
||||||
|
? context
|
||||||
|
.theme
|
||||||
|
.colorScheme
|
||||||
|
.secondaryContainer
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(
|
||||||
Radius.circular(20),
|
Radius.circular(20),
|
||||||
|
@ -140,8 +145,10 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
time: weatherCard.time![i],
|
time: weatherCard.time![i],
|
||||||
weather: weatherCard.weathercode![i],
|
weather: weatherCard.weathercode![i],
|
||||||
degree: weatherCard.temperature2M![i],
|
degree: weatherCard.temperature2M![i],
|
||||||
timeDay: weatherCard.sunrise![(i / 24).floor()],
|
timeDay:
|
||||||
timeNight: weatherCard.sunset![(i / 24).floor()],
|
weatherCard.sunrise![(i / 24).floor()],
|
||||||
|
timeNight:
|
||||||
|
weatherCard.sunset![(i / 24).floor()],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -175,10 +182,9 @@ class _PlaceInfoState extends State<PlaceInfo> {
|
||||||
),
|
),
|
||||||
DailyContainer(
|
DailyContainer(
|
||||||
weatherData: weatherCard,
|
weatherData: weatherCard,
|
||||||
onTap: () => Get.to(
|
onTap:
|
||||||
() => DailyCardList(
|
() => Get.to(
|
||||||
weatherData: weatherCard,
|
() => DailyCardList(weatherData: weatherCard),
|
||||||
),
|
|
||||||
transition: Transition.downToUp,
|
transition: Transition.downToUp,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -33,15 +33,13 @@ class _PlaceListState extends State<PlaceList> {
|
||||||
final textTheme = context.textTheme;
|
final textTheme = context.textTheme;
|
||||||
final titleMedium = textTheme.titleMedium;
|
final titleMedium = textTheme.titleMedium;
|
||||||
return Obx(
|
return Obx(
|
||||||
() => weatherController.weatherCards.isEmpty
|
() =>
|
||||||
|
weatherController.weatherCards.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset('assets/icons/City.png', scale: 6),
|
||||||
'assets/icons/City.png',
|
|
||||||
scale: 6,
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: Get.size.width * 0.8,
|
width: Get.size.width * 0.8,
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -71,9 +69,12 @@ class _PlaceListState extends State<PlaceList> {
|
||||||
),
|
),
|
||||||
controller: searchTasks,
|
controller: searchTasks,
|
||||||
margin: const EdgeInsets.symmetric(
|
margin: const EdgeInsets.symmetric(
|
||||||
horizontal: 10, vertical: 5),
|
horizontal: 10,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
onChanged: applyFilter,
|
onChanged: applyFilter,
|
||||||
iconButton: searchTasks.text.isNotEmpty
|
iconButton:
|
||||||
|
searchTasks.text.isNotEmpty
|
||||||
? IconButton(
|
? IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
searchTasks.clear();
|
searchTasks.clear();
|
||||||
|
|
|
@ -9,11 +9,7 @@ import 'package:rain/app/ui/widgets/text_form.dart';
|
||||||
import 'package:rain/main.dart';
|
import 'package:rain/main.dart';
|
||||||
|
|
||||||
class CreatePlace extends StatefulWidget {
|
class CreatePlace extends StatefulWidget {
|
||||||
const CreatePlace({
|
const CreatePlace({super.key, this.latitude, this.longitude});
|
||||||
super.key,
|
|
||||||
this.latitude,
|
|
||||||
this.longitude,
|
|
||||||
});
|
|
||||||
final String? latitude;
|
final String? latitude;
|
||||||
final String? longitude;
|
final String? longitude;
|
||||||
|
|
||||||
|
@ -85,7 +81,8 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const kTextFieldElevation = 4.0;
|
const kTextFieldElevation = 4.0;
|
||||||
bool showButton = _controllerLon.text.isNotEmpty &&
|
bool showButton =
|
||||||
|
_controllerLon.text.isNotEmpty &&
|
||||||
_controllerLat.text.isNotEmpty &&
|
_controllerLat.text.isNotEmpty &&
|
||||||
_controllerCity.text.isNotEmpty &&
|
_controllerCity.text.isNotEmpty &&
|
||||||
_controllerDistrict.text.isNotEmpty;
|
_controllerDistrict.text.isNotEmpty;
|
||||||
|
@ -115,18 +112,21 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
padding: const EdgeInsets.only(top: 14, bottom: 7),
|
padding: const EdgeInsets.only(top: 14, bottom: 7),
|
||||||
child: Text(
|
child: Text(
|
||||||
'create'.tr,
|
'create'.tr,
|
||||||
style: context.textTheme.titleLarge
|
style: context.textTheme.titleLarge?.copyWith(
|
||||||
?.copyWith(fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
RawAutocomplete<Result>(
|
RawAutocomplete<Result>(
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
textEditingController: _controller,
|
textEditingController: _controller,
|
||||||
fieldViewBuilder: (BuildContext context,
|
fieldViewBuilder: (
|
||||||
|
BuildContext context,
|
||||||
TextEditingController fieldTextEditingController,
|
TextEditingController fieldTextEditingController,
|
||||||
FocusNode fieldFocusNode,
|
FocusNode fieldFocusNode,
|
||||||
VoidCallback onFieldSubmitted) {
|
VoidCallback onFieldSubmitted,
|
||||||
|
) {
|
||||||
return MyTextForm(
|
return MyTextForm(
|
||||||
elevation: kTextFieldElevation,
|
elevation: kTextFieldElevation,
|
||||||
labelText: 'search'.tr,
|
labelText: 'search'.tr,
|
||||||
|
@ -134,7 +134,10 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
icon: const Icon(IconsaxPlusLinear.global_search),
|
icon: const Icon(IconsaxPlusLinear.global_search),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
margin: const EdgeInsets.only(
|
margin: const EdgeInsets.only(
|
||||||
left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -142,16 +145,20 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
if (textEditingValue.text.isEmpty) {
|
if (textEditingValue.text.isEmpty) {
|
||||||
return const Iterable<Result>.empty();
|
return const Iterable<Result>.empty();
|
||||||
}
|
}
|
||||||
return WeatherAPI()
|
return WeatherAPI().getCity(
|
||||||
.getCity(textEditingValue.text, locale);
|
textEditingValue.text,
|
||||||
|
locale,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onSelected: (Result selection) =>
|
onSelected:
|
||||||
fillController(selection),
|
(Result selection) => fillController(selection),
|
||||||
displayStringForOption: (Result option) =>
|
displayStringForOption:
|
||||||
'${option.name}, ${option.admin1}',
|
(Result option) => '${option.name}, ${option.admin1}',
|
||||||
optionsViewBuilder: (BuildContext context,
|
optionsViewBuilder: (
|
||||||
|
BuildContext context,
|
||||||
AutocompleteOnSelected<Result> onSelected,
|
AutocompleteOnSelected<Result> onSelected,
|
||||||
Iterable<Result> options) {
|
Iterable<Result> options,
|
||||||
|
) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
child: Align(
|
child: Align(
|
||||||
|
@ -164,8 +171,9 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: options.length,
|
itemCount: options.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final Result option =
|
final Result option = options.elementAt(
|
||||||
options.elementAt(index);
|
index,
|
||||||
|
);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => onSelected(option),
|
onTap: () => onSelected(option),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
@ -189,8 +197,11 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
type: TextInputType.number,
|
type: TextInputType.number,
|
||||||
icon: const Icon(IconsaxPlusLinear.location),
|
icon: const Icon(IconsaxPlusLinear.location),
|
||||||
onChanged: (value) => setState(() {}),
|
onChanged: (value) => setState(() {}),
|
||||||
margin:
|
margin: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateValue'.tr;
|
return 'validateValue'.tr;
|
||||||
|
@ -212,8 +223,11 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
type: TextInputType.number,
|
type: TextInputType.number,
|
||||||
icon: const Icon(IconsaxPlusLinear.location),
|
icon: const Icon(IconsaxPlusLinear.location),
|
||||||
onChanged: (value) => setState(() {}),
|
onChanged: (value) => setState(() {}),
|
||||||
margin:
|
margin: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateValue'.tr;
|
return 'validateValue'.tr;
|
||||||
|
@ -235,8 +249,11 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
type: TextInputType.name,
|
type: TextInputType.name,
|
||||||
icon: const Icon(IconsaxPlusLinear.building_3),
|
icon: const Icon(IconsaxPlusLinear.building_3),
|
||||||
onChanged: (value) => setState(() {}),
|
onChanged: (value) => setState(() {}),
|
||||||
margin:
|
margin: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateName'.tr;
|
return 'validateName'.tr;
|
||||||
|
@ -251,8 +268,11 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
type: TextInputType.streetAddress,
|
type: TextInputType.streetAddress,
|
||||||
icon: const Icon(IconsaxPlusLinear.global),
|
icon: const Icon(IconsaxPlusLinear.global),
|
||||||
onChanged: (value) => setState(() {}),
|
onChanged: (value) => setState(() {}),
|
||||||
margin:
|
margin: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(left: 10, right: 10, top: 10),
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'validateName'.tr;
|
return 'validateName'.tr;
|
||||||
|
@ -262,7 +282,9 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10, vertical: 10),
|
horizontal: 10,
|
||||||
|
vertical: 10,
|
||||||
|
),
|
||||||
child: SizeTransition(
|
child: SizeTransition(
|
||||||
sizeFactor: _animation,
|
sizeFactor: _animation,
|
||||||
axisAlignment: -1.0,
|
axisAlignment: -1.0,
|
||||||
|
@ -291,10 +313,7 @@ class _CreatePlaceState extends State<CreatePlace>
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isLoading)
|
if (isLoading) const Center(child: CircularProgressIndicator()),
|
||||||
const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -54,10 +54,15 @@ class _PlaceCardState extends State<PlaceCard> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
statusData.getDegree(widget.degree[weatherController
|
statusData.getDegree(
|
||||||
.getTime(widget.time, widget.timezone)]
|
widget
|
||||||
|
.degree[weatherController.getTime(
|
||||||
|
widget.time,
|
||||||
|
widget.timezone,
|
||||||
|
)]
|
||||||
.round()
|
.round()
|
||||||
.toInt()),
|
.toInt(),
|
||||||
|
),
|
||||||
style: context.textTheme.titleLarge?.copyWith(
|
style: context.textTheme.titleLarge?.copyWith(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
@ -65,8 +70,12 @@ class _PlaceCardState extends State<PlaceCard> {
|
||||||
),
|
),
|
||||||
const Gap(7),
|
const Gap(7),
|
||||||
Text(
|
Text(
|
||||||
statusWeather.getText(widget.weather[weatherController
|
statusWeather.getText(
|
||||||
.getTime(widget.time, widget.timezone)]),
|
widget.weather[weatherController.getTime(
|
||||||
|
widget.time,
|
||||||
|
widget.timezone,
|
||||||
|
)],
|
||||||
|
),
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
|
@ -107,14 +116,23 @@ class _PlaceCardState extends State<PlaceCard> {
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Image.asset(
|
Image.asset(
|
||||||
statusWeather.getImageNow(
|
statusWeather.getImageNow(
|
||||||
widget.weather[
|
widget.weather[weatherController.getTime(
|
||||||
weatherController.getTime(widget.time, widget.timezone)],
|
widget.time,
|
||||||
widget.time[
|
widget.timezone,
|
||||||
weatherController.getTime(widget.time, widget.timezone)],
|
)],
|
||||||
|
widget.time[weatherController.getTime(
|
||||||
|
widget.time,
|
||||||
|
widget.timezone,
|
||||||
|
)],
|
||||||
widget.timeDay[weatherController.getDay(
|
widget.timeDay[weatherController.getDay(
|
||||||
widget.timeDaily, widget.timezone)],
|
widget.timeDaily,
|
||||||
|
widget.timezone,
|
||||||
|
)],
|
||||||
widget.timeNight[weatherController.getDay(
|
widget.timeNight[weatherController.getDay(
|
||||||
widget.timeDaily, widget.timezone)]),
|
widget.timeDaily,
|
||||||
|
widget.timezone,
|
||||||
|
)],
|
||||||
|
),
|
||||||
scale: 6.5,
|
scale: 6.5,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -6,10 +6,7 @@ import 'package:rain/app/ui/places/view/place_info.dart';
|
||||||
import 'package:rain/app/ui/places/widgets/place_card.dart';
|
import 'package:rain/app/ui/places/widgets/place_card.dart';
|
||||||
|
|
||||||
class PlaceCardList extends StatefulWidget {
|
class PlaceCardList extends StatefulWidget {
|
||||||
const PlaceCardList({
|
const PlaceCardList({super.key, required this.searchCity});
|
||||||
super.key,
|
|
||||||
required this.searchCity,
|
|
||||||
});
|
|
||||||
final String searchCity;
|
final String searchCity;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -24,15 +21,21 @@ class _PlaceCardListState extends State<PlaceCardList> {
|
||||||
final textTheme = context.textTheme;
|
final textTheme = context.textTheme;
|
||||||
final titleMedium = textTheme.titleMedium;
|
final titleMedium = textTheme.titleMedium;
|
||||||
|
|
||||||
var weatherCards = weatherController.weatherCards
|
var weatherCards =
|
||||||
.where((weatherCard) => (widget.searchCity.isEmpty ||
|
weatherController.weatherCards
|
||||||
weatherCard.city!.toLowerCase().contains(widget.searchCity)))
|
.where(
|
||||||
|
(weatherCard) =>
|
||||||
|
(widget.searchCity.isEmpty ||
|
||||||
|
weatherCard.city!.toLowerCase().contains(
|
||||||
|
widget.searchCity,
|
||||||
|
)),
|
||||||
|
)
|
||||||
.toList()
|
.toList()
|
||||||
.obs;
|
.obs;
|
||||||
|
|
||||||
return ReorderableListView(
|
return ReorderableListView(
|
||||||
onReorder: (oldIndex, newIndex) =>
|
onReorder:
|
||||||
weatherController.reorder(oldIndex, newIndex),
|
(oldIndex, newIndex) => weatherController.reorder(oldIndex, newIndex),
|
||||||
children: [
|
children: [
|
||||||
...weatherCards.map(
|
...weatherCards.map(
|
||||||
(weatherCardList) => Dismissible(
|
(weatherCardList) => Dismissible(
|
||||||
|
@ -42,10 +45,7 @@ class _PlaceCardListState extends State<PlaceCardList> {
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
padding: EdgeInsets.only(right: 15),
|
padding: EdgeInsets.only(right: 15),
|
||||||
child: Icon(
|
child: Icon(IconsaxPlusLinear.trash_square, color: Colors.red),
|
||||||
IconsaxPlusLinear.trash_square,
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
confirmDismiss: (DismissDirection direction) async {
|
confirmDismiss: (DismissDirection direction) async {
|
||||||
|
@ -75,9 +75,7 @@ class _PlaceCardListState extends State<PlaceCardList> {
|
||||||
onPressed: () => Get.back(result: true),
|
onPressed: () => Get.back(result: true),
|
||||||
child: Text(
|
child: Text(
|
||||||
'delete'.tr,
|
'delete'.tr,
|
||||||
style: titleMedium?.copyWith(
|
style: titleMedium?.copyWith(color: Colors.red),
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -89,10 +87,9 @@ class _PlaceCardListState extends State<PlaceCardList> {
|
||||||
await weatherController.deleteCardWeather(weatherCardList);
|
await weatherController.deleteCardWeather(weatherCardList);
|
||||||
},
|
},
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => Get.to(
|
onTap:
|
||||||
() => PlaceInfo(
|
() => Get.to(
|
||||||
weatherCard: weatherCardList,
|
() => PlaceInfo(weatherCard: weatherCardList),
|
||||||
),
|
|
||||||
transition: Transition.downToUp,
|
transition: Transition.downToUp,
|
||||||
),
|
),
|
||||||
child: PlaceCard(
|
child: PlaceCard(
|
||||||
|
|
|
@ -41,9 +41,7 @@ class SettingCard extends StatelessWidget {
|
||||||
elevation: elevation ?? 1,
|
elevation: elevation ?? 1,
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
),
|
|
||||||
onTap: onPressed,
|
onTap: onPressed,
|
||||||
leading: icon,
|
leading: icon,
|
||||||
title: Text(
|
title: Text(
|
||||||
|
@ -51,13 +49,11 @@ class SettingCard extends StatelessWidget {
|
||||||
style: context.textTheme.titleMedium,
|
style: context.textTheme.titleMedium,
|
||||||
overflow: TextOverflow.visible,
|
overflow: TextOverflow.visible,
|
||||||
),
|
),
|
||||||
trailing: switcher
|
trailing:
|
||||||
|
switcher
|
||||||
? Transform.scale(
|
? Transform.scale(
|
||||||
scale: 0.8,
|
scale: 0.8,
|
||||||
child: Switch(
|
child: Switch(value: value!, onChanged: onChange),
|
||||||
value: value!,
|
|
||||||
onChanged: onChange,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: dropdown
|
: dropdown
|
||||||
? DropdownButton<String>(
|
? DropdownButton<String>(
|
||||||
|
@ -70,8 +66,10 @@ class SettingCard extends StatelessWidget {
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
||||||
underline: Container(),
|
underline: Container(),
|
||||||
value: dropdownName,
|
value: dropdownName,
|
||||||
items: dropdownList!
|
items:
|
||||||
.map<DropdownMenuItem<String>>((String value) {
|
dropdownList!.map<DropdownMenuItem<String>>((
|
||||||
|
String value,
|
||||||
|
) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value),
|
child: Text(value),
|
||||||
|
@ -84,17 +82,11 @@ class SettingCard extends StatelessWidget {
|
||||||
? Wrap(
|
? Wrap(
|
||||||
children: [
|
children: [
|
||||||
infoWidget!,
|
infoWidget!,
|
||||||
const Icon(
|
const Icon(IconsaxPlusLinear.arrow_right_3, size: 18),
|
||||||
IconsaxPlusLinear.arrow_right_3,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: infoWidget!
|
: infoWidget!
|
||||||
: const Icon(
|
: const Icon(IconsaxPlusLinear.arrow_right_3, size: 18),
|
||||||
IconsaxPlusLinear.arrow_right_3,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,11 @@ class MyTextButton extends StatelessWidget {
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
shadowColor: const WidgetStatePropertyAll(Colors.transparent),
|
shadowColor: const WidgetStatePropertyAll(Colors.transparent),
|
||||||
backgroundColor: WidgetStatePropertyAll(
|
backgroundColor: WidgetStatePropertyAll(
|
||||||
context.theme.colorScheme.secondaryContainer.withAlpha(80)),
|
context.theme.colorScheme.secondaryContainer.withAlpha(80),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
child: Text(
|
child: Text(buttonName, style: context.textTheme.titleMedium),
|
||||||
buttonName,
|
|
||||||
style: context.textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,7 @@ import 'package:get/get.dart';
|
||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
class MyShimmer extends StatelessWidget {
|
class MyShimmer extends StatelessWidget {
|
||||||
const MyShimmer({
|
const MyShimmer({super.key, required this.hight, this.edgeInsetsMargin});
|
||||||
super.key,
|
|
||||||
required this.hight,
|
|
||||||
this.edgeInsetsMargin,
|
|
||||||
});
|
|
||||||
final double hight;
|
final double hight;
|
||||||
final EdgeInsets? edgeInsetsMargin;
|
final EdgeInsets? edgeInsetsMargin;
|
||||||
|
|
||||||
|
@ -16,12 +12,7 @@ class MyShimmer extends StatelessWidget {
|
||||||
return Shimmer.fromColors(
|
return Shimmer.fromColors(
|
||||||
baseColor: context.theme.cardColor,
|
baseColor: context.theme.cardColor,
|
||||||
highlightColor: context.theme.primaryColor,
|
highlightColor: context.theme.primaryColor,
|
||||||
child: Card(
|
child: Card(margin: edgeInsetsMargin, child: SizedBox(height: hight)),
|
||||||
margin: edgeInsetsMargin,
|
|
||||||
child: SizedBox(
|
|
||||||
height: hight,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,9 @@ class _DailyCardState extends State<DailyCard> {
|
||||||
),
|
),
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Text(
|
Text(
|
||||||
DateFormat.MMMMEEEEd(locale.languageCode)
|
DateFormat.MMMMEEEEd(
|
||||||
.format(widget.timeDaily),
|
locale.languageCode,
|
||||||
|
).format(widget.timeDaily),
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
|
|
|
@ -64,16 +64,14 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
|
||||||
IconsaxPlusLinear.arrow_left_3,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
DateFormat.MMMMEEEEd(locale.languageCode)
|
DateFormat.MMMMEEEEd(
|
||||||
.format(timeDaily[pageIndex]),
|
locale.languageCode,
|
||||||
|
).format(timeDaily[pageIndex]),
|
||||||
style: textTheme.titleMedium?.copyWith(
|
style: textTheme.titleMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
@ -121,10 +119,11 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
Now(
|
Now(
|
||||||
weather:
|
weather:
|
||||||
weatherData.weathercode![startIndex + hourOfDay],
|
weatherData.weathercode![startIndex + hourOfDay],
|
||||||
degree: weatherData
|
degree:
|
||||||
.temperature2M![startIndex + hourOfDay],
|
weatherData.temperature2M![startIndex + hourOfDay],
|
||||||
feels: weatherData
|
feels:
|
||||||
.apparentTemperature![startIndex + hourOfDay]!,
|
weatherData.apparentTemperature![startIndex +
|
||||||
|
hourOfDay]!,
|
||||||
time: weatherData.time![startIndex + hourOfDay],
|
time: weatherData.time![startIndex + hourOfDay],
|
||||||
timeDay: sunrise,
|
timeDay: sunrise,
|
||||||
timeNight: sunset,
|
timeNight: sunset,
|
||||||
|
@ -135,12 +134,16 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10, vertical: 5),
|
horizontal: 10,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 135,
|
height: 135,
|
||||||
child: ScrollablePositionedList.separated(
|
child: ScrollablePositionedList.separated(
|
||||||
separatorBuilder:
|
separatorBuilder: (
|
||||||
(BuildContext context, int index) {
|
BuildContext context,
|
||||||
|
int index,
|
||||||
|
) {
|
||||||
return const VerticalDivider(
|
return const VerticalDivider(
|
||||||
width: 10,
|
width: 10,
|
||||||
indent: 40,
|
indent: 40,
|
||||||
|
@ -158,14 +161,18 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.symmetric(
|
margin: const EdgeInsets.symmetric(
|
||||||
vertical: 5),
|
vertical: 5,
|
||||||
|
),
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 20,
|
horizontal: 20,
|
||||||
vertical: 5,
|
vertical: 5,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: i == hourOfDay
|
color:
|
||||||
? context.theme.colorScheme
|
i == hourOfDay
|
||||||
|
? context
|
||||||
|
.theme
|
||||||
|
.colorScheme
|
||||||
.secondaryContainer
|
.secondaryContainer
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(
|
||||||
|
@ -174,9 +181,10 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
),
|
),
|
||||||
child: Hourly(
|
child: Hourly(
|
||||||
time: weatherData.time![hourlyIndex],
|
time: weatherData.time![hourlyIndex],
|
||||||
weather: weatherData
|
weather:
|
||||||
.weathercode![hourlyIndex],
|
weatherData.weathercode![hourlyIndex],
|
||||||
degree: weatherData
|
degree:
|
||||||
|
weatherData
|
||||||
.temperature2M![hourlyIndex],
|
.temperature2M![hourlyIndex],
|
||||||
timeDay: sunrise,
|
timeDay: sunrise,
|
||||||
timeNight: sunset,
|
timeNight: sunset,
|
||||||
|
@ -188,27 +196,28 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SunsetSunrise(
|
SunsetSunrise(timeSunrise: sunrise, timeSunset: sunset),
|
||||||
timeSunrise: sunrise,
|
|
||||||
timeSunset: sunset,
|
|
||||||
),
|
|
||||||
DescContainer(
|
DescContainer(
|
||||||
humidity: weatherData
|
humidity:
|
||||||
.relativehumidity2M?[startIndex + hourOfDay],
|
weatherData.relativehumidity2M?[startIndex +
|
||||||
wind:
|
hourOfDay],
|
||||||
weatherData.windspeed10M?[startIndex + hourOfDay],
|
wind: weatherData.windspeed10M?[startIndex + hourOfDay],
|
||||||
visibility:
|
visibility:
|
||||||
weatherData.visibility?[startIndex + hourOfDay],
|
weatherData.visibility?[startIndex + hourOfDay],
|
||||||
feels: weatherData
|
feels:
|
||||||
.apparentTemperature?[startIndex + hourOfDay],
|
weatherData.apparentTemperature?[startIndex +
|
||||||
evaporation: weatherData
|
hourOfDay],
|
||||||
.evapotranspiration?[startIndex + hourOfDay],
|
evaporation:
|
||||||
precipitation: weatherData
|
weatherData.evapotranspiration?[startIndex +
|
||||||
.precipitation?[startIndex + hourOfDay],
|
hourOfDay],
|
||||||
direction: weatherData
|
precipitation:
|
||||||
.winddirection10M?[startIndex + hourOfDay],
|
weatherData.precipitation?[startIndex + hourOfDay],
|
||||||
pressure: weatherData
|
direction:
|
||||||
.surfacePressure?[startIndex + hourOfDay],
|
weatherData.winddirection10M?[startIndex +
|
||||||
|
hourOfDay],
|
||||||
|
pressure:
|
||||||
|
weatherData.surfacePressure?[startIndex +
|
||||||
|
hourOfDay],
|
||||||
rain: weatherData.rain?[startIndex + hourOfDay],
|
rain: weatherData.rain?[startIndex + hourOfDay],
|
||||||
cloudcover:
|
cloudcover:
|
||||||
weatherData.cloudcover?[startIndex + hourOfDay],
|
weatherData.cloudcover?[startIndex + hourOfDay],
|
||||||
|
@ -218,10 +227,11 @@ class _DailyCardInfoState extends State<DailyCardInfo> {
|
||||||
dewpoint2M:
|
dewpoint2M:
|
||||||
weatherData.dewpoint2M?[startIndex + hourOfDay],
|
weatherData.dewpoint2M?[startIndex + hourOfDay],
|
||||||
precipitationProbability:
|
precipitationProbability:
|
||||||
weatherData.precipitationProbability?[
|
weatherData.precipitationProbability?[startIndex +
|
||||||
startIndex + hourOfDay],
|
hourOfDay],
|
||||||
shortwaveRadiation: weatherData
|
shortwaveRadiation:
|
||||||
.shortwaveRadiation?[startIndex + hourOfDay],
|
weatherData.shortwaveRadiation?[startIndex +
|
||||||
|
hourOfDay],
|
||||||
initiallyExpanded: true,
|
initiallyExpanded: true,
|
||||||
title: 'hourlyVariables'.tr,
|
title: 'hourlyVariables'.tr,
|
||||||
),
|
),
|
||||||
|
|
|
@ -6,10 +6,7 @@ import 'package:rain/app/ui/widgets/weather/daily/daily_card_info.dart';
|
||||||
import 'package:rain/app/ui/widgets/weather/daily/daily_card.dart';
|
import 'package:rain/app/ui/widgets/weather/daily/daily_card.dart';
|
||||||
|
|
||||||
class DailyCardList extends StatefulWidget {
|
class DailyCardList extends StatefulWidget {
|
||||||
const DailyCardList({
|
const DailyCardList({super.key, required this.weatherData});
|
||||||
super.key,
|
|
||||||
required this.weatherData,
|
|
||||||
});
|
|
||||||
final WeatherCard weatherData;
|
final WeatherCard weatherData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -31,10 +28,7 @@ class _DailyCardListState extends State<DailyCardList> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
|
||||||
IconsaxPlusLinear.arrow_left_3,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
splashColor: transparent,
|
splashColor: transparent,
|
||||||
highlightColor: transparent,
|
highlightColor: transparent,
|
||||||
),
|
),
|
||||||
|
@ -49,12 +43,12 @@ class _DailyCardListState extends State<DailyCardList> {
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: timeDaily.length,
|
itemCount: timeDaily.length,
|
||||||
itemBuilder: (context, index) => GestureDetector(
|
itemBuilder:
|
||||||
onTap: () => Get.to(
|
(context, index) => GestureDetector(
|
||||||
() => DailyCardInfo(
|
onTap:
|
||||||
weatherData: weatherData,
|
() => Get.to(
|
||||||
index: index,
|
() =>
|
||||||
),
|
DailyCardInfo(weatherData: weatherData, index: index),
|
||||||
transition: Transition.downToUp,
|
transition: Transition.downToUp,
|
||||||
),
|
),
|
||||||
child: DailyCard(
|
child: DailyCard(
|
||||||
|
|
|
@ -29,9 +29,7 @@ class _DailyContainerState extends State<DailyContainer> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final splashColor = context.theme.colorScheme.primary.withOpacity(0.4);
|
final splashColor = context.theme.colorScheme.primary.withOpacity(0.4);
|
||||||
const inkWellBorderRadius = BorderRadius.all(
|
const inkWellBorderRadius = BorderRadius.all(Radius.circular(16));
|
||||||
Radius.circular(16),
|
|
||||||
);
|
|
||||||
|
|
||||||
final weatherData = widget.weatherData;
|
final weatherData = widget.weatherData;
|
||||||
final weatherCodeDaily = weatherData.weathercodeDaily ?? [];
|
final weatherCodeDaily = weatherData.weathercodeDaily ?? [];
|
||||||
|
@ -52,7 +50,8 @@ class _DailyContainerState extends State<DailyContainer> {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
splashColor: splashColor,
|
splashColor: splashColor,
|
||||||
borderRadius: inkWellBorderRadius,
|
borderRadius: inkWellBorderRadius,
|
||||||
onTap: () => Get.to(
|
onTap:
|
||||||
|
() => Get.to(
|
||||||
() => DailyCardInfo(
|
() => DailyCardInfo(
|
||||||
weatherData: weatherData,
|
weatherData: weatherData,
|
||||||
index: index,
|
index: index,
|
||||||
|
@ -66,8 +65,9 @@ class _DailyContainerState extends State<DailyContainer> {
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
DateFormat.EEEE(locale.languageCode)
|
DateFormat.EEEE(
|
||||||
.format((weatherData.timeDaily ?? [])[index]),
|
locale.languageCode,
|
||||||
|
).format((weatherData.timeDaily ?? [])[index]),
|
||||||
style: labelLarge,
|
style: labelLarge,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
@ -77,15 +77,17 @@ class _DailyContainerState extends State<DailyContainer> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset(
|
||||||
statusWeather
|
statusWeather.getImage7Day(
|
||||||
.getImage7Day(weatherCodeDaily[index]),
|
weatherCodeDaily[index],
|
||||||
|
),
|
||||||
scale: 3,
|
scale: 3,
|
||||||
),
|
),
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
statusWeather
|
statusWeather.getText(
|
||||||
.getText(weatherCodeDaily[index]),
|
weatherCodeDaily[index],
|
||||||
|
),
|
||||||
style: labelLarge,
|
style: labelLarge,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
@ -100,17 +102,16 @@ class _DailyContainerState extends State<DailyContainer> {
|
||||||
Text(
|
Text(
|
||||||
statusData.getDegree(
|
statusData.getDegree(
|
||||||
(weatherData.temperature2MMin ?? [])[index]
|
(weatherData.temperature2MMin ?? [])[index]
|
||||||
?.round()),
|
?.round(),
|
||||||
style: labelLarge,
|
),
|
||||||
),
|
|
||||||
Text(
|
|
||||||
' / ',
|
|
||||||
style: labelLarge,
|
style: labelLarge,
|
||||||
),
|
),
|
||||||
|
Text(' / ', style: labelLarge),
|
||||||
Text(
|
Text(
|
||||||
statusData.getDegree(
|
statusData.getDegree(
|
||||||
(weatherData.temperature2MMax ?? [])[index]
|
(weatherData.temperature2MMax ?? [])[index]
|
||||||
?.round()),
|
?.round(),
|
||||||
|
),
|
||||||
style: labelLarge,
|
style: labelLarge,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -35,14 +35,12 @@ class _DescWeatherState extends State<DescWeather> {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset(widget.imageName, scale: 20),
|
||||||
widget.imageName,
|
|
||||||
scale: 20,
|
|
||||||
),
|
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Text(
|
Text(
|
||||||
widget.value,
|
widget.value,
|
||||||
style: textTheme.labelLarge,
|
style: textTheme.labelLarge,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -107,10 +107,7 @@ class _DescContainerState extends State<DescContainer> {
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: ExpansionTile(
|
child: ExpansionTile(
|
||||||
shape: const Border(),
|
shape: const Border(),
|
||||||
title: Text(
|
title: Text(title, style: context.textTheme.labelLarge),
|
||||||
title,
|
|
||||||
style: context.textTheme.labelLarge,
|
|
||||||
),
|
|
||||||
initiallyExpanded: initiallyExpanded,
|
initiallyExpanded: initiallyExpanded,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -123,16 +120,18 @@ class _DescContainerState extends State<DescContainer> {
|
||||||
? Container()
|
? Container()
|
||||||
: DescWeather(
|
: DescWeather(
|
||||||
imageName: 'assets/images/cold.png',
|
imageName: 'assets/images/cold.png',
|
||||||
value: statusData
|
value: statusData.getDegree(
|
||||||
.getDegree(apparentTemperatureMin.round()),
|
apparentTemperatureMin.round(),
|
||||||
|
),
|
||||||
desc: 'apparentTemperatureMin'.tr,
|
desc: 'apparentTemperatureMin'.tr,
|
||||||
),
|
),
|
||||||
apparentTemperatureMax == null
|
apparentTemperatureMax == null
|
||||||
? Container()
|
? Container()
|
||||||
: DescWeather(
|
: DescWeather(
|
||||||
imageName: 'assets/images/hot.png',
|
imageName: 'assets/images/hot.png',
|
||||||
value: statusData
|
value: statusData.getDegree(
|
||||||
.getDegree(apparentTemperatureMax.round()),
|
apparentTemperatureMax.round(),
|
||||||
|
),
|
||||||
desc: 'apparentTemperatureMax'.tr,
|
desc: 'apparentTemperatureMax'.tr,
|
||||||
),
|
),
|
||||||
uvIndexMax == null
|
uvIndexMax == null
|
||||||
|
@ -168,8 +167,7 @@ class _DescContainerState extends State<DescContainer> {
|
||||||
precipitationProbabilityMax == null
|
precipitationProbabilityMax == null
|
||||||
? Container()
|
? Container()
|
||||||
: DescWeather(
|
: DescWeather(
|
||||||
imageName:
|
imageName: 'assets/images/precipitation_probability.png',
|
||||||
'assets/images/precipitation_probability.png',
|
|
||||||
value: '$precipitationProbabilityMax%',
|
value: '$precipitationProbabilityMax%',
|
||||||
desc: 'precipitationProbability'.tr,
|
desc: 'precipitationProbability'.tr,
|
||||||
),
|
),
|
||||||
|
@ -254,8 +252,7 @@ class _DescContainerState extends State<DescContainer> {
|
||||||
precipitationProbability == null
|
precipitationProbability == null
|
||||||
? Container()
|
? Container()
|
||||||
: DescWeather(
|
: DescWeather(
|
||||||
imageName:
|
imageName: 'assets/images/precipitation_probability.png',
|
||||||
'assets/images/precipitation_probability.png',
|
|
||||||
value: '$precipitationProbability%',
|
value: '$precipitationProbability%',
|
||||||
desc: 'precipitationProbability'.tr,
|
desc: 'precipitationProbability'.tr,
|
||||||
),
|
),
|
||||||
|
|
|
@ -37,16 +37,13 @@ class _HourlyState extends State<Hourly> {
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
|
Text(statusData.getTimeFormat(time), style: textTheme.labelLarge),
|
||||||
Text(
|
Text(
|
||||||
statusData.getTimeFormat(time),
|
DateFormat(
|
||||||
style: textTheme.labelLarge,
|
'E',
|
||||||
),
|
locale.languageCode,
|
||||||
Text(
|
).format(DateTime.tryParse(time)!),
|
||||||
DateFormat('E', locale.languageCode)
|
style: textTheme.labelLarge?.copyWith(color: Colors.grey),
|
||||||
.format(DateTime.tryParse(time)!),
|
|
||||||
style: textTheme.labelLarge?.copyWith(
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -61,9 +58,7 @@ class _HourlyState extends State<Hourly> {
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
statusData.getDegree(widget.degree.round()),
|
statusData.getDegree(widget.degree.round()),
|
||||||
style: textTheme.titleMedium?.copyWith(
|
style: textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -45,8 +45,14 @@ class _NowState extends State<Now> {
|
||||||
children: [
|
children: [
|
||||||
const Gap(15),
|
const Gap(15),
|
||||||
Image(
|
Image(
|
||||||
image: AssetImage(statusWeather.getImageNow(widget.weather,
|
image: AssetImage(
|
||||||
widget.time, widget.timeDay, widget.timeNight)),
|
statusWeather.getImageNow(
|
||||||
|
widget.weather,
|
||||||
|
widget.time,
|
||||||
|
widget.timeDay,
|
||||||
|
widget.timeNight,
|
||||||
|
),
|
||||||
|
),
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
height: 200,
|
height: 200,
|
||||||
),
|
),
|
||||||
|
@ -55,12 +61,8 @@ class _NowState extends State<Now> {
|
||||||
style: context.textTheme.displayLarge?.copyWith(
|
style: context.textTheme.displayLarge?.copyWith(
|
||||||
fontSize: 90,
|
fontSize: 90,
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
shadows: const [
|
shadows: const [Shadow(blurRadius: 15, offset: Offset(5, 5))],
|
||||||
Shadow(
|
),
|
||||||
blurRadius: 15,
|
|
||||||
offset: Offset(5, 5),
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
statusWeather.getText(widget.weather),
|
statusWeather.getText(widget.weather),
|
||||||
|
@ -68,9 +70,9 @@ class _NowState extends State<Now> {
|
||||||
),
|
),
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Text(
|
Text(
|
||||||
DateFormat.MMMMEEEEd(locale.languageCode).format(
|
DateFormat.MMMMEEEEd(
|
||||||
DateTime.parse(widget.time),
|
locale.languageCode,
|
||||||
),
|
).format(DateTime.parse(widget.time)),
|
||||||
style: context.textTheme.labelLarge?.copyWith(
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
|
@ -82,7 +84,11 @@ class _NowState extends State<Now> {
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 18, bottom: 18, left: 25, right: 15),
|
top: 18,
|
||||||
|
bottom: 18,
|
||||||
|
left: 25,
|
||||||
|
right: 15,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -91,9 +97,9 @@ class _NowState extends State<Now> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
DateFormat.MMMMEEEEd(locale.languageCode).format(
|
DateFormat.MMMMEEEEd(
|
||||||
DateTime.parse(widget.time),
|
locale.languageCode,
|
||||||
),
|
).format(DateTime.parse(widget.time)),
|
||||||
style: context.textTheme.labelLarge?.copyWith(
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
|
@ -101,24 +107,26 @@ class _NowState extends State<Now> {
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Text(
|
Text(
|
||||||
statusWeather.getText(widget.weather),
|
statusWeather.getText(widget.weather),
|
||||||
style: context.textTheme.titleLarge
|
style: context.textTheme.titleLarge?.copyWith(
|
||||||
?.copyWith(fontSize: 20),
|
fontSize: 20,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('feels'.tr,
|
Text('feels'.tr, style: context.textTheme.bodyMedium),
|
||||||
style: context.textTheme.bodyMedium),
|
|
||||||
Text(' • ', style: context.textTheme.bodyMedium),
|
Text(' • ', style: context.textTheme.bodyMedium),
|
||||||
Text(statusData.getDegree(widget.feels.round()),
|
Text(
|
||||||
style: context.textTheme.bodyMedium),
|
statusData.getDegree(widget.feels.round()),
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Gap(30),
|
const Gap(30),
|
||||||
Text(
|
Text(
|
||||||
statusData.getDegree(roundDegree
|
statusData.getDegree(
|
||||||
? widget.degree.round()
|
roundDegree ? widget.degree.round() : widget.degree,
|
||||||
: widget.degree),
|
),
|
||||||
style: context.textTheme.displayMedium?.copyWith(
|
style: context.textTheme.displayMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
),
|
),
|
||||||
|
@ -127,19 +135,29 @@ class _NowState extends State<Now> {
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(statusData.getDegree((widget.tempMin.round())),
|
Text(
|
||||||
style: context.textTheme.labelLarge),
|
statusData.getDegree((widget.tempMin.round())),
|
||||||
|
style: context.textTheme.labelLarge,
|
||||||
|
),
|
||||||
Text(' / ', style: context.textTheme.labelLarge),
|
Text(' / ', style: context.textTheme.labelLarge),
|
||||||
Text(statusData.getDegree((widget.tempMax.round())),
|
Text(
|
||||||
style: context.textTheme.labelLarge),
|
statusData.getDegree((widget.tempMax.round())),
|
||||||
|
style: context.textTheme.labelLarge,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Image(
|
Image(
|
||||||
image: AssetImage(statusWeather.getImageNow(widget.weather,
|
image: AssetImage(
|
||||||
widget.time, widget.timeDay, widget.timeNight)),
|
statusWeather.getImageNow(
|
||||||
|
widget.weather,
|
||||||
|
widget.time,
|
||||||
|
widget.timeDay,
|
||||||
|
widget.timeNight,
|
||||||
|
),
|
||||||
|
),
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
height: 140,
|
height: 140,
|
||||||
),
|
),
|
||||||
|
|
|
@ -63,14 +63,17 @@ class StatusData {
|
||||||
String getTimeFormat(String time) {
|
String getTimeFormat(String time) {
|
||||||
switch (settings.timeformat) {
|
switch (settings.timeformat) {
|
||||||
case '12':
|
case '12':
|
||||||
return DateFormat.jm(locale.languageCode)
|
return DateFormat.jm(
|
||||||
.format(DateTime.tryParse(time)!);
|
locale.languageCode,
|
||||||
|
).format(DateTime.tryParse(time)!);
|
||||||
case '24':
|
case '24':
|
||||||
return DateFormat.Hm(locale.languageCode)
|
return DateFormat.Hm(
|
||||||
.format(DateTime.tryParse(time)!);
|
locale.languageCode,
|
||||||
|
).format(DateTime.tryParse(time)!);
|
||||||
default:
|
default:
|
||||||
return DateFormat.Hm(locale.languageCode)
|
return DateFormat.Hm(
|
||||||
.format(DateTime.tryParse(time)!);
|
locale.languageCode,
|
||||||
|
).format(DateTime.tryParse(time)!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,29 @@ const assetImageRoot = 'assets/images/';
|
||||||
|
|
||||||
class StatusWeather {
|
class StatusWeather {
|
||||||
String getImageNow(
|
String getImageNow(
|
||||||
int weather, String time, String timeDay, String timeNight) {
|
int weather,
|
||||||
|
String time,
|
||||||
|
String timeDay,
|
||||||
|
String timeNight,
|
||||||
|
) {
|
||||||
final currentTime = DateTime.parse(time);
|
final currentTime = DateTime.parse(time);
|
||||||
final day = DateTime.parse(timeDay);
|
final day = DateTime.parse(timeDay);
|
||||||
final night = DateTime.parse(timeNight);
|
final night = DateTime.parse(timeNight);
|
||||||
|
|
||||||
final dayTime =
|
final dayTime = DateTime(
|
||||||
DateTime(day.year, day.month, day.day, day.hour, day.minute);
|
day.year,
|
||||||
final nightTime =
|
day.month,
|
||||||
DateTime(night.year, night.month, night.day, night.hour, night.minute);
|
day.day,
|
||||||
|
day.hour,
|
||||||
|
day.minute,
|
||||||
|
);
|
||||||
|
final nightTime = DateTime(
|
||||||
|
night.year,
|
||||||
|
night.month,
|
||||||
|
night.day,
|
||||||
|
night.hour,
|
||||||
|
night.minute,
|
||||||
|
);
|
||||||
|
|
||||||
switch (weather) {
|
switch (weather) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -112,15 +126,29 @@ class StatusWeather {
|
||||||
}
|
}
|
||||||
|
|
||||||
String getImageToday(
|
String getImageToday(
|
||||||
int weather, String time, String timeDay, String timeNight) {
|
int weather,
|
||||||
|
String time,
|
||||||
|
String timeDay,
|
||||||
|
String timeNight,
|
||||||
|
) {
|
||||||
final currentTime = DateTime.parse(time);
|
final currentTime = DateTime.parse(time);
|
||||||
final day = DateTime.parse(timeDay);
|
final day = DateTime.parse(timeDay);
|
||||||
final night = DateTime.parse(timeNight);
|
final night = DateTime.parse(timeNight);
|
||||||
|
|
||||||
final dayTime =
|
final dayTime = DateTime(
|
||||||
DateTime(day.year, day.month, day.day, day.hour, day.minute);
|
day.year,
|
||||||
final nightTime =
|
day.month,
|
||||||
DateTime(night.year, night.month, night.day, night.hour, night.minute);
|
day.day,
|
||||||
|
day.hour,
|
||||||
|
day.minute,
|
||||||
|
);
|
||||||
|
final nightTime = DateTime(
|
||||||
|
night.year,
|
||||||
|
night.month,
|
||||||
|
night.day,
|
||||||
|
night.hour,
|
||||||
|
night.minute,
|
||||||
|
);
|
||||||
|
|
||||||
switch (weather) {
|
switch (weather) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -274,15 +302,29 @@ class StatusWeather {
|
||||||
}
|
}
|
||||||
|
|
||||||
String getImageNotification(
|
String getImageNotification(
|
||||||
int weather, String time, String timeDay, String timeNight) {
|
int weather,
|
||||||
|
String time,
|
||||||
|
String timeDay,
|
||||||
|
String timeNight,
|
||||||
|
) {
|
||||||
final currentTime = DateTime.parse(time);
|
final currentTime = DateTime.parse(time);
|
||||||
final day = DateTime.parse(timeDay);
|
final day = DateTime.parse(timeDay);
|
||||||
final night = DateTime.parse(timeNight);
|
final night = DateTime.parse(timeNight);
|
||||||
|
|
||||||
final dayTime =
|
final dayTime = DateTime(
|
||||||
DateTime(day.year, day.month, day.day, day.hour, day.minute);
|
day.year,
|
||||||
final nightTime =
|
day.month,
|
||||||
DateTime(night.year, night.month, night.day, night.hour, night.minute);
|
day.day,
|
||||||
|
day.hour,
|
||||||
|
day.minute,
|
||||||
|
);
|
||||||
|
final nightTime = DateTime(
|
||||||
|
night.year,
|
||||||
|
night.month,
|
||||||
|
night.day,
|
||||||
|
night.hour,
|
||||||
|
night.minute,
|
||||||
|
);
|
||||||
|
|
||||||
switch (weather) {
|
switch (weather) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
@ -55,10 +55,7 @@ class _SunsetSunriseState extends State<SunsetSunrise> {
|
||||||
),
|
),
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Image.asset(
|
child: Image.asset('assets/images/sunrise.png', scale: 10),
|
||||||
'assets/images/sunrise.png',
|
|
||||||
scale: 10,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -86,10 +83,7 @@ class _SunsetSunriseState extends State<SunsetSunrise> {
|
||||||
),
|
),
|
||||||
const Gap(5),
|
const Gap(5),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Image.asset(
|
child: Image.asset('assets/images/sunset.png', scale: 10),
|
||||||
'assets/images/sunset.png',
|
|
||||||
scale: 10,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -10,9 +10,17 @@ extension HexColor on Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`).
|
/// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`).
|
||||||
String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}'
|
String toHex({bool leadingHashSign = true}) {
|
||||||
'${alpha.toRadixString(16).padLeft(2, '0')}'
|
final argb = toARGB32(); // Get 32-bit integer representation
|
||||||
'${red.toRadixString(16).padLeft(2, '0')}'
|
final a = (argb >> 24) & 0xFF;
|
||||||
'${green.toRadixString(16).padLeft(2, '0')}'
|
final r = (argb >> 16) & 0xFF;
|
||||||
'${blue.toRadixString(16).padLeft(2, '0')}';
|
final g = (argb >> 8) & 0xFF;
|
||||||
|
final b = argb & 0xFF;
|
||||||
|
|
||||||
|
return '${leadingHashSign ? '#' : ''}'
|
||||||
|
'${a.toRadixString(16).padLeft(2, '0')}'
|
||||||
|
'${r.toRadixString(16).padLeft(2, '0')}'
|
||||||
|
'${g.toRadixString(16).padLeft(2, '0')}'
|
||||||
|
'${b.toRadixString(16).padLeft(2, '0')}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,9 @@ class NotificationShow {
|
||||||
enableVibration: false,
|
enableVibration: false,
|
||||||
largeIcon: FilePathAndroidBitmap(imagePath),
|
largeIcon: FilePathAndroidBitmap(imagePath),
|
||||||
);
|
);
|
||||||
NotificationDetails notificationDetails =
|
NotificationDetails notificationDetails = NotificationDetails(
|
||||||
NotificationDetails(android: androidNotificationDetails);
|
android: androidNotificationDetails,
|
||||||
|
);
|
||||||
|
|
||||||
var scheduledTime = tz.TZDateTime.from(date, tz.local);
|
var scheduledTime = tz.TZDateTime.from(date, tz.local);
|
||||||
flutterLocalNotificationsPlugin.zonedSchedule(
|
flutterLocalNotificationsPlugin.zonedSchedule(
|
||||||
|
|
|
@ -7,7 +7,8 @@ void showSnackBar({required String content, Function? onPressed}) {
|
||||||
globalKey.currentState?.showSnackBar(
|
globalKey.currentState?.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(content),
|
content: Text(content),
|
||||||
action: onPressed != null
|
action:
|
||||||
|
onPressed != null
|
||||||
? SnackBarAction(
|
? SnackBarAction(
|
||||||
label: 'settings'.tr,
|
label: 'settings'.tr,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
275
lib/main.dart
275
lib/main.dart
|
@ -33,7 +33,7 @@ final ValueNotifier<Future<bool>> isOnline = ValueNotifier(
|
||||||
InternetConnection().hasInternetAccess,
|
InternetConnection().hasInternetAccess,
|
||||||
);
|
);
|
||||||
|
|
||||||
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||||
FlutterLocalNotificationsPlugin();
|
FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
bool amoledTheme = false;
|
bool amoledTheme = false;
|
||||||
|
@ -47,36 +47,36 @@ String timeEnd = '21:00';
|
||||||
String widgetBackgroundColor = '';
|
String widgetBackgroundColor = '';
|
||||||
String widgetTextColor = '';
|
String widgetTextColor = '';
|
||||||
|
|
||||||
final List appLanguages = [
|
|
||||||
{'name': 'বাংলা', 'locale': const Locale('bn', 'IN')},
|
|
||||||
{'name': 'Čeština', 'locale': const Locale('cs', 'CZ')},
|
|
||||||
{'name': 'Dansk', 'locale': const Locale('da', 'DK')},
|
|
||||||
{'name': 'Deutsch', 'locale': const Locale('de', 'DE')},
|
|
||||||
{'name': 'English', 'locale': const Locale('en', 'US')},
|
|
||||||
{'name': 'Español', 'locale': const Locale('es', 'ES')},
|
|
||||||
{'name': 'Français', 'locale': const Locale('fr', 'FR')},
|
|
||||||
// {'name': 'Gaeilge', 'locale': const Locale('ga', 'IE')},
|
|
||||||
{'name': 'हिन्दी', 'locale': const Locale('hi', 'IN')},
|
|
||||||
{'name': 'Magyar', 'locale': const Locale('hu', 'HU')},
|
|
||||||
{'name': 'Italiano', 'locale': const Locale('it', 'IT')},
|
|
||||||
{'name': '한국어', 'locale': const Locale('ko', 'KR')},
|
|
||||||
{'name': 'فارسی', 'locale': const Locale('fa', 'IR')},
|
|
||||||
{'name': 'ქართული', 'locale': const Locale('ka', 'GE')},
|
|
||||||
{'name': 'Nederlands', 'locale': const Locale('nl', 'NL')},
|
|
||||||
{'name': 'Polski', 'locale': const Locale('pl', 'PL')},
|
|
||||||
{'name': 'Português (Brasil)', 'locale': const Locale('pt', 'BR')},
|
|
||||||
{'name': 'Română', 'locale': const Locale('ro', 'RO')},
|
|
||||||
{'name': 'Русский', 'locale': const Locale('ru', 'RU')},
|
|
||||||
{'name': 'Slovenčina', 'locale': const Locale('sk', 'SK')},
|
|
||||||
{'name': 'Türkçe', 'locale': const Locale('tr', 'TR')},
|
|
||||||
{'name': 'اردو', 'locale': const Locale('ur', 'PK')},
|
|
||||||
{'name': '中文(简体)', 'locale': const Locale('zh', 'CN')},
|
|
||||||
{'name': '中文(繁體)', 'locale': const Locale('zh', 'TW')},
|
|
||||||
];
|
|
||||||
|
|
||||||
const String appGroupId = 'DARK NIGHT';
|
const String appGroupId = 'DARK NIGHT';
|
||||||
const String androidWidgetName = 'OreoWidget';
|
const String androidWidgetName = 'OreoWidget';
|
||||||
|
|
||||||
|
const List<Map<String, dynamic>> appLanguages = [
|
||||||
|
{'name': 'বাংলা', 'locale': Locale('bn', 'IN')},
|
||||||
|
{'name': 'Čeština', 'locale': Locale('cs', 'CZ')},
|
||||||
|
{'name': 'Dansk', 'locale': Locale('da', 'DK')},
|
||||||
|
{'name': 'Deutsch', 'locale': Locale('de', 'DE')},
|
||||||
|
{'name': 'English', 'locale': Locale('en', 'US')},
|
||||||
|
{'name': 'Español', 'locale': Locale('es', 'ES')},
|
||||||
|
{'name': 'Français', 'locale': Locale('fr', 'FR')},
|
||||||
|
// {'name': 'Gaeilge', 'locale': Locale('ga', 'IE')},
|
||||||
|
{'name': 'हिन्दी', 'locale': Locale('hi', 'IN')},
|
||||||
|
{'name': 'Magyar', 'locale': Locale('hu', 'HU')},
|
||||||
|
{'name': 'Italiano', 'locale': Locale('it', 'IT')},
|
||||||
|
{'name': '한국어', 'locale': Locale('ko', 'KR')},
|
||||||
|
{'name': 'فارسی', 'locale': Locale('fa', 'IR')},
|
||||||
|
{'name': 'ქართული', 'locale': Locale('ka', 'GE')},
|
||||||
|
{'name': 'Nederlands', 'locale': Locale('nl', 'NL')},
|
||||||
|
{'name': 'Polski', 'locale': Locale('pl', 'PL')},
|
||||||
|
{'name': 'Português (Brasil)', 'locale': Locale('pt', 'BR')},
|
||||||
|
{'name': 'Română', 'locale': Locale('ro', 'RO')},
|
||||||
|
{'name': 'Русский', 'locale': Locale('ru', 'RU')},
|
||||||
|
{'name': 'Slovenčina', 'locale': Locale('sk', 'SK')},
|
||||||
|
{'name': 'Türkçe', 'locale': Locale('tr', 'TR')},
|
||||||
|
{'name': 'اردو', 'locale': Locale('ur', 'PK')},
|
||||||
|
{'name': '中文(简体)', 'locale': Locale('zh', 'CN')},
|
||||||
|
{'name': '中文(繁體)', 'locale': Locale('zh', 'TW')},
|
||||||
|
];
|
||||||
|
|
||||||
@pragma('vm:entry-point')
|
@pragma('vm:entry-point')
|
||||||
void callbackDispatcher() {
|
void callbackDispatcher() {
|
||||||
Workmanager().executeTask((task, inputData) {
|
Workmanager().executeTask((task, inputData) {
|
||||||
|
@ -85,59 +85,40 @@ void callbackDispatcher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final String timeZoneName;
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
Connectivity().onConnectivityChanged.listen((
|
await _initializeApp();
|
||||||
List<ConnectivityResult> result,
|
|
||||||
) {
|
|
||||||
result.contains(ConnectivityResult.none)
|
|
||||||
? isOnline.value = Future(() => false)
|
|
||||||
: isOnline.value = InternetConnection().hasInternetAccess;
|
|
||||||
});
|
|
||||||
DeviceFeature().init();
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
Workmanager().initialize(callbackDispatcher, isInDebugMode: kDebugMode);
|
|
||||||
await setOptimalDisplayMode();
|
|
||||||
}
|
|
||||||
timeZoneName = await FlutterTimezone.getLocalTimezone();
|
|
||||||
tz.initializeTimeZones();
|
|
||||||
tz.setLocalLocation(tz.getLocation(timeZoneName));
|
|
||||||
await isarInit();
|
|
||||||
const AndroidInitializationSettings initializationSettingsAndroid =
|
|
||||||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
|
||||||
const DarwinInitializationSettings initializationSettingsDarwin =
|
|
||||||
DarwinInitializationSettings();
|
|
||||||
const LinuxInitializationSettings initializationSettingsLinux =
|
|
||||||
LinuxInitializationSettings(defaultActionName: 'Rain');
|
|
||||||
const InitializationSettings initializationSettings = InitializationSettings(
|
|
||||||
android: initializationSettingsAndroid,
|
|
||||||
iOS: initializationSettingsDarwin,
|
|
||||||
linux: initializationSettingsLinux,
|
|
||||||
);
|
|
||||||
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setOptimalDisplayMode() async {
|
Future<void> _initializeApp() async {
|
||||||
final List<DisplayMode> supported = await FlutterDisplayMode.supported;
|
_setupConnectivityListener();
|
||||||
final DisplayMode active = await FlutterDisplayMode.active;
|
await _initializeTimeZone();
|
||||||
final List<DisplayMode> sameResolution =
|
await _initializeIsar();
|
||||||
supported
|
await _initializeNotifications();
|
||||||
.where(
|
if (Platform.isAndroid) {
|
||||||
(DisplayMode m) =>
|
await _setOptimalDisplayMode();
|
||||||
m.width == active.width && m.height == active.height,
|
Workmanager().initialize(callbackDispatcher, isInDebugMode: kDebugMode);
|
||||||
)
|
HomeWidget.setAppGroupId(appGroupId);
|
||||||
.toList()
|
}
|
||||||
..sort(
|
DeviceFeature().init();
|
||||||
(DisplayMode a, DisplayMode b) =>
|
|
||||||
b.refreshRate.compareTo(a.refreshRate),
|
|
||||||
);
|
|
||||||
final DisplayMode mostOptimalMode =
|
|
||||||
sameResolution.isNotEmpty ? sameResolution.first : active;
|
|
||||||
await FlutterDisplayMode.setPreferredMode(mostOptimalMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> isarInit() async {
|
void _setupConnectivityListener() {
|
||||||
|
Connectivity().onConnectivityChanged.listen((result) {
|
||||||
|
isOnline.value =
|
||||||
|
result.contains(ConnectivityResult.none)
|
||||||
|
? Future.value(false)
|
||||||
|
: InternetConnection().hasInternetAccess;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeTimeZone() async {
|
||||||
|
final timeZoneName = await FlutterTimezone.getLocalTimezone();
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
tz.setLocalLocation(tz.getLocation(timeZoneName));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeIsar() async {
|
||||||
isar = await Isar.open([
|
isar = await Isar.open([
|
||||||
SettingsSchema,
|
SettingsSchema,
|
||||||
MainWeatherCacheSchema,
|
MainWeatherCacheSchema,
|
||||||
|
@ -159,6 +140,28 @@ Future<void> isarInit() async {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeNotifications() async {
|
||||||
|
const initializationSettings = InitializationSettings(
|
||||||
|
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
|
||||||
|
iOS: DarwinInitializationSettings(),
|
||||||
|
linux: LinuxInitializationSettings(defaultActionName: 'Rain'),
|
||||||
|
);
|
||||||
|
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setOptimalDisplayMode() async {
|
||||||
|
final supported = await FlutterDisplayMode.supported;
|
||||||
|
final active = await FlutterDisplayMode.active;
|
||||||
|
final sameResolution =
|
||||||
|
supported
|
||||||
|
.where((m) => m.width == active.width && m.height == active.height)
|
||||||
|
.toList()
|
||||||
|
..sort((a, b) => b.refreshRate.compareTo(a.refreshRate));
|
||||||
|
final mostOptimalMode =
|
||||||
|
sameResolution.isNotEmpty ? sameResolution.first : active;
|
||||||
|
await FlutterDisplayMode.setPreferredMode(mostOptimalMode);
|
||||||
|
}
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@ -177,30 +180,14 @@ class MyApp extends StatefulWidget {
|
||||||
}) async {
|
}) async {
|
||||||
final state = context.findAncestorStateOfType<_MyAppState>()!;
|
final state = context.findAncestorStateOfType<_MyAppState>()!;
|
||||||
|
|
||||||
if (newAmoledTheme != null) {
|
if (newAmoledTheme != null) state.changeAmoledTheme(newAmoledTheme);
|
||||||
state.changeAmoledTheme(newAmoledTheme);
|
if (newMaterialColor != null) state.changeMarerialTheme(newMaterialColor);
|
||||||
}
|
if (newRoundDegree != null) state.changeRoundDegree(newRoundDegree);
|
||||||
if (newMaterialColor != null) {
|
if (newLargeElement != null) state.changeLargeElement(newLargeElement);
|
||||||
state.changeMarerialTheme(newMaterialColor);
|
if (newLocale != null) state.changeLocale(newLocale);
|
||||||
}
|
if (newTimeRange != null) state.changeTimeRange(newTimeRange);
|
||||||
if (newRoundDegree != null) {
|
if (newTimeStart != null) state.changeTimeStart(newTimeStart);
|
||||||
state.changeRoundDegree(newRoundDegree);
|
if (newTimeEnd != null) state.changeTimeEnd(newTimeEnd);
|
||||||
}
|
|
||||||
if (newLargeElement != null) {
|
|
||||||
state.changeLargeElement(newLargeElement);
|
|
||||||
}
|
|
||||||
if (newLocale != null) {
|
|
||||||
state.changeLocale(newLocale);
|
|
||||||
}
|
|
||||||
if (newTimeRange != null) {
|
|
||||||
state.changeTimeRange(newTimeRange);
|
|
||||||
}
|
|
||||||
if (newTimeStart != null) {
|
|
||||||
state.changeTimeStart(newTimeStart);
|
|
||||||
}
|
|
||||||
if (newTimeEnd != null) {
|
|
||||||
state.changeTimeEnd(newTimeEnd);
|
|
||||||
}
|
|
||||||
if (newWidgetBackgroundColor != null) {
|
if (newWidgetBackgroundColor != null) {
|
||||||
state.changeWidgetBackgroundColor(newWidgetBackgroundColor);
|
state.changeWidgetBackgroundColor(newWidgetBackgroundColor);
|
||||||
}
|
}
|
||||||
|
@ -216,68 +203,28 @@ class MyApp extends StatefulWidget {
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
final themeController = Get.put(ThemeController());
|
final themeController = Get.put(ThemeController());
|
||||||
|
|
||||||
void changeAmoledTheme(bool newAmoledTheme) {
|
void changeAmoledTheme(bool newAmoledTheme) =>
|
||||||
setState(() {
|
setState(() => amoledTheme = newAmoledTheme);
|
||||||
amoledTheme = newAmoledTheme;
|
void changeMarerialTheme(bool newMaterialColor) =>
|
||||||
});
|
setState(() => materialColor = newMaterialColor);
|
||||||
}
|
void changeRoundDegree(bool newRoundDegree) =>
|
||||||
|
setState(() => roundDegree = newRoundDegree);
|
||||||
void changeMarerialTheme(bool newMaterialColor) {
|
void changeLargeElement(bool newLargeElement) =>
|
||||||
setState(() {
|
setState(() => largeElement = newLargeElement);
|
||||||
materialColor = newMaterialColor;
|
void changeTimeRange(int newTimeRange) =>
|
||||||
});
|
setState(() => timeRange = newTimeRange);
|
||||||
}
|
void changeTimeStart(String newTimeStart) =>
|
||||||
|
setState(() => timeStart = newTimeStart);
|
||||||
void changeRoundDegree(bool newRoundDegree) {
|
void changeTimeEnd(String newTimeEnd) => setState(() => timeEnd = newTimeEnd);
|
||||||
setState(() {
|
void changeLocale(Locale newLocale) => setState(() => locale = newLocale);
|
||||||
roundDegree = newRoundDegree;
|
void changeWidgetBackgroundColor(String newWidgetBackgroundColor) =>
|
||||||
});
|
setState(() => widgetBackgroundColor = newWidgetBackgroundColor);
|
||||||
}
|
void changeWidgetTextColor(String newWidgetTextColor) =>
|
||||||
|
setState(() => widgetTextColor = newWidgetTextColor);
|
||||||
void changeLargeElement(bool newLargeElement) {
|
|
||||||
setState(() {
|
|
||||||
largeElement = newLargeElement;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeTimeRange(int newTimeRange) {
|
|
||||||
setState(() {
|
|
||||||
timeRange = newTimeRange;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeTimeStart(String newTimeStart) {
|
|
||||||
setState(() {
|
|
||||||
timeStart = newTimeStart;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeTimeEnd(String newTimeEnd) {
|
|
||||||
setState(() {
|
|
||||||
timeEnd = newTimeEnd;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeLocale(Locale newLocale) {
|
|
||||||
setState(() {
|
|
||||||
locale = newLocale;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeWidgetBackgroundColor(String newWidgetBackgroundColor) {
|
|
||||||
setState(() {
|
|
||||||
widgetBackgroundColor = newWidgetBackgroundColor;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeWidgetTextColor(String newWidgetTextColor) {
|
|
||||||
setState(() {
|
|
||||||
widgetTextColor = newWidgetTextColor;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
amoledTheme = settings.amoledTheme;
|
amoledTheme = settings.amoledTheme;
|
||||||
materialColor = settings.materialColor;
|
materialColor = settings.materialColor;
|
||||||
roundDegree = settings.roundDegree;
|
roundDegree = settings.roundDegree;
|
||||||
|
@ -291,10 +238,6 @@ class _MyAppState extends State<MyApp> {
|
||||||
timeEnd = settings.timeEnd ?? '21:00';
|
timeEnd = settings.timeEnd ?? '21:00';
|
||||||
widgetBackgroundColor = settings.widgetBackgroundColor ?? '';
|
widgetBackgroundColor = settings.widgetBackgroundColor ?? '';
|
||||||
widgetTextColor = settings.widgetTextColor ?? '';
|
widgetTextColor = settings.widgetTextColor ?? '';
|
||||||
if (Platform.isAndroid) {
|
|
||||||
HomeWidget.setAppGroupId(appGroupId);
|
|
||||||
}
|
|
||||||
super.initState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -379,10 +322,10 @@ class _MyAppState extends State<MyApp> {
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home:
|
home:
|
||||||
settings.onboard
|
settings.onboard
|
||||||
? (locationCache.city == null) ||
|
? (locationCache.city == null ||
|
||||||
(locationCache.district == null) ||
|
locationCache.district == null ||
|
||||||
(locationCache.lat == null) ||
|
locationCache.lat == null ||
|
||||||
(locationCache.lon == null)
|
locationCache.lon == null)
|
||||||
? const SelectGeolocation(isStart: true)
|
? const SelectGeolocation(isStart: true)
|
||||||
: const HomePage()
|
: const HomePage()
|
||||||
: const OnBording(),
|
: const OnBording(),
|
||||||
|
|
|
@ -20,10 +20,14 @@ ColorScheme colorSchemeDark = ColorScheme.fromSeed(
|
||||||
);
|
);
|
||||||
|
|
||||||
ThemeData lightTheme(
|
ThemeData lightTheme(
|
||||||
Color? color, ColorScheme? colorScheme, bool edgeToEdgeAvailable) {
|
Color? color,
|
||||||
|
ColorScheme? colorScheme,
|
||||||
|
bool edgeToEdgeAvailable,
|
||||||
|
) {
|
||||||
return baseLigth.copyWith(
|
return baseLigth.copyWith(
|
||||||
brightness: Brightness.light,
|
brightness: Brightness.light,
|
||||||
colorScheme: colorScheme
|
colorScheme:
|
||||||
|
colorScheme
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
brightness: Brightness.light,
|
brightness: Brightness.light,
|
||||||
surface: baseLigth.colorScheme.surface,
|
surface: baseLigth.colorScheme.surface,
|
||||||
|
@ -54,9 +58,7 @@ ThemeData lightTheme(
|
||||||
color: color,
|
color: color,
|
||||||
surfaceTintColor:
|
surfaceTintColor:
|
||||||
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
shadowColor: Colors.transparent,
|
shadowColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
bottomSheetTheme: baseLigth.bottomSheetTheme.copyWith(
|
bottomSheetTheme: baseLigth.bottomSheetTheme.copyWith(
|
||||||
|
@ -73,11 +75,9 @@ ThemeData lightTheme(
|
||||||
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
||||||
),
|
),
|
||||||
inputDecorationTheme: baseLigth.inputDecorationTheme.copyWith(
|
inputDecorationTheme: baseLigth.inputDecorationTheme.copyWith(
|
||||||
labelStyle: WidgetStateTextStyle.resolveWith(
|
labelStyle: WidgetStateTextStyle.resolveWith((Set<WidgetState> states) {
|
||||||
(Set<WidgetState> states) {
|
|
||||||
return const TextStyle(fontSize: 14);
|
return const TextStyle(fontSize: 14);
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
focusedBorder: InputBorder.none,
|
focusedBorder: InputBorder.none,
|
||||||
enabledBorder: InputBorder.none,
|
enabledBorder: InputBorder.none,
|
||||||
|
@ -87,10 +87,14 @@ ThemeData lightTheme(
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData darkTheme(
|
ThemeData darkTheme(
|
||||||
Color? color, ColorScheme? colorScheme, bool edgeToEdgeAvailable) {
|
Color? color,
|
||||||
|
ColorScheme? colorScheme,
|
||||||
|
bool edgeToEdgeAvailable,
|
||||||
|
) {
|
||||||
return baseDark.copyWith(
|
return baseDark.copyWith(
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
colorScheme: colorScheme
|
colorScheme:
|
||||||
|
colorScheme
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
surface: baseDark.colorScheme.surface,
|
surface: baseDark.colorScheme.surface,
|
||||||
|
@ -121,9 +125,7 @@ ThemeData darkTheme(
|
||||||
color: color,
|
color: color,
|
||||||
surfaceTintColor:
|
surfaceTintColor:
|
||||||
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
shadowColor: Colors.transparent,
|
shadowColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
bottomSheetTheme: baseDark.bottomSheetTheme.copyWith(
|
bottomSheetTheme: baseDark.bottomSheetTheme.copyWith(
|
||||||
|
@ -140,11 +142,9 @@ ThemeData darkTheme(
|
||||||
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
|
||||||
),
|
),
|
||||||
inputDecorationTheme: baseDark.inputDecorationTheme.copyWith(
|
inputDecorationTheme: baseDark.inputDecorationTheme.copyWith(
|
||||||
labelStyle: WidgetStateTextStyle.resolveWith(
|
labelStyle: WidgetStateTextStyle.resolveWith((Set<WidgetState> states) {
|
||||||
(Set<WidgetState> states) {
|
|
||||||
return const TextStyle(fontSize: 14);
|
return const TextStyle(fontSize: 14);
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
focusedBorder: InputBorder.none,
|
focusedBorder: InputBorder.none,
|
||||||
enabledBorder: InputBorder.none,
|
enabledBorder: InputBorder.none,
|
||||||
|
|
|
@ -4,7 +4,8 @@ import 'package:rain/app/data/db.dart';
|
||||||
import 'package:rain/main.dart';
|
import 'package:rain/main.dart';
|
||||||
|
|
||||||
class ThemeController extends GetxController {
|
class ThemeController extends GetxController {
|
||||||
ThemeMode get theme => settings.theme == 'system'
|
ThemeMode get theme =>
|
||||||
|
settings.theme == 'system'
|
||||||
? ThemeMode.system
|
? ThemeMode.system
|
||||||
: settings.theme == 'dark'
|
: settings.theme == 'dark'
|
||||||
? ThemeMode.dark
|
? ThemeMode.dark
|
||||||
|
|
|
@ -44,8 +44,7 @@ class EsEs {
|
||||||
'hPa': 'hPa',
|
'hPa': 'hPa',
|
||||||
'settings': 'Ajustes',
|
'settings': 'Ajustes',
|
||||||
'no_inter': 'Sin conexión a Internet',
|
'no_inter': 'Sin conexión a Internet',
|
||||||
'on_inter':
|
'on_inter': 'Conéctate a Internet para obtener información meteorológica.',
|
||||||
'Conéctate a Internet para obtener información meteorológica.',
|
|
||||||
'location': 'Ubicación',
|
'location': 'Ubicación',
|
||||||
'no_location':
|
'no_location':
|
||||||
'Activa la localización para obtener información meteorológica para tu ubicación actual.',
|
'Activa la localización para obtener información meteorológica para tu ubicación actual.',
|
||||||
|
@ -136,8 +135,7 @@ class EsEs {
|
||||||
'map': 'Mapa',
|
'map': 'Mapa',
|
||||||
'clearCacheStore': 'Borrar caché',
|
'clearCacheStore': 'Borrar caché',
|
||||||
'deletedCacheStore': 'Borrando caché',
|
'deletedCacheStore': 'Borrando caché',
|
||||||
'deletedCacheStoreQuery':
|
'deletedCacheStoreQuery': '¿Estás seguro de que quieres borrar el caché?',
|
||||||
'¿Estás seguro de que quieres borrar el caché?',
|
|
||||||
'addWidget': 'Agregar widget',
|
'addWidget': 'Agregar widget',
|
||||||
'hideMap': 'Ocultar mapa',
|
'hideMap': 'Ocultar mapa',
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,8 +60,7 @@ class FrFr {
|
||||||
'district': 'District',
|
'district': 'District',
|
||||||
'noWeatherCard': 'Ajouter une ville',
|
'noWeatherCard': 'Ajouter une ville',
|
||||||
'deletedCardWeather': 'Supprimer une ville',
|
'deletedCardWeather': 'Supprimer une ville',
|
||||||
'deletedCardWeatherQuery':
|
'deletedCardWeatherQuery': 'Êtes-vous sûr de vouloir supprimer la ville ?',
|
||||||
'Êtes-vous sûr de vouloir supprimer la ville ?',
|
|
||||||
'delete': 'Supprimer',
|
'delete': 'Supprimer',
|
||||||
'cancel': 'Annuler',
|
'cancel': 'Annuler',
|
||||||
'time': 'Heure locale',
|
'time': 'Heure locale',
|
||||||
|
|
|
@ -44,8 +44,7 @@ class HuHu {
|
||||||
'hPa': 'hPa',
|
'hPa': 'hPa',
|
||||||
'settings': 'Beállítások',
|
'settings': 'Beállítások',
|
||||||
'no_inter': 'Nincs internet',
|
'no_inter': 'Nincs internet',
|
||||||
'on_inter':
|
'on_inter': 'Kapcsolja be az internetet az időjárási adatok lekéréséhez.',
|
||||||
'Kapcsolja be az internetet az időjárási adatok lekéréséhez.',
|
|
||||||
'location': 'Hely',
|
'location': 'Hely',
|
||||||
'no_location':
|
'no_location':
|
||||||
'Engedélyezze a helyszolgáltatást az aktuális hely időjárásadatainak megszerzéséhez.',
|
'Engedélyezze a helyszolgáltatást az aktuális hely időjárásadatainak megszerzéséhez.',
|
||||||
|
|
|
@ -44,8 +44,7 @@ class ItIt {
|
||||||
'hPa': 'hPa',
|
'hPa': 'hPa',
|
||||||
'settings': 'Imposta.',
|
'settings': 'Imposta.',
|
||||||
'no_inter': 'Non c\'è connessione Internet',
|
'no_inter': 'Non c\'è connessione Internet',
|
||||||
'on_inter':
|
'on_inter': 'Attiva la connessione Internet per avere dati meteorologici.',
|
||||||
'Attiva la connessione Internet per avere dati meteorologici.',
|
|
||||||
'location': 'Posizione',
|
'location': 'Posizione',
|
||||||
'no_location':
|
'no_location':
|
||||||
'Abilita il servizio di localizzazione per ottenere i dati meteo per la posizione corrente.',
|
'Abilita il servizio di localizzazione per ottenere i dati meteo per la posizione corrente.',
|
||||||
|
@ -60,8 +59,7 @@ class ItIt {
|
||||||
'district': 'Regione',
|
'district': 'Regione',
|
||||||
'noWeatherCard': 'Aggiungi una città',
|
'noWeatherCard': 'Aggiungi una città',
|
||||||
'deletedCardWeather': 'Rimozione della città',
|
'deletedCardWeather': 'Rimozione della città',
|
||||||
'deletedCardWeatherQuery':
|
'deletedCardWeatherQuery': 'Sei sicuro di voler rimuovere questa città?',
|
||||||
'Sei sicuro di voler rimuovere questa città?',
|
|
||||||
'delete': 'Elimina',
|
'delete': 'Elimina',
|
||||||
'cancel': 'Annulla',
|
'cancel': 'Annulla',
|
||||||
'time': 'Orario locale',
|
'time': 'Orario locale',
|
||||||
|
|
|
@ -59,8 +59,7 @@ class KaGe {
|
||||||
'district': 'რაიონი',
|
'district': 'რაიონი',
|
||||||
'noWeatherCard': 'დაამატეთ ქალაქი',
|
'noWeatherCard': 'დაამატეთ ქალაქი',
|
||||||
'deletedCardWeather': 'ქალაქის წაშლა',
|
'deletedCardWeather': 'ქალაქის წაშლა',
|
||||||
'deletedCardWeatherQuery':
|
'deletedCardWeatherQuery': 'დარწმუნებული ხართ, რომ გსურთ ქალაქის წაშლა?',
|
||||||
'დარწმუნებული ხართ, რომ გსურთ ქალაქის წაშლა?',
|
|
||||||
'delete': 'ამოღება',
|
'delete': 'ამოღება',
|
||||||
'cancel': 'გაუქმება',
|
'cancel': 'გაუქმება',
|
||||||
'time': 'დრო ქალაქში',
|
'time': 'დრო ქალაქში',
|
||||||
|
@ -135,8 +134,7 @@ class KaGe {
|
||||||
'map': 'რუკა',
|
'map': 'რუკა',
|
||||||
'clearCacheStore': 'ქეშის გასუფთავება',
|
'clearCacheStore': 'ქეშის გასუფთავება',
|
||||||
'deletedCacheStore': 'ქეშის გასუფთავება მიმდინარეობს',
|
'deletedCacheStore': 'ქეშის გასუფთავება მიმდინარეობს',
|
||||||
'deletedCacheStoreQuery':
|
'deletedCacheStoreQuery': 'დარწმუნებული ხართ, რომ გსურთ ქეშის გასუფთავება?',
|
||||||
'დარწმუნებული ხართ, რომ გსურთ ქეშის გასუფთავება?',
|
|
||||||
'addWidget': 'ვიდჯეტის დამატება',
|
'addWidget': 'ვიდჯეტის დამატება',
|
||||||
'hideMap': 'რუკის დამალვა',
|
'hideMap': 'რუკის დამალვა',
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,8 +44,7 @@ class NlNl {
|
||||||
'hPa': 'hPa',
|
'hPa': 'hPa',
|
||||||
'settings': 'Instellingen.',
|
'settings': 'Instellingen.',
|
||||||
'no_inter': 'Geen Internet',
|
'no_inter': 'Geen Internet',
|
||||||
'on_inter':
|
'on_inter': 'Schakel Internet in om meteorologische gegevens te ontvangen.',
|
||||||
'Schakel Internet in om meteorologische gegevens te ontvangen.',
|
|
||||||
'location': 'Locatie',
|
'location': 'Locatie',
|
||||||
'no_location':
|
'no_location':
|
||||||
'Schakel de locatiedienst in om weer gegevens voor de huidige locatie te ontvangen.',
|
'Schakel de locatiedienst in om weer gegevens voor de huidige locatie te ontvangen.',
|
||||||
|
@ -60,8 +59,7 @@ class NlNl {
|
||||||
'district': 'District',
|
'district': 'District',
|
||||||
'noWeatherCard': 'Voeg een stad toe',
|
'noWeatherCard': 'Voeg een stad toe',
|
||||||
'deletedCardWeather': 'Verwijder een city',
|
'deletedCardWeather': 'Verwijder een city',
|
||||||
'deletedCardWeatherQuery':
|
'deletedCardWeatherQuery': 'Weet je zeker dat je de stad wilt verwijderen?',
|
||||||
'Weet je zeker dat je de stad wilt verwijderen?',
|
|
||||||
'delete': 'Verwijder',
|
'delete': 'Verwijder',
|
||||||
'cancel': 'Annuleer',
|
'cancel': 'Annuleer',
|
||||||
'time': 'Tijd in de stad',
|
'time': 'Tijd in de stad',
|
||||||
|
|
|
@ -134,8 +134,7 @@ class PlPl {
|
||||||
'map': 'Mapa',
|
'map': 'Mapa',
|
||||||
'clearCacheStore': 'Wyczyść pamięć podręczną',
|
'clearCacheStore': 'Wyczyść pamięć podręczną',
|
||||||
'deletedCacheStore': 'Czyszczenie pamięci podręcznej',
|
'deletedCacheStore': 'Czyszczenie pamięci podręcznej',
|
||||||
'deletedCacheStoreQuery':
|
'deletedCacheStoreQuery': 'Czy na pewno chcesz wyczyścić pamięć podręczną?',
|
||||||
'Czy na pewno chcesz wyczyścić pamięć podręczną?',
|
|
||||||
'addWidget': 'Dodaj widget',
|
'addWidget': 'Dodaj widget',
|
||||||
'hideMap': 'Ukryj mapę',
|
'hideMap': 'Ukryj mapę',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1385,5 +1385,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.7.0 <4.0.0"
|
dart: ">=3.7.2 <4.0.0"
|
||||||
flutter: ">=3.27.0"
|
flutter: ">=3.27.0"
|
||||||
|
|
|
@ -6,7 +6,7 @@ publish_to: "none"
|
||||||
version: 1.3.8+41
|
version: 1.3.8+41
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.7.0 <4.0.0"
|
sdk: ">=3.7.2 <4.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue