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.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 { 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 { 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 { 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 { 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 { Some(AccessibilityContent::new( format!("{} {}", TITLE, self.subtitle()), ACCESSIBILITY_HELP, GalaxyA11yRole::WindowRole, )) } fn render(&self, app: &AppContext) -> Box { 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) { match action { RewardAction::OpenThemePicker => { ctx.emit(RewardEvent::OpenThemePicker); } } } }