Files
galaxy/app/src/auth/login_error_modal.rs
T

140 lines
4.5 KiB
Rust

use std::borrow::Cow;
use pathfinder_color::ColorU;
use warpui::{
elements::{
Align, Border, ConstrainedBox, Container, CornerRadius, Flex, ParentElement, Shrinkable,
},
ui_components::{
components::{UiComponent, UiComponentStyles},
text::Span,
},
AppContext, Element, SingletonEntity as _,
};
use crate::{
appearance::Appearance,
modal::MODAL_CORNER_RADIUS,
root_view::unthemed_window_border,
themes::theme::{Blend, Fill},
};
/// A full-window login error.
///
/// This is used for uncommon login error states, such as:
/// * A user needing to link SSO after logging in with an incorrect Firebase provider.
/// * An error importing the user from a host web application.
pub struct LoginErrorModal {
modal_styles: UiComponentStyles,
header_styles: UiComponentStyles,
header: Option<Cow<'static, str>>,
detail_styles: UiComponentStyles,
detail: Option<Cow<'static, str>>,
action: Option<Box<dyn Element>>,
window_corner_radius: CornerRadius,
}
impl LoginErrorModal {
pub fn new(app: &AppContext) -> Self {
let appearance = Appearance::as_ref(app);
let modal_styles = UiComponentStyles {
width: Some(480.),
height: Some(280.),
border_color: Some(Fill::black().blend(&Fill::white().with_opacity(15)).into()),
border_width: Some(1.),
..Default::default()
};
let header_styles = UiComponentStyles {
font_family_id: Some(appearance.ui_font_family()),
font_size: Some(appearance.header_font_size()),
..Default::default()
};
let detail_styles = UiComponentStyles {
font_family_id: Some(appearance.ui_font_family()),
font_size: Some(appearance.ui_font_size()),
font_color: Some(appearance.theme().nonactive_ui_text_color().into()),
..Default::default()
};
LoginErrorModal {
modal_styles,
header_styles,
detail_styles,
window_corner_radius: app.windows().window_corner_radius(),
header: None,
detail: None,
action: None,
}
}
pub fn with_header(mut self, header: impl Into<Cow<'static, str>>) -> Self {
self.header = Some(header.into());
self
}
pub fn with_detail(mut self, detail: impl Into<Cow<'static, str>>) -> Self {
self.detail = Some(detail.into());
self
}
pub fn with_action(mut self, action: Box<dyn Element>) -> Self {
self.action = Some(action);
self
}
}
impl UiComponent for LoginErrorModal {
type ElementType = Container;
fn build(self) -> Self::ElementType {
let mut contents = Flex::column();
if let Some(header) = self.header {
contents.add_child(
Shrinkable::new(
1.,
Align::new(Span::new(header, self.header_styles).build().finish()).finish(),
)
.finish(),
);
}
if let Some(detail) = self.detail {
contents.add_child(
Shrinkable::new(
1.,
Align::new(Span::new(detail, self.detail_styles).build().finish()).finish(),
)
.finish(),
);
}
if let Some(action) = self.action {
contents.add_child(Shrinkable::new(1., Align::new(action).finish()).finish());
}
let modal = Container::new(
ConstrainedBox::new(contents.finish())
.with_width(self.modal_styles.width.unwrap_or_default())
.with_height(self.modal_styles.height.unwrap_or_default())
.finish(),
)
.with_border(
Border::all(self.modal_styles.border_width.unwrap_or_default())
.with_border_fill(self.modal_styles.border_color.unwrap_or_default()),
)
.with_corner_radius(CornerRadius::with_all(MODAL_CORNER_RADIUS))
.finish();
Container::new(Align::new(modal).finish())
.with_background_color(ColorU::black())
.with_corner_radius(self.window_corner_radius)
.with_border(unthemed_window_border())
}
fn with_style(mut self, style: UiComponentStyles) -> Self {
self.modal_styles = self.modal_styles.merge(style);
self.header_styles = self.header_styles.merge(style);
self.detail_styles = self.detail_styles.merge(style);
self
}
}