use roost::events::OnEvent;
use roost::drawable::{Align, Color, Image};
use roost::layouts::{Column, Stack, Row, Padding, Offset, Size};
use roost::{Context, Component};
use roost::emitters;
use crate::interactions;
use crate::components::{Rectangle, Icon, Text, TextSize, ExpandableText, TextStyle};
use crate::components::avatar::{Avatar, AvatarContent, AvatarSize};
use crate::plugin::PelicanUI;
use crate::utils::TitleSubtitle;
#[derive(Debug, Component)]
pub struct ListItem(Stack, emitters::Button<interactions::Button>);
impl OnEvent for ListItem {}
impl ListItem {
pub fn new(
ctx: &mut Context,
avatar: Option<AvatarContent>,
left: ListItemInfoLeft,
right: Option<TitleSubtitle>,
icon_l: Option<&'static str>,
icon_r: Option<&'static str>,
on_click: impl FnMut(&mut Context) + 'static,
) -> Self {
let list_item = _ListItem::new(ctx, avatar, left, right, icon_l, icon_r);
ListItem(Stack::default(), interactions::Button::new(list_item, None::<_ListItem>, None::<_ListItem>, None::<_ListItem>, false, Box::new(on_click)))
}
}
#[derive(Component)]
pub struct _ListItem(Stack, Rectangle, ListItemContent);
impl _ListItem {
pub fn new(
ctx: &mut Context,
avatar: Option<AvatarContent>,
left: ListItemInfoLeft,
right: Option<TitleSubtitle>,
icon_l: Option<&'static str>,
icon_r: Option<&'static str>,
) -> Self {
let background = ctx.get::<PelicanUI>().get().0.theme().colors.background.primary;
let content = ListItemContent::new(ctx, avatar, left, right, icon_l, icon_r);
let layout = Stack(Offset::Start, Offset::Center, Size::Fill, Size::custom(|heights: Vec<(f32, f32)>| heights[1]), Padding(0.0, 16.0, 0.0, 16.0));
_ListItem(layout, Rectangle::new(background, 0.0, None), content)
}
}
impl OnEvent for _ListItem {}
impl std::fmt::Debug for _ListItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "_ListItem")
}
}
#[derive(Debug, Component)]
struct ListItemContent(Row, Option<Image>, Option<Avatar>, ListItemData, Option<Image>);
impl OnEvent for ListItemContent {}
impl ListItemContent {
#[allow(clippy::too_many_arguments)]
fn new(
ctx: &mut Context,
avatar: Option<AvatarContent>,
left: ListItemInfoLeft,
right: Option<TitleSubtitle>,
icon_l: Option<&'static str>,
icon_r: Option<&'static str>,
) -> Self {
let avatar = avatar.map(|data| Avatar::new(ctx, data, None, false, AvatarSize::Md, None));
let content = ListItemData::new(ctx, left, right);
let icon_l = icon_l.map(|i| {let c = ctx.get::<PelicanUI>().get().0.theme().colors.text.primary; Icon::new(ctx, i, c, 24.0)});
let icon_r = icon_r.map(|i| {let c = ctx.get::<PelicanUI>().get().0.theme().colors.text.primary; Icon::new(ctx, i, c, 16.0)});
ListItemContent(Row::center(16.0), icon_l, avatar, content, icon_r)
}
}
#[derive(Debug, Component)]
struct ListItemData(Row, LeftData, Option<RightData>);
impl OnEvent for ListItemData {}
impl ListItemData {
fn new(ctx: &mut Context, left: ListItemInfoLeft, right: Option<TitleSubtitle>) -> Self {
ListItemData(Row::start(8.0), LeftData::new(ctx, left), right.map(|info| RightData::new(ctx, info)))
}
}
#[derive(Debug, Component)]
struct LeftData(Column, TitleRow, ExpandableText, Option<ExpandableText>);
impl OnEvent for LeftData {}
impl LeftData {
pub fn new(ctx: &mut Context, info: ListItemInfoLeft) -> Self {
let layout = Column::new(4.0, Offset::Start, Size::Fill, Padding::default());
let subtitle = ExpandableText::new(ctx, &info.title.subtitle, TextSize::Xs, TextStyle::Secondary, Align::Left, Some(2));
let description = info.description.map(|text| ExpandableText::new(ctx, &text, TextSize::Xs, TextStyle::Secondary, Align::Left, Some(2)));
LeftData(layout, TitleRow::new(ctx, &info.title.title, info.flair), subtitle, description)
}
}
#[derive(Debug, Component)]
struct TitleRow(Row, Text, Option<Image>);
impl OnEvent for TitleRow {}
impl TitleRow {
fn new(ctx: &mut Context, title: &str, flair: Option<(&'static str, Color)>) -> Self {
let layout = Row::new(4.0, Offset::Center, Size::Fit, Padding::default());
let text = Text::new(ctx, title, TextSize::H5, TextStyle::Heading, Align::Left, Some(1));
let flair = flair.map(|(name, color)| Icon::new(ctx, name, color, 16.0));
TitleRow(layout, text, flair)
}
}
#[derive(Debug, Component)]
struct RightData(Column, Text, Text);
impl OnEvent for RightData {}
impl RightData {
fn new(ctx: &mut Context, info: TitleSubtitle) -> Self {
let title = Text::new(ctx, &info.title, TextSize::H5, TextStyle::Heading, Align::Left, Some(1));
let subtitle = Text::new(ctx, &info.subtitle, TextSize::Xs, TextStyle::Secondary, Align::Left, Some(2));
RightData(Column::end(4.0), title, subtitle)
}
}
pub struct ListItemInfoLeft {
title: TitleSubtitle,
flair: Option<(&'static str, Color)>,
description: Option<String>,
}
impl ListItemInfoLeft {
pub fn new(title: &str, subtitle: &str, description: Option<&str>, flair: Option<(&'static str, Color)>) -> Self {
ListItemInfoLeft {
title: TitleSubtitle::new(title, subtitle),
description: description.map(|text| text.to_string()),
flair,
}
}
}
#[derive(Debug, Component)]
pub struct ListItemGroup(Column, Vec<ListItem>);
impl OnEvent for ListItemGroup {}
impl ListItemGroup {
pub fn new(items: Vec<ListItem>) -> Self {
ListItemGroup(Column::start(0.0), items)
}
}