191 lines
7 KiB
Rust
191 lines
7 KiB
Rust
use gpui::{
|
|
App, Context, EventEmitter, IntoElement, PlatformDisplay, Size, Window,
|
|
WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowOptions,
|
|
linear_color_stop, linear_gradient, point,
|
|
};
|
|
use release_channel::ReleaseChannel;
|
|
use std::rc::Rc;
|
|
use theme;
|
|
use ui::{Render, prelude::*};
|
|
|
|
pub struct AgentNotification {
|
|
title: SharedString,
|
|
caption: SharedString,
|
|
icon: IconName,
|
|
project_name: Option<SharedString>,
|
|
}
|
|
|
|
impl AgentNotification {
|
|
pub fn new(
|
|
title: impl Into<SharedString>,
|
|
caption: impl Into<SharedString>,
|
|
icon: IconName,
|
|
project_name: Option<impl Into<SharedString>>,
|
|
) -> Self {
|
|
Self {
|
|
title: title.into(),
|
|
caption: caption.into(),
|
|
icon,
|
|
project_name: project_name.map(|name| name.into()),
|
|
}
|
|
}
|
|
|
|
pub fn window_options(screen: Rc<dyn PlatformDisplay>, cx: &App) -> WindowOptions {
|
|
let size = Size {
|
|
width: px(450.),
|
|
height: px(72.),
|
|
};
|
|
|
|
let notification_margin_width = px(16.);
|
|
let notification_margin_height = px(-48.);
|
|
|
|
let bounds = gpui::Bounds::<Pixels> {
|
|
origin: screen.bounds().top_right()
|
|
- point(
|
|
size.width + notification_margin_width,
|
|
notification_margin_height,
|
|
),
|
|
size,
|
|
};
|
|
|
|
let app_id = ReleaseChannel::global(cx).app_id();
|
|
|
|
WindowOptions {
|
|
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
|
titlebar: None,
|
|
focus: false,
|
|
show: true,
|
|
kind: WindowKind::PopUp,
|
|
is_movable: false,
|
|
display_id: Some(screen.id()),
|
|
window_background: WindowBackgroundAppearance::Transparent,
|
|
app_id: Some(app_id.to_owned()),
|
|
window_min_size: None,
|
|
window_decorations: Some(WindowDecorations::Client),
|
|
tabbing_identifier: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum AgentNotificationEvent {
|
|
Accepted,
|
|
Dismissed,
|
|
}
|
|
|
|
impl EventEmitter<AgentNotificationEvent> for AgentNotification {}
|
|
|
|
impl Render for AgentNotification {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let ui_font = theme::setup_ui_font(window, cx);
|
|
let line_height = window.line_height();
|
|
|
|
let bg = cx.theme().colors().elevated_surface_background;
|
|
let gradient_overflow = || {
|
|
div()
|
|
.h_full()
|
|
.absolute()
|
|
.w_8()
|
|
.bottom_0()
|
|
.right_0()
|
|
.bg(linear_gradient(
|
|
90.,
|
|
linear_color_stop(bg, 1.),
|
|
linear_color_stop(bg.opacity(0.2), 0.),
|
|
))
|
|
};
|
|
|
|
h_flex()
|
|
.id("agent-notification")
|
|
.size_full()
|
|
.p_3()
|
|
.gap_4()
|
|
.justify_between()
|
|
.elevation_3(cx)
|
|
.text_ui(cx)
|
|
.font(ui_font)
|
|
.border_color(cx.theme().colors().border)
|
|
.rounded_xl()
|
|
.on_click(cx.listener(|_, _, _, cx| {
|
|
cx.emit(AgentNotificationEvent::Accepted);
|
|
}))
|
|
.child(
|
|
h_flex()
|
|
.items_start()
|
|
.gap_2()
|
|
.flex_1()
|
|
.child(
|
|
h_flex().h(line_height).justify_center().child(
|
|
Icon::new(self.icon)
|
|
.color(Color::Muted)
|
|
.size(IconSize::Small),
|
|
),
|
|
)
|
|
.child(
|
|
v_flex()
|
|
.flex_1()
|
|
.max_w(px(300.))
|
|
.child(
|
|
div()
|
|
.relative()
|
|
.text_size(px(14.))
|
|
.text_color(cx.theme().colors().text)
|
|
.truncate()
|
|
.child(self.title.clone())
|
|
.child(gradient_overflow()),
|
|
)
|
|
.child(
|
|
h_flex()
|
|
.relative()
|
|
.gap_1p5()
|
|
.text_size(px(12.))
|
|
.text_color(cx.theme().colors().text_muted)
|
|
.truncate()
|
|
.when_some(
|
|
self.project_name.clone(),
|
|
|description, project_name| {
|
|
description.child(
|
|
h_flex()
|
|
.gap_1p5()
|
|
.child(
|
|
div()
|
|
.max_w_16()
|
|
.truncate()
|
|
.child(project_name),
|
|
)
|
|
.child(
|
|
div().size(px(3.)).rounded_full().bg(cx
|
|
.theme()
|
|
.colors()
|
|
.text
|
|
.opacity(0.5)),
|
|
),
|
|
)
|
|
},
|
|
)
|
|
.child(self.caption.clone())
|
|
.child(gradient_overflow()),
|
|
),
|
|
),
|
|
)
|
|
.child(
|
|
v_flex()
|
|
.gap_1()
|
|
.items_center()
|
|
.child(
|
|
Button::new("open", "View Panel")
|
|
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
|
.full_width()
|
|
.on_click({
|
|
cx.listener(move |_this, _event, _, cx| {
|
|
cx.emit(AgentNotificationEvent::Accepted);
|
|
})
|
|
}),
|
|
)
|
|
.child(Button::new("dismiss", "Dismiss").full_width().on_click({
|
|
cx.listener(move |_, _event, _, cx| {
|
|
cx.emit(AgentNotificationEvent::Dismissed);
|
|
})
|
|
})),
|
|
)
|
|
}
|
|
}
|