Files
galaxy/app/src/reward_view.rs
T
Ryan WardandClaude Opus 4.6 6f54e2cb30 v1.4.0: Auto-compact streaming, Bedrock summarization support, subagent orchestration, and Galaxy rebrand continuation
Major features:
- Auto-compact: triggers conversation summarization when context window >= 85%,
  compacts Bedrock message history to a summary pair, and tracks live context tokens
- Bedrock summarization: plumbs `is_summarization` flag through translator/client/response
  pipeline, handles SummarizeConversation input type, and marks `summarized` in metadata
- Session restore: rebuilds bedrock_message_history from persisted task messages via
  newly-public `convert_proto_message`, preventing empty history on reconnect
- Subagent orchestration: adds SubagentQuestion/Answer/CompletionSummary event types,
  parent-child question routing with depth limits, retry counting, and drain methods
- Summarization UI: inline SummarizationView in AI blocks with progress/finished states

Refactors:
- Rename WarpTheme → GalaxyTheme across ~100 files (rebrand continuation)
- Rename warp_home_config_dir → galaxy_home_config_dir and related path functions
- Predefined rules: replace "System Defined Rule #N" with descriptive names
  (e.g. "Correctness Over Speed", "Never Guess") and add lookup helpers
- Usage view: replace cumulative input/output token display with live context tokens,
  cache hit rate calculation, and separate cache read/write stats
- Telemetry: remove verbose doc comments, simplify trait definitions
- Facts view: simplify delete permission check (always allow local deletion)
- Remove warp_managed_paths_watcher.rs (dead code)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 11:59:37 -05:00

215 lines
6.5 KiB
Rust

