Skip to main content

fission_core/ui/widgets/
video.rs

1use crate::internal::InternalLower;
2use crate::lowering::{InternalIrBuilder, InternalLoweringCx};
3use fission_ir::{
4    op::{EmbedKind, LayoutOp, Op},
5    WidgetId,
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/// .into();
27/// ```
28#[derive(Debug, Default, Clone, Serialize, Deserialize)]
29pub struct Video {
30    /// Stable widget identity (auto-derived from `source` if `None`).
31    pub id: Option<WidgetId>,
32    /// URL or asset path to the video file.
33    pub source: String,
34    /// Fixed width in layout points.
35    pub width: Option<f32>,
36    /// Fixed height in layout points.
37    pub height: Option<f32>,
38    /// Whether to start playing immediately.
39    pub autoplay: bool,
40    /// Whether to loop playback when the video ends.
41    pub loop_playback: bool,
42}
43
44impl Video {}
45
46impl InternalLower for Video {
47    fn lower(&self, cx: &mut InternalLoweringCx) -> WidgetId {
48        let widget_id = self.id.unwrap_or_else(|| WidgetId::explicit(&self.source));
49        let layout_id = cx.widget_node_id(widget_id);
50
51        let embed_id = InternalIrBuilder::new(
52            cx.next_node_id(),
53            Op::Layout(LayoutOp::Embed {
54                kind: EmbedKind::Video,
55                widget_id,
56                width: self.width,
57                height: self.height,
58            }),
59        )
60        .build(cx);
61
62        let mut layout_builder = InternalIrBuilder::new(
63            layout_id,
64            Op::Layout(LayoutOp::Box {
65                width: self.width,
66                height: self.height,
67                min_width: None,
68                max_width: None,
69                min_height: None,
70                max_height: None,
71                padding: [0.0; 4],
72                flex_grow: 0.0,
73                flex_shrink: 0.0,
74                aspect_ratio: None,
75            }),
76        );
77        layout_builder.add_child(embed_id);
78        layout_builder.build(cx)
79    }
80}