From d951b15d1caaf35ea6a5a3862788d7552a9fb902 Mon Sep 17 00:00:00 2001 From: bl1nch <130155870+bl1nch@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:31:24 +0600 Subject: [PATCH 1/5] feat: custom content --- sdk/python/packages/flet-video/src/flet_video/video.py | 5 +++++ .../flet-video/src/flutter/flet_video/lib/src/video.dart | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) 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..47fe0fae74 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. 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..8c06387e24 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,9 @@ class _VideoControlState extends State with FletStoreMixin { key: _videoKey, controller: _controller, wakelock: widget.control.getBool("wakelock", true)!, - controls: showControls ? AdaptiveVideoControls : null, + controls: showControls + ? (state) => content ?? AdaptiveVideoControls(state) + : null, pauseUponEnteringBackgroundMode: widget.control.getBool("pause_upon_entering_background_mode", true)!, resumeUponEnteringForegroundMode: widget.control From 1f7a0e1b59bb609d48108cddd3021b0569e15719 Mon Sep 17 00:00:00 2001 From: bl1nch <130155870+bl1nch@users.noreply.github.com> Date: Mon, 13 Apr 2026 12:34:48 +0600 Subject: [PATCH 2/5] add changelog record --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f06a2120a..cffe501670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add `ft.use_dialog()` hook for declarative dialog management from within `@ft.component` functions, with frozen-diff reactive updates and automatic open/close lifecycle ([#6335](https://github.com/flet-dev/flet/pull/6335)) by @FeodorFitsner. * Add `scrollable`, `pin_leading_to_top`, and `pin_trailing_to_bottom` properties to `NavigationRail` for scrollable content with optional pinned leading/trailing controls ([#1923](https://github.com/flet-dev/flet/issues/1923), [#6356](https://github.com/flet-dev/flet/pull/6356)) by @ndonkoHenri. * 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. +* Add `content` property to `Video` control ([#6392](https://github.com/flet-dev/flet/pull/6392)) by @bl1nch. ### Improvements From bdc6a1024917f396d8829d0988fc09a75ec9dcd6 Mon Sep 17 00:00:00 2001 From: bl1nch <130155870+bl1nch@users.noreply.github.com> Date: Mon, 13 Apr 2026 22:53:23 +0600 Subject: [PATCH 3/5] fix content force expand --- .../packages/flet-video/src/flet_video/video.py | 4 ++++ .../src/flutter/flet_video/lib/src/video.dart | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) 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 47fe0fae74..8e0c5350eb 100644 --- a/sdk/python/packages/flet-video/src/flet_video/video.py +++ b/sdk/python/packages/flet-video/src/flet_video/video.py @@ -186,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 8c06387e24..4349ff7aaf 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 @@ -241,7 +241,16 @@ class _VideoControlState extends State with FletStoreMixin { controller: _controller, wakelock: widget.control.getBool("wakelock", true)!, controls: showControls - ? (state) => content ?? AdaptiveVideoControls(state) + ? (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)!, From 0aa73d9c83f4b01d68df135e7487d2fb9cab8d97 Mon Sep 17 00:00:00 2001 From: bl1nch <130155870+bl1nch@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:06:05 +0600 Subject: [PATCH 4/5] add example --- .../controls/video/custom-content/main.py | 95 +++++++++++++++++++ .../video/custom-content/pyproject.toml | 26 +++++ 2 files changed, 121 insertions(+) create mode 100644 sdk/python/examples/controls/video/custom-content/main.py create mode 100644 sdk/python/examples/controls/video/custom-content/pyproject.toml 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" From 629342c1e45c23cf028ab36e9ec98f1a469d9ce8 Mon Sep 17 00:00:00 2001 From: bl1nch <130155870+bl1nch@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:16:27 +0600 Subject: [PATCH 5/5] fix --- .../flet-video/src/flutter/flet_video/lib/src/video.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4349ff7aaf..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 @@ -246,7 +246,7 @@ class _VideoControlState extends State with FletStoreMixin { return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, - children: [content!] + children: [content] ); } return AdaptiveVideoControls(state);