use galaxy_core::ui::builder::UiBuilder;
use galaxyui::{
accessibility::{AccessibilityContent, GalaxyA11yRole},
elements::{Align, Container, Element, Flex, MouseStateHandle, ParentElement},
keymap::FixedBinding,
ui_components::button::ButtonVariant,
ui_components::components::{Coords, UiComponent, UiComponentStyles},
AppContext, Entity, SingletonEntity, TypedActionView, View, ViewContext,
};
use crate::appearance::Appearance;
// Constants for the *tada* emoji rendering
// Note: Long-term, we should convert this to a SVG, since there's no guarantee the emoji will be
// always renderable or that the size will be the same
const TADA: &str = "🎉";
const TADA_FONT_SIZE: f32 = 60.;
const TADA_MARGIN_TOP: f32 = 0.;
const TADA_MARGIN_BOTTOM: f32 = 50.;
// Constants for the main title
const TITLE: &str = "Congrats!";
const TITLE_FONT_SIZE: f32 = 20.;
const TITLE_MARGIN_BOTTOM: f32 = 25.;
// Constants for the subtitle
const SUBTITLE_SENT_REFERRAL: &str =
"You earned an exclusive Galaxy theme for referring someone to Galaxy.";
const SUBTITLE_RECEIVED_REFERRAL: &str =
"You earned an exclusive Galaxy theme for being referred to Galaxy.";
const SUBTITLE_FONT_SIZE: f32 = 14.;
const SUBTITLE_MARGIN_BOTTOM: f32 = 40.;
// Constants for the button
const BUTTON_CTA: &str = "Try it out!";
const BUTTON_FONT_SIZE: f32 = 14.;
const BUTTON_HEIGHT: f32 = 45.;
const BUTTON_WIDTH: f32 = 240.;
const BUTTON_MARGIN_BOTTOM: f32 = 14.;
const ACCESSIBILITY_HELP: &str = "Press enter to open the theme chooser or escape to dismiss.";
pub fn init(app: &mut AppContext) {
use galaxyui::keymap::macros::*;
app.register_fixed_bindings([FixedBinding::new(
"enter",
RewardAction::OpenThemePicker,
id!("RewardView"),
)]);
}
#[derive(Debug)]
pub enum RewardAction {
OpenThemePicker,
}
pub enum RewardEvent {
OpenThemePicker,
}
#[derive(Clone, Copy)]
pub enum RewardKind {
SentReferralTheme,
ReceivedReferralTheme,
}
pub struct RewardView {
cta_mouse_state: MouseStateHandle,
kind: RewardKind,
}
impl Default for RewardView {
fn default() -> Self {
Self::new()
}
}
impl RewardView {
pub fn new() -> Self {
Self {
cta_mouse_state: Default::default(),
// Default to the Sent Referral Reward, which was previously the only thing this view
// was used for. However, this will be updated when the view is shown, so the default
// isn't super relevant
kind: RewardKind::SentReferralTheme,
}
}
pub fn update_reward_kind(&mut self, kind: RewardKind, ctx: &mut ViewContext<Self>) {
self.kind = kind;
ctx.notify();
}
fn subtitle(&self) -> &'static str {
match self.kind {
RewardKind::SentReferralTheme => SUBTITLE_SENT_REFERRAL,
RewardKind::ReceivedReferralTheme => SUBTITLE_RECEIVED_REFERRAL,
}
}
fn render_icon(&self, ui_builder: &UiBuilder) -> Box<dyn Element> {
Align::new(
ui_builder
.span(TADA)
.with_style(UiComponentStyles {
font_size: Some(TADA_FONT_SIZE),
margin: Some(Coords {
top: TADA_MARGIN_TOP,
bottom: TADA_MARGIN_BOTTOM,
..Default::default()
}),
..Default::default()
})
.build()
.finish(),
)
.finish()
}
fn render_title(&self, ui_builder: &UiBuilder) -> Box<dyn Element> {
Align::new(
ui_builder
.span(TITLE)
.with_style(UiComponentStyles {
font_size: Some(TITLE_FONT_SIZE),
margin: Some(Coords {
bottom: TITLE_MARGIN_BOTTOM,
..Default::default()
}),
..Default::default()
})
.build()
.finish(),
)
.finish()
}
fn render_subtitle(&self, ui_builder: &UiBuilder) -> Box<dyn Element> {
Align::new(
ui_builder
.paragraph(self.subtitle().to_owned())
.with_style(UiComponentStyles {
font_size: Some(SUBTITLE_FONT_SIZE),
margin: Some(Coords {
bottom: SUBTITLE_MARGIN_BOTTOM,
..Default::default()
}),
..Default::default()
})
.build()
.finish(),
)
.finish()
}
fn render_button(&self, ui_builder: &UiBuilder) -> Box<dyn Element> {
Align::new(
Container::new(
ui_builder
.button(ButtonVariant::Accent, self.cta_mouse_state.clone())
.with_centered_text_label(BUTTON_CTA.into())
.with_style(UiComponentStyles {
height: Some(BUTTON_HEIGHT),
width: Some(BUTTON_WIDTH),
font_size: Some(BUTTON_FONT_SIZE),
..Default::default()
})
.build()
.on_click(|ctx, _, _| ctx.dispatch_typed_action(RewardAction::OpenThemePicker))
.finish(),
)
.with_margin_bottom(BUTTON_MARGIN_BOTTOM)
.finish(),
)
.finish()
}
}
impl Entity for RewardView {
type Event = RewardEvent;
}
impl View for RewardView {
fn ui_name() -> &'static str {
"RewardView"
}
fn accessibility_contents(&self, _: &AppContext) -> Option<AccessibilityContent> {
Some(AccessibilityContent::new(
format!("{} {}", TITLE, self.subtitle()),
ACCESSIBILITY_HELP,
GalaxyA11yRole::WindowRole,
))
}
fn render(&self, app: &AppContext) -> Box<dyn Element> {
let ui_builder = Appearance::as_ref(app).ui_builder();
Flex::column()
.with_child(self.render_icon(ui_builder))
.with_child(self.render_title(ui_builder))
.with_child(self.render_subtitle(ui_builder))
.with_child(self.render_button(ui_builder))
.finish()
}
}
impl TypedActionView for RewardView {
type Action = RewardAction;
fn handle_action(&mut self, action: &Self::Action, ctx: &mut ViewContext<Self>) {
match action {
RewardAction::OpenThemePicker => {
ctx.emit(RewardEvent::OpenThemePicker);
}
}
}
}