Skip to content

feat(clipboard): add image and file set/get APIs#6141

Open
ndonkoHenri wants to merge 20 commits intomainfrom
improve-clipboard
Open

feat(clipboard): add image and file set/get APIs#6141
ndonkoHenri wants to merge 20 commits intomainfrom
improve-clipboard

Conversation

@ndonkoHenri
Copy link
Contributor

@ndonkoHenri ndonkoHenri commented Feb 7, 2026

Fix #349

Related to flet-dev/flet-build-template#75

Test code

Details

import base64

import flet as ft

SAMPLE_PNG = base64.b64decode(
    "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC"
)


async def main(page: ft.Page):
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    async def set_image_to_clipboard(e: ft.Event[ft.Button]):
        await ft.Clipboard().set_image(SAMPLE_PNG)
        status.value = f"Sample image copied to clipboard ({len(SAMPLE_PNG)} bytes)."
        preview.content = ft.Image(src=SAMPLE_PNG)

    async def get_image_from_clipboard(e: ft.Event[ft.Button]):
        clipboard_image = await ft.Clipboard().get_image()
        if clipboard_image is None:
            status.value = "No image found in clipboard."
            preview.content = None
            return
        else:
            preview.content = ft.Image(src=clipboard_image)
            status.value = (
                f"Image loaded from clipboard ({len(clipboard_image)} bytes)."
            )

    page.add(
        ft.SafeArea(
            ft.Column(
                horizontal_alignment=ft.CrossAxisAlignment.CENTER,
                controls=[
                    ft.Button(
                        "Set example image to clipboard",
                        on_click=set_image_to_clipboard,
                        disabled=not (page.web or page.platform.is_mobile()),
                        tooltip="Supported on mobile platforms only."
                        if not (page.web or page.platform.is_mobile())
                        else None,
                    ),
                    ft.Button(
                        "Get image from clipboard",
                        on_click=get_image_from_clipboard,
                    ),
                    status := ft.Text(),
                    preview := ft.Container(width=360, height=240),
                ],
            )
        )
    )


ft.run(main)

Summary by Sourcery

Add cross-platform clipboard support for images and files and strengthen service-related testing and platform integration.

New Features:

  • Expose Clipboard service APIs to set and get image bytes.
  • Expose Clipboard service APIs to set and get file references across supported platforms.
  • Provide Python examples demonstrating clipboard usage for strings, images, and files.

Bug Fixes:

  • Fix Cupertino text field shadow property binding to use the correct control attribute.

Enhancements:

  • Guard new clipboard image and file APIs with explicit platform checks and dedicated exceptions.
  • Wire Flutter clipboard service through the pasteboard plugin and shared Uint8List conversion helper.
  • Make test fixtures set and restore the global page context to avoid leakage between tests.

Build:

  • Add pasteboard as a Flutter dependency and register its plugins on Android, iOS, macOS, Windows, and Linux.
  • Configure Android FileProvider and path XML for sharing file references via clipboard.
  • Override the Flutter flet package in the Python build test app to use the local package path.
  • Raise the iOS minimum deployment target to 14.0 in project configuration.

CI:

  • Include services integration tests in the macOS GitHub Actions workflow.

Documentation:

  • Restructure clipboard documentation to cover separate examples for strings, images, and files.

Tests:

  • Add integration tests for clipboard text, image, and file operations with platform-specific expectations.
  • Add integration tests for storage paths covering supported and unsupported platforms.
  • Add integration tests for shared preferences CRUD flows.
  • Add integration tests for battery service level, state, and power save mode.

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

@cloudflare-workers-and-pages
Copy link

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

Deploying flet-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2fe5a57
Status: ✅  Deploy successful!
Preview URL: https://2749b71d.flet-docs.pages.dev
Branch Preview URL: https://improve-clipboard.flet-docs.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link

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

Deploying flet-examples with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2fe5a57
Status: ✅  Deploy successful!
Preview URL: https://dbbc2bfb.flet-examples.pages.dev
Branch Preview URL: https://improve-clipboard.flet-examples.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 new clipboard capabilities (images + file references) to Flet by extending the Python Clipboard service API and implementing corresponding Flutter-side handlers, alongside new integration tests and examples.

Changes:

  • Extend Python Clipboard service with set_image/get_image and set_files/get_files APIs, plus updated docs/examples.
  • Implement new clipboard method handlers on the Flutter client using the pasteboard plugin and add supporting utility changes.
  • Add/enable integration tests for services (clipboard, battery, storage paths, shared preferences) and CI wiring.

Reviewed changes

