Conversation
Introduces the flet-camera package with Python and Flutter bindings, including camera control, types, and documentation. Integrates flet_camera into the client app, updates dependencies, and provides a usage example for camera control in Flet Python apps.
Added detailed docstrings to enums, dataclasses, and methods in camera.py and types.py for improved API documentation and clarity. Implemented CameraDescription.to_dict() for proper serialization when passing camera descriptions. Updated method argument handling to use serialized camera descriptions and clarified return values and arguments in method docstrings.
Refactored Python camera example to use a dataclass for state management, improved event handling, and added support for image streaming and preview controls. Updated camera API to remove enum-to-value conversions and dictionary serialization, passing objects directly. Adjusted Flutter implementation to match new API, including support for image streaming and controller initialization changes.
Added a ValueKey to DropdownMenu based on the options set to ensure the menu recalculates its intrinsic width when options change, preventing incorrect sizing when new, longer options are added.
Session reconnect now uses an async task to avoid blocking the websocket receive loop with user handlers. Errors during reconnect are logged and reported to the session if possible.
Replaced print statements with logging for better output control, fixed color constant typo, removed redundant camera initialization, and set up camera retrieval on page connect. These changes streamline the example and improve maintainability.
Register flet_camera and flet_code_editor (imports and extension entries) in client main, reorder some extension registrations and tidy a desktop-mode exception formatting. Update camera package usage and utils: change resolution preset parsing to use a nullable default and non-null return, replace parseOffsetFromJson calls with parseOffset, simplify parseCameraDescription to use parseEnum with defaults, remove the old parseOffsetFromJson/parseEnum implementations, and add flet import in utils. Also add the flet_camera package (path) to pubspec.lock and apply dependency lock updates.
Register the new flet-camera extension across the repository: update sdk/python/packages/flet/pyproject.toml (extensions list), add flet-camera to the example app sdk/python/examples/apps/flet_build_test/pyproject.toml (dependencies, editable package and local path mapping), and include flet-camera in the GitHub Actions workflow (.github/workflows/ci.yml) in both the build_flet_extensions PACKAGES list and the py_publish publish loop. Also clarify the SKILL.md guidance to remind to add the extension in both CI locations.
Replace debug print with logic to render incoming camera frames by setting last_image.src and calling last_image.update(). Wrap rendering in a try/except and log exceptions with logging.exception to avoid crashing the stream handler and improve robustness.
Extend the camera example with video recording capabilities: import datetime, change dropdown label to "Select camera", and add a recorded_video_path Text control. Implement detect_video_extension to infer webm/mp4/mov from bytes and add start/pause/resume/stop recording handlers that save the recorded bytes using FilePicker with a timestamped filename. Update camera state handling to correctly reflect paused vs recording states and add UI buttons for recording controls alongside the existing photo/streaming controls.
Enhance the camera example with full recording/streaming UI and state handling: add flags to State (is_streaming, is_recording, preview/recording paused, streaming support), replace text buttons with icon buttons (take photo, record, pause recording, stream, preview), and wire up toggle helpers. Introduce sync_action_buttons to keep button states in sync, update handlers to set state and call page.update(), check for image streaming support, and handle CameraState events to reflect runtime changes. Also remove unused logging setup and tweak the dropdown label.
Deploying flet-examples with
|
| Latest commit: |
eda03a7
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://758882b6.flet-examples.pages.dev |
| Branch Preview URL: | https://flet-camera.flet-examples.pages.dev |
Document required platform permissions for the Camera control: add iOS Info.plist keys (NSCameraUsageDescription, NSMicrophoneUsageDescription) and Android permission flags (android.permission.CAMERA, android.permission.RECORD_AUDIO). Clarifies that microphone permissions are only needed for audio-enabled video recording and links to the platform-specific permissions docs.
Deploying flet-docs with
|
| Latest commit: |
eda03a7
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://28b3549d.flet-docs.pages.dev |
| Branch Preview URL: | https://flet-camera.flet-docs.pages.dev |
There was a problem hiding this comment.
Pull request overview
Adds a new flet-camera extension/control to the Flet Python SDK (with Flutter-side implementation), wiring it into docs, examples, CI, and the Flutter client app so camera preview/capture/streaming is available on supported platforms.
Changes:
- Introduces the new
flet-cameraPython package + Flutter extension implementation, and registers it across workspace/CI/client dependencies. - Adds API docs pages and a full Python example for the Camera control.
- Includes a couple of unrelated runtime/UI fixes: async reconnect handling in
flet-weband a DropdownMenu rebuild key to recalc intrinsic width.
Reviewed changes
Copilot reviewed 31 out of 32 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| sdk/python/pyproject.toml | Adds flet-camera to workspace dependencies + isort config. |
| sdk/python/packages/flet/pyproject.toml | Registers flet-camera as a built-in extension. |
| sdk/python/packages/flet/mkdocs.yml | Adds nav entries for Camera docs (but also duplicates Audio/AudioRecorder). |
| sdk/python/packages/flet/docs/extend/built-in-extensions.md | Lists flet-camera among built-in extensions. |
| sdk/python/packages/flet/docs/camera/index.md | New Camera control documentation page. |
| sdk/python/packages/flet/docs/camera/types/camera_description.md | New type doc stub. |
| sdk/python/packages/flet/docs/camera/types/camera_image.md | New type doc stub. |
| sdk/python/packages/flet/docs/camera/types/camera_state.md | New type doc stub. |
| sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app_manager.py | Changes reconnect behavior to run session.connect() in a background task. |
| sdk/python/packages/flet-camera/src/flutter/flet_camera/pubspec.yaml | New Flutter extension package definition. |
| sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart | New camera parsing + image encoding utilities (pixel conversion in Dart). |
| sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/camera.dart | New Camera control widget + invoke-method handling. |
| sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/extension.dart | Registers the Camera widget with the Flet extension. |
| sdk/python/packages/flet-camera/src/flet_camera/types.py | New Python dataclasses/enums for camera types/events. |
| sdk/python/packages/flet-camera/src/flet_camera/camera.py | New Python Camera control wrapper with async API methods. |
| sdk/python/examples/controls/camera/example_1.py | New end-to-end example showcasing preview, photos, video, streaming. |
| sdk/python/examples/apps/flet_build_test/pyproject.toml | Adds flet-camera to build-test app dependencies. |
| packages/flet/lib/src/controls/dropdown.dart | Forces DropdownMenu rebuild when options change to recalc intrinsic width. |
| client/pubspec.yaml | Adds the Flutter flet_camera extension dependency to the client. |
| client/pubspec.lock | Locks new transitive deps for camera/image, etc. |
| client/lib/main.dart | Imports/registers the camera extension in the client extensions list. |
| client/ios/Runner/Info.plist | Adds NSCameraUsageDescription for iOS. |
| .github/workflows/ci.yml | Adds flet-camera to extension build/publish workflows. |
| .codex/skills/implement-flet-extension/SKILL.md | Updates extension implementation checklist to reflect CI update locations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/camera.dart
Show resolved
Hide resolved
|
|
||
| /// admonition | Permissions | ||
| type: tip | ||
| Request camera (and microphone if recording video with audio) permissions on mobile and desktop platforms before initializing the control. You can use [`flet-permission-handler`](https://pypi.org/project/flet-permission-handler/) to prompt the user. |
There was a problem hiding this comment.
The permissions note mentions requesting camera/microphone permissions on “mobile and desktop platforms”, but the Platform Support table above indicates Windows/macOS/Linux are not supported. Consider updating this text to avoid implying desktop support (or update the support table if desktop support is intended).
| Request camera (and microphone if recording video with audio) permissions on mobile and desktop platforms before initializing the control. You can use [`flet-permission-handler`](https://pypi.org/project/flet-permission-handler/) to prompt the user. | |
| Request camera (and microphone if recording video with audio) permissions on mobile platforms before initializing the control. You can use [`flet-permission-handler`](https://pypi.org/project/flet-permission-handler/) to prompt the user. |
There was a problem hiding this comment.
Seems legit?
Maybe we could even completely remove the platform mentions...
Also, for the flet-permission-handler link, maybe instead point to its docs page directly?
sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart
Outdated
Show resolved
Hide resolved
Pass image_format_group=fc.ImageFormatGroup.JPEG when starting the camera preview so frames are delivered as JPEG. This ensures consistent encoding for image streaming and downstream processing.
Move camera image encoding off the main thread by serializing CameraImage into a payload and running encoding in an Isolate. Import dart:isolate and update _processStreamImage to use Isolate.run for non-JPEG formats. Add cameraImageToPayload and encodeCameraImagePayload helpers and refactor BGRA/NV21/YUV420 encoders to accept payload maps (with stronger validation and bounds checks). Keep JPEG fast-path returning plane bytes directly. This reduces UI jank and ensures safe cross-isolate data handling.
Set gapless_playback=True on the media widget in sdk/python/examples/controls/camera/example_1.py to avoid visible reload/flicker when the source is updated (e.g., switching camera frames). This makes playback smoother in the camera example.
Update camera docs to specify that camera (and microphone when recording audio) permissions should be requested on mobile platforms only, removing the previous mention of desktop. Keeps the recommendation to use flet-permission-handler to prompt the user.
Flatten the Camera navigation by replacing the nested Camera subtree with a single Camera index entry (camera/index.md) and move Camera type pages into the global Types section. Also remove the Audio and AudioRecorder nav entries from this section to keep the docs navigation simpler and more consistent.
Prevent fall-through in camera controller message handling by adding a break after awaiting _initializeController(...) in the 'initialize' switch case. This ensures subsequent cases (like exposure queries) are not executed unintentionally after initialization.
ndonkoHenri
left a comment
There was a problem hiding this comment.
Docs: only 4 classes were documented. Still about 8 left.
Example: on web - i was able to record a video, and when I stopped the recording it saved as .webm into my downloads folder - awesome! This was on the first try though. On the next tries though, i didnt work :( Flow: launch with fvm flutter run -d chrome, grant permission, then click take picture or preview buttons. A flutter exception (see logs below) is shown immediately after the app launches (when await get_cameras() on line 358 is executed). The Python exception is shown when i click a button.
Logs
Received message: [2, {id: 1, patch: [[0, {views: [1, {0: [2]}]}], [0, 0, title, Camera control], [0, 0, on_connect, true], [0, 2, padding, 16], [0, 2, scroll, auto], [0, 2, horizontal_alignment, stretch], [0, 2, controls, [{_i:
118, _c: SafeArea, content: {_i: 117, _c: Column, _internals: {host_expanded: true}, controls: [{_i: 113, _c: Row, _internals: {host_expanded: true}, controls: [{_i: 105, _c: Dropdown, on_select: true, label: Camera}, {_i: 112,
_c: IconButton, icon: 71733, on_click: true}], wrap: true}, {_i: 114, _c: Container, _internals: {skip_properties: [width, height, margin]}, height: 320, content: {_i: 102, _c: Camera, expand: true, content: {_i: 101, _c:
Container, _internals: {skip_properties: [width, height, margin]}, content: {_i: 100, _c: Icon, icon: 66817, color: white70, size: 48}, alignment: {x: 0, y: 0}}, on_state_change: true, on_stream_image: true}, bgcolor: black,
border_radius: 3}, {_i: 103, _c: Text, value: Select a camera, size: 12}, {_i: 115, _c: Row, _internals: {host_expanded: true}, controls: [{_i: 107, _c: FilledIconButton, tooltip: Take photo, icon: 71254, on_click: true}, {_i:
108, _c: FilledTonalIconButton, tooltip: Start / stop recording, icon: 73878, selected: false, selected_icon: 72931, on_click: true}, {_i: 109, _c: OutlinedIconButton, tooltip: Pause / resume recording, disabled: true, icon:
70989, selected: false, selected_icon: 71356, on_click: true}, {_i: 110, _c: OutlinedIconButton, tooltip: Start / stop image stream, visible: false, icon: 71356, selected: false, selected_icon: 72931, on_click: true}, {_i: 111,
_c: OutlinedIconButton, tooltip: Pause / resume preview, icon: 73987, selected: true, selected_icon: 73986, on_click: true}], wrap: true}, {_i: 106, _c: Text, value: Recorded video: not saved yet, size: 12}, {_i: 116, _c: Text,
value: Last photo}, {_i: 104, _c: Image, _internals: {skip_properties: [width, height]}, height: 200, src: iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wIAAgMBAp0YVwAAAABJRU5ErkJggg==, fit: contain,
gapless_playback: true}]}}]]]}]
Control(1).applyPatch: [[0, {views: [1, {0: [2]}]}], [0, 0, title, Camera control], [0, 0, on_connect, true], [0, 2, padding, 16], [0, 2, scroll, auto], [0, 2, horizontal_alignment, stretch], [0, 2, controls, [{_i: 118, _c:
SafeArea, content: {_i: 117, _c: Column, _internals: {host_expanded: true}, controls: [{_i: 113, _c: Row, _internals: {host_expanded: true}, controls: [{_i: 105, _c: Dropdown, on_select: true, label: Camera}, {_i: 112, _c:
IconButton, icon: 71733, on_click: true}], wrap: true}, {_i: 114, _c: Container, _internals: {skip_properties: [width, height, margin]}, height: 320, content: {_i: 102, _c: Camera, expand: true, content: {_i: 101, _c: Container,
_internals: {skip_properties: [width, height, margin]}, content: {_i: 100, _c: Icon, icon: 66817, color: white70, size: 48}, alignment: {x: 0, y: 0}}, on_state_change: true, on_stream_image: true}, bgcolor: black, border_radius:
3}, {_i: 103, _c: Text, value: Select a camera, size: 12}, {_i: 115, _c: Row, _internals: {host_expanded: true}, controls: [{_i: 107, _c: FilledIconButton, tooltip: Take photo, icon: 71254, on_click: true}, {_i: 108, _c:
FilledTonalIconButton, tooltip: Start / stop recording, icon: 73878, selected: false, selected_icon: 72931, on_click: true}, {_i: 109, _c: OutlinedIconButton, tooltip: Pause / resume recording, disabled: true, icon: 70989,
selected: false, selected_icon: 71356, on_click: true}, {_i: 110, _c: OutlinedIconButton, tooltip: Start / stop image stream, visible: false, icon: 71356, selected: false, selected_icon: 72931, on_click: true}, {_i: 111, _c:
OutlinedIconButton, tooltip: Pause / resume preview, icon: 73987, selected: true, selected_icon: 73986, on_click: true}], wrap: true}, {_i: 106, _c: Text, value: Recorded video: not saved yet, size: 12}, {_i: 116, _c: Text,
value: Last photo}, {_i: 104, _c: Image, _internals: {skip_properties: [width, height]}, height: 200, src: iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wIAAgMBAp0YVwAAAABJRU5ErkJggg==, fit: contain,
gapless_playback: true}]}}]]], shouldNotify = true
Notify Page(1)
Page updated: TargetPlatform.macOS TargetPlatform.macOS
Notify Page(1)
Page updated: TargetPlatform.macOS TargetPlatform.macOS
Notify View(94)
Notify View(94)
Notify View(94)
Notify View(94)
Received message: [5, {control_id: 102, call_id: ayGpSZOPQh, name: get_available_cameras}]
Camera(102).get_available_cameras(null)
Page.didUpdateWidget: 1
Page.build: 1
Page navigator build: 1
View.didUpdateWidget: 94
View.build: 94
ScrollableControl build: 94
SafeArea build: 118
Column build: 117
ScrollableControl build: 117
Row build: 113
ScrollableControl build: 113
DropdownMenu build: 105
IconButton build: 112
Container build: 114
Camera build: 102
Text build: 103
Row build: 115
ScrollableControl build: 115
IconButton build: 107
IconButton build: 108
IconButton build: 109
IconButton build: 111
Text build: 106
Text build: 116
Image build: 104
Camera.get_available_cameras(null)
══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
The following DomException object was thrown resolving an image frame:
EncodingError: Failed to decode frame at index 0
When the exception was thrown, this was the stack
════════════════════════════════════════════════════════════════════════════════════════════════════
_send: MessageAction.controlEvent {target: 1, name: app_lifecycle_state_change, data: {state: inactive}}
_send: MessageAction.controlEvent {target: 1, name: app_lifecycle_state_change, data: {state: resume}}
_send: MessageAction.invokeControlMethod {control_id: 102, call_id: ayGpSZOPQh, result: [{name: MacBook Pro Camera (0000:0001), lens_direction: external, sensor_orientation: 0, lens_type: unknown}, {name: OBS Virtual Camera,
lens_direction: external, sensor_orientation: 0, lens_type: unknown}], error: null}
Received message: [2, {id: 1, patch: [[0, {views: [1, {0: [2, {controls: [3, {0: [4, {content: [5, {controls: [6, {0: [7, {controls: [8, {0: [9]}]}]}]}]}]}]}]}]}], [0, 9, options, [{_i: 119, _c: DropdownOption, key: MacBook Pro
Camera (0000:0001), text: MacBook Pro Camera (0000:0001)}, {_i: 120, _c: DropdownOption, key: OBS Virtual Camera, text: OBS Virtual Camera}]]]}]
Control(1).applyPatch: [[0, {views: [1, {0: [2, {controls: [3, {0: [4, {content: [5, {controls: [6, {0: [7, {controls: [8, {0: [9]}]}]}]}]}]}]}]}]}], [0, 9, options, [{_i: 119, _c: DropdownOption, key: MacBook Pro Camera
(0000:0001), text: MacBook Pro Camera (0000:0001)}, {_i: 120, _c: DropdownOption, key: OBS Virtual Camera, text: OBS Virtual Camera}]]], shouldNotify = true
Notify Dropdown(105)
DropdownMenu build: 105
OutlinedIconButton(111).on_click(null)
_send: MessageAction.controlEvent {target: 111, name: click, data: null}
Received message: [5, {control_id: 102, call_id: QTb9SabhZz, name: pause_preview}]
Camera(102).pause_preview(null)
Camera.pause_preview(null)
_send: MessageAction.invokeControlMethod {control_id: 102, call_id: QTb9SabhZz, result: null, error: Exception: Camera is not initialized. Call initialize() first.}
Received message: [6, {message: Exception: Camera is not initialized. Call initialize() first.
Traceback (most recent call last):
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/packages/flet/src/flet/messaging/session.py", line 319, in dispatch_event
await control._trigger_event(event_name, event_data)
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/packages/flet/src/flet/controls/base_control.py", line 414, in _trigger_event
await event_handler()
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/examples/controls/camera/example_1.py", line 312, in toggle_preview
await pause_preview()
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/examples/controls/camera/example_1.py", line 279, in pause_preview
await preview.pause_preview()
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/packages/flet-camera/src/flet_camera/camera.py", line 134, in pause_preview
await self._invoke_method("pause_preview")
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/packages/flet/src/flet/controls/base_control.py", line 360, in _invoke_method
return await self.page.session.invoke_method(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/ndonkohenri/PycharmProjects/flet-dev/flet/sdk/python/packages/flet/src/flet/messaging/session.py", line 374, in invoke_method
raise RuntimeError(err)
RuntimeError: Exception: Camera is not initialized. Call initialize() first.
}]
sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/camera.dart
Outdated
Show resolved
Hide resolved
sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart
Outdated
Show resolved
Hide resolved
sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart
Outdated
Show resolved
Hide resolved
sdk/python/packages/flet/docs/camera/types/camera_description.md
Outdated
Show resolved
Hide resolved
|
OK, I think the error I mentioned to have faced occured because I didnt select a camera.
Bluestacks Android 13 Emulator ✔︎: Screen.Recording.2026-02-20.at.2.38.18.PM.mov |
Minor fixes and cleanup across camera and canvas docs and a small docstring tweak:
- Camera: adjust docstring indentation in lock_capture_orientation.
- Docs: replace flet-permission-handler link text with PermissionHandler reference for prompting permissions.
- Camera types: remove YAML frontmatter and use {{ class_all_options("flet_camera.*") }} for CameraDescription, CameraImage, and CameraState to standardize type docs.
- Canvas: correct on_resize cross-reference to flet.canvas.Canvas.on_resize.
These changes improve documentation consistency and fix broken/unclear references.
Rename three camera type documentation files to remove underscores (camera_description.md -> cameradescription.md, camera_image.md -> cameraimage.md, camera_state.md -> camerastate.md) and update mkdocs.yml nav entries accordingly. Keeps documentation filenames consistent with project naming conventions and ensures the site nav points to the new paths.
Add a note in the camera docs suggesting the use of predefined cross-platform permission bundles for camera and microphone permissions (links to publish docs). This complements the existing guidance to use PermissionHandler on mobile platforms. File modified: sdk/python/packages/flet/docs/camera/index.md.
Update docstring coverage badge links across Python package README.md files to point to the direct badge URLs on docs.flet.dev instead of the GitHub tree path. Changes affect multiple packages under sdk/python/packages/* (and the main flet README), fixing incorrect/broken badge links and ensuring the badges link directly to the hosted images.
Replace the README tagline 'A cross-platform camera control for Flet apps.' with 'A camera control for Flet apps.' in sdk/python/packages/flet-camera/README.md to simplify the package description.
Export control_widget and device_info from the flet package so downstream packages can import them from package:flet/flet.dart. Remove the implementation import of control_widget from flet_camera's camera.dart. Also remove the unused parseDeviceOrientation helper from utils/camera.dart and perform a small formatting/cleanup of the uvPixelStride assignment.
Replace manual type checks with parse helpers (parseBool, parseInt, parseDouble) for args like enable_audio, fps, video_bitrate, audio_bitrate, offset and zoom to improve null-safety and reduce boilerplate. Use hasEventHandler("stream_image") instead of checking a boolean control value before processing image stream. Simplify preview child creation by using widget.control.buildWidget("content") instead of manually constructing the child ControlWidget. These changes make the camera control code cleaner and more robust to unexpected argument types.
Rename CameraImage -> CameraImageEvent and CameraState -> CameraStateEvent across the flet-camera package and examples. Update public exports, type annotations in Camera, and example handler signatures to use the new event classes. Replace the local DeviceOrientation enum with ft.DeviceOrientation to keep orientation types consistent. Update docs files and mkdocs navigation to reflect the new type names. Note: this is a breaking API change for callers expecting the old type names.
Refactor: extracted the detect_video_extension helper from the example into a new flet_camera/utils.py and re-exported it from flet_camera.__init__.py. Updated the camera example to call fc.detect_video_extension instead of the local implementation. This centralizes the utility for reuse and removes duplication; no functional behavior was changed.
Enhance the Python camera example to handle device orientation and image rotation, and to guard actions until the camera is initialized. Changes include: track device_orientation and last frame dimensions; add is_initialized flag; decode placeholder image as bytes and wrap it in a fixed-size frame container; compute and apply rotation/offset transforms to last_image; show a "Last photo" label when an image is available; disable action buttons (take photo, record, stream, preview) until initialization; add safety checks in take_photo/record/stream/preview handlers; attempt to lock capture orientation with error handling; update camera state on events; and ensure streaming updates store frame size. Also include small Dart formatting adjustments in the flet-camera package (reformatted multi-line arguments and function signature) for readability.
Remove the local DeviceOrientation alias/export and reference ft.DeviceOrientation directly across the package. Updated __init__.py to stop exporting DeviceOrientation, changed type annotations in flet_camera/types.py to use ft.DeviceOrientation, and updated camera.lock_capture_orientation signature in flet_camera/camera.py to use ft.DeviceOrientation. This keeps orientation types consistent with the core Flet package.
Add documentation pages for camera type enums using the class_all_options macro: CameraLensDirection, CameraLensType, CameraPreviewSize, ExposureMode, FlashMode, FocusMode, ImageFormatGroup, and ResolutionPreset. Update sdk/python/packages/flet/mkdocs.yml to include these new pages under the Camera section in the navigation.
Remove misplaced Camera entry and reinsert it under the controls list (after Button, before Canvas) in sdk/python/packages/flet/mkdocs.yml. This reorders the navigation to group Camera with other controls and corrects its placement in the docs nav.
Attach the connection synchronously and run page-level connect handlers asynchronously to avoid blocking the websocket receive loop. FletAppManager now calls session.attach_connection() immediately and dispatches the connect event via an async dispatch_connect_event task. Session.attach_connection was separated from connect: it now resets expiration and flushes the outbound buffer, dispatch_connect_event handles the connect event, and connect composes both behaviors. Tests added/updated to verify attach_connection restores state and flushes buffered messages (including a _RecordingConnection helper).
Adjust import marker ordering in client/lib/main.dart to fix FAT_CLIENT/RIVE markers and group platform plugins consistently. In client/pubspec.yaml, relocate the flet_camera dependency down into the plugins block (placed after flet_audio_recorder) to keep related native plugin deps together. No functional code changes—just reorganization for consistent project structure.
Summary by Sourcery
Add a new cross-platform Camera control as a first-class Flet extension and integrate it into the client, SDK, docs, CI, and examples.
New Features:
Bug Fixes:
Enhancements:
Build:
CI:
Documentation: