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 .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 9.0.x

- name: Restore dependencies
run: dotnet restore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.47.0" />
<PackageReference Include="Spectre.Console" Version="0.50.0" />
</ItemGroup>

<ItemGroup>
Expand Down
116 changes: 56 additions & 60 deletions samples/OpenWeatherMapSharp.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,92 +3,88 @@
using OpenWeatherMapSharp.Models.Enums;
using Spectre.Console;

// Your OpenWeatherMap API key (replace with your actual one)
string openWeatherMapApiKey = "OWMAPIKEY";

// HEADER
// == HEADER ==
Grid headerGrid = new();
headerGrid.AddColumn();
headerGrid.AddRow(new FigletText("OpenWeatherMap").Centered().Color(Color.Red));
AnsiConsole.Write(headerGrid);

// ASK FOR CITY NAME
// == ASK FOR CITY ==
AnsiConsole.WriteLine();
string cityName = AnsiConsole.Ask<string>("[white]Insert the name of the[/] [red]city[/][white]?[/]");
AnsiConsole.WriteLine();

// GET WEATHER
// == INIT SERVICE ==
OpenWeatherMapService openWeatherMapService = new(openWeatherMapApiKey);
var geolocationResponse = await openWeatherMapService.GetLocationByNameAsync(cityName);

if (!geolocationResponse.IsSuccess)
// == GEOCODE ==
OpenWeatherMapServiceResponse<List<GeocodeInfo>> geolocationResponse
= await openWeatherMapService.GetLocationByNameAsync(cityName);

if (!geolocationResponse.IsSuccess || geolocationResponse.Response?.FirstOrDefault() is not GeocodeInfo geolocation)
{
AnsiConsole.Write("Unfortunately I can't recognize the city. Please try again.");
Console.WriteLine();
AnsiConsole.MarkupLine("[bold red]Unfortunately I can't recognize the city. Please try again.[/]");
return;
}

var geolocations = geolocationResponse.Response;
var geolocation = geolocations.FirstOrDefault();
// == WEATHER ==
OpenWeatherMapServiceResponse<WeatherRoot> weatherResponse
= await openWeatherMapService.GetWeatherAsync(
geolocation.Latitude,
geolocation.Longitude,
unit: Unit.Metric);

if (geolocation is null)
if (!weatherResponse.IsSuccess || weatherResponse.Response is not WeatherRoot weatherRoot)
{
AnsiConsole.Write("Unfortunately I can't recognize the city. Please try again.");
Console.WriteLine();
AnsiConsole.MarkupLine("[bold red]Unfortunately I can't retrieve weather data. Please try again.[/]");
return;
}

OpenWeatherMapServiceResponse<WeatherRoot> weatherResponse = await openWeatherMapService.GetWeatherAsync(geolocation.Latitude, geolocation.Longitude, unit: Unit.Metric);
Main mainWeather = weatherRoot.MainWeather;

if (weatherResponse.IsSuccess)
// == LOCATION PANEL ==
Panel locationPanel = new(new Rows(new List<Markup>
{
new($"[red]City: [/]{weatherRoot.Name}"),
new($"[red]Latitude: [/]{weatherRoot.Coordinates.Latitude:0.0000}"),
new($"[red]Longitude: [/]{weatherRoot.Coordinates.Longitude:0.0000}"),
new($"[red]Country: [/]{geolocation.Country}"),
new($"[red]State: [/]{geolocation.State ?? "[not available]"}")
}))
{
WeatherRoot weatherRoot = weatherResponse.Response;
Main mainWeather = weatherRoot.MainWeather;
Header = new PanelHeader("Location"),
Width = 120
};
AnsiConsole.Write(locationPanel);

// LOCATION
List<Markup> locationMarkupList = new()
{
new Markup($"[red]City: [/]{weatherRoot.Name}"),
new Markup($"[red]Latitude: [/]{weatherRoot.Coordinates.Latitude:0.0000}"),
new Markup($"[red]Longitude: [/]{weatherRoot.Coordinates.Longitude:0.0000}"),
new Markup($"[red]Country: [/]{geolocation.Country}"),
new Markup($"[red]State: [/]{geolocation.State}")
};
Rows locationRows = new(locationMarkupList);
Panel locationPanel = new(locationRows)
{
Header = new PanelHeader("Location"),
Width = 120
};
AnsiConsole.Write(locationPanel);
// == WEATHER PANEL ==
List<Markup> weatherMarkupList =
[
new($"[red]Temperature: [/]{mainWeather.Temperature}° C"),
new($"[red]Feels Like: [/]{mainWeather.FeelsLikeTemperature}° C"),
new($"[red]Min Temperature: [/]{mainWeather.MinTemperature}° C"),
new($"[red]Max Temperature: [/]{mainWeather.MaxTemperature}° C"),
new("-----"),
new($"[red]Pressure (Sea Level): [/]{mainWeather.Pressure} hPa"),
new($"[red]Humidity: [/]{mainWeather.Humidity} %"),
new($"[red]Sunrise: [/]{weatherRoot.System.Sunrise:g}"),
new($"[red]Sunset: [/]{weatherRoot.System.Sunset:g}")
];

