Model list arrow flips when open; temperatures in a fixed order; bigger avatar; clock font, weight and digit width as settings; Cancel at the top of the event form, Esc cancels it

This commit is contained in:
server2
2026-10-16 02:52:11 +02:00
parent e2ef1a9d52
commit 8cbd211da0
6 changed files with 61 additions and 20 deletions
+37 -12
View File
@@ -349,12 +349,28 @@ fn sync_settings() -> (String, String, String, bool) {
(agenda_settings::account(), agenda_settings::server(), agenda_settings::contacts_server(), agenda_settings::birthdays())
}
// whether the card has a form to type into: then it keeps the keyboard and stays open
// the sky now and whether it's day, once the weather is known (the home pill takes its colour from it)
pub fn sky() -> Option<(parse::Sky, bool)> {
Forecast::read().weather.as_ref().map(|weather| (parse::sky(weather.code), weather.is_day))
}
// the event form closes without saving
fn cancel() {
Agenda::write().form = None;
}
// Esc in the card: closes the event form if it's open (then true), else leaves it to the card
pub fn escape() -> bool {
let open = Agenda::read().form.is_some();
if open {
cancel();
}
open
}
// whether the card has a form to type into: then it keeps the keyboard and stays open
pub fn typing() -> bool {
Agenda::read().form.is_some()
}
@@ -1202,18 +1218,18 @@ fn top_row(clock: &Clock, width: f32, shapes: &mut Vec<Box<dyn Shape>>) -> Box<d
// the big clock, and the weather beside it; `y` is where the row starts in the card
fn middle_row(clock: &Clock, forecast: &Forecast, width: f32, today: i64, y: f32, shapes: &mut Vec<Box<dyn Shape>>) -> Box<dyn Widget> {
let theme = theme::now();
let gap = settings::gap();
let seconds_today = clock.now.rem_euclid(86_400);
let (hour, minute, second) = (seconds_today / 3_600, seconds_today % 3_600 / 60, seconds_today % 60);
let time = if settings::seconds() { format!("{hour:02}:{minute:02}:{second:02}") } else { format!("{hour:02}:{minute:02}") };
let clock_w = (settings::clock_size() * font::letter_width() * time.chars().count() as f32).min(width / 2.0);
let letter = if settings::clock_letter_width() > 0.0 { settings::clock_letter_width() } else { font::letter_width() };
let clock_w = (settings::clock_size() * letter * time.chars().count() as f32).min(width / 2.0);
let weather_w = (width - clock_w - gap).max(0.0);
let height = middle_h();
let big = Rectangle::new().width(clock_w).height(height).align_child(Start, Center).child(Text::new(time).size(settings::clock_size()).weight(Weight::Bold).color(theme.text).tight());
let big = Rectangle::new().width(clock_w).height(height).align_child(Start, Center).child(clock_text(time));
let weather = weather(forecast, weather_w, today, (clock_w + gap, y + (height - weather_h()) / 2.0), shapes);
Box::new(
@@ -1224,6 +1240,14 @@ fn middle_row(clock: &Clock, forecast: &Forecast, width: f32, today: i64, y: f32
)
}
// the big clock's digits in its own font and weight
fn clock_text(time: String) -> Text {
let digits = Text::new(time).size(settings::clock_size()).weight(settings::clock_weight().min(1000) as u16).color(theme::now().text).tight();
let family = settings::clock_font();
if family.trim().is_empty() { digits } else { digits.font(family.trim()) }
}
// the weather now over the coming days, at `origin` in the card
fn weather(forecast: &Forecast, width: f32, today: i64, origin: (f32, f32), shapes: &mut Vec<Box<dyn Shape>>) -> Rectangle {
let theme = theme::now();
@@ -1749,6 +1773,7 @@ fn event_form(agenda: &Agenda, form: &Form, width: f32, origin: (f32, f32), shap
};
let mut top: Vec<Box<dyn Widget>> = vec![Box::new(Text::new(heading).size(text::heading()).weight(Weight::Bold).color(theme.text))];
let mut actions: Vec<Box<dyn Widget>> = Vec::new();
if form.editing.is_some() {
let words = match (form.confirm, series) {
@@ -1758,11 +1783,16 @@ fn event_form(agenda: &Agenda, form: &Form, width: f32, origin: (f32, f32), shap
};
let button = button_size();
let at = (origin.0 + width - choice_width(words, button / 2.0 + 6.0), origin.1 + (pods::header_height() - button) / 2.0);
let cancel_w = choice_width("Cancel", 0.0);
let at = (origin.0 + width - cancel_w - gap - choice_width(words, button / 2.0 + 6.0), origin.1 + (pods::header_height() - button) / 2.0);
top.push(Box::new(icon_chip(words, form.confirm, Glyph::Trash, at, shapes, remove)));
actions.push(Box::new(icon_chip(words, form.confirm, Glyph::Trash, at, shapes, remove)));
}
// Cancel at the top, where it's always in sight (Esc does the same)
actions.push(Box::new(pods::chip("Cancel", None, cancel)));
top.push(Box::new(Row::new(actions).gap(gap).align(Center)));
let mut parts: Vec<Box<dyn Widget>> = vec![
Box::new(Rectangle::new().width(width).height(pods::header_height()).child(Row::new(top).width(width).justify(SpaceBetween).align(Center))),
Box::new(field(title, width)),
@@ -1839,12 +1869,7 @@ fn event_form(agenda: &Agenda, form: &Form, width: f32, origin: (f32, f32), shap
parts.push(Box::new(wrapped(problem.clone(), overlays::low_battery(), width)));
}
let buttons: Vec<Box<dyn Widget>> = vec![
Box::new(choice(if form.saving { "Saving…" } else { "Save" }, true, None, save)),
Box::new(pods::chip("Cancel", None, || Agenda::write().form = None)),
];
parts.push(Box::new(Row::new(buttons).gap(gap).align(Center)));
parts.push(Box::new(choice(if form.saving { "Saving…" } else { "Save" }, true, None, save)));
Box::new(Rectangle::new().width(width).height(calendar_h()).child(Column::new(parts).gap(gap)))
}