Skip to main content

ยท 2 min read
Feodor Fitsner

๐ŸŽ‰ Whoo-hoo, Flet app is now on App Store! ๐ŸŽ‰

With Flet iOS app you can see how your Flet Python app looks and behaves on iPhone or iPad while the app itself is running on your computer.

But it's more than just testing Flet apps on the phone! Flet mobile app itself is written in Python and its publishing to App Store is an important milestone for the entire Flet project. It is a successful proof that you can create awesome mobile apps in Python only and package them so that they are accepted in App Store!

Follow this guide to get started with testing your Flet apps on iPhone or iPad. Explore the app, browse gallery, play with sample projects and app settings.

I would like to thank Kivy project for making a toolchain for iOS which we used to compile Python interpreter and dependencies for iOS devices. We published serious_python package for adding Python runtime to any Flutter app.

FAQโ€‹

When Android is supported?โ€‹

Soon. It has #1 priority now and we've already started working on it.

How to package my Flet app for App Store?โ€‹

We are going to provide a project template for bootstrap Flutter app and a guide how to combine Flutter, serious_python package and your Python app together to create a standalone iOS app and publish it to App Store.

Later this year we'll create a CI pipeline to fully automate the process.

Check serious_python's readme for instructions on how create a Flutter bootstrap and package your Python app to run within it. Use flet_example project as a starting point.

Flet v0.8.0 release notesโ€‹

For testing on iOS you need to upgrade your Flet installation to v0.8.0.

It's been changed a lot in v0.8.0 and there were some breaking changes. Bear with us while you are upgrading to 0.8.0 and let us know if you have any troubles with it.

Enjoy!

ยท 5 min read
Feodor Fitsner

Flet 0.7.1 enables developers changing scroll position and receiving scroll notifications from Page, View, Column, Row, ListView and GridView controls.

The release also introduces theming improvements:

Controlling scroll positionโ€‹

Scrollable controls (Page, View, Column, Row, ListView and GridView) introduce scroll_to() method to change their scroll position to either absolute offset, relative delta or jump to the control with specified key.

Moving to a key is particularly exciting as it allows simulating the navigation between page bookmarks, kind of HTML hrefs with #:

Check the source code of the example above.

See Column.scroll_to for more details about controlling scroll position.

Receiving scroll notificationsโ€‹

All scrollable controls now provide on_scroll event handler which fires when a scroll position is changed. From event object properties you can determine whether scroll operation has started, finished, changed direction or scroll position went behind scrolling extent (overscroll). You can also get updates of the current scroll position as well as dimensions of the scroll area, for example:

import flet as ft

def main(page: ft.Page):
def on_column_scroll(e: ft.OnScrollEvent):
print(
f"Type: {e.event_type}, pixels: {e.pixels}, min_scroll_extent: {e.min_scroll_extent}, max_scroll_extent: {e.max_scroll_extent}"
)

cl = ft.Column(
spacing=10,
height=200,
width=200,
scroll=ft.ScrollMode.ALWAYS,
on_scroll=on_column_scroll,
)
for i in range(0, 50):
cl.controls.append(ft.Text(f"Text line {i}", key=str(i)))

page.add(
ft.Container(cl, border=ft.border.all(1)),
)

ft.app(main)

See Column.on_scroll for more details about scroll notification.

Check infinite scroll example.

Color scheme customizationโ€‹

Until today the only way to control color scheme for your application was specifying color_scheme_seed when creating a new ft.Theme object.

This release enables you to fine tune all 30 colors based on the Material spec and used by various Flet controls.

You can even use Material Theme Builder and apply exported color palette to your app, for example:

page.theme = ft.Theme(
color_scheme=ft.ColorScheme(
primary=ft.colors.GREEN,
primary_container=ft.colors.GREEN_200
# ...
),
)

See ColorScheme class for more details.

Nested themesโ€‹

Another awesome feature of this release is nested themes!

You can have a part of your app to use a different theme or override some theme styles for specific controls.

Remember page object having theme and theme_mode properties? Now Container has theme and theme_mode properties too!

