diff --git a/CHANGELOG.md b/CHANGELOG.md index e37c70b90a..6d7756436f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Add `Page.pop_views_until()` to pop multiple views and return a result to the destination view ([#6326](https://github.com/flet-dev/flet/issues/6326), [#6347](https://github.com/flet-dev/flet/pull/6347)) by @brunobrown. * Make `NavigationDrawerDestination.label` accept custom controls and add `NavigationDrawerTheme.icon_theme` ([#6379](https://github.com/flet-dev/flet/issues/6379), [#6395](https://github.com/flet-dev/flet/pull/6395)) by @ndonkoHenri. * Add `local_position` and `global_position` to `DragTargetEvent`, deprecating `x`, `y`, and `offset` ([#6387](https://github.com/flet-dev/flet/issues/6387), [#6401](https://github.com/flet-dev/flet/pull/6401)) by @ndonkoHenri. +* Add `content` property to `Video` control ([#6392](https://github.com/flet-dev/flet/pull/6392)) by @bl1nch. ### Improvements diff --git a/sdk/python/examples/controls/video/custom-content/main.py b/sdk/python/examples/controls/video/custom-content/main.py new file mode 100644 index 0000000000..f3c05eb4c0 --- /dev/null +++ b/sdk/python/examples/controls/video/custom-content/main.py @@ -0,0 +1,95 @@ +import flet as ft +import flet_video as ftv + +sample_media = [ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4", + extras={ + "artist": "Thousand Foot Krutch", + "album": "The End Is Where We Begin", + }, + http_headers={ + "Foo": "Bar", + "Accept": "*/*", + }, + ), +] + + +async def main(page: ft.Page): + page.spacing = 20 + + video = ft.Ref[ftv.Video]() + title = ft.Ref[ft.Text]() + + async def handle_pause(e: ft.Event[ft.Button]): + await video.current.pause() + + async def handle_play_or_pause(e: ft.Event[ft.Button]): + await video.current.play_or_pause() + + async def handle_play(e: ft.Event[ft.Button]): + await video.current.play() + + async def handle_stop(e: ft.Event[ft.Button]): + await video.current.stop() + + async def handle_next(e: ft.Event[ft.Button]): + await video.current.next() + + async def handle_previous(e: ft.Event[ft.Button]): + await video.current.previous() + + def handle_track_change(e: ft.Event[ftv.Video]): + title.current.value = sample_media[e.data].resource + + page.add( + ftv.Video( + width=640, + height=360, + ref=video, + playlist=sample_media, + on_track_change=handle_track_change, + content=ft.Container( + padding=ft.Padding.all(10), + expand=True, + content=ft.Column( + controls=[ + ft.Container( + padding=ft.Padding.all(5), + border_radius=20, + bgcolor=ft.Colors.GREEN_ACCENT_100, + content=ft.Text(size=10, value="", ref=title) + ) + ], + ) + ) + ), + ft.Row( + wrap=True, + controls=[ + ft.Button("Play", on_click=handle_play), + ft.Button("Pause", on_click=handle_pause), + ft.Button("Play Or Pause", on_click=handle_play_or_pause), + ft.Button("Stop", on_click=handle_stop), + ft.Button("Next", on_click=handle_next), + ft.Button("Previous", on_click=handle_previous), + ], + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/video/custom-content/pyproject.toml b/sdk/python/examples/controls/video/custom-content/pyproject.toml new file mode 100644 index 0000000000..b4f9120286 --- /dev/null +++ b/sdk/python/examples/controls/video/custom-content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-custom-content-example" +version = "1.0.0" +description = "Custom content in a Flet video player." +requires-python = ">=3.10" +keywords = ["video", "media", "playlist", "player", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Video custom content example" +controls = ["Container", "Column", "Row", "Button", "Text", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["custom content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet-video/src/flet_video/video.py b/sdk/python/packages/flet-video/src/flet_video/video.py index 9b8491d0b2..8e0c5350eb 100644 --- a/sdk/python/packages/flet-video/src/flet_video/video.py +++ b/sdk/python/packages/flet-video/src/flet_video/video.py @@ -61,6 +61,11 @@ class Video(ft.LayoutControl): Whether to show the video player controls. """ + content: Optional[ft.Control] = None + """ + The custom content of the video control. + """ + fullscreen: bool = False """ Whether the video player is presented in fullscreen mode. @@ -181,6 +186,10 @@ class Video(ft.LayoutControl): the index of the new track. """ + def init(self): + super().init() + self._internals["host_expanded"] = True + def before_update(self): super().before_update() if not (0 <= self.volume <= 100): diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart index ad5a0a217e..8887a97f06 100644 --- a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart @@ -208,6 +208,7 @@ class _VideoControlState extends State with FletStoreMixin { @override Widget build(BuildContext context) { debugPrint("Video build: ${widget.control.id}"); + var content = widget.control.buildWidget("content"); var subtitleConfiguration = parseSubtitleConfiguration( widget.control.get("subtitle_configuration"), @@ -239,7 +240,18 @@ class _VideoControlState extends State with FletStoreMixin { key: _videoKey, controller: _controller, wakelock: widget.control.getBool("wakelock", true)!, - controls: showControls ? AdaptiveVideoControls : null, + controls: showControls + ? (state) { + if (content != null) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [content] + ); + } + return AdaptiveVideoControls(state); + } + : null, pauseUponEnteringBackgroundMode: widget.control.getBool("pause_upon_entering_background_mode", true)!, resumeUponEnteringForegroundMode: widget.control