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
13/// [`crate::internal::BuildCtx::video_controls`] to create play/pause/seek
14/// action envelopes.
15///
16/// # Example
17///
18/// ```rust,ignore
19/// Video {
20///     source: "https://example.com/clip.mp4".into(),
21///     width: Some(640.0),
22///     height: Some(360.0),
23///     autoplay: true,
24///     loop_playback: false,
25///     ..Default::default()
26/// }
27/// .into();
28/// ```
29#[derive(Debug, Default, Clone, Serialize, Deserialize)]
30pub struct Video {
31    /// Stable widget identity (auto-derived from `source` if `None`).
32    pub id: Option<WidgetId>,
33    /// URL or asset path to the video file.
34    pub source: String,
35    /// Fixed width in layout points.
36    pub width: Option<f32>,
37    /// Fixed height in layout points.
38    pub height: Option<f32>,
39    /// Whether to start playing immediately.
40    pub autoplay: bool,
41    /// Whether to loop playback when the video ends.
42    pub loop_playback: bool,
43}
44
45impl Video {}
46
47impl InternalLower for Video {
48    fn lower(&self, cx: &mut InternalLoweringCx) -> WidgetId {
49        let widget_id = self.id.unwrap_or_else(|| WidgetId::explicit(&self.source));
50        let layout_id = cx.widget_node_id(widget_id);
51
52        let embed_id = InternalIrBuilder::new(
53            cx.next_node_id(),
54            Op::Layout(LayoutOp::Embed {
55                kind: EmbedKind::Video,
56                widget_id,
57                width: self.width,
58                height: self.height,
59            }),
60        )
61        .build(cx);
62
63        let mut layout_builder = InternalIrBuilder::new(
64            layout_id,
65            Op::Layout(LayoutOp::Box {
66                width: self.width,
67                height: self.height,
68                min_width: None,
69                max_width: None,
70                min_height: None,
71                max_height: None,
72                padding: [0.0; 4],
73                flex_grow: 0.0,
74                flex_shrink: 0.0,
75                aspect_ratio: None,
76            }),
77        );
78        layout_builder.add_child(embed_id);
79        layout_builder.build(cx)
80    }
81}