From e338a177c55909c3f4618f25d840365b023fd38a Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Fri, 17 Jan 2025 20:22:27 -0300 Subject: [PATCH] assistant2: Adjust "generating" state design (#23299) To ensure message readability is not affected in any way. https://github.com/user-attachments/assets/9a2ad949-1a8a-4c31-ad3c-db70f48e5d98 Release Notes: - N/A --- crates/assistant2/src/active_thread.rs | 81 ++---------------------- crates/assistant2/src/assistant_panel.rs | 3 - crates/assistant2/src/message_editor.rs | 76 +++++++++++++++++----- 3 files changed, 65 insertions(+), 95 deletions(-) diff --git a/crates/assistant2/src/active_thread.rs b/crates/assistant2/src/active_thread.rs index a0506e57688b5..1bfd607866dfe 100644 --- a/crates/assistant2/src/active_thread.rs +++ b/crates/assistant2/src/active_thread.rs @@ -1,20 +1,18 @@ use std::sync::Arc; -use std::time::Duration; use assistant_tool::ToolWorkingSet; use collections::HashMap; use gpui::{ - linear_color_stop, linear_gradient, list, percentage, AbsoluteLength, Animation, AnimationExt, - AnyElement, AppContext, DefiniteLength, EdgesRefinement, Empty, FocusHandle, Length, + list, AbsoluteLength, AnyElement, AppContext, DefiniteLength, EdgesRefinement, Empty, Length, ListAlignment, ListOffset, ListState, Model, StyleRefinement, Subscription, - TextStyleRefinement, Transformation, UnderlineStyle, View, WeakView, + TextStyleRefinement, UnderlineStyle, View, WeakView, }; use language::LanguageRegistry; use language_model::Role; use markdown::{Markdown, MarkdownStyle}; use settings::Settings as _; use theme::ThemeSettings; -use ui::{prelude::*, Divider, KeyBinding}; +use ui::prelude::*; use workspace::Workspace; use crate::thread::{MessageId, Thread, ThreadError, ThreadEvent}; @@ -29,7 +27,6 @@ pub struct ActiveThread { list_state: ListState, rendered_messages_by_id: HashMap>, last_error: Option, - focus_handle: FocusHandle, _subscriptions: Vec, } @@ -39,7 +36,6 @@ impl ActiveThread { workspace: WeakView, language_registry: Arc, tools: Arc, - focus_handle: FocusHandle, cx: &mut ViewContext, ) -> Self { let subscriptions = vec![ @@ -62,7 +58,6 @@ impl ActiveThread { } }), last_error: None, - focus_handle, _subscriptions: subscriptions, }; @@ -280,9 +275,7 @@ impl ActiveThread { .child( v_flex() .bg(colors.editor_background) - .rounded_t_lg() - .rounded_bl_lg() - .rounded_br_none() + .rounded_lg() .border_1() .border_color(colors.border) .shadow_sm() @@ -326,74 +319,10 @@ impl ActiveThread { } impl Render for ActiveThread { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - let is_streaming_completion = self.thread.read(cx).is_streaming(); - let panel_bg = cx.theme().colors().panel_background; - let focus_handle = self.focus_handle.clone(); - + fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { v_flex() .size_full() .pt_1p5() .child(list(self.list_state.clone()).flex_grow()) - .when(is_streaming_completion, |parent| { - parent.child( - h_flex() - .w_full() - .pb_2p5() - .absolute() - .bottom_0() - .flex_shrink() - .justify_center() - .bg(linear_gradient( - 180., - linear_color_stop(panel_bg.opacity(0.0), 0.), - linear_color_stop(panel_bg, 1.), - )) - .child( - h_flex() - .flex_none() - .p_1p5() - .bg(cx.theme().colors().editor_background) - .border_1() - .border_color(cx.theme().colors().border) - .rounded_md() - .shadow_lg() - .gap_1() - .child( - Icon::new(IconName::ArrowCircle) - .size(IconSize::Small) - .color(Color::Muted) - .with_animation( - "arrow-circle", - Animation::new(Duration::from_secs(2)).repeat(), - |icon, delta| { - icon.transform(Transformation::rotate(percentage( - delta, - ))) - }, - ), - ) - .child( - Label::new("Generating…") - .size(LabelSize::Small) - .color(Color::Muted), - ) - .child(Divider::vertical()) - .child( - Button::new("cancel-generation", "Cancel") - .label_size(LabelSize::Small) - .key_binding(KeyBinding::for_action_in( - &editor::actions::Cancel, - &self.focus_handle, - cx, - )) - .on_click(move |_event, cx| { - focus_handle - .dispatch_action(&editor::actions::Cancel, cx); - }), - ), - ), - ) - }) } } diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index 0d4e5a8d54991..e2f14264d3c2d 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -122,7 +122,6 @@ impl AssistantPanel { workspace, language_registry, tools.clone(), - message_editor.focus_handle(cx), cx, ) }), @@ -163,7 +162,6 @@ impl AssistantPanel { self.workspace.clone(), self.language_registry.clone(), self.tools.clone(), - self.focus_handle(cx), cx, ) }); @@ -200,7 +198,6 @@ impl AssistantPanel { self.workspace.clone(), self.language_registry.clone(), self.tools.clone(), - self.focus_handle(cx), cx, ) }); diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index 4aad2a8361805..7a597849b933c 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/crates/assistant2/src/message_editor.rs @@ -4,17 +4,16 @@ use editor::actions::MoveUp; use editor::{Editor, EditorElement, EditorEvent, EditorStyle}; use fs::Fs; use gpui::{ - AppContext, DismissEvent, FocusableView, Model, Subscription, TextStyle, View, WeakModel, - WeakView, + pulsating_between, Animation, AnimationExt, AppContext, DismissEvent, FocusableView, Model, + Subscription, TextStyle, View, WeakModel, WeakView, }; use language_model::{LanguageModelRegistry, LanguageModelRequestTool}; use language_model_selector::LanguageModelSelector; use rope::Point; use settings::Settings; +use std::time::Duration; use theme::ThemeSettings; -use ui::{ - prelude::*, ButtonLike, ElevationIndex, KeyBinding, PopoverMenu, PopoverMenuHandle, Switch, -}; +use ui::{prelude::*, ButtonLike, KeyBinding, PopoverMenu, PopoverMenuHandle, Switch, TintColor}; use workspace::Workspace; use crate::assistant_model_selector::AssistantModelSelector; @@ -261,6 +260,8 @@ impl Render for MessageEditor { let focus_handle = self.editor.focus_handle(cx); let inline_context_picker = self.inline_context_picker.clone(); let bg_color = cx.theme().colors().editor_background; + let is_streaming_completion = self.thread.read(cx).is_streaming(); + let button_width = px(64.); v_flex() .key_context("MessageEditor") @@ -340,21 +341,64 @@ impl Render for MessageEditor { cx, )), ) - .child( - h_flex().gap_1().child(self.model_selector.clone()).child( - ButtonLike::new("chat") + .child(h_flex().gap_1().child(self.model_selector.clone()).child( + if is_streaming_completion { + ButtonLike::new("cancel-generation") + .width(button_width.into()) + .style(ButtonStyle::Tinted(TintColor::Accent)) + .child( + h_flex() + .w_full() + .justify_between() + .child( + Label::new("Cancel") + .size(LabelSize::Small) + .with_animation( + "pulsating-label", + Animation::new(Duration::from_secs(2)) + .repeat() + .with_easing(pulsating_between( + 0.4, 0.8, + )), + |label, delta| label.alpha(delta), + ), + ) + .children( + KeyBinding::for_action_in( + &editor::actions::Cancel, + &focus_handle, + cx, + ) + .map(|binding| binding.into_any_element()), + ), + ) + .on_click(move |_event, cx| { + focus_handle + .dispatch_action(&editor::actions::Cancel, cx); + }) + } else { + ButtonLike::new("submit-message") + .width(button_width.into()) .style(ButtonStyle::Filled) - .layer(ElevationIndex::ModalSurface) - .child(Label::new("Submit").size(LabelSize::Small)) - .children( - KeyBinding::for_action_in(&Chat, &focus_handle, cx) - .map(|binding| binding.into_any_element()), + .child( + h_flex() + .w_full() + .justify_between() + .child(Label::new("Submit").size(LabelSize::Small)) + .children( + KeyBinding::for_action_in( + &Chat, + &focus_handle, + cx, + ) + .map(|binding| binding.into_any_element()), + ), ) .on_click(move |_event, cx| { focus_handle.dispatch_action(&Chat, cx); - }), - ), - ), + }) + }, + )), ), ) }