Every page and scripted state was shot with gpui 0.2.2 and with the port, light and dark, full width and at 280px, judged pair by pair by agents with skeptics, and every page's log diffed. What differed is fixed, each with a test that fails without it where the test platform can show it: - The gallery's harness takes posted mouse moves (gpui_macos listens to a tracking area), posts each drag move twice (it no longer replays a held drag), and waits three frames before each shot. - Rolling digits: a block column, so taffy 0.13 lends the cell no baseline, and a line of whole device pixels, since gpui snaps each length on its own. DescriptionList's row aligns ends. - Margins that taffy 0.13 collapses through a plain block: the drawer's pull and snap, the stagger and transition rise, the dialog and palette rises, the fullscreen dialog's slide. - An Input keeps room to type in a squeezed row; the field rows drop w_full, whose reason was taffy 0.9's. AGENTS.md's rules that named gpui 0.2.2 or taffy 0.9 were re-tested against both sources and rewritten, and new ones say what the port changed. TASKS.md's tags follow: what the new gpui makes possible is prove. Captions, doc comments and README say what holds now.
145 lines
5.1 KiB
Rust
145 lines
5.1 KiB
Rust
use ely_gpui_component::{
|
|
buttons::{Button, ButtonVariant},
|
|
shell::{TrayIcon, TrayItem, dock_badge, set_dock_badge},
|
|
typography::Caption,
|
|
};
|
|
use gpui::{App, IntoElement, ParentElement, SharedString, Window};
|
|
|
|
use crate::{
|
|
probe::probe,
|
|
ui::{blocked, row, section},
|
|
};
|
|
|
|
const ITEMS: [&str; 3] = ["Open gallery", "Toggle theme", "Quit"];
|
|
|
|
pub fn tray(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
|
let tray = window.use_keyed_state("tray", cx, |_, _| None::<TrayIcon>);
|
|
let last = window.use_keyed_state("tray-last", cx, |_, _| SharedString::from("nothing yet"));
|
|
let shown = tray.read(cx).is_some();
|
|
let note = last.read(cx).clone();
|
|
let (toggle, pick) = (tray.clone(), tray);
|
|
section(
|
|
"TrayIcon / TrayMenu",
|
|
"An SF Symbol in the menu bar with a menu. macOS only.",
|
|
cx,
|
|
)
|
|
.child(
|
|
row()
|
|
.child(probe(
|
|
"tray-show",
|
|
Button::new(
|
|
"tray-show",
|
|
if shown {
|
|
"Remove tray icon"
|
|
} else {
|
|
"Show tray icon"
|
|
},
|
|
)
|
|
.variant(ButtonVariant::Outline)
|
|
.on_click(move |_, _, cx| {
|
|
let last = last.clone();
|
|
let next = match toggle.read(cx) {
|
|
Some(_) => None,
|
|
None => {
|
|
let items = vec![
|
|
TrayItem::Action(ITEMS[0].into()),
|
|
TrayItem::Action(ITEMS[1].into()),
|
|
TrayItem::Separator,
|
|
TrayItem::Action(ITEMS[2].into()),
|
|
];
|
|
let made = TrayIcon::new(
|
|
"circle.hexagongrid",
|
|
items,
|
|
move |index, cx| {
|
|
let label = match index {
|
|
0 => ITEMS[0],
|
|
1 => ITEMS[1],
|
|
3 => ITEMS[2],
|
|
other => panic!("tray has no action at {other}"),
|
|
};
|
|
last.update(cx, |last, cx| {
|
|
*last = label.into();
|
|
cx.notify();
|
|
})
|
|
},
|
|
cx,
|
|
);
|
|
match made {
|
|
Ok(icon) => Some(icon),
|
|
Err(error) => {
|
|
log::error!("gallery: tray failed: {error:#}");
|
|
None
|
|
}
|
|
}
|
|
}
|
|
};
|
|
toggle.update(cx, |tray, cx| {
|
|
*tray = next;
|
|
cx.notify();
|
|
})
|
|
}),
|
|
))
|
|
.child(probe(
|
|
"tray-pick",
|
|
Button::new("tray-pick", "Pick “Open gallery”")
|
|
.variant(ButtonVariant::Ghost)
|
|
.disabled(!shown)
|
|
.on_click(move |_, _, cx| {
|
|
if let Some(icon) = pick.read(cx) {
|
|
icon.pick(0);
|
|
}
|
|
}),
|
|
))
|
|
.child(Caption::new(format!("Last pick: {note}"))),
|
|
)
|
|
}
|
|
|
|
pub fn dock(cx: &mut App) -> impl IntoElement + use<> {
|
|
let reading = match dock_badge() {
|
|
Ok(Some(label)) => format!("The Dock shows “{label}”."),
|
|
Ok(None) => "The Dock shows no badge.".to_string(),
|
|
Err(error) => format!("{error:#}"),
|
|
};
|
|
let badge = |label: Option<&'static str>| {
|
|
move |_: &gpui::ClickEvent, window: &mut Window, _: &mut App| {
|
|
if let Err(error) = set_dock_badge(label) {
|
|
log::error!("gallery: badge failed: {error:#}");
|
|
}
|
|
window.refresh();
|
|
}
|
|
};
|
|
section(
|
|
"DockBadge",
|
|
"A count on the app's Dock icon. macOS only.",
|
|
cx,
|
|
)
|
|
.child(
|
|
row()
|
|
.child(probe(
|
|
"badge-set",
|
|
Button::new("badge-set", "Badge 3")
|
|
.variant(ButtonVariant::Outline)
|
|
.on_click(badge(Some("3"))),
|
|
))
|
|
.child(probe(
|
|
"badge-clear",
|
|
Button::new("badge-clear", "Clear")
|
|
.variant(ButtonVariant::Ghost)
|
|
.on_click(badge(None)),
|
|
))
|
|
.child(Caption::new(reading)),
|
|
)
|
|
}
|
|
|
|
pub fn notification(cx: &App) -> impl IntoElement + use<> {
|
|
section(
|
|
"SystemNotification",
|
|
"Notices from the system's own center.",
|
|
cx,
|
|
)
|
|
.child(blocked(
|
|
"Not yet shown: gpui posts a system notification only from an app bundle, and the gallery runs unbundled.",
|
|
cx,
|
|
))
|
|
}
|