Calendar · views on the clock keep moving
The week and day views read the clock once and handed that moment down as given, which turned off the line's ticker: the line at now and the lit day stood still. The owner's moment now goes down unchanged, and a time grid, month view or year view on the clock keeps its own ticker, so the line moves and today turns over at midnight, even on days that are not today. A given moment holds them still. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a41cb2f9c2
commit
b68f2bf1d5
6 files changed
+106
-7
No files matched your search
@@ -355,3 +355,4 @@ Per-component lines live in `tasks/`. Tags there:
|
|||||||
| T29d | 2 | FAIL | a raise inside a raise took its place in the queue as its namespace, so one appearing before it rebuilt its state and dropped its focus |
|
| T29d | 2 | FAIL | a raise inside a raise took its place in the queue as its namespace, so one appearing before it rebuilt its state and dropped its focus |
|
||||||
| T29d | 3 | PASS | |
|
| T29d | 3 | PASS | |
|
||||||
| T30a | 1 | PASS | |
|
| T30a | 1 | PASS | |
|
||||||
|
| T30b | 1 | FAIL | the week and day views froze the line at now and today: the moment read once went down as given and turned the ticker off |
|
||||||
@@ -262,9 +262,9 @@ impl<const DAYS: usize> RenderOnce for CalendarDays<DAYS> {
|
|||||||
Some(on_event) => whole.on_event(move |key, window, cx| on_event(key, window, cx)),
|
Some(on_event) => whole.on_event(move |key, window, cx| on_event(key, window, cx)),
|
||||||
None => whole,
|
None => whole,
|
||||||
};
|
};
|
||||||
let mut grid = TimeGrid::new((self.id.clone(), "grid"), days.clone(), self.events)
|
let mut grid =
|
||||||
.zone(zone)
|
TimeGrid::new((self.id.clone(), "grid"), days.clone(), self.events).zone(zone);
|
||||||
.now(now);
|
grid.now = self.now;
|
||||||
grid.overlay = self.overlay;
|
grid.overlay = self.overlay;
|
||||||
grid.on_create = self.on_create;
|
grid.on_create = self.on_create;
|
||||||
grid.on_resize = self.on_resize;
|
grid.on_resize = self.on_resize;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use crate::{
|
|||||||
forms::{Drawing, OnValue, Stroke, pen},
|
forms::{Drawing, OnValue, Stroke, pen},
|
||||||
layout::on_axis,
|
layout::on_axis,
|
||||||
theme::{ActiveTheme, Radius, TextSize},
|
theme::{ActiveTheme, Radius, TextSize},
|
||||||
typography::format,
|
typography::{format, fresh},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Where a grid first opens: half past seven, or an hour and a half before now when that is later.
|
/// Where a grid first opens: half past seven, or an hour and a half before now when that is later.
|
||||||
@@ -53,7 +53,7 @@ pub struct TimeGrid {
|
|||||||
days: Vec<Date>,
|
days: Vec<Date>,
|
||||||
events: Vec<Event>,
|
events: Vec<Event>,
|
||||||
zone: Option<TimeZone>,
|
zone: Option<TimeZone>,
|
||||||
now: Option<Timestamp>,
|
pub(crate) now: Option<Timestamp>,
|
||||||
pub(crate) overlay: Option<TimezoneOverlay>,
|
pub(crate) overlay: Option<TimezoneOverlay>,
|
||||||
pub(crate) on_create: Option<OnSpan>,
|
pub(crate) on_create: Option<OnSpan>,
|
||||||
pub(crate) on_resize: Option<OnResize>,
|
pub(crate) on_resize: Option<OnResize>,
|
||||||
@@ -361,6 +361,9 @@ impl TimeGrid {
|
|||||||
|
|
||||||
impl RenderOnce for TimeGrid {
|
impl RenderOnce for TimeGrid {
|
||||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
if self.now.is_none() {
|
||||||
|
fresh((self.id.clone(), "clock"), window, cx);
|
||||||
|
}
|
||||||
let zone = self
|
let zone = self
|
||||||
.zone
|
.zone
|
||||||
.clone()
|
.clone()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::{
|
|||||||
layout::seeded::use_seeded,
|
layout::seeded::use_seeded,
|
||||||
primitives::{FocusRing, tab_stop},
|
primitives::{FocusRing, tab_stop},
|
||||||
theme::{ActiveTheme, Radius, TextSize},
|
theme::{ActiveTheme, Radius, TextSize},
|
||||||
typography::{Ellipsis, format},
|
typography::{Ellipsis, format, fresh},
|
||||||
};
|
};
|
||||||
|
|
||||||
const WEEKDAYS: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
const WEEKDAYS: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||||
@@ -287,6 +287,9 @@ impl Row<'_> {
|
|||||||
|
|
||||||
impl RenderOnce for CalendarMonthView {
|
impl RenderOnce for CalendarMonthView {
|
||||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
if self.today.is_none() {
|
||||||
|
fresh((self.id.clone(), "clock"), window, cx);
|
||||||
|
}
|
||||||
let zone = self
|
let zone = self
|
||||||
.zone
|
.zone
|
||||||
.unwrap_or_else(|| format::system_zone("calendar month view"));
|
.unwrap_or_else(|| format::system_zone("calendar month view"));
|
||||||
|
|||||||
@@ -226,3 +226,92 @@ fn a_grid_without_today_opens_on_the_morning(cx: &mut TestAppContext) {
|
|||||||
let (_, cx) = planning(nights, cx);
|
let (_, cx) = planning(nights, cx);
|
||||||
assert_eq!(opened(cx), px(48.0 * 7.5), "from 07:30");
|
assert_eq!(opened(cx), px(48.0 * 7.5), "from 07:30");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How often the host was told to redraw across a clock tick and a half, with no refresh of its own.
|
||||||
|
fn redraws(
|
||||||
|
part: fn(&Planning, Entity<Planning>) -> gpui::AnyElement,
|
||||||
|
cx: &mut TestAppContext,
|
||||||
|
) -> usize {
|
||||||
|
let (host, cx) = planning(part, cx);
|
||||||
|
let told = std::rc::Rc::new(std::cell::Cell::new(0));
|
||||||
|
let count = told.clone();
|
||||||
|
cx.update(|_, cx| {
|
||||||
|
cx.observe(&host, move |_, _| count.set(count.get() + 1))
|
||||||
|
.detach()
|
||||||
|
});
|
||||||
|
cx.executor()
|
||||||
|
.advance_clock(std::time::Duration::from_secs(45));
|
||||||
|
cx.run_until_parked();
|
||||||
|
told.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clocked_day(_: &Planning, _: Entity<Planning>) -> gpui::AnyElement {
|
||||||
|
let today = jiff::Timestamp::now().to_zoned(TimeZone::UTC).date();
|
||||||
|
div()
|
||||||
|
.h(px(600.0))
|
||||||
|
.child(crate::calendar::CalendarDayView::new("day", today, []).zone(TimeZone::UTC))
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn still_day(_: &Planning, _: Entity<Planning>) -> gpui::AnyElement {
|
||||||
|
div()
|
||||||
|
.h(px(600.0))
|
||||||
|
.child(
|
||||||
|
crate::calendar::CalendarDayView::new("day", date(2026, 9, 22), [])
|
||||||
|
.zone(TimeZone::UTC)
|
||||||
|
.now(at(22, 12)),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_day_on_the_clock_redraws_as_it_runs(cx: &mut TestAppContext) {
|
||||||
|
assert!(
|
||||||
|
redraws(clocked_day, cx) > 0,
|
||||||
|
"the line at now moves with the clock"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_day_given_its_moment_holds_still(cx: &mut TestAppContext) {
|
||||||
|
assert_eq!(redraws(still_day, cx), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clocked_month(_: &Planning, _: Entity<Planning>) -> gpui::AnyElement {
|
||||||
|
crate::calendar::CalendarMonthView::new("month", date(2026, 9, 1), [])
|
||||||
|
.zone(TimeZone::UTC)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_month_on_the_clock_redraws_so_today_turns_over(cx: &mut TestAppContext) {
|
||||||
|
assert!(redraws(clocked_month, cx) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clocked_year(_: &Planning, _: Entity<Planning>) -> gpui::AnyElement {
|
||||||
|
crate::calendar::YearView::new("year", 2026, [])
|
||||||
|
.zone(TimeZone::UTC)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_year_on_the_clock_redraws_so_today_turns_over(cx: &mut TestAppContext) {
|
||||||
|
assert!(redraws(clocked_year, cx) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clocked_other_day(_: &Planning, _: Entity<Planning>) -> gpui::AnyElement {
|
||||||
|
div()
|
||||||
|
.h(px(600.0))
|
||||||
|
.child(
|
||||||
|
crate::calendar::CalendarDayView::new("day", date(2026, 9, 22), []).zone(TimeZone::UTC),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_day_before_today_still_watches_the_clock_for_midnight(cx: &mut TestAppContext) {
|
||||||
|
assert!(
|
||||||
|
redraws(clocked_other_day, cx) > 0,
|
||||||
|
"no line to tick, the grid itself does"
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ use crate::{
|
|||||||
layout::seeded::use_seeded,
|
layout::seeded::use_seeded,
|
||||||
primitives::tab_stop,
|
primitives::tab_stop,
|
||||||
theme::{ActiveTheme, TextSize},
|
theme::{ActiveTheme, TextSize},
|
||||||
typography::format,
|
typography::{format, fresh},
|
||||||
};
|
};
|
||||||
|
|
||||||
const INITIALS: [&str; 7] = ["M", "T", "W", "T", "F", "S", "S"];
|
const INITIALS: [&str; 7] = ["M", "T", "W", "T", "F", "S", "S"];
|
||||||
@@ -191,6 +191,9 @@ impl Mini<'_> {
|
|||||||
|
|
||||||
impl RenderOnce for YearView {
|
impl RenderOnce for YearView {
|
||||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
if self.today.is_none() {
|
||||||
|
fresh((self.id.clone(), "clock"), window, cx);
|
||||||
|
}
|
||||||
let zone = self
|
let zone = self
|
||||||
.zone
|
.zone
|
||||||
.unwrap_or_else(|| format::system_zone("year view"));
|
.unwrap_or_else(|| format::system_zone("year view"));
|
||||||
|
|||||||
Reference in new issue
Block a user