Container.theme accepts the same ft.Theme object as a page. Specifying theme_mode in the container means you don't want to inherit parent theme, but want a completely new, unique scheme for all controls inside the container. However, if the container does not have theme_mode property set then the styles from its theme property will override the ones from the parent, inherited theme:

import flet as ft

def main(page: ft.Page):
# Yellow page theme with SYSTEM (default) mode
page.theme = ft.Theme(
color_scheme_seed=ft.colors.YELLOW,
)

page.add(
# Page theme
ft.Container(
content=ft.ElevatedButton("Page theme button"),
bgcolor=ft.colors.SURFACE_VARIANT,
padding=20,
width=300,
),

# Inherited theme with primary color overridden
ft.Container(
theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.colors.PINK)),
content=ft.ElevatedButton("Inherited theme button"),
bgcolor=ft.colors.SURFACE_VARIANT,
padding=20,
width=300,
),

# Unique always DARK theme
ft.Container(
theme=ft.Theme(color_scheme_seed=ft.colors.INDIGO),
theme_mode=ft.ThemeMode.DARK,
content=ft.ElevatedButton("Unique theme button"),
bgcolor=ft.colors.SURFACE_VARIANT,
padding=20,
width=300,
),
)

ft.app(main)

Scrollbar themeโ€‹

You can now customize the look and fill of scrollbars in your application (or a particular scroillbar with nested themes).

It could be done via page.theme.scrollbar_theme property, for example:

page.theme = ft.Theme(
scrollbar_theme=ft.ScrollbarTheme(
track_color={
ft.MaterialState.HOVERED: ft.colors.AMBER,
ft.MaterialState.DEFAULT: ft.colors.TRANSPARENT,
},
track_visibility=True,
track_border_color=ft.colors.BLUE,
thumb_visibility=True,
thumb_color={
ft.MaterialState.HOVERED: ft.colors.RED,
ft.MaterialState.DEFAULT: ft.colors.GREY_300,
},
thickness=30,
radius=15,
main_axis_margin=5,
cross_axis_margin=10,
)
)

Text themingโ€‹

Material 3 design defines 5 groups of text styles with 3 sizes in each group: "Display", "Headline", "Title", "Label" and "Body" which are used across Flet controls. You can now customize each of those styles with page.theme.text_theme, for example:

import flet as ft

def main(page: ft.Page):
page.theme = ft.Theme(
text_theme=ft.TextTheme(body_medium=ft.TextStyle(color=ft.colors.GREEN))
)

page.add(ft.Text("Hello, green world!"))

ft.app(main)

Apparently, Body Medium is used by Text control as a default style.

See TextTheme class for more details.

Tabs themingโ€‹

You can now control the look and feel of Tabs control. In this release Tabs adds a bunch of new properties and there is a new page.theme.tabs_theme property to style all tabs in your app:

page.theme = ft.Theme(
tabs_theme=ft.TabsTheme(
divider_color=ft.colors.BLUE,
indicator_color=ft.colors.RED,
indicator_tab_size=True,
label_color=ft.colors.GREEN,
unselected_label_color=ft.colors.AMBER,
overlay_color={
ft.MaterialState.FOCUSED: ft.colors.with_opacity(0.2, ft.colors.GREEN),
ft.MaterialState.DEFAULT: ft.colors.with_opacity(0.2, ft.colors.PINK),
},
)
)

See TabsTheme class for more details.

Other changesโ€‹

Flutter 3.10โ€‹

This Flet release is based on Flutter 3.10 which brings new features, performance and size optimizations. As a result, most of Flet dependencies bumped their versions too, so if you notice any issues please let us know.

Color emoji in web appsโ€‹

Color emoji support in web apps are back! In Flutter 3.7 color emoji were disabled in "CanvasKit" renderer (default in Flet) because of their font size (8 MB!) and returned back as an opt-in in Flutter 3.10. You can enable color emoji in server-driven app with use_color_emoji argument:

ft.app(main, use_color_emoji=True)

and use --use-color-emoji switch when publishing app as a static side.

That's all for today!

Upgrade Flet module to the latest version (pip install flet --upgrade) and let us know what you think!

ยท 3 min read
Feodor Fitsner

Unleash your inner artist ๐Ÿง‘โ€๐ŸŽจ and boost your Flet creativity with brand-new Canvas control just released in Flet 0.6.0!

