diff --git a/.appveyor.yml b/.appveyor.yml index c4f271b46..1a3dbecad 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,7 +10,7 @@ skip_commits: environment: python_stack: python 3.12 - FLUTTER_VERSION: 3.27.4 + FLUTTER_VERSION: 3.29.0 GITHUB_TOKEN: secure: 9SKIwc3VSfYJ5IChvNR74hQprJ0DRmcV9pPX+8KyE6IXIdfMsX6ikeUmMhJGRu3ztkZaF45jmU7Xn/6tauXQXhDBxK1N8kFHFSAnq6LjUXyhS0TZKX/H+jDozBeVbCXp TWINE_USERNAME: __token__ diff --git a/client/.fvmrc b/client/.fvmrc index c2783c697..4cfa3d5f2 100644 --- a/client/.fvmrc +++ b/client/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.27.4" + "flutter": "3.29.0" } \ No newline at end of file diff --git a/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 300cdaf5c..16d4c22e3 100644 --- a/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -48,6 +48,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/client/pubspec.lock b/client/pubspec.lock index a94dfdd55..648534153 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" audioplayers: dependency: transitive description: @@ -85,18 +85,18 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -117,18 +117,18 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" cross_file: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" ffi: dependency: transitive description: @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_picker: dependency: transitive description: @@ -263,7 +263,7 @@ packages: path: "../packages/flet" relative: true source: path - version: "0.27.5" + version: "0.27.6" flet_ads: dependency: "direct main" description: @@ -610,18 +610,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -682,10 +682,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -770,10 +770,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mgrs_dart: dependency: transitive description: @@ -802,10 +802,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_parsing: dependency: transitive description: @@ -922,10 +922,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -946,10 +946,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" proj4dart: dependency: transitive description: @@ -1215,10 +1215,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" sprintf: dependency: transitive description: @@ -1231,26 +1231,26 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" sync_http: dependency: transitive description: @@ -1271,18 +1271,18 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.4" torch_light: dependency: transitive description: @@ -1439,10 +1439,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.3.1" volume_controller: dependency: transitive description: @@ -1596,5 +1596,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.5.0 <4.0.0" + dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.24.0" diff --git a/packages/flet/lib/src/controls/app_bar.dart b/packages/flet/lib/src/controls/app_bar.dart index dffea2746..1dac5d65e 100644 --- a/packages/flet/lib/src/controls/app_bar.dart +++ b/packages/flet/lib/src/controls/app_bar.dart @@ -33,7 +33,9 @@ class AppBarControl extends StatelessWidget debugPrint("AppBar build: ${control.id}"); return withPagePlatform((context, platform) { - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; + bool? adaptive = control.isAdaptive ?? parentAdaptive; + bool disabled = control.isDisabled || parentDisabled; + if (adaptive == true && (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS)) { @@ -53,14 +55,14 @@ class AppBarControl extends StatelessWidget var appBar = AppBar( leading: leadingCtrls.isNotEmpty - ? createControl(control, leadingCtrls.first.id, control.isDisabled, + ? createControl(control, leadingCtrls.first.id, disabled, parentAdaptive: adaptive) : null, leadingWidth: control.attrDouble("leadingWidth"), automaticallyImplyLeading: control.attrBool("automaticallyImplyLeading", true)!, title: titleCtrls.isNotEmpty - ? createControl(control, titleCtrls.first.id, control.isDisabled, + ? createControl(control, titleCtrls.first.id, disabled, parentAdaptive: adaptive) : null, centerTitle: control.attrBool("centerTitle", false)!, @@ -69,7 +71,7 @@ class AppBarControl extends StatelessWidget backgroundColor: control.attrColor("bgcolor", context), elevation: control.attrDouble("elevation"), actions: actionCtrls - .map((c) => createControl(control, c.id, control.isDisabled, + .map((c) => createControl(control, c.id, disabled, parentAdaptive: adaptive)) .toList(), systemOverlayStyle: Theme.of(context) diff --git a/packages/flet/lib/src/controls/create_control.dart b/packages/flet/lib/src/controls/create_control.dart index 2c8bb8843..e8b4d13ed 100644 --- a/packages/flet/lib/src/controls/create_control.dart +++ b/packages/flet/lib/src/controls/create_control.dart @@ -66,6 +66,7 @@ import 'expansion_panel.dart'; import 'expansion_tile.dart'; import 'file_picker.dart'; import 'flet_app_control.dart'; +import 'flexible_space_bar.dart'; import 'floating_action_button.dart'; import 'gesture_detector.dart'; import 'grid_view.dart'; @@ -106,6 +107,11 @@ import 'semantics_service.dart'; import 'shader_mask.dart'; import 'shake_detector.dart'; import 'slider.dart'; +import 'sliver_app_bar.dart'; +import 'sliver_grid_view.dart'; +import 'sliver_list_view.dart'; +import 'sliver_safe_area.dart'; +import 'sliver_scroll_view.dart'; import 'snack_bar.dart'; import 'stack.dart'; import 'submenu_button.dart'; @@ -214,6 +220,18 @@ Widget createControl(Control? parent, String id, bool parentDisabled, ); } +List? createControls( + Control? parent, Iterable controls, bool parentDisabled, + {bool? parentAdaptive, Widget? nextChild}) { + if (controls.isEmpty) { + return null; + } + return controls + .map((control) => createControl(parent, control.id, parentDisabled, + parentAdaptive: parentAdaptive, nextChild: nextChild)) + .toList(); +} + Widget createWidget( Key? key, ControlViewModel controlView, @@ -979,6 +997,58 @@ Widget createWidget( parentAdaptive: parentAdaptive, children: controlView.children, ); + case "sliverappbar": + return SliverAppBarControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + parentAdaptive: parentAdaptive, + children: controlView.children, + backend: backend, + ); + case "sliverscrollview": + return SliverScrollViewControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + parentAdaptive: parentAdaptive, + children: controlView.children, + backend: backend, + ); + case "slivergridview": + return SliverGridViewControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + parentAdaptive: parentAdaptive, + children: controlView.children, + backend: backend, + ); + case "sliverlistview": + return SliverListViewControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + parentAdaptive: parentAdaptive, + children: controlView.children, + backend: backend, + ); + case "sliversafearea": + return SliverSafeAreaControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + parentAdaptive: parentAdaptive, + children: controlView.children, + ); + case "flexiblespacebar": + return FlexibleSpaceBarControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + parentAdaptive: parentAdaptive, + children: controlView.children, + ); case "windowdragarea": return WindowDragAreaControl( parent: parent, diff --git a/packages/flet/lib/src/controls/flexible_space_bar.dart b/packages/flet/lib/src/controls/flexible_space_bar.dart new file mode 100644 index 000000000..5ceb7bde3 --- /dev/null +++ b/packages/flet/lib/src/controls/flexible_space_bar.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../utils/edge_insets.dart'; +import '../utils/others.dart'; +import 'create_control.dart'; +import 'flet_store_mixin.dart'; + +class FlexibleSpaceBarControl extends StatelessWidget with FletStoreMixin { + final Control? parent; + final Control control; + final bool parentDisabled; + final bool? parentAdaptive; + final List children; + + const FlexibleSpaceBarControl({ + super.key, + this.parent, + required this.control, + required this.children, + required this.parentDisabled, + required this.parentAdaptive, + }); + + @override + Widget build(BuildContext context) { + debugPrint("FlexibleSpaceBar build: ${control.id}"); + + bool? adaptive = control.isAdaptive ?? parentAdaptive; + bool disabled = control.isDisabled || parentDisabled; + + var backgroundCtrl = children + .where((c) => c.name == "background" && c.isVisible) + .firstOrNull; + var titleCtrl = + children.where((c) => c.name == "title" && c.isVisible).firstOrNull; + + var bar = FlexibleSpaceBar( + title: titleCtrl != null + ? createControl(control, titleCtrl.id, disabled, + parentAdaptive: adaptive) + : null, + background: backgroundCtrl != null + ? createControl(control, backgroundCtrl.id, disabled, + parentAdaptive: adaptive) + : null, + centerTitle: control.attrBool("centerTitle", false)!, + expandedTitleScale: control.attrDouble("expandedTitleScale", 1.5)!, + titlePadding: parseEdgeInsets(control, "titlePadding"), + collapseMode: parseCollapseMode( + control.attrString("collapseMode"), CollapseMode.parallax)!, + //stretchModes: , + ); + return constrainedControl(context, bar, parent, control); + } +} diff --git a/packages/flet/lib/src/controls/reorderable_list_view.dart b/packages/flet/lib/src/controls/reorderable_list_view.dart index 9bed6ebd0..cde3c3847 100644 --- a/packages/flet/lib/src/controls/reorderable_list_view.dart +++ b/packages/flet/lib/src/controls/reorderable_list_view.dart @@ -28,10 +28,10 @@ class ReorderableListViewControl extends StatefulWidget { required this.backend}); @override - State createState() => _ListViewControlState(); + State createState() => _ReorderableListViewControlState(); } -class _ListViewControlState extends State { +class _ReorderableListViewControlState extends State { late final ScrollController _controller; @override @@ -48,7 +48,7 @@ class _ListViewControlState extends State { @override Widget build(BuildContext context) { - debugPrint("ListViewControl build: ${widget.control.id}"); + debugPrint("ReorderableListViewControl build: ${widget.control.id}"); bool disabled = widget.control.isDisabled || widget.parentDisabled; bool? adaptive = diff --git a/packages/flet/lib/src/controls/sliver_app_bar.dart b/packages/flet/lib/src/controls/sliver_app_bar.dart new file mode 100644 index 000000000..1e1dc4c43 --- /dev/null +++ b/packages/flet/lib/src/controls/sliver_app_bar.dart @@ -0,0 +1,219 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; + +import '../flet_control_backend.dart'; +import '../models/control.dart'; +import '../utils/borders.dart'; +import '../utils/edge_insets.dart'; +import '../utils/others.dart'; +import '../utils/text.dart'; +import '../utils/theme.dart'; +import 'create_control.dart'; +import 'flet_store_mixin.dart'; + +enum SliverAppBarMode { + medium, + large, +} + +class SliverAppBarControl extends StatelessWidget with FletStoreMixin { + final Control? parent; + final Control control; + final bool parentDisabled; + final bool? parentAdaptive; + final List children; + final FletControlBackend backend; + + const SliverAppBarControl({ + super.key, + this.parent, + required this.control, + required this.children, + required this.parentDisabled, + required this.parentAdaptive, + required this.backend, + }); + + @override + Widget build(BuildContext context) { + debugPrint("SliverAppBar build: ${control.id}"); + + bool? adaptive = control.isAdaptive ?? parentAdaptive; + bool disabled = control.isDisabled || parentDisabled; + const double kToolbarHeight = 56.0; + + var leadingCtrl = + children.where((c) => c.name == "leading" && c.isVisible).firstOrNull; + var leading = leadingCtrl != null + ? createControl(control, leadingCtrl.id, disabled, + parentAdaptive: adaptive) + : null; + var titleCtrl = + children.where((c) => c.name == "title" && c.isVisible).firstOrNull; + var title = titleCtrl != null + ? createControl(control, titleCtrl.id, disabled, + parentAdaptive: adaptive) + : null; + var flexibleSpaceCtrl = children + .where((c) => c.name == "flexibleSpace" && c.isVisible) + .firstOrNull; + var flexibleSpace = flexibleSpaceCtrl != null + ? createControl(control, flexibleSpaceCtrl.id, disabled, + parentAdaptive: adaptive) + : null; + var actionCtrls = children.where((c) => c.name == "action" && c.isVisible); + var actions = createControls(control, actionCtrls, disabled, + parentAdaptive: adaptive); + var leadingWidth = control.attrDouble("leadingWidth"); + var automaticallyImplyLeading = + control.attrBool("automaticallyImplyLeading", true)!; + var centerTitle = control.attrBool("centerTitle", false)!; + var toolbarHeight = control.attrDouble("toolbarHeight", kToolbarHeight)!; + var foregroundColor = control.attrColor("color", context); + var backgroundColor = control.attrColor("bgcolor", context); + var elevation = control.attrDouble("elevation"); + var systemOverlayStyle = Theme.of(context) + .extension() + ?.systemUiOverlayStyle; + var shadowColor = control.attrColor("shadowColor", context); + var surfaceTintColor = control.attrColor("surfaceTintColor", context); + var scrolledUnderElevation = control.attrDouble("elevationOnScroll"); + var forceMaterialTransparency = + control.attrBool("forceMaterialTransparency", false)!; + var primary = control.attrBool("primary", true)!; + var titleSpacing = control.attrDouble("titleSpacing"); + var excludeHeaderSemantics = + control.attrBool("excludeHeaderSemantics", false)!; + var clipBehavior = parseClip(control.attrString("clipBehavior")); + var titleTextStyle = + parseTextStyle(Theme.of(context), control, "titleTextStyle"); + var shape = parseOutlinedBorder(control, "shape"); + var toolbarTextStyle = + parseTextStyle(Theme.of(context), control, "toolbarTextStyle"); + var actionsPadding = parseEdgeInsets(control, "actionsPadding"); + var collapsedHeight = control.attrDouble("collapsedHeight"); + var pinned = control.attrBool("pinned", false)!; + var snap = control.attrBool("snap", false)!; + var floating = control.attrBool("floating", false)!; + var stretch = control.attrBool("stretch", false)!; + var expandedHeight = control.attrDouble("expandedHeight"); + var forceElevated = control.attrBool("forceElevated", false)!; + var stretchTriggerOffset = + control.attrDouble("stretchTriggerOffset", 100.0)!; + Future onStretchTrigger() async { + backend.triggerControlEvent(control.id, "stretch"); + } + + var type = SliverAppBarMode.values.firstWhereOrNull((e) => + e.name.toLowerCase() == control.attrString("type")?.toLowerCase()); + + var appBar = type == SliverAppBarMode.large + ? SliverAppBar.large( + leading: leading, + leadingWidth: leadingWidth, + automaticallyImplyLeading: automaticallyImplyLeading, + title: title, + centerTitle: centerTitle, + toolbarHeight: toolbarHeight, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + elevation: elevation, + actions: actions, + systemOverlayStyle: systemOverlayStyle, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, + scrolledUnderElevation: scrolledUnderElevation, + forceMaterialTransparency: forceMaterialTransparency, + primary: primary, + titleSpacing: titleSpacing, + excludeHeaderSemantics: excludeHeaderSemantics, + clipBehavior: clipBehavior, + titleTextStyle: titleTextStyle, + shape: shape, + toolbarTextStyle: toolbarTextStyle, + actionsPadding: actionsPadding, + collapsedHeight: collapsedHeight, + pinned: pinned, + snap: snap, + floating: floating, + stretch: stretch, + expandedHeight: expandedHeight, + forceElevated: forceElevated, + stretchTriggerOffset: stretchTriggerOffset, + flexibleSpace: flexibleSpace, + onStretchTrigger: onStretchTrigger, + ) + : type == SliverAppBarMode.medium + ? SliverAppBar.medium( + leading: leading, + leadingWidth: leadingWidth, + automaticallyImplyLeading: automaticallyImplyLeading, + title: title, + centerTitle: centerTitle, + toolbarHeight: toolbarHeight, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + elevation: elevation, + actions: actions, + systemOverlayStyle: systemOverlayStyle, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, + scrolledUnderElevation: scrolledUnderElevation, + forceMaterialTransparency: forceMaterialTransparency, + primary: primary, + titleSpacing: titleSpacing, + excludeHeaderSemantics: excludeHeaderSemantics, + clipBehavior: clipBehavior, + titleTextStyle: titleTextStyle, + shape: shape, + toolbarTextStyle: toolbarTextStyle, + actionsPadding: actionsPadding, + collapsedHeight: collapsedHeight, + pinned: pinned, + snap: snap, + floating: floating, + stretch: stretch, + expandedHeight: expandedHeight, + forceElevated: forceElevated, + stretchTriggerOffset: stretchTriggerOffset, + flexibleSpace: flexibleSpace, + onStretchTrigger: onStretchTrigger, + ) + : SliverAppBar( + leading: leading, + leadingWidth: leadingWidth, + automaticallyImplyLeading: automaticallyImplyLeading, + title: title, + centerTitle: centerTitle, + toolbarHeight: toolbarHeight, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + elevation: elevation, + actions: actions, + systemOverlayStyle: systemOverlayStyle, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, + scrolledUnderElevation: scrolledUnderElevation, + forceMaterialTransparency: forceMaterialTransparency, + primary: primary, + titleSpacing: titleSpacing, + excludeHeaderSemantics: excludeHeaderSemantics, + clipBehavior: clipBehavior, + titleTextStyle: titleTextStyle, + shape: shape, + toolbarTextStyle: toolbarTextStyle, + actionsPadding: actionsPadding, + collapsedHeight: collapsedHeight, + pinned: pinned, + snap: snap, + floating: floating, + stretch: stretch, + expandedHeight: expandedHeight, + forceElevated: forceElevated, + stretchTriggerOffset: stretchTriggerOffset, + flexibleSpace: flexibleSpace, + onStretchTrigger: onStretchTrigger, + ); + return baseControl(context, appBar, parent, control); + } +} diff --git a/packages/flet/lib/src/controls/sliver_grid_view.dart b/packages/flet/lib/src/controls/sliver_grid_view.dart new file mode 100644 index 000000000..4a95c23d1 --- /dev/null +++ b/packages/flet/lib/src/controls/sliver_grid_view.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import '../flet_control_backend.dart'; +import '../models/control.dart'; +import 'create_control.dart'; +import 'scroll_notification_control.dart'; +import 'scrollable_control.dart'; + +class SliverGridViewControl extends StatefulWidget { + final Control? parent; + final Control control; + final bool parentDisabled; + final List children; + final bool? parentAdaptive; + final FletControlBackend backend; + + const SliverGridViewControl( + {super.key, + this.parent, + required this.control, + required this.children, + required this.parentDisabled, + required this.parentAdaptive, + required this.backend}); + + @override + State createState() => _SliverGridViewControlState(); +} + +class _SliverGridViewControlState extends State { + late final ScrollController _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("SliverGridViewControl build: ${widget.control.id}"); + + bool disabled = widget.control.isDisabled || widget.parentDisabled; + bool? adaptive = + widget.control.attrBool("adaptive") ?? widget.parentAdaptive; + + final spacing = widget.control.attrDouble("spacing", 0)!; + List ctrls = widget.children.where((c) => c.isVisible).toList(); + final maxExtent = widget.control.attrDouble("maxExtent"); + final runSpacing = widget.control.attrDouble("runSpacing", 10)!; + final runsCount = widget.control.attrInt("runsCount", 1)!; + final childAspectRatio = widget.control.attrDouble("childAspectRatio", 1)!; + var buildControlsOnDemand = + widget.control.attrBool("buildControlsOnDemand", true)!; + + var gridDelegate = maxExtent == null + ? SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: runsCount, + mainAxisSpacing: spacing, + crossAxisSpacing: runSpacing, + childAspectRatio: childAspectRatio) + : SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: maxExtent, + mainAxisSpacing: spacing, + crossAxisSpacing: runSpacing, + childAspectRatio: childAspectRatio); + + Widget child = buildControlsOnDemand + ? SliverGrid.builder( + itemCount: widget.children.length, + gridDelegate: gridDelegate, + itemBuilder: (context, index) { + return createControl(widget.control, ctrls[index].id, disabled, + parentAdaptive: adaptive); + }, + ) + : SliverGrid( + gridDelegate: gridDelegate, + delegate: SliverChildBuilderDelegate( + (context, index) => createControl( + widget.control, ctrls[index].id, disabled, + parentAdaptive: adaptive), + childCount: ctrls.length, + ), + ); + child = ScrollableControl( + control: widget.control, + scrollDirection: Axis.vertical, + scrollController: _controller, + backend: widget.backend, + parentAdaptive: adaptive, + child: child); + + if (widget.control.attrBool("onScroll", false)!) { + child = ScrollNotificationControl( + control: widget.control, backend: widget.backend, child: child); + } + + return constrainedControl(context, child, widget.parent, widget.control); + } +} diff --git a/packages/flet/lib/src/controls/sliver_list_view.dart b/packages/flet/lib/src/controls/sliver_list_view.dart new file mode 100644 index 000000000..742cd6bfe --- /dev/null +++ b/packages/flet/lib/src/controls/sliver_list_view.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; + +import '../flet_control_backend.dart'; +import '../models/control.dart'; +import 'create_control.dart'; +import 'scroll_notification_control.dart'; +import 'scrollable_control.dart'; + +class SliverListViewControl extends StatefulWidget { + final Control? parent; + final Control control; + final bool parentDisabled; + final List children; + final bool? parentAdaptive; + final FletControlBackend backend; + + const SliverListViewControl( + {super.key, + this.parent, + required this.control, + required this.children, + required this.parentDisabled, + required this.parentAdaptive, + required this.backend}); + + @override + State createState() => _SliverListViewControlState(); +} + +class _SliverListViewControlState extends State { + late final ScrollController _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("SliverListViewControl build: ${widget.control.id}"); + + bool disabled = widget.control.isDisabled || widget.parentDisabled; + bool? adaptive = + widget.control.attrBool("adaptive") ?? widget.parentAdaptive; + + final spacing = widget.control.attrDouble("spacing", 0)!; + final dividerThickness = widget.control.attrDouble("dividerThickness", 0)!; + List ctrls = widget.children.where((c) => c.isVisible).toList(); + var itemCount = ctrls.length; + + Widget child = spacing > 0 + ? SliverList.separated( + itemCount: itemCount, + itemBuilder: (context, index) { + return createControl(widget.control, ctrls[index].id, disabled, + parentAdaptive: adaptive); + }, + separatorBuilder: (context, index) { + return dividerThickness == 0 + ? SizedBox(height: spacing) + : Divider(height: spacing, thickness: dividerThickness); + }, + ) + : SliverList.builder( + itemCount: itemCount, + itemBuilder: (context, index) { + return createControl(widget.control, ctrls[index].id, disabled, + parentAdaptive: adaptive); + }, + ); + child = ScrollableControl( + control: widget.control, + scrollDirection: Axis.vertical, + scrollController: _controller, + backend: widget.backend, + parentAdaptive: adaptive, + child: child); + + if (widget.control.attrBool("onScroll", false)!) { + child = ScrollNotificationControl( + control: widget.control, backend: widget.backend, child: child); + } + + return constrainedControl(context, child, widget.parent, widget.control); + } +} diff --git a/packages/flet/lib/src/controls/sliver_safe_area.dart b/packages/flet/lib/src/controls/sliver_safe_area.dart new file mode 100644 index 000000000..688ce6c85 --- /dev/null +++ b/packages/flet/lib/src/controls/sliver_safe_area.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../utils/edge_insets.dart'; +import 'create_control.dart'; +import 'error.dart'; + +class SliverSafeAreaControl extends StatelessWidget { + final Control? parent; + final Control control; + final List children; + final bool parentDisabled; + final bool? parentAdaptive; + + const SliverSafeAreaControl( + {super.key, + this.parent, + required this.control, + required this.children, + required this.parentDisabled, + required this.parentAdaptive}); + + @override + Widget build(BuildContext context) { + debugPrint("SliverSafeArea build: ${control.id}"); + + var contentCtrls = + children.where((c) => c.name == "content" && c.isVisible); + bool disabled = control.isDisabled || parentDisabled; + bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; + var safeArea = SliverSafeArea( + left: control.attrBool("left", true)!, + top: control.attrBool("top", true)!, + right: control.attrBool("right", true)!, + bottom: control.attrBool("bottom", true)!, + minimum: parseEdgeInsets(control, "minimumPadding") ?? + parseEdgeInsets(control, "minimum") ?? + EdgeInsets.zero, + sliver: contentCtrls.isNotEmpty + ? createControl(control, contentCtrls.first.id, disabled, + parentAdaptive: adaptive) + : const ErrorControl( + "SliverSafeArea.content must be provided and visible")); + + return constrainedControl(context, safeArea, parent, control); + } +} diff --git a/packages/flet/lib/src/controls/sliver_scroll_view.dart b/packages/flet/lib/src/controls/sliver_scroll_view.dart new file mode 100644 index 000000000..1476c7348 --- /dev/null +++ b/packages/flet/lib/src/controls/sliver_scroll_view.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; + +import '../flet_control_backend.dart'; +import '../models/control.dart'; +import '../utils/others.dart'; +import 'create_control.dart'; +import 'flet_store_mixin.dart'; +import 'scroll_notification_control.dart'; +import 'scrollable_control.dart'; + +class SliverScrollViewControl extends StatefulWidget with FletStoreMixin { + final Control? parent; + final Control control; + final bool parentDisabled; + final bool? parentAdaptive; + final List children; + final FletControlBackend backend; + + const SliverScrollViewControl({ + super.key, + this.parent, + required this.control, + required this.children, + required this.parentDisabled, + required this.parentAdaptive, + required this.backend, + }); + + @override + State createState() => + _SliverScrollViewControlState(); +} + +class _SliverScrollViewControlState extends State { + late final ScrollController _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("SliverScrollView build: ${widget.control.id}"); + + bool? adaptive = widget.control.isAdaptive ?? widget.parentAdaptive; + bool disabled = widget.control.isDisabled || widget.parentDisabled; + var ctrls = createControls( + widget.control, widget.children.where((c) => c.isVisible), disabled, + parentAdaptive: adaptive) ?? + const []; + var scrollDirection = widget.control.attrBool("horizontal", false)! + ? Axis.horizontal + : Axis.vertical; + + Widget child = CustomScrollView( + clipBehavior: + parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!, + reverse: widget.control.attrBool("reverse", false)!, + scrollDirection: scrollDirection, + shrinkWrap: widget.control.attrBool("shrinkWrap", false)!, + semanticChildCount: + widget.control.attrInt("semanticChildCount", ctrls.length), + anchor: widget.control.attrDouble("anchor", 0.0)!, + primary: widget.control.attrBool("primary"), + cacheExtent: widget.control.attrDouble("cacheExtent"), + slivers: ctrls, + ); + child = ScrollableControl( + control: widget.control, + scrollDirection: scrollDirection, + scrollController: _controller, + backend: widget.backend, + parentAdaptive: adaptive, + child: child); + + if (widget.control.attrBool("onScroll", false)!) { + child = ScrollNotificationControl( + control: widget.control, backend: widget.backend, child: child); + } + + return baseControl(context, child, widget.parent, widget.control); + } +} diff --git a/packages/flet/lib/src/utils/others.dart b/packages/flet/lib/src/utils/others.dart index 6727e01be..89e6d105c 100644 --- a/packages/flet/lib/src/utils/others.dart +++ b/packages/flet/lib/src/utils/others.dart @@ -286,3 +286,35 @@ PointerDeviceKind? parsePointerDeviceKind(String? value, (e) => e.name.toLowerCase() == value.toLowerCase()) ?? defValue; } + +CollapseMode? parseCollapseMode(String? value, [CollapseMode? defValue]) { + if (value == null) { + return defValue; + } + return CollapseMode.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defValue; +} + +StretchMode? parseStretchMode(String? value, [StretchMode? defValue]) { + if (value == null) { + return defValue; + } + return StretchMode.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defValue; +} + +List? parseStretchModes(Control control, String propName, + [List? defValue]) { + var v = control.attrString(propName, null); + if (v == null) { + return defValue; + } + + final j = json.decode(v); + return (j as List) + .map((e) => parseStretchMode(e as String)) + .nonNulls + .toList(); +} diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index 8df93d480..e509e8167 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -176,6 +176,7 @@ from flet.core.filled_tonal_button import FilledTonalButton from flet.core.flashlight import Flashlight from flet.core.flet_app import FletApp +from flet.core.flexible_space_bar import FlexibleSpaceBar, CollapseMode, StretchMode from flet.core.floating_action_button import FloatingActionButton from flet.core.form_field_control import InputBorder from flet.core.geolocator import ( @@ -313,6 +314,12 @@ from flet.core.shake_detector import ShakeDetector from flet.core.size import Size from flet.core.slider import Slider, SliderInteraction +from flet.core.sliver import Sliver +from flet.core.sliver_app_bar import SliverAppBar, SliverAppBarType +from flet.core.sliver_grid_view import SliverGridView +from flet.core.sliver_list_view import SliverListView +from flet.core.sliver_safe_area import SliverSafeArea +from flet.core.sliver_scroll_view import SliverScrollView from flet.core.snack_bar import DismissDirection, SnackBar, SnackBarBehavior from flet.core.stack import Stack, StackFit from flet.core.submenu_button import SubmenuButton diff --git a/sdk/python/packages/flet/src/flet/core/app_bar.py b/sdk/python/packages/flet/src/flet/core/app_bar.py index 9853a16cd..9ec40115e 100644 --- a/sdk/python/packages/flet/src/flet/core/app_bar.py +++ b/sdk/python/packages/flet/src/flet/core/app_bar.py @@ -77,13 +77,16 @@ def __init__( toolbar_text_style: Optional[TextStyle] = None, shape: Optional[OutlinedBorder] = None, # - # AdaptiveControl + # Control # ref: Optional[Ref] = None, visible: Optional[bool] = None, disabled: Optional[bool] = None, data: Any = None, rtl: Optional[bool] = None, + # + # AdaptiveControl + # adaptive: Optional[bool] = None, ): Control.__init__( diff --git a/sdk/python/packages/flet/src/flet/core/container.py b/sdk/python/packages/flet/src/flet/core/container.py index 2f404cf45..2fce60c59 100644 --- a/sdk/python/packages/flet/src/flet/core/container.py +++ b/sdk/python/packages/flet/src/flet/core/container.py @@ -28,8 +28,6 @@ ClipBehavior, ColorEnums, ColorValue, - ImageFit, - ImageRepeat, MarginValue, OffsetValue, OptionalControlEventCallable, @@ -41,7 +39,6 @@ ThemeMode, UrlTarget, ) -from flet.utils.deprecated import deprecated_property class Container(ConstrainedControl, AdaptiveControl): diff --git a/sdk/python/packages/flet/src/flet/core/dropdown.py b/sdk/python/packages/flet/src/flet/core/dropdown.py index a349bd71c..dbe991833 100644 --- a/sdk/python/packages/flet/src/flet/core/dropdown.py +++ b/sdk/python/packages/flet/src/flet/core/dropdown.py @@ -7,7 +7,6 @@ from flet.core.buttons import ButtonStyle from flet.core.control import Control, OptionalNumber from flet.core.form_field_control import FormFieldControl, InputBorder -from flet.core.menu_bar import MenuStyle from flet.core.ref import Ref from flet.core.text_style import TextStyle from flet.core.textfield import InputFilter, TextCapitalization diff --git a/sdk/python/packages/flet/src/flet/core/flexible_space_bar.py b/sdk/python/packages/flet/src/flet/core/flexible_space_bar.py new file mode 100644 index 000000000..0e619ee04 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/flexible_space_bar.py @@ -0,0 +1,207 @@ +from enum import Enum +from typing import Any, List, Optional, Union + +from flet.core.adaptive_control import AdaptiveControl +from flet.core.animation import AnimationValue +from flet.core.badge import BadgeValue +from flet.core.constrained_control import ConstrainedControl +from flet.core.control import Control +from flet.core.ref import Ref +from flet.core.tooltip import TooltipValue +from flet.core.types import ( + OffsetValue, + OptionalControlEventCallable, + OptionalNumber, + PaddingValue, + ResponsiveNumber, + RotateValue, + ScaleValue, +) + + +class CollapseMode(Enum): + PARALLAX = "parallax" + PIN = "pin" + NONE = "none" + + +class StretchMode(Enum): + ZOOM_BACKGROUND = "zoomBackground" + BLUR_BACKGROUND = "blurBackground" + FADE_TITLE = "fadeTitle" + + +class FlexibleSpaceBar(ConstrainedControl, AdaptiveControl): + """ + A flexible space bar. + + ----- + + Online docs: https://flet.dev/docs/controls/flexiblespacebar + """ + + def __init__( + self, + title: Optional[Control] = None, + background: Optional[Control] = None, + center_title: Optional[bool] = None, + expanded_title_scale: OptionalNumber = None, + tile_padding: Optional[PaddingValue] = None, + collapse_mode: Optional[CollapseMode] = None, + stretch_mode: Optional[List[StretchMode]] = None, + # + # ConstrainedControl and AdaptiveControl + # + ref: Optional[Ref] = None, + key: Optional[str] = None, + width: OptionalNumber = None, + height: OptionalNumber = None, + left: OptionalNumber = None, + top: OptionalNumber = None, + right: OptionalNumber = None, + bottom: OptionalNumber = None, + expand: Union[None, bool, int] = None, + expand_loose: Optional[bool] = None, + col: Optional[ResponsiveNumber] = None, + opacity: OptionalNumber = None, + rotate: Optional[RotateValue] = None, + scale: Optional[ScaleValue] = None, + offset: Optional[OffsetValue] = None, + aspect_ratio: OptionalNumber = None, + animate_opacity: Optional[AnimationValue] = None, + animate_size: Optional[AnimationValue] = None, + animate_position: Optional[AnimationValue] = None, + animate_rotation: Optional[AnimationValue] = None, + animate_scale: Optional[AnimationValue] = None, + animate_offset: Optional[AnimationValue] = None, + on_animation_end: OptionalControlEventCallable = None, + tooltip: Optional[TooltipValue] = None, + badge: Optional[BadgeValue] = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + adaptive: Optional[bool] = None, + ): + ConstrainedControl.__init__( + self, + ref=ref, + key=key, + width=width, + height=height, + left=left, + top=top, + right=right, + bottom=bottom, + expand=expand, + expand_loose=expand_loose, + col=col, + opacity=opacity, + rotate=rotate, + scale=scale, + offset=offset, + aspect_ratio=aspect_ratio, + animate_opacity=animate_opacity, + animate_size=animate_size, + animate_position=animate_position, + animate_rotation=animate_rotation, + animate_scale=animate_scale, + animate_offset=animate_offset, + on_animation_end=on_animation_end, + tooltip=tooltip, + badge=badge, + visible=visible, + disabled=disabled, + data=data, + ) + + AdaptiveControl.__init__(self, adaptive=adaptive) + + self.title = title + self.background = background + self.center_title = center_title + self.expanded_title_scale = expanded_title_scale + self.tile_padding = tile_padding + self.collapse_mode = collapse_mode + self.stretch_mode = stretch_mode + + def _get_control_name(self): + return "flexiblespacebar" + + def before_update(self): + super().before_update() + self._set_attr_json("tilePadding", self.__tile_padding) + self._set_attr_json("stretchMode", self.__stretch_mode) + + def _get_children(self): + children = [] + if self.__title: + self.__title._set_attr_internal("n", "title") + children.append(self.__title) + if self.__background: + self.__background._set_attr_internal("n", "background") + children.append(self.__background) + return children + + # background + @property + def background(self) -> Optional[Control]: + return self.__background + + @background.setter + def background(self, value: Optional[Control]): + self.__background = value + + # title + @property + def title(self) -> Optional[Control]: + return self.__title + + @title.setter + def title(self, value: Optional[Control]): + self.__title = value + + # center_title + @property + def center_title(self) -> bool: + return self._get_attr("centerTitle", data_type="bool", def_value=False) + + @center_title.setter + def center_title(self, value: Optional[bool]): + self._set_attr("centerTitle", value) + + # expanded_title_scale + @property + def expanded_title_scale(self) -> OptionalNumber: + return self._get_attr("expandedTitleScale", data_type="float") + + @expanded_title_scale.setter + def expanded_title_scale(self, value: OptionalNumber): + self._set_attr("expandedTitleScale", value) + + # tile_padding + @property + def tile_padding(self) -> Optional[PaddingValue]: + return self.__tile_padding + + @tile_padding.setter + def tile_padding(self, value: Optional[PaddingValue]): + self.__tile_padding = value + + # collapse_mode + @property + def collapse_mode(self) -> Optional[CollapseMode]: + return self.__collapse_mode + + @collapse_mode.setter + def collapse_mode(self, value: Optional[CollapseMode]): + self.__collapse_mode = value + self._set_enum_attr("collapseMode", value, CollapseMode) + + # stretch_mode + @property + def stretch_mode(self) -> Optional[List[StretchMode]]: + return self.__stretch_mode + + @stretch_mode.setter + def stretch_mode(self, value: Optional[List[StretchMode]]): + self.__stretch_mode = value diff --git a/sdk/python/packages/flet/src/flet/core/list_view.py b/sdk/python/packages/flet/src/flet/core/list_view.py index f74389d26..2bc433873 100644 --- a/sdk/python/packages/flet/src/flet/core/list_view.py +++ b/sdk/python/packages/flet/src/flet/core/list_view.py @@ -71,7 +71,7 @@ def __init__( cache_extent: OptionalNumber = None, build_controls_on_demand: Optional[bool] = None, # - # ScrollableControl specific + # ScrollableControl # auto_scroll: Optional[bool] = None, reverse: Optional[bool] = None, diff --git a/sdk/python/packages/flet/src/flet/core/markdown.py b/sdk/python/packages/flet/src/flet/core/markdown.py index e32aa4672..6709e0e08 100644 --- a/sdk/python/packages/flet/src/flet/core/markdown.py +++ b/sdk/python/packages/flet/src/flet/core/markdown.py @@ -1,4 +1,3 @@ -import warnings from dataclasses import dataclass from enum import Enum, EnumMeta from typing import Any, Optional, Union, cast diff --git a/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py b/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py index 80d7fab85..9cd7a1040 100644 --- a/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py +++ b/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py @@ -38,56 +38,56 @@ class ReorderableListView(ListView): """ def __init__( - self, - controls: Optional[Sequence[Control]] = None, - horizontal: Optional[bool] = None, - item_extent: OptionalNumber = None, - first_item_prototype: Optional[bool] = None, - padding: PaddingValue = None, - clip_behavior: Optional[ClipBehavior] = None, - cache_extent: OptionalNumber = None, - anchor: OptionalNumber = None, - auto_scroller_velocity_scalar: OptionalNumber = None, - header: Optional[Control] = None, - footer: Optional[Control] = None, - build_controls_on_demand: Optional[bool] = None, - on_reorder: OptionalEventCallable[OnReorderEvent] = None, - on_reorder_start: OptionalEventCallable[OnReorderEvent] = None, - on_reorder_end: OptionalEventCallable[OnReorderEvent] = None, - # - # ScrollableControl - # - auto_scroll: Optional[bool] = None, - reverse: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: OptionalEventCallable[OnScrollEvent] = None, - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: RotateValue = None, - scale: ScaleValue = None, - offset: OffsetValue = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, + self, + controls: Optional[Sequence[Control]] = None, + horizontal: Optional[bool] = None, + item_extent: OptionalNumber = None, + first_item_prototype: Optional[bool] = None, + padding: PaddingValue = None, + clip_behavior: Optional[ClipBehavior] = None, + cache_extent: OptionalNumber = None, + anchor: OptionalNumber = None, + auto_scroller_velocity_scalar: OptionalNumber = None, + header: Optional[Control] = None, + footer: Optional[Control] = None, + build_controls_on_demand: Optional[bool] = None, + on_reorder: OptionalEventCallable[OnReorderEvent] = None, + on_reorder_start: OptionalEventCallable[OnReorderEvent] = None, + on_reorder_end: OptionalEventCallable[OnReorderEvent] = None, + # + # ScrollableControl + # + auto_scroll: Optional[bool] = None, + reverse: Optional[bool] = None, + on_scroll_interval: OptionalNumber = None, + on_scroll: OptionalEventCallable[OnScrollEvent] = None, + ref: Optional[Ref] = None, + key: Optional[str] = None, + width: OptionalNumber = None, + height: OptionalNumber = None, + left: OptionalNumber = None, + top: OptionalNumber = None, + right: OptionalNumber = None, + bottom: OptionalNumber = None, + expand: Union[None, bool, int] = None, + expand_loose: Optional[bool] = None, + col: Optional[ResponsiveNumber] = None, + opacity: OptionalNumber = None, + rotate: RotateValue = None, + scale: ScaleValue = None, + offset: OffsetValue = None, + aspect_ratio: OptionalNumber = None, + animate_opacity: Optional[AnimationValue] = None, + animate_size: Optional[AnimationValue] = None, + animate_position: Optional[AnimationValue] = None, + animate_rotation: Optional[AnimationValue] = None, + animate_scale: Optional[AnimationValue] = None, + animate_offset: Optional[AnimationValue] = None, + on_animation_end: OptionalControlEventCallable = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + adaptive: Optional[bool] = None, ): ListView.__init__( self, @@ -151,9 +151,6 @@ def __init__( def _get_control_name(self): return "reorderablelistview" - def before_update(self): - super().before_update() - def _get_children(self): children = super()._get_children() if self.header: diff --git a/sdk/python/packages/flet/src/flet/core/sliver.py b/sdk/python/packages/flet/src/flet/core/sliver.py new file mode 100644 index 000000000..e3701be2d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/sliver.py @@ -0,0 +1,11 @@ +from flet.core.control import Control + + +class Sliver(Control): + """ + A base class for sliver controls. + + ----- + + Online docs: https://flet.dev/docs/controls/sliver + """ diff --git a/sdk/python/packages/flet/src/flet/core/sliver_app_bar.py b/sdk/python/packages/flet/src/flet/core/sliver_app_bar.py new file mode 100644 index 000000000..71d3447ec --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/sliver_app_bar.py @@ -0,0 +1,272 @@ +from enum import Enum +from typing import Any, List, Optional + +from flet.core.app_bar import AppBar +from flet.core.buttons import OutlinedBorder +from flet.core.control import Control +from flet.core.ref import Ref +from flet.core.sliver import Sliver +from flet.core.text_style import TextStyle +from flet.core.types import ( + ClipBehavior, + ColorValue, + OptionalControlEventCallable, + OptionalNumber, + PaddingValue, +) + + +class SliverAppBarType(Enum): + MEDIUM = "medium" + LARGE = "large" + DEFAULT = "default" + + +class SliverAppBar(AppBar, Sliver): + """ + A Material Design app bar that integrates with a SliverScrollView. + + ----- + + Online docs: https://flet.dev/docs/controls/sliverappbar + """ + + def __init__( + self, + leading: Optional[Control] = None, + title: Optional[Control] = None, + actions: Optional[List[Control]] = None, + flexible_space: Optional[Control] = None, + actions_padding: Optional[PaddingValue] = None, + collapsed_height: OptionalNumber = None, + pinned: Optional[bool] = None, + snap: Optional[bool] = None, + floating: Optional[bool] = None, + stretch: Optional[bool] = None, + expanded_height: OptionalNumber = None, + force_elevated: Optional[bool] = None, + stretch_trigger_offset: OptionalNumber = None, + type: Optional[SliverAppBarType] = None, + primary: Optional[bool] = None, + on_stretch: OptionalControlEventCallable = None, + # + # AppBar + # + leading_width: OptionalNumber = None, + automatically_imply_leading: Optional[bool] = None, + center_title: Optional[bool] = None, + toolbar_height: OptionalNumber = None, + color: Optional[ColorValue] = None, + bgcolor: Optional[ColorValue] = None, + elevation: OptionalNumber = None, + elevation_on_scroll: OptionalNumber = None, + shadow_color: Optional[ColorValue] = None, + surface_tint_color: Optional[ColorValue] = None, + clip_behavior: Optional[ClipBehavior] = None, + force_material_transparency: Optional[bool] = None, + title_spacing: OptionalNumber = None, + exclude_header_semantics: Optional[bool] = None, + title_text_style: Optional[TextStyle] = None, + toolbar_text_style: Optional[TextStyle] = None, + shape: Optional[OutlinedBorder] = None, + # + # Control + # + ref: Optional[Ref] = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + rtl: Optional[bool] = None, + # + # AdaptiveControl + # + adaptive: Optional[bool] = None, + ): + AppBar.__init__( + self, + leading=leading, + leading_width=leading_width, + automatically_imply_leading=automatically_imply_leading, + title=title, + center_title=center_title, + toolbar_height=toolbar_height, + color=color, + bgcolor=bgcolor, + elevation=elevation, + elevation_on_scroll=elevation_on_scroll, + shadow_color=shadow_color, + surface_tint_color=surface_tint_color, + clip_behavior=clip_behavior, + force_material_transparency=force_material_transparency, + title_spacing=title_spacing, + exclude_header_semantics=exclude_header_semantics, + actions=actions, + title_text_style=title_text_style, + toolbar_text_style=toolbar_text_style, + shape=shape, + ref=ref, + visible=visible, + disabled=disabled, + data=data, + rtl=rtl, + adaptive=adaptive, + ) + + self.flexible_space = flexible_space + self.actions_padding = actions_padding + self.collapsed_height = collapsed_height + self.pinned = pinned + self.snap = snap + self.floating = floating + self.stretch = stretch + self.expanded_height = expanded_height + self.force_elevated = force_elevated + self.stretch_trigger_offset = stretch_trigger_offset + self.type = type + self.primary = primary + self.on_stretch = on_stretch + + def _get_control_name(self): + return "sliverappbar" + + def before_update(self): + super().before_update() + assert ( + self.floating or not self.snap + ), "snap can only be True when floating is True" + assert ( + self.collapsed_height is None + or self.collapsed_height >= self.toolbar_height + ), f"collapsed_height ({self.collapsed_height}) must be greater than or equal to toolbar_height ({self.toolbar_height})" + if isinstance(self.__actions_padding, PaddingValue): + self._set_attr_json("actionsPadding", self.__actions_padding) + + def _get_children(self): + children = super()._get_children() + if self.__flexible_space: + self.__flexible_space._set_attr_internal("n", "flexibleSpace") + children.append(self.__flexible_space) + return children + + # flexible_space + @property + def flexible_space(self) -> Optional[Control]: + return self.__flexible_space + + @flexible_space.setter + def flexible_space(self, value: Optional[Control]): + self.__flexible_space = value + + # actions_padding + @property + def actions_padding(self) -> Optional[PaddingValue]: + return self.__actions_padding + + @actions_padding.setter + def actions_padding(self, value: Optional[PaddingValue]): + self.__actions_padding = value + + # collapsed_height + @property + def collapsed_height(self) -> OptionalNumber: + return self._get_attr("collapsedHeight") + + @collapsed_height.setter + def collapsed_height(self, value: OptionalNumber): + self._set_attr("collapsedHeight", value) + + # pinned + @property + def pinned(self) -> bool: + return self._get_attr("pinned", data_type="bool", def_value=False) + + @pinned.setter + def pinned(self, value: bool): + self._set_attr("pinned", value) + + # primary + @property + def primary(self) -> bool: + return self._get_attr("primary", data_type="bool", def_value=False) + + @primary.setter + def primary(self, value: bool): + self._set_attr("primary", value) + + # snap + @property + def snap(self) -> bool: + return self._get_attr("snap", data_type="bool", def_value=False) + + @snap.setter + def snap(self, value: bool): + self._set_attr("snap", value) + + # floating + @property + def floating(self) -> bool: + return self._get_attr("floating", data_type="bool", def_value=False) + + @floating.setter + def floating(self, value: bool): + self._set_attr("floating", value) + + # stretch + @property + def stretch(self) -> bool: + return self._get_attr("stretch", data_type="bool", def_value=False) + + @stretch.setter + def stretch(self, value: bool): + self._set_attr("stretch", value) + + # expanded_height + @property + def expanded_height(self) -> OptionalNumber: + return self._get_attr("expandedHeight") + + @expanded_height.setter + def expanded_height(self, value: OptionalNumber): + self._set_attr("expandedHeight", value) + + # force_elevated + @property + def force_elevated(self) -> bool: + return self._get_attr("forceElevated", data_type="bool", def_value=False) + + @force_elevated.setter + def force_elevated(self, value: bool): + self._set_attr("forceElevated", value) + + # stretch_trigger_offset + @property + def stretch_trigger_offset(self) -> OptionalNumber: + return self._get_attr( + "stretchTriggerOffset", data_type="float", def_value=100.0 + ) + + @stretch_trigger_offset.setter + def stretch_trigger_offset(self, value: OptionalNumber): + assert ( + value is None or value > 0 + ), "stretch_trigger_offset must be greater than 0" + self._set_attr("stretchTriggerOffset", value) + + # type + @property + def type(self) -> Optional[SliverAppBarType]: + return self.__type + + @type.setter + def type(self, value: Optional[SliverAppBarType]): + self.__type = value + self._set_enum_attr("type", value, SliverAppBarType) + + # on_stretch + @property + def on_stretch(self) -> OptionalControlEventCallable: + return self._get_event_handler("stretch") + + @on_stretch.setter + def on_stretch(self, handler: OptionalControlEventCallable): + self._add_event_handler("stretch", handler) diff --git a/sdk/python/packages/flet/src/flet/core/sliver_grid_view.py b/sdk/python/packages/flet/src/flet/core/sliver_grid_view.py new file mode 100644 index 000000000..349a6e8fe --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/sliver_grid_view.py @@ -0,0 +1,191 @@ +from typing import Any, List, Optional, Union + +from flet.core.adaptive_control import AdaptiveControl +from flet.core.animation import AnimationValue +from flet.core.constrained_control import ConstrainedControl +from flet.core.control import Control +from flet.core.ref import Ref +from flet.core.scrollable_control import ScrollableControl +from flet.core.sliver import Sliver +from flet.core.types import ( + OffsetValue, + OptionalNumber, + ResponsiveNumber, + RotateValue, + ScaleValue, +) + + +class SliverGridView(ConstrainedControl, ScrollableControl, AdaptiveControl, Sliver): + """ + A sliver that places multiple box children in a linear array along the main axis. + + ----- + + Online docs: https://flet.dev/docs/controls/slivergridview + """ + + def __init__( + self, + controls: Optional[List[Control]] = None, + runs_count: Optional[int] = None, + max_extent: Optional[int] = None, + spacing: OptionalNumber = None, + run_spacing: OptionalNumber = None, + child_aspect_ratio: OptionalNumber = None, + build_controls_on_demand: Optional[bool] = None, + # + # ScrollableControl + # + on_scroll_interval: OptionalNumber = None, + on_scroll: Any = None, + reverse: Optional[bool] = None, + # + # ConstrainedControl + # + ref: Optional[Ref] = None, + key: Optional[str] = None, + width: OptionalNumber = None, + height: OptionalNumber = None, + left: OptionalNumber = None, + top: OptionalNumber = None, + right: OptionalNumber = None, + bottom: OptionalNumber = None, + expand: Union[None, bool, int] = None, + expand_loose: Optional[bool] = None, + col: Optional[ResponsiveNumber] = None, + opacity: OptionalNumber = None, + rotate: RotateValue = None, + scale: ScaleValue = None, + offset: OffsetValue = None, + aspect_ratio: OptionalNumber = None, + animate_opacity: AnimationValue = None, + animate_size: AnimationValue = None, + animate_position: AnimationValue = None, + animate_rotation: AnimationValue = None, + animate_scale: AnimationValue = None, + animate_offset: AnimationValue = None, + on_animation_end=None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + # + # AdaptiveControl + # + adaptive: Optional[bool] = None, + ): + ConstrainedControl.__init__( + self, + ref=ref, + key=key, + width=width, + height=height, + left=left, + top=top, + right=right, + bottom=bottom, + expand=expand, + expand_loose=expand_loose, + col=col, + opacity=opacity, + rotate=rotate, + scale=scale, + offset=offset, + aspect_ratio=aspect_ratio, + animate_opacity=animate_opacity, + animate_size=animate_size, + animate_position=animate_position, + animate_rotation=animate_rotation, + animate_scale=animate_scale, + animate_offset=animate_offset, + on_animation_end=on_animation_end, + visible=visible, + disabled=disabled, + data=data, + ) + + ScrollableControl.__init__( + self, + on_scroll_interval=on_scroll_interval, + on_scroll=on_scroll, + reverse=reverse, + ) + + AdaptiveControl.__init__(self, adaptive=adaptive) + + self.controls = controls + self.runs_count = runs_count + self.max_extent = max_extent + self.spacing = spacing + self.run_spacing = run_spacing + self.child_aspect_ratio = child_aspect_ratio + self.build_controls_on_demand = build_controls_on_demand + + def _get_control_name(self): + return "slivergridview" + + def _get_children(self): + return self.__controls + + # controls + @property + def controls(self) -> Optional[List[Control]]: + return self.__controls + + @controls.setter + def controls(self, value: Optional[List[Control]]): + self.__controls = value + + # build_controls_on_demand + @property + def build_controls_on_demand(self) -> Optional[bool]: + return self._get_attr("buildControlsOnDemand", data_type="bool") + + @build_controls_on_demand.setter + def build_controls_on_demand(self, value: Optional[bool]): + self._set_attr("buildControlsOnDemand", value) + + # runs_count + @property + def runs_count(self) -> Optional[int]: + return self._get_attr("runsCount") + + @runs_count.setter + def runs_count(self, value: Optional[int]): + self._set_attr("runsCount", value) + + # max_extent + @property + def max_extent(self) -> OptionalNumber: + return self._get_attr("maxExtent", data_type="float") + + @max_extent.setter + def max_extent(self, value: OptionalNumber): + self._set_attr("maxExtent", value) + + # spacing + @property + def spacing(self) -> OptionalNumber: + return self._get_attr("spacing", data_type="float") + + @spacing.setter + def spacing(self, value: OptionalNumber): + self._set_attr("spacing", value) + + # run_spacing + @property + def run_spacing(self) -> OptionalNumber: + return self._get_attr("runSpacing", data_type="float") + + @run_spacing.setter + def run_spacing(self, value: OptionalNumber): + self._set_attr("runSpacing", value) + + # child_aspect_ratio + @property + def child_aspect_ratio(self) -> OptionalNumber: + return self._get_attr("childAspectRatio") + + @child_aspect_ratio.setter + def child_aspect_ratio(self, value: OptionalNumber): + self._set_attr("childAspectRatio", value) diff --git a/sdk/python/packages/flet/src/flet/core/sliver_list_view.py b/sdk/python/packages/flet/src/flet/core/sliver_list_view.py new file mode 100644 index 000000000..8bdd7c3e4 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/sliver_list_view.py @@ -0,0 +1,161 @@ +from typing import Any, List, Optional, Union + +from flet.core.adaptive_control import AdaptiveControl +from flet.core.animation import AnimationValue +from flet.core.constrained_control import ConstrainedControl +from flet.core.control import Control +from flet.core.ref import Ref +from flet.core.scrollable_control import ScrollableControl +from flet.core.sliver import Sliver +from flet.core.types import ( + ClipBehavior, + OffsetValue, + OptionalNumber, + ResponsiveNumber, + RotateValue, + ScaleValue, +) + + +class SliverListView(ConstrainedControl, ScrollableControl, AdaptiveControl, Sliver): + """ + A sliver that places multiple box children in a linear array along the main axis. + + ----- + + Online docs: https://flet.dev/docs/controls/sliverlistview + """ + + def __init__( + self, + controls: Optional[List[Control]] = None, + spacing: OptionalNumber = None, + divider_thickness: OptionalNumber = None, + # + # ScrollableControl + # + on_scroll_interval: OptionalNumber = None, + on_scroll: Any = None, + reverse: Optional[bool] = None, + # + # ConstrainedControl + # + ref: Optional[Ref] = None, + key: Optional[str] = None, + width: OptionalNumber = None, + height: OptionalNumber = None, + left: OptionalNumber = None, + top: OptionalNumber = None, + right: OptionalNumber = None, + bottom: OptionalNumber = None, + expand: Union[None, bool, int] = None, + expand_loose: Optional[bool] = None, + col: Optional[ResponsiveNumber] = None, + opacity: OptionalNumber = None, + rotate: RotateValue = None, + scale: ScaleValue = None, + offset: OffsetValue = None, + aspect_ratio: OptionalNumber = None, + animate_opacity: AnimationValue = None, + animate_size: AnimationValue = None, + animate_position: AnimationValue = None, + animate_rotation: AnimationValue = None, + animate_scale: AnimationValue = None, + animate_offset: AnimationValue = None, + on_animation_end=None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + # + # AdaptiveControl + # + adaptive: Optional[bool] = None, + ): + ConstrainedControl.__init__( + self, + ref=ref, + key=key, + width=width, + height=height, + left=left, + top=top, + right=right, + bottom=bottom, + expand=expand, + expand_loose=expand_loose, + col=col, + opacity=opacity, + rotate=rotate, + scale=scale, + offset=offset, + aspect_ratio=aspect_ratio, + animate_opacity=animate_opacity, + animate_size=animate_size, + animate_position=animate_position, + animate_rotation=animate_rotation, + animate_scale=animate_scale, + animate_offset=animate_offset, + on_animation_end=on_animation_end, + visible=visible, + disabled=disabled, + data=data, + ) + + ScrollableControl.__init__( + self, + on_scroll_interval=on_scroll_interval, + on_scroll=on_scroll, + reverse=reverse, + ) + + AdaptiveControl.__init__(self, adaptive=adaptive) + + self.controls = controls + self.spacing = spacing + self.divider_thickness = divider_thickness + + def _get_control_name(self): + return "sliverlistview" + + def before_update(self): + super().before_update() + + def _get_children(self): + return self.__controls + + # spacing + @property + def spacing(self) -> OptionalNumber: + return self._get_attr("spacing", data_type="float") + + @spacing.setter + def spacing(self, value: OptionalNumber): + self._set_attr("spacing", value) + + # divider_thickness + @property + def divider_thickness(self) -> OptionalNumber: + return self._get_attr("dividerThickness") + + @divider_thickness.setter + def divider_thickness(self, value: OptionalNumber): + self._set_attr("dividerThickness", value) + + # controls + @property + def controls(self) -> List[Control]: + return self.__controls + + @controls.setter + def controls(self, value: List[Control]): + self.__controls = value if value is not None else [] + + # clip_behavior + @property + def clip_behavior(self) -> Optional[ClipBehavior]: + return self.__clip_behavior + + @clip_behavior.setter + def clip_behavior(self, value: Optional[ClipBehavior]): + self.__clip_behavior = value + self._set_enum_attr("clipBehavior", value, ClipBehavior) diff --git a/sdk/python/packages/flet/src/flet/core/sliver_safe_area.py b/sdk/python/packages/flet/src/flet/core/sliver_safe_area.py new file mode 100644 index 000000000..9213e5862 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/sliver_safe_area.py @@ -0,0 +1,106 @@ +from typing import Any, Optional, Union + +from flet.core.adaptive_control import AdaptiveControl +from flet.core.animation import AnimationValue +from flet.core.badge import BadgeValue +from flet.core.control import OptionalNumber +from flet.core.ref import Ref +from flet.core.safe_area import SafeArea +from flet.core.sliver import Sliver +from flet.core.tooltip import TooltipValue +from flet.core.types import ( + OffsetValue, + OptionalControlEventCallable, + PaddingValue, + ResponsiveNumber, + RotateValue, + ScaleValue, +) + + +class SliverSafeArea(SafeArea, Sliver): + """ + A sliver that insets another sliver by sufficient padding to avoid intrusions by the operating system. + + ----- + + Online docs: https://flet.dev/docs/controls/sliversafearea + """ + + def __init__( + self, + content: Sliver, + left: Optional[bool] = None, + top: Optional[bool] = None, + right: Optional[bool] = None, + bottom: Optional[bool] = None, + minimum_padding: Optional[PaddingValue] = None, + # + # ConstrainedControl and AdaptiveControl + # + ref: Optional[Ref] = None, + key: Optional[str] = None, + width: OptionalNumber = None, + height: OptionalNumber = None, + expand: Union[None, bool, int] = None, + expand_loose: Optional[bool] = None, + col: Optional[ResponsiveNumber] = None, + opacity: OptionalNumber = None, + rotate: Optional[RotateValue] = None, + scale: Optional[ScaleValue] = None, + offset: Optional[OffsetValue] = None, + aspect_ratio: OptionalNumber = None, + animate_opacity: Optional[AnimationValue] = None, + animate_size: Optional[AnimationValue] = None, + animate_position: Optional[AnimationValue] = None, + animate_rotation: Optional[AnimationValue] = None, + animate_scale: Optional[AnimationValue] = None, + animate_offset: Optional[AnimationValue] = None, + on_animation_end: OptionalControlEventCallable = None, + tooltip: Optional[TooltipValue] = None, + badge: Optional[BadgeValue] = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + rtl: Optional[bool] = None, + adaptive: Optional[bool] = None, + ): + SafeArea.__init__( + self, + content=content, + left=left, + top=top, + right=right, + bottom=bottom, + minimum_padding=minimum_padding, + ref=ref, + key=key, + width=width, + height=height, + expand=expand, + expand_loose=expand_loose, + col=col, + opacity=opacity, + rotate=rotate, + scale=scale, + offset=offset, + aspect_ratio=aspect_ratio, + animate_opacity=animate_opacity, + animate_size=animate_size, + animate_position=animate_position, + animate_rotation=animate_rotation, + animate_scale=animate_scale, + animate_offset=animate_offset, + on_animation_end=on_animation_end, + tooltip=tooltip, + badge=badge, + visible=visible, + disabled=disabled, + data=data, + rtl=rtl, + ) + + AdaptiveControl.__init__(self, adaptive=adaptive) + + def _get_control_name(self): + return "sliversafearea" diff --git a/sdk/python/packages/flet/src/flet/core/sliver_scroll_view.py b/sdk/python/packages/flet/src/flet/core/sliver_scroll_view.py new file mode 100644 index 000000000..ba935e934 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/core/sliver_scroll_view.py @@ -0,0 +1,149 @@ +from typing import Any, List, Optional + +from flet.core.adaptive_control import AdaptiveControl +from flet.core.control import Control +from flet.core.ref import Ref +from flet.core.sliver import Sliver +from flet.core.types import ClipBehavior, OptionalNumber + + +class SliverScrollView(AdaptiveControl, Sliver): + """ + A scroll view that creates custom scroll effects using slivers. + + ----- + + Online docs: https://flet.dev/docs/controls/sliverscrollview + """ + + def __init__( + self, + slivers: List[Sliver], + clip_behavior: Optional[ClipBehavior] = None, + reverse: Optional[bool] = None, + horizontal: Optional[bool] = None, + shrink_wrap: Optional[bool] = None, + semantic_child_count: Optional[int] = None, + anchor: OptionalNumber = None, + primary: Optional[bool] = None, + cache_extent: OptionalNumber = None, + # + # AdaptiveControl + # + ref: Optional[Ref] = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + rtl: Optional[bool] = None, + adaptive: Optional[bool] = None, + expand: Optional[bool] = None, + ): + Control.__init__( + self, + ref=ref, + visible=visible, + disabled=disabled, + data=data, + rtl=rtl, + expand=expand, + ) + + AdaptiveControl.__init__(self, adaptive=adaptive) + + self.slivers = slivers + self.clip_behavior = clip_behavior + self.reverse = reverse + self.horizontal = horizontal + self.shrink_wrap = shrink_wrap + self.semantic_child_count = semantic_child_count + self.anchor = anchor + self.primary = primary + self.cache_extent = cache_extent + + def _get_control_name(self): + return "sliverscrollview" + + def _get_children(self): + return self.__slivers + + # slivers + @property + def slivers(self) -> List[Control]: + return self.__slivers + + @slivers.setter + def slivers(self, value: List[Control]): + self.__slivers = value + + # clip_behavior + @property + def clip_behavior(self) -> Optional[ClipBehavior]: + return self.__clip_behavior + + @clip_behavior.setter + def clip_behavior(self, value: Optional[ClipBehavior]): + self.__clip_behavior = value + self._set_enum_attr("clipBehavior", value, ClipBehavior) + + # reverse + @property + def reverse(self) -> Optional[bool]: + return self._get_attr("reverse", data_type="bool", def_value=False) + + @reverse.setter + def reverse(self, value: Optional[bool]): + self._set_attr("reverse", value) + + # horizontal + @property + def horizontal(self) -> Optional[bool]: + return self._get_attr("horizontal", data_type="bool", def_value=False) + + @horizontal.setter + def horizontal(self, value: Optional[bool]): + self._set_attr("horizontal", value) + + # shrink_wrap + @property + def shrink_wrap(self) -> Optional[bool]: + return self._get_attr("shrinkWrap", data_type="bool", def_value=False) + + @shrink_wrap.setter + def shrink_wrap(self, value: Optional[bool]): + self._set_attr("shrinkWrap", value) + + # semantic_child_count + @property + def semantic_child_count(self) -> Optional[int]: + return self._get_attr("semanticChildCount", data_type="int") + + @semantic_child_count.setter + def semantic_child_count(self, value: Optional[int]): + self._set_attr("semanticChildCount", value) + + # anchor + @property + def anchor(self) -> OptionalNumber: + return self._get_attr("anchor", data_type="float", def_value=0.0) + + @anchor.setter + def anchor(self, value: OptionalNumber): + self._set_attr("anchor", value) + + # primary + @property + def primary(self) -> Optional[bool]: + return self._get_attr("primary", data_type="bool", def_value=False) + + @primary.setter + def primary(self, value: Optional[bool]): + self._set_attr("primary", value) + + # cache_extent + @property + def cache_extent(self) -> OptionalNumber: + return self._get_attr("cacheExtent", data_type="float") + + @cache_extent.setter + def cache_extent(self, value: OptionalNumber): + self._set_attr("cacheExtent", value) diff --git a/sdk/python/packages/flet/src/flet/core/theme.py b/sdk/python/packages/flet/src/flet/core/theme.py index 39a6f1f34..0c39ca1b7 100644 --- a/sdk/python/packages/flet/src/flet/core/theme.py +++ b/sdk/python/packages/flet/src/flet/core/theme.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field from enum import Enum -from typing import List, Optional, Union +from typing import List, Optional from flet.core.alignment import Alignment from flet.core.border import BorderSide diff --git a/sdk/python/packages/flet/src/flet/core/types.py b/sdk/python/packages/flet/src/flet/core/types.py index e4b18da6d..bb8b97cca 100644 --- a/sdk/python/packages/flet/src/flet/core/types.py +++ b/sdk/python/packages/flet/src/flet/core/types.py @@ -1,8 +1,7 @@ from dataclasses import dataclass from datetime import date, datetime -from enum import Enum, EnumMeta +from enum import Enum from typing import ( - TYPE_CHECKING, Any, Callable, Dict, @@ -13,7 +12,6 @@ TypeVar, Union, ) -from warnings import warn from flet.core.border_radius import BorderRadius from flet.core.colors import Colors, colors