Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion WeatherExtension/DockBands/PinnedWeatherBand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private async Task UpdateWeatherAsync()
"{0} {1}",
WeatherFormatter.Temperature(current.Temperature, tempUnit),
condition);
Icon = Icons.GetIconForWeatherCode(current.WeatherCode);
Icon = Icons.GetIconForWeatherCode(current.WeatherCode, isNight: current.IsDay == 0);

if (DockItem is CommandItem dockCommandItem)
{
Expand Down
19 changes: 14 additions & 5 deletions WeatherExtension/Icons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,22 @@ internal sealed class Icons

internal static IconInfo ThunderstormHail { get; } = new IconInfo("⛈️");

internal static IconInfo GetIconForWeatherCode(int weatherCode)
// Nighttime variants
internal static IconInfo ClearSkyNight { get; } = new IconInfo("🌙");

internal static IconInfo MainlyClearNight { get; } = new IconInfo("🌙");

internal static IconInfo PartlyCloudyNight { get; } = new IconInfo("☁️");

internal static IconInfo WeatherIconNight { get; } = new IconInfo("🌙");

internal static IconInfo GetIconForWeatherCode(int weatherCode, bool isNight = false)
{
return weatherCode switch
{
0 => ClearSky,
1 or 2 => MainlyClear,
3 => PartlyCloudy,
0 => isNight ? ClearSkyNight : ClearSky,
1 or 2 => isNight ? MainlyClearNight : MainlyClear,
3 => isNight ? PartlyCloudyNight : PartlyCloudy,
45 or 48 => Fog,
51 or 53 or 55 => Drizzle,
56 or 57 => DrizzleFreezing,
Expand All @@ -67,7 +76,7 @@ internal static IconInfo GetIconForWeatherCode(int weatherCode)
85 or 86 => SnowShowers,
95 => Thunderstorm,
96 or 99 => ThunderstormHail,
_ => WeatherIcon,
_ => isNight ? WeatherIconNight : WeatherIcon,
};
}

Expand Down
18 changes: 18 additions & 0 deletions WeatherExtension/Models/ForecastData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,22 @@ public sealed class DailyForecast

[JsonPropertyName("precipitation_probability_max")]
public List<int>? PrecipitationProbabilityMax { get; set; }

[JsonPropertyName("sunrise")]
public List<string>? Sunrise { get; set; }

[JsonPropertyName("sunset")]
public List<string>? Sunset { get; set; }
}

public sealed class HourlyForecastData
{
[JsonPropertyName("hourly")]
public HourlyForecast? Hourly { get; set; }

[JsonPropertyName("daily")]
public HourlyDailyInfo? Daily { get; set; }

[JsonPropertyName("latitude")]
public double Latitude { get; set; }

Expand Down Expand Up @@ -80,4 +89,13 @@ public sealed class HourlyForecast
public List<int>? RelativeHumidity { get; set; }
}

public sealed class HourlyDailyInfo
{
[JsonPropertyName("sunrise")]
public List<string>? Sunrise { get; set; }

[JsonPropertyName("sunset")]
public List<string>? Sunset { get; set; }
}

#pragma warning restore SA1402 // File may only contain a single type
3 changes: 3 additions & 0 deletions WeatherExtension/Models/WeatherData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public sealed class CurrentWeather

[JsonPropertyName("wind_direction_10m")]
public int WindDirection { get; set; }

[JsonPropertyName("is_day")]
public int IsDay { get; set; } = 1;
}

#pragma warning restore SA1402 // File may only contain a single type
40 changes: 39 additions & 1 deletion WeatherExtension/Pages/HourlyForecastPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ private List<ListItem> CreateHourlyItems(HourlyForecastData hourlyData)
var windUnit = _settingsManager.WindSpeedUnit == "mph" ? "mph" : "km/h";
var now = DateTime.Now;

// Parse sunrise/sunset times for night determination
var sunriseTimes = ParseDailyTimes(hourlyData.Daily?.Sunrise);
var sunsetTimes = ParseDailyTimes(hourlyData.Daily?.Sunset);