// WEATHER
List<Markup> weatherMarkupList = new()
{
new Markup($"[red]Temperature: [/]{mainWeather.Temperature}° C"),
new Markup($"[red]Temperature (Feels Like): [/]{mainWeather.FeelsLikeTemperature}° C"),
new Markup($"[red]Minimal Temperature: [/]{mainWeather.MinTemperature}° C"),
new Markup($"[red]Maximal Temperature: [/]{mainWeather.MaxTemperature}° C"),
new Markup("-----"),
new Markup($"[red]Pressure Sea Level hPa: [/]{mainWeather.Pressure} hPa"),
new Markup($"[red]Humidity: [/]{mainWeather.Humidity} %"),
new Markup($"[red]Sunrise: [/]{weatherRoot.System.Sunrise:g}"),
new Markup($"[red]Sunset: [/]{weatherRoot.System.Sunset:g}")
};
foreach (WeatherInfo weatherInfo in weatherRoot.WeatherInfos)
{
weatherMarkupList.Add(new Markup($"[red]Current Conditions: [/]{weatherInfo.Description}"));
}
Rows currentWeatherRows = new(weatherMarkupList);
Panel currentWeatherPanel = new(currentWeatherRows)
{
Header = new PanelHeader("Current Weather"),
Width = 120
};
AnsiConsole.Write(currentWeatherPanel);
}
else
// Add weather descriptions
foreach (WeatherInfo? weatherInfo in weatherRoot.WeatherInfos)
{
AnsiConsole.Write("Unfortunately I can't recognize the city. Please try again.");
weatherMarkupList.Add(new($"[red]Conditions: [/]{weatherInfo.Description}"));
}

Console.ReadLine();
Panel weatherPanel = new(new Rows(weatherMarkupList))
{
Header = new PanelHeader("Current Weather"),
Width = 120
};
AnsiConsole.Write(weatherPanel);