Copilot reviewed 27 out of 30 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
sdk/python/packages/flet/src/flet/controls/services/clipboard.py Adds image/file clipboard APIs and platform guards to Python service layer.
sdk/python/packages/flet/integration_tests/controls/services/test_storage_paths.py Adds integration coverage for StoragePaths across supported/unsupported platforms.
sdk/python/packages/flet/integration_tests/controls/services/test_shared_preferences.py Adds CRUD integration coverage for SharedPreferences.
sdk/python/packages/flet/integration_tests/controls/services/test_clipboard.py Adds integration coverage for clipboard text/image/files behavior.
sdk/python/packages/flet/integration_tests/controls/services/test_battery.py Adds integration coverage for Battery service.
sdk/python/packages/flet/integration_tests/conftest.py Ensures ft.context.page is set during tests and prevents context leakage.
sdk/python/packages/flet/integration_tests/README.md Documents how to run the new services integration tests.
sdk/python/packages/flet/docs/services/clipboard.md Updates clipboard docs to include strings/images/files examples.
sdk/python/examples/services/clipboard/strings.py Updates strings example to use controls=[...] argument style.
sdk/python/examples/services/clipboard/images.py New example demonstrating image clipboard set/get.
sdk/python/examples/services/clipboard/files.py New example demonstrating file reference clipboard set/get.
sdk/python/examples/controls/alert_dialog/media/modal_and_non_modal.gif Media asset change included in PR.
sdk/python/examples/apps/flet_build_test/pyproject.toml Adds Flutter dependency override for local flet package in build test app.
packages/flet/pubspec.yaml Adds pasteboard dependency to enable image/files clipboard support.
packages/flet/lib/src/utils/images.dart Exposes a reusable convertToUint8List() helper (rename from private).
packages/flet/lib/src/services/clipboard.dart Implements new clipboard methods via pasteboard plugin.
packages/flet/lib/src/controls/cupertino_textfield.dart Fixes box shadow property lookup key (shadowshadows).
client/windows/flutter/generated_plugins.cmake Registers pasteboard plugin for Windows client.
client/windows/flutter/generated_plugin_registrant.cc Registers pasteboard plugin for Windows client (C++ registrant).
client/pubspec.lock Records resolved pasteboard dependency in the client lockfile.
client/macos/Flutter/GeneratedPluginRegistrant.swift Registers pasteboard plugin for macOS client.
client/linux/flutter/generated_plugins.cmake Registers pasteboard plugin for Linux client.
client/linux/flutter/generated_plugin_registrant.cc Registers pasteboard plugin for Linux client (C++ registrant).
client/ios/Runner.xcodeproj/project.pbxproj Bumps iOS deployment target in Xcode project settings.
client/ios/Podfile.lock Updates iOS pods lockfile to include new/updated dependencies.
client/ios/Podfile Sets iOS platform minimum version to 14.0.
client/ios/Flutter/AppFrameworkInfo.plist Bumps MinimumOSVersion to 14.0.
client/android/app/src/main/res/xml/provider_paths.xml Adds FileProvider paths configuration used for file URI sharing.
client/android/app/src/main/AndroidManifest.xml Adds FileProvider entry to support file URI grants.
.github/workflows/macos-integration-tests.yml Enables running services integration tests in macOS CI job.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
platform :ios, '14.0'
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

This PR bumps the iOS minimum deployment target to 14.0. That’s a breaking platform support change and isn’t mentioned in the PR description; please document the requirement (e.g., dependency constraint from pasteboard) and confirm dropping iOS 13 is intended for all clients.

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +6
from flet.controls.exceptions import FletUnimplementedPlatformException
from flet.controls.services.service import Service
from flet.controls.types import PagePlatform
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Platform checks in services typically raise FletUnsupportedPlatformException (meaning the operation isn’t supported), whereas FletUnimplementedPlatformException is documented as “not implemented yet”. Since these clipboard APIs are implemented on some platforms, consider switching to FletUnsupportedPlatformException (and updating the docstrings accordingly) for consistency with other services (e.g., StoragePaths).

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +50

Raises:
FletUnimplementedPlatformException: If called on platforms other than the
following: Android, iOS, Web.
"""
if not (self.page.web or self.page.platform.is_mobile()):
raise FletUnimplementedPlatformException(
"set_image is not supported on this platform"
)
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

The Python API currently blocks set_image() on desktop platforms, but the Flutter backend implements the "set_image" method unconditionally. Unless there’s a known platform limitation, this guard will unnecessarily prevent desktop usage and make the Python-side supported-platform list diverge from the backend.

Suggested change
Raises:
FletUnimplementedPlatformException: If called on platforms other than the
following: Android, iOS, Web.
"""
if not (self.page.web or self.page.platform.is_mobile()):
raise FletUnimplementedPlatformException(
"set_image is not supported on this platform"
)
"""

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +38
assert await prefs.contains_key(key_1) is False
assert await prefs.set(key_1, "value-1") is True
assert await prefs.set(key_2, "value-2") is True
assert await prefs.get(key_1) == "value-1"
assert await prefs.contains_key(key_1) is True

keys = await prefs.get_keys(prefix)
assert key_1 in keys
assert key_2 in keys

assert await prefs.remove(key_1) is True
assert await prefs.contains_key(key_1) is False
assert await prefs.get(key_1) is None

assert await prefs.clear() is True
assert await prefs.get(key_2) is None
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

This 'assert' statement contains an expression which may have side effects.

Suggested change
assert await prefs.contains_key(key_1) is False
assert await prefs.set(key_1, "value-1") is True
assert await prefs.set(key_2, "value-2") is True
assert await prefs.get(key_1) == "value-1"
assert await prefs.contains_key(key_1) is True
keys = await prefs.get_keys(prefix)
assert key_1 in keys
assert key_2 in keys
assert await prefs.remove(key_1) is True
assert await prefs.contains_key(key_1) is False
assert await prefs.get(key_1) is None
assert await prefs.clear() is True
assert await prefs.get(key_2) is None
contains_1_initial = await prefs.contains_key(key_1)
assert contains_1_initial is False
set_1_result = await prefs.set(key_1, "value-1")
assert set_1_result is True
set_2_result = await prefs.set(key_2, "value-2")
assert set_2_result is True
value_1 = await prefs.get(key_1)
assert value_1 == "value-1"
contains_1_after_set = await prefs.contains_key(key_1)
assert contains_1_after_set is True
keys = await prefs.get_keys(prefix)
assert key_1 in keys
assert key_2 in keys
removed = await prefs.remove(key_1)
assert removed is True
contains_1_after_remove = await prefs.contains_key(key_1)
assert contains_1_after_remove is False
value_1_after_remove = await prefs.get(key_1)
assert value_1_after_remove is None
cleared = await prefs.clear()
assert cleared is True
value_2_after_clear = await prefs.get(key_2)
assert value_2_after_clear is None

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fetch image from a clipboard

1 participant