Beacon/src/ui.rs
RTSDA dd086d0b30 feat: migrate to church-core crate for maximum code simplification
Major improvements leveraging the shared church-core library:

- **Replace custom Event struct**: Now using church-core::Event directly
  with built-in helper methods (formatted_date, clean_description, etc.)
- **Remove duplicate HTML cleaning**: Using church-core's clean_description()
- **Simplify API integration**: Replace custom ApiClient with church-core's
  ChurchApiClient and standardized endpoints
- **Remove redundant dependencies**: html2text, chrono no longer needed
- **Clean up configuration**: Remove unused cache settings, church-core handles caching
- **Streamline image loading**: Remove redundant HEAD requests, keep essential validation

Result: 37+ lines of duplicate code removed, 2 dependencies eliminated,
zero functionality lost. Project now maximizes church-core capabilities
while maintaining all original features.

Fixes: Eliminates code duplication and maintenance overhead
2025-08-16 21:54:13 -04:00

181 lines
6.6 KiB
Rust

use iced::widget::{column, row, image, container, text};
use iced::{Element, Length, Theme};
use church_core::Event;
use crate::{Message, LOADING_FRAMES, SETTINGS, cache::ImageCache};
pub fn render_event_title(event: &Event) -> Element<'_, Message, Theme> {
container(
text(&event.title)
.size(if event.title.len() > 50 {
SETTINGS.ui.font_sizes.title_small
} else {
SETTINGS.ui.font_sizes.title_large
})
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.title_color()),
..Default::default()
})
)
.width(Length::Fill)
.padding(SETTINGS.ui.spacing.container_padding)
.into()
}
pub fn render_event_image<'a>(
event: &Event,
image_cache: &ImageCache,
loading_frame: usize
) -> Element<'a, Message, Theme> {
container(
if let Some(ref image_url) = event.image {
if let Some(handle) = image_cache.get(image_url) {
container(
image::Image::new(handle.clone())
.width(Length::Fixed(SETTINGS.ui.image_width))
.height(Length::Fixed(SETTINGS.ui.image_height))
)
.style(|_: &Theme| container::Style {
background: Some(SETTINGS.theme.image_bg_color().into()),
..Default::default()
})
} else {
container(
column![
text(LOADING_FRAMES[loading_frame])
.size(SETTINGS.ui.font_sizes.loading_animation)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.accent_color()),
..Default::default()
}),
text("Loading image...")
.size(SETTINGS.ui.font_sizes.loading_text)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.secondary_text_color()),
..Default::default()
})
]
.spacing(SETTINGS.ui.spacing.loading_container_spacing)
.align_x(iced::alignment::Horizontal::Center)
)
}
} else {
container(
text("No image available")
.size(SETTINGS.ui.font_sizes.no_image_text)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.secondary_text_color()),
..Default::default()
})
)
}
)
.width(Length::Fixed(SETTINGS.ui.image_width))
.height(Length::Fixed(SETTINGS.ui.image_height))
.style(|_: &Theme| container::Style {
background: Some(SETTINGS.theme.image_bg_color().into()),
..Default::default()
})
.into()
}
pub fn render_event_category(event: &Event) -> Element<'_, Message, Theme> {
container(
text(event.category.to_string().to_uppercase())
.size(SETTINGS.ui.font_sizes.category)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.text_color()),
..Default::default()
})
)
.padding(SETTINGS.ui.spacing.category_container_padding)
.style(|_: &Theme| container::Style {
background: Some(SETTINGS.theme.category_color().into()),
..Default::default()
})
.into()
}
pub fn render_event_datetime(event: &Event) -> Element<'_, Message, Theme> {
container(
column![
text(event.formatted_date())
.size(SETTINGS.ui.font_sizes.date)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.date_color()),
..Default::default()
}),
text(format!("{} - {}", event.formatted_start_time(), event.formatted_end_time()))
.size(SETTINGS.ui.font_sizes.time)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.time_color()),
..Default::default()
})
]
.spacing(SETTINGS.ui.spacing.datetime_container_spacing)
)
.padding(SETTINGS.ui.spacing.datetime_container_padding)
.into()
}
pub fn render_event_location(event: &Event) -> Element<'_, Message, Theme> {
if !event.location.is_empty() {
container(
row![
text("") // Location/target symbol
.size(SETTINGS.ui.font_sizes.location_icon)
.font(iced::Font::with_name("Segoe UI Symbol"))
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.location_icon_color()),
..Default::default()
}),
text(&event.location)
.size(SETTINGS.ui.font_sizes.location_text)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.secondary_text_color()),
..Default::default()
})
]
.spacing(SETTINGS.ui.spacing.location_row_spacing)
.align_y(iced::Alignment::Center)
)
.padding(SETTINGS.ui.spacing.location_row_padding)
.into()
} else {
container(text("")).into()
}
}
pub fn render_event_description(event: &Event) -> Element<'_, Message, Theme> {
container(
text(event.clean_description())
.size(SETTINGS.ui.font_sizes.description)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.text_color()),
..Default::default()
})
)
.width(Length::Fill)
.height(Length::Fill)
.padding(SETTINGS.ui.spacing.description_container_padding)
.style(|_: &Theme| container::Style {
background: Some(SETTINGS.theme.description_bg_color().into()),
..Default::default()
})
.into()
}
pub fn render_loading_screen() -> Element<'static, Message, Theme> {
container(
text("Loading events...")
.size(SETTINGS.ui.font_sizes.loading_events)
.style(|_: &Theme| text::Style {
color: Some(SETTINGS.theme.accent_color()),
..Default::default()
})
)
.width(Length::Fill)
.height(Length::Fill)
.center_x(Length::Fill)
.center_y(Length::Fill)
.into()
}