Improve life calendar and add it to header

This commit is contained in:
2021-05-31 23:19:41 +02:00
parent 6f984ed6fb
commit 653853b4f6
5 changed files with 91 additions and 52 deletions

View File

@ -9,8 +9,10 @@ use crate::auth::MasterPassword;
use crate::database::migrations::migrate;
use crate::database::unversioned::global::schema_version;
use crate::database::SCHEMA_VERSION;
use crate::routes::pages::weeks::BirthDate;
use crate::util::EventNotifier;
use bincode::{deserialize, serialize};
use chrono::NaiveDate;
use dotenv::dotenv;
use rocket_contrib::serve::StaticFiles;
use rocket_contrib::templates::Template;
@ -29,6 +31,10 @@ async fn main() -> io::Result<()> {
})
.into();
let birth_date: BirthDate = env::var("BIRTH_DATE")
.map(|s| BirthDate(s.parse().expect("failed to parse BIRTH_DATE")))
.unwrap_or_else(|_| BirthDate(NaiveDate::from_ymd(2000, 1, 1)));
let mut sled = sled::open(db_path)?;
match sled.insert(
serialize(schema_version::K).unwrap(),
@ -56,6 +62,7 @@ async fn main() -> io::Result<()> {
}))
.manage(sled)
.manage(master_pass)
.manage(birth_date)
.manage(EventNotifier::new())
.mount("/static", StaticFiles::from("static"))
.mount(

View File

@ -1,30 +1,49 @@
use crate::auth::Authorized;
use crate::status_json::StatusJson;
use chrono::{Duration, Local, NaiveDate};
use rocket::get;
use itertools::Itertools;
use rocket::{get, State};
use rocket_contrib::templates::Template;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::iter::{once, repeat};
pub struct BirthDate(pub NaiveDate);
#[get("/weeks")]
pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> {
pub fn weeks(_auth: Authorized, birth_date: State<BirthDate>) -> Result<Template, StatusJson> {
type Color<'a> = Cow<'a, str>;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct WeekCtx<'a> {
border_color: Color<'a>,
fill_color: Option<Color<'a>>,
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Style<'a> {
border: Color<'a>,
fill: Option<Color<'a>>,
}
impl<'a, T> From<T> for WeekCtx<'a>
where
T: Into<Cow<'a, str>>,
{
fn from(color: T) -> Self {
WeekCtx {
border_color: color.into(),
fill_color: None,
#[derive(Debug, Clone, Serialize, Deserialize)]
struct PeriodCtx<'a> {
style: Style<'a>,
weeks: Vec<()>,
}
impl<'a> Style<'a> {
fn border<C>(border: C) -> Self
where
C: Into<Cow<'a, str>>,
{
Style {
border: border.into(),
fill: None,
}
}
fn fill<C>(border: C, fill: C) -> Self
where
C: Into<Cow<'a, str>>,
{
Style {
border: border.into(),
fill: Some(fill.into()),
}
}
}
@ -32,13 +51,11 @@ pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> {
#[derive(Debug, Serialize, Deserialize)]
struct Ctx<'a> {
weeks_left: i64,
weeks: Vec<WeekCtx<'a>>,
periods: Vec<PeriodCtx<'a>>,
}
let now = Local::now().date();
// TODO: change this
let birth_date = NaiveDate::from_ymd(1999, 01, 01);
let birth_date = birth_date.0;
let lived: Duration = now.naive_local() - birth_date;
let one_year = Duration::days(365);
@ -51,40 +68,41 @@ pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> {
let color_birth = "green";
let color_child = "#ff0";
let color_teen = "#f0f";
let color_adult = "#f33";
let color_teen = "#f33";
let color_adult = "#f0f";
let color_today = "wheat";
let color_future = "#eee";
let context = Ctx {
weeks_left: life_expectancy - lived.num_weeks(),
weeks: once(WeekCtx {
border_color: color_birth.into(),
fill_color: Some(color_birth.into()),
})
// childhood
.chain((1..childhood_end).map(|_| color_child.into()))
// teens
.chain((childhood_end..teenage_end).map(|_| color_teen.into()))
// adulthood
.chain((teenage_end..).map(|_| color_adult.into()))
// take from above for lived number of weeks
.take(lived.num_weeks() as usize - 1)
// add a week for this week
.chain(once(WeekCtx {
border_color: color_today.into(),
fill_color: Some(color_today.into()),
}))
// fill remaining weeks until death
.chain(repeat(color_future.into()))
.take((life_expectancy - uncertainty * 2) as usize)
// add some fading around expected life span
.chain((0..uncertainty).rev().map(|i| {
let m = u8::MAX as i64;
let alpha = ((m * i) / (uncertainty)) as u8;
format!("#eeeeee{:02x}", alpha).into()
}))
.collect(),
periods: once(Style::fill(color_birth, color_birth))
// childhood
.chain((1..childhood_end).map(|_| Style::border(color_child)))
// teens
.chain((childhood_end..teenage_end).map(|_| Style::border(color_teen)))
// adulthood
.chain((teenage_end..).map(|_| Style::border(color_adult)))
// take from above for lived number of weeks
.take(lived.num_weeks() as usize - 1)
// add a week for this week
.chain(once(Style::fill(color_today, color_today)))
// fill remaining weeks until death
.chain(repeat(Style::border(color_future)))
.take((life_expectancy - uncertainty * 2) as usize)
// add some fading around expected life span
.chain((0..uncertainty).rev().map(|i| {
let m = u8::MAX as i64;
let alpha = ((m * i) / (uncertainty)) as u8;
Style::border(format!("#eeeeee{:02x}", alpha))
}))
// group weeks by color to save space
.group_by(|style| style.clone())
.into_iter()
.map(|(style, weeks)| PeriodCtx {
style,
weeks: vec![(); weeks.count()],
})
.collect(),
};
Ok(Template::render("weeks", &context))