Skip to main content

fission_core/ui/widgets/
video.rs

1use crate::lowering::{LoweringContext, NodeBuilder};
2use crate::ui::traits::Lower;
3use fission_ir::{
4    op::{EmbedKind, LayoutOp, Op},
5    NodeId, WidgetNodeId,
6};
7use serde::{Deserialize, Serialize};
8
9/// A platform-native video player widget.
10///
11/// The video is rendered by the platform's native player and embedded into the
12/// Fission layout as an opaque surface. Use [`BuildCtx::video_controls`] to
13/// create play/pause/seek action envelopes.
14///
15/// # Example
16///
17/// ```rust,ignore
18/// Video {
19///     source: "https://example.com/clip.mp4".into(),
20///     width: Some(640.0),
21///     height: Some(360.0),
22///     autoplay: true,
23///     loop_playback: false,
24///     ..Default::default()
25/// }
26/// ```
27#[derive(Debug, Default, Clone, Serialize, Deserialize)]
28pub struct Video {
29    /// Stable widget identity (auto-derived from `source` if `None`).
30    pub id: Option<WidgetNodeId>,
31    /// URL or asset path to the video file.
32    pub source: String,
33    /// Fixed width in layout points.
34    pub width: Option<f32>,
35    /// Fixed height in layout points.
36    pub height: Option<f32>,
37    /// Whether to start playing immediately.
38    pub autoplay: bool,
39    /// Whether to loop playback when the video ends.
40    pub loop_playback: bool,
41}
42
43impl Video {
44    pub fn into_node(self) -> crate::ui::Node {
45        crate::ui::Node::Video(self)
46    }
47}
48
49impl Lower for Video {
50    fn lower(&self, cx: &mut LoweringContext) -> NodeId {
51        let widget_id = self
52            .id
53            .unwrap_or_else(|| WidgetNodeId::explicit(&self.source));
54        let layout_id = cx.widget_node_id(widget_id);
55
56        let embed_id = NodeBuilder::new(
57            cx.next_node_id(),
58            Op::Layout(LayoutOp::Embed {
59                kind: EmbedKind::Video,
60                widget_id,
61                width: self.width,
62                height: self.height,
63            }),
64        )
65        .build(cx);
66
67        let mut layout_builder = NodeBuilder::new(
68            layout_id,
69            Op::Layout(LayoutOp::Box {
70                width: self.width,
71                height: self.height,
72                min_width: None,
73                max_width: None,
74                min_height: None,
75                max_height: None,
76                padding: [0.0; 4],
77                flex_grow: 0.0,
78                flex_shrink: 0.0,
79                aspect_ratio: None,
80            }),
81        );
82        layout_builder.add_child(embed_id);
83        layout_builder.build(cx)
84    }
85}