diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..5b8b9e0
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "messagepack.generator": {
+ "version": "2.5.140",
+ "commands": [
+ "mpc"
+ ],
+ "rollForward": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/.idea/.idea.FluentWeather/.idea/indexLayout.xml b/.idea/.idea.FluentWeather/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.FluentWeather/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.FluentWeather/.idea/vcs.xml b/.idea/.idea.FluentWeather/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.FluentWeather/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.FluentWeather/.idea/workspace.xml b/.idea/.idea.FluentWeather/.idea/workspace.xml
index 329b864..d986678 100644
--- a/.idea/.idea.FluentWeather/.idea/workspace.xml
+++ b/.idea/.idea.FluentWeather/.idea/workspace.xml
@@ -7,7 +7,10 @@
-
+
+
+
+
@@ -16,9 +19,9 @@
-
+ {
+ "associatedIndex": 4
+}
@@ -27,8 +30,8 @@
-
+
@@ -80,6 +83,7 @@
1714267439950
+
diff --git a/FluentWeather.Abstraction/Interfaces/WeatherProvider/IHistoricalWeatherProvider.cs b/FluentWeather.Abstraction/Interfaces/WeatherProvider/IHistoricalWeatherProvider.cs
new file mode 100644
index 0000000..fd9fe34
--- /dev/null
+++ b/FluentWeather.Abstraction/Interfaces/WeatherProvider/IHistoricalWeatherProvider.cs
@@ -0,0 +1,11 @@
+using FluentWeather.Abstraction.Models;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace FluentWeather.Abstraction.Interfaces.WeatherProvider;
+
+public interface IHistoricalWeatherProvider
+{
+ public Task> GetHistoricalDailyWeather(double lon, double lat, DateTime startTime, DateTime endTime);
+}
\ No newline at end of file
diff --git a/FluentWeather.Abstraction/Models/HistoricalDailyWeatherBase.cs b/FluentWeather.Abstraction/Models/HistoricalDailyWeatherBase.cs
new file mode 100644
index 0000000..4ccb347
--- /dev/null
+++ b/FluentWeather.Abstraction/Models/HistoricalDailyWeatherBase.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace FluentWeather.Abstraction.Models;
+
+public class HistoricalDailyWeatherBase
+{
+ public DateTime Date { get; set; }
+
+ public WeatherCode Weather { get; set; }
+
+ public int HistoricalMaxTemperature { get; set; }
+
+ public DateTime HistoricalMaxTemperatureDate { get; set; }
+
+ public int HistoricalMinTemperature { get; set; }
+
+ public DateTime HistoricalMinTemperatureDate { get; set; }
+
+ public int AverageMaxTemperature { get; set; }
+
+ public int AverageMinTemperature { get; set; }
+
+ public double? AveragePrecipitation { get; set; }
+
+ public double? MaxPrecipitation { get; set; }
+
+ public DateTime? MaxPrecipitationDate { get; set; }
+ public double? AveragePrecipitationHours { get; set; }
+}
\ No newline at end of file
diff --git a/FluentWeather.Abstraction/Models/Location.cs b/FluentWeather.Abstraction/Models/Location.cs
index eca081e..0703707 100644
--- a/FluentWeather.Abstraction/Models/Location.cs
+++ b/FluentWeather.Abstraction/Models/Location.cs
@@ -116,6 +116,12 @@ public override bool Equals(object obj)
public override int GetHashCode()
{
- return base.GetHashCode();
+ unchecked
+ {
+ int hash = 17;
+ hash = hash * 23 + Latitude.GetHashCode();
+ hash = hash * 23 + Longitude.GetHashCode();
+ return hash;
+ }
}
}
diff --git a/FluentWeather.Abstraction/Models/WeatherDailyBase.cs b/FluentWeather.Abstraction/Models/WeatherDailyBase.cs
index f2981af..a82a749 100644
--- a/FluentWeather.Abstraction/Models/WeatherDailyBase.cs
+++ b/FluentWeather.Abstraction/Models/WeatherDailyBase.cs
@@ -7,8 +7,8 @@ namespace FluentWeather.Abstraction.Models;
public class WeatherDailyBase : WeatherBase, IWeatherNight, ITemperatureRange, IWind, ITime, IAstronomic,ICloudAmount,IVisibility,IPressure,IHumidity
{
- public int MaxTemperature { get; set; }
- public int MinTemperature { get; set; }
+ public int MaxTemperature { get; set; }
+ public int MinTemperature { get; set; }
public DateTime Time { get; set; }
public WeatherBase? WeatherNight { get; set; }
@@ -30,4 +30,6 @@ public string WindDirectionDescription
public int? Visibility { get; set; }
public int? Pressure { get; set; }
public int? Humidity { get; set ; }
+ public double? Precipitation { get; set; }
+ public double? PrecipitationHours { get; set; }
}
\ No newline at end of file
diff --git a/FluentWeather.OpenMeteoProvider/FluentWeather.OpenMeteoProvider.csproj b/FluentWeather.OpenMeteoProvider/FluentWeather.OpenMeteoProvider.csproj
index 29afc10..e34f8cf 100644
--- a/FluentWeather.OpenMeteoProvider/FluentWeather.OpenMeteoProvider.csproj
+++ b/FluentWeather.OpenMeteoProvider/FluentWeather.OpenMeteoProvider.csproj
@@ -8,7 +8,7 @@
enable
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/FluentWeather.OpenMeteoProvider/Mappers/CurrentWeatherMapper.cs b/FluentWeather.OpenMeteoProvider/Mappers/CurrentWeatherMapper.cs
index 8204a32..f4f62d2 100644
--- a/FluentWeather.OpenMeteoProvider/Mappers/CurrentWeatherMapper.cs
+++ b/FluentWeather.OpenMeteoProvider/Mappers/CurrentWeatherMapper.cs
@@ -12,14 +12,14 @@ public static OpenMeteoWeatherNow MapToOpenMeteoWeatherNow(this CurrentWeather i
return new OpenMeteoWeatherNow
{
//Description = WeatherCodeHelper.GetWeatherDescription(item.WeatherCode!.Value),
- WeatherType = WeatherCodeHelper.GetWeatherType(item.WeatherCode.Value),
+ WeatherType = WeatherCodeHelper.GetWeatherType(item.WeatherCode!.Value),
WindDirection = UnitConverter.GetWindDirectionFromAngle(item.WindDirection10m!.Value),
- WindScale = UnitConverter.GetWindScaleFromKM((int)item.WindSpeed10m!).ToString(),
+ WindScale = UnitConverter.GetWindScaleFromKM((int)item.WindSpeed10m!.Value).ToString(),
WindSpeed = (int)item.WindSpeed10m,
ApparentTemperature = (int)item.ApparentTemperature!.Value,
Humidity = item.RelativeHumidity2m!.Value,
- Temperature = (int)item.Temperature2m!,
- Pressure = (int)item.SurfacePressure!,
+ Temperature = (int)Math.Round(item.Temperature2m!.Value),
+ Pressure = item.SurfacePressure is null ? null : (int)Math.Round(item.SurfacePressure.Value),
//Visibility = int.Parse(item.),
CloudAmount = item.CloudCover
diff --git a/FluentWeather.OpenMeteoProvider/Mappers/DailyForecastMapper.cs b/FluentWeather.OpenMeteoProvider/Mappers/DailyForecastMapper.cs
index 8421347..4a23d47 100644
--- a/FluentWeather.OpenMeteoProvider/Mappers/DailyForecastMapper.cs
+++ b/FluentWeather.OpenMeteoProvider/Mappers/DailyForecastMapper.cs
@@ -15,11 +15,11 @@ public static OpenMeteoDailyForecast MapToOpenMeteoDailyForecast(this DailyForec
//Description = WeatherCodeHelper.GetWeatherDescription(item.WeatherCode!.Value),
WeatherType = WeatherCodeHelper.GetWeatherType(item.WeatherCode!.Value),
WindDirection = UnitConverter.GetWindDirectionFromAngle(item.WindDirection10mDominant!.Value),
- WindSpeed = (int)item.WindSpeed10mMax!,
- WindScale = UnitConverter.GetWindScaleFromKM((int)item.WindSpeed10mMax!.Value).ToString(),
+ WindSpeed = (int)Math.Round(item.WindSpeed10mMax!.Value),
+ WindScale = UnitConverter.GetWindScaleFromKM((int)Math.Round(item.WindSpeed10mMax!.Value)).ToString(),
//Humidity = int.Parse(item.),
- MaxTemperature = (int)item.Temperature2mMax!,
- MinTemperature = (int)item.Temperature2mMin!,
+ MaxTemperature = (int)Math.Round(item.Temperature2mMax!.Value),
+ MinTemperature = (int)Math.Round(item.Temperature2mMin!.Value),
//Pressure = int.Parse(item),
Time = item.Time!.Value,
//Visibility = int.Parse(item.),
diff --git a/FluentWeather.OpenMeteoProvider/Mappers/HourlyForecastMapper.cs b/FluentWeather.OpenMeteoProvider/Mappers/HourlyForecastMapper.cs
index c09b173..d7c066e 100644
--- a/FluentWeather.OpenMeteoProvider/Mappers/HourlyForecastMapper.cs
+++ b/FluentWeather.OpenMeteoProvider/Mappers/HourlyForecastMapper.cs
@@ -16,14 +16,14 @@ public static WeatherHourlyBase MapToHourlyForecast(this HourlyForecastItem item
WindDirection = UnitConverter.GetWindDirectionFromAngle(item.WindDirection10m!.Value),
//Description = WeatherCodeHelper.GetWeatherDescription(item.WeatherCode!.Value),
WindScale = UnitConverter.GetWindScaleFromKM((int)item.WindSpeed10m!.Value).ToString(),
- WindSpeed = (int)item.WindSpeed10m!.Value,
+ WindSpeed = (int)Math.Round(item.WindSpeed10m!.Value),
Humidity = item.RelativeHumidity2m,
- Pressure = (int?)item.SurfacePressure,
- Temperature = (int)item.Temperature2m!,
+ Pressure = item.SurfacePressure is null ? null : (int)Math.Round(item.SurfacePressure.Value),
+ Temperature = (int)Math.Round(item.Temperature2m!.Value),
Time = item.Time!.Value,
PrecipitationProbability = item.PrecipitationProbability,
CloudAmount = item.CloudCover,
- Visibility = (int?)item.Visibility/1000,
+ Visibility = item.Visibility is null ? null : (int)Math.Round(item.Visibility.Value/1000),
};
}
}
\ No newline at end of file
diff --git a/FluentWeather.OpenMeteoProvider/OpenMeteoProvider.cs b/FluentWeather.OpenMeteoProvider/OpenMeteoProvider.cs
index 54b6d0f..f31e985 100644
--- a/FluentWeather.OpenMeteoProvider/OpenMeteoProvider.cs
+++ b/FluentWeather.OpenMeteoProvider/OpenMeteoProvider.cs
@@ -11,10 +11,11 @@
using FluentWeather.OpenMeteoProvider.Models;
using OpenMeteoApi.Variables;
using System;
+using System.Linq;
namespace FluentWeather.OpenMeteoProvider;
-public sealed class OpenMeteoProvider : ProviderBase, ICurrentWeatherProvider, IAirConditionProvider, IDailyForecastProvider, IHourlyForecastProvider , IPrecipitationProvider
+public sealed class OpenMeteoProvider : ProviderBase, ICurrentWeatherProvider, IAirConditionProvider, IDailyForecastProvider, IHourlyForecastProvider, IPrecipitationProvider, IHistoricalWeatherProvider
{
public override string Name => "OpenMeteo";
public override string Id => "open-meteo";
@@ -48,7 +49,7 @@ public async Task> GetDailyForecasts(double lon, double l
public async Task> GetHourlyForecasts(double lon, double lat)
{
var result = await Client.GetHourlyForecasts(lat, lon);
- return result.ConvertAll(p => p.MapToHourlyForecast());
+ return result.ConvertAll(p => p.MapToHourlyForecast());
}
public async Task GetPrecipitations(double lon, double lat)
@@ -60,4 +61,25 @@ public async Task GetPrecipitations(double lon, double lat)
};
return precip;
}
+
+ public async Task> GetHistoricalDailyWeather(double lon, double lat, DateTime startTime, DateTime endTime)
+ {
+ var list = new List();
+ var data = await Client.GetHistoricalWeatherData(lat, lon, startTime, endTime,
+ dailyVariables: [DailyVariables.WeatherCode,DailyVariables.Temperature2mMax,DailyVariables.Temperature2mMin,DailyVariables.PrecipitationSum,DailyVariables.PrecipitationHours]
+ );
+ for (var i = 0; i < data.DailyForecast!.Time!.Count(); i++)
+ {
+ var item = new WeatherDailyBase
+ {
+ Time = data.DailyForecast.Time![i]!.Value,
+ Precipitation = data.DailyForecast.PrecipitationSum![i],
+ PrecipitationHours = data.DailyForecast.PrecipitationHours![i],
+ MaxTemperature = (int)Math.Round(data.DailyForecast.Temperature2mMax![i]!.Value),
+ MinTemperature = (int)Math.Round(data.DailyForecast.Temperature2mMin![i]!.Value),
+ };
+ list.Add(item);
+ }
+ return list;
+ }
}
\ No newline at end of file
diff --git a/FluentWeather.Uwp.Shared/Helpers/ValueConverters/ConverterMethods.cs b/FluentWeather.Uwp.Shared/Helpers/ValueConverters/ConverterMethods.cs
index 1afc2c7..609a6fc 100644
--- a/FluentWeather.Uwp.Shared/Helpers/ValueConverters/ConverterMethods.cs
+++ b/FluentWeather.Uwp.Shared/Helpers/ValueConverters/ConverterMethods.cs
@@ -144,5 +144,10 @@ public static string GetImageNameNight(this WeatherCode weatherType)
_ => "",
};
}
+
+ public static int Subtract(this int num1,int num2)
+ {
+ return num1 - num2;
+ }
}
diff --git a/FluentWeather.Uwp/App.xaml b/FluentWeather.Uwp/App.xaml
index 5a31457..b2b99d8 100644
--- a/FluentWeather.Uwp/App.xaml
+++ b/FluentWeather.Uwp/App.xaml
@@ -3,10 +3,10 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
- xmlns:local="using:FluentWeather.Uwp"
+ xmlns:local="using:FluentWeather.Uwp"
xmlns:themes="using:FluentWeather.Uwp.Themes"
- xmlns:valueConverters2="using:ValueConverters"
- xmlns:valueConverters="using:FluentWeather.Uwp.Shared.Helpers.ValueConverters">
+ xmlns:valueConverters="using:FluentWeather.Uwp.Shared.Helpers.ValueConverters"
+ xmlns:valueConverters2="using:ValueConverters">
diff --git a/FluentWeather.Uwp/Controls/Dialogs/DailyForecastDialog.xaml.cs b/FluentWeather.Uwp/Controls/Dialogs/DailyForecastDialog.xaml.cs
index baa9adc..ebe96b2 100644
--- a/FluentWeather.Uwp/Controls/Dialogs/DailyForecastDialog.xaml.cs
+++ b/FluentWeather.Uwp/Controls/Dialogs/DailyForecastDialog.xaml.cs
@@ -98,12 +98,12 @@ private List GetHourly(ObservableCollection wea
private string GetTextFirst(List weatherList)
{
if (weatherList is null) return null;
- return weatherList.Count is 0 ? null : weatherList?.ConvertAll(p => (ITime)p).ToList().First().Time.ToShortTimeString();
+ return weatherList.Count is 0 ? null : weatherList?.First().Time.ToShortTimeString();
}
private string GetTextLast(List weatherList)
{
if (weatherList is null) return null;
- return weatherList.Count is 0 ? null : weatherList?.ConvertAll(p => (ITime)p).ToList().Last().Time.ToShortTimeString();
+ return weatherList.Count is 0 ? null : weatherList?.Last().Time.ToShortTimeString();
}
private void ForecastGridView_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
diff --git a/FluentWeather.Uwp/Controls/Dialogs/HistoricalWeatherSetupDialog.xaml b/FluentWeather.Uwp/Controls/Dialogs/HistoricalWeatherSetupDialog.xaml
new file mode 100644
index 0000000..4d54e52
--- /dev/null
+++ b/FluentWeather.Uwp/Controls/Dialogs/HistoricalWeatherSetupDialog.xaml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open-Meteo(ERA5 / ECMWF IFS)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FluentWeather.Uwp/Controls/Dialogs/HistoricalWeatherSetupDialog.xaml.cs b/FluentWeather.Uwp/Controls/Dialogs/HistoricalWeatherSetupDialog.xaml.cs
new file mode 100644
index 0000000..5a09004
--- /dev/null
+++ b/FluentWeather.Uwp/Controls/Dialogs/HistoricalWeatherSetupDialog.xaml.cs
@@ -0,0 +1,120 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using FluentWeather.Abstraction.Models;
+using FluentWeather.Uwp.Helpers;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Windows.ApplicationModel.Core;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.Storage;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板
+namespace FluentWeather.Uwp.Controls.Dialogs;
+
+[ObservableObject]
+public sealed partial class HistoricalWeatherSetupDialog : ContentDialog
+{
+
+
+ public Location Location
+ {
+ get => (Location)GetValue(LocationProperty);
+ set => SetValue(LocationProperty, value);
+ }
+
+ public static readonly DependencyProperty LocationProperty =
+ DependencyProperty.Register(nameof(LocationProperty), typeof(int), typeof(HistoricalWeatherSetupDialog), new PropertyMetadata(default));
+
+
+ public HistoricalWeatherSetupDialog(Location location)
+ {
+ this.InitializeComponent();
+ Location = location;
+ }
+
+ private async void GetHistoricalWeatherButton_Click(object sender, RoutedEventArgs e)
+ {
+ GetHistoricalWeatherButton.IsEnabled = false;
+ DownloadProgressBar.ShowError = false;
+ ProgressBarPanel.Visibility = Visibility.Visible;
+ WarningInfoBar.Visibility = Visibility.Collapsed;
+ DownloadProgressBar.Value = 0;
+ ProgressText.Text = "HistoricalWeatherSetupProgress_Downloading".GetLocalized();
+ try
+ {
+ await Task.Delay(500);
+
+ var data = await HistoricalWeatherHelper.DownloadHistoricalWeatherAsync(Location);
+
+ DownloadProgressBar.Value = 50;
+ ProgressText.Text = "HistoricalWeatherSetupProgress_Analysing".GetLocalized();
+ await Task.Delay(1000);
+
+ var result = await HistoricalWeatherHelper.AnalyseHistoricalWeatherAsync(data);
+ var folder = await ApplicationData.Current.LocalFolder.GetOrCreateFolderAsync("HistoricalWeather");
+ var folder1 = await folder.GetOrCreateFolderAsync(Location.GetHashCode().ToString());
+ var dic = new Dictionary>();
+ DownloadProgressBar.Value = 75;
+ ProgressText.Text = "HistoricalWeatherSetupProgress_Saving".GetLocalized();
+
+ foreach (var pair in result)
+ {
+ var month = pair.Key.AsSpan().Slice(0, 2).ToString();
+ var day = pair.Value.Date.Day.ToString();
+ if (!dic.ContainsKey(month))
+ {
+ dic[month] = [];
+ }
+
+ dic[month][day] = pair.Value;
+ }
+ foreach (var item in dic)
+ {
+ var file = await folder1.GetOrCreateFileAsync(item.Key);
+ using var stream = await file.OpenStreamForWriteAsync();
+ await JsonSerializer.SerializeAsync(stream, item.Value);
+ stream.Close();
+ }
+
+ await Task.Delay(500);
+ ProgressText.Text = "HistoricalWeatherSetupProgress_Done".GetLocalized();
+ GetHistoricalWeatherButton.Visibility = Visibility.Collapsed;
+ RestartButton.Visibility = Visibility.Visible;
+ }
+ catch (Exception ex)
+ {
+ DownloadProgressBar.ShowError = true;
+ ProgressText.Text = ex.Message;
+ throw;
+ }
+ finally
+ {
+ DownloadProgressBar.Value = 100;
+ GetHistoricalWeatherButton.IsEnabled = true;
+ }
+
+ }
+
+ private void HideButton_Click(object sender, RoutedEventArgs e)
+ {
+ Hide();
+ }
+
+ private async void RestartButton_Click(object sender, RoutedEventArgs e)
+ {
+ await CoreApplication.RequestRestartAsync(string.Empty);
+ }
+}
\ No newline at end of file
diff --git a/FluentWeather.Uwp/FluentWeather.Uwp.csproj b/FluentWeather.Uwp/FluentWeather.Uwp.csproj
index 1d92e9f..4d9f65f 100644
--- a/FluentWeather.Uwp/FluentWeather.Uwp.csproj
+++ b/FluentWeather.Uwp/FluentWeather.Uwp.csproj
@@ -157,6 +157,9 @@
ErrorDialog.xaml
+
+ HistoricalWeatherSetupDialog.xaml
+
LocationDialog.xaml
@@ -220,6 +223,7 @@
+
@@ -465,6 +469,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/FluentWeather.Uwp/Helpers/CacheHelper.cs b/FluentWeather.Uwp/Helpers/CacheHelper.cs
index e028aaa..097210b 100644
--- a/FluentWeather.Uwp/Helpers/CacheHelper.cs
+++ b/FluentWeather.Uwp/Helpers/CacheHelper.cs
@@ -106,6 +106,8 @@ public static async Task DeleteUnused()
[JsonSerializable(typeof(IndicesBase))]
[JsonSerializable(typeof(PrecipitationBase))]
[JsonSerializable(typeof(PrecipitationItemBase))]
+[JsonSerializable(typeof(HistoricalDailyWeatherBase))]
+[JsonSerializable(typeof(Dictionary))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}
\ No newline at end of file
diff --git a/FluentWeather.Uwp/Helpers/DIFactory.cs b/FluentWeather.Uwp/Helpers/DIFactory.cs
index 99ecce3..9f9a5a0 100644
--- a/FluentWeather.Uwp/Helpers/DIFactory.cs
+++ b/FluentWeather.Uwp/Helpers/DIFactory.cs
@@ -70,6 +70,7 @@ public static void RegisterOpenMeteo()
//ServiceDescriptors.AddSingleton(typeof(IWeatherWarningProvider), typeof(QWeatherProvider.QWeatherProvider));
//ServiceDescriptors.AddSingleton(typeof(IIndicesProvider), typeof(QWeatherProvider.QWeatherProvider));
ServiceDescriptors.AddSingleton(typeof(IPrecipitationProvider), typeof(OpenMeteoProvider.OpenMeteoProvider));
+ ServiceDescriptors.AddSingleton(typeof(IHistoricalWeatherProvider), typeof(OpenMeteoProvider.OpenMeteoProvider));
//ServiceDescriptors.AddSingleton(typeof(ITyphoonProvider), typeof(QWeatherProvider.QWeatherProvider));
ServiceDescriptors.AddSingleton(typeof(IGeolocationProvider), typeof(BingGeolocationProvider.BingGeolocationProvider));
OpenMeteoProvider.OpenMeteoProvider.Client.ForecastParameters.Add("forecast_hours", "168");
diff --git a/FluentWeather.Uwp/Helpers/Extensions.cs b/FluentWeather.Uwp/Helpers/Extensions.cs
index 30f7d9d..d62e210 100644
--- a/FluentWeather.Uwp/Helpers/Extensions.cs
+++ b/FluentWeather.Uwp/Helpers/Extensions.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
+using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.UI.Xaml;
@@ -41,4 +42,28 @@ public static async Task GetOrCreateFolderAsync(this StorageFolde
item ??= await folder.CreateFolderAsync(name);
return item;
}
+ public static TValue GetOrCreate(this IDictionary dict, TKey key)
+ {
+ if (!dict.TryGetValue(key, out TValue val))
+ {
+ val = default;
+ dict.Add(key, val);
+ }
+
+ return val;
+ }
+}
+internal static class ResourceExtensions
+{
+ private static readonly ResourceLoader ResLoader = ResourceLoader.GetForCurrentView();
+ private static readonly ResourceLoader IndependentResLoader = ResourceLoader.GetForViewIndependentUse();
+
+ public static string GetLocalized(this string resourceKey)
+ {
+ return ResLoader.GetString(resourceKey);
+ }
+ public static string GetLocalizedIndependent(this string resourceKey)
+ {
+ return IndependentResLoader.GetString(resourceKey);
+ }
}
\ No newline at end of file
diff --git a/FluentWeather.Uwp/Helpers/HistoricalWeatherHelper.cs b/FluentWeather.Uwp/Helpers/HistoricalWeatherHelper.cs
new file mode 100644
index 0000000..b8d5f65
--- /dev/null
+++ b/FluentWeather.Uwp/Helpers/HistoricalWeatherHelper.cs
@@ -0,0 +1,144 @@
+using FluentWeather.Abstraction.Interfaces.WeatherProvider;
+using FluentWeather.Abstraction.Models;
+using FluentWeather.DIContainer;
+using FluentWeather.OpenMeteoProvider;
+using Microsoft.Extensions.DependencyInjection;
+using OpenMeteoApi;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Windows.Storage;
+
+namespace FluentWeather.Uwp.Helpers;
+
+public class HistoricalWeatherHelper
+{
+ public static async Task> DownloadHistoricalWeatherAsync(Location location)
+ {
+ var folder = await ApplicationData.Current.LocalFolder.GetOrCreateFolderAsync("HistoricalWeather");
+ var folder1 = await folder.GetOrCreateFolderAsync(location.GetHashCode().ToString());
+ //if (await folder1.TryGetItemAsync("data") is not null)
+ //{
+ // var cache = await folder1.GetFileAsync("data");
+ // return await JsonSerializer.DeserializeAsync>(await cache.OpenStreamForReadAsync(), new JsonSerializerOptions { TypeInfoResolver = SourceGenerationContext.Default });
+ //}
+
+ var service = Locator.ServiceProvider.GetService();
+ service ??= new OpenMeteoProvider.OpenMeteoProvider();
+ var data = await service.GetHistoricalDailyWeather(location.Longitude, location.Latitude,DateTime.Parse("1940-01-01"), DateTime.Parse($"{DateTime.Now.Year}-01-01"));
+
+ //保存原始数据
+ var file =await folder1.GetOrCreateFileAsync("data");
+ using var stream = await file.OpenStreamForWriteAsync();
+ await JsonSerializer.SerializeAsync(stream, data, new JsonSerializerOptions { TypeInfoResolver = SourceGenerationContext.Default });
+ await stream.FlushAsync();
+
+ return data;
+ }
+
+ public static async Task> AnalyseHistoricalWeatherAsync(List dailyWeather)
+ {
+ return await Task.Run(() =>
+ {
+ var dic = new Dictionary>();
+ foreach (var item in dailyWeather)
+ {
+ var date = item.Time.ToString("MM-dd");
+ if (!dic.ContainsKey(date))
+ {
+ dic[date] = [];
+ }
+ dic[date].AddLast(item);
+ }
+ var result = new Dictionary();
+
+ foreach (var pair in dic)
+ {
+ var maxTemp = int.MinValue;
+ var maxTempDate = DateTime.MinValue;
+ var minTemp = int.MaxValue;
+ var minTempDate = DateTime.MinValue;
+
+ double? totalPrecip = 0.0;
+ double? maxPrecip = 0.0;
+ DateTime? maxPrecipDate = DateTime.MinValue;
+
+
+ var totalMaxTemp = 0;
+ var totalMinTemp = 0;
+ double? totalPrecipHours = 0.0;
+ var weatherCodeDic = new Dictionary();
+ var count = 0;
+ foreach (var item in pair.Value)
+ {
+ if (item.MaxTemperature >= maxTemp)
+ {
+ maxTemp = item.MaxTemperature;
+ maxTempDate = item.Time;
+ }
+ if (item.MinTemperature <= minTemp)
+ {
+ minTemp = item.MinTemperature;
+ minTempDate = item.Time;
+ }
+ if (item.Precipitation >= maxPrecip)
+ {
+ maxPrecip = item.Precipitation;
+ maxPrecipDate = item.Time;
+ }
+ totalMaxTemp += item.MaxTemperature;
+ totalMinTemp += item.MinTemperature;
+ totalPrecipHours += item.PrecipitationHours;
+ totalPrecip += item.Precipitation;
+ weatherCodeDic[item.WeatherType] = weatherCodeDic.GetOrCreate(item.WeatherType) + 1;
+ count++;
+ }
+ var historicalWeather = new HistoricalDailyWeatherBase
+ {
+ Date = pair.Value.First.Value.Time.Date,
+ AverageMaxTemperature = totalMaxTemp / count,
+ AverageMinTemperature = totalMinTemp / count,
+ MaxPrecipitation = maxPrecip,
+ MaxPrecipitationDate = maxPrecipDate,
+ AveragePrecipitation = totalPrecip / count,
+ AveragePrecipitationHours = totalPrecipHours / count,
+ HistoricalMaxTemperature = maxTemp,
+ HistoricalMaxTemperatureDate = maxTempDate,
+ HistoricalMinTemperature = minTemp,
+ HistoricalMinTemperatureDate = minTempDate,
+ Weather = weatherCodeDic.Max(p => p).Key
+ };
+ result[pair.Key] = historicalWeather;
+ }
+
+ return result;
+ });
+ }
+
+
+ public static void SaveHistoricalWeather(IList weatherList)
+ {
+
+ }
+
+ public static void ClearHistoricalWeather()
+ {
+
+ }
+ public static async Task GetHistoricalWeatherAsync(Location location,DateTime date)
+ {
+ var folder = await ApplicationData.Current.LocalFolder.GetOrCreateFolderAsync("HistoricalWeather");
+ var folderItem = await folder.TryGetItemAsync(location.GetHashCode().ToString());
+ if (folderItem == null) return null;
+ var folder1 = (StorageFolder)folderItem;
+ var id = date.Month.ToString().PadLeft(2, '0');
+ var file = await folder1.GetFileAsync(id);
+ using var stream = await file.OpenStreamForReadAsync();
+ var dic = JsonSerializer.Deserialize>(stream, new JsonSerializerOptions { TypeInfoResolver = SourceGenerationContext.Default });
+ return dic[date.Day.ToString()];
+
+ }
+}
\ No newline at end of file
diff --git a/FluentWeather.Uwp/Pages/CitiesPage.xaml b/FluentWeather.Uwp/Pages/CitiesPage.xaml
index b7bfb60..18d9c91 100644
--- a/FluentWeather.Uwp/Pages/CitiesPage.xaml
+++ b/FluentWeather.Uwp/Pages/CitiesPage.xaml
@@ -47,7 +47,17 @@
x:Name="CurrentCityView"
Grid.Row="1"
Margin="{ThemeResource CityViewMargin}">
-
+
+
+
+
+
+
+
@@ -178,6 +179,7 @@
+
+ Text="{x:Bind converters1:ConverterMethods.ConvertTemperatureUnit(ViewModel.WeatherNow.Temperature, x:False)}">
@@ -214,13 +216,13 @@
FontSize="18"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}">
-
+