Console.ReadLine();
102 changes: 51 additions & 51 deletions src/OpenWeatherMapSharp/IOpenWeatherMapService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,119 +7,119 @@
namespace OpenWeatherMapSharp
{
/// <summary>
/// This interface defines the methods to communicate with the Open Weather Map API
/// Defines the contract for communicating with the OpenWeatherMap API.
/// </summary>
public interface IOpenWeatherMapService
{
/// <summary>
/// Gets forecast for a location given its longitude and latitude
/// Gets forecast data for a location based
/// on its geographic coordinates.
/// </summary>
/// <param name="latitude">The latitude of the location</param>
/// <param name="longitude">The longitude of the location</param>
/// <param name="language">The language used for the response</param>
/// <param name="unit">The unit of measurement for the response</param>
/// <returns>The OpenWeatherMapServiceResponse containing the forecast information</returns>
/// <param name="latitude">Latitude of the location.</param>
/// <param name="longitude">Longitude of the location.</param>
/// <param name="language">Language of the response (default: English).</param>
/// <param name="unit">Unit of measurement (default: Standard).</param>
/// <returns>A forecast response wrapped in <see cref="OpenWeatherMapServiceResponse{T}"/>.</returns>
Task<OpenWeatherMapServiceResponse<ForecastRoot>> GetForecastAsync(
double latitude,
double longitude,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);

/// <summary>
/// Gets forecast for a location given its city ID
/// Gets forecast data based on a city ID.
/// </summary>
/// <param name="cityId">The ID of the location's city</param>
/// <param name="language">The language used for the response</param>
/// <param name="unit">The unit of measurement for the response</param>
/// <returns>The OpenWeatherMapServiceResponse containing the forecast information</returns>
[Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
/// <param name="cityId">The city ID.</param>
/// <param name="language">Language of the response.</param>
/// <param name="unit">Unit of measurement.</param>
/// <returns>A forecast response wrapped in <see cref="OpenWeatherMapServiceResponse{T}"/>.</returns>
[Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task<OpenWeatherMapServiceResponse<ForecastRoot>> GetForecastAsync(
int cityId,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);

/// <summary>
/// Gets forecast for a location given its city name
/// Gets forecast data based on a city name.
/// </summary>
/// <param name="city">The name of the location's city</param>
/// <param name="language">The language used for the response</param>
/// <param name="unit">The unit of measurement for the response</param>
/// <returns>The OpenWeatherMapServiceResponse containing the forecast information</returns>
[Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
/// <param name="city">The city name.</param>
/// <param name="language">Language of the response.</param>
/// <param name="unit">Unit of measurement.</param>
/// <returns>A forecast response wrapped in <see cref="OpenWeatherMapServiceResponse{T}"/>.</returns>
[Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task<OpenWeatherMapServiceResponse<ForecastRoot>> GetForecastAsync(
string city,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);

/// <summary>
/// Gets weather information for a location given its longitude and latitude
/// Gets current weather data for a location based on its geographic coordinates.
/// </summary>
/// <param name="latitude">The latitude of the location</param>
/// <param name="longitude">The longitude of the location</param>
/// <param name="language">The language used for the response</param>
/// <param name="unit">The unit of measurement for the response</param>
/// <returns>The OpenWeatherMapServiceResponse containing the weather information</returns>
/// <param name="latitude">Latitude of the location.</param>
/// <param name="longitude">Longitude of the location.</param>
/// <param name="language">Language of the response (default: English).</param>
/// <param name="unit">Unit of measurement (default: Standard).</param>
/// <returns>A weather response wrapped in <see cref="OpenWeatherMapServiceResponse{T}"/>.</returns>
Task<OpenWeatherMapServiceResponse<WeatherRoot>> GetWeatherAsync(
double latitude,
double longitude,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);

/// <summary>
/// Gets weather information for a location given its city ID
/// Gets current weather data based on a city ID.
/// </summary>
/// <param name="cityId">The ID of the location's city</param>
/// <param name="language">The language used for the response</param>
/// <param name="unit">The unit of measurement for the response</param>
/// <returns>The OpenWeatherMapServiceResponse containing the weather information</returns>
[Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
/// <param name="cityId">The city ID.</param>
/// <param name="language">Language of the response.</param>
/// <param name="unit">Unit of measurement.</param>
/// <returns>A weather response wrapped in <see cref="OpenWeatherMapServiceResponse{T}"/>.</returns>
[Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task<OpenWeatherMapServiceResponse<WeatherRoot>> GetWeatherAsync(
int cityId,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);

/// <summary>
/// Gets weather information for a location given its city name
/// Gets current weather data based on a city name.
/// </summary>
/// <param name="city">The name of the location's city</param>
/// <param name="language">The language used for the response</param>
/// <param name="unit">The unit of measurement for the response</param>
/// <returns>The OpenWeatherMapServiceResponse containing the weather information</returns>
[Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
/// <param name="city">The city name.</param>
/// <param name="language">Language of the response.</param>
/// <param name="unit">Unit of measurement.</param>
/// <returns>A weather response wrapped in <see cref="OpenWeatherMapServiceResponse{T}"/>.</returns>
[Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task<OpenWeatherMapServiceResponse<WeatherRoot>> GetWeatherAsync(
string city,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);


/// <summary>
/// Gets a list of locations given a query string
/// Gets a list of matching locations for a given query string.
/// </summary>
/// <param name="query">The query string to search for</param>
/// <param name="limit">The maximum number of locations to return</param>
/// <returns>The OpenWeatherMapServiceResponse containing the list of relevant locations</returns>
/// <param name="query">The location name or part of it to search for.</param>
/// <param name="limit">The maximum number of results to return (default: 5).</param>
/// <returns>A response with a list of matching <see cref="GeocodeInfo"/> objects.</returns>
Task<OpenWeatherMapServiceResponse<List<GeocodeInfo>>> GetLocationByNameAsync(
string query,
int limit = 5);

/// <summary>
/// Gets location information for a given zip code
/// Gets geolocation information based on a ZIP or postal code.
/// </summary>
/// <param name="zipCode">The zip code to search for</param>
/// <returns>The OpenWeatherMapServiceResponse containing the location information</returns>
/// <param name="zipCode">The ZIP/postal code to search for.</param>
/// <returns>A response containing a <see cref="GeocodeZipInfo"/> object.</returns>
Task<OpenWeatherMapServiceResponse<GeocodeZipInfo>> GetLocationByZipAsync(
string zipCode);

/// <summary>
/// Gets location information for a given latitude and longitude
/// Gets a list of matching locations for a given pair of coordinates.
/// </summary>
/// <param name="latitude">The latitude of the location</param>
/// <param name="longitude">The longitude of the location</param>
/// <param name="limit">The maximum number of locations to return</param>
/// <returns>The OpenWeatherMapServiceResponse containing the location information</returns>
/// <param name="latitude">Latitude of the location.</param>
/// <param name="longitude">Longitude of the location.</param>
/// <param name="limit">The maximum number of results to return (default: 5).</param>
/// <returns>A response with a list of <see cref="GeocodeInfo"/> objects.</returns>
Task<OpenWeatherMapServiceResponse<List<GeocodeInfo>>> GetLocationByLatLonAsync(
double latitude,
double longitude,
int limit = 5);
}
}
}
Loading