diff --git a/.fvmrc b/.fvmrc index 6b3d30c248..4e46fba09b 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.47.7" + "flutter": "3.47.8" } diff --git a/CHANGELOG.md b/CHANGELOG.md index a9cf707de8..345261e9d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ * Add `Theme.markdown_theme`: a default `MarkdownStyleSheet` for every `Markdown`, with a control's own `md_style_sheet` applied on top property by property by @FeodorFitsner. * Add `PopupMenuTheme.border_radius` to set the default hover/splash corner radius of every `PopupMenuButton` by @FeodorFitsner. -* Bump the bundled Flutter to [3.47.7](https://github.com/flutter/flutter/blob/stable/CHANGELOG.md#3477) (from 3.44.8). Android builds use Gradle 9.3.1, Android Gradle Plugin 8.13.2 and Kotlin 2.3.21 by @ndonkoHenri. +* Bump the bundled Flutter to [3.47.8](https://github.com/flutter/flutter/blob/stable/CHANGELOG.md#3478) (from 3.44.8). Android builds use Gradle 9.3.1, Android Gradle Plugin 8.13.2 and Kotlin 2.3.21 ([#6916](https://github.com/flet-dev/flet/pull/6916), [#7023](https://github.com/flet-dev/flet/pull/7023)) by @ndonkoHenri. **Compatibility:** Desktop apps and the desktop app that `flet run` opens now render with Impeller, Flutter 3.47's default desktop renderer, instead of Skia. Use `flet build --no-impeller` (or `impeller = false` under `[tool.flet]`), `flet run --no-impeller` or the `FLET_NO_IMPELLER` environment variable to render with Skia; see [Renderer](/docs/publish#renderer). Android plugins that still use `jcenter()` or other APIs removed in Gradle 9 no longer build. `flet build` downloads Flutter 3.47.7 on first use. @@ -59,14 +59,14 @@ ### Bug fixes -* Fix `use_state()` type inference for callable initializers in mypy and ty ([#6960](https://github.com/flet-dev/flet/issues/6960), [#7014](https://github.com/flet-dev/flet/pull/7014)) by @mmporong. +* Fix `use_state()` and `use_ref()` type inference for callable initializers in mypy and ty ([#6960](https://github.com/flet-dev/flet/issues/6960), [#7014](https://github.com/flet-dev/flet/pull/7014), [#7023](https://github.com/flet-dev/flet/pull/7023)) by @mmporong. * Fix `flet build` apps showing a blank page when the system suspended them while Python was starting, such as when iOS launches an app in the background for a notification action ([#6999](https://github.com/flet-dev/flet/pull/6999)) by @ndonkoHenri. * Fix `flet build` naming a Linux app's icons `None.png` and leaving the iOS frameworks it builds from the app's packages under shared identifiers when no `bundle_id` is set ([#6999](https://github.com/flet-dev/flet/pull/6999)) by @ndonkoHenri. * Fix `flet build` writing numbers in `[tool.flet.macos.entitlement]`, `[tool.flet.ios.info]` and `[tool.flet.macos.info]` as strings, producing invalid plists when keys or values contain `&` or `<`, and failing when a `pyproject.toml` value contains `{{` ([#6999](https://github.com/flet-dev/flet/pull/6999)) by @ndonkoHenri. * Fix `FilePicker` dialogs failing with a timeout after being open for an hour ([#6999](https://github.com/flet-dev/flet/pull/6999)) by @ndonkoHenri. * Fix `flet build` failing on every rebuild after one with changed build options, in apps with Flutter extensions ([#7010](https://github.com/flet-dev/flet/issues/7010), [#7012](https://github.com/flet-dev/flet/pull/7012)) by @ndonkoHenri. * Fix `flet build` not reinstalling the app's packages after `requirements.txt` is edited or `build/site-packages` is deleted ([#6994](https://github.com/flet-dev/flet/issues/6994), [#6996](https://github.com/flet-dev/flet/pull/6996)) by @ndonkoHenri. -* Fix `flet test` failing when the app under test starts slowly, as on the first run after a build: the test now waits until the app finishes initializing its first page ([#6993](https://github.com/flet-dev/flet/issues/6993), [#6995](https://github.com/flet-dev/flet/pull/6995)) by @ndonkoHenri. +* Fix `flet test` failing when the app under test starts slowly, as on the first run after a build: the test now waits until the app finishes initializing its first page, and fails right away with the Python traceback when the app's Python program fails to start ([#6993](https://github.com/flet-dev/flet/issues/6993), [#6995](https://github.com/flet-dev/flet/pull/6995), [#7023](https://github.com/flet-dev/flet/pull/7023)) by @ndonkoHenri. * Fix `use_effect()` cleanups being skipped: a cleanup returned by the setup was lost once the component re-rendered, only one ran when `cleanup=` was passed too, and `async` cleanups never ran when a dependency change re-ran the effect. A pending `async` setup is also cancelled on unmount ([#6963](https://github.com/flet-dev/flet/issues/6963), [#6983](https://github.com/flet-dev/flet/pull/6983), [#7005](https://github.com/flet-dev/flet/pull/7005)) by @mangod12. * iOS apps built with `flet build ipa` no longer fail App Store Connect validation with ITMS-90683 (missing `NSPhotoLibraryUsageDescription` and `NSCameraUsageDescription` purpose strings): the `file_picker` plugin is updated to 13.x, which picks photos with the system photo picker and no longer links DKImagePickerController's camera and photo-library code. `device_info_plus`, `package_info_plus` and `share_plus` move to their next major versions with it (`win32` 6). `FilePicker.save_file()` on desktop now creates the chosen file (empty when no `src_bytes` are given) before returning its path by @FeodorFitsner. * Fix `Tester.find_by_key()` not finding `Tab` and `PopupMenuItem` controls by their keys ([#6965](https://github.com/flet-dev/flet/issues/6965), [#6976](https://github.com/flet-dev/flet/pull/6976)) by @RezaShamsipour. diff --git a/packages/flet/CHANGELOG.md b/packages/flet/CHANGELOG.md index 058ca5d23f..0d1c677b9d 100644 --- a/packages/flet/CHANGELOG.md +++ b/packages/flet/CHANGELOG.md @@ -1,5 +1,6 @@ ## 1.1.0 +* Flutter updated to [3.47.8](https://github.com/flutter/flutter/blob/stable/CHANGELOG.md#3478). * Update `file_picker` to 13.x (federated; iOS picks media with `PHPickerViewController`, dropping DKImagePickerController, whose camera and photo-library references made App Store Connect demand purpose strings). `FilePickerService` uses `pickFile()`/`pickFiles()`, reads bytes and uploads through `PlatformFile.readAsBytes()`/`readAsByteStream()`, passes `lockParentWindow` through `WindowsOptions`/`LinuxOptions` and `cancel_upload_on_window_blur` through `file_picker_web`'s `FilePickerWebOptions` (imported only on web). `saveFile()` always writes the file, so desktop saves without `src_bytes` create it empty. Bump `device_info_plus` to ^13.3.0, `package_info_plus` to ^10.2.2 and `share_plus` to ^13.3.1 (`win32` 6, required by file_picker 13's Windows implementation) by @FeodorFitsner. * Apply `min_width`/`max_width`/`min_height`/`max_height` to every `LayoutControl` as a `ConstrainedBox` around the control (outside any fixed size). A control that implements one of these names itself lists it in `skip_properties` (`ListTile.min_height`, `NavigationRail.min_width`) by @FeodorFitsner. * Pass `material_tap_target_size` to `Switch` and `ThemeData` (`parseMaterialTapTargetSize()`) by @FeodorFitsner. @@ -22,7 +23,6 @@ * An embedded page builds its `Navigator` with `requestFocus: false`, so pushing its routes doesn't move the focus out of the host app by @FeodorFitsner. * `PageControl` wraps an embedded page's app in a `CupertinoTheme` derived from the page's own Material theme (top-level pages are unchanged). Flutter's `Theme` reuses an ambient `CupertinoTheme` when one exists above it instead of deriving one from its `ThemeData`, so an embedded page's Cupertino widgets took the host app's colors by @FeodorFitsner. * `CupertinoButtonControl` falls back to the `ButtonStyle` in `internals["style"]` - what an adaptive Material `Button` sends - for background, foreground and padding when `bgcolor`/`color`/`padding` are absent by @FeodorFitsner. -* Flutter updated to [3.47.7](https://github.com/flutter/flutter/blob/stable/CHANGELOG.md#3477). * **Breaking:** `parseTheme()` now builds themes from a seed with neutral surfaces by default (`#ffffff` / `#121212` and a neutral grey ramp for surface containers, `onSurface`, `outline` and inverse surfaces); the seed still drives accent colors. A theme's `surfaces: "tonal"` restores the seed-tinted Material 3 surfaces. Adds the `ThemeSurfaces` enum, `parseThemeSurfaces()` and `neutralizeSurfaces()` ([#6921](https://github.com/flet-dev/flet/issues/6921)) by @FeodorFitsner. * Import Material and Cupertino from the `material_ui` and `cupertino_ui` packages instead of `package:flutter/material.dart` and `package:flutter/cupertino.dart`. Helpers that take or return Material or Cupertino types, such as `parseColor()`, `parseTextStyle()` and `parseButtonStyle()`, now use those packages' types, and `flet.dart` no longer re-exports `Icons` and `CupertinoIcons`. Requires Flutter 3.47 or later. * Add `markdownStyleSheetFromTheme()`, which builds the default `MarkdownStyleSheet` from a `material_ui` theme. `MarkdownStyleSheet.fromTheme()` from `flutter_markdown_plus` only accepts the Flutter SDK's `ThemeData`. diff --git a/packages/flet_integration_test/lib/src/app_startup.dart b/packages/flet_integration_test/lib/src/app_startup.dart index 9b33b0b6ad..898a82f3da 100644 --- a/packages/flet_integration_test/lib/src/app_startup.dart +++ b/packages/flet_integration_test/lib/src/app_startup.dart @@ -9,12 +9,22 @@ import 'package:flutter_test/flutter_test.dart'; /// the first launch after a build, when antivirus software scans the bundle, /// so a fixed number of frames is not enough. Throws when the app reports a /// startup error or has not loaded within [timeout]. +/// +/// A startup error includes the embedded Python program failing before it +/// connects, such as an exception raised while importing the app's modules. +/// The app reports that on its boot screen rather than through the Flet +/// protocol, so the thrown exception carries the boot screen's error text, +/// including the Python traceback. Future waitForAppLoaded(WidgetTester tester, {Duration timeout = const Duration(minutes: 2)}) async { final deadline = tester.binding.clock.now().add(timeout); while (true) { await tester.pump(const Duration(milliseconds: 100)); final backend = _findFletBackend(tester); + final bootError = backend?.bootStatus.value.error; + if (bootError != null && bootError.isNotEmpty) { + throw Exception("The app failed to start:\n$bootError"); + } if (backend != null && !backend.isLoading) { if (backend.error.isNotEmpty) { throw Exception("The app failed to start: ${backend.error}"); diff --git a/packages/flet_integration_test/test/app_startup_test.dart b/packages/flet_integration_test/test/app_startup_test.dart index 7863624774..60b1359780 100644 --- a/packages/flet_integration_test/test/app_startup_test.dart +++ b/packages/flet_integration_test/test/app_startup_test.dart @@ -74,6 +74,22 @@ void main() { contains('Initialization failed')))); }); + testWidgets('a Python program that fails to start fails with its traceback', + (tester) async { + final backend = await _mountApp(tester); + // The embedded Python program exits before it connects, so the backend + // is still loading and only the boot screen shows the error. + Timer(const Duration(milliseconds: 300), () { + backend.bootStatus.value = const BootStatus(BootStage.startingUp, + error: "ModuleNotFoundError: No module named 'pydantic_core'"); + }); + + await expectLater( + () => waitForAppLoaded(tester), + throwsA(isA().having((e) => e.toString(), 'message', + contains("No module named 'pydantic_core'")))); + }); + testWidgets('a registered app that never initializes times out', (tester) async { final backend = await _mountApp(tester); diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py b/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py index 8f8bd469d7..d223502d9c 100644 --- a/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py @@ -2,7 +2,7 @@ from collections.abc import Callable from dataclasses import dataclass -from typing import Generic, TypeVar +from typing import Any, Generic, TypeVar, overload from flet.components.hooks.hook import Hook from flet.components.utils import current_component @@ -35,6 +35,20 @@ class RefHook(Hook, Generic[RefValueT]): ref: MutableRef[RefValueT] +@overload +def use_ref(initial_value: None = None) -> MutableRef[Any]: ... + + +@overload +def use_ref(initial_value: Callable[[], RefValueT]) -> MutableRef[RefValueT]: ... + + +@overload +def use_ref( + initial_value: RefValueT | Callable[[], RefValueT], +) -> MutableRef[RefValueT]: ... + + def use_ref( initial_value: RefValueT | Callable[[], RefValueT] | None = None, ) -> MutableRef[RefValueT]: