Skip to content

Comments

Camera control#6190

Open
FeodorFitsner wants to merge 36 commits intomainfrom
flet-camera
Open

Camera control#6190
FeodorFitsner wants to merge 36 commits intomainfrom
flet-camera

Conversation

@FeodorFitsner
Copy link
Contributor

@FeodorFitsner FeodorFitsner commented Feb 19, 2026

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:

  • Introduce the flet-camera Python package and Flutter extension providing a Camera control for preview, photo capture, video recording, and image streaming.
  • Add a Camera example app demonstrating camera selection, preview, photo capture, video recording, and image streaming in Flet.
  • Document the Camera control and its related types in the Flet docs site and package README.

Bug Fixes:

  • Prevent dropdown menus from keeping a stale intrinsic width when their option set changes by forcing the menu to rebuild with a key derived from options.
  • Avoid blocking the websocket receive loop during session reconnection by running the session connect logic asynchronously and surfacing errors back to the session.

Enhancements:

  • Register the new camera and related extensions in the Flutter client startup sequence and reorder imports for consistency.
  • Clarify internal checklist docs for adding new Flet extensions and add iOS camera usage description to the client Info.plist.

Build:

  • Add flet-camera to the Python workspace, dependency graphs, and build metadata so it is built and published with other extensions.
  • Add a Flutter package for the flet_camera extension wired into the monorepo with its own pubspec and analysis options.

CI:

  • Include flet-camera in CI extension build and publish jobs so it is validated and released with the rest of the extension ecosystem.

Documentation:

  • Add Camera control and type reference pages plus navigation entries to the Flet documentation, including usage, platform support, and permissions guidance.
  • Add flet-camera to the list of built-in extensions and provide a package-level README with links to docs and platform support matrix.

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.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 19, 2026

Deploying flet-examples with  Cloudflare Pages  Cloudflare Pages

Latest commit: eda03a7
Status: ✅  Deploy successful!
Preview URL: https://758882b6.flet-examples.pages.dev
Branch Preview URL: https://flet-camera.flet-examples.pages.dev

View logs

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've reviewed this pull request using the Sourcery rules engine

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.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 19, 2026

Deploying flet-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: eda03a7
Status: ✅  Deploy successful!
Preview URL: https://28b3549d.flet-docs.pages.dev
Branch Preview URL: https://flet-camera.flet-docs.pages.dev

View logs

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-camera Python 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-web and 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.


/// 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.
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
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.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

FeodorFitsner and others added 7 commits February 19, 2026 15:37
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.
Copy link
Contributor

@ndonkoHenri ndonkoHenri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
}]

@ndonkoHenri
Copy link
Contributor

OK, I think the error I mentioned to have faced occured because I didnt select a camera.

  • Will be nice to handle that case - for example, by disabling the buttons.
  • Also, at app start, we could invisible the last image, so it doesnt show that placeholder.
  • The last image (and video recordings) appear to be rotated. Will be nice if they conserved input's transform.

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).
@ndonkoHenri ndonkoHenri moved this to 👀 In review in Flet Development Feb 21, 2026
@github-project-automation github-project-automation bot moved this from 👀 In review to 🏗 In progress in Flet Development Feb 21, 2026
@ndonkoHenri ndonkoHenri moved this from 🏗 In progress to 👀 In review in Flet Development Feb 21, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

2 participants