Canvas enables you to draw arbitrary graphics using a set of primitives, or "shapes", such as line, circle, arc, path and text. I bet you can even implement your own version of charts using Canvas control!

Combine Canvas with GestureDetector and you get a free-hand drawing app - Flet Brush ๐Ÿ˜€!

Example source

Canvas control is located in flet.canvas package. You need another import to use it:

import flet.canvas as cv

Here's a simple program drawing a smiley face with Circle and Arc shapes using filled and stroke Paint:

import math
import flet as ft
import flet.canvas as cv

def main(page: ft.Page):
stroke_paint = paint = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE)
fill_paint = paint = ft.Paint(style=ft.PaintingStyle.FILL)
cp = cv.Canvas(
[
cv.Circle(100, 100, 50, stroke_paint),
cv.Circle(80, 90, 10, stroke_paint),
cv.Circle(84, 87, 5, fill_paint),
cv.Circle(120, 90, 10, stroke_paint),
cv.Circle(124, 87, 5, fill_paint),
cv.Arc(70, 95, 60, 40, 0, math.pi, paint=stroke_paint),
],
width=float("inf"),
expand=True,
)

page.add(cp)

ft.app(main)

Read more about Canvas in docs and explore Canvas examples!

Other changesโ€‹

Rich text supportโ€‹

While working on drawing text on Canvas, as a bonus to this release, we implemented a new TextSpan control which can now be used with Text.spans to output rich text.

Check rich text examples: one, two and three.

url property for buttonsโ€‹

If you need to open a URL by clicking on a button or any other control with on_click event you can just provide that URL in url instead of doing that in the code with page.launch_url() method.

Instead of that:

ft.ElevatedButton("Go to Google", on_click=lambda e: e.page.launch_url("https://google.com"))

you can just do this:

ft.ElevatedButton("Go to Google", url="https://google.com")

A new url property also solves blocked window on Safari issue.

As a continuation of url property Markdown control can now be enabled to auto-follow URLs in the document:

import flet as ft

md = """
[Go to Google](https://www.google.com)
"""

def main(page: ft.Page):
page.add(
ft.Markdown(
md,
extension_set=ft.MarkdownExtensionSet.GITHUB_WEB,
auto_follow_links=True,
)
)

ft.app(main)

Better web supportโ€‹

In this release we also did some improvements to web support like capturing user info in page.client_id and page.client_user_agent as well as fixing nasty #1333 and #1289 bugs related to routing.

That's all for today!

Upgrade Flet module to the latest version (pip install flet --upgrade), give canvas and rich text a try and let us know what you think!

ยท 2 min read
Feodor Fitsner

Last year we introduced support for Matplotlib and Plotly charts. Both libraries are able to export charts as SVG images which are then displayed in a Flet app. However, such charts, while serving the purpose of visualization, are lacking interactivity and animation.

Today we are releasing Flet 0.5.2 with built-in charts ๐Ÿ“Š based on the awesome fl_chart library!

Three new chart controls have been introduced:

LineChartโ€‹

Docs ยท Examples

BarChartโ€‹

Docs ยท Examples

PieChartโ€‹

Docs ยท Examples

note

We spent a lot of time studying fl_chart library while trying to implement most of its features in a Flet way. However, if you see anything missing in Flet, but available in a library please submit a new feature request.

Other changesโ€‹

Pyodide 0.23โ€‹

Pyodide, which provides Python runtime in a browser and is used to run Flet app as a static website, was upgraded to version 0.23 which is based on Python 3.11.2 and giving some size and performance improvements.

Memory leak fixesโ€‹

In this release we paid a lot of attention to memory leak issues in Flet apps. Now, when a user session is closed its memory is reliably released and garbage-collected. That makes Flet ready for production applications with a lot of users.

Upgrade Flet module to the latest version (pip install flet --upgrade), give charts a try and let us know what you think!

Hey, Flet project has reached โญ๏ธ 5K stars โญ๏ธ - thank you all for your continuing support!

ยท 4 min read
Feodor Fitsner

