a2ui_tui/components/
video.rs1use ratatui::{
4 Frame,
5 layout::Rect,
6 style::{Color, Style},
7 text::{Line, Span},
8 widgets::Paragraph,
9};
10
11use a2ui_base::model::component_context::ComponentContext;
12use a2ui_base::protocol::common_types::DynamicString;
13use crate::component_impl::TuiComponent;
14
15pub struct VideoComponent;
21
22impl TuiComponent for VideoComponent {
23 fn name(&self) -> &'static str {
24 "Video"
25 }
26
27 fn render(
28 &self,
29 ctx: &ComponentContext,
30 area: Rect,
31 frame: &mut Frame,
32 _render_child: &mut dyn FnMut(&str, Rect, &mut Frame, &str),
33 _measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
34 ) {
35 let comp_model = match ctx.components.get(&ctx.component_id) {
36 Some(m) => m,
37 None => return,
38 };
39
40 let inner = Rect {
42 x: area.x + 1,
43 y: area.y + 1,
44 width: area.width.saturating_sub(2),
45 height: area.height.saturating_sub(2),
46 };
47
48 if inner.width == 0 || inner.height == 0 {
49 return;
50 }
51
52 let url = match comp_model.get_property::<DynamicString>("url") {
54 Some(ds) => ctx.data_context.resolve_dynamic_string(&ds),
55 None => String::new(),
56 };
57
58 let poster = comp_model.get_property::<DynamicString>("posterUrl")
60 .map(|ds| ctx.data_context.resolve_dynamic_string(&ds));
61
62 let display_text = if !url.is_empty() { url } else { "video".to_string() };
63 let placeholder = if let Some(ref poster_url) = poster {
64 if !poster_url.is_empty() {
65 format!("[\u{25B6} {} | poster: {}]", display_text, poster_url)
66 } else {
67 format!("[\u{25B6} {}]", display_text)
68 }
69 } else {
70 format!("[\u{25B6} {}]", display_text)
71 };
72
73 let paragraph = Paragraph::new(Line::from(Span::styled(
74 placeholder,
75 Style::default().fg(Color::DarkGray),
76 )));
77 frame.render_widget(paragraph, inner);
78 }
79
80 fn natural_height(
81 &self,
82 _ctx: &ComponentContext,
83 _available_width: u16,
84 _measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
85 ) -> Option<u16> {
86 None
89 }
90}