var count = hourly.Time?.Count ?? 0;
for (var i = 0; i < count; i++)
{
Expand Down Expand Up @@ -122,6 +126,7 @@ private List<ListItem> CreateHourlyItems(HourlyForecastData hourlyData)
var temperature = hourly.Temperature[i];
var feelsLike = hourly.ApparentTemperature[i];
var condition = Icons.GetWeatherDescription(weatherCode);
var isNight = IsNightTime(time, sunriseTimes, sunsetTimes);

var precipProb = hourly.PrecipitationProbability != null && i < hourly.PrecipitationProbability.Count
? hourly.PrecipitationProbability[i]
Expand All @@ -139,7 +144,7 @@ private List<ListItem> CreateHourlyItems(HourlyForecastData hourlyData)
{
Title = WeatherFormatter.Hour(time, _settingsManager.Use24HourClock),
Subtitle = $"{condition} — {temperature:F0}{tempUnit}",
Icon = Icons.GetIconForWeatherCode(weatherCode),
Icon = Icons.GetIconForWeatherCode(weatherCode, isNight),
Details = new Details
{
Title = WeatherFormatter.Hour(time, _settingsManager.Use24HourClock),
Expand All @@ -159,6 +164,39 @@ private List<ListItem> CreateHourlyItems(HourlyForecastData hourlyData)
return items;
}

private static List<DateTime> ParseDailyTimes(List<string>? times)
{
var result = new List<DateTime>();
if (times == null)
{
return result;
}

foreach (var t in times)
{
if (DateTime.TryParse(t, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsed))
{
result.Add(parsed);
}
}

return result;
}

private static bool IsNightTime(DateTime time, List<DateTime> sunriseTimes, List<DateTime> sunsetTimes)
{
// Find the sunrise/sunset for the same day
var sunrise = sunriseTimes.FirstOrDefault(s => s.Date == time.Date);
var sunset = sunsetTimes.FirstOrDefault(s => s.Date == time.Date);

if (sunrise == default || sunset == default)
{
return false;
}

return time < sunrise || time >= sunset;
}

public override IListItem[] GetItems()
{
lock (_sync)
Expand Down
2 changes: 1 addition & 1 deletion WeatherExtension/Pages/WeatherDetailPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private ListItem CreateCurrentWeatherItem(WeatherData weatherData)
{
Title = Resources.current_weather,
Subtitle = $"{condition} — {current.Temperature:F0}{tempUnit}",
Icon = Icons.GetIconForWeatherCode(current.WeatherCode),
Icon = Icons.GetIconForWeatherCode(current.WeatherCode, isNight: current.IsDay == 0),
Details = new Details
{
Title = Resources.current_weather,
Expand Down
2 changes: 1 addition & 1 deletion WeatherExtension/Pages/WeatherListPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ private ListItem CreateWeatherItem(GeocodingResult location, WeatherData weather
{
Title = location.DisplayName,
Subtitle = WeatherFormatter.CurrentSubtitle(current, _settingsManager.TemperatureUnit),
Icon = Icons.GetIconForWeatherCode(current.WeatherCode),
Icon = Icons.GetIconForWeatherCode(current.WeatherCode, isNight: current.IsDay == 0),
Tags = tags.ToArray(),
Details = new Details
{
Expand Down
6 changes: 3 additions & 3 deletions WeatherExtension/Services/OpenMeteoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ internal OpenMeteoService(HttpMessageHandler handler)

var url = string.Create(
CultureInfo.InvariantCulture,
$"{BaseUrl}?latitude={latitude}&longitude={longitude}&current=temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,wind_direction_10m&temperature_unit={temperatureUnit}&wind_speed_unit={windSpeedUnit}&timezone=auto");
$"{BaseUrl}?latitude={latitude}&longitude={longitude}&current=temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,wind_direction_10m,is_day&temperature_unit={temperatureUnit}&wind_speed_unit={windSpeedUnit}&timezone=auto");

var response = await _httpClient.GetAsync(url, ct).ConfigureAwait(false);

Expand Down Expand Up @@ -143,7 +143,7 @@ internal OpenMeteoService(HttpMessageHandler handler)

var url = string.Create(
CultureInfo.InvariantCulture,
$"{BaseUrl}?latitude={latitude}&longitude={longitude}&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max&temperature_unit={temperatureUnit}&timezone=auto");
$"{BaseUrl}?latitude={latitude}&longitude={longitude}&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max,sunrise,sunset&temperature_unit={temperatureUnit}&timezone=auto");

var response = await _httpClient.GetAsync(url, ct).ConfigureAwait(false);

Expand Down Expand Up @@ -214,7 +214,7 @@ internal OpenMeteoService(HttpMessageHandler handler)

var url = string.Create(
CultureInfo.InvariantCulture,
$"{BaseUrl}?latitude={latitude}&longitude={longitude}&hourly=temperature_2m,apparent_temperature,weather_code,precipitation_probability,wind_speed_10m,relative_humidity_2m&temperature_unit={temperatureUnit}&wind_speed_unit={windSpeedUnit}&forecast_days=2&timezone=auto");
$"{BaseUrl}?latitude={latitude}&longitude={longitude}&hourly=temperature_2m,apparent_temperature,weather_code,precipitation_probability,wind_speed_10m,relative_humidity_2m&daily=sunrise,sunset&temperature_unit={temperatureUnit}&wind_speed_unit={windSpeedUnit}&forecast_days=2&timezone=auto");

var response = await _httpClient.GetAsync(url, ct).ConfigureAwait(false);

Expand Down
1 change: 1 addition & 0 deletions WeatherExtension/Services/WeatherJsonContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Microsoft.CmdPal.Ext.Weather.Services;
[JsonSerializable(typeof(WeatherData))]
[JsonSerializable(typeof(ForecastData))]
[JsonSerializable(typeof(HourlyForecastData))]
[JsonSerializable(typeof(HourlyDailyInfo))]
[JsonSerializable(typeof(List<NominatimResult>))]
[JsonSerializable(typeof(NominatimAddress))]
[JsonSerializable(typeof(List<PinnedLocation>))]
Expand Down
Loading