diff --git a/CHANGELOG.md b/CHANGELOG.md index 839986f6c9..502278a66b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ### Bug fixes -* Fix ink ripples and hover highlights not covering the whole `Container` when both `ink=True` and `animate` are set, and its `padding` being applied twice. In that combination `padding` and `alignment` were passed to the outer `AnimatedContainer` *and* to the inner `Container` that wraps the content inside the `InkWell`, so a `padding=10` container was laid out with 20 on each side. The duplicated `alignment` was the more visible half: it made the `Material`/`InkWell` shrink-wrap to the content, so splashes and the hover overlay stopped short of the container's edges while `bgcolor` on the same container still filled it - the two disagreed on where the control ended. Both properties now live only on the inner container, which becomes an `AnimatedContainer` when `animate` is set so that padding and alignment changes still animate; this is what the non-animated ink path already did. Inked, animated containers with padding will render tighter than before - by the padding they declare, instead of double by @FeodorFitsner. +* Fix ink ripples and hover highlights not covering the whole `Container` when both `ink=True` and `animate` are set, and its `padding` being applied twice. In that combination `padding` and `alignment` were passed to the outer `AnimatedContainer` *and* to the inner `Container` that wraps the content inside the `InkWell`, so a `padding=10` container was laid out with 20 on each side. The duplicated `alignment` was the more visible half: it made the `Material`/`InkWell` shrink-wrap to the content, so splashes and the hover overlay stopped short of the container's edges while `bgcolor` on the same container still filled it - the two disagreed on where the control ended. Both properties now live only on the inner container, which becomes an `AnimatedContainer` when `animate` is set so that padding and alignment changes still animate; this is what the non-animated ink path already did. Inked, animated containers with padding will render tighter than before - by the padding they declare, instead of double ([#6757](https://github.com/flet-dev/flet/pull/6757)) by @FeodorFitsner. +* Fix `disabled=True` having almost no effect on `Radio` and `CupertinoRadio`: the radio could still be selected and kept its enabled colors; only the label grayed out. Broken since the migration to Flutter's native `RadioGroup` widget ([#5651](https://github.com/flet-dev/flet/pull/5651)), whose API needs an explicit `enabled: false` that Flet never passed. A disabled radio now ignores clicks and renders grayed out (`fill_color`'s `ControlState.DISABLED` value applies too), disabling a whole `RadioGroup` cascades to its radios, and the label grays out with the default text style as well ([#6159](https://github.com/flet-dev/flet/issues/6159), [#6769](https://github.com/flet-dev/flet/pull/6769)) by @ndonkoHenri. ## 0.86.5 @@ -12,61 +13,61 @@ ### Improvements -* An Android permission set to `false` is now actively **removed** from the merged manifest instead of merely being left out of the generated one. Gradle's manifest merger folds in the manifest of every Flutter plugin and can also synthesize permissions on its own, and `false` previously had no effect on either — the template only skipped emitting the entry, so a plugin-contributed permission passed straight through with no way to stop it. Concretely: `flet-camera` pulls in `camera_android_camerax`, which declares `WRITE_EXTERNAL_STORAGE` bounded to `maxSdkVersion="28"`, and the merger implies an **unbounded** `READ_EXTERNAL_STORAGE` from it (legacy behaviour — write once implied read). Both then appear in the Play Console despite being absent from `pyproject.toml`, and the unbounded read is exactly the shape Google Play's storage policy objects to. Permissions set to `false` now render as `` (the template's `` gained the `tools` namespace), which strips them during the merge; removing a permission nothing declares is a harmless no-op. Verified on Flet Studio: 11 permissions down to 9, both storage entries gone from the built APK by @FeodorFitsner. +* An Android permission set to `false` is now actively **removed** from the merged manifest instead of merely being left out of the generated one. Gradle's manifest merger folds in the manifest of every Flutter plugin and can also synthesize permissions on its own, and `false` previously had no effect on either — the template only skipped emitting the entry, so a plugin-contributed permission passed straight through with no way to stop it. Concretely: `flet-camera` pulls in `camera_android_camerax`, which declares `WRITE_EXTERNAL_STORAGE` bounded to `maxSdkVersion="28"`, and the merger implies an **unbounded** `READ_EXTERNAL_STORAGE` from it (legacy behaviour — write once implied read). Both then appear in the Play Console despite being absent from `pyproject.toml`, and the unbounded read is exactly the shape Google Play's storage policy objects to. Permissions set to `false` now render as `` (the template's `` gained the `tools` namespace), which strips them during the merge; removing a permission nothing declares is a harmless no-op. Verified on Flet Studio: 11 permissions down to 9, both storage entries gone from the built APK ([#6742](https://github.com/flet-dev/flet/pull/6742)) by @FeodorFitsner. -* Bumped `serious_python` to **4.5.1** and re-pinned the bundled python-build snapshot to [20260730](https://github.com/flet-dev/python-build/releases/tag/20260730) (`dart_bridge` 1.7.1). `serious_python` 4.5.1 tracks the same python-build release, keeping `PYTHON_BUILD_RELEASE_DATE` in sync with its `pythonReleaseDate` as the pin requires by @FeodorFitsner. +* Bumped `serious_python` to **4.5.1** and re-pinned the bundled python-build snapshot to [20260730](https://github.com/flet-dev/python-build/releases/tag/20260730) (`dart_bridge` 1.7.1). `serious_python` 4.5.1 tracks the same python-build release, keeping `PYTHON_BUILD_RELEASE_DATE` in sync with its `pythonReleaseDate` as the pin requires ([#6742](https://github.com/flet-dev/flet/pull/6742)) by @FeodorFitsner. -* Android ProGuard/R8 rules can now be extended from `pyproject.toml` via `[tool.flet.android].proguard_rules`. The generated project's `android/app/proguard-rules.pro` was a fixed template file, so an app that needed an extra keep rule had no way to add one short of downloading the published build template, patching the file and passing `--template`. This matters for [Pyjnius](https://flet.dev/blog/tap-into-native-android-and-ios-apis-with-Pyjnius-and-pyobjus): `autoclass()` resolves Java classes by name at runtime, and R8 renames anything in the APK that isn't kept — so `autoclass()` on a class bundled by a Flutter plugin or by your own Java/Kotlin fails in release builds. It fails hard: JNI `FindClass` returns null and the process aborts with `JNI DETECTED ERROR IN APPLICATION: obj == null` / `SIGABRT` rather than raising a catchable Python exception, and because R8 only runs in release builds it never reproduces in debug. Android framework classes (`android.os.Build` and friends) live outside the APK and never needed a rule. Rules are *appended* to the defaults, since R8 has no directive that undoes a keep; to remove the defaults instead — in particular `-keepnames class * { *; }`, which keeps every class and member name in the app and costs 2.5 MB of `classes.dex` on Flet Studio (5.9 MB → 3.4 MB, -43%) — set `[tool.flet.android].proguard_default_rules = false`. Dropping the defaults is safe for Pyjnius's `PythonActivity` access, because `serious_python_android` 4.1.0+ ships that keep rule in its own `consumer-rules.pro`. Defaults are unchanged, so existing builds render exactly the same file by @FeodorFitsner. +* Android ProGuard/R8 rules can now be extended from `pyproject.toml` via `[tool.flet.android].proguard_rules`. The generated project's `android/app/proguard-rules.pro` was a fixed template file, so an app that needed an extra keep rule had no way to add one short of downloading the published build template, patching the file and passing `--template`. This matters for [Pyjnius](https://flet.dev/blog/tap-into-native-android-and-ios-apis-with-Pyjnius-and-pyobjus): `autoclass()` resolves Java classes by name at runtime, and R8 renames anything in the APK that isn't kept — so `autoclass()` on a class bundled by a Flutter plugin or by your own Java/Kotlin fails in release builds. It fails hard: JNI `FindClass` returns null and the process aborts with `JNI DETECTED ERROR IN APPLICATION: obj == null` / `SIGABRT` rather than raising a catchable Python exception, and because R8 only runs in release builds it never reproduces in debug. Android framework classes (`android.os.Build` and friends) live outside the APK and never needed a rule. Rules are *appended* to the defaults, since R8 has no directive that undoes a keep; to remove the defaults instead — in particular `-keepnames class * { *; }`, which keeps every class and member name in the app and costs 2.5 MB of `classes.dex` on Flet Studio (5.9 MB → 3.4 MB, -43%) — set `[tool.flet.android].proguard_default_rules = false`. Dropping the defaults is safe for Pyjnius's `PythonActivity` access, because `serious_python_android` 4.1.0+ ships that keep rule in its own `consumer-rules.pro`. Defaults are unchanged, so existing builds render exactly the same file ([#6741](https://github.com/flet-dev/flet/pull/6741)) by @FeodorFitsner. -* Android Gradle properties can now be configured from `pyproject.toml` via `[tool.flet.android.gradle_properties]`. The generated project's `android/gradle.properties` was previously fixed, so its memory settings — `org.gradle.jvmargs=-Xmx8G` plus a 4 GB metaspace — could not be changed. That is larger than the total RAM of a standard GitHub-hosted runner (measured: 7.8 GB with 3 GB of swap), so release builds, which additionally run Dart AOT once per ABI and R8, could exhaust memory and stall with no error; the only workaround was to download the published build template, patch the file and pass `--template`. Entries in the table override the defaults or add new properties, e.g. `"org.gradle.jvmargs" = "-Xmx3G -XX:MaxMetaspaceSize=1G"` and `"org.gradle.workers.max" = 2`. Defaults are unchanged, so existing builds render exactly the same file by @FeodorFitsner. +* Android Gradle properties can now be configured from `pyproject.toml` via `[tool.flet.android.gradle_properties]`. The generated project's `android/gradle.properties` was previously fixed, so its memory settings — `org.gradle.jvmargs=-Xmx8G` plus a 4 GB metaspace — could not be changed. That is larger than the total RAM of a standard GitHub-hosted runner (measured: 7.8 GB with 3 GB of swap), so release builds, which additionally run Dart AOT once per ABI and R8, could exhaust memory and stall with no error; the only workaround was to download the published build template, patch the file and pass `--template`. Entries in the table override the defaults or add new properties, e.g. `"org.gradle.jvmargs" = "-Xmx3G -XX:MaxMetaspaceSize=1G"` and `"org.gradle.workers.max" = 2`. Defaults are unchanged, so existing builds render exactly the same file ([#6732](https://github.com/flet-dev/flet/issues/6732), [#6733](https://github.com/flet-dev/flet/pull/6733)) by @FeodorFitsner. ## 0.86.4 ### Bug fixes -* Fix services registered after an embedded `FletApp` is opened never becoming usable on the host page — calling one failed with `Timeout waiting for invoke method listener for (id).`. `ServiceRegistry` subclasses `Service`, so it registered *itself* on construction; when an embedded app's page built its own registry while the host page was still the current context, the embedded registry was registered as a service **inside the host's registry**. The client has no binding for a control of type `ServiceRegistry`, so building it threw `Unknown service` inside the host's service loop and aborted it, leaving every service positioned after that entry unbound — permanently, since the entry stays in the list. A registry is the container for services, not a service, so it no longer self-registers; the client-side loop also isolates per-service failures now, so a single unbuildable entry can't stop the rest from binding. Reproduced with a host app embedding a `FletApp` and registering a `Clipboard` afterwards by @FeodorFitsner. +* Fix services registered after an embedded `FletApp` is opened never becoming usable on the host page — calling one failed with `Timeout waiting for invoke method listener for (id).`. `ServiceRegistry` subclasses `Service`, so it registered *itself* on construction; when an embedded app's page built its own registry while the host page was still the current context, the embedded registry was registered as a service **inside the host's registry**. The client has no binding for a control of type `ServiceRegistry`, so building it threw `Unknown service` inside the host's service loop and aborted it, leaving every service positioned after that entry unbound — permanently, since the entry stays in the list. A registry is the container for services, not a service, so it no longer self-registers; the client-side loop also isolates per-service failures now, so a single unbuildable entry can't stop the rest from binding. Reproduced with a host app embedding a `FletApp` and registering a `Clipboard` afterwards ([#6728](https://github.com/flet-dev/flet/pull/6728)) by @FeodorFitsner. ## 0.86.3 ### Improvements -* An embedded `FletApp` can now run over the in-process `dart_bridge` transport instead of a socket. Set `url="dartbridge://"` and the client allocates a native channel, delivers its port through the new `FletApp.on_connect` event, and the host serves that port with a `FletDartBridgeServer` — so a Flet program hosted inside another Flet app (a gallery, a preview) exchanges messages at memcpy speed with no socket file, no TCP port, and no `AF_UNIX` path-length limit (which broke embedded apps on the iOS simulator, where the container path overflows `sun_path`). High-throughput `DataChannel`s used by embedded apps (`RawImage`, `MatplotlibChart`) get their own dedicated bridge too. The transport is opt-in and falls back to the existing URL-scheme channels: on web and desktop dev builds, where `dart_bridge` is unavailable, hosts keep using a socket URL by @FeodorFitsner. +* An embedded `FletApp` can now run over the in-process `dart_bridge` transport instead of a socket. Set `url="dartbridge://"` and the client allocates a native channel, delivers its port through the new `FletApp.on_connect` event, and the host serves that port with a `FletDartBridgeServer` — so a Flet program hosted inside another Flet app (a gallery, a preview) exchanges messages at memcpy speed with no socket file, no TCP port, and no `AF_UNIX` path-length limit (which broke embedded apps on the iOS simulator, where the container path overflows `sun_path`). High-throughput `DataChannel`s used by embedded apps (`RawImage`, `MatplotlibChart`) get their own dedicated bridge too. The transport is opt-in and falls back to the existing URL-scheme channels: on web and desktop dev builds, where `dart_bridge` is unavailable, hosts keep using a socket URL ([#6723](https://github.com/flet-dev/flet/pull/6723)) by @FeodorFitsner. -* `flet run` can now pass custom arguments to your app script: everything after a `--` separator is forwarded to the script instead of being parsed by Flet, and arrives there as `sys.argv[1:]` - e.g. `flet run --web main.py -- --dataset big.csv --verbose`. Previously there was no way to do this: the app was always launched as `python -u