├── .appveyor.yml ├── .gitattributes ├── .github ├── DISCUSSION_TEMPLATE │ └── q-a.yml ├── ISSUE_TEMPLATE │ ├── 01_bug_report.yml │ ├── 02_feature_request.yml │ └── config.yml └── pull_request_template.md ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ci ├── clean-pypi.sh ├── common.sh ├── download-web.py ├── generate_cupertino_icons_dart.sh ├── generate_cupertino_icons_python.sh ├── generate_material_icons_dart.sh ├── generate_material_icons_python.sh ├── install_flutter.sh ├── patch_pubspec.py ├── patch_toml_package_name.py ├── patch_toml_versions.py ├── repackage_wheel_with_tag.py ├── update-flet-wheel-deps.py └── whats-new.ps1 ├── client ├── .fvmrc ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── appveyor │ │ │ │ │ └── flet │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── icon │ │ ├── flet-android-192.png │ │ └── flet-ios-1024.png ├── build.cmd ├── integration_test │ └── app_test.dart ├── ios │ ├── .bundle │ │ └── config │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Gemfile │ ├── Gemfile.lock │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-50x50@1x.png │ │ │ │ ├── Icon-App-50x50@2x.png │ │ │ │ ├── Icon-App-57x57@1x.png │ │ │ │ ├── Icon-App-57x57@2x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-72x72@1x.png │ │ │ │ ├── Icon-App-72x72@2x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h │ └── fastlane │ │ ├── Appfile │ │ ├── Fastfile │ │ └── Matchfile ├── lib │ └── main.dart ├── linux │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ ├── main.cc │ ├── my_application.cc │ └── my_application.h ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ │ ├── Base.lproj │ │ └── MainMenu.xib │ │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ │ ├── DebugProfile.entitlements │ │ ├── Info.plist │ │ ├── MainFlutterWindow.swift │ │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── web │ ├── favicon.png │ ├── flutter_bootstrap.js │ ├── icons │ │ ├── apple-touch-icon-192.png │ │ ├── icon-192.png │ │ ├── icon-512.png │ │ ├── icon-maskable-192.png │ │ ├── icon-maskable-512.png │ │ └── loading-animation.png │ ├── index.html │ ├── manifest.json │ ├── python-worker.js │ └── python.js └── windows │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake │ └── runner │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── resources │ └── app_icon.ico │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── docs ├── flet.md └── roadmap.md ├── media ├── diagrams │ ├── chat-tutorial-layout.drawio │ ├── chat-tutorial-layout.svg │ ├── flet-highlevel-diagram-v2.drawio │ ├── flet-highlevel-diagram.drawio │ ├── flet-mobile-update.drawio │ └── page-views.drawio ├── flutter │ └── icon_flutter.svg ├── icons │ └── macos │ │ ├── flet-png │ │ ├── app_icon_1024.png │ │ ├── app_icon_128.png │ │ ├── app_icon_16.png │ │ ├── app_icon_256.png │ │ ├── app_icon_32.png │ │ ├── app_icon_512.png │ │ └── app_icon_64.png │ │ ├── flet-psd │ │ ├── flet-macos-icon-white-bg-1024.psd │ │ ├── flet-macos-icon-white-bg-128.psd │ │ ├── flet-macos-icon-white-bg-16.psd │ │ ├── flet-macos-icon-white-bg-256.psd │ │ ├── flet-macos-icon-white-bg-32.psd │ │ ├── flet-macos-icon-white-bg-512.psd │ │ └── flet-macos-icon-white-bg-64.psd │ │ └── templates │ │ ├── apple-original.7z │ │ ├── macos-icon-white-bg-1024.psd │ │ ├── macos-icon-white-bg-128.psd │ │ ├── macos-icon-white-bg-16.psd │ │ ├── macos-icon-white-bg-256.psd │ │ ├── macos-icon-white-bg-32.psd │ │ ├── macos-icon-white-bg-512.psd │ │ └── macos-icon-white-bg-64.psd ├── logo │ ├── Icon-192.png │ ├── Icon-512.png │ ├── app_icon_1024.png │ ├── app_icon_128.png │ ├── app_icon_16.png │ ├── app_icon_256.png │ ├── app_icon_32.png │ ├── app_icon_512.png │ ├── app_icon_64.png │ ├── favicon.png │ ├── flet-logo-256x256.png │ ├── flet-logo-512x512.png │ ├── flet-logo-no-text.svg │ ├── flet-logo-v2-512-white.png │ ├── flet-logo-v2-512.png │ ├── flet-logo-white-text.svg │ ├── flet-logo.cdr │ ├── flet-logo.png │ ├── flet-logo.svg │ └── logo-inkscape.svg ├── pictures │ └── plus-icon.svg └── website │ └── homepage-icons.cdr ├── packages └── flet │ ├── .gitignore │ ├── .metadata │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ ├── flet.dart │ └── src │ │ ├── actions.dart │ │ ├── control_factory.dart │ │ ├── controls │ │ ├── alert_dialog.dart │ │ ├── animated_switcher.dart │ │ ├── app_bar.dart │ │ ├── auto_complete.dart │ │ ├── autofill_group.dart │ │ ├── banner.dart │ │ ├── barchart.dart │ │ ├── bottom_app_bar.dart │ │ ├── bottom_sheet.dart │ │ ├── canvas.dart │ │ ├── card.dart │ │ ├── charts.dart │ │ ├── checkbox.dart │ │ ├── chip.dart │ │ ├── circle_avatar.dart │ │ ├── column.dart │ │ ├── container.dart │ │ ├── create_control.dart │ │ ├── cupertino_action_sheet.dart │ │ ├── cupertino_action_sheet_action.dart │ │ ├── cupertino_activity_indicator.dart │ │ ├── cupertino_alert_dialog.dart │ │ ├── cupertino_app_bar.dart │ │ ├── cupertino_bottom_sheet.dart │ │ ├── cupertino_button.dart │ │ ├── cupertino_checkbox.dart │ │ ├── cupertino_context_menu.dart │ │ ├── cupertino_context_menu_action.dart │ │ ├── cupertino_date_picker.dart │ │ ├── cupertino_dialog_action.dart │ │ ├── cupertino_list_tile.dart │ │ ├── cupertino_navigation_bar.dart │ │ ├── cupertino_picker.dart │ │ ├── cupertino_radio.dart │ │ ├── cupertino_segmented_button.dart │ │ ├── cupertino_slider.dart │ │ ├── cupertino_sliding_segmented_button.dart │ │ ├── cupertino_switch.dart │ │ ├── cupertino_textfield.dart │ │ ├── cupertino_timer_picker.dart │ │ ├── datatable.dart │ │ ├── date_picker.dart │ │ ├── dismissible.dart │ │ ├── divider.dart │ │ ├── drag_target.dart │ │ ├── draggable.dart │ │ ├── dropdown.dart │ │ ├── dropdownm2.dart │ │ ├── elevated_button.dart │ │ ├── error.dart │ │ ├── expansion_panel.dart │ │ ├── expansion_tile.dart │ │ ├── file_picker.dart │ │ ├── flet_app_control.dart │ │ ├── flet_store_mixin.dart │ │ ├── floating_action_button.dart │ │ ├── gesture_detector.dart │ │ ├── grid_view.dart │ │ ├── haptic_feedback.dart │ │ ├── highlight_view.dart │ │ ├── icon.dart │ │ ├── icon_button.dart │ │ ├── image.dart │ │ ├── interactive_viewer.dart │ │ ├── linechart.dart │ │ ├── list_tile.dart │ │ ├── list_view.dart │ │ ├── markdown.dart │ │ ├── menu_bar.dart │ │ ├── menu_item_button.dart │ │ ├── merge_semantics.dart │ │ ├── navigation_bar.dart │ │ ├── navigation_drawer.dart │ │ ├── navigation_rail.dart │ │ ├── outlined_button.dart │ │ ├── page.dart │ │ ├── pagelet.dart │ │ ├── piechart.dart │ │ ├── placeholder.dart │ │ ├── popup_menu_button.dart │ │ ├── progress_bar.dart │ │ ├── progress_ring.dart │ │ ├── radio.dart │ │ ├── radio_group.dart │ │ ├── range_slider.dart │ │ ├── reorderable_draggable.dart │ │ ├── reorderable_list_view.dart │ │ ├── responsive_row.dart │ │ ├── row.dart │ │ ├── safe_area.dart │ │ ├── scroll_notification_control.dart │ │ ├── scrollable_control.dart │ │ ├── search_anchor.dart │ │ ├── segmented_button.dart │ │ ├── selection_area.dart │ │ ├── semantics.dart │ │ ├── semantics_service.dart │ │ ├── shader_mask.dart │ │ ├── shake_detector.dart │ │ ├── slider.dart │ │ ├── snack_bar.dart │ │ ├── stack.dart │ │ ├── submenu_button.dart │ │ ├── switch.dart │ │ ├── tabs.dart │ │ ├── text.dart │ │ ├── text_button.dart │ │ ├── textfield.dart │ │ ├── time_picker.dart │ │ ├── transparent_pointer.dart │ │ └── vertical_divider.dart │ │ ├── flet_app.dart │ │ ├── flet_app_context.dart │ │ ├── flet_app_errors_handler.dart │ │ ├── flet_app_main.dart │ │ ├── flet_app_services.dart │ │ ├── flet_control_backend.dart │ │ ├── flet_server.dart │ │ ├── flet_server_protocol.dart │ │ ├── flet_server_protocol_javascript_io.dart │ │ ├── flet_server_protocol_javascript_web.dart │ │ ├── flet_server_protocol_tcp_socket.dart │ │ ├── flet_server_protocol_web_socket.dart │ │ ├── models │ │ ├── app_state.dart │ │ ├── asset_src.dart │ │ ├── control.dart │ │ ├── control_ancestor_view_model.dart │ │ ├── control_tree_view_model.dart │ │ ├── control_view_model.dart │ │ ├── controls_view_model.dart │ │ ├── page_args_model.dart │ │ ├── page_load_view_model.dart │ │ ├── page_media_view_model.dart │ │ ├── page_size_view_model.dart │ │ └── window_media_data.dart │ │ ├── protocol │ │ ├── add_page_controls_payload.dart │ │ ├── app_become_active_payload.dart │ │ ├── app_become_inactive_payload.dart │ │ ├── append_control_props_request.dart │ │ ├── clean_control_payload.dart │ │ ├── invoke_method_payload.dart │ │ ├── invoke_method_result.dart │ │ ├── message.dart │ │ ├── page_controls_batch_payload.dart │ │ ├── page_event_from_web_request.dart │ │ ├── page_media_data.dart │ │ ├── register_webclient_request.dart │ │ ├── register_webclient_response.dart │ │ ├── remove_control_payload.dart │ │ ├── replace_page_controls_payload.dart │ │ ├── session_crashed_payload.dart │ │ ├── session_payload.dart │ │ ├── update_control_props_payload.dart │ │ └── update_control_props_request.dart │ │ ├── reducers.dart │ │ ├── routing │ │ ├── route_parser.dart │ │ ├── route_state.dart │ │ └── router_delegate.dart │ │ ├── utils.dart │ │ ├── utils │ │ ├── alignment.dart │ │ ├── animations.dart │ │ ├── auto_complete.dart │ │ ├── autofill.dart │ │ ├── badge.dart │ │ ├── borders.dart │ │ ├── box.dart │ │ ├── browser_context_menu.dart │ │ ├── buttons.dart │ │ ├── charts.dart │ │ ├── client_storage.dart │ │ ├── clipboard.dart │ │ ├── collections.dart │ │ ├── colors.dart │ │ ├── cupertino_colors.dart │ │ ├── cupertino_icons.dart │ │ ├── dash_path.dart │ │ ├── debouncer.dart │ │ ├── desktop.dart │ │ ├── dismissible.dart │ │ ├── drawing.dart │ │ ├── edge_insets.dart │ │ ├── form_field.dart │ │ ├── gradient.dart │ │ ├── icons.dart │ │ ├── images.dart │ │ ├── images_io.dart │ │ ├── images_web.dart │ │ ├── launch_url.dart │ │ ├── locale.dart │ │ ├── markdown.dart │ │ ├── material_icons.dart │ │ ├── material_state.dart │ │ ├── menu.dart │ │ ├── mouse.dart │ │ ├── networking.dart │ │ ├── numbers.dart │ │ ├── others.dart │ │ ├── overlay_style.dart │ │ ├── platform.dart │ │ ├── platform_utils_non_web.dart │ │ ├── platform_utils_web.dart │ │ ├── responsive.dart │ │ ├── session_store_non_web.dart │ │ ├── session_store_web.dart │ │ ├── strings.dart │ │ ├── text.dart │ │ ├── textfield.dart │ │ ├── theme.dart │ │ ├── time.dart │ │ ├── tooltip.dart │ │ ├── transforms.dart │ │ ├── uri.dart │ │ ├── user_fonts.dart │ │ ├── user_fonts_io.dart │ │ └── user_fonts_web.dart │ │ └── widgets │ │ ├── animated_transition_page.dart │ │ ├── loading_page.dart │ │ ├── page_media.dart │ │ └── window_media.dart │ ├── pubspec.yaml │ └── test │ ├── controls │ └── control_test.dart │ ├── models │ └── linechart_event_data_test.dart │ ├── protocol │ ├── add_page_controls_payload_test.dart │ ├── app_become_inactive_payload_test.dart │ ├── append_control_props_payload_test.dart │ ├── clean_control_payload_test.dart │ ├── message_test.dart │ ├── page_controls_batch_payload_test.dart │ ├── page_event_from_web_request_test.dart │ ├── register_webclient_payload_test.dart │ ├── register_webclient_request_test.dart │ ├── register_webclient_response_test.dart │ ├── remove_control_payload_test.dart │ ├── replace_page_controls_payload_test.dart │ ├── session_crashed_payload_test.dart │ ├── session_payload_test.dart │ ├── update_control_props_payload_test.dart │ └── update_control_props_request_test.dart │ └── utils │ ├── networking_test.dart │ ├── theme_test.dart │ ├── uri_test.dart │ └── user_fonts_test.dart └── sdk └── python ├── .gitattributes ├── .gitignore ├── .pre-commit-config.yaml ├── README.md ├── packages ├── flet-cli │ ├── README.md │ ├── pyproject.toml │ └── src │ │ └── flet_cli │ │ ├── __pyinstaller │ │ ├── __init__.py │ │ ├── config.py │ │ ├── hook-flet.py │ │ ├── macos_utils.py │ │ ├── rthooks.dat │ │ ├── rthooks │ │ │ └── pyi_rth_localhost_fletd.py │ │ ├── utils.py │ │ └── win_utils.py │ │ ├── cli.py │ │ ├── commands │ │ ├── base.py │ │ ├── build.py │ │ ├── create.py │ │ ├── doctor.py │ │ ├── options.py │ │ ├── pack.py │ │ ├── publish.py │ │ └── run.py │ │ ├── utils │ │ ├── android_sdk.py │ │ ├── distros.py │ │ ├── flutter.py │ │ ├── hash_stamp.py │ │ ├── jdk.py │ │ ├── merge.py │ │ ├── processes.py │ │ ├── project_dependencies.py │ │ └── pyproject_toml.py │ │ └── version.py ├── flet-desktop │ ├── .gitignore │ ├── README.md │ ├── pyproject.toml │ └── src │ │ └── flet_desktop │ │ ├── __init__.py │ │ └── version.py ├── flet-web │ ├── .gitignore │ ├── README.md │ ├── pyproject.toml │ └── src │ │ └── flet_web │ │ ├── __init__.py │ │ ├── fastapi │ │ ├── README.md │ │ ├── __init__.py │ │ ├── app.py │ │ ├── flet_app.py │ │ ├── flet_app_manager.py │ │ ├── flet_fastapi.py │ │ ├── flet_oauth.py │ │ ├── flet_static_files.py │ │ ├── flet_upload.py │ │ ├── oauth_state.py │ │ └── serve_fastapi_web_app.py │ │ ├── patch_index.py │ │ ├── uploads.py │ │ └── version.py └── flet │ ├── README.md │ ├── poetry.lock │ ├── pyproject.toml │ ├── src │ └── flet │ │ ├── __init__.py │ │ ├── ads │ │ └── __init__.py │ │ ├── app.py │ │ ├── auth │ │ ├── __init__.py │ │ ├── authorization.py │ │ ├── group.py │ │ ├── oauth_provider.py │ │ ├── oauth_token.py │ │ ├── providers │ │ │ ├── __init__.py │ │ │ ├── auth0_oauth_provider.py │ │ │ ├── azure_oauth_provider.py │ │ │ ├── github_oauth_provider.py │ │ │ └── google_oauth_provider.py │ │ └── user.py │ │ ├── canvas │ │ └── __init__.py │ │ ├── cli.py │ │ ├── core │ │ ├── adaptive_control.py │ │ ├── ads │ │ │ ├── banner.py │ │ │ ├── base_ad.py │ │ │ ├── interstitial.py │ │ │ └── native.py │ │ ├── alert_dialog.py │ │ ├── alignment.py │ │ ├── animated_switcher.py │ │ ├── animation.py │ │ ├── app_bar.py │ │ ├── audio.py │ │ ├── audio_recorder.py │ │ ├── auto_complete.py │ │ ├── autofill_group.py │ │ ├── badge.py │ │ ├── banner.py │ │ ├── blur.py │ │ ├── border.py │ │ ├── border_radius.py │ │ ├── bottom_app_bar.py │ │ ├── bottom_sheet.py │ │ ├── box.py │ │ ├── button.py │ │ ├── buttons.py │ │ ├── canvas │ │ │ ├── arc.py │ │ │ ├── canvas.py │ │ │ ├── circle.py │ │ │ ├── color.py │ │ │ ├── fill.py │ │ │ ├── line.py │ │ │ ├── oval.py │ │ │ ├── path.py │ │ │ ├── points.py │ │ │ ├── rect.py │ │ │ ├── shadow.py │ │ │ ├── shape.py │ │ │ └── text.py │ │ ├── card.py │ │ ├── charts │ │ │ ├── bar_chart.py │ │ │ ├── bar_chart_group.py │ │ │ ├── bar_chart_rod.py │ │ │ ├── bar_chart_rod_stack_item.py │ │ │ ├── chart_axis.py │ │ │ ├── chart_axis_label.py │ │ │ ├── chart_grid_lines.py │ │ │ ├── chart_point_line.py │ │ │ ├── chart_point_shape.py │ │ │ ├── line_chart.py │ │ │ ├── line_chart_data.py │ │ │ ├── line_chart_data_point.py │ │ │ ├── pie_chart.py │ │ │ └── pie_chart_section.py │ │ ├── checkbox.py │ │ ├── chip.py │ │ ├── circle_avatar.py │ │ ├── client_storage.py │ │ ├── colors.py │ │ ├── column.py │ │ ├── connection.py │ │ ├── constrained_control.py │ │ ├── container.py │ │ ├── control.py │ │ ├── control_event.py │ │ ├── cupertino_action_sheet.py │ │ ├── cupertino_action_sheet_action.py │ │ ├── cupertino_activity_indicator.py │ │ ├── cupertino_alert_dialog.py │ │ ├── cupertino_app_bar.py │ │ ├── cupertino_bottom_sheet.py │ │ ├── cupertino_button.py │ │ ├── cupertino_checkbox.py │ │ ├── cupertino_colors.py │ │ ├── cupertino_context_menu.py │ │ ├── cupertino_context_menu_action.py │ │ ├── cupertino_date_picker.py │ │ ├── cupertino_dialog_action.py │ │ ├── cupertino_filled_button.py │ │ ├── cupertino_icons.py │ │ ├── cupertino_list_tile.py │ │ ├── cupertino_navigation_bar.py │ │ ├── cupertino_picker.py │ │ ├── cupertino_radio.py │ │ ├── cupertino_segmented_button.py │ │ ├── cupertino_slider.py │ │ ├── cupertino_sliding_segmented_button.py │ │ ├── cupertino_switch.py │ │ ├── cupertino_textfield.py │ │ ├── cupertino_timer_picker.py │ │ ├── datatable.py │ │ ├── date_picker.py │ │ ├── dismissible.py │ │ ├── divider.py │ │ ├── drag_target.py │ │ ├── draggable.py │ │ ├── dropdown.py │ │ ├── dropdownm2.py │ │ ├── elevated_button.py │ │ ├── embed_json_encoder.py │ │ ├── event.py │ │ ├── event_handler.py │ │ ├── exceptions.py │ │ ├── expansion_panel.py │ │ ├── expansion_tile.py │ │ ├── file_picker.py │ │ ├── filled_button.py │ │ ├── filled_tonal_button.py │ │ ├── flashlight.py │ │ ├── flet_app.py │ │ ├── floating_action_button.py │ │ ├── form_field_control.py │ │ ├── geolocator.py │ │ ├── gesture_detector.py │ │ ├── gradients.py │ │ ├── grid_view.py │ │ ├── haptic_feedback.py │ │ ├── icon.py │ │ ├── icon_button.py │ │ ├── icons.py │ │ ├── image.py │ │ ├── inline_span.py │ │ ├── interactive_viewer.py │ │ ├── list_tile.py │ │ ├── list_view.py │ │ ├── local_connection.py │ │ ├── locks.py │ │ ├── lottie.py │ │ ├── map │ │ │ ├── circle_layer.py │ │ │ ├── map.py │ │ │ ├── map_layer.py │ │ │ ├── marker_layer.py │ │ │ ├── polygon_layer.py │ │ │ ├── polyline_layer.py │ │ │ ├── rich_attribution.py │ │ │ ├── simple_attribution.py │ │ │ ├── text_source_attribution.py │ │ │ └── tile_layer.py │ │ ├── margin.py │ │ ├── markdown.py │ │ ├── matplotlib_chart.py │ │ ├── menu_bar.py │ │ ├── menu_item_button.py │ │ ├── merge_semantics.py │ │ ├── navigation_bar.py │ │ ├── navigation_drawer.py │ │ ├── navigation_rail.py │ │ ├── outlined_button.py │ │ ├── padding.py │ │ ├── page.py │ │ ├── pagelet.py │ │ ├── painting.py │ │ ├── permission_handler.py │ │ ├── placeholder.py │ │ ├── plotly_chart.py │ │ ├── popup_menu_button.py │ │ ├── progress_bar.py │ │ ├── progress_ring.py │ │ ├── protocol.py │ │ ├── pubsub │ │ │ ├── pubsub_client.py │ │ │ └── pubsub_hub.py │ │ ├── querystring.py │ │ ├── radio.py │ │ ├── radio_group.py │ │ ├── range_slider.py │ │ ├── ref.py │ │ ├── reorderable_draggable.py │ │ ├── reorderable_list_view.py │ │ ├── responsive_row.py │ │ ├── rive.py │ │ ├── row.py │ │ ├── safe_area.py │ │ ├── scrollable_control.py │ │ ├── search_bar.py │ │ ├── segmented_button.py │ │ ├── selection_area.py │ │ ├── semantics.py │ │ ├── semantics_service.py │ │ ├── session_storage.py │ │ ├── shader_mask.py │ │ ├── shake_detector.py │ │ ├── size.py │ │ ├── slider.py │ │ ├── snack_bar.py │ │ ├── stack.py │ │ ├── submenu_button.py │ │ ├── switch.py │ │ ├── tabs.py │ │ ├── template_route.py │ │ ├── text.py │ │ ├── text_button.py │ │ ├── text_span.py │ │ ├── text_style.py │ │ ├── textfield.py │ │ ├── theme.py │ │ ├── time_picker.py │ │ ├── tooltip.py │ │ ├── transform.py │ │ ├── transparent_pointer.py │ │ ├── types.py │ │ ├── vertical_divider.py │ │ ├── video.py │ │ ├── view.py │ │ ├── webview.py │ │ └── window_drag_area.py │ │ ├── fastapi │ │ └── __init__.py │ │ ├── flet_socket_server.py │ │ ├── map │ │ └── __init__.py │ │ ├── matplotlib_chart.py │ │ ├── plotly_chart.py │ │ ├── pyodide_connection.py │ │ ├── security │ │ └── __init__.py │ │ ├── utils │ │ ├── __init__.py │ │ ├── browser.py │ │ ├── classproperty.py │ │ ├── deprecated.py │ │ ├── files.py │ │ ├── hashing.py │ │ ├── network.py │ │ ├── once.py │ │ ├── pip.py │ │ ├── platform_utils.py │ │ ├── slugify.py │ │ ├── strings.py │ │ └── vector.py │ │ └── version.py │ └── tests │ ├── __init__.py │ ├── test_alert_dialog.py │ ├── test_animated_switcher.py │ ├── test_checkbox.py │ ├── test_colors.py │ ├── test_column.py │ ├── test_container.py │ ├── test_datatable.py │ ├── test_dropdown.py │ ├── test_file_picker.py │ ├── test_icons.py │ ├── test_image.py │ ├── test_markdown.py │ ├── test_moving_children.py │ ├── test_navigation_bar.py │ ├── test_navigation_rail.py │ ├── test_page.py │ ├── test_radio.py │ ├── test_responsive_row.py │ ├── test_row.py │ ├── test_shader_mask.py │ ├── test_stack.py │ ├── test_switch.py │ ├── test_text.py │ ├── test_textfield.py │ └── test_view.py ├── poetry.lock └── pyproject.toml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/q-a.yml: -------------------------------------------------------------------------------- 1 | title: "[Question]" 2 | labels: ["help wanted"] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | This is the place to ask for specifics about Flet or for help with problems you encountered while using it. 8 | - type: textarea 9 | id: question 10 | attributes: 11 | label: Question 12 | description: Please formulate your question as precisely as possible. 13 | validations: 14 | required: true 15 | - type: textarea 16 | id: code 17 | attributes: 18 | label: Code sample 19 | description: | 20 | If applicable, paste in a code sample of your best attempt so far. It will automatically be rendered as python code. 21 | render: python 22 | - type: textarea 23 | id: error 24 | attributes: 25 | label: Error message 26 | description: If applicable, paste in the full error message you received. 27 | render: bash 28 | - type: checkboxes 29 | id: similar-search 30 | attributes: 31 | label: ------------------------------------------------------ 32 | options: 33 | - label: I have searched for answers to my question both in the issues and in previous discussions. 34 | required: true 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Flet Discord server 4 | url: https://discord.gg/dzWXP8SHG8 5 | about: Join our Discord server to chat with the community and the dev-team, with faster response times. 6 | - name: Flet Discussions 7 | url: https://github.com/flet-dev/flet/discussions 8 | about: Open a discussion to ask questions, share ideas, and connect with other community members. 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | 6 | 7 | ## Test Code 8 | 9 | ```python 10 | # Test code for the review of this PR 11 | ``` 12 | 13 | ## Type of change 14 | 15 | 16 | 17 | - [ ] Bug fix (non-breaking change which fixes an issue) 18 | - [ ] New feature (non-breaking change which adds functionality) 19 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 20 | - [ ] This change requires a documentation update 21 | 22 | ## Checklist 23 | 24 | - [ ] I signed the CLA. 25 | - [ ] My code follows the style guidelines of this project 26 | - [ ] I have performed a self-review of my own code 27 | - [ ] I have commented my code, particularly in hard-to-understand areas 28 | - [ ] My changes generate no new warnings 29 | - [ ] New and existing tests pass locally with my changes 30 | - [ ] I have made corresponding changes to the [documentation](https://github.com/flet-dev/website) (if applicable) 31 | 32 | ## Screenshots 33 | 34 | 35 | 36 | ## Additional details 37 | 38 | 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | 18 | # VS Code 19 | .vscode/ 20 | 21 | # Pycharm Files 22 | .idea/ 23 | 24 | # mac specific 25 | .DS_Store 26 | *.bkp 27 | .python-version 28 | vendor/ 29 | /client/android/app/.cxx 30 | -------------------------------------------------------------------------------- /ci/clean-pypi.sh: -------------------------------------------------------------------------------- 1 | # set PYPI_CLEANUP_PASSWORD with pypi.org password 2 | VER="0\.28\.0\.dev" 3 | #VER="0\.21\.1" 4 | pypi-cleanup -u flet -p flet -y -r $VER --do-it 5 | pypi-cleanup -u flet -p flet-cli -y -r $VER --do-it 6 | pypi-cleanup -u flet -p flet-desktop -y -r $VER --do-it 7 | pypi-cleanup -u flet -p flet-web -y -r $VER --do-it -------------------------------------------------------------------------------- /ci/generate_cupertino_icons_dart.sh: -------------------------------------------------------------------------------- 1 | url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/cupertino/icons.dart' 2 | output_file="cupertino_icons.txt" 3 | 4 | echo "Map cupertinoIcons = {" > "$output_file" 5 | 6 | curl -s $url | python -c ' 7 | import re 8 | 9 | for line in __import__("sys").stdin: 10 | match = re.search(r"const IconData ([a-z0-9_]+)", line) 11 | if match: 12 | print("\"cupertino_{}\": CupertinoIcons.{}, ".format(match.group(1), match.group(1))) 13 | ' >> "$output_file" 14 | 15 | echo "};" >> "$output_file" -------------------------------------------------------------------------------- /ci/generate_cupertino_icons_python.sh: -------------------------------------------------------------------------------- 1 | url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/cupertino/icons.dart' 2 | output_file="cupertino_icons_python.txt" 3 | 4 | curl -s $url | python -c ' 5 | import re 6 | 7 | for line in __import__("sys").stdin: 8 | match = re.search(r"const IconData ([a-z0-9_]+)", line) 9 | if match: 10 | print("{} = \"cupertino_{}\"".format(match.group(1).upper(), match.group(1))) 11 | ' >> "$output_file" -------------------------------------------------------------------------------- /ci/generate_material_icons_dart.sh: -------------------------------------------------------------------------------- 1 | url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/material/icons.dart' 2 | output_file="material-icons.txt" 3 | 4 | echo "Map materialIcons = {" > "$output_file" 5 | 6 | curl -s $url | python -c ' 7 | import re 8 | 9 | for line in __import__("sys").stdin: 10 | match = re.search(r"const IconData ([a-z0-9_]+)", line) 11 | if match: 12 | print("\"{}\": Icons.{}, ".format(match.group(1), match.group(1))) 13 | ' >> "$output_file" 14 | 15 | echo "};" >> "$output_file" -------------------------------------------------------------------------------- /ci/generate_material_icons_python.sh: -------------------------------------------------------------------------------- 1 | url='https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/src/material/icons.dart' 2 | output_file="material_icons_python.txt" 3 | 4 | curl -s $url | python -c ' 5 | import re 6 | 7 | for line in __import__("sys").stdin: 8 | match = re.search(r"const IconData ([a-z0-9_]+)", line) 9 | if match: 10 | print("{} = \"{}\"".format(match.group(1).upper(), match.group(1))) 11 | ' >> "$output_file" -------------------------------------------------------------------------------- /ci/install_flutter.sh: -------------------------------------------------------------------------------- 1 | dart pub global activate fvm 2 | export PATH=$HOME/.pub-cache/bin:$HOME/fvm/default/bin:$PATH 3 | fvm install $FLUTTER_VERSION 4 | fvm global $FLUTTER_VERSION 5 | flutter --version -------------------------------------------------------------------------------- /ci/patch_pubspec.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | import sys 4 | 5 | import yaml 6 | 7 | if len(sys.argv) < 3: 8 | print("Specify pubspec.yaml file and version to patch") 9 | sys.exit(1) 10 | 11 | current_dir = pathlib.Path(os.getcwd()) 12 | pubspec_path = current_dir.joinpath(current_dir, sys.argv[1]) 13 | ver = sys.argv[2] 14 | print(f"Patching pubspec.yaml file {pubspec_path} with {ver}") 15 | 16 | dependencies = [ 17 | "flet", 18 | ] 19 | 20 | with open(pubspec_path, "r") as f: 21 | data = yaml.safe_load(f) 22 | 23 | # patch version 24 | data["version"] = ver 25 | 26 | # patch dependencies 27 | for dep in data["dependencies"]: 28 | if dep in dependencies: 29 | data["dependencies"][dep] = f"^{ver}" 30 | # print(dep) 31 | with open(pubspec_path, "w") as file: 32 | yaml.dump(data, file, sort_keys=False) 33 | -------------------------------------------------------------------------------- /ci/patch_toml_package_name.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | import sys 4 | 5 | import tomlkit 6 | 7 | if len(sys.argv) < 2: 8 | print("Specify toml file and a new package name") 9 | sys.exit(1) 10 | 11 | current_dir = pathlib.Path(os.getcwd()) 12 | toml_path = current_dir.joinpath(current_dir, sys.argv[1]) 13 | package_name = sys.argv[2] 14 | print(f"Patching TOML file {toml_path} to {package_name}") 15 | 16 | # read 17 | with open(toml_path, "r") as f: 18 | t = tomlkit.parse(f.read()) 19 | 20 | # patch name 21 | t["project"]["name"] = package_name 22 | 23 | # save 24 | with open(toml_path, "w") as f: 25 | f.write(tomlkit.dumps(t)) 26 | -------------------------------------------------------------------------------- /ci/patch_toml_versions.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | import sys 4 | 5 | import tomlkit 6 | 7 | if len(sys.argv) < 3: 8 | print("Specify toml file and version to patch") 9 | sys.exit(1) 10 | 11 | current_dir = pathlib.Path(os.getcwd()) 12 | toml_path = current_dir.joinpath(current_dir, sys.argv[1]) 13 | ver = sys.argv[2] 14 | print(f"Patching TOML file {toml_path} to {ver}") 15 | 16 | # read 17 | with open(toml_path, "r") as f: 18 | t = tomlkit.parse(f.read()) 19 | 20 | # patch version 21 | t["project"]["version"] = ver 22 | 23 | # patch dependencies 24 | deps = t["tool"]["poetry"]["dependencies"] 25 | 26 | 27 | def patch_dep(dep_name): 28 | if deps.get(dep_name): 29 | if isinstance(deps[dep_name], dict): 30 | deps[dep_name]["version"] = ver 31 | else: 32 | deps[dep_name] = ver 33 | 34 | 35 | patch_dep("flet-cli") 36 | patch_dep("flet-desktop") 37 | patch_dep("flet-web") 38 | patch_dep("flet") 39 | 40 | # save 41 | with open(toml_path, "w") as f: 42 | f.write(tomlkit.dumps(t)) 43 | -------------------------------------------------------------------------------- /ci/whats-new.ps1: -------------------------------------------------------------------------------- 1 | $milestone = 17 2 | 3 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 4 | 5 | # Fetch issues from GitHub 6 | $issues = Invoke-RestMethod "https://api.github.com/repos/flet-dev/flet/issues?state=all&per_page=100&milestone=$($milestone)&sort=created&direction=asc" 7 | 8 | # Prepare an array with sorting 9 | $sortedIssues = $issues | ForEach-Object { 10 | $isBug = 0 11 | foreach ($label in $_.labels) { 12 | if ($label.name -eq 'bug') { 13 | $isBug = 1 14 | } 15 | } 16 | [PSCustomObject]@{ 17 | Issue = $_ 18 | IsBug = $isBug # Sorting key: 0 for non-bug, 1 for bug 19 | } 20 | } | Sort-Object IsBug # Sort: Non-bug first, bug last 21 | 22 | # Output sorted issues 23 | foreach ($item in $sortedIssues) { 24 | $issue = $item.Issue 25 | $prefix = "" 26 | 27 | foreach ($label in $issue.labels) { 28 | if ($label.name -eq 'bug') { 29 | $prefix = "Fixed: " 30 | } 31 | } 32 | 33 | $title = $issue.title.replace('fix: ', '') 34 | 35 | "* $prefix$($title) ([#$($issue.number)]($($issue.html_url)))" 36 | } -------------------------------------------------------------------------------- /client/.fvmrc: -------------------------------------------------------------------------------- 1 | { 2 | "flutter": "3.29.0" 3 | } -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | 47 | # Ruby 48 | vendor/ 49 | 50 | # FVM Version Cache 51 | .fvm/ -------------------------------------------------------------------------------- /client/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 17 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 18 | - platform: linux 19 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 20 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # flet_view 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | 18 | ## TODO 19 | 20 | * Close connection on application exit: 21 | * https://docs.flutter.dev/cookbook/networking/web-sockets 22 | * https://stackoverflow.com/questions/52074265/flutter-detect-killing-off-the-app 23 | * https://stackoverflow.com/questions/60184497/how-to-execute-code-before-app-exit-flutter 24 | * Change `base.href` for non-root apps: 25 | * https://docs.flutter.dev/development/ui/navigation/url-strategies#hosting-a-flutter-app-at-a-non-root-location -------------------------------------------------------------------------------- /client/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /client/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/android/app/src/main/kotlin/com/appveyor/flet/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.appveyor.flet 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /client/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /client/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /client/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /client/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /client/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.9.24' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | } 19 | 20 | rootProject.buildDir = '../build' 21 | subprojects { 22 | project.buildDir = "${rootProject.buildDir}/${project.name}" 23 | } 24 | subprojects { 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | tasks.register("clean", Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /client/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /client/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 7 | -------------------------------------------------------------------------------- /client/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false 21 | } 22 | } 23 | 24 | plugins { 25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 26 | id "com.android.application" version "8.3.1" apply false 27 | } 28 | 29 | include ":app" 30 | -------------------------------------------------------------------------------- /client/assets/icon/flet-android-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/assets/icon/flet-android-192.png -------------------------------------------------------------------------------- /client/assets/icon/flet-ios-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/assets/icon/flet-ios-1024.png -------------------------------------------------------------------------------- /client/build.cmd: -------------------------------------------------------------------------------- 1 | flutter build web --web-renderer auto -------------------------------------------------------------------------------- /client/integration_test/app_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flet_client/main.dart' as app; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter_test/flutter_test.dart'; 6 | import 'package:integration_test/integration_test.dart'; 7 | 8 | void main() { 9 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 10 | 11 | tearDown(() { 12 | debugPrint("TEAR DOWN"); 13 | }); 14 | 15 | group('end-to-end test', () { 16 | testWidgets('tap on the floating action button, verify counter', 17 | (tester) async { 18 | var dir = Directory.current.path; 19 | debugPrint("Current dir: $dir"); 20 | app.main(); 21 | await tester.pumpAndSettle(const Duration(milliseconds: 100), 22 | EnginePhase.sendSemanticsUpdate, const Duration(seconds: 20)); 23 | 24 | // Verify the counter starts at 0. 25 | expect(find.text('0'), findsOneWidget); 26 | 27 | // Finds the floating action button to tap on. 28 | final Finder fab = find.byTooltip('Increment'); 29 | 30 | // Emulate a tap on the floating action button. 31 | await tester.tap(fab); 32 | 33 | // Trigger a frame. 34 | await tester.pumpAndSettle(); 35 | 36 | // Verify the counter increments by 1. 37 | expect(find.text('1'), findsOneWidget); 38 | }); 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /client/ios/.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: "vendor/bundle" 3 | -------------------------------------------------------------------------------- /client/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | 36 | fastlane/README.md 37 | fastlane/report.xml -------------------------------------------------------------------------------- /client/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /client/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /client/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /client/ios/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "cocoapods" 4 | gem "fastlane" -------------------------------------------------------------------------------- /client/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /client/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /client/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /client/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /client/ios/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("com.appveyor.flet") # The bundle identifier of your app 2 | # apple_id("[[APPLE_ID]]") # Your Apple email address 3 | 4 | 5 | # For more information about the Appfile, see: 6 | # https://docs.fastlane.tools/advanced/#appfile 7 | -------------------------------------------------------------------------------- /client/ios/fastlane/Matchfile: -------------------------------------------------------------------------------- 1 | git_url("https://github.com/flet-dev/fastlane-match") 2 | 3 | storage_mode("git") 4 | 5 | type("development") # The default type, can be: appstore, adhoc, enterprise or development 6 | 7 | # app_identifier(["tools.fastlane.app", "tools.fastlane.app2"]) 8 | # username("user@fastlane.tools") # Your Apple Developer Portal username 9 | 10 | # For all available options run `fastlane match --help` 11 | # Remove the # in the beginning of the line to enable the other options 12 | 13 | # The docs are available on https://docs.fastlane.tools/actions/match 14 | -------------------------------------------------------------------------------- /client/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /client/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /client/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | audioplayers_linux 7 | media_kit_libs_linux 8 | media_kit_video 9 | record_linux 10 | rive_common 11 | screen_retriever_linux 12 | url_launcher_linux 13 | window_manager 14 | window_to_front 15 | ) 16 | 17 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 18 | media_kit_native_event_loop 19 | ) 20 | 21 | set(PLUGIN_BUNDLED_LIBRARIES) 22 | 23 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 25 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 27 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 28 | endforeach(plugin) 29 | 30 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 31 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 32 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 33 | endforeach(ffi_plugin) 34 | -------------------------------------------------------------------------------- /client/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /client/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /client/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | Podfile.lock 5 | 6 | # Xcode-related 7 | **/dgph 8 | **/xcuserdata/ 9 | -------------------------------------------------------------------------------- /client/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /client/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /client/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /client/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /client/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = Flet 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.appveyor.flet 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 Appveyor Systems Inc. All rights reserved. Licensed under the Apache License, Version 2.0 15 | -------------------------------------------------------------------------------- /client/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /client/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /client/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /client/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | com.apple.security.device.audio-input 14 | 15 | com.apple.security.personal-information.location 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /client/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | flutterViewController.backgroundColor = .clear 8 | let windowFrame = self.frame 9 | self.contentViewController = flutterViewController 10 | self.setFrame(windowFrame, display: true) 11 | 12 | RegisterGeneratedPlugins(registry: flutterViewController) 13 | 14 | super.awakeFromNib() 15 | } 16 | 17 | override public func order(_ place: NSWindow.OrderingMode, relativeTo otherWin: Int) { 18 | super.order(place, relativeTo: otherWin) 19 | hiddenWindowAtLaunch() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | com.apple.security.device.audio-input 10 | 11 | com.apple.security.personal-information.location 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/favicon.png -------------------------------------------------------------------------------- /client/web/flutter_bootstrap.js: -------------------------------------------------------------------------------- 1 | {{flutter_js}} 2 | {{flutter_build_config}} 3 | 4 | var loading = document.querySelector('#loading'); 5 | _flutter.loader.load({ 6 | config: { 7 | renderer: webRenderer 8 | }, 9 | serviceWorkerSettings: { 10 | serviceWorkerVersion: {{flutter_service_worker_version}}, 11 | }, 12 | onEntrypointLoaded: async function (engineInitializer) { 13 | loading.classList.add('main_done'); 14 | const appRunner = await engineInitializer.initializeEngine({useColorEmoji: useColorEmoji}); 15 | 16 | loading.classList.add('init_done'); 17 | await appRunner.runApp(); 18 | 19 | window.setTimeout(function () { 20 | loading.remove(); 21 | }, 200); 22 | } 23 | }); -------------------------------------------------------------------------------- /client/web/icons/apple-touch-icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/icons/apple-touch-icon-192.png -------------------------------------------------------------------------------- /client/web/icons/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/icons/icon-192.png -------------------------------------------------------------------------------- /client/web/icons/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/icons/icon-512.png -------------------------------------------------------------------------------- /client/web/icons/icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/icons/icon-maskable-192.png -------------------------------------------------------------------------------- /client/web/icons/icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/icons/icon-maskable-512.png -------------------------------------------------------------------------------- /client/web/icons/loading-animation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/web/icons/loading-animation.png -------------------------------------------------------------------------------- /client/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Flet", 3 | "short_name": "Flet", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#FFFFFF", 7 | "theme_color": "#0175C2", 8 | "description": "Flet - the fastest way to build Flutter apps in Python", 9 | "orientation": "natural", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /client/web/python.js: -------------------------------------------------------------------------------- 1 | const pythonWorker = new Worker("python-worker.js"); 2 | 3 | let _onPythonInitialized = null; 4 | let pythonInitialized = new Promise((onSuccess) => _onPythonInitialized = onSuccess); 5 | let _onReceivedCallback = null; 6 | 7 | pythonWorker.onmessage = (event) => { 8 | if (event.data == "initialized") { 9 | _onPythonInitialized(); 10 | } else { 11 | _onReceivedCallback(event.data); 12 | } 13 | }; 14 | 15 | documentUrl = document.URL; 16 | 17 | // initialize worker 18 | pythonWorker.postMessage({ documentUrl, micropipIncludePre, pythonModuleName }); 19 | 20 | async function jsConnect(receiveCallback) { 21 | _onReceivedCallback = receiveCallback; 22 | await pythonInitialized; 23 | console.log("Python engine initialized!"); 24 | } 25 | 26 | async function jsSend(data) { 27 | pythonWorker.postMessage(data); 28 | } -------------------------------------------------------------------------------- /client/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /client/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /client/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | audioplayers_windows 7 | geolocator_windows 8 | media_kit_libs_windows_video 9 | media_kit_video 10 | permission_handler_windows 11 | record_windows 12 | rive_common 13 | screen_brightness_windows 14 | screen_retriever_windows 15 | url_launcher_windows 16 | window_manager 17 | window_to_front 18 | ) 19 | 20 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 21 | media_kit_native_event_loop 22 | ) 23 | 24 | set(PLUGIN_BUNDLED_LIBRARIES) 25 | 26 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 27 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 28 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 29 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 31 | endforeach(plugin) 32 | 33 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 34 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 35 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 36 | endforeach(ffi_plugin) 37 | -------------------------------------------------------------------------------- /client/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /client/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /client/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/client/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /client/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /client/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /media/diagrams/page-views.drawio: -------------------------------------------------------------------------------- 1 | 7Zhdb5swFIZ/DZeNwIZALpukaaVparVO23rpggPeDEbGaUh//exgEz7SJUuTJtJWVa05NsfmOe+xD1hwkpa3HOXJZxZhagE7Ki04tQBwXAAs9WtHq8oSOF5liDmJ9KCN4ZG8Ym20tXVBIly0BgrGqCB52xiyLMOhaNkQ52zZHjZntD1rjmLcMzyGiPat30kkEm11bHvTcYdJnOipA093pMgM1oYiQRFbNkzwxoITzpioWmk5wVTBM1yq+2Zv9NYL4zgT+9wwo+OfIxim03sRPK2mn67ur1+vtJcXRBf6gR8UkGrBYmUocLbIIqwc2RYcLxMi8GOOQtW7lHGXtkSkVF45sjlnmdCBlMGG4/5CzayYC1w2THrht5ilWPCVHGJ6hxqiVhEw+JeNmBjQSSMc9UCkdRDXvjeoZEPT+gty4ATkjkDKDdqkHP/spOBlkvLsDqmRf25Sbo/UN4KXF5eNHuhkI3DPTc4cFw1078RGKJ0wyvj6Xjifz0EYnhufeyJ63m54DTT1QaYwRqhIaqaIkjiT7VDCwZLcWEEh8jC91h0piSLlUfnIlee0jFXdMKiOalD9V24VG3vgu6qtuPkDF6iwUJLf6XVkTISJnvkoYQnaYYFOPyxuPyrOyTTdP2IuV9MHb6an0rT/X9MqLB1N21u2mg/VdL8YuFhNH15KnUrTTr9A6NHDWXRdCW4aUlQUJNyzcsJR602oj6Xx2N6WpzY2jikS5KX9/rQNhZ7hgRG5kpo6GLWpw27NULAFD7G+q/m+03Hk+jscCcRjLHqO1pGpH/sdweqfql9Zrgzrms4mhXotJkVO0UqqvRtHKVLRjlwhOPuFjdgzluGO/rVp/x1rW261s69ZPR5pTxp20gr6W44Ke2v1eKq02uOsaKSVxtyKDOLCdDPpxthmhJox0oEGCU1v4/pNrpXa/7B4vSVUYt5DjheS5l0VuIemuQ87cvI+OM2Dnni+qG86Js+HVKXxM5etWLVClGXr7mesIs7yfyr3h3scqc6H5v7o7LmPSyJ+mJGy/bQuEz19NS11ONYXq1214c79wlRguzeM4LI2DK+b56MBsBs/3oH7hzMcOCPb9Yf6b3uWwD/SbiIvN996q+GbL+bw5jc= -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_1024.png -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_128.png -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_16.png -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_256.png -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_32.png -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_512.png -------------------------------------------------------------------------------- /media/icons/macos/flet-png/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-png/app_icon_64.png -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-1024.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-1024.psd -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-128.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-128.psd -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-16.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-16.psd -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-256.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-256.psd -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-32.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-32.psd -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-512.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-512.psd -------------------------------------------------------------------------------- /media/icons/macos/flet-psd/flet-macos-icon-white-bg-64.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/flet-psd/flet-macos-icon-white-bg-64.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/apple-original.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/apple-original.7z -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-1024.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-1024.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-128.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-128.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-16.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-16.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-256.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-256.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-32.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-32.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-512.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-512.psd -------------------------------------------------------------------------------- /media/icons/macos/templates/macos-icon-white-bg-64.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/icons/macos/templates/macos-icon-white-bg-64.psd -------------------------------------------------------------------------------- /media/logo/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/Icon-192.png -------------------------------------------------------------------------------- /media/logo/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/Icon-512.png -------------------------------------------------------------------------------- /media/logo/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_1024.png -------------------------------------------------------------------------------- /media/logo/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_128.png -------------------------------------------------------------------------------- /media/logo/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_16.png -------------------------------------------------------------------------------- /media/logo/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_256.png -------------------------------------------------------------------------------- /media/logo/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_32.png -------------------------------------------------------------------------------- /media/logo/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_512.png -------------------------------------------------------------------------------- /media/logo/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/app_icon_64.png -------------------------------------------------------------------------------- /media/logo/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/favicon.png -------------------------------------------------------------------------------- /media/logo/flet-logo-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/flet-logo-256x256.png -------------------------------------------------------------------------------- /media/logo/flet-logo-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/flet-logo-512x512.png -------------------------------------------------------------------------------- /media/logo/flet-logo-no-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /media/logo/flet-logo-v2-512-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/flet-logo-v2-512-white.png -------------------------------------------------------------------------------- /media/logo/flet-logo-v2-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/flet-logo-v2-512.png -------------------------------------------------------------------------------- /media/logo/flet-logo.cdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/flet-logo.cdr -------------------------------------------------------------------------------- /media/logo/flet-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/logo/flet-logo.png -------------------------------------------------------------------------------- /media/website/homepage-icons.cdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/media/website/homepage-icons.cdr -------------------------------------------------------------------------------- /packages/flet/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | .flutter-plugins 32 | .flutter-plugins-dependencies 33 | -------------------------------------------------------------------------------- /packages/flet/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 8c1149878bbb8f062aecfab4d825e5b87bdb4487 8 | channel: beta 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /packages/flet/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /packages/flet/lib/src/control_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | import 'flet_control_backend.dart'; 4 | import 'models/control.dart'; 5 | 6 | class CreateControlArgs { 7 | final Key? key; 8 | final Control? parent; 9 | final Control control; 10 | final List children; 11 | final Widget? nextChild; 12 | final bool parentDisabled; 13 | final bool? parentAdaptive; 14 | final FletControlBackend backend; 15 | 16 | CreateControlArgs(this.key, this.parent, this.control, this.children, 17 | this.nextChild, this.parentDisabled, this.parentAdaptive, this.backend); 18 | } 19 | 20 | typedef CreateControlFactory = Widget? Function(CreateControlArgs args); 21 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/autofill_group.dart: -------------------------------------------------------------------------------- 1 | import 'package:flet/src/utils/autofill.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../models/control.dart'; 5 | import 'create_control.dart'; 6 | import 'error.dart'; 7 | 8 | class AutofillGroupControl extends StatelessWidget { 9 | final Control? parent; 10 | final Control control; 11 | final List children; 12 | final bool parentDisabled; 13 | final bool? parentAdaptive; 14 | 15 | const AutofillGroupControl( 16 | {super.key, 17 | required this.parent, 18 | required this.control, 19 | required this.children, 20 | required this.parentDisabled, 21 | this.parentAdaptive}); 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | debugPrint("AutofillGroup build: ${control.id}"); 26 | 27 | var contentCtrls = 28 | children.where((c) => c.name == "content" && c.isVisible); 29 | bool disabled = control.isDisabled || parentDisabled; 30 | 31 | if (contentCtrls.isEmpty) { 32 | return const ErrorControl("AutofillGroup control has no content."); 33 | } 34 | 35 | return AutofillGroup( 36 | onDisposeAction: parseAutofillContextAction( 37 | control.attrString("disposeAction"), AutofillContextAction.commit)!, 38 | child: createControl(control, contentCtrls.first.id, disabled, 39 | parentAdaptive: parentAdaptive)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/cupertino_activity_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | import '../flet_control_backend.dart'; 4 | import '../models/control.dart'; 5 | import 'create_control.dart'; 6 | 7 | class CupertinoActivityIndicatorControl extends StatelessWidget { 8 | final Control? parent; 9 | final Control control; 10 | final bool parentDisabled; 11 | final FletControlBackend backend; 12 | 13 | const CupertinoActivityIndicatorControl( 14 | {super.key, 15 | this.parent, 16 | required this.control, 17 | required this.parentDisabled, 18 | required this.backend}); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | debugPrint("CupertinoActivityIndicatorControl build: ${control.id}"); 23 | 24 | return constrainedControl( 25 | context, 26 | CupertinoActivityIndicator( 27 | radius: control.attrDouble("radius", 10)!, 28 | animating: control.attrBool("animating", true)!, 29 | color: control.attrColor("color", context), 30 | ), 31 | parent, 32 | control); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../models/control.dart'; 4 | import 'create_control.dart'; 5 | 6 | class DividerControl extends StatelessWidget { 7 | final Control? parent; 8 | final Control control; 9 | 10 | const DividerControl( 11 | {super.key, required this.parent, required this.control}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | debugPrint("Divider build: ${control.id}"); 16 | 17 | var divider = Divider( 18 | height: control.attrDouble("height"), 19 | thickness: control.attrDouble("thickness"), 20 | color: control.attrColor("color", context), 21 | indent: control.attrDouble("leadingIndent"), 22 | endIndent: control.attrDouble("trailingIndent"), 23 | ); 24 | return baseControl(context, divider, parent, control); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/error.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ErrorControl extends StatelessWidget { 4 | final String message; 5 | final String? description; 6 | 7 | const ErrorControl(this.message, {super.key, this.description}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | debugPrint("ErrorControl build"); 12 | List lines = [ 13 | Text(message, style: const TextStyle(color: Colors.white, fontSize: 12)) 14 | ]; 15 | if (description != null) { 16 | lines.addAll([ 17 | const SizedBox(height: 5), 18 | Text(description!, 19 | style: const TextStyle(color: Colors.white70, fontSize: 11)) 20 | ]); 21 | } 22 | return SelectionArea( 23 | child: Container( 24 | padding: const EdgeInsets.all(5), 25 | decoration: BoxDecoration( 26 | color: Colors.red, borderRadius: BorderRadius.circular(3)), 27 | child: Column( 28 | crossAxisAlignment: CrossAxisAlignment.start, 29 | children: lines, 30 | ), 31 | )); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flet/src/utils/box.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../models/control.dart'; 5 | import '../utils/icons.dart'; 6 | import '../utils/images.dart'; 7 | import 'create_control.dart'; 8 | 9 | class IconControl extends StatelessWidget { 10 | final Control? parent; 11 | final Control control; 12 | 13 | const IconControl({super.key, required this.parent, required this.control}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | debugPrint("Icon build: ${control.id}"); 18 | 19 | return constrainedControl( 20 | context, 21 | Icon( 22 | parseIcon(control.attrString("name", "")!), 23 | size: control.attrDouble("size"), 24 | color: control.attrColor("color", context), 25 | blendMode: parseBlendMode(control.attrString("blendMode")), 26 | semanticLabel: control.attrString("semanticsLabel"), 27 | applyTextScaling: control.attrBool("applyTextScaling"), 28 | fill: control.attrDouble("fill"), 29 | grade: control.attrDouble("grade"), 30 | weight: control.attrDouble("weight"), 31 | opticalSize: control.attrDouble("opticalSize"), 32 | shadows: parseBoxShadow(Theme.of(context), control, "shadows"), 33 | ), 34 | parent, 35 | control); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/merge_semantics.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../models/control.dart'; 4 | import 'create_control.dart'; 5 | 6 | class MergeSemanticsControl extends StatelessWidget { 7 | final Control? parent; 8 | final Control control; 9 | final List children; 10 | final bool parentDisabled; 11 | final bool? parentAdaptive; 12 | 13 | const MergeSemanticsControl( 14 | {super.key, 15 | this.parent, 16 | required this.control, 17 | required this.children, 18 | required this.parentDisabled, 19 | required this.parentAdaptive}); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | debugPrint("MergeSemantics build: ${control.id}"); 24 | 25 | var contentCtrls = 26 | children.where((c) => c.name == "content" && c.isVisible); 27 | bool disabled = control.isDisabled || parentDisabled; 28 | 29 | MergeSemantics mergeSemantics = MergeSemantics( 30 | child: contentCtrls.isNotEmpty 31 | ? createControl(control, contentCtrls.first.id, disabled, 32 | parentAdaptive: parentAdaptive) 33 | : null); 34 | 35 | return constrainedControl(context, mergeSemantics, parent, control); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/radio_group.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../models/control.dart'; 4 | import 'create_control.dart'; 5 | import 'error.dart'; 6 | 7 | class RadioGroupControl extends StatelessWidget { 8 | final Control? parent; 9 | final Control control; 10 | final List children; 11 | final bool parentDisabled; 12 | final bool? parentAdaptive; 13 | 14 | const RadioGroupControl( 15 | {super.key, 16 | this.parent, 17 | required this.control, 18 | required this.children, 19 | required this.parentDisabled, 20 | required this.parentAdaptive}); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | debugPrint("RadioGroupControl build: ${control.id}"); 25 | 26 | var contentCtrls = 27 | children.where((c) => c.name == "content" && c.isVisible); 28 | bool disabled = control.isDisabled || parentDisabled; 29 | 30 | if (contentCtrls.isEmpty) { 31 | return const ErrorControl( 32 | "RadioGroup.content must be provided and visible"); 33 | } 34 | 35 | return createControl(control, contentCtrls.first.id, disabled, 36 | parentAdaptive: parentAdaptive); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/flet/lib/src/controls/vertical_divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../models/control.dart'; 4 | import 'create_control.dart'; 5 | 6 | class VerticalDividerControl extends StatelessWidget { 7 | final Control? parent; 8 | final Control control; 9 | 10 | const VerticalDividerControl( 11 | {super.key, required this.parent, required this.control}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | debugPrint("VerticalDivider build: ${control.id}"); 16 | var divider = VerticalDivider( 17 | width: control.attrDouble("width"), 18 | thickness: control.attrDouble("thickness"), 19 | color: control.attrColor("color", context), 20 | indent: control.attrDouble("leadingIndent"), 21 | endIndent: control.attrDouble("trailingIndent"), 22 | ); 23 | 24 | return baseControl(context, divider, parent, control); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/flet/lib/src/flet_app_context.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FletAppContext extends InheritedWidget { 4 | final ThemeMode? themeMode; 5 | 6 | const FletAppContext( 7 | {super.key, required this.themeMode, required super.child}); 8 | 9 | @override 10 | bool updateShouldNotify(covariant InheritedWidget oldWidget) { 11 | return false; 12 | } 13 | 14 | static FletAppContext? of(BuildContext context) => 15 | context.dependOnInheritedWidgetOfExactType(); 16 | } 17 | -------------------------------------------------------------------------------- /packages/flet/lib/src/flet_app_errors_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class FletAppErrorsHandler extends ChangeNotifier { 4 | String? _error; 5 | String? get error => _error; 6 | void onError(String error) { 7 | _error = error; 8 | notifyListeners(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/flet/lib/src/flet_app_main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_redux/flutter_redux.dart'; 3 | 4 | import 'controls/create_control.dart'; 5 | import 'flet_app_services.dart'; 6 | import 'models/app_state.dart'; 7 | 8 | class FletAppMain extends StatelessWidget { 9 | final String title; 10 | 11 | const FletAppMain({ 12 | super.key, 13 | required this.title, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return StoreProvider( 19 | store: FletAppServices.of(context).store, 20 | child: createControl(null, "page", false), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/flet/lib/src/flet_control_backend.dart: -------------------------------------------------------------------------------- 1 | abstract class FletControlBackend { 2 | void updateControlState(String controlId, Map props, 3 | {bool client = true, bool server = true}); 4 | 5 | void triggerControlEvent(String controlId, String eventName, 6 | [String? eventData]); 7 | 8 | void subscribeMethods(String controlId, 9 | Future Function(String, Map) methodHandler); 10 | 11 | void unsubscribeMethods(String controlId); 12 | } 13 | -------------------------------------------------------------------------------- /packages/flet/lib/src/flet_server_protocol_javascript_io.dart: -------------------------------------------------------------------------------- 1 | import 'flet_server_protocol.dart'; 2 | 3 | class FletJavaScriptServerProtocol implements FletServerProtocol { 4 | final String address; 5 | final FletServerProtocolOnMessageCallback onMessage; 6 | final FletServerProtocolOnDisconnectCallback onDisconnect; 7 | 8 | FletJavaScriptServerProtocol( 9 | {required this.address, 10 | required this.onDisconnect, 11 | required this.onMessage}); 12 | 13 | @override 14 | connect() async {} 15 | 16 | @override 17 | bool get isLocalConnection => true; 18 | 19 | @override 20 | int get defaultReconnectIntervalMs => 10; 21 | 22 | @override 23 | void send(String message) {} 24 | 25 | @override 26 | void disconnect() {} 27 | } 28 | -------------------------------------------------------------------------------- /packages/flet/lib/src/flet_server_protocol_javascript_web.dart: -------------------------------------------------------------------------------- 1 | @JS() 2 | library script.js; 3 | 4 | import 'dart:js_util'; 5 | 6 | import 'package:flutter/foundation.dart'; 7 | import 'package:js/js.dart'; 8 | 9 | import 'flet_server_protocol.dart'; 10 | 11 | @JS() 12 | external dynamic jsConnect(FletServerProtocolOnMessageCallback onMessage); 13 | 14 | @JS() 15 | external dynamic jsSend(String data); 16 | 17 | class FletJavaScriptServerProtocol implements FletServerProtocol { 18 | final String address; 19 | final FletServerProtocolOnMessageCallback onMessage; 20 | final FletServerProtocolOnDisconnectCallback onDisconnect; 21 | 22 | FletJavaScriptServerProtocol( 23 | {required this.address, 24 | required this.onDisconnect, 25 | required this.onMessage}); 26 | 27 | @override 28 | connect() async { 29 | debugPrint("Connecting to JavaScript server $address..."); 30 | await promiseToFuture(jsConnect(allowInterop(onMessage))); 31 | } 32 | 33 | @override 34 | bool get isLocalConnection => true; 35 | 36 | @override 37 | int get defaultReconnectIntervalMs => 10; 38 | 39 | @override 40 | void send(String message) { 41 | jsSend(message); 42 | } 43 | 44 | @override 45 | void disconnect() {} 46 | } 47 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/asset_src.dart: -------------------------------------------------------------------------------- 1 | class AssetSrc { 2 | final String path; 3 | final bool isFile; 4 | 5 | const AssetSrc({required this.path, required this.isFile}); 6 | } 7 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/control_ancestor_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:redux/redux.dart'; 3 | 4 | import 'app_state.dart'; 5 | import 'control.dart'; 6 | 7 | class ControlAncestorViewModel extends Equatable { 8 | final Control? ancestor; 9 | 10 | const ControlAncestorViewModel({required this.ancestor}); 11 | 12 | static ControlAncestorViewModel fromStore( 13 | Store store, String id, String ancestorType) { 14 | Control? ancestor; 15 | String controlId = id; 16 | while (true) { 17 | String parentId = store.state.controls[controlId]!.pid; 18 | if (parentId == "") { 19 | break; 20 | } 21 | ancestor = store.state.controls[parentId]!; 22 | if (ancestor.type.toLowerCase() == ancestorType.toLowerCase()) { 23 | break; 24 | } 25 | controlId = ancestor.id; 26 | } 27 | 28 | return ControlAncestorViewModel(ancestor: ancestor); 29 | } 30 | 31 | @override 32 | List get props => [ancestor]; 33 | } 34 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/control_tree_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:redux/redux.dart'; 4 | 5 | import 'app_state.dart'; 6 | import 'control.dart'; 7 | 8 | class ControlTreeViewModel extends Equatable { 9 | final Control control; 10 | final List children; 11 | 12 | const ControlTreeViewModel({required this.control, required this.children}); 13 | 14 | static ControlTreeViewModel fromStore( 15 | Store store, Control control) { 16 | return ControlTreeViewModel( 17 | control: control, 18 | children: control.childIds 19 | .map((childId) => store.state.controls[childId]) 20 | .whereNotNull() 21 | .where((c) => c.isVisible) 22 | .map((c) => ControlTreeViewModel.fromStore(store, c)) 23 | .toList()); 24 | } 25 | 26 | @override 27 | List get props => [control, children]; 28 | } 29 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/control_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:redux/redux.dart'; 4 | 5 | import 'app_state.dart'; 6 | import 'control.dart'; 7 | 8 | class ControlViewModel extends Equatable { 9 | final Control control; 10 | final List children; 11 | final dynamic dispatch; 12 | 13 | const ControlViewModel( 14 | {required this.control, required this.children, required this.dispatch}); 15 | 16 | static ControlViewModel? fromStore(Store store, String id) { 17 | var control = store.state.controls[id]; 18 | return control != null 19 | ? ControlViewModel( 20 | control: control, 21 | children: control.childIds 22 | .map((childId) => store.state.controls[childId]) 23 | .whereNotNull() 24 | .toList(), 25 | dispatch: store.dispatch) 26 | : null; 27 | } 28 | 29 | @override 30 | List get props => [control, children, dispatch]; 31 | } 32 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/controls_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:redux/redux.dart'; 4 | 5 | import 'app_state.dart'; 6 | import 'control_view_model.dart'; 7 | 8 | class ControlsViewModel extends Equatable { 9 | final List controlViews; 10 | 11 | const ControlsViewModel({required this.controlViews}); 12 | 13 | static ControlsViewModel fromStore( 14 | Store store, Iterable ids) { 15 | return ControlsViewModel( 16 | controlViews: ids 17 | .map((id) => ControlViewModel.fromStore(store, id)) 18 | .whereNotNull() 19 | .toList()); 20 | } 21 | 22 | @override 23 | List get props => [controlViews]; 24 | } 25 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/page_args_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:redux/redux.dart'; 3 | 4 | import 'app_state.dart'; 5 | 6 | class PageArgsModel extends Equatable { 7 | final Uri? pageUri; 8 | final String assetsDir; 9 | 10 | const PageArgsModel({required this.pageUri, required this.assetsDir}); 11 | 12 | static PageArgsModel fromStore(Store store) { 13 | return PageArgsModel( 14 | pageUri: store.state.pageUri, assetsDir: store.state.assetsDir); 15 | } 16 | 17 | @override 18 | List get props => [pageUri, assetsDir]; 19 | } 20 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/page_load_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:redux/redux.dart'; 3 | 4 | import 'app_state.dart'; 5 | import 'page_media_view_model.dart'; 6 | 7 | class PageLoadViewModel extends Equatable { 8 | final Uri? pageUri; 9 | final String sessionId; 10 | final PageMediaViewModel sizeViewModel; 11 | 12 | const PageLoadViewModel( 13 | {required this.pageUri, 14 | required this.sessionId, 15 | required this.sizeViewModel}); 16 | 17 | static PageLoadViewModel fromStore(Store store) { 18 | return PageLoadViewModel( 19 | pageUri: store.state.pageUri, 20 | sessionId: store.state.sessionId, 21 | sizeViewModel: PageMediaViewModel.fromStore(store)); 22 | } 23 | 24 | @override 25 | List get props => [pageUri, sizeViewModel]; 26 | } 27 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/page_media_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:redux/redux.dart'; 5 | 6 | import '../protocol/page_media_data.dart'; 7 | import 'app_state.dart'; 8 | 9 | class PageMediaViewModel extends Equatable { 10 | final bool isRegistered; 11 | final Size size; 12 | final Brightness displayBrightness; 13 | final PageMediaData media; 14 | final Function dispatch; 15 | 16 | const PageMediaViewModel( 17 | {required this.isRegistered, 18 | required this.size, 19 | required this.displayBrightness, 20 | required this.media, 21 | required this.dispatch}); 22 | 23 | static PageMediaViewModel fromStore(Store store) { 24 | return PageMediaViewModel( 25 | isRegistered: store.state.isRegistered, 26 | size: store.state.size, 27 | displayBrightness: store.state.displayBrightness, 28 | media: store.state.media, 29 | dispatch: store.dispatch); 30 | } 31 | 32 | @override 33 | List get props => [size, displayBrightness, dispatch, isRegistered]; 34 | } 35 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/page_size_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:redux/redux.dart'; 5 | 6 | import 'app_state.dart'; 7 | 8 | class PageSizeViewModel extends Equatable { 9 | final Map breakpoints; 10 | final Size size; 11 | 12 | const PageSizeViewModel({required this.size, required this.breakpoints}); 13 | 14 | static PageSizeViewModel fromStore(Store store) { 15 | return PageSizeViewModel( 16 | size: store.state.size, breakpoints: store.state.sizeBreakpoints); 17 | } 18 | 19 | @override 20 | List get props => [size, breakpoints]; 21 | } 22 | -------------------------------------------------------------------------------- /packages/flet/lib/src/models/window_media_data.dart: -------------------------------------------------------------------------------- 1 | class WindowMediaData { 2 | bool? isMaximized; 3 | bool? isMinimized; 4 | bool? isMinimizable; 5 | bool? isFullScreen; 6 | bool? isResizable; 7 | bool? isMovable; 8 | bool? isClosable; 9 | bool? isAlwaysOnTop; 10 | bool? isFocused; 11 | bool? isPreventClose; 12 | bool? isVisible; 13 | double? width; 14 | double? height; 15 | double? top; 16 | double? left; 17 | double? opacity; 18 | } 19 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/add_page_controls_payload.dart: -------------------------------------------------------------------------------- 1 | import '../models/control.dart'; 2 | 3 | class AddPageControlsPayload { 4 | final List trimIDs; 5 | final List controls; 6 | 7 | AddPageControlsPayload({required this.trimIDs, required this.controls}); 8 | 9 | factory AddPageControlsPayload.fromJson(Map json) { 10 | var controlsJson = json['controls'] as List; 11 | final controls = controlsJson.map((j) => Control.fromJson(j)).toList(); 12 | return AddPageControlsPayload( 13 | trimIDs: List.from(json['trimIDs']), controls: controls); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/app_become_active_payload.dart: -------------------------------------------------------------------------------- 1 | class AppBecomeActivePayload { 2 | AppBecomeActivePayload(); 3 | 4 | factory AppBecomeActivePayload.fromJson(Map json) => 5 | AppBecomeActivePayload(); 6 | } 7 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/app_become_inactive_payload.dart: -------------------------------------------------------------------------------- 1 | class AppBecomeInactivePayload { 2 | final String message; 3 | 4 | AppBecomeInactivePayload({required this.message}); 5 | 6 | factory AppBecomeInactivePayload.fromJson(Map json) => 7 | AppBecomeInactivePayload(message: json['message'] as String); 8 | } 9 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/append_control_props_request.dart: -------------------------------------------------------------------------------- 1 | class AppendControlPropsPayload { 2 | final List> props; 3 | 4 | AppendControlPropsPayload({required this.props}); 5 | 6 | factory AppendControlPropsPayload.fromJson(Map json) { 7 | var propsJson = json['props'] as List; 8 | var props = propsJson 9 | .map((propJson) => Map.from(propJson)) 10 | .toList(); 11 | return AppendControlPropsPayload(props: props); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/clean_control_payload.dart: -------------------------------------------------------------------------------- 1 | class CleanControlPayload { 2 | final List ids; 3 | 4 | CleanControlPayload({required this.ids}); 5 | 6 | factory CleanControlPayload.fromJson(Map json) => 7 | CleanControlPayload(ids: List.from(json['ids'])); 8 | } 9 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/invoke_method_payload.dart: -------------------------------------------------------------------------------- 1 | class InvokeMethodPayload { 2 | final String methodId; 3 | final String methodName; 4 | final String controlId; 5 | final Map args; 6 | 7 | InvokeMethodPayload( 8 | {required this.methodId, 9 | required this.methodName, 10 | required this.controlId, 11 | required this.args}); 12 | 13 | factory InvokeMethodPayload.fromJson(Map json) { 14 | return InvokeMethodPayload( 15 | methodId: json["methodId"], 16 | methodName: json['methodName'], 17 | controlId: json["controlId"], 18 | args: json['arguments'] != null 19 | ? Map.from(json['arguments']) 20 | : {}); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/invoke_method_result.dart: -------------------------------------------------------------------------------- 1 | class InvokeMethodResult { 2 | final String methodId; 3 | final String? result; 4 | final String? error; 5 | 6 | InvokeMethodResult({required this.methodId, this.result, this.error}); 7 | 8 | Map toJson() => { 9 | 'method_id': methodId, 10 | 'result': result, 11 | 'error': error 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/message.dart: -------------------------------------------------------------------------------- 1 | enum MessageAction { 2 | registerWebClient, 3 | pageEventFromWeb, 4 | updateControlProps, 5 | appBecomeActive, 6 | appBecomeInactive, 7 | sessionCrashed, 8 | invokeMethod, 9 | addPageControls, 10 | replacePageControls, 11 | pageControlsBatch, 12 | appendControlProps, 13 | cleanControl, 14 | removeControl 15 | } 16 | 17 | class Message { 18 | final MessageAction action; 19 | final dynamic payload; 20 | 21 | Message({required this.action, required this.payload}); 22 | 23 | Map toJson() => 24 | {'action': action.name, 'payload': payload.toJson()}; 25 | 26 | factory Message.fromJson(Map json) { 27 | return Message( 28 | action: MessageAction.values 29 | .firstWhere((e) => e.name == json['action'] as String), 30 | payload: json['payload']); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/page_controls_batch_payload.dart: -------------------------------------------------------------------------------- 1 | import 'message.dart'; 2 | 3 | class PageControlsBatchPayload { 4 | final List messages; 5 | 6 | PageControlsBatchPayload({required this.messages}); 7 | 8 | factory PageControlsBatchPayload.fromJson(dynamic json) { 9 | var messagesJson = json as List; 10 | return PageControlsBatchPayload( 11 | messages: messagesJson.map((m) => Message.fromJson(m)).toList()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/page_event_from_web_request.dart: -------------------------------------------------------------------------------- 1 | class PageEventFromWebRequest { 2 | final String eventTarget; 3 | final String eventName; 4 | final String? eventData; 5 | 6 | PageEventFromWebRequest( 7 | {required this.eventTarget, 8 | required this.eventName, 9 | required this.eventData}); 10 | 11 | Map toJson() => { 12 | 'eventTarget': eventTarget, 13 | 'eventName': eventName, 14 | 'eventData': eventData 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/page_media_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class PageMediaData extends Equatable { 5 | final PaddingData padding; 6 | final PaddingData viewPadding; 7 | final PaddingData viewInsets; 8 | 9 | const PageMediaData( 10 | {required this.padding, 11 | required this.viewPadding, 12 | required this.viewInsets}); 13 | 14 | Map toJson() => { 15 | 'padding': padding, 16 | 'view_padding': viewPadding, 17 | 'view_insets': viewInsets, 18 | }; 19 | 20 | @override 21 | List get props => [padding, viewPadding, viewInsets]; 22 | } 23 | 24 | class PaddingData extends Equatable { 25 | final double top; 26 | final double right; 27 | final double bottom; 28 | final double left; 29 | 30 | PaddingData(EdgeInsets insets) 31 | : top = insets.top, 32 | right = insets.right, 33 | bottom = insets.bottom, 34 | left = insets.left; 35 | 36 | Map toJson() => { 37 | 'top': top, 38 | 'right': right, 39 | 'bottom': bottom, 40 | 'left': left, 41 | }; 42 | 43 | @override 44 | List get props => [top, right, bottom, left]; 45 | } 46 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/register_webclient_response.dart: -------------------------------------------------------------------------------- 1 | import 'session_payload.dart'; 2 | 3 | class RegisterWebClientResponse { 4 | final SessionPayload? session; 5 | final bool appInactive; 6 | final String? error; 7 | 8 | RegisterWebClientResponse( 9 | {this.session, required this.appInactive, this.error}); 10 | 11 | factory RegisterWebClientResponse.fromJson(Map json) { 12 | return RegisterWebClientResponse( 13 | session: json['session'] != null 14 | ? SessionPayload.fromJson(json['session']) 15 | : null, 16 | appInactive: json['appInactive'] as bool, 17 | error: json['error'] as String?); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/remove_control_payload.dart: -------------------------------------------------------------------------------- 1 | class RemoveControlPayload { 2 | final List ids; 3 | 4 | RemoveControlPayload({required this.ids}); 5 | 6 | factory RemoveControlPayload.fromJson(Map json) => 7 | RemoveControlPayload(ids: List.from(json['ids'])); 8 | } 9 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/replace_page_controls_payload.dart: -------------------------------------------------------------------------------- 1 | import '../models/control.dart'; 2 | 3 | class ReplacePageControlsPayload { 4 | final List ids; 5 | final List controls; 6 | final bool remove; 7 | 8 | ReplacePageControlsPayload( 9 | {required this.ids, required this.controls, required this.remove}); 10 | 11 | factory ReplacePageControlsPayload.fromJson(Map json) { 12 | var controlsJson = json['controls'] as List; 13 | final controls = controlsJson.map((j) => Control.fromJson(j)).toList(); 14 | return ReplacePageControlsPayload( 15 | ids: List.from(json['ids']), 16 | controls: controls, 17 | remove: json['remove'] as bool); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/session_crashed_payload.dart: -------------------------------------------------------------------------------- 1 | class SessionCrashedPayload { 2 | final String message; 3 | 4 | SessionCrashedPayload({required this.message}); 5 | 6 | factory SessionCrashedPayload.fromJson(Map json) => 7 | SessionCrashedPayload(message: json['message'] as String); 8 | } 9 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/session_payload.dart: -------------------------------------------------------------------------------- 1 | import '../models/control.dart'; 2 | 3 | class SessionPayload { 4 | final String id; 5 | final Map controls; 6 | 7 | SessionPayload({required this.id, required this.controls}); 8 | 9 | factory SessionPayload.fromJson(Map json) { 10 | Map controls = {}; 11 | for (var key in json['controls'].keys) { 12 | controls[key] = Control.fromJson(json['controls'][key]); 13 | } 14 | return SessionPayload(id: json['id'] as String, controls: controls); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/update_control_props_payload.dart: -------------------------------------------------------------------------------- 1 | class UpdateControlPropsPayload { 2 | final List> props; 3 | 4 | UpdateControlPropsPayload({required this.props}); 5 | 6 | factory UpdateControlPropsPayload.fromJson(Map json) { 7 | var propsJson = json['props'] as List; 8 | var props = propsJson 9 | .map((propJson) => Map.from(propJson)) 10 | .toList(); 11 | return UpdateControlPropsPayload(props: props); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/flet/lib/src/protocol/update_control_props_request.dart: -------------------------------------------------------------------------------- 1 | class UpdateControlPropsRequest { 2 | final List> props; 3 | 4 | UpdateControlPropsRequest({required this.props}); 5 | 6 | Map toJson() => {'props': props}; 7 | } 8 | -------------------------------------------------------------------------------- /packages/flet/lib/src/routing/route_parser.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class RouteParser extends RouteInformationParser { 4 | @override 5 | Future parseRouteInformation( 6 | RouteInformation routeInformation) async { 7 | return routeInformation.uri.toString(); 8 | } 9 | 10 | @override 11 | RouteInformation restoreRouteInformation(String configuration) => 12 | RouteInformation(uri: Uri.parse(configuration)); 13 | } 14 | -------------------------------------------------------------------------------- /packages/flet/lib/src/routing/route_state.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021, the Flutter project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'package:flutter/widgets.dart'; 6 | 7 | import 'route_parser.dart'; 8 | 9 | class RouteState extends ChangeNotifier { 10 | final RouteParser _parser; 11 | String _route; 12 | 13 | RouteState(this._parser) : _route = ""; 14 | 15 | String get route => _route; 16 | 17 | set route(String route) { 18 | // Don't notify listeners if the path hasn't changed. 19 | if (_route == route) return; 20 | 21 | _route = route; 22 | debugPrint("Route changed to: $route"); 23 | notifyListeners(); 24 | } 25 | 26 | Future go(String route) async { 27 | this.route = await _parser 28 | .parseRouteInformation(RouteInformation(uri: Uri.parse(route))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/flet/lib/src/routing/router_delegate.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import 'route_state.dart'; 5 | 6 | class SimpleRouterDelegate extends RouterDelegate 7 | with ChangeNotifier, PopNavigatorRouterDelegateMixin { 8 | final RouteState routeState; 9 | final WidgetBuilder builder; 10 | 11 | @override 12 | final GlobalKey navigatorKey; 13 | 14 | SimpleRouterDelegate({ 15 | required this.routeState, 16 | required this.builder, 17 | required this.navigatorKey, 18 | }) { 19 | routeState.addListener(notifyListeners); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) => builder(context); 24 | 25 | @override 26 | Future setNewRoutePath(String configuration) async { 27 | routeState.route = configuration; 28 | return SynchronousFuture(null); 29 | } 30 | 31 | @override 32 | String get currentConfiguration { 33 | return routeState.route; 34 | } 35 | 36 | @override 37 | void dispose() { 38 | routeState.removeListener(notifyListeners); 39 | routeState.dispose(); 40 | super.dispose(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:window_manager/window_manager.dart'; 6 | 7 | import 'utils/platform.dart'; 8 | 9 | Future setupDesktop() async { 10 | if (isDesktopPlatform()) { 11 | WidgetsFlutterBinding.ensureInitialized(); 12 | await windowManager.ensureInitialized(); 13 | 14 | Map env = Platform.environment; 15 | var hideWindowOnStart = env["FLET_HIDE_WINDOW_ON_START"]; 16 | debugPrint("hideWindowOnStart: $hideWindowOnStart"); 17 | 18 | await windowManager.waitUntilReadyToShow(null, () async { 19 | if (hideWindowOnStart == null) { 20 | await windowManager.show(); 21 | await windowManager.focus(); 22 | } 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/badge.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/flet.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | Badge? parseBadge( 7 | Control control, String propName, Widget widget, ThemeData theme) { 8 | var v = control.attrString(propName, null); 9 | if (v == null) { 10 | return null; 11 | } 12 | final j = json.decode(v); 13 | return badgeFromJSON(j, widget, theme); 14 | } 15 | 16 | Badge? badgeFromJSON(dynamic j, Widget widget, ThemeData theme) { 17 | if (j == null) { 18 | return null; 19 | } else if (j is String) { 20 | return Badge(label: Text(j), child: widget); 21 | } 22 | 23 | String? label = j["text"]; 24 | 25 | return Badge( 26 | label: label != null ? Text(label) : null, 27 | isLabelVisible: parseBool(j["label_visible"]) ?? true, 28 | offset: offsetFromJson(j["offset"]), 29 | alignment: alignmentFromJson(j["alignment"]), 30 | backgroundColor: parseColor(theme, j["bgcolor"]), 31 | largeSize: parseDouble(j["large_size"]), 32 | padding: edgeInsetsFromJson(j["padding"]), 33 | smallSize: parseDouble(j["small_size"]), 34 | textColor: parseColor(theme, j["text_color"]), 35 | textStyle: textStyleFromJson(theme, j["text_style"]), 36 | child: widget, 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/browser_context_menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | Future disableBrowserContextMenu() async { 4 | return BrowserContextMenu.disableContextMenu(); 5 | } 6 | 7 | Future enableBrowserContextMenu() async { 8 | return BrowserContextMenu.enableContextMenu(); 9 | } 10 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/clipboard.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | void setClipboard(String data) async { 4 | await Clipboard.setData(ClipboardData(text: data)); 5 | } 6 | 7 | Future getClipboard() async { 8 | var data = await Clipboard.getData(Clipboard.kTextPlain); 9 | return data?.text; 10 | } 11 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/collections.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | int arrayIndexOf(Uint8List haystack, Uint8List needle) { 4 | var len = needle.length; 5 | var limit = haystack.length - len; 6 | for (var i = 0; i <= limit; i++) { 7 | var k = 0; 8 | for (; k < len; k++) { 9 | if (needle[k] != haystack[i + k]) break; 10 | } 11 | if (k == len) return i; 12 | } 13 | return -1; 14 | } 15 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/debouncer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'dart:async'; 3 | 4 | class Debouncer { 5 | final int milliseconds; 6 | Timer? _timer; 7 | 8 | Debouncer({required this.milliseconds}); 9 | 10 | void run(VoidCallback action) { 11 | if (_timer?.isActive ?? false) _timer!.cancel(); 12 | _timer = Timer(Duration(milliseconds: milliseconds), action); 13 | } 14 | 15 | void dispose() { 16 | _timer?.cancel(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/icons.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | import '../models/control.dart'; 6 | import 'cupertino_icons.dart'; 7 | import 'material_icons.dart'; 8 | import 'material_state.dart'; 9 | 10 | IconData? parseIcon(String? iconName, [IconData? defaultIcon]) { 11 | if (iconName == null) { 12 | return defaultIcon; 13 | } 14 | return materialIcons[iconName.toLowerCase()] ?? cupertinoIcons[iconName.toLowerCase()]; 15 | } 16 | 17 | WidgetStateProperty? parseWidgetStateIcon( 18 | ThemeData theme, Control control, String propName) { 19 | var v = control.attrString(propName, null); 20 | if (v == null) { 21 | return null; 22 | } 23 | 24 | final j1 = json.decode(v); 25 | 26 | return getWidgetStateProperty( 27 | j1, (jv) => Icon(parseIcon(jv as String))); 28 | } 29 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/images_web.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | 4 | import '../models/asset_src.dart'; 5 | 6 | SvgPicture getSvgPictureFromFile( 7 | {required String src, 8 | required double? width, 9 | required double? height, 10 | required BoxFit fit, 11 | required Color? color, 12 | required BlendMode blendMode, 13 | required String? semanticsLabel}) { 14 | return SvgPicture.string(""); 15 | } 16 | 17 | AssetSrc getAssetSrc(String src, Uri pageUri, String assetsDir) { 18 | return AssetSrc( 19 | path: src.startsWith("/") ? src.substring(1) : src, isFile: false); 20 | } 21 | 22 | ImageProvider getFileImageProvider(String path) { 23 | throw UnimplementedError(); 24 | } 25 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/launch_url.dart: -------------------------------------------------------------------------------- 1 | import 'package:url_launcher/url_launcher.dart'; 2 | 3 | import 'platform_utils_non_web.dart' 4 | if (dart.library.js) "platform_utils_web.dart"; 5 | 6 | Future openWebBrowser(String url, 7 | {String? webWindowName, 8 | bool? webPopupWindow, 9 | int? windowWidth, 10 | int? windowHeight}) async { 11 | if (webPopupWindow == true) { 12 | openPopupBrowserWindow( 13 | url, webWindowName ?? "Flet", windowWidth ?? 1200, windowHeight ?? 800); 14 | } else { 15 | LaunchMode? mode; 16 | if (webWindowName == "_blank") { 17 | mode = LaunchMode.externalApplication; 18 | } 19 | 20 | await launchUrl(Uri.parse(url), 21 | webOnlyWindowName: webWindowName, 22 | mode: mode ?? LaunchMode.platformDefault); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/networking.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:typed_data'; 3 | 4 | Future isPrivateHost(String host) async { 5 | String? ip; 6 | var addr = InternetAddress.tryParse(host); 7 | if (addr == null) { 8 | InternetAddress ipAddr; 9 | try { 10 | ipAddr = (await InternetAddress.lookup(host)).first; 11 | } on SocketException { 12 | throw Exception("Cannot resolve host: $host"); 13 | } 14 | if (ipAddr.rawAddress.length == 16) { 15 | return ipAddr.isLinkLocal || ipAddr.isLoopback; 16 | } 17 | ip = ipAddr.address; 18 | } else { 19 | ip = addr.address; 20 | } 21 | var f = ipToInt(ip); 22 | var private = [ 23 | ["127.0.0.0", "255.0.0.0"], 24 | ["192.168.0.0", "255.255.0.0"], 25 | ["172.16.0.0", "255.240.0.0"], 26 | ["10.0.0.0", "255.0.0.0"], 27 | ]; 28 | for (var net in private) { 29 | if ((f & ipToInt(net[1])) == ipToInt(net[0])) { 30 | return true; 31 | } 32 | } 33 | return false; 34 | } 35 | 36 | int ipToInt(String ip) { 37 | ByteData byteData = ByteData.view( 38 | Int8List.fromList(InternetAddress(ip).rawAddress.toList()).buffer); 39 | return byteData.getUint32(0, Endian.big); 40 | } 41 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/platform_utils_non_web.dart: -------------------------------------------------------------------------------- 1 | import 'strings.dart'; 2 | 3 | bool isProgressiveWebApp() { 4 | return false; 5 | } 6 | 7 | String getWebsocketEndpointPath(String uriPath) { 8 | var pagePath = trim(uriPath, "/"); 9 | if (pagePath != "") { 10 | pagePath = "$pagePath/"; 11 | } 12 | return "${pagePath}ws"; 13 | } 14 | 15 | String getFletRouteUrlStrategy() { 16 | return ""; 17 | } 18 | 19 | bool isFletWebPyodideMode() { 20 | return false; 21 | } 22 | 23 | void openPopupBrowserWindow( 24 | String url, String windowName, int minWidth, int minHeight) {} 25 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/session_store_non_web.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class SessionStore { 4 | static String? get sessionId { 5 | return null; 6 | } 7 | 8 | static set sessionId(String? value) { 9 | // nothing to do 10 | } 11 | 12 | static String? get(String name) { 13 | return null; 14 | } 15 | 16 | static void set(String name, String value) { 17 | debugPrint("Do not set cookie!"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/session_store_web.dart: -------------------------------------------------------------------------------- 1 | // ignore: avoid_web_libraries_in_flutter 2 | import 'dart:html' as html; 3 | 4 | import 'package:flutter/foundation.dart'; 5 | 6 | const String _sessionIdKey = "_flet_session_id"; 7 | 8 | class SessionStore { 9 | static String? get sessionId { 10 | return get(_sessionIdKey); 11 | } 12 | 13 | static set sessionId(String? value) { 14 | set(_sessionIdKey, value ?? ""); 15 | } 16 | 17 | static String? get(String name) { 18 | debugPrint("Get session storage $name"); 19 | return html.window.sessionStorage[name]; 20 | } 21 | 22 | static void set(String name, String value) { 23 | debugPrint("Set session storage $name"); 24 | html.window.sessionStorage[name] = value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/strings.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../models/control.dart'; 4 | 5 | List? parseStringList(Control control, String propName) { 6 | var v = control.attrString(propName, null); 7 | if (v == null) { 8 | return null; 9 | } 10 | 11 | final jv = json.decode(v); 12 | return (jv as List).map((c) => c as String).toList(); 13 | } 14 | 15 | String trimStart(String str, String symbol) { 16 | if (str.startsWith(symbol)) { 17 | return str.substring(symbol.length); 18 | } else { 19 | return str; 20 | } 21 | } 22 | 23 | String trimEnd(String str, String symbol) { 24 | if (str.endsWith(symbol)) { 25 | return str.substring(0, str.length - symbol.length); 26 | } else { 27 | return str; 28 | } 29 | } 30 | 31 | String trim(String str, String symbol) { 32 | return trimEnd(trimStart(str, symbol), symbol); 33 | } 34 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/time.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../models/control.dart'; 4 | import 'numbers.dart'; 5 | 6 | Duration? parseDuration(Control control, String propName, 7 | [Duration? defaultValue]) { 8 | var v = control.attrString(propName, null); 9 | if (v == null) { 10 | return defaultValue; 11 | } 12 | 13 | final j1 = json.decode(v); 14 | return durationFromJSON(j1); 15 | } 16 | 17 | Duration? durationFromJSON(dynamic json, [Duration? defaultValue]) { 18 | if (json == null) { 19 | return defaultValue; 20 | } 21 | if (json is int || json is double) { 22 | return Duration(milliseconds: parseInt(json, 0)!); 23 | } 24 | return Duration( 25 | days: parseInt(json["days"], 0)!, 26 | hours: parseInt(json["hours"], 0)!, 27 | minutes: parseInt(json["minutes"], 0)!, 28 | seconds: parseInt(json["seconds"], 0)!, 29 | milliseconds: parseInt(json["milliseconds"], 0)!, 30 | microseconds: parseInt(json["microseconds"], 0)!); 31 | } 32 | 33 | Duration? durationFromString(String? duration, [Duration? defaultValue]) { 34 | return duration != null 35 | ? durationFromJSON(json.decode(duration), defaultValue) 36 | : defaultValue; 37 | } -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/uri.dart: -------------------------------------------------------------------------------- 1 | import 'strings.dart'; 2 | 3 | String getWebPageName(Uri uri) { 4 | var urlPath = trim(uri.path, "/"); 5 | if (urlPath != "") { 6 | var pathParts = urlPath.split("/"); 7 | if (pathParts.length > 1) { 8 | urlPath = pathParts.sublist(0, 2).join("/"); 9 | } 10 | } 11 | return urlPath; 12 | } 13 | 14 | Uri getAssetUri(Uri pageUri, String assetPath) { 15 | return Uri( 16 | scheme: pageUri.scheme, 17 | host: pageUri.host, 18 | port: pageUri.port, 19 | pathSegments: [...pageUri.pathSegments, ...assetPath.split("/")]); 20 | } 21 | 22 | Uri getBaseUri(Uri pageUri) { 23 | return Uri(scheme: pageUri.scheme, host: pageUri.host, port: pageUri.port); 24 | } 25 | 26 | bool isLocalhost(Uri uri) { 27 | return uri.host == "localhost" || uri.host == "127.0.0.1"; 28 | } 29 | 30 | bool isUdsPath(String address) { 31 | var uri = Uri.tryParse(address); 32 | return uri == null || !uri.hasScheme; 33 | } 34 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/user_fonts_io.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'dart:io'; 3 | 4 | Future fetchFontFromFile(String path) async { 5 | File file = File(path); 6 | Uint8List bytes = await file.readAsBytes(); 7 | return ByteData.view(bytes.buffer); 8 | } 9 | -------------------------------------------------------------------------------- /packages/flet/lib/src/utils/user_fonts_web.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | Future fetchFontFromFile(String path) async { 4 | throw UnimplementedError(); 5 | } 6 | -------------------------------------------------------------------------------- /packages/flet/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flet 2 | description: Write entire Flutter app in Python or add server-driven UI experience into existing Flutter app. 3 | homepage: https://flet.dev 4 | repository: https://github.com/flet-dev/flet/packages/flet 5 | version: 0.28.3 6 | 7 | # This package supports all platforms listed below. 8 | platforms: 9 | android: 10 | ios: 11 | linux: 12 | macos: 13 | web: 14 | windows: 15 | 16 | environment: 17 | sdk: '>=3.0.0 <4.0.0' 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | flutter_localizations: 23 | sdk: flutter 24 | 25 | redux: ^5.0.0 26 | flutter_redux: ^0.10.0 27 | equatable: ^2.0.3 28 | web_socket_channel: ^2.4.0 29 | window_manager: ^0.4.3 30 | http: ^1.2.2 31 | collection: ^1.16.0 32 | url_launcher: ^6.3.1 33 | flutter_markdown: ^0.7.4+1 34 | flutter_highlight: ^0.7.0 35 | highlight: ^0.7.0 36 | markdown: ^7.2.2 37 | file_picker: ^10.1.9 38 | shared_preferences: ^2.3.2 39 | flutter_svg: ^2.0.13 40 | window_to_front: ^0.0.3 41 | sensors_plus: ^4.0.2 42 | path: ^1.8.2 43 | js: ^0.6.5 44 | fl_chart: ^0.69.0 45 | device_info_plus: ^11.2.0 46 | 47 | dev_dependencies: 48 | flutter_test: 49 | sdk: flutter 50 | flutter_lints: ^3.0.1 51 | 52 | flutter: 53 | 54 | # To add assets to your package, add an assets section, like this: 55 | # assets: 56 | # - images/a_dot_burr.jpeg 57 | # - images/a_dot_ham.jpeg 58 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/add_page_controls_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/add_page_controls_payload.dart'; 4 | 5 | void main() { 6 | test("AddPageControlsPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "trimIDs": ["c1", "c2"], 9 | "controls": [ 10 | { 11 | "i": "txt1", 12 | "t": "text", 13 | "p": "page", 14 | "c": [], 15 | "value": "Text A" 16 | }, 17 | { 18 | "i": "stack1", 19 | "t": "stack", 20 | "p": "page", 21 | "c": ["txt2"], 22 | "align": "center" 23 | } 24 | ]}'''; 25 | 26 | final s = AddPageControlsPayload.fromJson(json.decode(myJsonAsString)); 27 | expect(s.trimIDs.length, 2); 28 | expect(s.controls.length, 2); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/app_become_inactive_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/app_become_inactive_payload.dart'; 4 | 5 | void main() { 6 | test("AppBecomeInactivePayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "message": "Application is inactive." 9 | }'''; 10 | 11 | final s = AppBecomeInactivePayload.fromJson(json.decode(myJsonAsString)); 12 | expect(s.message, "Application is inactive."); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/append_control_props_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/append_control_props_request.dart'; 4 | 5 | void main() { 6 | test("AppendControlPropsPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "props": [ 9 | { 10 | "i": "txt1", 11 | "value": "Text A" 12 | }, 13 | { 14 | "i": "stack1", 15 | "align": "center" 16 | } 17 | ]}'''; 18 | 19 | final s = AppendControlPropsPayload.fromJson(json.decode(myJsonAsString)); 20 | expect(s.props.length, 2); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/clean_control_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/clean_control_payload.dart'; 4 | 5 | void main() { 6 | test("CleanControlPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "ids": ["c1", "c2"] 9 | }'''; 10 | 11 | final s = CleanControlPayload.fromJson(json.decode(myJsonAsString)); 12 | expect(s.ids.length, 2); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/message_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/message.dart'; 4 | import 'package:flet/src/protocol/remove_control_payload.dart'; 5 | 6 | void main() { 7 | test("Message parse from JSON", () { 8 | const s = ''' 9 | { 10 | "action": "removeControl", 11 | "payload": { 12 | "ids": ["i1", "i2"] 13 | } 14 | } 15 | '''; 16 | 17 | final m = Message.fromJson(json.decode(s)); 18 | expect(m.action, MessageAction.removeControl); 19 | 20 | if (m.action == MessageAction.removeControl) { 21 | final payload = RemoveControlPayload.fromJson(m.payload); 22 | expect(payload.ids.length, 2); 23 | } 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/page_controls_batch_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/src/protocol/page_controls_batch_payload.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | 6 | void main() { 7 | test("PageControlsBatchPayload serialize to message", () { 8 | const myJsonAsString = '''[ 9 | {"action":"updateControlProps","payload":{"props":[{"i":"page","width":"100","height":"200"},{"i":"txt1","value":"Hello, world!"}]}}, 10 | {"action":"removeControl","payload":{"ids":["a1", "b2"]}} 11 | ] 12 | '''; 13 | 14 | final s = PageControlsBatchPayload.fromJson(json.decode(myJsonAsString)); 15 | expect(s.messages.length, 2); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/page_event_from_web_request_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/message.dart'; 4 | import 'package:flet/src/protocol/page_event_from_web_request.dart'; 5 | 6 | void main() { 7 | test("PageEventFromWebRequest serialize to message", () { 8 | final m = Message( 9 | action: MessageAction.pageEventFromWeb, 10 | payload: PageEventFromWebRequest( 11 | eventTarget: "page", eventName: "resize", eventData: "100x200")); 12 | 13 | final j = json.encode(m); 14 | 15 | expect(j, 16 | '{"action":"pageEventFromWeb","payload":{"eventTarget":"page","eventName":"resize","eventData":"100x200"}}'); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/register_webclient_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/session_payload.dart'; 4 | 5 | void main() { 6 | test("Session payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "id": "session-1234", 9 | "controls": { 10 | "page": { 11 | "t": "page", 12 | "p": "", 13 | "i": "page", 14 | "c": [] 15 | } 16 | }}'''; 17 | 18 | final s = SessionPayload.fromJson(json.decode(myJsonAsString)); 19 | expect(s.id, 'session-1234'); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/register_webclient_request_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/src/protocol/message.dart'; 4 | import 'package:flet/src/protocol/register_webclient_request.dart'; 5 | import 'package:flutter_test/flutter_test.dart'; 6 | 7 | void main() { 8 | test("RegisterWebClientRequest serialize to message", () { 9 | final m = Message( 10 | action: MessageAction.registerWebClient, 11 | payload: RegisterWebClientRequest(pageName: "test-page1")); 12 | 13 | final j = json.encode(m); 14 | expect(j, 15 | '{"action":"registerWebClient","payload":{"pageName":"test-page1","pageRoute":null,"pageWidth":null,"pageHeight":null,"windowWidth":null,"windowHeight":null,"windowTop":null,"windowLeft":null,"isPWA":null,"isWeb":null,"isDebug":null,"platform":null,"platformBrightness":null,"media":null,"sessionId":null}}'); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/register_webclient_response_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/src/protocol/register_webclient_response.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | 6 | void main() { 7 | test("RegisterWebClientResponse with session deserialized", () { 8 | const myJsonAsString = '''{ 9 | "appInactive": false, 10 | "session": { 11 | "id": "session-1234", 12 | "controls": { 13 | "page": { 14 | "i": "page", 15 | "t": "page", 16 | "p": "", 17 | "c": ["txt1", "stack1"], 18 | "hash": "aaa" 19 | } 20 | } 21 | }}'''; 22 | 23 | final s = RegisterWebClientResponse.fromJson(json.decode(myJsonAsString)); 24 | expect(s.session!.id, 'session-1234'); 25 | expect(s.session!.controls.length, 1); 26 | }); 27 | 28 | test("RegisterWebClientResponse with error deserialized", () { 29 | const myJsonAsString = '''{ 30 | "error": "Page does not exist", 31 | "appInactive": false, 32 | "session": null 33 | }'''; 34 | 35 | final s = RegisterWebClientResponse.fromJson(json.decode(myJsonAsString)); 36 | expect(s.session == null, true); 37 | expect(s.error, "Page does not exist"); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/remove_control_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/remove_control_payload.dart'; 4 | 5 | void main() { 6 | test("RemoveControlPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "ids": ["c1", "c2"] 9 | }'''; 10 | 11 | final s = RemoveControlPayload.fromJson(json.decode(myJsonAsString)); 12 | expect(s.ids.length, 2); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/replace_page_controls_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/replace_page_controls_payload.dart'; 4 | 5 | void main() { 6 | test("ReplacePageControlsPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "remove": true, 9 | "ids": ["c1", "c2"], 10 | "controls": [ 11 | { 12 | "i": "txt1", 13 | "t": "text", 14 | "p": "page", 15 | "c": [], 16 | "value": "Text A" 17 | }, 18 | { 19 | "i": "stack1", 20 | "t": "stack", 21 | "p": "page", 22 | "c": ["txt2"], 23 | "align": "center" 24 | } 25 | ]}'''; 26 | 27 | final s = ReplacePageControlsPayload.fromJson(json.decode(myJsonAsString)); 28 | expect(s.ids.length, 2); 29 | expect(s.controls.length, 2); 30 | expect(s.remove, true); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/session_crashed_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/session_crashed_payload.dart'; 4 | 5 | void main() { 6 | test("SessionCrashedPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "message": "Error while processing request!" 9 | }'''; 10 | 11 | final s = SessionCrashedPayload.fromJson(json.decode(myJsonAsString)); 12 | expect(s.message, "Error while processing request!"); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/update_control_props_payload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flet/src/protocol/update_control_props_payload.dart'; 4 | 5 | void main() { 6 | test("UpdateControlPropsPayload payload deserialized", () { 7 | const myJsonAsString = '''{ 8 | "props": [ 9 | { 10 | "i": "txt1", 11 | "value": "Text A" 12 | }, 13 | { 14 | "i": "stack1", 15 | "align": "center" 16 | } 17 | ]}'''; 18 | 19 | final s = UpdateControlPropsPayload.fromJson(json.decode(myJsonAsString)); 20 | expect(s.props.length, 2); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /packages/flet/test/protocol/update_control_props_request_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/src/protocol/message.dart'; 4 | import 'package:flet/src/protocol/update_control_props_request.dart'; 5 | import 'package:flutter_test/flutter_test.dart'; 6 | 7 | void main() { 8 | test("UpdateControlPropsRequest serialize to message", () { 9 | final m = Message( 10 | action: MessageAction.updateControlProps, 11 | payload: UpdateControlPropsRequest(props: [ 12 | {"i": "page", "width": "100", "height": "200"}, 13 | {"i": "txt1", "value": "Hello, world!"}, 14 | ])); 15 | 16 | final j = json.encode(m); 17 | 18 | expect(j, 19 | '{"action":"updateControlProps","payload":{"props":[{"i":"page","width":"100","height":"200"},{"i":"txt1","value":"Hello, world!"}]}}'); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /packages/flet/test/utils/networking_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flet/src/utils/networking.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | test("localhost address is private", () async { 6 | expect(await isPrivateHost("localhost"), true); 7 | }); 8 | 9 | test("127.0.1.1 address is private", () async { 10 | expect(await isPrivateHost("127.0.1.1"), true); 11 | }); 12 | 13 | test("192.168.0.1 address is private", () async { 14 | expect(await isPrivateHost("192.168.0.1"), true); 15 | }); 16 | 17 | test("172.16.0.10 address is private", () async { 18 | expect(await isPrivateHost("172.16.0.10"), true); 19 | }); 20 | 21 | test("10.0.5.100 address is private", () async { 22 | expect(await isPrivateHost("10.0.5.100"), true); 23 | }); 24 | 25 | test("216.34.2.201 address is public", () async { 26 | expect(await isPrivateHost("216.34.2.201"), false); 27 | }); 28 | 29 | test("45.3.2.2 address is public", () async { 30 | expect(await isPrivateHost("45.3.2.2"), false); 31 | }); 32 | 33 | test("flutter.dev address is public", () async { 34 | expect(await isPrivateHost("flutter.dev"), false); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /packages/flet/test/utils/theme_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/src/utils/theme.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | import 'package:flutter_test/flutter_test.dart'; 7 | 8 | void main() { 9 | test("Light theme is parsed correctly from JSON", () { 10 | const t1 = '''{ 11 | "color_scheme_seed": "red", 12 | "brightness": "light", 13 | "use_material3": false 14 | }'''; 15 | 16 | final j1 = json.decode(t1); 17 | var theme = themeFromJson(j1, Brightness.light, null); 18 | 19 | expect(theme.brightness, Brightness.light); 20 | expect(theme.useMaterial3, false); 21 | expect(theme.primaryColor, const Color(0xff904a42)); 22 | }); 23 | 24 | test("Dark theme is parsed correctly from JSON", () { 25 | const t1 = '''{ 26 | "color_scheme_seed": "cyan", 27 | "brightness": "dark" 28 | }'''; 29 | 30 | final j1 = json.decode(t1); 31 | var theme = themeFromJson(j1, Brightness.dark, null); 32 | 33 | expect(theme.brightness, Brightness.dark); 34 | expect(theme.useMaterial3, true); 35 | expect(theme.primaryColor, const Color(0xff0e1416)); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /packages/flet/test/utils/uri_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flet/src/utils/uri.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | test("Empty URI can be parsed", () { 6 | var uri = Uri.parse(""); 7 | expect(uri.hasAuthority, false); 8 | }); 9 | test("Relative URI can be parsed", () { 10 | var uri = Uri.parse("images/test.png"); 11 | expect(uri.hasAuthority, false); 12 | }); 13 | 14 | test("getWebPageName returns correct name from Uri", () { 15 | expect( 16 | getWebPageName(Uri.parse('http://localhost:8550/p/test/')), "p/test"); 17 | expect(getWebPageName(Uri.parse('http://localhost:8550/p/test')), "p/test"); 18 | expect(getWebPageName(Uri.parse('http://localhost:8550/aaa')), "aaa"); 19 | expect(getWebPageName(Uri.parse('http://localhost:8550/p/test/store')), 20 | "p/test"); 21 | expect( 22 | getWebPageName( 23 | Uri.parse('http://localhost:8550/p/test/store/products/1')), 24 | "p/test"); 25 | expect(getWebPageName(Uri.parse('http://localhost:8550/')), ""); 26 | expect(getWebPageName(Uri.parse('http://localhost:8550/#/')), ""); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /packages/flet/test/utils/user_fonts_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flet/src/utils/user_fonts.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | 6 | void main() { 7 | test("Custom fonts are parsed from JSON", () { 8 | const t1 = '''{ 9 | "font1": "https://fonts.com/font1.ttf", 10 | "font2": "https://fonts.com/font2.ttf" 11 | }'''; 12 | 13 | final j1 = json.decode(t1); 14 | var fonts = fontsFromJson(j1); 15 | 16 | expect(fonts.length, 2); 17 | expect(fonts["font1"], "https://fonts.com/font1.ttf"); 18 | expect(fonts["font2"], "https://fonts.com/font2.ttf"); 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /sdk/python/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /sdk/python/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pycqa/isort 3 | rev: 5.13.2 4 | hooks: 5 | - id: isort 6 | - repo: https://github.com/ambv/black 7 | rev: 22.12.0 8 | hooks: 9 | - id: black 10 | -------------------------------------------------------------------------------- /sdk/python/README.md: -------------------------------------------------------------------------------- 1 | # Python SDK for Flet 2 | 3 | Package relationships: 4 | 5 | ```mermaid 6 | graph TD; 7 | flet-core-->flet-runtime; 8 | flet-core-->flet-pyodide; 9 | flet-runtime-->flet-embed; 10 | flet-runtime-->flet; 11 | ``` -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/README.md: -------------------------------------------------------------------------------- 1 | # Flet CLI 2 | 3 | Flet CLI is a command-line interface tool for Flet, a framework for building interactive multi-platform applications using Python. 4 | 5 | ## Features 6 | 7 | - Create new Flet projects 8 | - Run Flet applications 9 | - Package and deploy Flet apps 10 | 11 | ## Basic Usage 12 | 13 | To create a new Flet project: 14 | 15 | ``` 16 | flet create myapp 17 | ``` -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "flet-cli" 3 | version = "0.1.0" 4 | description = "Flet CLI" 5 | authors = [{name = "Appveyor Systems Inc.", email ="hello@flet.dev"}] 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | requires-python = ">=3.9" 9 | 10 | [tool.poetry] 11 | packages = [{ include = "flet_cli", from = "src" }] 12 | 13 | [tool.poetry.urls] 14 | Homepage = "https://flet.dev" 15 | Repository = "https://github.com/flet-dev/flet" 16 | Documentation = "https://flet.dev/docs" 17 | 18 | [tool.poetry.dependencies] 19 | flet = { version = "0.1.0" } 20 | watchdog = "^4.0.0" 21 | packaging = "*" 22 | qrcode = "^7.4.2" 23 | toml = "^0.10.2" 24 | cookiecutter = "^2.6.0" 25 | 26 | [tool.poetry.plugins."pyinstaller40"] 27 | hook-dirs = "flet_cli.__pyinstaller:get_hook_dirs" 28 | 29 | [build-system] 30 | requires = ["poetry-core"] 31 | build-backend = "poetry.core.masonry.api" 32 | 33 | [tool.isort] 34 | profile = "black" 35 | float_to_top = true 36 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def get_hook_dirs(): 5 | return [os.path.dirname(__file__)] 6 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/config.py: -------------------------------------------------------------------------------- 1 | temp_bin_dir = None 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/hook-flet.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import flet_cli.__pyinstaller.config as hook_config 4 | from flet_cli.__pyinstaller.utils import get_flet_bin_path 5 | 6 | bin_path = hook_config.temp_bin_dir 7 | if not bin_path: 8 | bin_path = get_flet_bin_path() 9 | 10 | if bin_path: 11 | datas = [(bin_path, "flet_desktop/app")] 12 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/rthooks.dat: -------------------------------------------------------------------------------- 1 | { 2 | 'flet': [ 3 | 'pyi_rth_localhost_fletd.py' 4 | ], 5 | } -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | import flet 5 | 6 | logger = logging.getLogger(flet.__name__) 7 | 8 | 9 | logger.info("Running PyInstaller runtime hook for Flet...") 10 | 11 | os.environ["FLET_SERVER_IP"] = "127.0.0.1" 12 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | import uuid 4 | from pathlib import Path 5 | 6 | from flet.utils import copy_tree 7 | from flet_desktop import get_package_bin_dir 8 | 9 | 10 | def get_flet_bin_path(): 11 | bin_path = get_package_bin_dir() 12 | if not os.path.exists(bin_path): 13 | return None 14 | return bin_path 15 | 16 | 17 | def copy_flet_bin(): 18 | bin_path = get_flet_bin_path() 19 | if not bin_path: 20 | return None 21 | 22 | # create temp bin dir 23 | temp_bin_dir = Path(tempfile.gettempdir()).joinpath(str(uuid.uuid4())) 24 | copy_tree(bin_path, str(temp_bin_dir)) 25 | return str(temp_bin_dir) 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/commands/options.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from typing import Any 3 | 4 | 5 | class Option: 6 | """A reusable option object which delegates all arguments 7 | to parser.add_argument(). 8 | """ 9 | 10 | def __init__(self, *args: Any, **kwargs: Any) -> None: 11 | self.args = args 12 | self.kwargs = kwargs 13 | 14 | def add_to_parser(self, parser: argparse._ActionsContainer) -> None: 15 | parser.add_argument(*self.args, **self.kwargs) 16 | 17 | def add_to_group(self, group: argparse._ArgumentGroup) -> None: 18 | group.add_argument(*self.args, **self.kwargs) 19 | 20 | 21 | verbose_option = Option( 22 | "-v", 23 | "--verbose", 24 | action="count", 25 | default=0, 26 | help="-v for detailed output and -vv for more detailed", 27 | ) 28 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/utils/hash_stamp.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from pathlib import Path 3 | 4 | 5 | class HashStamp: 6 | def __init__(self, path) -> None: 7 | self._path = path 8 | self._hash = hashlib.sha256() 9 | 10 | def update(self, data): 11 | if data is not None: 12 | self._hash.update(str(data).encode()) 13 | 14 | def has_changed(self): 15 | hash_file = Path(self._path) 16 | last_hash = hash_file.read_text() if hash_file.exists() else "" 17 | return self._hash.hexdigest() != last_hash 18 | 19 | def commit(self): 20 | hash_file = Path(self._path) 21 | hash_file.parent.mkdir(parents=True, exist_ok=True) 22 | hash_file.write_text(self._hash.hexdigest()) 23 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/utils/merge.py: -------------------------------------------------------------------------------- 1 | def merge_dict(a: dict, b: dict, path=[]): 2 | for key in b: 3 | if key in a and isinstance(a[key], dict) and isinstance(b[key], dict): 4 | merge_dict(a[key], b[key], path + [str(key)]) 5 | else: 6 | a[key] = b[key] 7 | return a 8 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/utils/pyproject_toml.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import Any, Optional 3 | 4 | import toml 5 | 6 | 7 | def load_pyproject_toml(project_dir: Path): 8 | pyproject_toml: Optional[dict[str, Any]] = {} 9 | pyproject_toml_file = project_dir.joinpath("pyproject.toml") 10 | if pyproject_toml_file.exists(): 11 | with pyproject_toml_file.open("r", encoding="utf-8") as f: 12 | pyproject_toml = toml.loads(f.read()) 13 | 14 | def get_pyproject(setting: Optional[str] = None): 15 | if not setting: 16 | return pyproject_toml 17 | 18 | d = pyproject_toml 19 | for k in setting.split("."): 20 | d = d.get(k) 21 | if d is None: 22 | return None 23 | return d 24 | 25 | return get_pyproject 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-cli/src/flet_cli/version.py: -------------------------------------------------------------------------------- 1 | version = "" 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-desktop/.gitignore: -------------------------------------------------------------------------------- 1 | app/ -------------------------------------------------------------------------------- /sdk/python/packages/flet-desktop/README.md: -------------------------------------------------------------------------------- 1 | # Flet Desktop client in Flutter 2 | 3 | This package contains a compiled Flutter Flet desktop client. -------------------------------------------------------------------------------- /sdk/python/packages/flet-desktop/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "flet-desktop" 3 | version = "0.1.0" 4 | description = "Flet Desktop client in Flutter" 5 | authors = [{name = "Appveyor Systems Inc.", email ="hello@flet.dev"}] 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | requires-python = ">=3.9" 9 | 10 | [tool.poetry] 11 | packages = [ 12 | { include = "flet_desktop", from = "src" }, 13 | ] 14 | 15 | include = [ 16 | { path = "src/flet_desktop/app/**/*", format = ["sdist", "wheel"] }, 17 | ] 18 | 19 | [tool.poetry.urls] 20 | Homepage = "https://flet.dev" 21 | Repository = "https://github.com/flet-dev/flet" 22 | Documentation = "https://flet.dev/docs" 23 | 24 | [tool.poetry.dependencies] 25 | flet = { version = "0.1.0" } 26 | 27 | [tool.poetry.group.dev.dependencies] 28 | pre-commit = "^2.6" 29 | pytest = "^7.2.0" 30 | 31 | [build-system] 32 | requires = ["poetry-core"] 33 | build-backend = "poetry.core.masonry.api" 34 | 35 | [tool.isort] 36 | profile = "black" 37 | float_to_top = true -------------------------------------------------------------------------------- /sdk/python/packages/flet-desktop/src/flet_desktop/version.py: -------------------------------------------------------------------------------- 1 | version = "" 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/.gitignore: -------------------------------------------------------------------------------- 1 | web/ -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/README.md: -------------------------------------------------------------------------------- 1 | # Flet Web client in Flutter 2 | 3 | This package contains a compiled Flutter Flet web client. -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "flet-web" 3 | version = "0.1.0" 4 | description = "Flet web client in Flutter." 5 | authors = [{name = "Appveyor Systems Inc.", email ="hello@flet.dev"}] 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | requires-python = ">=3.9" 9 | 10 | [tool.poetry] 11 | packages = [{ include = "flet_web", from = "src" }] 12 | 13 | include = [{ path = "src/flet_web/web/**/*", format = ["sdist", "wheel"] }] 14 | 15 | [tool.poetry.urls] 16 | Homepage = "https://flet.dev" 17 | Repository = "https://github.com/flet-dev/flet" 18 | Documentation = "https://flet.dev/docs" 19 | 20 | [tool.poetry.dependencies] 21 | flet = { version = "0.1.0" } 22 | fastapi = "*" 23 | uvicorn = { extras = ["standard"], version = "*" } 24 | 25 | [build-system] 26 | requires = ["poetry-core"] 27 | build-backend = "poetry.core.masonry.api" 28 | 29 | [tool.isort] 30 | profile = "black" 31 | float_to_top = true 32 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/src/flet_web/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | from flet_web.patch_index import patch_index_html, patch_manifest_json 5 | 6 | 7 | def get_package_web_dir(): 8 | web_root_dir = os.environ.get("FLET_WEB_PATH") 9 | return web_root_dir or str(Path(__file__).parent.joinpath("web")) 10 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/src/flet_web/fastapi/__init__.py: -------------------------------------------------------------------------------- 1 | from flet_web.fastapi.app import app 2 | from flet_web.fastapi.flet_app import FletApp 3 | from flet_web.fastapi.flet_app_manager import app_manager 4 | from flet_web.fastapi.flet_fastapi import FastAPI 5 | from flet_web.fastapi.flet_static_files import FletStaticFiles 6 | from flet_web.fastapi.flet_upload import FletUpload 7 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/src/flet_web/fastapi/oauth_state.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | from datetime import datetime 3 | from typing import Optional 4 | 5 | 6 | @dataclasses.dataclass 7 | class OAuthState: 8 | session_id: str 9 | expires_at: datetime 10 | complete_page_url: Optional[str] = dataclasses.field(default=None) 11 | complete_page_html: Optional[str] = dataclasses.field(default=None) 12 | -------------------------------------------------------------------------------- /sdk/python/packages/flet-web/src/flet_web/version.py: -------------------------------------------------------------------------------- 1 | version = "" 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/ads/__init__.py: -------------------------------------------------------------------------------- 1 | from flet.core.ads.banner import BannerAd 2 | from flet.core.ads.interstitial import InterstitialAd 3 | 4 | """ 5 | from flet.core.ads.native import ( 6 | NativeAd, 7 | NativeAdTemplateStyle, 8 | NativeAdTemplateTextStyle, 9 | NativeTemplateFontStyle, 10 | NativeAdTemplateType, 11 | ) 12 | """ 13 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/__init__.py: -------------------------------------------------------------------------------- 1 | from flet.auth.authorization import Authorization 2 | from flet.auth.group import Group 3 | from flet.auth.oauth_provider import OAuthProvider 4 | from flet.auth.oauth_token import OAuthToken 5 | from flet.auth.user import User 6 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/group.py: -------------------------------------------------------------------------------- 1 | class Group(dict): 2 | def __init__(self, kwargs, name: str) -> None: 3 | super().__init__(kwargs) 4 | self.name = name 5 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/oauth_token.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import List, Optional 3 | 4 | from flet.core.embed_json_encoder import EmbedJsonEncoder 5 | 6 | 7 | class OAuthToken: 8 | def __init__( 9 | self, 10 | access_token: str, 11 | scope: Optional[List[str]] = None, 12 | token_type: Optional[str] = None, 13 | expires_in: Optional[int] = None, 14 | expires_at: Optional[float] = None, 15 | refresh_token: Optional[str] = None, 16 | ) -> None: 17 | self.access_token = access_token 18 | self.scope = scope 19 | self.token_type = token_type 20 | self.expires_in = expires_in 21 | self.expires_at = expires_at 22 | self.refresh_token = refresh_token 23 | 24 | def to_json(self): 25 | return json.dumps(self, cls=EmbedJsonEncoder, separators=(",", ":")) 26 | 27 | @staticmethod 28 | def from_json(data: str): 29 | t = json.loads(data) 30 | return OAuthToken(**t) 31 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/providers/__init__.py: -------------------------------------------------------------------------------- 1 | from flet.auth.providers.auth0_oauth_provider import Auth0OAuthProvider 2 | from flet.auth.providers.azure_oauth_provider import AzureOAuthProvider 3 | from flet.auth.providers.github_oauth_provider import GitHubOAuthProvider 4 | from flet.auth.providers.google_oauth_provider import GoogleOAuthProvider 5 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/providers/auth0_oauth_provider.py: -------------------------------------------------------------------------------- 1 | from flet.auth.oauth_provider import OAuthProvider 2 | 3 | 4 | class Auth0OAuthProvider(OAuthProvider): 5 | def __init__( 6 | self, domain: str, client_id: str, client_secret: str, redirect_url: str 7 | ) -> None: 8 | super().__init__( 9 | client_id=client_id, 10 | client_secret=client_secret, 11 | authorization_endpoint=f"https://{domain}/authorize", 12 | token_endpoint=f"https://{domain}/oauth/token", 13 | redirect_url=redirect_url, 14 | scopes=["offline_access"], 15 | user_scopes=["openid", "profile", "email"], 16 | user_endpoint=f"https://{domain}/userinfo", 17 | user_id_fn=lambda u: u["sub"], 18 | group_scopes=[], 19 | ) 20 | self.domain = domain 21 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/providers/azure_oauth_provider.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from flet.auth.oauth_provider import OAuthProvider 4 | 5 | 6 | class AzureOAuthProvider(OAuthProvider): 7 | def __init__( 8 | self, 9 | client_id: str, 10 | client_secret: str, 11 | redirect_url: str, 12 | tenant: Optional[str] = "common", 13 | ) -> None: 14 | super().__init__( 15 | client_id=client_id, 16 | client_secret=client_secret, 17 | authorization_endpoint=f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize", 18 | token_endpoint=f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", 19 | redirect_url=redirect_url, 20 | user_scopes=["user.read"], 21 | user_endpoint="https://graph.microsoft.com/v1.0/me", 22 | user_id_fn=lambda u: u["id"], 23 | group_scopes=[], 24 | ) 25 | self.tenant = tenant 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/providers/google_oauth_provider.py: -------------------------------------------------------------------------------- 1 | from flet.auth.oauth_provider import OAuthProvider 2 | 3 | 4 | class GoogleOAuthProvider(OAuthProvider): 5 | def __init__(self, client_id: str, client_secret: str, redirect_url: str) -> None: 6 | super().__init__( 7 | client_id=client_id, 8 | client_secret=client_secret, 9 | authorization_endpoint="https://accounts.google.com/o/oauth2/auth", 10 | token_endpoint="https://oauth2.googleapis.com/token", 11 | redirect_url=redirect_url, 12 | user_scopes=[ 13 | "https://www.googleapis.com/auth/userinfo.email", 14 | "https://www.googleapis.com/auth/userinfo.profile", 15 | ], 16 | user_endpoint="https://www.googleapis.com/oauth2/v3/userinfo", 17 | user_id_fn=lambda u: u["sub"], 18 | group_scopes=[], 19 | ) 20 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/auth/user.py: -------------------------------------------------------------------------------- 1 | class User(dict): 2 | def __init__(self, kwargs, id: str) -> None: 3 | super().__init__(kwargs) 4 | self.id = id 5 | self.groups = [] 6 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/canvas/__init__.py: -------------------------------------------------------------------------------- 1 | from flet.core.canvas.arc import Arc 2 | from flet.core.canvas.canvas import Canvas, CanvasResizeEvent 3 | from flet.core.canvas.circle import Circle 4 | from flet.core.canvas.color import Color 5 | from flet.core.canvas.fill import Fill 6 | from flet.core.canvas.line import Line 7 | from flet.core.canvas.oval import Oval 8 | from flet.core.canvas.path import Path 9 | from flet.core.canvas.points import PointMode, Points 10 | from flet.core.canvas.rect import Rect 11 | from flet.core.canvas.shadow import Shadow 12 | from flet.core.canvas.text import Text 13 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/cli.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | 4 | from flet.utils.pip import ensure_flet_cli_package_installed 5 | 6 | 7 | def main(): 8 | ensure_flet_cli_package_installed() 9 | import flet_cli.cli 10 | 11 | flet_cli.cli.main() 12 | 13 | 14 | if __name__ == "__main__": 15 | main() 16 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/adaptive_control.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from flet.core.control import Control 4 | 5 | 6 | class AdaptiveControl(Control): 7 | def __init__(self, adaptive: Optional[bool] = None): 8 | self.adaptive = adaptive 9 | 10 | # adaptive 11 | @property 12 | def adaptive(self) -> bool: 13 | return self._get_attr("adaptive", data_type="bool", def_value=False) 14 | 15 | @adaptive.setter 16 | def adaptive(self, value: Optional[bool]): 17 | self._set_attr("adaptive", value) 18 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/alignment.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | from enum import Enum 3 | from typing import Union 4 | 5 | 6 | class Axis(Enum): 7 | HORIZONTAL = "horizontal" 8 | VERTICAL = "vertical" 9 | 10 | 11 | @dataclasses.dataclass 12 | class Alignment: 13 | x: Union[float, int] 14 | y: Union[float, int] 15 | 16 | 17 | bottom_center = Alignment(0, 1) 18 | bottom_left = Alignment(-1, 1) 19 | bottom_right = Alignment(1, 1) 20 | center = Alignment(0, 0) 21 | center_left = Alignment(-1, 0) 22 | center_right = Alignment(1, 0) 23 | top_center = Alignment(0, -1) 24 | top_left = Alignment(-1, -1) 25 | top_right = Alignment(1, -1) 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/badge.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional, Union 3 | 4 | from flet.core.alignment import Alignment 5 | from flet.core.text_style import TextStyle 6 | from flet.core.types import ColorValue, OffsetValue, OptionalNumber, PaddingValue 7 | 8 | 9 | @dataclass 10 | class Badge: 11 | """Badges are used to show notifications, counts, or status information on navigation items such as NavigationBar or NavigationRail destinations 12 | or a button's icon.""" 13 | 14 | text: Optional[str] = None 15 | offset: Optional[OffsetValue] = None 16 | alignment: Optional[Alignment] = None 17 | bgcolor: Optional[ColorValue] = None 18 | label_visible: Optional[bool] = None 19 | large_size: OptionalNumber = None 20 | padding: Optional[PaddingValue] = None 21 | small_size: OptionalNumber = None 22 | text_color: Optional[ColorValue] = None 23 | text_style: Optional[TextStyle] = None 24 | 25 | 26 | BadgeValue = Union[str, "Badge"] 27 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/blur.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import Enum 3 | from typing import Optional 4 | 5 | 6 | class BlurTileMode(Enum): 7 | CLAMP = "clamp" 8 | DECAL = "decal" 9 | MIRROR = "mirror" 10 | REPEATED = "repeated" 11 | 12 | 13 | @dataclass 14 | class Blur: 15 | sigma_x: float 16 | sigma_y: float 17 | tile_mode: Optional[BlurTileMode] = None 18 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/border_radius.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | from typing import Union 3 | 4 | 5 | @dataclasses.dataclass 6 | class BorderRadius: 7 | top_left: Union[float, int] 8 | top_right: Union[float, int] 9 | bottom_left: Union[float, int] 10 | bottom_right: Union[float, int] 11 | 12 | 13 | def all(value: float) -> BorderRadius: 14 | return BorderRadius( 15 | top_left=value, top_right=value, bottom_left=value, bottom_right=value 16 | ) 17 | 18 | 19 | def horizontal(left: float = 0, right: float = 0) -> BorderRadius: 20 | return BorderRadius( 21 | top_left=left, top_right=right, bottom_left=left, bottom_right=right 22 | ) 23 | 24 | 25 | def vertical(top: float = 0, bottom: float = 0) -> BorderRadius: 26 | return BorderRadius( 27 | top_left=top, top_right=top, bottom_left=bottom, bottom_right=bottom 28 | ) 29 | 30 | 31 | def only( 32 | top_left: float = 0, 33 | top_right: float = 0, 34 | bottom_left: float = 0, 35 | bottom_right: float = 0, 36 | ) -> BorderRadius: 37 | return BorderRadius( 38 | top_left=top_left, 39 | top_right=top_right, 40 | bottom_left=bottom_left, 41 | bottom_right=bottom_right, 42 | ) 43 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/button.py: -------------------------------------------------------------------------------- 1 | from flet.core.elevated_button import ElevatedButton 2 | 3 | 4 | class Button(ElevatedButton): 5 | """ 6 | Elevated buttons or Buttons are essentially filled tonal buttons with a shadow. To prevent shadow creep, only use them when absolutely necessary, such as when the button requires visual separation from a patterned background. 7 | 8 | Example: 9 | ``` 10 | import flet as ft 11 | 12 | def main(page: ft.Page): 13 | page.title = "Basic buttons" 14 | page.add( 15 | ft.Button(text="Button"), 16 | ft.Button("Disabled button", disabled=True), 17 | ) 18 | 19 | ft.app(target=main) 20 | ``` 21 | 22 | ----- 23 | 24 | Online docs: https://flet.dev/docs/controls/elevatedbutton 25 | """ 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/canvas/fill.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional 2 | 3 | from flet.core.canvas.shape import Shape 4 | from flet.core.painting import Paint 5 | 6 | 7 | class Fill(Shape): 8 | def __init__( 9 | self, 10 | paint: Optional[Paint] = None, 11 | # 12 | # Control 13 | # 14 | ref=None, 15 | visible: Optional[bool] = None, 16 | disabled: Optional[bool] = None, 17 | data: Any = None, 18 | ): 19 | Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) 20 | 21 | self.paint = paint 22 | 23 | def _get_control_name(self): 24 | return "fill" 25 | 26 | def before_update(self): 27 | super().before_update() 28 | self._set_attr_json("paint", self.__paint) 29 | 30 | # paint 31 | @property 32 | def paint(self) -> Optional[Paint]: 33 | return self.__paint 34 | 35 | @paint.setter 36 | def paint(self, value: Optional[Paint]): 37 | self.__paint = value 38 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/canvas/shape.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional 2 | 3 | from flet.core.control import Control 4 | 5 | 6 | class Shape(Control): 7 | def __init__( 8 | self, 9 | ref=None, 10 | visible: Optional[bool] = None, 11 | disabled: Optional[bool] = None, 12 | data: Any = None, 13 | ): 14 | Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) 15 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/charts/chart_grid_lines.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional 3 | 4 | from flet.core.types import ColorValue 5 | 6 | 7 | @dataclass 8 | class ChartGridLines: 9 | interval: Optional[float] = None 10 | color: Optional[ColorValue] = None 11 | width: Optional[float] = None 12 | dash_pattern: Optional[List[int]] = None 13 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/charts/chart_point_line.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import List, Optional 3 | 4 | from flet.core.types import ColorValue 5 | 6 | 7 | @dataclass 8 | class ChartPointLine: 9 | color: Optional[ColorValue] = field(default=None) 10 | width: Optional[float] = field(default=None) 11 | dash_pattern: Optional[List[int]] = field(default=None) 12 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/charts/chart_point_shape.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from flet.core.types import ColorValue, OptionalNumber 5 | 6 | 7 | @dataclass 8 | class ChartPointShape: 9 | pass 10 | 11 | 12 | @dataclass 13 | class ChartCirclePoint(ChartPointShape): 14 | color: Optional[ColorValue] = None 15 | radius: OptionalNumber = None 16 | stroke_color: Optional[ColorValue] = None 17 | stroke_width: OptionalNumber = None 18 | 19 | def __post_init__(self): 20 | self.type = "circle" 21 | 22 | 23 | @dataclass 24 | class ChartSquarePoint(ChartPointShape): 25 | color: Optional[ColorValue] = None 26 | size: OptionalNumber = None 27 | stroke_color: Optional[ColorValue] = None 28 | stroke_width: OptionalNumber = None 29 | 30 | def __post_init__(self): 31 | self.type = "square" 32 | 33 | 34 | @dataclass 35 | class ChartCrossPoint(ChartPointShape): 36 | color: Optional[ColorValue] = None 37 | size: OptionalNumber = None 38 | width: OptionalNumber = None 39 | 40 | def __post_init__(self): 41 | self.type = "cross" 42 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/connection.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from flet.core.protocol import Command 4 | from flet.core.pubsub.pubsub_hub import PubSubHub 5 | 6 | 7 | class Connection: 8 | def __init__(self): 9 | self.page_name: str = "" 10 | self.page_url: Optional[str] = None 11 | self.sessions = {} 12 | self.pubsubhub = PubSubHub() 13 | 14 | def send_command(self, session_id: str, command: Command): 15 | raise NotImplementedError() 16 | 17 | def send_commands(self, session_id: str, commands: List[Command]): 18 | raise NotImplementedError() 19 | 20 | def _get_ws_url(self, server: str): 21 | url = server.rstrip("/") 22 | if server.startswith("https://"): 23 | url = url.replace("https://", "wss://") 24 | elif server.startswith("http://"): 25 | url = url.replace("http://", "ws://") 26 | else: 27 | url = "ws://" + url 28 | return url + "/ws" 29 | 30 | def dispose(self): 31 | pass 32 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/control_event.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from flet.core.event import Event 4 | 5 | 6 | class ControlEvent(Event): 7 | def __init__(self, target: str, name: str, data: Optional[str], control, page): 8 | Event.__init__(self, target=target, name=name, data=data) 9 | 10 | self.control = control 11 | self.page = page 12 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/event.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | 4 | class Event: 5 | def __init__(self, target: str, name: str, data: Optional[str]): 6 | self.target = target 7 | self.name = name 8 | self.data = data 9 | 10 | def __repr__(self): 11 | attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items()) 12 | return f"{self.__class__.__name__}({attrs})" 13 | 14 | def __str__(self): 15 | attrs = ", ".join( 16 | f"{k}={v!r}" 17 | for k, v in self.__dict__.items() 18 | if k not in ["control", "page", "target", "data"] # ignore these keys 19 | ) 20 | return f"{self.__class__.__name__}({attrs}, data={self.data!r})" # reinsert data as last arg 21 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/event_handler.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from flet.core.control_event import ControlEvent 4 | from flet.core.types import OptionalControlEventCallable 5 | 6 | 7 | class EventHandler: 8 | def __init__(self, result_converter=None) -> None: 9 | self.__result_converter = result_converter 10 | self.handler: OptionalControlEventCallable = None 11 | 12 | def get_handler(self): 13 | async def fn(e: ControlEvent): 14 | if self.handler is not None: 15 | ce = e 16 | if self.__result_converter is not None: 17 | ce = self.__result_converter(e) 18 | if ce is not None: 19 | ce.target = e.target 20 | ce.name = e.name 21 | ce.data = e.data 22 | ce.control = e.control 23 | ce.page = e.page 24 | 25 | if ce is not None: 26 | if asyncio.iscoroutinefunction(self.handler): 27 | await self.handler(ce) 28 | else: 29 | e.page.run_thread(self.handler, ce) 30 | 31 | return fn 32 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/exceptions.py: -------------------------------------------------------------------------------- 1 | class FletException(Exception): 2 | pass 3 | 4 | 5 | class FletUnsupportedPlatformException(FletException): 6 | """ 7 | Thrown by operations that are not supported on the current platform. 8 | """ 9 | 10 | def __init__(self, message: str): 11 | super().__init__(message) 12 | 13 | 14 | class FletUnimplementedPlatformEception(FletUnsupportedPlatformException): 15 | """ 16 | Thrown by operations that have not been implemented yet. 17 | """ 18 | 19 | pass 20 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/filled_button.py: -------------------------------------------------------------------------------- 1 | from flet.core.elevated_button import ElevatedButton 2 | 3 | 4 | class FilledButton(ElevatedButton): 5 | """ 6 | Filled buttons have the most visual impact after the FloatingActionButton (https://flet.dev/docs/controls/floatingactionbutton), and should be used for important, final actions that complete a flow, like Save, Join now, or Confirm. 7 | 8 | Example: 9 | ``` 10 | import flet as ft 11 | 12 | 13 | def main(page: ft.Page): 14 | page.title = "Basic filled buttons" 15 | page.add( 16 | ft.FilledButton(text="Filled button"), 17 | ft.FilledButton("Disabled button", disabled=True), 18 | ft.FilledButton("Button with icon", icon="add"), 19 | ) 20 | 21 | ft.app(target=main) 22 | ``` 23 | 24 | ----- 25 | 26 | Online docs: https://flet.dev/docs/controls/filledbutton 27 | """ 28 | 29 | def _get_control_name(self): 30 | return "filledbutton" 31 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/filled_tonal_button.py: -------------------------------------------------------------------------------- 1 | from flet.core.elevated_button import ElevatedButton 2 | 3 | 4 | class FilledTonalButton(ElevatedButton): 5 | """ 6 | A filled tonal button is an alternative middle ground between FilledButton and OutlinedButton buttons. They’re useful in contexts where a lower-priority button requires slightly more emphasis than an outline would give, such as "Next" in an onboarding flow. Tonal buttons use the secondary color mapping. 7 | 8 | Example: 9 | ``` 10 | import flet as ft 11 | 12 | 13 | def main(page: ft.Page): 14 | page.title = "Basic filled tonal buttons" 15 | page.add( 16 | ft.FilledTonalButton(text="Filled tonal button"), 17 | ft.FilledTonalButton("Disabled button", disabled=True), 18 | ft.FilledTonalButton("Button with icon", icon="add"), 19 | ) 20 | 21 | ft.app(target=main) 22 | ``` 23 | 24 | ----- 25 | 26 | Online docs: https://flet.dev/docs/controls/filledtonalbutton 27 | """ 28 | 29 | def _get_control_name(self): 30 | return "filledtonalbutton" 31 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/inline_span.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional 2 | 3 | from flet.core.control import Control 4 | 5 | 6 | class InlineSpan(Control): 7 | def __init__( 8 | self, 9 | # base 10 | ref=None, 11 | visible: Optional[bool] = None, 12 | disabled: Optional[bool] = None, 13 | data: Any = None, 14 | ): 15 | Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) 16 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/locks.py: -------------------------------------------------------------------------------- 1 | class NopeLock: 2 | def __enter__(self): 3 | pass 4 | 5 | def __exit__(self, *args): 6 | pass 7 | 8 | 9 | class AsyncNopeLock: 10 | async def __aenter__(self): 11 | pass 12 | 13 | async def __aexit__(self, *args): 14 | pass 15 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/map/map_layer.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional 2 | 3 | from flet.core.control import Control 4 | from flet.core.ref import Ref 5 | 6 | 7 | class MapLayer(Control): 8 | """ 9 | Abstract class for all map layers. 10 | """ 11 | 12 | def __init__( 13 | self, 14 | # 15 | # Control 16 | # 17 | ref: Optional[Ref] = None, 18 | visible: Optional[bool] = None, 19 | data: Any = None, 20 | ): 21 | Control.__init__( 22 | self, 23 | ref=ref, 24 | visible=visible, 25 | data=data, 26 | ) 27 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/margin.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | from typing import Union 3 | 4 | 5 | @dataclasses.dataclass 6 | class Margin: 7 | left: Union[float, int] 8 | top: Union[float, int] 9 | right: Union[float, int] 10 | bottom: Union[float, int] 11 | 12 | 13 | def all(value: float) -> Margin: 14 | return Margin(left=value, top=value, right=value, bottom=value) 15 | 16 | 17 | def symmetric(vertical: float = 0, horizontal: float = 0) -> Margin: 18 | return Margin(left=horizontal, top=vertical, right=horizontal, bottom=vertical) 19 | 20 | 21 | def only( 22 | left: float = 0, top: float = 0, right: float = 0, bottom: float = 0 23 | ) -> Margin: 24 | return Margin(left=left, top=top, right=right, bottom=bottom) 25 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/padding.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | from typing import Union 3 | 4 | 5 | @dataclasses.dataclass 6 | class Padding: 7 | left: Union[float, int] 8 | top: Union[float, int] 9 | right: Union[float, int] 10 | bottom: Union[float, int] 11 | 12 | 13 | def all(value: float) -> Padding: 14 | return Padding(left=value, top=value, right=value, bottom=value) 15 | 16 | 17 | def symmetric(vertical: float = 0, horizontal: float = 0) -> Padding: 18 | return Padding(left=horizontal, top=vertical, right=horizontal, bottom=vertical) 19 | 20 | 21 | def only( 22 | left: float = 0, top: float = 0, right: float = 0, bottom: float = 0 23 | ) -> Padding: 24 | return Padding(left=left, top=top, right=right, bottom=bottom) 25 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/ref.py: -------------------------------------------------------------------------------- 1 | from typing import Generic, TypeVar 2 | 3 | T = TypeVar("T") 4 | 5 | 6 | class Ref(Generic[T]): 7 | def __init__(self): 8 | self._current: T = None 9 | 10 | @property 11 | def current(self) -> T: 12 | return self._current 13 | 14 | @current.setter 15 | def current(self, value: T): 16 | self._current = value 17 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/session_storage.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List 2 | 3 | 4 | class SessionStorage: 5 | def __init__(self, page): 6 | self.__page = page 7 | self.__store: Dict[str, Any] = {} 8 | 9 | def set(self, key: str, value: Any): 10 | self.__store[key] = value 11 | 12 | def get(self, key: str): 13 | return self.__store.get(key) 14 | 15 | def contains_key(self, key: str) -> bool: 16 | return key in self.__store 17 | 18 | def remove(self, key: str): 19 | self.__store.pop(key) 20 | 21 | def get_keys(self) -> List[str]: 22 | return list(self.__store.keys()) 23 | 24 | def clear(self): 25 | self.__store.clear() 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/template_route.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import repath 4 | 5 | 6 | class TemplateRoute: 7 | def __init__(self, route: str) -> None: 8 | self.__last_params = {} 9 | self.route = route 10 | 11 | def match(self, route_template: str) -> bool: 12 | # remove old properties 13 | for k in self.__last_params: 14 | setattr(self, k, None) 15 | 16 | # perform new match 17 | pattern = repath.pattern(route_template) 18 | match = re.match(pattern, self.route) 19 | 20 | if match: 21 | self.__last_params = match.groupdict() 22 | for k, v in self.__last_params.items(): 23 | setattr(self, k, v) 24 | return True 25 | return False 26 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/core/transform.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import Optional 3 | 4 | from flet.core.alignment import Alignment 5 | 6 | 7 | @dataclass 8 | class Scale: 9 | scale: Optional[float] = field(default=None) 10 | scale_x: Optional[float] = field(default=None) 11 | scale_y: Optional[float] = field(default=None) 12 | alignment: Optional[Alignment] = field(default=None) 13 | 14 | 15 | @dataclass 16 | class Rotate: 17 | angle: float 18 | alignment: Optional[Alignment] = field(default=None) 19 | 20 | 21 | @dataclass 22 | class Offset: 23 | x: float 24 | y: float 25 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/fastapi/__init__.py: -------------------------------------------------------------------------------- 1 | from flet_web.fastapi import * 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/map/__init__.py: -------------------------------------------------------------------------------- 1 | from flet.core.map.circle_layer import CircleLayer, CircleMarker 2 | from flet.core.map.map import ( 3 | Map, 4 | MapEvent, 5 | MapEventSource, 6 | MapHoverEvent, 7 | MapInteractionConfiguration, 8 | MapInteractiveFlag, 9 | MapLatitudeLongitude, 10 | MapLatitudeLongitudeBounds, 11 | MapMultiFingerGesture, 12 | MapPointerDeviceType, 13 | MapPointerEvent, 14 | MapPositionChangeEvent, 15 | MapTapEvent, 16 | ) 17 | from flet.core.map.marker_layer import Marker, MarkerLayer 18 | from flet.core.map.polygon_layer import PolygonLayer, PolygonMarker 19 | from flet.core.map.polyline_layer import ( 20 | DashedStrokePattern, 21 | DottedStrokePattern, 22 | PatternFit, 23 | PolylineLayer, 24 | PolylineMarker, 25 | SolidStrokePattern, 26 | ) 27 | from flet.core.map.rich_attribution import RichAttribution 28 | from flet.core.map.simple_attribution import SimpleAttribution 29 | from flet.core.map.text_source_attribution import TextSourceAttribution 30 | from flet.core.map.tile_layer import MapTileLayerEvictErrorTileStrategy, TileLayer 31 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/matplotlib_chart.py: -------------------------------------------------------------------------------- 1 | from flet.core.matplotlib_chart import MatplotlibChart 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/plotly_chart.py: -------------------------------------------------------------------------------- 1 | from flet.core.plotly_chart import PlotlyChart 2 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from flet.utils.browser import open_in_browser 2 | from flet.utils.classproperty import classproperty 3 | from flet.utils.deprecated import deprecated 4 | from flet.utils.files import ( 5 | cleanup_path, 6 | copy_tree, 7 | get_current_script_dir, 8 | is_within_directory, 9 | safe_tar_extractall, 10 | which, 11 | ) 12 | from flet.utils.hashing import calculate_file_hash, sha1 13 | from flet.utils.network import get_free_tcp_port, get_local_ip 14 | from flet.utils.once import Once 15 | from flet.utils.platform_utils import ( 16 | get_arch, 17 | get_bool_env_var, 18 | get_platform, 19 | is_android, 20 | is_asyncio, 21 | is_embedded, 22 | is_ios, 23 | is_linux, 24 | is_linux_server, 25 | is_macos, 26 | is_mobile, 27 | is_pyodide, 28 | is_windows, 29 | ) 30 | from flet.utils.slugify import slugify 31 | from flet.utils.strings import random_string 32 | from flet.utils.vector import Vector 33 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/browser.py: -------------------------------------------------------------------------------- 1 | from flet.utils.platform_utils import is_mobile 2 | 3 | 4 | def open_in_browser(url): 5 | if not is_mobile(): 6 | import webbrowser 7 | 8 | webbrowser.open(url) 9 | 10 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/classproperty.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, Type, Any, Callable 2 | 3 | 4 | T = TypeVar("T") 5 | 6 | 7 | class classproperty: 8 | def __init__(self, func: Callable[[Type[T]], Any]) -> None: 9 | self.fget = func 10 | 11 | def __get__(self, instance: T, owner: Type[T]) -> Any: 12 | return self.fget(owner) 13 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/hashing.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | 4 | def sha1(input_string): 5 | sha1_hash = hashlib.sha1() 6 | sha1_hash.update(input_string.encode("utf-8")) 7 | return sha1_hash.hexdigest() 8 | 9 | 10 | def calculate_file_hash(path, blocksize=65536): 11 | h = hashlib.sha256() 12 | with open(path, "rb") as f: 13 | while True: 14 | data = f.read(blocksize) 15 | if not data: 16 | break 17 | h.update(data) 18 | return h.hexdigest() 19 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/network.py: -------------------------------------------------------------------------------- 1 | 2 | import socket 3 | 4 | 5 | def get_free_tcp_port(): 6 | sock = socket.socket() 7 | sock.bind(("", 0)) 8 | return sock.getsockname()[1] 9 | 10 | 11 | def get_local_ip(): 12 | try: 13 | with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: 14 | s.connect(("8.8.8.8", 80)) 15 | local_ip = s.getsockname()[0] 16 | return local_ip 17 | except Exception: 18 | hostname = socket.gethostname() 19 | return socket.gethostbyname(hostname) 20 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/once.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | 4 | class Once: 5 | def __init__(self): 6 | self._lock = asyncio.Lock() 7 | self._done = False 8 | 9 | async def do(self, func, *args, **kwargs): 10 | if not self._done: 11 | async with self._lock: 12 | if not self._done: 13 | await func(*args, **kwargs) 14 | self._done = True 15 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/slugify.py: -------------------------------------------------------------------------------- 1 | import re 2 | import unicodedata 3 | 4 | 5 | def slugify(value: str) -> str: 6 | """ 7 | Converts to lowercase, removes non-word characters (alphanumerics and underscores) 8 | and converts spaces to hyphens. Also strips leading and trailing whitespace. 9 | """ 10 | value = ( 11 | unicodedata.normalize("NFKD", value).encode("ascii", "ignore").decode("ascii") 12 | ) 13 | value = re.sub(r"[^\w\s-]", "", value).strip().lower() 14 | return re.sub(r"[-_\s]+", "-", value).strip("-") 15 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/src/flet/utils/strings.py: -------------------------------------------------------------------------------- 1 | import secrets 2 | import string 3 | 4 | 5 | def random_string(length): 6 | alphabet = string.ascii_letters + string.digits 7 | return "".join(secrets.choice(alphabet) for _ in range(length)) 8 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flet-dev/flet/1c040efec481463edbbc41101f7e4db23fdbddac/sdk/python/packages/flet/tests/__init__.py -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_checkbox.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.Checkbox() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["checkbox"], 14 | attrs={}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_label_position_enum(): 21 | r = ft.Checkbox(label_position=ft.LabelPosition.LEFT) 22 | assert isinstance(r.label_position, ft.LabelPosition) 23 | assert isinstance(r._get_attr("labelPosition"), str) 24 | cmd = r._build_add_commands() 25 | assert cmd[0].attrs["labelposition"] == "left" 26 | 27 | 28 | def test_label_position_str(): 29 | r = ft.Checkbox(label_position="left") 30 | assert isinstance(r.label_position, str) 31 | assert isinstance(r._get_attr("labelPosition"), str) 32 | cmd = r._build_add_commands() 33 | assert cmd[0].attrs["labelposition"] == "left" 34 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_colors.py: -------------------------------------------------------------------------------- 1 | import flet as ft 2 | 3 | 4 | def test_material_colors_random_with_weights_and_exclude(): 5 | """Test random material color selection with weights and exclusion list.""" 6 | results = [ 7 | ft.Colors.random( 8 | exclude=[ft.Colors.RED], 9 | weights={ft.Colors.BLUE: 150}, 10 | ) 11 | for _ in range(1000) 12 | ] 13 | assert ft.Colors.RED not in results 14 | assert ft.Colors.BLUE in results 15 | 16 | 17 | def test_cupertino_colors_random_with_weights_and_exclude(): 18 | """Test random cupertino color selection with weights and exclusion list.""" 19 | results = [ 20 | ft.CupertinoColors.random( 21 | exclude=[ft.CupertinoColors.SYSTEM_RED], 22 | weights={ft.CupertinoColors.SEPARATOR: 150}, 23 | ) 24 | for _ in range(1000) 25 | ] 26 | assert ft.CupertinoColors.SYSTEM_RED not in results 27 | assert ft.CupertinoColors.SEPARATOR in results 28 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_dropdown.py: -------------------------------------------------------------------------------- 1 | import flet as ft 2 | from flet.core.protocol import Command 3 | 4 | 5 | def test_instance_no_attrs_set(): 6 | r = ft.Dropdown() 7 | assert isinstance(r, ft.Control) 8 | assert r._build_add_commands() == [ 9 | Command( 10 | indent=0, 11 | name=None, 12 | values=["dropdown"], 13 | attrs={}, 14 | commands=[], 15 | ) 16 | ], "Test failed" 17 | 18 | 19 | def test_border_enum(): 20 | r = ft.Dropdown() 21 | assert r.border is None 22 | assert r._get_attr("border") is None 23 | 24 | r = ft.Dropdown(border=ft.InputBorder.OUTLINE) 25 | assert isinstance(r.border, ft.InputBorder) 26 | assert r.border == ft.InputBorder.OUTLINE 27 | assert r._get_attr("border") == "outline" 28 | 29 | r = ft.Dropdown(border="none") 30 | assert isinstance(r.border, str) 31 | assert r._get_attr("border") == "none" 32 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_file_picker.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.FilePicker() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["filepicker"], 14 | attrs={"upload": "[]"}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_file_type_enum(): 21 | r = ft.FilePicker() 22 | r.file_type = ft.FilePickerFileType.VIDEO 23 | assert isinstance(r.file_type, ft.FilePickerFileType) 24 | assert r.file_type == ft.FilePickerFileType.VIDEO 25 | assert r._get_attr("fileType") == "video" 26 | 27 | r = ft.FilePicker() 28 | r.file_type = "any" 29 | assert isinstance(r.file_type, str) 30 | assert r._get_attr("fileType") == "any" 31 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_icons.py: -------------------------------------------------------------------------------- 1 | import flet as ft 2 | 3 | 4 | def test_material_icons_random_with_weights_and_exclude(): 5 | """Test random material icon selection with weights and exclusion list.""" 6 | results = [ 7 | ft.Icons.random( 8 | exclude=[ft.Icons.FAVORITE], 9 | weights={ft.Icons.SCHOOL: 150}, 10 | ) 11 | for _ in range(1000) 12 | ] 13 | assert ft.Icons.FAVORITE not in results 14 | assert ft.Icons.SCHOOL in results 15 | 16 | 17 | def test_cupertino_icons_random_with_weights_and_exclude(): 18 | """Test random cupertino icon selection with weights and exclusion list.""" 19 | results = [ 20 | ft.CupertinoIcons.random( 21 | exclude=[ft.CupertinoIcons.CAMERA], 22 | weights={ft.CupertinoIcons.TABLE: 150}, 23 | ) 24 | for _ in range(1000) 25 | ] 26 | assert ft.CupertinoIcons.CAMERA not in results 27 | assert ft.CupertinoIcons.TABLE in results 28 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_markdown.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.Markdown() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["markdown"], 14 | attrs={}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_extension_set_enum(): 21 | r = ft.Markdown() 22 | assert r.extension_set is None 23 | assert r._get_attr("extensionSet") is None 24 | 25 | r = ft.Markdown(extension_set=ft.MarkdownExtensionSet.COMMON_MARK) 26 | assert isinstance(r.extension_set, ft.MarkdownExtensionSet) 27 | assert r.extension_set == ft.MarkdownExtensionSet.COMMON_MARK 28 | assert r._get_attr("extensionSet") == "commonMark" 29 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_navigation_bar.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.NavigationBar() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["navigationbar"], 14 | attrs={}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_extension_set_enum(): 21 | r = ft.NavigationBar() 22 | assert r.label_behavior is None 23 | assert r._get_attr("labelBehavior") is None 24 | 25 | r = ft.NavigationBar(label_behavior=ft.NavigationBarLabelBehavior.ALWAYS_SHOW) 26 | assert isinstance(r.label_behavior, ft.NavigationBarLabelBehavior) 27 | assert r.label_behavior == ft.NavigationBarLabelBehavior.ALWAYS_SHOW 28 | assert r._get_attr("labelBehavior") == "alwaysShow" 29 | 30 | r = ft.NavigationBar(label_behavior="alwaysHide") 31 | assert isinstance(r.label_behavior, str) 32 | assert r._get_attr("labelBehavior") == "alwaysHide" 33 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_navigation_rail.py: -------------------------------------------------------------------------------- 1 | import flet as ft 2 | from flet.core.protocol import Command 3 | 4 | 5 | def test_instance_no_attrs_set(): 6 | r = ft.NavigationRail() 7 | assert isinstance(r, ft.Control) 8 | assert r._build_add_commands() == [ 9 | Command( 10 | indent=0, 11 | name=None, 12 | values=["navigationrail"], 13 | attrs={"rtl": "false"}, 14 | commands=[], 15 | ) 16 | ], "Test failed" 17 | 18 | 19 | def test_extension_set_enum(): 20 | r = ft.NavigationRail() 21 | assert r.label_type is None 22 | assert r._get_attr("labelType") is None 23 | 24 | r = ft.NavigationRail(label_type=ft.NavigationRailLabelType.SELECTED) 25 | assert isinstance(r.label_type, ft.NavigationRailLabelType) 26 | assert r.label_type == ft.NavigationRailLabelType.SELECTED 27 | assert r._get_attr("labelType") == "selected" 28 | 29 | r = ft.NavigationRail(label_type="none") 30 | assert isinstance(r.label_type, str) 31 | assert r._get_attr("labelType") == "none" 32 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_page.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.skip(reason="no way of currently testing this") 5 | def test_page(page): 6 | assert page.url != "" and page.url.startswith("http"), "Test failed" 7 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_radio.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.Radio() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["radio"], 14 | attrs={}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_label_position_enum(): 21 | r = ft.Radio(label_position=ft.LabelPosition.LEFT) 22 | assert isinstance(r.label_position, ft.LabelPosition) 23 | assert isinstance(r._get_attr("labelPosition"), str) 24 | cmd = r._build_add_commands() 25 | assert cmd[0].attrs["labelposition"] == "left" 26 | 27 | 28 | def test_label_position_str(): 29 | r = ft.Radio(label_position="left") 30 | assert isinstance(r.label_position, str) 31 | assert isinstance(r._get_attr("labelPosition"), str) 32 | cmd = r._build_add_commands() 33 | assert cmd[0].attrs["labelposition"] == "left" 34 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_shader_mask.py: -------------------------------------------------------------------------------- 1 | import flet as ft 2 | from flet.core.protocol import Command 3 | 4 | 5 | def test_instance_no_attrs_set(): 6 | r = ft.ShaderMask(shader=ft.LinearGradient(colors=[ft.Colors.BLUE])) 7 | assert isinstance(r, ft.Control) 8 | assert r._build_add_commands() == [ 9 | Command( 10 | indent=0, 11 | name=None, 12 | values=["shadermask"], 13 | attrs={ 14 | "shader": '{"colors":["blue"],"tile_mode":"clamp","begin":{"x":-1,"y":0},"end":{"x":1,"y":0},"type":"linear"}' 15 | }, 16 | commands=[], 17 | ) 18 | ], "Test failed" 19 | 20 | 21 | def test_blend_mode_enum(): 22 | r = ft.ShaderMask( 23 | shader=ft.LinearGradient(colors=[ft.Colors.BLUE]), 24 | blend_mode=ft.BlendMode.LIGHTEN, 25 | ) 26 | assert isinstance(r.blend_mode, ft.BlendMode) 27 | assert isinstance(r._get_attr("blendMode"), str) 28 | cmd = r._build_add_commands() 29 | assert cmd[0].attrs["blendmode"] == "lighten" 30 | 31 | 32 | def test_blend_mode_str(): 33 | r = ft.ShaderMask( 34 | shader=ft.LinearGradient(colors=[ft.Colors.BLUE]), blend_mode="darken" 35 | ) 36 | assert isinstance(r.blend_mode, str) 37 | assert isinstance(r._get_attr("blendMode"), str) 38 | cmd = r._build_add_commands() 39 | assert cmd[0].attrs["blendmode"] == "darken" 40 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_stack.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.Stack() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["stack"], 14 | attrs={}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_clip_behavior_enum(): 21 | r = ft.Stack() 22 | assert r.clip_behavior is None 23 | assert r._get_attr("clipBehavior") is None 24 | 25 | r = ft.Stack(clip_behavior=ft.ClipBehavior.ANTI_ALIAS) 26 | assert isinstance(r.clip_behavior, ft.ClipBehavior) 27 | assert r.clip_behavior == ft.ClipBehavior.ANTI_ALIAS 28 | assert r._get_attr("clipBehavior") == "antiAlias" 29 | 30 | r = ft.Stack(clip_behavior="none") 31 | assert isinstance(r.clip_behavior, str) 32 | assert r._get_attr("clipBehavior") == "none" 33 | -------------------------------------------------------------------------------- /sdk/python/packages/flet/tests/test_switch.py: -------------------------------------------------------------------------------- 1 | from flet.core.protocol import Command 2 | 3 | import flet as ft 4 | 5 | 6 | def test_instance_no_attrs_set(): 7 | r = ft.Switch() 8 | assert isinstance(r, ft.Control) 9 | assert r._build_add_commands() == [ 10 | Command( 11 | indent=0, 12 | name=None, 13 | values=["switch"], 14 | attrs={}, 15 | commands=[], 16 | ) 17 | ], "Test failed" 18 | 19 | 20 | def test_label_position_enum(): 21 | r = ft.Switch(label_position=ft.LabelPosition.LEFT) 22 | assert isinstance(r.label_position, ft.LabelPosition) 23 | assert isinstance(r._get_attr("labelPosition"), str) 24 | cmd = r._build_add_commands() 25 | assert cmd[0].attrs["labelposition"] == "left" 26 | 27 | 28 | def test_label_position_str(): 29 | r = ft.Switch(label_position="left") 30 | assert isinstance(r.label_position, str) 31 | assert isinstance(r._get_attr("labelPosition"), str) 32 | cmd = r._build_add_commands() 33 | assert cmd[0].attrs["labelposition"] == "left" 34 | -------------------------------------------------------------------------------- /sdk/python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "flet-project" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Appveyor Systems Inc. "] 6 | license = "Apache-2.0" 7 | package-mode = false 8 | 9 | [tool.poetry.dependencies] 10 | python = ">=3.9,<3.14" 11 | 12 | [tool.poetry.group.dev.dependencies] 13 | flet-cli = {path = "packages/flet-cli", develop = true} 14 | flet-desktop = {path = "packages/flet-desktop", develop = true} 15 | flet-web = {path = "packages/flet-web", develop = true} 16 | flet = {path = "packages/flet", develop = true} 17 | pytest = "^7.2.0" 18 | black = "^22.12.0" 19 | tomlkit = "^0.11.6" 20 | cryptography = "^39.0.0" 21 | pyinstaller = "^6.6.0" 22 | pillow = "^10.3.0" 23 | pre-commit = "^2.21.0" 24 | hypercorn = "^0.14.4" 25 | gunicorn = "^21.2.0" 26 | pypi-cleanup = "0.1.4" 27 | 28 | [build-system] 29 | requires = ["poetry-core"] 30 | build-backend = "poetry.core.masonry.api" 31 | --------------------------------------------------------------------------------