Skip to content

Commit

Permalink
💥 forecast as option (#38)
Browse files Browse the repository at this point in the history
improves accessibility, but reduces further extensibility of the forecast sub-command. Considering the rather small end product this app aims to be, this is a fair trade.

The change can be seen as a breaking change as the weather forecast is now accessed without flags e.g.,: `-f w` | `-f d` | `-f w,d`

instead of e.g., `-f -w`,`-f` solely.
  • Loading branch information
ttytm committed Nov 13, 2022
1 parent 4469cc6 commit 6cf0ab1
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 169 deletions.
5 changes: 3 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;
use clap::Parser;

use modules::config::Config;
use modules::*;
use modules::{args::Cli, display::Product, location::Geolocation, params::Params, weather::Weather};

Expand All @@ -9,8 +10,8 @@ mod modules;
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
let config = confy::load("weathercrab", "wthrr")?;
let params = Params::get(&args, &config).await?;
let config: Config = confy::load("weathercrab", "wthrr")?;
let params = Params::get(&args, config.clone()).await?;

let product = run(&params).await?;
product
Expand Down
60 changes: 35 additions & 25 deletions src/modules/args.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,61 @@
use clap::{Args, Parser, Subcommand, ValueEnum};
// use clap::{Args, Parser, Subcommand, ValueEnum};
use clap::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};
use strum_macros::AsRefStr;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(author, version, about, long_about = None, next_line_help = true)]
pub struct Cli {
/// Address to check the weather for
pub address: Option<String>,

#[command(subcommand)]
pub commands: Option<Commands>,
/// [e.g.: -f w,d]
#[arg(long, short, use_value_delimiter = true, value_name = "FORECAST,...")]
pub forecast: Vec<Forecast>,

/// Units for temperature and/or speed
#[arg(long, short, next_line_help = false, use_value_delimiter = true)]
/// [e.g.: -u f,12h]
#[arg(long, short, use_value_delimiter = true, value_name = "UNIT,...")]
pub units: Vec<ArgUnits>,

/// Output language
/// Output language [e.g.: en_US]
#[arg(short, long, global = true)]
pub language: Option<String>,

/// Toggle greeting message
#[arg(short, long, action, global = true)]
#[arg(short, long, action, hide = true)]
pub greeting: bool,

/// Save the supplied values as default
#[arg(short, long, action, group = "config_file_action", global = true)]
#[arg(short, long, action, group = "config_file_action")]
pub save: bool,

/// Wipe wthrr's configuration data
#[arg(short, long, action, group = "config_file_action", global = true)]
#[arg(short, long, action, group = "config_file_action")]
pub reset: bool,
}

#[derive(Subcommand)]
pub enum Commands {
/// Include the weather forecast
#[clap(short_flag = 'f')]
Forecast(Forecast),
}

