waterui_media/lib.rs
1//! # `WaterUI` Media Components
2//!
3//! This crate provides media handling and display components for the `WaterUI` framework.
4//! It includes support for images, videos, and Live Photos with a reactive, configurable API.
5//!
6//! ## Components
7//!
8//! - [`Photo`]: Display static images with customizable placeholders
9//! - [`Video`]: Video sources that can be used with [`VideoPlayer`]
10//! - [`VideoPlayer`]: Video playback with reactive volume control
11//! - [`LivePhoto`]: Apple Live Photo display with image and video components
12//! - [`Media`]: Unified enum for different media types
13//!
14//! ## Features
15//!
16//! - **Reactive**: All components integrate with `WaterUI`'s reactive system
17//! - **Configurable**: Built using `WaterUI`'s configuration pattern
18//! - **Media Picker**: Platform-native media selection (feature: `media-picker`)
19//! - **Type Safety**: Strong typing with URLs and media sources
20//!
21//! ## Examples
22//!
23//! ### Basic Photo
24//! ```rust,ignore
25//! use waterui_media::{Photo, url::Url};
26//!
27//! let url = Url::parse("https://example.com/image.jpg").unwrap();
28//! let _photo = Photo::new(url);
29//! ```
30//!
31//! ### Video with Controls
32//! ```rust,ignore
33//! use waterui_core::binding;
34//! use waterui_media::{Video, VideoPlayer, url::Url};
35//!
36//! let url = Url::parse("https://example.com/video.mp4").unwrap();
37//! let video = Video::new(url);
38//! let muted = binding(false);
39//! let _player = VideoPlayer::new(video).muted(&muted);
40//! ```
41//!
42//! ### Unified Media Type
43//! ```rust,ignore
44//! use waterui_media::{Media, live::LivePhotoSource, url::Url};
45//!
46//! let image = Media::Image(Url::parse("https://example.com/photo.jpg").unwrap());
47//! let video = Media::Video(Url::parse("https://example.com/video.mp4").unwrap());
48//! let live_photo = Media::LivePhoto(LivePhotoSource::new(
49//! Url::parse("https://example.com/photo.jpg").unwrap(),
50//! Url::parse("https://example.com/video.mov").unwrap(),
51//! ));
52//! assert!(matches!(image, Media::Image(_)));
53//! assert!(matches!(video, Media::Video(_)));
54//! assert!(matches!(live_photo, Media::LivePhoto(_)));
55//! ```
56
57#![allow(clippy::future_not_send)]
58#![allow(rustdoc::invalid_rust_codeblocks)]
59
60extern crate alloc;
61
62/// Live Photo components and types.
63///
64/// This module provides the [`LivePhoto`] component for displaying Apple Live Photos,
65/// which consist of both an image and a video component.
66pub mod live;
67/// Photo components and types.
68///
69/// This module provides the [`Photo`] component for displaying static images
70/// with customizable placeholder views.
71pub mod photo;
72
73/// Media picker functionality for platform-native media selection.
74pub mod media_picker;
75/// Video components and types.
76///
77/// This module provides [`Video`] sources and [`VideoPlayer`] components
78/// for video playback with reactive controls.
79pub mod video;
80pub use {
81 live::LivePhoto,
82 photo::Photo,
83 video::{AspectRatio, Video, VideoConfig, VideoPlayer, VideoPlayerConfig},
84};
85
86/// URL types for working with media resources
87pub mod url;
88pub use url::Url;
89/// Image view primitives and supporting types.
90pub mod image;
91
92use waterui_core::{AnyView, Environment, View, reactive::impl_constant};
93
94use crate::live::LivePhotoSource;
95
96/// A unified media type that can represent different kinds of media content.
97///
98/// This enum automatically chooses the appropriate component when used as a View:
99/// - [`Media::Image`] renders as a [`Photo`] component
100/// - [`Media::Video`] renders as a [`Video`] component
101/// - [`Media::LivePhoto`] renders as a [`LivePhoto`] component
102///
103/// # Examples
104///
105/// ```text
106/// use waterui_media::{Media, live::LivePhotoSource, url::Url};
107///
108/// let image = Media::Image(Url::parse("https://example.com/photo.jpg").unwrap());
109/// let video = Media::Video(Url::parse("https://example.com/video.mp4").unwrap());
110/// let live_photo = Media::LivePhoto(LivePhotoSource::new(
111/// Url::parse("https://example.com/photo.jpg").unwrap(),
112/// Url::parse("https://example.com/video.mov").unwrap(),
113/// ));
114/// assert!(matches!(image, Media::Image(_)));
115/// assert!(matches!(video, Media::Video(_)));
116/// assert!(matches!(live_photo, Media::LivePhoto(_)));
117/// ```
118#[derive(Debug, Clone, PartialEq, Eq)]
119pub enum Media {
120 /// An image from a URL that will be displayed using the [`Photo`] component.
121 Image(Url),
122 /// A Live Photo with image and video components that will be displayed using the [`LivePhoto`] component.
123 LivePhoto(LivePhotoSource),
124 /// A video from a URL that will be displayed using the [`Video`] component.
125 Video(Url),
126}
127
128impl_constant!(LivePhotoSource, Media);
129
130impl View for Media {
131 fn body(self, _env: &Environment) -> impl View {
132 match self {
133 Self::Image(url) => AnyView::new(Photo::new(url)),
134 Self::LivePhoto(live) => AnyView::new(LivePhoto::new(live)),
135 Self::Video(url) => AnyView::new(VideoPlayer::new(url)),
136 }
137 }
138}