From d8207d0426aa5c668bbe2feeae88d63311ec932e Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 24 Dec 2025 14:52:42 -0800 Subject: [PATCH 1/2] Update CI workflow for tagged releases and pub.dev publish Restrict tag triggers to semantic version tags, add permissions for OIDC authentication, patch pubspec version only on tag, and update pub.dev publish steps to use GitHub Actions environment. Removes legacy token-based authentication and improves release automation. --- .github/workflows/ci.yml | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd56efc20..65ee32fc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: - '**' tags: - - '*' + - 'v[0-9]+.[0-9]+.[0-9]+' paths: - '.github/workflows/ci.yml' - '.github/scripts/**' @@ -82,6 +82,9 @@ jobs: build_flet_package: name: Build Flet Flutter package runs-on: ubuntu-latest + permissions: + contents: read + id-token: write # Required for authentication using OIDC (pub.dev trusted publisher) outputs: PKG_VER: ${{ steps.versions.outputs.PKG_VER }} BUILD_VER: ${{ steps.versions.outputs.BUILD_VER }} @@ -111,25 +114,31 @@ jobs: working-directory: packages/flet run: flutter test + - name: Patch pubspec version for release + if: ${{ github.ref_type == 'tag' }} + shell: bash + working-directory: packages/flet + run: | + source "$SCRIPTS/common.sh" + patch_pubspec_version ./pubspec.yaml "$PKG_VER" + + - name: Install dependencies + shell: bash + working-directory: packages/flet + run: dart pub get + - name: Publish to pub.dev (Dry Run) shell: bash working-directory: packages/flet - run: dart pub publish --dry-run || exit 0 + run: dart pub publish --dry-run - name: Publish to pub.dev (Release) if: ${{ github.ref_type == 'tag' }} env: - PUB_DEV_TOKEN: ${{ secrets.PUB_DEV_TOKEN }} + PUB_ENVIRONMENT: github-actions shell: bash working-directory: packages/flet run: | - source "$SCRIPTS/common.sh" - mkdir -p "$HOME/.config/dart" - printf %s "$PUB_DEV_TOKEN" | base64 --decode > "$HOME/.config/dart/pub-credentials.json" - - # patch pubspec for release - patch_pubspec_version ./pubspec.yaml "$PKG_VER" - dart pub publish --force # ============================= From 7e6f7d38126c40cba54a8670600d039de4c58e71 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 24 Dec 2025 15:11:30 -0800 Subject: [PATCH 2/2] Release Flet 1.0 Beta and update color handling Bump package version to 0.80.0 for Flet 1.0 Beta release. Improve color handling by replacing withOpacity with withValues and updating color conversion logic to use 8-bit components. Refactor deprecated properties and clean up unused variables and imports. Update dependencies in pubspec.yaml to use caret versions. --- client/pubspec.lock | 2 +- packages/flet/CHANGELOG.md | 4 +++ packages/flet/lib/src/controls/button.dart | 2 +- .../lib/src/controls/cupertino_app_bar.dart | 3 +- .../lib/src/controls/navigation_drawer.dart | 1 - .../flet/lib/src/controls/progress_bar.dart | 1 + .../flet/lib/src/controls/progress_ring.dart | 1 + .../flet/lib/src/controls/search_bar.dart | 4 --- .../lib/src/controls/segmented_button.dart | 2 +- packages/flet/lib/src/controls/slider.dart | 1 + packages/flet/lib/src/controls/view.dart | 2 -- .../lib/src/services/semantics_service.dart | 8 +++-- .../transport/flet_backend_channel_mock.dart | 18 +++++----- packages/flet/lib/src/utils/colors.dart | 33 +++++++++++++------ packages/flet/pubspec.yaml | 16 ++++----- 15 files changed, 59 insertions(+), 39 deletions(-) diff --git a/client/pubspec.lock b/client/pubspec.lock index 4d35f1842..1ce7307e0 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -295,7 +295,7 @@ packages: path: "../packages/flet" relative: true source: path - version: "0.70.0" + version: "0.80.0" flet_ads: dependency: "direct main" description: diff --git a/packages/flet/CHANGELOG.md b/packages/flet/CHANGELOG.md index 1443f59c6..a90a0437c 100644 --- a/packages/flet/CHANGELOG.md +++ b/packages/flet/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.80.0 + +* **Flet 1.0 Beta Release** – [Read the announcement](https://flet.dev/blog/flet-1-0-beta) + # 0.70.0 * **Flet 1.0 Alpha Released** – [Read the announcement](https://flet.dev/blog/introducing-flet-1-0-alpha) diff --git a/packages/flet/lib/src/controls/button.dart b/packages/flet/lib/src/controls/button.dart index d741c4d35..c154ec97e 100644 --- a/packages/flet/lib/src/controls/button.dart +++ b/packages/flet/lib/src/controls/button.dart @@ -104,7 +104,7 @@ class _ButtonControlState extends State with FletStoreMixin { widget.control.getColor("color", context, theme.colorScheme.primary)!, defaultBackgroundColor: widget.control .getColor("bgcolor", context, theme.colorScheme.surface)!, - defaultOverlayColor: theme.colorScheme.primary.withOpacity(0.08), + defaultOverlayColor: theme.colorScheme.primary.withValues(alpha: 0.08), defaultShadowColor: theme.colorScheme.shadow, defaultSurfaceTintColor: theme.colorScheme.surfaceTint, defaultElevation: widget.control.getDouble("elevation", 1)!, diff --git a/packages/flet/lib/src/controls/cupertino_app_bar.dart b/packages/flet/lib/src/controls/cupertino_app_bar.dart index 6fac0f5d3..cb24be447 100644 --- a/packages/flet/lib/src/controls/cupertino_app_bar.dart +++ b/packages/flet/lib/src/controls/cupertino_app_bar.dart @@ -91,6 +91,7 @@ class CupertinoAppBarControl extends StatelessWidget final Color backgroundColor = CupertinoDynamicColor.maybeResolve( control.getColor("bgcolor", context), context) ?? CupertinoTheme.of(context).barBackgroundColor; - return backgroundColor.alpha == 0xFF; + final alpha8 = (backgroundColor.a * 255.0).round().clamp(0, 255); + return alpha8 == 0xFF; } } diff --git a/packages/flet/lib/src/controls/navigation_drawer.dart b/packages/flet/lib/src/controls/navigation_drawer.dart index 24a7159a5..a3d91e8cf 100644 --- a/packages/flet/lib/src/controls/navigation_drawer.dart +++ b/packages/flet/lib/src/controls/navigation_drawer.dart @@ -36,7 +36,6 @@ class _NavigationDrawerControlState extends State { debugPrint("NavigationDrawerControl build: ${widget.control.id}"); var selectedIndex = widget.control.getInt("selected_index", 0)!; - var endDrawer = widget.control.get("position") == "end"; if (_selectedIndex != selectedIndex) { _selectedIndex = selectedIndex; diff --git a/packages/flet/lib/src/controls/progress_bar.dart b/packages/flet/lib/src/controls/progress_bar.dart index 7278d97c7..348c3e278 100644 --- a/packages/flet/lib/src/controls/progress_bar.dart +++ b/packages/flet/lib/src/controls/progress_bar.dart @@ -28,6 +28,7 @@ class ProgressBarControl extends StatelessWidget { stopIndicatorColor: control.getColor("stop_indicator_color", context), stopIndicatorRadius: control.getDouble("stop_indicator_radius"), trackGap: control.getDouble("track_gap"), + // ignore: deprecated_member_use year2023: control.getBool( "year_2023"), // todo: deprecated and to be removed in future versions ); diff --git a/packages/flet/lib/src/controls/progress_ring.dart b/packages/flet/lib/src/controls/progress_ring.dart index 2b8242455..45efca077 100644 --- a/packages/flet/lib/src/controls/progress_ring.dart +++ b/packages/flet/lib/src/controls/progress_ring.dart @@ -31,6 +31,7 @@ class ProgressRingControl extends StatelessWidget { trackGap: control.getDouble("track_gap"), constraints: control.getBoxConstraints("size_constraints"), padding: control.getPadding("padding"), + // ignore: deprecated_member_use year2023: control.getBool( "year2023"), // todo: deprecated and to be removed in future versions ); diff --git a/packages/flet/lib/src/controls/search_bar.dart b/packages/flet/lib/src/controls/search_bar.dart index ef7941e65..91f682f06 100644 --- a/packages/flet/lib/src/controls/search_bar.dart +++ b/packages/flet/lib/src/controls/search_bar.dart @@ -26,7 +26,6 @@ class SearchBarControl extends StatefulWidget { class _SearchBarControlState extends State { late final SearchController _controller; - bool _focused = false; TextCapitalization? _textCapitalization; late final FocusNode _focusNode; String? _lastFocusValue; @@ -43,9 +42,6 @@ class _SearchBarControlState extends State { } void _onFocusChange() { - setState(() { - _focused = _focusNode.hasFocus; - }); widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } diff --git a/packages/flet/lib/src/controls/segmented_button.dart b/packages/flet/lib/src/controls/segmented_button.dart index b995698e0..b4bf29d57 100644 --- a/packages/flet/lib/src/controls/segmented_button.dart +++ b/packages/flet/lib/src/controls/segmented_button.dart @@ -37,7 +37,7 @@ class _SegmentedButtonControlState extends State var style = widget.control.getButtonStyle("style", Theme.of(context), defaultForegroundColor: theme.colorScheme.primary, defaultBackgroundColor: theme.colorScheme.surface, - defaultOverlayColor: theme.colorScheme.primary.withOpacity(0.08), + defaultOverlayColor: theme.colorScheme.primary.withValues(alpha: 0.08), defaultShadowColor: theme.colorScheme.shadow, defaultSurfaceTintColor: theme.colorScheme.surfaceTint, defaultElevation: 1, diff --git a/packages/flet/lib/src/controls/slider.dart b/packages/flet/lib/src/controls/slider.dart index 4d0eb5c50..81e1c28fe 100644 --- a/packages/flet/lib/src/controls/slider.dart +++ b/packages/flet/lib/src/controls/slider.dart @@ -75,6 +75,7 @@ class _SliderControlState extends State { min: min, max: max, // todo: remove deprecated property year2023 + // ignore: deprecated_member_use year2023: widget.control.getBool("year_2023"), divisions: widget.control.getInt("divisions"), label: label?.replaceAll("{value}", _value.toStringAsFixed(round)), diff --git a/packages/flet/lib/src/controls/view.dart b/packages/flet/lib/src/controls/view.dart index 61831be88..cff69c6bf 100644 --- a/packages/flet/lib/src/controls/view.dart +++ b/packages/flet/lib/src/controls/view.dart @@ -16,7 +16,6 @@ import '../utils/buttons.dart'; import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/numbers.dart'; -import '../utils/platform.dart'; import '../utils/theme.dart'; import '../widgets/loading_page.dart'; import '../widgets/page_context.dart'; @@ -172,7 +171,6 @@ class _ViewControlState extends State { .addAll(dialogControls.map((c) => ControlWidget(control: c))); overlayWidgets.add(PageMedia(view: widget.control.parent)); } - } Widget body = Stack(children: [ diff --git a/packages/flet/lib/src/services/semantics_service.dart b/packages/flet/lib/src/services/semantics_service.dart index 0345d2d34..cc1a92183 100644 --- a/packages/flet/lib/src/services/semantics_service.dart +++ b/packages/flet/lib/src/services/semantics_service.dart @@ -26,8 +26,12 @@ class SemanticsServiceControl extends FletService { switch (name) { case "announce_message": var message = args["message"].toString(); - return SemanticsService.announce( - message, args["rtl"] ? TextDirection.rtl : TextDirection.ltr, + final view = WidgetsBinding.instance.platformDispatcher.implicitView; + if (view == null) { + return; + } + return SemanticsService.sendAnnouncement( + view, message, args["rtl"] ? TextDirection.rtl : TextDirection.ltr, assertiveness: control.getAssertiveness( args["assertiveness"], Assertiveness.polite)!); case "announce_tooltip": diff --git a/packages/flet/lib/src/transport/flet_backend_channel_mock.dart b/packages/flet/lib/src/transport/flet_backend_channel_mock.dart index 1555dd88b..f583f2381 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel_mock.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel_mock.dart @@ -24,13 +24,13 @@ class FletMockBackendChannel implements FletBackendChannel { await Future.delayed( const Duration(seconds: 1)); // Simulating async operation debugPrint("Connected to the Mock Flet backend channel"); - //_scenario_line_chart_simple(); - _scenario_register(); - //_scenario_test_services(); - //_scenario_call_window_methods(); + // _scenarioLineChartSimple(); + _scenarioRegister(); + // _scenarioTestServices(); + // scenarioCallWindowMethods(); } - _scenario_register() async { + Future _scenarioRegister() async { onMessage(Message(action: MessageAction.registerClient, payload: { "id": 1, "patch": { @@ -81,7 +81,8 @@ class FletMockBackendChannel implements FletBackendChannel { })); } - _scenario_line_chart_simple() async { + // ignore: unused_element + Future _scenarioLineChartSimple() async { onMessage(Message(action: MessageAction.registerClient, payload: { "id": 1, "patch": { @@ -169,7 +170,8 @@ class FletMockBackendChannel implements FletBackendChannel { })); } - _scenario_test_services() async { + // ignore: unused_element + Future _scenarioTestServices() async { onMessage(Message(action: MessageAction.patchControl, payload: { "id": 11, "patch": { @@ -212,7 +214,7 @@ class FletMockBackendChannel implements FletBackendChannel { // payload: {"id": 9, "name": "close", "args": {}})); } - scenario_call_window_methods() async { + Future scenarioCallWindowMethods() async { onMessage(Message( action: MessageAction.invokeControlMethod, payload: {"id": 9, "name": "to_front", "args": {}})); diff --git a/packages/flet/lib/src/utils/colors.dart b/packages/flet/lib/src/utils/colors.dart index 377845857..552f817e1 100644 --- a/packages/flet/lib/src/utils/colors.dart +++ b/packages/flet/lib/src/utils/colors.dart @@ -200,7 +200,7 @@ extension HexColor on Color { } if (color != null && colorOpacity != null) { - color = color.withOpacity(parseDouble(colorOpacity, 1.0)!); + color = color.withValues(alpha: parseDouble(colorOpacity, 1.0)!); } return color ?? defaultColor; @@ -262,11 +262,21 @@ extension HexColor on Color { } /// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`). - String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}' - '${alpha.toRadixString(16).padLeft(2, '0')}' - '${red.toRadixString(16).padLeft(2, '0')}' - '${green.toRadixString(16).padLeft(2, '0')}' - '${blue.toRadixString(16).padLeft(2, '0')}'; + String toHex({bool leadingHashSign = true}) { + int to8bit(double component) => + (component * 255.0).round().clamp(0, 255); + + final alpha8 = to8bit(a); + final red8 = to8bit(r); + final green8 = to8bit(g); + final blue8 = to8bit(b); + + return '${leadingHashSign ? '#' : ''}' + '${alpha8.toRadixString(16).padLeft(2, '0')}' + '${red8.toRadixString(16).padLeft(2, '0')}' + '${green8.toRadixString(16).padLeft(2, '0')}' + '${blue8.toRadixString(16).padLeft(2, '0')}'; + } } extension ColorExtension on Color { @@ -274,11 +284,14 @@ extension ColorExtension on Color { Color darken([int percent = 40]) { assert(1 <= percent && percent <= 100); final value = 1 - percent / 100; + int to8bit(double component) => + (component * 255.0).round().clamp(0, 255); + return Color.fromARGB( - alpha, - (red * value).round(), - (green * value).round(), - (blue * value).round(), + to8bit(a), + (to8bit(r) * value).round().clamp(0, 255), + (to8bit(g) * value).round().clamp(0, 255), + (to8bit(b) * value).round().clamp(0, 255), ); } } diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index e0f280973..3374cfbdf 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -2,7 +2,7 @@ name: flet description: Write entire Flutter app in Python or add server-driven UI experience into existing Flutter app. homepage: https://flet.dev repository: https://github.com/flet-dev/flet/packages/flet -version: 0.70.0 +version: 0.80.0 # Supported platforms platforms: @@ -27,12 +27,12 @@ dependencies: device_info_plus: ^12.3.0 equatable: ^2.0.3 file_picker: ^10.3.3 - flutter_highlight: 0.7.0 - flutter_markdown: 0.7.6+2 - flutter_svg: 2.2.1 + flutter_highlight: ^0.7.0 + flutter_markdown: ^0.7.6+2 + flutter_svg: ^2.2.1 highlight: ^0.7.0 - http: 1.5.0 - markdown: 7.3.0 + http: ^1.5.0 + markdown: ^7.3.0 msgpack_dart: ^1.0.1 path: ^1.9.0 path_provider: ^2.1.5 @@ -40,10 +40,10 @@ dependencies: screenshot: ^3.0.0 screen_brightness: ^2.1.7 sensors_plus: ^7.0.0 - shared_preferences: 2.5.3 + shared_preferences: ^2.5.3 share_plus: ^12.0.1 shimmer: ^3.0.0 - url_launcher: 6.3.2 + url_launcher: ^6.3.2 vector_math: ^2.2.0 web: ^1.1.1 web_socket_channel: ^3.0.2