null handle fixed #463

This commit is contained in:
Pranshul committed 2025-07-17 15:21:17 +05:30
1 parent ad03fb4217
commit ef5c22bb22
4 files changed
+295 -119

No files matched your search

+98 -24
View File
@@ -70,15 +70,10 @@ void main() async {
DeviceOrientation.portraitDown,
]);
// WebViewPlatform.instance ??= SurfaceAndroidWebView();;
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.transparent,
),
);
final dir = await getApplicationDocumentsDirectory();
Hive.init(dir.path);
@@ -164,8 +159,21 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
final themeController = Provider.of<ThemeController>(context);
final isLight = Theme.of(context).brightness == Brightness.light;
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Color(0x01000000),
statusBarIconBrightness: isLight ? Brightness.dark : Brightness.light,
systemNavigationBarIconBrightness: isLight ? Brightness.dark : Brightness.light,
systemNavigationBarColor: MediaQuery.of(context).systemGestureInsets.left > 0 ? Color(0x01000000) : isLight ? Color(0x01000000) : Color.fromRGBO(0, 0, 0, 0.3)
),
);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
return MaterialApp(
title: 'WeatherMaster',
debugShowCheckedModeBanner: false,
@@ -235,13 +243,7 @@ class MyApp extends StatelessWidget {
}
class LocationPromptScreen extends StatelessWidget {
const LocationPromptScreen({super.key});
@override
Widget build(BuildContext context) {
ColorScheme customDarkScheme = ColorScheme(
ColorScheme customDarkScheme = ColorScheme(
brightness: Brightness.dark,
primary: Color(paletteStartScreen.primary.get(80)),
onPrimary: Color(paletteStartScreen.primary.get(20)),
@@ -274,16 +276,14 @@ class LocationPromptScreen extends StatelessWidget {
surfaceContainerLowest: Color(paletteStartScreen.neutral.get(4))
);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
class LocationPromptScreen extends StatelessWidget {
const LocationPromptScreen({super.key});
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Theme.of(context).brightness == Brightness.light ? Brightness.dark : Brightness.light,
systemNavigationBarColor: Colors.transparent,
),
);
@@ -309,6 +309,8 @@ class LocationPromptScreen extends StatelessWidget {
}
return
Scaffold(
backgroundColor: customDarkScheme.surfaceContainerLow,
@@ -389,8 +391,21 @@ class LocationPromptScreen extends StatelessWidget {
minimumSize: WidgetStateProperty.all(const Size(300, 60)),
),
onPressed: () async {
final dialogKey = GlobalKey<LoadingDialogState>();
try {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => LoadingDialog(
key: dialogKey,
initialMessage: "Getting your location...",
),
);
final position = await getCurrentPosition();
final geoData = await reverseGeocode(position.latitude, position.longitude);
@@ -402,6 +417,9 @@ class LocationPromptScreen extends StatelessWidget {
country: geoData['country']!,
);
dialogKey.currentState?.updateMessage("Found\n ${geoData['city']}, ${geoData['country']}\n Loading weather...");
saveLocation(saved);
final cacheKey =
@@ -418,6 +436,8 @@ class LocationPromptScreen extends StatelessWidget {
}));
final weatherService = WeatherService();
await weatherService.fetchWeather(
saved.latitude,
@@ -425,6 +445,9 @@ class LocationPromptScreen extends StatelessWidget {
locationName: cacheKey,
);
Navigator.of(context, rootNavigator: true).pop();
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (_) => WeatherHome(
@@ -438,6 +461,7 @@ class LocationPromptScreen extends StatelessWidget {
),
);
} catch (e) {
Navigator.of(context, rootNavigator: true).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${e.toString()}')),
);
@@ -468,3 +492,53 @@ class LocationPromptScreen extends StatelessWidget {
);
}
}
class LoadingDialog extends StatefulWidget {
final String initialMessage;
final GlobalKey<LoadingDialogState> key;
const LoadingDialog({
required this.key,
required this.initialMessage,
}) : super(key: key);
@override
LoadingDialogState createState() => LoadingDialogState();
}
class LoadingDialogState extends State<LoadingDialog> {
late String message;
@override
void initState() {
super.initState();
message = widget.initialMessage;
}
void updateMessage(String newMessage) {
if (mounted) {
setState(() {
message = newMessage;
});
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: customDarkScheme.surfaceContainerHigh,
content: Column(
mainAxisSize: MainAxisSize.min,
spacing: 10,
children: [
const SizedBox(height: 6,),
CircularProgressIndicator(color: customDarkScheme.primary, year2023: false,),
Text(message, style: TextStyle(color: customDarkScheme.onSurface,), textAlign: TextAlign.center,),
],
),
);
}
}
+60 -49
View File
@@ -4,8 +4,6 @@ import 'package:hive/hive.dart';
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import '../utils/unit_converter.dart';
import 'package:provider/provider.dart';
import '../notifiers/unit_settings_notifier.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import '../utils/icon_map.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -190,21 +188,21 @@ class _DailyForecastPageState extends State<DailyForecastPage> {
SizedBox(
child: ConditionsWidgets(
selectedContainerBgIndex: Theme.of(context).colorScheme.surfaceContainerLowest.toARGB32(),
currentHumidity: current['relative_humidity_2m'],
currentDewPoint: hourly['dew_point_2m'][0].toDouble(),
currentSunrise: daily['sunrise'][0],
currentSunset: daily['sunset'][0],
currentPressure: current['pressure_msl'],
currentVisibility: hourly['visibility'][0],
currentWindSpeed: current['wind_speed_10m'],
currentWindDirc: current['wind_direction_10m'],
currentHumidity: current['relative_humidity_2m'] ?? 0.0000001,
currentDewPoint: hourly['dew_point_2m'][0].toDouble() ?? 0.0000001,
currentSunrise: daily['sunrise'][0] ?? 0.0000001,
currentSunset: daily['sunset'][0] ?? 0.0000001,
currentPressure: current['pressure_msl'] ?? 0.0000001,
currentVisibility: hourly['visibility'][0] ?? 0.0000001,
currentWindSpeed: current['wind_speed_10m'] ?? 0.0000001,
currentWindDirc: current['wind_direction_10m'] ?? 0.0000001,
timezone: weather['timezone'].toString(),
utcOffsetSeconds: weather['utc_offset_seconds'].toString(),
currentUvIndex: daily['uv_index_max'][0],
currentAQIUSA: weather['air_quality']['current']['us_aqi'],
currentAQIEURO: weather['air_quality']['current']['european_aqi'],
currentTotalPrec: daily['precipitation_sum'][0],
currentDayLength: daily['daylight_duration'][0],
currentUvIndex: daily['uv_index_max'][0] ?? 0.0000001,
currentAQIUSA: weather['air_quality']['current']['us_aqi'] ?? 0.0000001,
currentAQIEURO: weather['air_quality']['current']['european_aqi'] ?? 0.0000001,
currentTotalPrec: daily['precipitation_sum'][0] ?? 0.0000001,
currentDayLength: daily['daylight_duration'][0] ?? 0.0000001,
isFromHome: false,
),
)
@@ -214,15 +212,15 @@ class _DailyForecastPageState extends State<DailyForecastPage> {
selectedContainerBgIndex: Theme.of(context).colorScheme.surfaceContainerLowest.toARGB32(),
currentSunrise: daily['sunrise']?[selectedIndex] ?? '',
currentSunset: daily['sunset']?[selectedIndex] ?? '',
currentPressure: hourly['pressure_msl']?[firstIndex] ?? 0,
currentVisibility: hourly['visibility']?[firstIndex] ?? 0,
currentWindSpeed: daily['wind_speed_10m_max']?[selectedIndex] ?? 0,
currentWindDirc: hourly['wind_direction_10m']?[firstIndex] ?? 0,
currentPressure: hourly['pressure_msl']?[firstIndex] ?? 0.0000001,
currentVisibility: hourly['visibility']?[firstIndex] ?? 0.0000001,
currentWindSpeed: daily['wind_speed_10m_max']?[selectedIndex] ?? 0.0000001,
currentWindDirc: hourly['wind_direction_10m']?[firstIndex] ?? 0.0000001,
timezone: weather['timezone'].toString(),
utcOffsetSeconds: weather['utc_offset_seconds'].toString(),
currentUvIndex: daily['uv_index_max']?[selectedIndex] ?? 0,
currentTotalPrec: daily['precipitation_sum']?[selectedIndex] ?? 0,
currentTotalPrecProb: daily['precipitation_probability_max']?[selectedIndex] ?? 0,
currentUvIndex: daily['uv_index_max']?[selectedIndex] ?? 0.0000001,
currentTotalPrec: daily['precipitation_sum']?[selectedIndex] ?? 0.0000001,
currentTotalPrecProb: daily['precipitation_probability_max']?[selectedIndex] ?? 0.0000001,
)
),
SizedBox(height: MediaQuery.of(context).padding.bottom + 16,)
@@ -315,7 +313,7 @@ class _DailyForecastCardState extends State<DailyForecastCard> {
final tempUnit = context.watch<UnitSettingsNotifier>().tempUnit;
final tempUnit = PreferencesHelper.getString("selectedTempUnit") ?? "Celsius";
num convert(num celsius) => tempUnit == "Fahrenheit"
? UnitConverter.celsiusToFahrenheit(celsius.toDouble()).round()
@@ -485,9 +483,10 @@ class HourlyCardForecast extends StatelessWidget {
if (startIndex == -1) startIndex = 0;
final timeUnit = PreferencesHelper.getString("selectedTimeUnit") ?? '12 hr';
final tempUnit = PreferencesHelper.getString("selectedTempUnit") ?? "Celsius";
print(startIndex);
return Container(
decoration: BoxDecoration(
@@ -532,8 +531,8 @@ class HourlyCardForecast extends StatelessWidget {
forecastLocal.hour,
);
final hour = context.watch<UnitSettingsNotifier>().timeUnit == '24 hr' ? "${roundedDisplayTime.hour.toString().padLeft(2, '0')}:00" : UnitConverter.formatTo12Hour(roundedDisplayTime);
final temp = context.watch<UnitSettingsNotifier>().tempUnit == 'Fahrenheit' ? UnitConverter.celsiusToFahrenheit(hourlyTemps[dataIndex].toDouble()).round() : hourlyTemps[dataIndex].toDouble().round();
final hour = timeUnit == '24 hr' ? "${roundedDisplayTime.hour.toString().padLeft(2, '0')}:00" : UnitConverter.formatTo12Hour(roundedDisplayTime);
final temp = tempUnit == 'Fahrenheit' ? UnitConverter.celsiusToFahrenheit(hourlyTemps[dataIndex].toDouble()).round() : hourlyTemps[dataIndex].toDouble().round();
final code = hourlyWeatherCodes[dataIndex];
final precipProb = hourlyPrecpProb[dataIndex];
@@ -588,6 +587,11 @@ class ForecastDetailsHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
final tempUnit = PreferencesHelper.getString("selectedTempUnit") ?? "Celsius";
if (selectedDayData == null) {
return const Text('No data selected.');
}
@@ -599,8 +603,8 @@ class ForecastDetailsHeader extends StatelessWidget {
Padding(padding: EdgeInsets.only(left: 12, right: 12, top: 3),
child: Text(getCityFromPreferences(), style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 22, fontWeight: FontWeight.w500),)),
Padding(padding: EdgeInsets.only(left: 12, right: 12),
child: Row(children: [Text(context.watch<UnitSettingsNotifier>().tempUnit == 'Fahrenheit' ? "${UnitConverter.celsiusToFahrenheit(selectedDayData!['maxTemp']).round()}°/" : "${selectedDayData!['maxTemp'].round()}°/", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 56, fontWeight: FontWeight.w500)),
Text(context.watch<UnitSettingsNotifier>().tempUnit == 'Fahrenheit' ? "${UnitConverter.celsiusToFahrenheit(selectedDayData!['minTemp']).round()}°" : "${selectedDayData!['minTemp'].round()}°", style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 56, fontWeight: FontWeight.w500)),
child: Row(children: [Text(tempUnit == 'Fahrenheit' ? "${UnitConverter.celsiusToFahrenheit(selectedDayData!['maxTemp']).round()}°/" : "${selectedDayData!['maxTemp'].round()}°/", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 56, fontWeight: FontWeight.w500)),
Text(tempUnit == 'Fahrenheit' ? "${UnitConverter.celsiusToFahrenheit(selectedDayData!['minTemp']).round()}°" : "${selectedDayData!['minTemp'].round()}°", style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 56, fontWeight: FontWeight.w500)),
SizedBox(width: 10,),
SvgPicture.asset(
WeatherIconMapper.getIcon(selectedDayData!['weatherCode'], 1),
@@ -692,23 +696,30 @@ class ConditionsWidgetsForecast extends StatelessWidget {
now.microsecond,
);
final sunriseFormat = context.watch<UnitSettingsNotifier>().timeUnit == '24 hr' ? DateFormat.Hm().format(sunrise) : DateFormat.jm().format(sunrise);
final sunsetFormat = context.watch<UnitSettingsNotifier>().timeUnit == '24 hr' ? DateFormat.Hm().format(sunset) : DateFormat.jm().format(sunset);
final timeUnit = PreferencesHelper.getString("selectedTimeUnit") ?? '12 hr';
final pressureUnit = PreferencesHelper.getString("selectedPressureUnit") ?? "hPa";
final precipUnit = PreferencesHelper.getString("selectedPrecipitationUnit") ?? "mm";
final visibilityUnit = PreferencesHelper.getString("selectedVisibilityUnit") ?? "Km";
final windUnit = PreferencesHelper.getString("selectedWindUnit") ?? "Km/h";
final convertedPressure = context.watch<UnitSettingsNotifier>().pressureUnit == 'inHg'
final sunriseFormat = timeUnit == '24 hr' ? DateFormat.Hm().format(sunrise) : DateFormat.jm().format(sunrise);
final sunsetFormat = timeUnit == '24 hr' ? DateFormat.Hm().format(sunset) : DateFormat.jm().format(sunset);
final convertedPressure = pressureUnit == 'inHg'
? UnitConverter.hPaToInHg(currentPressure)
: context.watch<UnitSettingsNotifier>().pressureUnit == 'mmHg'
: pressureUnit == 'mmHg'
? UnitConverter.hPaToMmHg(currentPressure)
: currentPressure;
final convertedPrecip = context.watch<UnitSettingsNotifier>().precipitationUnit == 'cm'
final convertedPrecip = precipUnit == 'cm'
? UnitConverter.mmToCm(currentTotalPrec)
: context.watch<UnitSettingsNotifier>().precipitationUnit == 'in'
: precipUnit == 'in'
? UnitConverter.mmToIn(currentTotalPrec)
: currentTotalPrec;
final convertedVisibility = context.watch<UnitSettingsNotifier>().visibilityUnit == 'Mile'
final convertedVisibility = visibilityUnit == 'Mile'
? UnitConverter.mToMiles(currentVisibility.toDouble()) : UnitConverter.mToKm(currentVisibility.toDouble());
@@ -717,9 +728,9 @@ class ConditionsWidgetsForecast extends StatelessWidget {
}
final convertedwindSpeed = context.watch<UnitSettingsNotifier>().windUnit == 'Mph'
final convertedwindSpeed = windUnit == 'Mph'
? UnitConverter.kmhToMph(currentWindSpeed)
: context.watch<UnitSettingsNotifier>().windUnit == 'M/s'
: windUnit == 'M/s'
? UnitConverter.kmhToMs(currentWindSpeed)
: currentWindSpeed.toStringAsFixed(0);
@@ -825,13 +836,13 @@ class ConditionsWidgetsForecast extends StatelessWidget {
Align(
alignment: Alignment.center,
child: Text("${convertedPressure.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(currentPressure == 0.0000001 ? '--' : "${convertedPressure.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Padding(
padding: EdgeInsets.only(bottom: 30),
child: Align(
alignment: Alignment.bottomCenter,
child: Text(context.watch<UnitSettingsNotifier>().pressureUnit, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 18),),
child: Text(pressureUnit, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 18),),
),
),
]
@@ -859,13 +870,13 @@ class ConditionsWidgetsForecast extends StatelessWidget {
Align(
alignment: Alignment.center,
child: Text("${convertedVisibility.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onTertiaryContainer, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(currentVisibility == 0.0000001 ? '--' : "${convertedVisibility.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onTertiaryContainer, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Padding(
padding: EdgeInsets.only(bottom: 30),
child: Align(
alignment: Alignment.bottomCenter,
child: Text(context.watch<UnitSettingsNotifier>().visibilityUnit, style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 18),),
child: Text(visibilityUnit, style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 18),),
),
),
],
@@ -882,12 +893,12 @@ class ConditionsWidgetsForecast extends StatelessWidget {
),
child: Stack(
children: [
WindCompassWidget(currentWindDirc: currentWindDirc, backgroundColor: Color(selectedContainerBgIndex)),
WindCompassWidget(currentWindDirc: currentWindDirc, backgroundColor: Color(selectedContainerBgIndex)),
headerWidgetConditions(headerText: "direction".tr(), headerIcon: Symbols.explore,),
Align(
alignment: Alignment.center,
child: Text(getCompassDirection(currentWindDirc), style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(currentWindDirc == 0.0000001 ? '--' : getCompassDirection(currentWindDirc), style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Align(
@@ -895,7 +906,7 @@ class ConditionsWidgetsForecast extends StatelessWidget {
child: Container(
margin: EdgeInsets.only(left: 20, right: 20),
height: 55,
child: Text("$convertedwindSpeed ${context.watch<UnitSettingsNotifier>().windUnit}", style:
child: Text(currentWindSpeed == 0.0000001 ? '--' : "$convertedwindSpeed $windUnit", style:
TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 16), maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,),
),
),
@@ -926,13 +937,13 @@ class ConditionsWidgetsForecast extends StatelessWidget {
Align(
alignment: Alignment.center,
child: Text("${currentUvIndex.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(currentUvIndex == 0.0000001 ? '--' : "${currentUvIndex.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).size.width * 0.11),
child: Align(
alignment: Alignment.bottomCenter,
child: Text(getUvIndexType(currentUvIndex.round()), style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 15),),
child: Text(currentUvIndex == 0.0000001 ? '--' : getUvIndexType(currentUvIndex.round()), style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 15),),
),
),
],
@@ -960,10 +971,10 @@ class ConditionsWidgetsForecast extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("${double.parse(convertedPrecip.toStringAsFixed(2))}", style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.11, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurface),),
Text(currentTotalPrec == 0.0000001 ? '--' : "${double.parse(convertedPrecip.toStringAsFixed(2))}", style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.11, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurface),),
Padding(
padding: EdgeInsets.only(top: 15),
child: Text(context.watch<UnitSettingsNotifier>().precipitationUnit, style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.secondary),),
child: Text(precipUnit, style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.secondary),),
),
],
),
@@ -979,7 +990,7 @@ class ConditionsWidgetsForecast extends StatelessWidget {
SizedBox(
width: 100,
child: Text("Total rain for the day", style: TextStyle(height: 1.2, color: Theme.of(context).colorScheme.onSurfaceVariant))),
Text("$currentTotalPrecProb%", style: TextStyle(fontWeight: FontWeight.w700, color: Theme.of(context).colorScheme.primary),)
Text(currentTotalPrecProb == 0.0000001 ? '--' : "$currentTotalPrecProb%", style: TextStyle(fontWeight: FontWeight.w700, color: Theme.of(context).colorScheme.primary),)
],
)
)
+38 -11
View File
@@ -799,8 +799,9 @@ final duskFormatted = formatInstantToLocalTime(dusk, timeUnit: timeFormatDUSKDAW
final data = snapshot.data!;
final weather = data['data'];
final hourly = weather['hourly'];
final List<dynamic> hourlyTime = hourly['time'];
final currentVisibility = hourly['visibility'][0];
final currentVisibility = hourly['visibility'][getStartIndex(weather['utc_offset_seconds'].toString(), hourlyTime)] ?? 0.0;
final visibilityUnit = PreferencesHelper.getString("selectedVisibilityUnit") ?? "Km";
final convertedVisibility = visibilityUnit == 'Mile'
@@ -1145,7 +1146,8 @@ Widget buildUVExtended(){
final hourly = weather['hourly'];
final List<dynamic> hourlyTime = hourly['time'];
final List<dynamic> uvIndexes = hourly['uv_index'];
final List<dynamic> uvIndexes = hourly['uv_index'];
final offset = Duration(seconds: int.parse(weather['utc_offset_seconds'].toString()));
@@ -1164,8 +1166,11 @@ Widget buildUVExtended(){
if (startIndex == -1) startIndex = 0;
final double minUv = uvIndexes.reduce((a, b) => a < b ? a : b);
final double maxUv = uvIndexes.reduce((a, b) => a > b ? a : b);
final nonNullUvIndexes = uvIndexes.whereType<num>().toList();
final double minUv = nonNullUvIndexes.isNotEmpty ? nonNullUvIndexes.reduce((a, b) => a < b ? a : b).toDouble() : 0;
final double maxUv = nonNullUvIndexes.isNotEmpty ? nonNullUvIndexes.reduce((a, b) => a > b ? a : b).toDouble() : 1;
List<double> todayUvIndexes = [];
@@ -1202,9 +1207,9 @@ final double maxUv = uvIndexes.reduce((a, b) => a > b ? a : b);
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text("${avgUv.round()}", style: TextStyle(fontSize: 50, color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.w500),),
Text(avgUv != null ? "${avgUv.round()}" : "--", style: TextStyle(fontSize: 50, color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.w500),),
Padding(padding: EdgeInsets.only(bottom: 11, left: 8),
child: Text(getUvIndexType(avgUv.round()), style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500),))
child: Text(avgUv != null ? getUvIndexType(avgUv.round()) : "Not available", style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500),))
],
)
@@ -1236,9 +1241,11 @@ final double maxUv = uvIndexes.reduce((a, b) => a > b ? a : b);
final uv = uvIndexes[dataIndex];
final double uvValue = (uv is num) ? uv.toDouble() : 0;
final double uvPercentage = ((uvValue - minUv) / (maxUv - minUv)) * 100;
final bool isValidUv = uv is num;
final double? uvValue = isValidUv ? uv.toDouble() : null;
final double uvPercentage = uvValue != null && maxUv != minUv
? ((uvValue - minUv) / (maxUv - minUv)) * 100
: 0;
EdgeInsets itemMargin = EdgeInsets.only(
@@ -1281,7 +1288,7 @@ final double maxUv = uvIndexes.reduce((a, b) => a > b ? a : b);
width: 43,
height: math.max((uvPercentage / 100) * 160, 48),
decoration: BoxDecoration(
color: getUvColor(uvValue, context),
color: getUvColor(uvValue ?? 0, context),
borderRadius: BorderRadius.circular(50),
),
child: Align(
@@ -1316,7 +1323,7 @@ final double maxUv = uvIndexes.reduce((a, b) => a > b ? a : b);
),
const SizedBox(height: 10),
Text("${uv.round()}", style: TextStyle(fontSize: 14, color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500)),
Text(uvValue != null ? "${uvValue.round()}" : "--", style: TextStyle(fontSize: 14, color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500)),
Text(hour, style: TextStyle(fontSize: 15, color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.w500)),
],
),
@@ -1985,4 +1992,24 @@ class AQISliderBar extends StatelessWidget {
// ],
);
}
}
int getStartIndex(utc_offset_seconds, hourlyTime) {
final offset = Duration(seconds: int.parse(utc_offset_seconds));
final nowUtc = DateTime.now().toUtc();
final nowLocal = nowUtc.add(offset);
final timeUnit = PreferencesHelper.getString("selectedTimeUnit") ?? '12 hr';
final roundedNow = DateTime(nowLocal.year, nowLocal.month, nowLocal.day, nowLocal.hour);
int startIndex = hourlyTime.indexWhere((timeStr) {
final forecastLocal = DateTime.parse(timeStr);
return !forecastLocal.isBefore(roundedNow);
});
if (startIndex == -1) startIndex = 0;
return startIndex;
}
+99 -35
View File
@@ -64,6 +64,7 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
List<int> itemOrder = [];
final String orderPrefsKey = 'tile_order';
@override
@@ -193,7 +194,7 @@ List<Widget> gridItems = itemOrder.map((i) {
padding: EdgeInsets.only(left: 10),
child: Align(
alignment: Alignment.centerLeft,
child: Text("${widget.currentHumidity}%",
child: Text("${widget.currentHumidity == 0.0000001 ? '--' : widget.currentHumidity}%",
style: TextStyle(
color: Theme.of(context).colorScheme.onTertiaryContainer, fontSize: MediaQuery.of(context).size.width * 0.13, fontWeight: FontWeight.w500),
),
@@ -213,7 +214,7 @@ List<Widget> gridItems = itemOrder.map((i) {
color: Theme.of(context).colorScheme.tertiary,
borderRadius: BorderRadius.circular(50),
),
child: Center(child: Text("$dewpointConverted°", style: TextStyle(color: Theme.of(context).colorScheme.onTertiary, fontSize: 16))),
child: Center(child: Text(widget.currentDewPoint == 0.0000001 ? '--' : "$dewpointConverted°", style: TextStyle(color: Theme.of(context).colorScheme.onTertiary, fontSize: 16))),
),
Text("dew_point".tr(), style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.w500))
],
@@ -225,11 +226,20 @@ List<Widget> gridItems = itemOrder.map((i) {
),
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(widget.currentPressure == 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('humidity_widget'), fullscreenDialog: true),
) : null;
},
);
);
}
}
},
);
case 1:
return
GestureDetector(
@@ -280,7 +290,7 @@ List<Widget> gridItems = itemOrder.map((i) {
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Theme.of(context).colorScheme.outline, // Or any color you need
color: Theme.of(context).colorScheme.outline,
width: 1.5,
),
),
@@ -342,7 +352,7 @@ List<Widget> gridItems = itemOrder.map((i) {
Align(
alignment: Alignment.center,
child: Text("${convertedPressure.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(widget.currentPressure == 0.0000001 ? '--' : "${convertedPressure.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Padding(
padding: EdgeInsets.only(bottom: 30),
@@ -355,10 +365,19 @@ List<Widget> gridItems = itemOrder.map((i) {
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(widget.currentPressure == 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('pressure_widget'), fullscreenDialog: true),
) : null;
},
);
}
}
},
);
case 3:
@@ -387,7 +406,7 @@ List<Widget> gridItems = itemOrder.map((i) {
Align(
alignment: Alignment.center,
child: Text("${convertedVisibility.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onTertiaryContainer, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(widget.currentVisibility == 0.0000001 ? '--' : "${convertedVisibility.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onTertiaryContainer, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Padding(
padding: EdgeInsets.only(bottom: 30),
@@ -401,10 +420,19 @@ List<Widget> gridItems = itemOrder.map((i) {
),
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(widget.currentVisibility== 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('visibility_widget'), fullscreenDialog: true),
) : null;
},
);
}
}
}
);
case 4:
@@ -425,7 +453,7 @@ List<Widget> gridItems = itemOrder.map((i) {
headerWidgetConditions(headerText: "direction".tr(), headerIcon: Symbols.explore,),
Align(
alignment: Alignment.center,
child: Text(getCompassDirection(widget.currentWindDirc), style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text(widget.currentWindDirc == 0.0000001 ? '--' : getCompassDirection(widget.currentWindDirc), style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Align(
@@ -433,7 +461,7 @@ List<Widget> gridItems = itemOrder.map((i) {
child: Container(
margin: EdgeInsets.only(left: 20, right: 20),
height: 55,
child: Text(getWindSpeedType(widget.currentWindSpeed), style:
child: Text(widget.currentWindSpeed == 0.0000001 ? '--' : getWindSpeedType(widget.currentWindSpeed), style:
TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 16), maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,),
),
),
@@ -442,10 +470,19 @@ List<Widget> gridItems = itemOrder.map((i) {
)
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(widget.currentWindSpeed == 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('winddirc_widget'), fullscreenDialog: true),
) : null;
},
);
}
}
},
);
case 5:
@@ -472,13 +509,13 @@ List<Widget> gridItems = itemOrder.map((i) {
Align(
alignment: Alignment.center,
child: Text("${widget.currentUvIndex.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
child: Text("${widget.currentUvIndex == 0.0000001 ? '--' : widget.currentUvIndex.round()}", style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: MediaQuery.of(context).size.width * 0.1, fontWeight: FontWeight.w500),),
),
Padding(
padding: EdgeInsets.only(bottom: 40),
child: Align(
alignment: Alignment.bottomCenter,
child: Text(getUvIndexType(widget.currentUvIndex.round()), style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 15),),
child: Text(widget.currentUvIndex == 0.0000001 ? '--' : getUvIndexType(widget.currentUvIndex.round()), style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 15),),
),
),
],
@@ -486,10 +523,19 @@ List<Widget> gridItems = itemOrder.map((i) {
),
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(widget.currentUvIndex == 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('uv_widget'), fullscreenDialog: true),
) : null;
},
);
}
}
}
);
case 6:
@@ -512,7 +558,7 @@ List<Widget> gridItems = itemOrder.map((i) {
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(right: 10, bottom: 12),
child: Text(aqiFormat.toString(), style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.11, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurface),),
child: Text(aqiFormat == 0.0000001 ? '--' : aqiFormat.toString(), style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.11, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurface),),
),
),
AQISliderBar(
@@ -523,17 +569,26 @@ List<Widget> gridItems = itemOrder.map((i) {
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10, bottom: 25),
child: Text(getAQIIndexType(aqiFormat, aqiUnit == 'European' ? true : false), style: TextStyle(fontSize: 17, color: Theme.of(context).colorScheme.onSurfaceVariant),),
child: Text(aqiFormat == 0.0000001 ? '--' : getAQIIndexType(aqiFormat, aqiUnit == 'European' ? true : false), style: TextStyle(fontSize: 17, color: Theme.of(context).colorScheme.onSurfaceVariant),),
),
),
],
),
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(aqiFormat == 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('aqi_widget'), fullscreenDialog: true),
) : null;
},
);
}
}
},
);
case 7:
@@ -558,7 +613,7 @@ List<Widget> gridItems = itemOrder.map((i) {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("${double.parse(convertedPrecip.toStringAsFixed(2))}", style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.11, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurface),),
Text(widget.currentTotalPrec == 0.0000001 ? '--' : "${double.parse(convertedPrecip.toStringAsFixed(2))}", style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.11, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurface),),
Padding(
padding: EdgeInsets.only(top: 15),
child: Text(precipitationUnit, style: TextStyle(fontSize: 20, color: Theme.of(context).colorScheme.secondary),),
@@ -586,10 +641,19 @@ List<Widget> gridItems = itemOrder.map((i) {
),
),
onTap: () {
widget.isFromHome ? Navigator.of(context).push(
if(widget.isFromHome){
if(widget.currentTotalPrec == 0.0000001){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Row(spacing: 10, children: [Icon(Symbols.error, color: Theme.of(context).colorScheme.onInverseSurface,), Text("No data available")],))
);
} else{
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ExtendWidget('precip_widget'), fullscreenDialog: true),
) : null;
},
);
}
}
},
);
default:
return const SizedBox();
@@ -1025,7 +1089,7 @@ String buildUVSvg(Color colorSurface, uvValue) {
<path fill="#af5cf7" d="M143,121m8,-0a8,8 0,1 1,-16 -0a8,8 0,1 1,16 -0" />
</svg>
''';
}
}
return returnSvg;