Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/flet-validation/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: flet-validation
description: Use when adding or changing validation for Python controls (dataclasses) in sdk/python/packages/, including Annotated/V rules, __validation_rules__, and property Raises docstrings.
description: Use whenever editing validation for Python controls in sdk/python/packages/: adding/changing constrained properties, `Raises: ValueError` docstrings, `before_update()` checks, `raise ValueError`, Annotated/V rules, or __validation_rules__.
---

## When To Use
Expand Down
18 changes: 9 additions & 9 deletions client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.4.1"
charcode:
dependency: transitive
description:
Expand Down Expand Up @@ -359,7 +359,7 @@ packages:
path: "../packages/flet"
relative: true
source: path
version: "0.82.2"
version: "0.85.0"
flet_ads:
dependency: "direct main"
description:
Expand Down Expand Up @@ -911,18 +911,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev"
source: hosted
version: "0.12.17"
version: "0.12.19"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
version: "0.13.0"
media_kit:
dependency: transitive
description:
Expand Down Expand Up @@ -1628,10 +1628,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
version: "0.7.7"
version: "0.7.10"
torch_light:
dependency: transitive
description:
Expand Down
51 changes: 51 additions & 0 deletions sdk/python/examples/controls/map/overlay_images/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import flet as ft
import flet_map as ftm

base64_image = "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" # noqa: E501


def main(page: ft.Page):
page.add(
ft.SafeArea(
expand=True,
content=ftm.Map(
expand=True,
initial_center=ftm.MapLatitudeLongitude(51.5, -0.09),
initial_zoom=6,
layers=[
ftm.TileLayer(
url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png"
),
ftm.OverlayImageLayer(
overlay_images=[
ftm.OverlayImage(
src=base64_image,
bounds=ftm.MapLatitudeLongitudeBounds(
corner_1=ftm.MapLatitudeLongitude(51.5, -0.09),
corner_2=ftm.MapLatitudeLongitude(48.8566, 2.3522),
),
opacity=0.8,
),
ftm.RotatedOverlayImage(
src=base64_image,
top_left_corner=ftm.MapLatitudeLongitude(
53.377, -2.999
),
bottom_left_corner=ftm.MapLatitudeLongitude(
52.503, -1.868
),
bottom_right_corner=ftm.MapLatitudeLongitude(
53.475, 0.275
),
opacity=0.8,
),
]
),
],
),
)
)


if __name__ == "__main__":
ft.run(main)
26 changes: 26 additions & 0 deletions sdk/python/examples/controls/map/overlay_images/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[project]
name = "map-overlay-images"
version = "1.0.0"
description = "Places rectangular and rotated image overlays on top of an interactive map."
requires-python = ">=3.10"
keywords = ["map", "overlay", "image", "rotated overlay"]
authors = [{ name = "Flet team", email = "hello@flet.dev" }]
dependencies = ["flet", "flet-map"]

[dependency-groups]
dev = ["flet-cli", "flet-desktop", "flet-web"]

[tool.flet.gallery]
categories = ["Extensions/Map"]

[tool.flet.metadata]
title = "Overlay Images"
controls = ["SafeArea", "Map", "TileLayer", "OverlayImageLayer", "OverlayImage", "RotatedOverlayImage"]
layout_pattern = "single-panel"
complexity = "basic"
features = ["rectangular image overlay", "rotated image overlay"]

[tool.flet]
org = "dev.flet"
company = "Flet"
copyright = "Copyright (C) 2023-2026 by Flet"
6 changes: 6 additions & 0 deletions sdk/python/packages/flet-map/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.85.0

### Added

