use ely_gpui_component::{ buttons::{Button, ButtonVariant}, shell::{ Connectivity, CrashReporter, OfflineIndicator, UpdateBanner, UpdateDialog, UpdateState, ZoomControl, }, theme::ActiveTheme, }; use gpui::{App, IntoElement, ParentElement, Styled, Window, div}; use super::chrome::window_frame; use crate::{ probe::{Opened, probe}, ui::{row, section, specimen}, }; fn log_action(name: &'static str) -> impl Fn(&mut Window, &mut App) + 'static { move |_, _| log::info!("gallery: update {name}") } pub fn update_banner(cx: &App) -> impl IntoElement + use<> { let banner = |id: &'static str, state| { UpdateBanner::new(id, "0.2.0", state) .on_download(log_action("download")) .on_restart(log_action("restart")) .on_later(log_action("later")) }; section( "UpdateBanner", "Offer, download, restart. One slim bar, three states.", cx, ) .child( window_frame(560.0, 126.0, cx) .bg(cx.theme().colors.bg) .child(banner("banner-available", UpdateState::Available)) .child(banner("banner-downloading", UpdateState::Downloading(0.42))) .child(banner("banner-ready", UpdateState::Ready)), ) } fn update_dialog() -> UpdateDialog { UpdateDialog::new("Ely", "0.1.0", "0.2.0", UpdateState::Available) .note("Window chrome for macOS, Windows and Linux.") .note("Docks remember their layout across launches.") .note("Sticky headers stay inside their scroll area.") .note("Drawers follow the pointer outside their bounds.") .on_download(log_action("download")) .on_later(|window, _| window.remove_window()) } pub fn update_window(cx: &App) -> impl IntoElement + use<> { section("UpdateDialog", "What changed, then one clear action.", cx) .child(specimen( "Inline", window_frame(400.0, 380.0, cx) .bg(cx.theme().colors.bg) .pt_6() .child(update_dialog().on_later(log_action("later"))), cx, )) .child(probe( "update-open", Button::new("update-open", "Open update window") .variant(ButtonVariant::Outline) .on_click(|_, _, cx| match update_dialog().open(cx) { Ok(handle) => Opened::insert("update", handle.into(), cx), Err(error) => log::error!("gallery: update window failed: {error:#}"), }), )) } const REPORT: &str = "Exception Type: EXC_BAD_ACCESS (SIGSEGV) Crashed Thread: 0 main 0 ely 0x0000000104a1c3f0 layout::dock::restore + 112 1 ely 0x0000000104a1b9d4 workspace::apply + 88 2 ely 0x0000000104a0f2a8 app::open_recent + 404 3 libdyld.dylib 0x000000018f2d4f28 start + 4"; pub fn crash_reporter(cx: &App) -> impl IntoElement + use<> { let reporter = |details: bool| { CrashReporter::new( "Ely", "The report says where it stopped. Sending it helps fix it.", REPORT, ) .details(details) .on_send(|_, _| log::info!("gallery: crash report sent")) .on_dismiss(|_, _| log::info!("gallery: crash report dismissed")) }; section( "CrashReporter", "Plain words first. The report waits behind a disclosure.", cx, ) .child(specimen( "Inline, report shown", window_frame(420.0, 520.0, cx) .bg(cx.theme().colors.bg) .pt_6() .child(reporter(true)), cx, )) .child(probe( "crash-open", Button::new("crash-open", "Open crash window") .variant(ButtonVariant::Outline) .on_click(move |_, _, cx| match reporter(false).open(cx) { Ok(handle) => Opened::insert("crash", handle.into(), cx), Err(error) => log::error!("gallery: crash window failed: {error:#}"), }), )) } pub fn offline(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> { let state = window.use_keyed_state("connectivity", cx, |_, _| Connectivity::Online); let current = *state.read(cx); let choices = [ ("offline-online", "Online", Connectivity::Online), ("offline-offline", "Offline", Connectivity::Offline), ( "offline-reconnecting", "Reconnecting", Connectivity::Reconnecting, ), ]; section( "OfflineIndicator", "Quiet while it matters, gone soon after the network returns.", cx, ) .child(row().children(choices.map(|(key, label, choice)| { let state = state.clone(); probe( key, Button::new(key, label) .size(ely_gpui_component::theme::ControlSize::Sm) .variant(if current == choice { ButtonVariant::Subtle } else { ButtonVariant::Ghost }) .on_click(move |_, _, cx| { state.update(cx, |state, cx| { *state = choice; cx.notify(); }) }), ) }))) .child( div() .h(cx .theme() .control_height(ely_gpui_component::theme::ControlSize::Lg)) .flex() .items_center() .child(OfflineIndicator::new("connectivity-pill", current)), ) } pub fn zoom(cx: &App) -> impl IntoElement + use<> { section( "ZoomControl", "Scales the whole window through its rem size. Click the number to reset.", cx, ) .child(probe("zoom", ZoomControl::new("zoom-control"))) }