#[derive(Debug, Args)]
pub struct Forecast {
/// Show the seven day forecast
#[arg(short, value_parser, action)]
pub week: bool,
/// Show the forecast for the day
#[arg(short, value_parser, action)]
pub day: bool,
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, AsRefStr, Serialize, Deserialize)]
#[allow(non_camel_case_types)]
pub enum Forecast {
disable,
#[value(name = "(w)eek", aliases = ["w", "week"])]
week,
#[value(name = "(d)ay", aliases = ["d", "day", "today"])]
day,
// #[value(alias = "monday")]
// mo,
// #[value(alias = "tuesday")]
// tu,
// #[value(alias = "wednesday")]
// we,
// #[value(alias = "thursday")]
// th,
// #[value(alias = "friday")]
// fr,
// #[value(alias = "saturday")]
// sa,
// #[value(alias = "sunday")]
// su,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, AsRefStr, Serialize, Deserialize)]
Expand All @@ -70,5 +79,6 @@ pub enum ArgUnits {
#[value(name = "24h", alias = "military")]
Military,
Mm,
#[value(name = "(in)ch", alias = "in")]
Inch,
}
16 changes: 10 additions & 6 deletions src/modules/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ use dialoguer::{theme::ColorfulTheme, Confirm, Select};
use serde::{Deserialize, Serialize};

use crate::{
args::Cli,
params::{forecast::Forecast, units::Units, Params},
args::{Cli, Forecast},
params::{units::Units, Params},
translation::translate,
};

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct Config {
pub address: Option<String>,
pub greeting: Option<bool>,
pub language: Option<String>,
pub forecast: Option<Vec<Forecast>>,
pub units: Option<Units>,
pub forecast: Option<Forecast>,
}

impl Default for Config {
fn default() -> Self {
Self {
address: None,
forecast: None,
greeting: Some(true),
language: Some("en".to_string()),
forecast: Some(Forecast::default()),
units: Some(Units::default()),
}
}
Expand All @@ -43,7 +43,11 @@ impl Config {
},
greeting: Some(params.greeting),
language: Some(params.language),
forecast: Some(params.forecast),
forecast: if !params.forecast.is_empty() {
Some(params.forecast)
} else {
None
},
units: Some(params.units),
};

Expand Down
9 changes: 3 additions & 6 deletions src/modules/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use term_painter::{
ToStyle,
};

use crate::{
params::{forecast::Forecast as ForecastParams, units::Units},
weather::Weather,
};
use crate::{args::Forecast as ForecastParams, params::units::Units, weather::Weather};

use self::{current::Current, forecast::Forecast};

Expand All @@ -31,14 +28,14 @@ pub const MIN_WIDTH: usize = 34;
impl Product {
pub async fn render(
&self,
forecast: &ForecastParams,
forecast: &[ForecastParams],
units: &Units,
include_greeting: bool,
lang: &str,
) -> Result<()> {
greeting::render(include_greeting, lang).await?;

if forecast.week.unwrap_or_default() || forecast.day.unwrap_or_default() {
if !forecast.is_empty() {
Forecast::render(self, forecast, units, lang).await?;
} else {
Current::render(self, false, units, lang).await?;
Expand Down
52 changes: 25 additions & 27 deletions src/modules/display/forecast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use chrono::prelude::*;
use serde::{Deserialize, Serialize};
use term_painter::{Color::*, ToStyle};

use crate::params::{forecast::Forecast as ForecastParams, units::Units};
use crate::{args::Forecast as ForecastParams, params::units::Units};

use super::{
border::{Border, Separator},
Expand All @@ -28,40 +28,38 @@ pub struct ForecastDay {
}

impl Forecast {
pub async fn render(product: &Product, forecast_args: &ForecastParams, units: &Units, lang: &str) -> Result<()> {
pub async fn render(product: &Product, forecast_args: &[ForecastParams], units: &Units, lang: &str) -> Result<()> {
let forecast = Self::prepare(product, lang).await?;
let mut width = forecast.width + 10;
let mut cell_width = MIN_WIDTH / 2;

match forecast_args {
// Only display daily forecast
ForecastParams {
day: Some(true),
week: Some(false),
} => {
Current::render(product, true, units, lang).await?;
let (mut include_day, mut include_week) = (false, false);
for val in forecast_args {
if ForecastParams::disable == *val {
Current::render(product, false, units, lang).await?;
return Ok(());
}
// Display both forecasts if no or both forecast subcommand flags are added
ForecastParams {
day: Some(false),
week: Some(false),
if ForecastParams::day == *val {
include_day = true;
}
| ForecastParams {
day: Some(true),
week: Some(true),
} => {
// Align dimensions of daily and weekly forecast
let dimensions_current = Current::render(product, true, units, lang).await?;

if dimensions_current.cell_width > cell_width {
cell_width = dimensions_current.cell_width
}
if dimensions_current.width > width {
width = dimensions_current.width
}
if ForecastParams::week == *val {
include_week = true;
}
_ => {}
}

if include_day {
let dimensions_current = Current::render(product, true, units, lang).await?;

if dimensions_current.cell_width > cell_width {
cell_width = dimensions_current.cell_width
}
if dimensions_current.width > width {
width = dimensions_current.width
}
}

if !include_week {
return Ok(());
}

// Border Top
Expand Down
24 changes: 8 additions & 16 deletions src/modules/params.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use anyhow::Result;

use crate::{args::Cli, config::Config};
use crate::{
args::{Cli, Forecast},
config::Config,
};

use self::{forecast::Forecast, units::Units};

use super::args::Commands;
use self::units::Units;

mod address;
pub mod forecast;
Expand All @@ -17,26 +18,17 @@ pub struct Params {
pub units: Units,
pub greeting: bool,
pub language: String,
pub forecast: Forecast,
pub forecast: Vec<Forecast>,
}

impl Params {
pub async fn get(args: &Cli, config: &Config) -> Result<Self> {
pub async fn get(args: &Cli, config: Config) -> Result<Self> {
let language = language::get(
args.language.as_deref().unwrap_or_default(),
config.language.as_deref().unwrap_or_default(),
)?;

let forecast = forecast::get(
match &args.commands {
Some(Commands::Forecast(args_forecast)) => Some(Forecast {
day: Some(args_forecast.day),
week: Some(args_forecast.week),
}),
_ => None,
},
config.forecast,
)?;
let forecast = forecast::get(&args.forecast, config.forecast)?;

if args.reset {
Config::reset(&language).await?;
Expand Down
Loading

0 comments on commit 6cf0ab1

Please sign in to comment.