- Added image overlay support for maps with `OverlayImageLayer`, `OverlayImage`, and `RotatedOverlayImage` ([#6319](https://github.com/flet-dev/flet/issues/6319), [#6421](https://github.com/flet-dev/flet/pull/6421)) by @ndonkoHenri.

## 0.81.1

### Added
Expand Down
10 changes: 10 additions & 0 deletions sdk/python/packages/flet-map/src/flet_map/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
from flet_map.map import Map
from flet_map.map_layer import MapLayer
from flet_map.marker_layer import Marker, MarkerLayer
from flet_map.overlay_image_layer import (
BaseOverlayImage,
OverlayImage,
OverlayImageLayer,
RotatedOverlayImage,
)
from flet_map.polygon_layer import PolygonLayer, PolygonMarker
from flet_map.polyline_layer import PolylineLayer, PolylineMarker
from flet_map.rich_attribution import RichAttribution
Expand Down Expand Up @@ -45,6 +51,7 @@

__all__ = [
"AttributionAlignment",
"BaseOverlayImage",
"Camera",
"CameraFit",
"CircleLayer",
Expand Down Expand Up @@ -73,12 +80,15 @@
"Marker",
"MarkerLayer",
"MultiFingerGesture",
"OverlayImage",
"OverlayImageLayer",
"PatternFit",
"PolygonLayer",
"PolygonMarker",
"PolylineLayer",
"PolylineMarker",
"RichAttribution",
"RotatedOverlayImage",
"SimpleAttribution",
"SolidStrokePattern",
"SourceAttribution",
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/packages/flet-map/src/flet_map/circle_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


@ft.control("CircleMarker")
class CircleMarker(ft.Control):
class CircleMarker(ft.BaseControl):
"""
A circular marker displayed on the Map at the specified
location through the :class:`~flet_map.CircleLayer`.
Expand Down
1 change: 1 addition & 0 deletions sdk/python/packages/flet-map/src/flet_map/map_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class MapLayer(ft.Control):

- :class:`~flet_map.CircleLayer`
- :class:`~flet_map.MarkerLayer`
- :class:`~flet_map.OverlayImageLayer`
- :class:`~flet_map.PolygonLayer`
- :class:`~flet_map.PolylineLayer`
- :class:`~flet_map.RichAttribution`
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/packages/flet-map/src/flet_map/marker_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


@ft.control("Marker")
class Marker(ft.Control):
class Marker(ft.BaseControl):
"""
A marker displayed on the Map at the specified location
through the :class:`~flet_map.MarkerLayer`.
Expand Down
111 changes: 111 additions & 0 deletions sdk/python/packages/flet-map/src/flet_map/overlay_image_layer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from typing import Annotated, Union

import flet as ft
from flet.utils.validation import V
from flet_map.map_layer import MapLayer
from flet_map.types import MapLatitudeLongitude, MapLatitudeLongitudeBounds

__all__ = [
"BaseOverlayImage",
"OverlayImage",
"OverlayImageLayer",
"RotatedOverlayImage",
]


@ft.control("BaseOverlayImage", kw_only=True)
class BaseOverlayImage(ft.BaseControl):
"""
Comment on lines +16 to +18
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

New controls in this module are declared with kw_only=True, but the other flet_map controls use @ft.control(...) without kw_only. This creates an inconsistent public API (some map controls accept positional args, these do not). Either drop kw_only=True here for consistency, or migrate the rest of the package to keyword-only in a dedicated change so the behavior is uniform.

Copilot uses AI. Check for mistakes.
Abstract class for image overlays displayed through
:class:`~flet_map.OverlayImageLayer`.

The following overlay image types are available:

- :class:`~flet_map.OverlayImage`
- :class:`~flet_map.RotatedOverlayImage`
"""

src: Union[str, bytes]
"""
The image source.

It can be one of the following:
- A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path;
- A base64 string;
- Raw bytes.
"""

opacity: Annotated[
ft.Number,
V.between(0.0, 1.0),
] = 1.0
"""
The opacity in which the image should get rendered on the map.

Raises:
ValueError: If it is not between `0.0` and `1.0`, inclusive.
"""

gapless_playback: bool = False
"""
Whether to continue showing the old image (`True`), or briefly show nothing
(`False`), when the image provider changes.
"""

filter_quality: ft.FilterQuality = ft.FilterQuality.MEDIUM
"""
The rendering quality of the image.
"""


@ft.control("OverlayImage", kw_only=True)
class OverlayImage(BaseOverlayImage):
"""
An unrotated image overlay that spans between a given bounding box.
"""

bounds: MapLatitudeLongitudeBounds
"""
The latitude and longitude bounds where this image will be displayed.
"""


@ft.control("RotatedOverlayImage", kw_only=True)
class RotatedOverlayImage(BaseOverlayImage):
"""
An image overlay transformed across three corner points.

The top-right corner is derived from :attr:`top_left_corner`,
:attr:`bottom_left_corner`, and :attr:`bottom_right_corner`.
"""

top_left_corner: MapLatitudeLongitude
"""
The coordinates of the top-left corner of the image.
"""

bottom_left_corner: MapLatitudeLongitude
"""
The coordinates of the bottom-left corner of the image.
"""

bottom_right_corner: MapLatitudeLongitude
"""
The coordinates of the bottom-right corner of the image.
"""


@ft.control("OverlayImageLayer", kw_only=True)
class OverlayImageLayer(MapLayer):
"""
A layer to display image overlays.

Tip:
Place this layer after every non-translucent layer that should appear
below it. Layers rendered after this one may cover its overlay images.
"""

overlay_images: list[BaseOverlayImage]
"""
A list of image overlays to display.
"""
2 changes: 1 addition & 1 deletion sdk/python/packages/flet-map/src/flet_map/polygon_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


@ft.control("PolygonMarker")
class PolygonMarker(ft.Control):
class PolygonMarker(ft.BaseControl):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Changing to BaseControl removes .visible, no?

"""
A marker for the :class:`~flet_map.PolygonLayer`.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


@ft.control("PolylineMarker")
class PolylineMarker(ft.Control):
class PolylineMarker(ft.BaseControl):
"""
A marker for the :class:`~flet_map.PolylineLayer`.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class CircleLayerControl extends StatelessWidget with FletStoreMixin {
.map((circle) {
circle.notifyParent = true;
return CircleMarker(
point: parseLatLng(circle.get("coordinates"))!,
point: circle.getLatLng("coordinates")!,
color: circle.getColor("color", context, const Color(0xFF00FF00))!,
borderColor: circle.getColor(
"border_color", context, const Color(0xFFFFFF00))!,
Expand All @@ -29,6 +29,6 @@ class CircleLayerControl extends StatelessWidget with FletStoreMixin {
radius: circle.getDouble("radius", 10)!);
}).toList();

return CircleLayer(circles: circles);
return BaseControl(control: control, child: CircleLayer(circles: circles));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
import 'circle_layer.dart';
import 'map.dart';
import 'marker_layer.dart';
import 'overlay_image_layer.dart';
import 'polygon_layer.dart';
import 'polyline_layer.dart';
import 'rich_attribution.dart';
Expand All @@ -24,6 +25,8 @@ class Extension extends FletExtension {
return TileLayerControl(key: key, control: control);
case "MarkerLayer":
return MarkerLayerControl(key: key, control: control);
case "OverlayImageLayer":
return OverlayImageLayerControl(key: key, control: control);
case "CircleLayer":
return CircleLayerControl(key: key, control: control);
case "PolygonLayer":
Expand Down
Loading
Loading