ruflet 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ruflet/version.rb +1 -1
- data/lib/ruflet_ui/ruflet/app.rb +10 -14
- data/lib/ruflet_ui/ruflet/control.rb +120 -7
- data/lib/ruflet_ui/ruflet/dsl.rb +68 -4
- data/lib/ruflet_ui/ruflet/event.rb +15 -1
- data/lib/ruflet_ui/ruflet/events/gesture_events.rb +552 -0
- data/lib/ruflet_ui/ruflet/page.rb +600 -73
- data/lib/ruflet_ui/ruflet/types/geometry.rb +65 -0
- data/lib/ruflet_ui/ruflet/types/text_style.rb +191 -0
- data/lib/ruflet_ui/ruflet/ui/control_factory.rb +35 -5
- data/lib/ruflet_ui/ruflet/ui/control_methods.rb +1 -0
- data/lib/ruflet_ui/ruflet/ui/control_registry.rb +22 -2
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheet_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheetaction_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactivityindicator_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoalertdialog_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoappbar_control.rb +44 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobottomsheet_control.rb +38 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocheckbox_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenu_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenuaction_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodatepicker_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodialogaction_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinofilledbutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinolisttile_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinonavigationbar_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinopicker_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoradio_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinosegmentedbutton_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslider_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslidingsegmentedbutton_control.rb +60 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoswitch_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotextfield_control.rb +159 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotimerpicker_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotintedbutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/ruflet_controls.rb +89 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/alertdialog_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/appbar_control.rb +53 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/audio_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/autocomplete_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/badge_control.rb +31 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/banner_control.rb +47 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomappbar_control.rb +62 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomsheet_control.rb +48 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/button_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/card_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chart_controls.rb +321 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/checkbox_control.rb +76 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chip_control.rb +88 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/circleavatar_control.rb +62 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/container_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/contextmenu_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacell_control.rb +38 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacolumn_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datarow_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datatable_control.rb +78 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datepicker_control.rb +55 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/daterangepicker_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/divider_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdown_control.rb +99 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownm2_control.rb +119 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownoption_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanel_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanellist_control.rb +60 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansiontile_control.rb +82 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledbutton_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/fillediconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonalbutton_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonaliconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/floatingactionbutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/iconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/listtile_control.rb +87 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menubar_control.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menuitembutton_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbar_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbardestination_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawer_control.rb +41 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawerdestination_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationrail_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationraildestination_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/option_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinedbutton_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinediconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenubutton_control.rb +74 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenuitem_control.rb +38 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressbar_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressring_control.rb +65 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/radio_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/radiogroup_control.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/rangeslider_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/reorderablelistview_control.rb +80 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/ruflet_controls.rb +252 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/searchbar_control.rb +94 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segment_control.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segmentedbutton_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/selectionarea_control.rb +32 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/slider_control.rb +76 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/snackbar_control.rb +51 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/submenubutton_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/switch_control.rb +77 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tab_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbar_control.rb +77 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbarview_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabs_control.rb +59 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textbutton_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textfield_control.rb +148 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/timepicker_control.rb +50 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/verticaldivider_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/video_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/webview_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/ruflet_controls.rb +447 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/animatedswitcher_control.rb +59 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/arc_control.rb +29 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/autofillgroup_control.rb +32 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/basepage_control.rb +44 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/browsercontextmenu_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/canvas_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/circle_control.rb +25 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/color_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/column_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dialogs_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dismissible_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/draggable_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dragtarget_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/fill_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/fletapp_control.rb +62 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gesturedetector_control.rb +129 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gridview_control.rb +71 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/hero_control.rb +56 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/icon_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/image_control.rb +27 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/interactiveviewer_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/keyboardlistener_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/line_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/listview_control.rb +71 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/markdown_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/mergesemantics_control.rb +31 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/oval_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/overlay_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/page_control.rb +74 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pagelet_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pageview_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/path_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/placeholder_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/points_control.rb +24 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/rect_control.rb +27 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/reorderabledraghandle_control.rb +56 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/responsiverow_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/row_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/ruflet_controls.rb +140 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/safearea_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/semantics_control.rb +79 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/serviceregistry_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shadermask_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shadow_control.rb +25 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shimmer_control.rb +60 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/stack_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/text_control.rb +32 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/textspan_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/transparentpointer_control.rb +54 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/view_control.rb +77 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/window_control.rb +56 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/windowdragarea_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_factory.rb +3 -30
- data/lib/ruflet_ui/ruflet/ui/material_control_factory.rb +3 -87
- data/lib/ruflet_ui/ruflet/ui/material_control_methods.rb +44 -2
- data/lib/ruflet_ui/ruflet/ui/material_control_registry.rb +26 -12
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/accelerometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/barometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/battery_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/camera_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/clipboard_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/connectivity_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/filepicker_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/flashlight_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/gyroscope_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/hapticfeedback_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/magnetometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/screenbrightness_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/screenshot_control.rb +31 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/semanticsservice_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/shakedetector_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/share_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/sharedpreferences_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/storagepaths_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/urllauncher_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/useraccelerometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/wakelock_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet_services.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/shared_control_forwarders.rb +41 -1
- data/lib/ruflet_ui/ruflet/ui/widget_builder.rb +9 -0
- data/lib/ruflet_ui.rb +14 -1
- metadata +178 -44
- data/lib/ruflet/manifest_compiler.rb +0 -62
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_action_sheet_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_alert_dialog_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_button_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_dialog_action_control.rb +0 -24
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_filled_button_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_navigation_bar_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_slider_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_switch_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/cupertino/cupertino_text_field_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/alert_dialog_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/app_bar_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/bottom_sheet_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/button_control.rb +0 -24
- data/lib/ruflet_ui/ruflet/ui/controls/material/checkbox_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/column_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/container_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/drag_target_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/draggable_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/elevated_button_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/filled_button_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/floating_action_button_control.rb +0 -28
- data/lib/ruflet_ui/ruflet/ui/controls/material/gesture_detector_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/grid_view_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/icon_button_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/icon_control.rb +0 -24
- data/lib/ruflet_ui/ruflet/ui/controls/material/image_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/markdown_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/navigation_bar_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/navigation_bar_destination_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/radio_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/radio_group_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/row_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/snack_bar_control.rb +0 -68
- data/lib/ruflet_ui/ruflet/ui/controls/material/stack_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/tab_bar_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/tab_bar_view_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/tab_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/tabs_control.rb +0 -63
- data/lib/ruflet_ui/ruflet/ui/controls/material/text_button_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/text_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/text_field_control.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/controls/material/view_control.rb +0 -13
|
@@ -4,28 +4,23 @@ require_relative "event"
|
|
|
4
4
|
require "ruflet_protocol"
|
|
5
5
|
require_relative "control"
|
|
6
6
|
require_relative "ui/widget_builder"
|
|
7
|
+
require_relative "ui/control_factory"
|
|
7
8
|
require_relative "icons/material_icon_lookup"
|
|
8
9
|
require_relative "icons/cupertino_icon_lookup"
|
|
9
10
|
require "set"
|
|
10
11
|
require "cgi"
|
|
12
|
+
require "thread"
|
|
13
|
+
require "timeout"
|
|
11
14
|
|
|
12
15
|
module Ruflet
|
|
13
16
|
class Page
|
|
14
17
|
PAGE_PROP_KEYS = %w[route title vertical_alignment horizontal_alignment scroll].freeze
|
|
15
18
|
DIALOG_PROP_KEYS = %w[dialog snack_bar bottom_sheet].freeze
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
alert_dialog alertdialog markdown icon image app_bar appbar floating_action_button snack_bar snackbar
|
|
22
|
-
bottom_sheet bottomsheet tabs tab tab_bar tabbar tab_bar_view tabbarview navigation_bar navigationbar
|
|
23
|
-
navigation_bar_destination navigationbardestination fab cupertino_button
|
|
24
|
-
cupertinobutton cupertino_filled_button cupertinofilledbutton cupertino_text_field cupertinotextfield
|
|
25
|
-
cupertino_switch cupertinoswitch cupertino_slider cupertinoslider cupertino_alert_dialog
|
|
26
|
-
cupertinoalertdialog cupertino_action_sheet cupertinoactionsheet cupertino_dialog_action
|
|
27
|
-
cupertinodialogaction cupertino_navigation_bar cupertinonavigationbar
|
|
28
|
-
].freeze
|
|
19
|
+
WIDGET_HELPER_METHODS = (
|
|
20
|
+
Ruflet::UI::MaterialControlMethods.instance_methods(false) +
|
|
21
|
+
Ruflet::UI::CupertinoControlMethods.instance_methods(false) +
|
|
22
|
+
%i[control widget]
|
|
23
|
+
).map(&:to_s).to_set.freeze
|
|
29
24
|
|
|
30
25
|
attr_reader :session_id, :client_details, :views
|
|
31
26
|
|
|
@@ -51,13 +46,17 @@ module Ruflet
|
|
|
51
46
|
@services_container = Ruflet::Control.new(
|
|
52
47
|
type: "service_registry",
|
|
53
48
|
id: "_services",
|
|
54
|
-
"_services": []
|
|
49
|
+
"_services": [],
|
|
50
|
+
"_internals": { "uid" => Ruflet::Control.generate_id }
|
|
55
51
|
)
|
|
56
52
|
@dialogs_container = Ruflet::Control.new(
|
|
57
53
|
type: "dialogs",
|
|
58
54
|
id: "_dialogs",
|
|
59
55
|
controls: []
|
|
60
56
|
)
|
|
57
|
+
@invoke_waiters = {}
|
|
58
|
+
@invoke_callbacks = {}
|
|
59
|
+
@invoke_waiters_mutex = Mutex.new
|
|
61
60
|
refresh_overlay_container!
|
|
62
61
|
refresh_services_container!
|
|
63
62
|
refresh_dialogs_container!
|
|
@@ -156,6 +155,45 @@ module Ruflet
|
|
|
156
155
|
self
|
|
157
156
|
end
|
|
158
157
|
|
|
158
|
+
def remove_service(*value)
|
|
159
|
+
targets = value.flatten.compact
|
|
160
|
+
return self if targets.empty?
|
|
161
|
+
|
|
162
|
+
@services_container.props["_services"] = services.reject do |service|
|
|
163
|
+
targets.any? do |target|
|
|
164
|
+
case target
|
|
165
|
+
when Control
|
|
166
|
+
service.equal?(target) || (!target.id.nil? && service.id.to_s == target.id.to_s)
|
|
167
|
+
else
|
|
168
|
+
needle = target.to_s
|
|
169
|
+
service.id.to_s == needle || service.type.to_s.downcase == needle.downcase
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
refresh_services_container!
|
|
175
|
+
push_services_update!
|
|
176
|
+
self
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def service(type, **props)
|
|
180
|
+
mapped_props = normalize_props(props || {})
|
|
181
|
+
id = mapped_props.delete("id")
|
|
182
|
+
normalized_type = type.to_s.downcase
|
|
183
|
+
|
|
184
|
+
existing =
|
|
185
|
+
if id
|
|
186
|
+
services.find { |s| s.is_a?(Control) && s.id.to_s == id.to_s }
|
|
187
|
+
else
|
|
188
|
+
services.find { |s| s.is_a?(Control) && s.type.to_s.downcase == normalized_type }
|
|
189
|
+
end
|
|
190
|
+
return existing if existing
|
|
191
|
+
|
|
192
|
+
svc = Ruflet::UI::ControlFactory.build(type.to_s, id: id&.to_s, **mapped_props)
|
|
193
|
+
add_service(svc) unless services.include?(svc)
|
|
194
|
+
svc
|
|
195
|
+
end
|
|
196
|
+
|
|
159
197
|
def go(route, **query_params)
|
|
160
198
|
@page_props["route"] = build_route(route, query_params)
|
|
161
199
|
dispatch_page_event(name: "route_change", data: @page_props["route"])
|
|
@@ -228,71 +266,327 @@ module Ruflet
|
|
|
228
266
|
self
|
|
229
267
|
end
|
|
230
268
|
|
|
231
|
-
def invoke(control_or_id, method_name, args: nil, timeout: 10)
|
|
232
|
-
|
|
233
|
-
|
|
269
|
+
def invoke(control_or_id, method_name, args: nil, timeout: 10, on_result: nil)
|
|
270
|
+
control_id =
|
|
271
|
+
if page_control_target?(control_or_id)
|
|
272
|
+
1
|
|
273
|
+
else
|
|
274
|
+
control = resolve_control(control_or_id)
|
|
275
|
+
return nil unless control
|
|
276
|
+
control.wire_id
|
|
277
|
+
end
|
|
234
278
|
|
|
235
279
|
call_id = "call_#{Ruflet::Control.generate_id}"
|
|
236
|
-
|
|
237
|
-
|
|
280
|
+
if on_result.respond_to?(:call)
|
|
281
|
+
@invoke_waiters_mutex.synchronize { @invoke_callbacks[call_id] = on_result }
|
|
282
|
+
unless timeout.nil?
|
|
283
|
+
Thread.new(call_id, timeout.to_f) do |pending_call_id, invoke_timeout|
|
|
284
|
+
sleep([invoke_timeout, 0.0].max + 0.1)
|
|
285
|
+
callback = @invoke_waiters_mutex.synchronize { @invoke_callbacks.delete(pending_call_id) }
|
|
286
|
+
callback&.call(nil, "execution expired")
|
|
287
|
+
rescue StandardError => e
|
|
288
|
+
Kernel.warn("invoke timeout callback error: #{e.class}: #{e.message}")
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
payload = {
|
|
293
|
+
"control_id" => control_id,
|
|
238
294
|
"call_id" => call_id,
|
|
239
295
|
"name" => method_name.to_s,
|
|
240
|
-
"args" => args
|
|
241
|
-
|
|
242
|
-
|
|
296
|
+
"args" => args
|
|
297
|
+
}
|
|
298
|
+
payload["timeout"] = timeout unless timeout.nil?
|
|
299
|
+
send_message(Protocol::ACTIONS[:invoke_control_method], payload)
|
|
243
300
|
|
|
244
301
|
call_id
|
|
245
302
|
end
|
|
246
303
|
|
|
247
|
-
|
|
248
|
-
|
|
304
|
+
# Synchronous invoke for controls/services that must return a value
|
|
305
|
+
# before continuing (e.g. picker selection, camera discovery/init).
|
|
306
|
+
def invoke_sync(control_or_id, method_name, args: nil, timeout: 10)
|
|
307
|
+
invoke_and_wait(control_or_id, method_name, args: args, timeout: timeout)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def launch_url(url, mode: nil, web_view_configuration: nil, browser_configuration: nil, web_only_window_name: nil, timeout: 10, on_result: nil)
|
|
311
|
+
url_launcher = ensure_url_launcher_service
|
|
312
|
+
args = { "url" => url }
|
|
313
|
+
args["mode"] = mode unless mode.nil?
|
|
314
|
+
args["web_view_configuration"] = web_view_configuration unless web_view_configuration.nil?
|
|
315
|
+
args["browser_configuration"] = browser_configuration unless browser_configuration.nil?
|
|
316
|
+
args["web_only_window_name"] = web_only_window_name unless web_only_window_name.nil?
|
|
249
317
|
invoke(
|
|
250
|
-
|
|
318
|
+
url_launcher,
|
|
251
319
|
"launch_url",
|
|
252
|
-
args:
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"web_view_configuration" => web_view_configuration,
|
|
256
|
-
"browser_configuration" => browser_configuration,
|
|
257
|
-
"web_only_window_name" => web_only_window_name
|
|
258
|
-
}.compact,
|
|
259
|
-
timeout: timeout
|
|
320
|
+
args: args,
|
|
321
|
+
timeout: timeout,
|
|
322
|
+
on_result: on_result
|
|
260
323
|
)
|
|
261
324
|
end
|
|
262
325
|
|
|
263
326
|
def can_launch_url(url, timeout: 10)
|
|
264
|
-
|
|
265
|
-
invoke(
|
|
327
|
+
url_launcher = ensure_url_launcher_service
|
|
328
|
+
invoke(url_launcher, "can_launch_url", args: { "url" => url }, timeout: timeout)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# File picker helpers: create an ephemeral service, invoke method, and dispose it.
|
|
332
|
+
def pick_files(
|
|
333
|
+
dialog_title: nil,
|
|
334
|
+
initial_directory: nil,
|
|
335
|
+
file_type: "any",
|
|
336
|
+
allowed_extensions: nil,
|
|
337
|
+
allow_multiple: false,
|
|
338
|
+
with_data: false,
|
|
339
|
+
timeout: nil,
|
|
340
|
+
on_result: nil
|
|
341
|
+
)
|
|
342
|
+
invoke_file_picker(
|
|
343
|
+
"pick_files",
|
|
344
|
+
{
|
|
345
|
+
"dialog_title" => dialog_title,
|
|
346
|
+
"initial_directory" => initial_directory,
|
|
347
|
+
"file_type" => file_type,
|
|
348
|
+
"allowed_extensions" => allowed_extensions,
|
|
349
|
+
"allow_multiple" => allow_multiple,
|
|
350
|
+
"with_data" => with_data
|
|
351
|
+
},
|
|
352
|
+
timeout: timeout,
|
|
353
|
+
on_result: on_result
|
|
354
|
+
)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def save_file(
|
|
358
|
+
dialog_title: nil,
|
|
359
|
+
file_name: nil,
|
|
360
|
+
initial_directory: nil,
|
|
361
|
+
file_type: "any",
|
|
362
|
+
allowed_extensions: nil,
|
|
363
|
+
src_bytes: nil,
|
|
364
|
+
timeout: nil,
|
|
365
|
+
on_result: nil
|
|
366
|
+
)
|
|
367
|
+
invoke_file_picker(
|
|
368
|
+
"save_file",
|
|
369
|
+
{
|
|
370
|
+
"dialog_title" => dialog_title,
|
|
371
|
+
"file_name" => file_name,
|
|
372
|
+
"initial_directory" => initial_directory,
|
|
373
|
+
"file_type" => file_type,
|
|
374
|
+
"allowed_extensions" => allowed_extensions,
|
|
375
|
+
"src_bytes" => src_bytes
|
|
376
|
+
},
|
|
377
|
+
timeout: timeout,
|
|
378
|
+
on_result: on_result
|
|
379
|
+
)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def get_directory_path(dialog_title: nil, initial_directory: nil, timeout: nil, on_result: nil)
|
|
383
|
+
invoke_file_picker(
|
|
384
|
+
"get_directory_path",
|
|
385
|
+
{
|
|
386
|
+
"dialog_title" => dialog_title,
|
|
387
|
+
"initial_directory" => initial_directory
|
|
388
|
+
},
|
|
389
|
+
timeout: timeout,
|
|
390
|
+
on_result: on_result
|
|
391
|
+
)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def set_clipboard(value, timeout: nil, on_result: nil)
|
|
395
|
+
invoke_clipboard_method(
|
|
396
|
+
"set_data",
|
|
397
|
+
args: { "data" => value.to_s },
|
|
398
|
+
timeout: timeout,
|
|
399
|
+
on_result: on_result
|
|
400
|
+
)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def get_clipboard(timeout: nil, on_result: nil)
|
|
404
|
+
invoke_clipboard_method("get_data", timeout: timeout, on_result: on_result)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def set_clipboard_files(files, timeout: nil, on_result: nil)
|
|
408
|
+
invoke_clipboard_method(
|
|
409
|
+
"set_files",
|
|
410
|
+
args: { "files" => Array(files).map(&:to_s) },
|
|
411
|
+
timeout: timeout,
|
|
412
|
+
on_result: on_result
|
|
413
|
+
)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def get_clipboard_files(timeout: nil, on_result: nil)
|
|
417
|
+
invoke_clipboard_method("get_files", timeout: timeout, on_result: on_result)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def set_clipboard_image(value, timeout: nil, on_result: nil)
|
|
421
|
+
invoke_clipboard_method(
|
|
422
|
+
"set_image",
|
|
423
|
+
args: { "data" => value },
|
|
424
|
+
timeout: timeout,
|
|
425
|
+
on_result: on_result
|
|
426
|
+
)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def get_clipboard_image(timeout: nil, on_result: nil)
|
|
430
|
+
invoke_clipboard_method("get_image", timeout: timeout, on_result: on_result)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def get_connectivity(timeout: nil, on_result: nil)
|
|
434
|
+
invoke_connectivity_method("get_connectivity", timeout: timeout, on_result: on_result)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def get_battery_level(timeout: nil, on_result: nil)
|
|
438
|
+
invoke_battery_method("get_battery_level", timeout: timeout, on_result: on_result)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def get_battery_state(timeout: nil, on_result: nil)
|
|
442
|
+
invoke_battery_method("get_battery_state", timeout: timeout, on_result: on_result)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def battery_save_mode?(timeout: nil, on_result: nil)
|
|
446
|
+
invoke_battery_method("is_in_battery_save_mode", timeout: timeout, on_result: on_result)
|
|
266
447
|
end
|
|
267
448
|
|
|
268
|
-
def
|
|
269
|
-
|
|
270
|
-
invoke(clipboard, "set", args: { "data" => value.to_s }, timeout: timeout)
|
|
449
|
+
def get_application_cache_directory(timeout: nil, on_result: nil)
|
|
450
|
+
invoke_storage_paths("get_application_cache_directory", timeout: timeout, on_result: on_result)
|
|
271
451
|
end
|
|
272
452
|
|
|
273
|
-
def
|
|
274
|
-
|
|
275
|
-
invoke(clipboard, "get", timeout: timeout)
|
|
453
|
+
def get_application_documents_directory(timeout: nil, on_result: nil)
|
|
454
|
+
invoke_storage_paths("get_application_documents_directory", timeout: timeout, on_result: on_result)
|
|
276
455
|
end
|
|
277
456
|
|
|
278
|
-
def
|
|
279
|
-
|
|
280
|
-
|
|
457
|
+
def get_application_support_directory(timeout: nil, on_result: nil)
|
|
458
|
+
invoke_storage_paths("get_application_support_directory", timeout: timeout, on_result: on_result)
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
def get_downloads_directory(timeout: nil, on_result: nil)
|
|
462
|
+
invoke_storage_paths("get_downloads_directory", timeout: timeout, on_result: on_result)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def get_external_cache_directories(timeout: nil, on_result: nil)
|
|
466
|
+
invoke_storage_paths("get_external_cache_directories", timeout: timeout, on_result: on_result)
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def get_external_storage_directories(timeout: nil, on_result: nil)
|
|
470
|
+
invoke_storage_paths("get_external_storage_directories", timeout: timeout, on_result: on_result)
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def get_library_directory(timeout: nil, on_result: nil)
|
|
474
|
+
invoke_storage_paths("get_library_directory", timeout: timeout, on_result: on_result)
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def get_external_storage_directory(timeout: nil, on_result: nil)
|
|
478
|
+
invoke_storage_paths("get_external_storage_directory", timeout: timeout, on_result: on_result)
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
def get_temporary_directory(timeout: nil, on_result: nil)
|
|
482
|
+
invoke_storage_paths("get_temporary_directory", timeout: timeout, on_result: on_result)
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
def get_console_log_filename(timeout: nil, on_result: nil)
|
|
486
|
+
invoke_storage_paths("get_console_log_filename", timeout: timeout, on_result: on_result)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
def share_text(
|
|
490
|
+
text:,
|
|
491
|
+
title: nil,
|
|
492
|
+
subject: nil,
|
|
493
|
+
preview_thumbnail: nil,
|
|
494
|
+
share_position_origin: nil,
|
|
495
|
+
download_fallback_enabled: true,
|
|
496
|
+
mail_to_fallback_enabled: true,
|
|
497
|
+
excluded_cupertino_activities: nil,
|
|
498
|
+
timeout: nil,
|
|
499
|
+
on_result: nil
|
|
500
|
+
)
|
|
501
|
+
share = ensure_share_service
|
|
502
|
+
invoke(
|
|
503
|
+
share,
|
|
504
|
+
"share_text",
|
|
505
|
+
args: {
|
|
506
|
+
"text" => text,
|
|
507
|
+
"title" => title,
|
|
508
|
+
"subject" => subject,
|
|
509
|
+
"preview_thumbnail" => preview_thumbnail,
|
|
510
|
+
"share_position_origin" => share_position_origin,
|
|
511
|
+
"download_fallback_enabled" => download_fallback_enabled,
|
|
512
|
+
"mail_to_fallback_enabled" => mail_to_fallback_enabled,
|
|
513
|
+
"excluded_cupertino_activities" => excluded_cupertino_activities
|
|
514
|
+
},
|
|
515
|
+
timeout: timeout,
|
|
516
|
+
on_result: on_result
|
|
517
|
+
)
|
|
281
518
|
end
|
|
282
519
|
|
|
283
|
-
def
|
|
284
|
-
|
|
285
|
-
|
|
520
|
+
def share_uri(
|
|
521
|
+
uri:,
|
|
522
|
+
share_position_origin: nil,
|
|
523
|
+
excluded_cupertino_activities: nil,
|
|
524
|
+
timeout: nil,
|
|
525
|
+
on_result: nil
|
|
526
|
+
)
|
|
527
|
+
share = ensure_share_service
|
|
528
|
+
invoke(
|
|
529
|
+
share,
|
|
530
|
+
"share_uri",
|
|
531
|
+
args: {
|
|
532
|
+
"uri" => uri,
|
|
533
|
+
"share_position_origin" => share_position_origin,
|
|
534
|
+
"excluded_cupertino_activities" => excluded_cupertino_activities
|
|
535
|
+
},
|
|
536
|
+
timeout: timeout,
|
|
537
|
+
on_result: on_result
|
|
538
|
+
)
|
|
286
539
|
end
|
|
287
540
|
|
|
288
|
-
def
|
|
289
|
-
|
|
290
|
-
|
|
541
|
+
def share_files(
|
|
542
|
+
files:,
|
|
543
|
+
text: nil,
|
|
544
|
+
title: nil,
|
|
545
|
+
subject: nil,
|
|
546
|
+
preview_thumbnail: nil,
|
|
547
|
+
share_position_origin: nil,
|
|
548
|
+
download_fallback_enabled: true,
|
|
549
|
+
mail_to_fallback_enabled: true,
|
|
550
|
+
excluded_cupertino_activities: nil,
|
|
551
|
+
timeout: nil,
|
|
552
|
+
on_result: nil
|
|
553
|
+
)
|
|
554
|
+
share = ensure_share_service
|
|
555
|
+
invoke(
|
|
556
|
+
share,
|
|
557
|
+
"share_files",
|
|
558
|
+
args: {
|
|
559
|
+
"files" => files,
|
|
560
|
+
"text" => text,
|
|
561
|
+
"title" => title,
|
|
562
|
+
"subject" => subject,
|
|
563
|
+
"preview_thumbnail" => preview_thumbnail,
|
|
564
|
+
"share_position_origin" => share_position_origin,
|
|
565
|
+
"download_fallback_enabled" => download_fallback_enabled,
|
|
566
|
+
"mail_to_fallback_enabled" => mail_to_fallback_enabled,
|
|
567
|
+
"excluded_cupertino_activities" => excluded_cupertino_activities
|
|
568
|
+
},
|
|
569
|
+
timeout: timeout,
|
|
570
|
+
on_result: on_result
|
|
571
|
+
)
|
|
291
572
|
end
|
|
292
573
|
|
|
293
|
-
def
|
|
294
|
-
|
|
295
|
-
|
|
574
|
+
def handle_invoke_method_result(payload)
|
|
575
|
+
call_id = payload["call_id"].to_s
|
|
576
|
+
waiter = @invoke_waiters_mutex.synchronize { @invoke_waiters[call_id] }
|
|
577
|
+
if waiter
|
|
578
|
+
waiter << payload
|
|
579
|
+
return true
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
callback = @invoke_waiters_mutex.synchronize { @invoke_callbacks.delete(call_id) }
|
|
583
|
+
return false unless callback
|
|
584
|
+
|
|
585
|
+
callback.call(payload["result"], payload["error"])
|
|
586
|
+
true
|
|
587
|
+
rescue StandardError => e
|
|
588
|
+
Kernel.warn("invoke callback error: #{e.class}: #{e.message}")
|
|
589
|
+
false
|
|
296
590
|
end
|
|
297
591
|
|
|
298
592
|
def pop_dialog
|
|
@@ -319,19 +613,32 @@ module Ruflet
|
|
|
319
613
|
|
|
320
614
|
control = resolve_control(control_or_id)
|
|
321
615
|
return self unless control
|
|
616
|
+
wire_id = control.wire_id
|
|
617
|
+
if wire_id.nil?
|
|
618
|
+
# Events can race with navigation/disposal; never emit patch_control with nil id.
|
|
619
|
+
refresh_control_indexes!
|
|
620
|
+
wire_id = control.wire_id
|
|
621
|
+
end
|
|
622
|
+
return self if wire_id.nil?
|
|
322
623
|
|
|
323
624
|
patch = normalize_props(props)
|
|
324
|
-
if
|
|
625
|
+
if text_maps_to_content?(control, patch)
|
|
325
626
|
patch["content"] = patch.delete("text")
|
|
326
627
|
end
|
|
327
628
|
|
|
629
|
+
# Keep runtime control tree aligned with incremental patches.
|
|
630
|
+
if patch.key?("controls")
|
|
631
|
+
control.children.clear
|
|
632
|
+
Array(patch["controls"]).each { |child| control.children << child if child.is_a?(Control) }
|
|
633
|
+
end
|
|
634
|
+
|
|
328
635
|
visited = Set.new
|
|
329
636
|
patch.each_value { |value| register_embedded_value(value, visited) }
|
|
330
637
|
|
|
331
638
|
patch_ops = patch.map { |k, v| [0, 0, k, serialize_patch_value(v)] }
|
|
332
639
|
|
|
333
640
|
send_message(Protocol::ACTIONS[:patch_control], {
|
|
334
|
-
"id" =>
|
|
641
|
+
"id" => wire_id,
|
|
335
642
|
"patch" => [[0], *patch_ops]
|
|
336
643
|
})
|
|
337
644
|
|
|
@@ -380,8 +687,7 @@ module Ruflet
|
|
|
380
687
|
prop_name = method_name.delete_suffix("=")
|
|
381
688
|
|
|
382
689
|
if method_name.end_with?("=")
|
|
383
|
-
if
|
|
384
|
-
Kernel.warn("[DEPRECATION] `page.#{prop_name}(...)` is no longer supported.")
|
|
690
|
+
if widget_helper_method?(prop_name)
|
|
385
691
|
raise NoMethodError, "Use `#{prop_name}(...)` as a free widget helper, then attach with `page.add(...)`."
|
|
386
692
|
end
|
|
387
693
|
assign_split_prop(prop_name, normalize_value(prop_name, args.first))
|
|
@@ -394,8 +700,7 @@ module Ruflet
|
|
|
394
700
|
return instance_variable_get("@#{method_name}") if DIALOG_PROP_KEYS.include?(method_name)
|
|
395
701
|
end
|
|
396
702
|
|
|
397
|
-
if
|
|
398
|
-
Kernel.warn("[DEPRECATION] `page.#{name}(...)` is no longer supported.")
|
|
703
|
+
if widget_helper_method?(name)
|
|
399
704
|
raise NoMethodError, "Use `#{name}(...)` as a free widget helper, then attach with `page.add(...)`."
|
|
400
705
|
end
|
|
401
706
|
|
|
@@ -405,8 +710,8 @@ module Ruflet
|
|
|
405
710
|
def respond_to_missing?(name, include_private = false)
|
|
406
711
|
method_name = name.to_s
|
|
407
712
|
prop_name = method_name.delete_suffix("=")
|
|
408
|
-
|
|
409
|
-
|
|
713
|
+
widget_helper_method?(name) ||
|
|
714
|
+
widget_helper_method?(prop_name) ||
|
|
410
715
|
method_name.end_with?("=") ||
|
|
411
716
|
@page_props.key?(method_name) ||
|
|
412
717
|
@view_props.key?(method_name) ||
|
|
@@ -416,8 +721,47 @@ module Ruflet
|
|
|
416
721
|
|
|
417
722
|
private
|
|
418
723
|
|
|
724
|
+
def invoke_and_wait(control_or_id, method_name, args: nil, timeout: 10)
|
|
725
|
+
control_id =
|
|
726
|
+
if page_control_target?(control_or_id)
|
|
727
|
+
1
|
|
728
|
+
else
|
|
729
|
+
control = resolve_control(control_or_id)
|
|
730
|
+
return nil unless control
|
|
731
|
+
control.wire_id
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
call_id = "call_#{Ruflet::Control.generate_id}"
|
|
735
|
+
waiter = Queue.new
|
|
736
|
+
@invoke_waiters_mutex.synchronize { @invoke_waiters[call_id] = waiter }
|
|
737
|
+
|
|
738
|
+
send_message(Protocol::ACTIONS[:invoke_control_method], {
|
|
739
|
+
"control_id" => control_id,
|
|
740
|
+
"call_id" => call_id,
|
|
741
|
+
"name" => method_name.to_s,
|
|
742
|
+
"args" => args,
|
|
743
|
+
"timeout" => timeout
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
response = Timeout.timeout(timeout.to_f) { waiter.pop }
|
|
747
|
+
error = response["error"]
|
|
748
|
+
raise RuntimeError, error if error && !error.to_s.empty?
|
|
749
|
+
|
|
750
|
+
response["result"]
|
|
751
|
+
ensure
|
|
752
|
+
@invoke_waiters_mutex.synchronize { @invoke_waiters.delete(call_id) } if call_id
|
|
753
|
+
end
|
|
754
|
+
|
|
419
755
|
def build_widget(type, **props, &block) = WidgetBuilder.new.control(type, **props, &block)
|
|
420
756
|
|
|
757
|
+
def widget_helper_method?(name)
|
|
758
|
+
WIDGET_HELPER_METHODS.include?(name.to_s)
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
def text_maps_to_content?(control, patch)
|
|
762
|
+
patch.key?("text") && control.type.end_with?("button")
|
|
763
|
+
end
|
|
764
|
+
|
|
421
765
|
def split_props(props)
|
|
422
766
|
props.each do |k, v|
|
|
423
767
|
assign_split_prop(k, v)
|
|
@@ -515,6 +859,7 @@ module Ruflet
|
|
|
515
859
|
def normalize_props(hash)
|
|
516
860
|
hash.each_with_object({}) do |(k, v), result|
|
|
517
861
|
key = k.to_s
|
|
862
|
+
key = "controls" if key == "children"
|
|
518
863
|
result[key] = normalize_value(key, v)
|
|
519
864
|
end
|
|
520
865
|
end
|
|
@@ -663,7 +1008,15 @@ module Ruflet
|
|
|
663
1008
|
end
|
|
664
1009
|
|
|
665
1010
|
def build_page_patch_ops
|
|
666
|
-
@page_props.
|
|
1011
|
+
@page_props.filter_map do |k, v|
|
|
1012
|
+
# Keep internal containers stable after initial mount.
|
|
1013
|
+
# Re-sending them as full objects can replace Control instances with
|
|
1014
|
+
# same IDs and detach service invoke listeners on the Flutter side.
|
|
1015
|
+
next nil if k == "_overlay" && @overlay_container.wire_id
|
|
1016
|
+
next nil if k == "_dialogs" && @dialogs_container.wire_id
|
|
1017
|
+
|
|
1018
|
+
[0, 0, k, serialize_patch_value(v)]
|
|
1019
|
+
end
|
|
667
1020
|
end
|
|
668
1021
|
|
|
669
1022
|
def resolve_icon_codepoint(value)
|
|
@@ -674,22 +1027,196 @@ module Ruflet
|
|
|
674
1027
|
codepoint
|
|
675
1028
|
end
|
|
676
1029
|
|
|
677
|
-
def ensure_url_launcher_service
|
|
678
|
-
launcher = services.find { |service| service.is_a?(Control) && service.type == "url_launcher" }
|
|
679
|
-
return launcher if launcher
|
|
680
|
-
|
|
681
|
-
launcher = build_widget(:url_launcher)
|
|
682
|
-
add_service(launcher)
|
|
683
|
-
launcher
|
|
684
|
-
end
|
|
685
|
-
|
|
686
1030
|
def ensure_clipboard_service
|
|
687
1031
|
clipboard = services.find { |service| service.is_a?(Control) && service.type == "clipboard" }
|
|
688
|
-
return clipboard if clipboard
|
|
1032
|
+
return [clipboard, false] if clipboard
|
|
689
1033
|
|
|
690
1034
|
clipboard = build_widget(:clipboard)
|
|
691
1035
|
add_service(clipboard)
|
|
692
|
-
clipboard
|
|
1036
|
+
[clipboard, true]
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
def invoke_clipboard_method(method_name, args: nil, timeout:, on_result:)
|
|
1040
|
+
clipboard, created = ensure_clipboard_service
|
|
1041
|
+
send_view_patch if created
|
|
1042
|
+
sleep(0.05) if created
|
|
1043
|
+
invoke(
|
|
1044
|
+
clipboard,
|
|
1045
|
+
method_name,
|
|
1046
|
+
args: args,
|
|
1047
|
+
timeout: timeout,
|
|
1048
|
+
on_result: lambda { |result, error|
|
|
1049
|
+
message = error.to_s
|
|
1050
|
+
if message.include?("inexistent control")
|
|
1051
|
+
remove_service(clipboard)
|
|
1052
|
+
fresh_clipboard, = ensure_clipboard_service
|
|
1053
|
+
sleep(0.08)
|
|
1054
|
+
invoke(
|
|
1055
|
+
fresh_clipboard,
|
|
1056
|
+
method_name,
|
|
1057
|
+
args: args,
|
|
1058
|
+
timeout: timeout,
|
|
1059
|
+
on_result: on_result
|
|
1060
|
+
)
|
|
1061
|
+
else
|
|
1062
|
+
on_result&.call(result, error)
|
|
1063
|
+
end
|
|
1064
|
+
}
|
|
1065
|
+
)
|
|
1066
|
+
rescue StandardError => e
|
|
1067
|
+
on_result&.call(nil, e.message)
|
|
1068
|
+
end
|
|
1069
|
+
|
|
1070
|
+
def ensure_url_launcher_service
|
|
1071
|
+
url_launcher = services.find { |service| service.is_a?(Control) && %w[urllauncher url_launcher].include?(service.type) }
|
|
1072
|
+
return url_launcher if url_launcher
|
|
1073
|
+
|
|
1074
|
+
url_launcher = build_widget(:url_launcher)
|
|
1075
|
+
add_service(url_launcher)
|
|
1076
|
+
url_launcher
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
def ensure_connectivity_service
|
|
1080
|
+
connectivity = services.find { |service| service.is_a?(Control) && service.type == "connectivity" }
|
|
1081
|
+
return [connectivity, false] if connectivity
|
|
1082
|
+
|
|
1083
|
+
connectivity = build_widget(:connectivity)
|
|
1084
|
+
add_service(connectivity)
|
|
1085
|
+
[connectivity, true]
|
|
1086
|
+
end
|
|
1087
|
+
|
|
1088
|
+
def invoke_connectivity_method(method_name, timeout:, on_result:)
|
|
1089
|
+
connectivity, created = ensure_connectivity_service
|
|
1090
|
+
send_view_patch if created
|
|
1091
|
+
sleep(0.05) if created
|
|
1092
|
+
invoke(
|
|
1093
|
+
connectivity,
|
|
1094
|
+
method_name,
|
|
1095
|
+
timeout: timeout,
|
|
1096
|
+
on_result: lambda { |result, error|
|
|
1097
|
+
message = error.to_s
|
|
1098
|
+
if message.include?("inexistent control")
|
|
1099
|
+
remove_service(connectivity)
|
|
1100
|
+
fresh_connectivity, = ensure_connectivity_service
|
|
1101
|
+
sleep(0.08)
|
|
1102
|
+
invoke(
|
|
1103
|
+
fresh_connectivity,
|
|
1104
|
+
method_name,
|
|
1105
|
+
timeout: timeout,
|
|
1106
|
+
on_result: on_result
|
|
1107
|
+
)
|
|
1108
|
+
else
|
|
1109
|
+
on_result&.call(result, error)
|
|
1110
|
+
end
|
|
1111
|
+
}
|
|
1112
|
+
)
|
|
1113
|
+
rescue StandardError => e
|
|
1114
|
+
on_result&.call(nil, e.message)
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
def ensure_battery_service
|
|
1118
|
+
battery = services.find { |service| service.is_a?(Control) && service.type == "battery" }
|
|
1119
|
+
return [battery, false] if battery
|
|
1120
|
+
|
|
1121
|
+
battery = build_widget(:battery)
|
|
1122
|
+
add_service(battery)
|
|
1123
|
+
[battery, true]
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
def ensure_share_service
|
|
1127
|
+
share = services.find { |service| service.is_a?(Control) && service.type == "share" }
|
|
1128
|
+
return share if share
|
|
1129
|
+
|
|
1130
|
+
share = build_widget(:share)
|
|
1131
|
+
add_service(share)
|
|
1132
|
+
share
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
def invoke_battery_method(method_name, timeout:, on_result:)
|
|
1136
|
+
battery, created = ensure_battery_service
|
|
1137
|
+
send_view_patch if created
|
|
1138
|
+
sleep(0.05) if created
|
|
1139
|
+
invoke(
|
|
1140
|
+
battery,
|
|
1141
|
+
method_name,
|
|
1142
|
+
timeout: timeout,
|
|
1143
|
+
on_result: lambda { |result, error|
|
|
1144
|
+
message = error.to_s
|
|
1145
|
+
if message.include?("inexistent control")
|
|
1146
|
+
remove_service(battery)
|
|
1147
|
+
fresh_battery, = ensure_battery_service
|
|
1148
|
+
sleep(0.08)
|
|
1149
|
+
invoke(
|
|
1150
|
+
fresh_battery,
|
|
1151
|
+
method_name,
|
|
1152
|
+
timeout: timeout,
|
|
1153
|
+
on_result: on_result
|
|
1154
|
+
)
|
|
1155
|
+
else
|
|
1156
|
+
on_result&.call(result, error)
|
|
1157
|
+
end
|
|
1158
|
+
}
|
|
1159
|
+
)
|
|
1160
|
+
rescue StandardError => e
|
|
1161
|
+
on_result&.call(nil, e.message)
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
def ensure_storage_paths_service
|
|
1165
|
+
storage_paths = services.find do |service|
|
|
1166
|
+
service.is_a?(Control) && %w[storage_paths storagepaths].include?(service.type.to_s)
|
|
1167
|
+
end
|
|
1168
|
+
return [storage_paths, false] if storage_paths
|
|
1169
|
+
|
|
1170
|
+
storage_paths = build_widget(:storage_paths)
|
|
1171
|
+
add_service(storage_paths)
|
|
1172
|
+
[storage_paths, true]
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
def invoke_storage_paths(method_name, timeout:, on_result:)
|
|
1176
|
+
storage_paths, created = ensure_storage_paths_service
|
|
1177
|
+
send_view_patch if created
|
|
1178
|
+
sleep(0.05) if created
|
|
1179
|
+
invoke(
|
|
1180
|
+
storage_paths,
|
|
1181
|
+
method_name,
|
|
1182
|
+
timeout: timeout,
|
|
1183
|
+
on_result: lambda { |result, error|
|
|
1184
|
+
message = error.to_s
|
|
1185
|
+
if message.include?("inexistent control")
|
|
1186
|
+
remove_service(storage_paths)
|
|
1187
|
+
fresh_storage_paths, = ensure_storage_paths_service
|
|
1188
|
+
sleep(0.08)
|
|
1189
|
+
invoke(
|
|
1190
|
+
fresh_storage_paths,
|
|
1191
|
+
method_name,
|
|
1192
|
+
timeout: timeout,
|
|
1193
|
+
on_result: on_result
|
|
1194
|
+
)
|
|
1195
|
+
else
|
|
1196
|
+
on_result&.call(result, error)
|
|
1197
|
+
end
|
|
1198
|
+
}
|
|
1199
|
+
)
|
|
1200
|
+
rescue StandardError => e
|
|
1201
|
+
on_result&.call(nil, e.message)
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
def invoke_file_picker(method_name, args, timeout:, on_result:)
|
|
1205
|
+
picker = build_widget(:file_picker)
|
|
1206
|
+
add_service(picker)
|
|
1207
|
+
invoke(
|
|
1208
|
+
picker,
|
|
1209
|
+
method_name,
|
|
1210
|
+
args: args,
|
|
1211
|
+
timeout: timeout,
|
|
1212
|
+
on_result: lambda { |result, error|
|
|
1213
|
+
remove_service(picker)
|
|
1214
|
+
on_result&.call(result, error)
|
|
1215
|
+
}
|
|
1216
|
+
)
|
|
1217
|
+
rescue StandardError => e
|
|
1218
|
+
remove_service(picker) if picker
|
|
1219
|
+
on_result&.call(nil, e.message)
|
|
693
1220
|
end
|
|
694
1221
|
end
|
|
695
1222
|
end
|