Skip to content

Commit

Permalink
✨ extend configurable units (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
ttytm committed Nov 13, 2022
1 parent 602e1ae commit 4469cc6
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 45 deletions.
7 changes: 7 additions & 0 deletions src/modules/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ pub enum ArgUnits {
Kmh,
Mph,
#[value(name = "(kn)ots", aliases = ["kn", "knots"])]
// serialize as kn for open-meteo api call
#[strum(serialize = "kn")]
Knots,
Ms,
#[value(name = "12h", alias = "am_pm")]
AmPm,
#[value(name = "24h", alias = "military")]
Military,
Mm,
Inch,
}
20 changes: 14 additions & 6 deletions src/modules/display/current.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use term_painter::{Attr::Bold, Color::BrightBlack, ToStyle};

use crate::{params::units::Units, translation::translate};
use crate::{params::units::Time, params::units::Units, translation::translate};

use super::{
border::{Border, Separator},
Expand Down Expand Up @@ -47,7 +47,7 @@ impl Current {
wmo_code,
hourly_forecast,
dimensions,
} = Self::prepare(product, add_hourly, lang).await?;
} = Self::prepare(product, add_hourly, lang, units).await?;

let Dimensions { width, cell_width } = dimensions;

Expand Down Expand Up @@ -132,19 +132,27 @@ impl Current {
Ok(dimensions)
}

async fn prepare(product: &Product, add_hourly: bool, lang: &str) -> Result<Self> {
async fn prepare(product: &Product, add_hourly: bool, lang: &str, units: &Units) -> Result<Self> {
let weather = &product.weather;
let address = Product::trunc_address(product.address.clone(), 60)?;

let (sunrise_time, sunset_time) = (&weather.daily.sunrise[0][11..16], &weather.daily.sunset[0][11..16]);
let (current_hour, sunrise_hour, sunset_hour) = (
weather.current_weather.time[11..13]
.parse::<usize>()
.unwrap_or_default(),
sunrise_time[..2].parse().unwrap_or_default(),
sunset_time[..2].parse().unwrap_or_default(),
weather.daily.sunrise[0][11..13].parse::<usize>().unwrap_or_default(),
weather.daily.sunset[0][11..13].parse::<usize>().unwrap_or_default(),
);
let sunrise_time = match units.time {
Some(Time::am_pm) => format!("{}:{}am", sunrise_hour, &weather.daily.sunrise[0][14..16]),
_ => weather.daily.sunrise[0][11..16].to_string(),
};
let sunset_time = match units.time {
Some(Time::am_pm) => format!("{}:{}pm", sunset_hour / 2, &weather.daily.sunset[0][14..16]),
_ => weather.daily.sunset[0][11..16].to_string(),
};
let night = current_hour < sunrise_hour || current_hour > sunset_hour;

let wmo_code = WeatherCode::resolve(&weather.current_weather.weathercode, Some(night), lang).await?;

let temperature = format!(
Expand Down
25 changes: 19 additions & 6 deletions src/modules/display/hourly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use term_painter::{
};

use crate::{
params::units::{Temperature, Units},
params::units::{Precipitation, Temperature, Time, Units},
weather::Weather,
};

Expand All @@ -29,11 +29,13 @@ impl HourlyForecast {
BrightBlack.with(|| println!("{}", Separator::Blank.fmt(width)));

let temperature_unit = match units.temperature {
Some(Temperature::celsius) => "糖",
Some(Temperature::fahrenheit) => "宅",
_ => " ",
_ => "糖",
};
let precipitation_unit = match units.precipitation {
Some(Precipitation::inch) => "ⁱⁿ",
_ => "ₘₘ",
};
let precipitation_unit = "ₘₘ".to_string();

println!(
"{} {: <width$} {}",
Expand Down Expand Up @@ -75,8 +77,19 @@ impl HourlyForecast {
BrightBlack.with(|| println!("{}", Separator::Dotted.fmt(width)));
});

// let hours = [ "¹²·⁰⁰ₐₘ", "³·⁰⁰ₐₘ", "⁶˙⁰⁰ₐₘ", "⁹˙⁰⁰ₐₘ", "¹²˙⁰⁰ₚₘ", "³˙⁰⁰ₚₘ", "⁶˙⁰⁰ₚₘ", "⁹˙⁰⁰ₚₘ", ];
let hours = ["⁰⁰˙⁰⁰", "⁰³˙⁰⁰", "⁰⁶˙⁰⁰", "⁰⁹˙⁰⁰", "¹²˙⁰⁰", "¹⁵˙⁰⁰", "¹⁸˙⁰⁰", "²¹˙⁰⁰"];
let hours = match units.time {
Some(Time::am_pm) => [
"¹²·⁰⁰ₐₘ",
"³·⁰⁰ₐₘ",
"⁶˙⁰⁰ₐₘ",
"⁹˙⁰⁰ₐₘ",
"¹²˙⁰⁰ₚₘ",
"³˙⁰⁰ₚₘ",
"⁶˙⁰⁰ₚₘ",
"⁹˙⁰⁰ₚₘ",
],
_ => ["⁰⁰˙⁰⁰", "⁰³˙⁰⁰", "⁰⁶˙⁰⁰", "⁰⁹˙⁰⁰", "¹²˙⁰⁰", "¹⁵˙⁰⁰", "¹⁸˙⁰⁰", "²¹˙⁰⁰"],
};
print!("{}", BrightBlack.paint(Border::L),);
for hour in hours {
print!("{: <9}", hour)
Expand Down
105 changes: 72 additions & 33 deletions src/modules/params/units.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,90 @@ use crate::args::ArgUnits;
pub struct Units {
pub temperature: Option<Temperature>,
pub speed: Option<Speed>,
pub time: Option<Time>,
pub precipitation: Option<Precipitation>,
}

impl Default for Units {
fn default() -> Self {
Self {
temperature: Some(Temperature::celsius),
speed: Some(Speed::kmh),
temperature: Some(Temperature::default()),
speed: Some(Speed::default()),
time: Some(Time::default()),
precipitation: Some(Precipitation::default()),
}
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumVariantNames, EnumString)]
#[derive(
Default, Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumVariantNames, EnumString,
)]
#[allow(non_camel_case_types)]
pub enum Temperature {
#[default]
celsius,
fahrenheit,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumVariantNames, EnumString)]
#[derive(
Default, Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumVariantNames, EnumString,
)]
#[allow(non_camel_case_types)]
pub enum Speed {
#[default]
kmh,
mph,
knots,
ms,
}

pub fn get(arg_units: &[ArgUnits], config_units: &Units) -> Result<Units> {
let mut units = assign_arg_units(arg_units)?;
#[derive(
Default, Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumVariantNames, EnumString,
)]
#[allow(non_camel_case_types)]
pub enum Time {
am_pm,
#[default]
military,
}

