135 lines
5.0 KiB
Rust
135 lines
5.0 KiB
Rust
use crate::link::NostrLink;
|
|
use crate::route::{RouteServices, RouteType};
|
|
use crate::stream_info::{StreamInfo, StreamStatus};
|
|
use crate::theme::{NEUTRAL_800, NEUTRAL_900, PRIMARY, ROUNDING_DEFAULT};
|
|
use crate::widgets::avatar::Avatar;
|
|
use crate::widgets::NostrWidget;
|
|
use eframe::epaint::{Rounding, Vec2};
|
|
use egui::epaint::RectShape;
|
|
use egui::load::TexturePoll;
|
|
use egui::{
|
|
vec2, Color32, CursorIcon, FontId, Label, Pos2, Rect, Response, RichText, Sense, TextWrapMode,
|
|
Ui,
|
|
};
|
|
use nostrdb::Note;
|
|
|
|
pub struct StreamEvent<'a> {
|
|
event: &'a Note<'a>,
|
|
}
|
|
|
|
impl<'a> StreamEvent<'a> {
|
|
pub fn new(event: &'a Note<'a>) -> Self {
|
|
Self { event }
|
|
}
|
|
}
|
|
impl NostrWidget for StreamEvent<'_> {
|
|
fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response {
|
|
ui.vertical(|ui| {
|
|
ui.style_mut().spacing.item_spacing = Vec2::new(12., 16.);
|
|
|
|
let host = self.event.host();
|
|
let host_profile = services.profile(host);
|
|
|
|
let w = ui.available_width();
|
|
let h = (w / 16.0) * 9.0;
|
|
|
|
let (response, painter) = ui.allocate_painter(Vec2::new(w, h), Sense::click());
|
|
|
|
let cover = if ui.is_visible() {
|
|
self.event.image().map(|p| services.image(p))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(cover) = cover.map(|c| {
|
|
c.rounding(Rounding::same(12.))
|
|
.load_for_size(painter.ctx(), Vec2::new(w, h))
|
|
}) {
|
|
match cover {
|
|
Ok(TexturePoll::Ready { texture }) => {
|
|
painter.add(RectShape {
|
|
rect: response.rect,
|
|
rounding: Rounding::same(ROUNDING_DEFAULT),
|
|
fill: Color32::WHITE,
|
|
stroke: Default::default(),
|
|
blur_width: 0.0,
|
|
fill_texture_id: texture.id,
|
|
uv: Rect::from_min_max(Pos2::new(0.0, 0.0), Pos2::new(1.0, 1.0)),
|
|
});
|
|
}
|
|
_ => {
|
|
painter.rect_filled(response.rect, ROUNDING_DEFAULT, NEUTRAL_800);
|
|
}
|
|
}
|
|
} else {
|
|
painter.rect_filled(response.rect, ROUNDING_DEFAULT, NEUTRAL_800);
|
|
}
|
|
|
|
let overlay_label_pad = Vec2::new(5., 5.);
|
|
let live_label_text = self.event.status().to_string().to_uppercase();
|
|
let live_label_color = if self.event.status() == StreamStatus::Live {
|
|
PRIMARY
|
|
} else {
|
|
NEUTRAL_900
|
|
};
|
|
let live_label =
|
|
painter.layout_no_wrap(live_label_text, FontId::default(), Color32::WHITE);
|
|
|
|
let overlay_react = response.rect.shrink(8.0);
|
|
let live_label_pos = overlay_react.min
|
|
+ vec2(
|
|
overlay_react.width() - live_label.rect.width() - (overlay_label_pad.x * 2.),
|
|
0.0,
|
|
);
|
|
let live_label_background = Rect::from_two_pos(
|
|
live_label_pos,
|
|
live_label_pos + live_label.size() + (overlay_label_pad * 2.),
|
|
);
|
|
painter.rect_filled(live_label_background, 8., live_label_color);
|
|
painter.galley(
|
|
live_label_pos + overlay_label_pad,
|
|
live_label,
|
|
Color32::PLACEHOLDER,
|
|
);
|
|
|
|
if let Some(viewers) = self.event.viewers() {
|
|
let viewers_label = painter.layout_no_wrap(
|
|
format!("{} viewers", viewers),
|
|
FontId::default(),
|
|
Color32::WHITE,
|
|
);
|
|
let rect_start =
|
|
overlay_react.max - viewers_label.size() - (overlay_label_pad * 2.0);
|
|
let pos = Rect::from_two_pos(rect_start, overlay_react.max);
|
|
painter.rect_filled(pos, 8., NEUTRAL_900);
|
|
painter.galley(
|
|
rect_start + overlay_label_pad,
|
|
viewers_label,
|
|
Color32::PLACEHOLDER,
|
|
);
|
|
}
|
|
let response = response.on_hover_and_drag_cursor(CursorIcon::PointingHand);
|
|
if response.clicked() {
|
|
services.navigate(RouteType::EventPage {
|
|
link: NostrLink::from_note(self.event),
|
|
event: None,
|
|
});
|
|
}
|
|
ui.horizontal(|ui| {
|
|
Avatar::from_profile(&host_profile)
|
|
.size(40.)
|
|
.render(ui, services.ctx.img_cache);
|
|
let title = RichText::new(self.event.title().unwrap_or("Untitled"))
|
|
.size(16.)
|
|
.color(Color32::WHITE);
|
|
ui.add(Label::new(title).wrap_mode(TextWrapMode::Truncate));
|
|
})
|
|
})
|
|
.response
|
|
}
|
|
|
|
fn update(&mut self, _services: &mut RouteServices<'_, '_>) -> anyhow::Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|