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.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-27 03:23:18 -04:00
1 parent 7e3f99f278
commit 57dd55320e
6 files changed
+106 -7

No files matched your search

+3 -3
View File
@@ -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)),
None => whole,
};
let mut grid = TimeGrid::new((self.id.clone(), "grid"), days.clone(), self.events)
.zone(zone)
.now(now);
let mut grid =
TimeGrid::new((self.id.clone(), "grid"), days.clone(), self.events).zone(zone);
grid.now = self.now;
grid.overlay = self.overlay;
grid.on_create = self.on_create;
grid.on_resize = self.on_resize;
+5 -2
View File
@@ -17,7 +17,7 @@ use crate::{
forms::{Drawing, OnValue, Stroke, pen},
layout::on_axis,
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.
@@ -53,7 +53,7 @@ pub struct TimeGrid {
days: Vec<Date>,
events: Vec<Event>,
zone: Option<TimeZone>,
now: Option<Timestamp>,
pub(crate) now: Option<Timestamp>,
pub(crate) overlay: Option<TimezoneOverlay>,
pub(crate) on_create: Option<OnSpan>,
pub(crate) on_resize: Option<OnResize>,
@@ -361,6 +361,9 @@ impl TimeGrid {
impl RenderOnce for TimeGrid {
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
.zone
.clone()
+4 -1
View File
@@ -18,7 +18,7 @@ use crate::{
layout::seeded::use_seeded,
primitives::{FocusRing, tab_stop},
theme::{ActiveTheme, Radius, TextSize},
typography::{Ellipsis, format},
typography::{Ellipsis, format, fresh},
};
const WEEKDAYS: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
@@ -287,6 +287,9 @@ impl Row<'_> {
impl RenderOnce for CalendarMonthView {
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
.zone
.unwrap_or_else(|| format::system_zone("calendar month view"));
+89
View File
@@ -226,3 +226,92 @@ fn a_grid_without_today_opens_on_the_morning(cx: &mut TestAppContext) {
let (_, cx) = planning(nights, cx);
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"
);
}
+4 -1
View File
@@ -16,7 +16,7 @@ use crate::{
layout::seeded::use_seeded,
primitives::tab_stop,
theme::{ActiveTheme, TextSize},
typography::format,
typography::{format, fresh},
};
const INITIALS: [&str; 7] = ["M", "T", "W", "T", "F", "S", "S"];
@@ -191,6 +191,9 @@ impl Mini<'_> {
impl RenderOnce for YearView {
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
.zone
.unwrap_or_else(|| format::system_zone("year view"));