if units.temperature == None && config_units.temperature.is_some() {
units.temperature = config_units.temperature
} else if units.temperature == None && config_units.temperature.is_none() {
units.temperature = Units::default().temperature
}
#[derive(
Default, Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumVariantNames, EnumString,
)]
#[allow(non_camel_case_types)]
pub enum Precipitation {
#[default]
mm,
inch,
}

if units.speed.is_none() && config_units.speed.is_some() {
units.speed = config_units.speed
} else if units.speed.is_none() && config_units.speed.is_none() {
units.speed = Units::default().speed
}
pub fn get(arg_units: &[ArgUnits], cfg_units: &Units) -> Result<Units> {
let mut units = assign_arg_units(arg_units)?;

units.temperature = evaluate_unit(units.temperature, cfg_units.temperature, Temperature::default());
units.speed = evaluate_unit(units.speed, cfg_units.speed, Speed::default());
units.time = evaluate_unit(units.time, cfg_units.time, Time::default());
units.precipitation = evaluate_unit(units.precipitation, cfg_units.precipitation, Precipitation::default());

Ok(units)
}

fn evaluate_unit<T>(arg_unit: Option<T>, cfg_unit: Option<T>, fallback_unit: T) -> Option<T> {
match arg_unit {
Some(unit) => Some(unit), // Some(u) => Some(u + 1),
None => match cfg_unit {
Some(unit) => Some(unit), // Some(u) => Some(u + 1),
_ => Some(fallback_unit),
},
}
}

