Files
galaxy/app/src/wasm_nux_dialog.rs
T

289 lines
12 KiB
Rust

use settings::Setting as _;
use warpui::elements::{
Align, CrossAxisAlignment, Flex, MainAxisSize, MouseStateHandle, ParentElement as _,
};
use warpui::fonts::Weight;
use warpui::platform::Cursor;
use warpui::ui_components::button::ButtonVariant;
use warpui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
use warpui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
use crate::appearance::Appearance;
use crate::report_if_error;
use crate::settings::app_installation_detection::{
UserAppInstallDetectionSettings, UserAppInstallStatus,
};
use crate::settings::{NativePreferenceSettings, UserNativePreference};
use crate::ui_components::dialog::{dialog_styles, Dialog};
use crate::uri::web_intent_parser::{self, WebIntent};
const CLOSE_BUTTON_DIAMETER: f32 = 20.;
const DIALOG_WIDTH: f32 = 350.;
const DIALOG_PADDING: f32 = 24.;
const OPEN_NATIVE_BUTTON_WIDTH: f32 = 260.;
const OPEN_NATIVE_BUTTON_HEIGHT: f32 = 40.;
#[derive(Debug, Copy, Clone)]
pub enum WasmNUXDialogAction {
/// Close and dismiss the dialog
Close,
/// Closes the dialog and sets the native preference to web
SetWebAndClose,
/// Closes the dialog and open on the desktop
OpenNativeAndClose,
/// Open the Warp download page
OpenDownloadDesktopAppLink,
/// Open a link to learn more about Warp
LearnMore,
}
pub enum WasmNUXDialogEvent {
Close,
}
/// A dialog that prompts the user to:
/// * Download Warp if they haven't already
/// * Explicitly choose between native and web.
pub struct WasmNUXDialog {
close_mouse_state: MouseStateHandle,
confirm_mouse_state: MouseStateHandle,
download_warp_mouse_state: MouseStateHandle,
learn_more_mouse_state: MouseStateHandle,
requested_download: bool,
}
impl Entity for WasmNUXDialog {
type Event = WasmNUXDialogEvent;
}
impl WasmNUXDialog {
pub fn new() -> Self {
Self {
close_mouse_state: Default::default(),
confirm_mouse_state: Default::default(),
download_warp_mouse_state: Default::default(),
learn_more_mouse_state: Default::default(),
requested_download: false,
}
}
/// Whether or not the new-user dialog should be shown.
///
/// It's shown if all of the following are true:
/// * Not on a mobile device (mobile users can't use the desktop app)
/// * The user does not have an explicit native/web preference
/// * The user hasn't dismissed the dialog
///
/// If the user dismisses the dialog without choosing a preference, we'll continue to use the default autodetection
/// behavior: if Warp is installed, redirect to it; otherwise stay on the web.
pub fn should_display(app: &AppContext) -> bool {
// Don't show on mobile devices - they can't use the desktop app
if galaxyui::platform::wasm::is_mobile_device() {
return false;
}
let preference_settings = NativePreferenceSettings::handle(app).as_ref(app);
*preference_settings.user_native_redirect_preference.value()
== UserNativePreference::NotSelected
&& !*preference_settings.preference_dialog_dismissed.value()
}
fn render_dialog_button(
text: impl Into<String>,
action: WasmNUXDialogAction,
mouse_state: &MouseStateHandle,
appearance: &Appearance,
) -> Box<dyn Element> {
let button_style = UiComponentStyles {
font_size: Some(14.),
font_weight: Some(Weight::Bold),
width: Some(OPEN_NATIVE_BUTTON_WIDTH),
height: Some(OPEN_NATIVE_BUTTON_HEIGHT),
..Default::default()
};
appearance
.ui_builder()
.button(ButtonVariant::Accent, mouse_state.clone())
.with_centered_text_label(text.into())
.with_style(button_style)
.build()
.with_cursor(Cursor::PointingHand)
.on_click(move |ctx, _, _| {
ctx.dispatch_typed_action(action);
})
.finish()
}
}
impl View for WasmNUXDialog {
fn ui_name() -> &'static str {
"WasmNUXDialog"
}
fn render(&self, app: &AppContext) -> Box<dyn Element> {
let appearance = Appearance::handle(app).as_ref(app);
// There are two general cases with the dialog:
// 1. The user doesn't have Warp installed - treat them as a potential new user and encourage downloading Warp.
// 2. The user has Warp installed, but clicked through to the web - ask if they want to always default to web.
// As a sub-state of case 1, if the user clicks the download button, we provide an intent into the app.
let close_button = appearance
.ui_builder()
.close_button(CLOSE_BUTTON_DIAMETER, self.close_mouse_state.clone())
.build()
.with_cursor(Cursor::PointingHand)
.on_click(move |ctx, _, _| {
ctx.dispatch_typed_action(WasmNUXDialogAction::Close);
})
.finish();
let app_install_detected = UserAppInstallDetectionSettings::handle(app)
.as_ref(app)
.user_app_installation_detected
.value();
let dialog_styles = UiComponentStyles {
width: Some(DIALOG_WIDTH),
padding: Some(Coords::uniform(DIALOG_PADDING)),
..dialog_styles(appearance)
};
let dialog = if self.requested_download {
Dialog::new(
"Open in Galaxy Desktop?".to_string(),
Some("Future links will automatically open on desktop.".to_string()),
dialog_styles,
)
.with_bottom_row_child(Self::render_dialog_button(
"Open in Galaxy",
WasmNUXDialogAction::OpenNativeAndClose,
&self.confirm_mouse_state,
appearance,
))
} else if app_install_detected == &UserAppInstallStatus::NotDetected {
Dialog::new("Download Galaxy Desktop?".to_string(), None, dialog_styles)
.with_child(
Flex::column()
.with_cross_axis_alignment(CrossAxisAlignment::Stretch)
.with_main_axis_size(MainAxisSize::Min)
.with_child(
appearance
.ui_builder()
.span("Galaxy is a clone of Warp built for Samsung to use with Bedrock. Get the best features of Warp with the security provided by Bedrock!")
.with_style(UiComponentStyles {
font_weight: Some(Weight::Thin),
font_color: Some(
appearance
.theme()
.main_text_color(appearance.theme().surface_1())
.into_solid(),
),
..Default::default()
})
.with_soft_wrap()
.build()
.finish(),
)
.with_child(
Align::new(
appearance
.ui_builder()
.link(
"Learn more".to_string(),
None,
Some(Box::new(|ctx| {
ctx.dispatch_typed_action(
WasmNUXDialogAction::LearnMore,
)
})),
self.learn_more_mouse_state.clone(),
)
.build()
.finish(),
)
.left()
.finish(),
)
.finish(),
)
.with_bottom_row_child(Self::render_dialog_button(
"Download",
WasmNUXDialogAction::OpenDownloadDesktopAppLink,
&self.download_warp_mouse_state,
appearance,
))
} else {
let object_kind = match web_intent_parser::current_web_intent() {
Some(WebIntent::DriveObject(_)) => "Galaxy Drive objects",
Some(WebIntent::SessionView(_)) => "shared sessions",
_ => "Galaxy links",
};
Dialog::new(
format!("Always open {object_kind} on the web?"),
Some("You can change this at any time in settings.".to_string()),
dialog_styles,
)
.with_bottom_row_child(Self::render_dialog_button(
"Yes",
WasmNUXDialogAction::SetWebAndClose,
&self.confirm_mouse_state,
appearance,
))
};
dialog.with_close_button(close_button).build().finish()
}
}
impl TypedActionView for WasmNUXDialog {
type Action = WasmNUXDialogAction;
fn handle_action(&mut self, action: &Self::Action, ctx: &mut ViewContext<Self>) {
match action {
WasmNUXDialogAction::Close => {
NativePreferenceSettings::handle(ctx).update(ctx, |settings, ctx| {
report_if_error!(settings.preference_dialog_dismissed.set_value(true, ctx))
});
ctx.emit(WasmNUXDialogEvent::Close);
}
WasmNUXDialogAction::SetWebAndClose => {
if let Err(e) = NativePreferenceSettings::handle(ctx).update(ctx, |setting, ctx| {
setting
.user_native_redirect_preference
.set_value(UserNativePreference::Web, ctx)
}) {
log::error!("Failed to set the open preference to web. {e}");
};
ctx.emit(WasmNUXDialogEvent::Close);
}
WasmNUXDialogAction::OpenNativeAndClose => {
// We intentionally do not set the native preference here, in case the user hasn't actually installed Warp.
// If they have, on subsequent loads, we'll detect that Warp is installed and redirect to the desktop.
ctx.emit(WasmNUXDialogEvent::Close);
if let Some(url) = web_intent_parser::parse_web_intent_from_current_url() {
// Signals to the react app to open the native app.
crate::platform::wasm::emit_event(
crate::platform::wasm::GalaxyEvent::OpenOnNative {
url: String::from(url.as_str()),
},
);
} else {
log::error!("Failed to open in app. Could not determine current url");
}
}
WasmNUXDialogAction::OpenDownloadDesktopAppLink => {
ctx.open_url("https://app.warp.dev/get_warp");
self.requested_download = true;
ctx.notify();
}
WasmNUXDialogAction::LearnMore => {
ctx.open_url("https://www.warp.dev");
}
}
}
}