We've just released Flet 0.4.0 with a super exciting new feature - packaging Flet apps into a standalone static website that can be run entirely in the browser! The app can be published to any free hosting for static websites such as GitHub Pages or Cloudflare Pages. Thanks to Pyodide - a Python port to WebAssembly!

You can quickly build awesome single-page applications (SPA) entirely in Python and host them everywhere! No HTML, CSS or JavaScript required!

Quick Flet with Pyodide demoโ€‹

Install the latest Flet package:

pip install flet --upgrade

Create a simple counter.py app:

counter.py
import flet as ft

def main(page: ft.Page):
page.title = "Flet counter example"
page.vertical_alignment = ft.MainAxisAlignment.CENTER

txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100)

def minus_click(e):
txt_number.value = str(int(txt_number.value) - 1)
page.update()

def plus_click(e):
txt_number.value = str(int(txt_number.value) + 1)
page.update()

page.add(
ft.Row(
[
ft.IconButton(ft.icons.REMOVE, on_click=minus_click),
txt_number,
ft.IconButton(ft.icons.ADD, on_click=plus_click),
],
alignment=ft.MainAxisAlignment.CENTER,
)
)

ft.app(main)

Run a brand-new flet publish command to publish Flet app as a static website:

flet publish counter.py

The website will be published to dist directory next to counter.py. Give website a try using built-in Python web server:

python -m http.server --directory dist

Open http://localhost:8000 in your browser to check the published app.

Here are a few live Flet apps hosted at Cloudflare Pages:

Check the guide for more information about publishing Flet apps as standalone websites.

Built-in Fletd server in Pythonโ€‹

Flet 0.4.0 also implements a new Flet desktop architecture.

It replaces Fletd server written in Go with a light-weight shim written in Python with a number of pros:

  1. Only 2 system processes are needed to run Flet app: Python interpreter and Flutter client.
  2. Less communication overhead (minus two network hops between Python and Fletd) and lower latency (shim uses TCP on Windows and Unix domain sockets on macOS/Linux).
  3. Shim binds to 127.0.0.1 on Windows by default which is more secure.
  4. The size of a standalone app bundle produced by flet pack reduced by ~8 MB.

The implementation was also required to support Pyodide (we can't run Go web server in the browser, right?) and paves the way to iOS and Android support.

Other changesโ€‹

  • All controls loading resources from web URLs (Image.src, Audio.src, Page.fonts, Container.image_src) are now able to load them from local files too, by providing a full path in the file system, and from assets directory by providing relative path. For desktop apps a path in src property could be one of the following:
    • A path relative to assets directory, with or without starting slash, for example: /image.png or image.png. The name of artifact dir should not be included.
    • An absolute path within a computer file system, e.g. C:\projects\app\assets\image.png or /Users/john/images/picture.png.
    • A full URL, e.g. https://mysite.com/images/pic.png.
    • Add page.on_error = lambda e: print("Page error:", e.data) to see failing images.
  • flet Python package has separated into two packages: flet-core and flet.
  • PDM replaced with Poetry.
  • beartype removed everywhere.

๐Ÿ’ฅ Breaking changesโ€‹

  • Default routing scheme changed from "hash" to "path" (no /#/ at the end of app URL). Use ft.app(main, route_url_strategy="hash") to get original behavior.
  • OAuth authentication is not supported anymore in standalone desktop Flet apps.

Async supportโ€‹

Flet apps can now be written as async apps and use asyncio with other Python async libraries. Calling coroutines is naturally supported in Flet, so you don't need to wrap them to run synchronously.

To start with an async Flet app you should make main() method async:

import flet as ft

async def main(page: ft.Page):
await page.add_async(ft.Text("Hello, async world!"))

ft.app(main)

Read the guide for more information about writing async Flet apps.

Conclusionโ€‹

Flet 0.4.0 brings the following exciting features:

  • Standalone web apps with Pyodide running in the browser and hosted on a cheap hosting.
  • Faster and more secure architecture with a built-in Fletd server.
  • Async apps support.

Upgrade Flet module to the latest version (pip install flet --upgrade), give flet publish command a try and let us know what you think!

Hey, by the way, Flet project has reached โญ๏ธ 4.2K stars โญ๏ธ (+1K in just one month) - keep going!