pub fn assign_arg_units(arg_units: &[ArgUnits]) -> Result<Units> {
let mut units = Units {
temperature: None,
speed: None,
time: None,
precipitation: None,
};

for val in arg_units {
Expand All @@ -68,6 +103,12 @@ pub fn assign_arg_units(arg_units: &[ArgUnits]) -> Result<Units> {
if Speed::VARIANTS.as_ref().contains(&val.as_ref()) {
units.speed = Some(Speed::from_str(val.as_ref()).unwrap())
}
if Time::VARIANTS.as_ref().contains(&val.as_ref()) {
units.time = Some(Time::from_str(val.as_ref()).unwrap())
}
if Precipitation::VARIANTS.as_ref().contains(&val.as_ref()) {
units.precipitation = Some(Precipitation::from_str(val.as_ref()).unwrap())
}
}

Ok(units)
Expand All @@ -79,17 +120,21 @@ mod tests {

#[test]
fn units_from_args() -> Result<()> {
let arg_units = [ArgUnits::Fahrenheit, ArgUnits::Mph];
let arg_units = [ArgUnits::Fahrenheit, ArgUnits::Mph, ArgUnits::AmPm, ArgUnits::Inch];
let cfg_units = Units {
temperature: Some(Temperature::celsius),
speed: Some(Speed::kmh),
time: Some(Time::military),
precipitation: Some(Precipitation::mm),
};

assert_eq!(
get(&arg_units, &cfg_units)?,
Units {
temperature: Some(Temperature::fahrenheit),
speed: Some(Speed::mph),
time: Some(Time::am_pm),
precipitation: Some(Precipitation::inch),
}
);

Expand All @@ -102,32 +147,32 @@ mod tests {
let cfg_units = Units {
temperature: Some(Temperature::fahrenheit),
speed: Some(Speed::knots),
time: Some(Time::am_pm),
precipitation: Some(Precipitation::inch),
};

assert_eq!(
get(&arg_units, &cfg_units)?,
Units {
temperature: Some(Temperature::fahrenheit),
speed: Some(Speed::knots),
}
);
assert_eq!(get(&arg_units, &cfg_units)?, cfg_units);

Ok(())
}

#[test]
fn units_split_from_args_cfg() -> Result<()> {
let arg_units = [ArgUnits::Fahrenheit];
let arg_units = [ArgUnits::Fahrenheit, ArgUnits::AmPm];
let cfg_units = Units {
temperature: Some(Temperature::celsius),
speed: Some(Speed::ms),
time: None,
precipitation: Some(Precipitation::inch),
};

assert_eq!(
get(&arg_units, &cfg_units)?,
Units {
temperature: Some(Temperature::fahrenheit),
speed: Some(Speed::ms),
speed: cfg_units.speed,
time: Some(Time::am_pm),
precipitation: cfg_units.precipitation,
}
);

Expand All @@ -139,13 +184,7 @@ mod tests {
let arg_units = [];
let cfg_units = Units::default();

assert_eq!(
get(&arg_units, &cfg_units)?,
Units {
temperature: Units::default().temperature,
speed: Units::default().speed,
}
);
assert_eq!(get(&arg_units, &cfg_units)?, Units::default());

Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions src/modules/weather.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@ latitude={}
&current_weather=true
&temperature_unit={}
&windspeed_unit={}
&precipitation_unit={}
&timezone=auto",
lat,
lon,
unit.temperature.unwrap().as_ref(),
unit.speed.unwrap().as_ref(),
unit.precipitation.unwrap().as_ref(),
);

let res = reqwest::get(url)
Expand Down

0 comments on commit 4469cc6

Please sign in to comment.