ruflet_core 0.0.12 → 0.0.14
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_protocol/ruflet/protocol.rb +50 -4
- data/lib/ruflet_ui/ruflet/control.rb +11 -4
- data/lib/ruflet_ui/ruflet/dsl.rb +229 -37
- data/lib/ruflet_ui/ruflet/events/gesture_events.rb +113 -9
- data/lib/ruflet_ui/ruflet/page.rb +884 -162
- data/lib/ruflet_ui/ruflet/types/animation.rb +110 -0
- data/lib/ruflet_ui/ruflet/ui/control_registry.rb +1 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheet_control.rb +13 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheetaction_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactivityindicator_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoalertdialog_control.rb +17 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoappbar_control.rb +3 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobottomsheet_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobutton_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocheckbox_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenu_control.rb +11 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenuaction_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodatepicker_control.rb +14 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodialogaction_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinofilledbutton_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinolisttile_control.rb +12 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinonavigationbar_control.rb +11 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinopicker_control.rb +18 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoradio_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinosegmentedbutton_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslider_control.rb +7 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslidingsegmentedbutton_control.rb +3 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoswitch_control.rb +7 -1
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotextfield_control.rb +7 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotimerpicker_control.rb +18 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotintedbutton_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/alertdialog_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/appbar_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/audio_control.rb +33 -1
- data/lib/ruflet_ui/ruflet/ui/controls/materials/autocomplete_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/autocompletesuggestion_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/badge_control.rb +7 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/banner_control.rb +11 -1
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomappbar_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomsheet_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/button_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/card_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chip_control.rb +11 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/circleavatar_control.rb +12 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/contextmenu_control.rb +19 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacell_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacolumn_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datatable_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datepicker_control.rb +18 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/daterangepicker_control.rb +20 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/divider_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdown_control.rb +11 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownoption_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanel_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanellist_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansiontile_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledbutton_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/fillediconbutton_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonalbutton_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonaliconbutton_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/floatingactionbutton_control.rb +20 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/iconbutton_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/listtile_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/map_controls.rb +311 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menubar_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menuitembutton_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbar_control.rb +11 -1
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbardestination_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawer_control.rb +12 -1
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawerdestination_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationrail_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationraildestination_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinedbutton_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinediconbutton_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenubutton_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenuitem_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressbar_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressring_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/rangeslider_control.rb +13 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/ruflet_controls.rb +24 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/searchbar_control.rb +28 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segment_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segmentedbutton_control.rb +19 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/selectionarea_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/snackbar_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/submenubutton_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tab_control.rb +7 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbar_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbarview_control.rb +7 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabs_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textbutton_control.rb +5 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/verticaldivider_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/video_control.rb +86 -1
- data/lib/ruflet_ui/ruflet/ui/controls/ruflet_controls.rb +24 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/animatedswitcher_control.rb +10 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/browsercontextmenu_control.rb +12 -1
- data/lib/ruflet_ui/ruflet/ui/controls/shared/canvas_control.rb +14 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dismissible_control.rb +19 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/draggable_control.rb +9 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dragtarget_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gridview_control.rb +20 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/image_control.rb +19 -1
- data/lib/ruflet_ui/ruflet/ui/controls/shared/interactiveviewer_control.rb +37 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/listview_control.rb +17 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pageview_control.rb +13 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/placeholder_control.rb +12 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/reorderabledraghandle_control.rb +4 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/responsiverow_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/safearea_control.rb +11 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/semantics_control.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/stack_control.rb +3 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/text_control.rb +20 -1
- data/lib/ruflet_ui/ruflet/ui/controls/shared/view_control.rb +8 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/window_control.rb +16 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/windowdragarea_control.rb +6 -0
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_methods.rb +83 -6
- data/lib/ruflet_ui/ruflet/ui/material_control_methods.rb +513 -33
- data/lib/ruflet_ui/ruflet/ui/material_control_registry.rb +2 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/audio_recorder_control.rb +87 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/geolocator_control.rb +85 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/permissionhandler_control.rb +55 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/securestorage_control.rb +91 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/semanticsservice_control.rb +28 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/tester_control.rb +126 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet_services.rb +16 -0
- data/lib/ruflet_ui/ruflet/ui/shared_control_forwarders.rb +230 -38
- data/lib/ruflet_ui.rb +4 -0
- metadata +9 -1
|
@@ -14,7 +14,132 @@ require "timeout"
|
|
|
14
14
|
|
|
15
15
|
module Ruflet
|
|
16
16
|
class Page
|
|
17
|
-
|
|
17
|
+
class SharedPreferencesService
|
|
18
|
+
def initialize(page)
|
|
19
|
+
@page = page
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def set(key, value, timeout: 10, on_result: nil)
|
|
23
|
+
invoke("set", { "key" => key, "value" => value }, timeout: timeout, on_result: on_result)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get(key, timeout: 10, on_result: nil)
|
|
27
|
+
invoke("get", { "key" => key }, timeout: timeout, on_result: on_result)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def contains_key(key, timeout: 10, on_result: nil)
|
|
31
|
+
invoke("contains_key", { "key" => key }, timeout: timeout, on_result: on_result)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def get_keys(key_prefix, timeout: 10, on_result: nil)
|
|
35
|
+
invoke("get_keys", { "key_prefix" => key_prefix }, timeout: timeout, on_result: on_result)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def remove(key, timeout: 10, on_result: nil)
|
|
39
|
+
invoke("remove", { "key" => key }, timeout: timeout, on_result: on_result)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def clear(timeout: 10, on_result: nil)
|
|
43
|
+
invoke("clear", nil, timeout: timeout, on_result: on_result)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def invoke(method_name, args, timeout:, on_result:)
|
|
49
|
+
@page.__send__(:invoke_shared_preferences, method_name, args: args, timeout: timeout, on_result: on_result)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class WakelockService
|
|
54
|
+
def initialize(page)
|
|
55
|
+
@page = page
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def enable(timeout: 10, on_result: nil)
|
|
59
|
+
invoke("enable", timeout: timeout, on_result: on_result)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def disable(timeout: 10, on_result: nil)
|
|
63
|
+
invoke("disable", timeout: timeout, on_result: on_result)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def is_enabled(timeout: 10, on_result: nil)
|
|
67
|
+
invoke("is_enabled", timeout: timeout, on_result: on_result)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def invoke(method_name, timeout:, on_result:)
|
|
73
|
+
@page.__send__(:invoke_wakelock, method_name, timeout: timeout, on_result: on_result)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class FlashlightService
|
|
78
|
+
def initialize(page)
|
|
79
|
+
@page = page
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def on(timeout: 10, on_result: nil)
|
|
83
|
+
invoke("on", timeout: timeout, on_result: on_result)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def off(timeout: 10, on_result: nil)
|
|
87
|
+
invoke("off", timeout: timeout, on_result: on_result)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def is_available(timeout: 10, on_result: nil)
|
|
91
|
+
invoke("is_available", timeout: timeout, on_result: on_result)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def invoke(method_name, timeout:, on_result:)
|
|
97
|
+
@page.__send__(:invoke_flashlight, method_name, timeout: timeout, on_result: on_result)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class ScreenBrightnessService
|
|
102
|
+
def initialize(page)
|
|
103
|
+
@page = page
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
%w[
|
|
107
|
+
can_change_system_screen_brightness
|
|
108
|
+
get_application_screen_brightness
|
|
109
|
+
get_system_screen_brightness
|
|
110
|
+
is_animate
|
|
111
|
+
is_auto_reset
|
|
112
|
+
reset_application_screen_brightness
|
|
113
|
+
].each do |method_name|
|
|
114
|
+
define_method(method_name) do |timeout: 10, on_result: nil|
|
|
115
|
+
invoke(method_name, nil, timeout: timeout, on_result: on_result)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def set_animate(animate, timeout: 10, on_result: nil)
|
|
120
|
+
invoke("set_animate", { "value" => animate }, timeout: timeout, on_result: on_result)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def set_auto_reset(auto_reset, timeout: 10, on_result: nil)
|
|
124
|
+
invoke("set_auto_reset", { "value" => auto_reset }, timeout: timeout, on_result: on_result)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def set_application_screen_brightness(brightness, timeout: 10, on_result: nil)
|
|
128
|
+
invoke("set_application_screen_brightness", { "value" => brightness }, timeout: timeout, on_result: on_result)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def set_system_screen_brightness(brightness, timeout: 10, on_result: nil)
|
|
132
|
+
invoke("set_system_screen_brightness", { "value" => brightness }, timeout: timeout, on_result: on_result)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def invoke(method_name, args, timeout:, on_result:)
|
|
138
|
+
@page.__send__(:invoke_screen_brightness, method_name, args: args, timeout: timeout, on_result: on_result)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
PAGE_PROP_KEYS = %w[dark_theme fonts route rtl show_semantics_debugger theme theme_mode title vertical_alignment horizontal_alignment scroll].freeze
|
|
18
143
|
DIALOG_PROP_KEYS = %w[dialog snack_bar bottom_sheet].freeze
|
|
19
144
|
WIDGET_HELPER_METHODS = (
|
|
20
145
|
Ruflet::UI::MaterialControlMethods.instance_methods(false) +
|
|
@@ -35,6 +160,10 @@ module Ruflet
|
|
|
35
160
|
@root_controls = []
|
|
36
161
|
@views = []
|
|
37
162
|
@dialogs = []
|
|
163
|
+
@overlay_container_mounted = false
|
|
164
|
+
@dialogs_container_mounted = false
|
|
165
|
+
@services_container_mounted = false
|
|
166
|
+
@visual_service_controls = {}
|
|
38
167
|
@page_event_handlers = {}
|
|
39
168
|
@view_props = {}
|
|
40
169
|
@page_props = { "route" => (client_details["route"] || "/") }
|
|
@@ -57,6 +186,10 @@ module Ruflet
|
|
|
57
186
|
@invoke_waiters = {}
|
|
58
187
|
@invoke_callbacks = {}
|
|
59
188
|
@invoke_waiters_mutex = Mutex.new
|
|
189
|
+
@shared_preferences_proxy = SharedPreferencesService.new(self)
|
|
190
|
+
@wakelock_proxy = WakelockService.new(self)
|
|
191
|
+
@flashlight_proxy = FlashlightService.new(self)
|
|
192
|
+
@screen_brightness_proxy = ScreenBrightnessService.new(self)
|
|
60
193
|
refresh_overlay_container!
|
|
61
194
|
refresh_services_container!
|
|
62
195
|
refresh_dialogs_container!
|
|
@@ -111,15 +244,16 @@ module Ruflet
|
|
|
111
244
|
@view_props["bgcolor"] = normalize_value("bgcolor", value)
|
|
112
245
|
end
|
|
113
246
|
|
|
114
|
-
def add(*controls, appbar: nil, floating_action_button: nil, navigation_bar: nil, dialog: nil, snack_bar: nil, bottom_sheet: nil)
|
|
247
|
+
def add(*controls, appbar: nil, bottom_appbar: nil, floating_action_button: nil, navigation_bar: nil, dialog: nil, snack_bar: nil, bottom_sheet: nil)
|
|
115
248
|
controls = controls.flatten
|
|
116
249
|
visited = Set.new
|
|
117
250
|
controls.each { |c| register_control_tree(c, visited) }
|
|
118
251
|
@root_controls = controls
|
|
119
252
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
253
|
+
update_view_slot("appbar", appbar)
|
|
254
|
+
update_view_slot("bottom_appbar", bottom_appbar)
|
|
255
|
+
update_view_slot("floating_action_button", floating_action_button)
|
|
256
|
+
update_view_slot("navigation_bar", navigation_bar)
|
|
123
257
|
@dialog = dialog if dialog
|
|
124
258
|
@snack_bar = snack_bar if snack_bar
|
|
125
259
|
@bottom_sheet = bottom_sheet if bottom_sheet
|
|
@@ -148,6 +282,50 @@ module Ruflet
|
|
|
148
282
|
self
|
|
149
283
|
end
|
|
150
284
|
|
|
285
|
+
def shared_preferences(**props)
|
|
286
|
+
return service(:shared_preferences, **props) unless props.empty?
|
|
287
|
+
|
|
288
|
+
@shared_preferences_proxy
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def wakelock(**props)
|
|
292
|
+
return service(:wakelock, **props) unless props.empty?
|
|
293
|
+
|
|
294
|
+
@wakelock_proxy
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def flashlight(**props)
|
|
298
|
+
return service(:flashlight, **props) unless props.empty?
|
|
299
|
+
|
|
300
|
+
@flashlight_proxy
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def screen_brightness(**props)
|
|
304
|
+
return service(:screen_brightness, **props) unless props.empty?
|
|
305
|
+
|
|
306
|
+
@screen_brightness_proxy
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def audio(**props)
|
|
310
|
+
service(:audio, **props)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def audio_recorder(**props)
|
|
314
|
+
service(:audio_recorder, **props)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def browser_context_menu(**props)
|
|
318
|
+
service(:browser_context_menu, **props)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def window(**props)
|
|
322
|
+
service(:window, **props)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def tester(**props)
|
|
326
|
+
service(:tester, **props)
|
|
327
|
+
end
|
|
328
|
+
|
|
151
329
|
def add_service(*value)
|
|
152
330
|
@services_container.props["_services"] = services + value.flatten.compact
|
|
153
331
|
refresh_services_container!
|
|
@@ -180,12 +358,25 @@ module Ruflet
|
|
|
180
358
|
mapped_props = normalize_props(props || {})
|
|
181
359
|
id = mapped_props.delete("id")
|
|
182
360
|
normalized_type = type.to_s.downcase
|
|
361
|
+
compact_type = normalized_type.delete("_")
|
|
362
|
+
|
|
363
|
+
if visual_service_type?(normalized_type)
|
|
364
|
+
key = id ? "id:#{id}" : normalized_type
|
|
365
|
+
existing = @visual_service_controls[key]
|
|
366
|
+
return existing if existing
|
|
367
|
+
|
|
368
|
+
svc = Ruflet::UI::ControlFactory.build(type.to_s, id: id&.to_s, **mapped_props)
|
|
369
|
+
@visual_service_controls[key] = svc
|
|
370
|
+
return svc
|
|
371
|
+
end
|
|
183
372
|
|
|
184
373
|
existing =
|
|
185
374
|
if id
|
|
186
375
|
services.find { |s| s.is_a?(Control) && s.id.to_s == id.to_s }
|
|
187
376
|
else
|
|
188
|
-
services.find
|
|
377
|
+
services.find do |s|
|
|
378
|
+
s.is_a?(Control) && s.type.to_s.downcase.delete("_") == compact_type
|
|
379
|
+
end
|
|
189
380
|
end
|
|
190
381
|
return existing if existing
|
|
191
382
|
|
|
@@ -201,6 +392,18 @@ module Ruflet
|
|
|
201
392
|
self
|
|
202
393
|
end
|
|
203
394
|
|
|
395
|
+
def navigate(route, **query_params)
|
|
396
|
+
go(route, **query_params)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def push_route(route, **query_params)
|
|
400
|
+
go(route, **query_params)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def query
|
|
404
|
+
parse_query(route)
|
|
405
|
+
end
|
|
406
|
+
|
|
204
407
|
def on_route_change=(handler)
|
|
205
408
|
@page_event_handlers["route_change"] = handler
|
|
206
409
|
end
|
|
@@ -224,20 +427,70 @@ module Ruflet
|
|
|
224
427
|
@view_props["appbar"] = value
|
|
225
428
|
end
|
|
226
429
|
|
|
430
|
+
def bottom_appbar=(value)
|
|
431
|
+
@view_props["bottom_appbar"] = value
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def bottomappbar=(value)
|
|
435
|
+
self.bottom_appbar = value
|
|
436
|
+
end
|
|
437
|
+
|
|
227
438
|
def floating_action_button=(value)
|
|
228
439
|
@view_props["floating_action_button"] = value
|
|
229
440
|
end
|
|
230
441
|
|
|
442
|
+
def drawer
|
|
443
|
+
@view_props["drawer"]
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def drawer=(value)
|
|
447
|
+
@view_props["drawer"] = value
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
def end_drawer
|
|
451
|
+
@view_props["end_drawer"]
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def end_drawer=(value)
|
|
455
|
+
@view_props["end_drawer"] = value
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def show_drawer(timeout: 10, on_result: nil)
|
|
459
|
+
raise ArgumentError, "show_drawer requires drawer" unless drawer
|
|
460
|
+
|
|
461
|
+
invoke_current_view("show_drawer", timeout: timeout, on_result: on_result)
|
|
462
|
+
self
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def close_drawer(timeout: 10, on_result: nil)
|
|
466
|
+
invoke_current_view("close_drawer", timeout: timeout, on_result: on_result)
|
|
467
|
+
self
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def show_end_drawer(timeout: 10, on_result: nil)
|
|
471
|
+
raise ArgumentError, "show_end_drawer requires end_drawer" unless end_drawer
|
|
472
|
+
|
|
473
|
+
invoke_current_view("show_end_drawer", timeout: timeout, on_result: on_result)
|
|
474
|
+
self
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def close_end_drawer(timeout: 10, on_result: nil)
|
|
478
|
+
invoke_current_view("close_end_drawer", timeout: timeout, on_result: on_result)
|
|
479
|
+
self
|
|
480
|
+
end
|
|
481
|
+
|
|
231
482
|
def dialog = @dialog
|
|
232
483
|
|
|
233
484
|
def dialog=(value)
|
|
234
485
|
@dialog = value
|
|
235
486
|
refresh_dialogs_container!
|
|
487
|
+
push_dialogs_update! if @dialogs_container_mounted
|
|
236
488
|
end
|
|
237
489
|
|
|
238
490
|
def snack_bar=(value)
|
|
239
491
|
@snack_bar = value
|
|
240
492
|
refresh_dialogs_container!
|
|
493
|
+
push_dialogs_update! if @dialogs_container_mounted
|
|
241
494
|
end
|
|
242
495
|
|
|
243
496
|
def snackbar=(value)
|
|
@@ -259,6 +512,7 @@ module Ruflet
|
|
|
259
512
|
return self if dialog_open?(dialog_control)
|
|
260
513
|
|
|
261
514
|
dialog_control.props["open"] = true
|
|
515
|
+
remove_existing_singleton_dialogs(dialog_control)
|
|
262
516
|
@dialogs << dialog_control unless @dialogs.include?(dialog_control)
|
|
263
517
|
refresh_dialogs_container!
|
|
264
518
|
send_view_patch unless @dialogs_container.wire_id
|
|
@@ -328,6 +582,30 @@ module Ruflet
|
|
|
328
582
|
invoke(url_launcher, "can_launch_url", args: { "url" => url }, timeout: timeout)
|
|
329
583
|
end
|
|
330
584
|
|
|
585
|
+
def close_in_app_web_view(timeout: 10, on_result: nil)
|
|
586
|
+
url_launcher = ensure_url_launcher_service
|
|
587
|
+
invoke(url_launcher, "close_in_app_web_view", timeout: timeout, on_result: on_result)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def open_window(url, title: nil, width: nil, height: nil, timeout: 10, on_result: nil)
|
|
591
|
+
url_launcher = ensure_url_launcher_service
|
|
592
|
+
args = { "url" => url }
|
|
593
|
+
args["title"] = title unless title.nil?
|
|
594
|
+
args["width"] = width unless width.nil?
|
|
595
|
+
args["height"] = height unless height.nil?
|
|
596
|
+
invoke(url_launcher, "open_window", args: args, timeout: timeout, on_result: on_result)
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
def supports_launch_mode(mode, timeout: 10, on_result: nil)
|
|
600
|
+
url_launcher = ensure_url_launcher_service
|
|
601
|
+
invoke(url_launcher, "supports_launch_mode", args: { "mode" => mode }, timeout: timeout, on_result: on_result)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
def supports_close_for_launch_mode(mode, timeout: 10, on_result: nil)
|
|
605
|
+
url_launcher = ensure_url_launcher_service
|
|
606
|
+
invoke(url_launcher, "supports_close_for_launch_mode", args: { "mode" => mode }, timeout: timeout, on_result: on_result)
|
|
607
|
+
end
|
|
608
|
+
|
|
331
609
|
# File picker helpers: create an ephemeral service, invoke method, and dispose it.
|
|
332
610
|
def pick_files(
|
|
333
611
|
dialog_title: nil,
|
|
@@ -341,14 +619,14 @@ module Ruflet
|
|
|
341
619
|
)
|
|
342
620
|
invoke_file_picker(
|
|
343
621
|
"pick_files",
|
|
344
|
-
|
|
622
|
+
compact_service_args(
|
|
345
623
|
"dialog_title" => dialog_title,
|
|
346
624
|
"initial_directory" => initial_directory,
|
|
347
625
|
"file_type" => file_type,
|
|
348
626
|
"allowed_extensions" => allowed_extensions,
|
|
349
627
|
"allow_multiple" => allow_multiple,
|
|
350
628
|
"with_data" => with_data
|
|
351
|
-
|
|
629
|
+
),
|
|
352
630
|
timeout: timeout,
|
|
353
631
|
on_result: on_result
|
|
354
632
|
)
|
|
@@ -366,14 +644,14 @@ module Ruflet
|
|
|
366
644
|
)
|
|
367
645
|
invoke_file_picker(
|
|
368
646
|
"save_file",
|
|
369
|
-
|
|
647
|
+
compact_service_args(
|
|
370
648
|
"dialog_title" => dialog_title,
|
|
371
649
|
"file_name" => file_name,
|
|
372
650
|
"initial_directory" => initial_directory,
|
|
373
651
|
"file_type" => file_type,
|
|
374
652
|
"allowed_extensions" => allowed_extensions,
|
|
375
653
|
"src_bytes" => src_bytes
|
|
376
|
-
|
|
654
|
+
),
|
|
377
655
|
timeout: timeout,
|
|
378
656
|
on_result: on_result
|
|
379
657
|
)
|
|
@@ -382,18 +660,212 @@ module Ruflet
|
|
|
382
660
|
def get_directory_path(dialog_title: nil, initial_directory: nil, timeout: nil, on_result: nil)
|
|
383
661
|
invoke_file_picker(
|
|
384
662
|
"get_directory_path",
|
|
385
|
-
|
|
663
|
+
compact_service_args(
|
|
386
664
|
"dialog_title" => dialog_title,
|
|
387
665
|
"initial_directory" => initial_directory
|
|
388
|
-
|
|
666
|
+
),
|
|
667
|
+
timeout: timeout,
|
|
668
|
+
on_result: on_result
|
|
669
|
+
)
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
def upload(files, timeout: nil, on_result: nil)
|
|
673
|
+
invoke_file_picker(
|
|
674
|
+
"upload",
|
|
675
|
+
{ "files" => Array(files).map { |file| normalize_service_value(file) } },
|
|
389
676
|
timeout: timeout,
|
|
390
677
|
on_result: on_result
|
|
391
678
|
)
|
|
392
679
|
end
|
|
393
680
|
|
|
681
|
+
def upload_files(files, timeout: nil, on_result: nil)
|
|
682
|
+
upload(files, timeout: timeout, on_result: on_result)
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
def disable_browser_context_menu(timeout: 10, on_result: nil)
|
|
686
|
+
invoke_browser_context_menu("disable_menu", timeout: timeout, on_result: on_result)
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
def enable_browser_context_menu(timeout: 10, on_result: nil)
|
|
690
|
+
invoke_browser_context_menu("enable_menu", timeout: timeout, on_result: on_result)
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def wait_until_ready_to_show(timeout: 10, on_result: nil)
|
|
694
|
+
invoke_window("wait_until_ready_to_show", timeout: timeout, on_result: on_result)
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
def window_to_front(timeout: 10, on_result: nil)
|
|
698
|
+
invoke_window("to_front", timeout: timeout, on_result: on_result)
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
def center_window(timeout: 10, on_result: nil)
|
|
702
|
+
invoke_window("center", timeout: timeout, on_result: on_result)
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
def close_window(timeout: 10, on_result: nil)
|
|
706
|
+
invoke_window("close", timeout: timeout, on_result: on_result)
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
def destroy_window(timeout: 10, on_result: nil)
|
|
710
|
+
invoke_window("destroy", timeout: timeout, on_result: on_result)
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
def start_window_dragging(timeout: 10, on_result: nil)
|
|
714
|
+
invoke_window("start_dragging", timeout: timeout, on_result: on_result)
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def start_window_resizing(edge, timeout: 10, on_result: nil)
|
|
718
|
+
invoke_window(
|
|
719
|
+
"start_resizing",
|
|
720
|
+
args: { "edge" => normalize_service_value(edge) },
|
|
721
|
+
timeout: timeout,
|
|
722
|
+
on_result: on_result
|
|
723
|
+
)
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
def tester_pump(options = nil, duration: nil, timeout: 10, on_result: nil)
|
|
727
|
+
duration = options[:duration] || options["duration"] if options.is_a?(Hash) && duration.nil?
|
|
728
|
+
invoke_tester("pump", args: compact_service_args("duration" => duration), timeout: timeout, on_result: on_result)
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
def tester_pump_and_settle(options = nil, duration: nil, timeout: 10, on_result: nil)
|
|
732
|
+
duration = options[:duration] || options["duration"] if options.is_a?(Hash) && duration.nil?
|
|
733
|
+
invoke_tester("pump_and_settle", args: compact_service_args("duration" => duration), timeout: timeout, on_result: on_result)
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
def find_by_text(text, timeout: 10, on_result: nil)
|
|
737
|
+
invoke_tester("find_by_text", args: { "text" => text }, timeout: timeout, on_result: on_result)
|
|
738
|
+
end
|
|
739
|
+
|
|
740
|
+
def find_by_text_containing(pattern, timeout: 10, on_result: nil)
|
|
741
|
+
invoke_tester("find_by_text_containing", args: { "pattern" => pattern }, timeout: timeout, on_result: on_result)
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
def find_by_key(key, timeout: 10, on_result: nil)
|
|
745
|
+
invoke_tester("find_by_key", args: { "key" => key }, timeout: timeout, on_result: on_result)
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
def find_by_tooltip(value, timeout: 10, on_result: nil)
|
|
749
|
+
invoke_tester("find_by_tooltip", args: { "value" => value }, timeout: timeout, on_result: on_result)
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
def find_by_icon(icon, timeout: 10, on_result: nil)
|
|
753
|
+
invoke_tester("find_by_icon", args: { "icon" => normalize_service_value(icon) }, timeout: timeout, on_result: on_result)
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
def take_screenshot(name, timeout: 10, on_result: nil)
|
|
757
|
+
invoke_tester("take_screenshot", args: { "name" => name }, timeout: timeout, on_result: on_result)
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
def tap(finder_id = nil, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
761
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
762
|
+
invoke_tester_finder("tap", finder_id, finder_index: finder_index, timeout: timeout, on_result: on_result)
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
def mouse_click(finder_id = nil, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
766
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
767
|
+
invoke_tester_finder("mouse_click", finder_id, finder_index: finder_index, timeout: timeout, on_result: on_result)
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
def mouse_double_click(finder_id = nil, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
771
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
772
|
+
invoke_tester_finder("mouse_double_click", finder_id, finder_index: finder_index, timeout: timeout, on_result: on_result)
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
def right_mouse_click(finder_id = nil, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
776
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
777
|
+
invoke_tester_finder("right_mouse_click", finder_id, finder_index: finder_index, timeout: timeout, on_result: on_result)
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def tap_at(offset = nil, timeout: 10, on_result: nil)
|
|
781
|
+
invoke_tester_at("tap_at", offset, timeout: timeout, on_result: on_result)
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
def mouse_click_at(offset = nil, timeout: 10, on_result: nil)
|
|
785
|
+
invoke_tester_at("mouse_click_at", offset, timeout: timeout, on_result: on_result)
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
def mouse_double_click_at(offset = nil, timeout: 10, on_result: nil)
|
|
789
|
+
invoke_tester_at("mouse_double_click_at", offset, timeout: timeout, on_result: on_result)
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
def right_mouse_click_at(offset = nil, timeout: 10, on_result: nil)
|
|
793
|
+
invoke_tester_at("right_mouse_click_at", offset, timeout: timeout, on_result: on_result)
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
def drag(finder_id, offset, finder_index: nil, timeout: 10, on_result: nil)
|
|
797
|
+
invoke_tester(
|
|
798
|
+
"drag",
|
|
799
|
+
args: compact_service_args(
|
|
800
|
+
"finder_id" => finder_id,
|
|
801
|
+
"finder_index" => finder_index,
|
|
802
|
+
"offset" => offset
|
|
803
|
+
),
|
|
804
|
+
timeout: timeout,
|
|
805
|
+
on_result: on_result
|
|
806
|
+
)
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
def drag_from(start, offset, timeout: 10, on_result: nil)
|
|
810
|
+
invoke_tester(
|
|
811
|
+
"drag_from",
|
|
812
|
+
args: compact_service_args("start" => start, "offset" => offset),
|
|
813
|
+
timeout: timeout,
|
|
814
|
+
on_result: on_result
|
|
815
|
+
)
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def long_press(finder_id = nil, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
819
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
820
|
+
invoke_tester_finder("long_press", finder_id, finder_index: finder_index, timeout: timeout, on_result: on_result)
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
def enter_text(finder_id, text, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
824
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
825
|
+
invoke_tester(
|
|
826
|
+
"enter_text",
|
|
827
|
+
args: compact_service_args(
|
|
828
|
+
"finder_id" => finder_id,
|
|
829
|
+
"finder_index" => finder_index,
|
|
830
|
+
"text" => text
|
|
831
|
+
),
|
|
832
|
+
timeout: timeout,
|
|
833
|
+
on_result: on_result
|
|
834
|
+
)
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
def mouse_hover(finder_id = nil, options = nil, finder_index: nil, timeout: 10, on_result: nil)
|
|
838
|
+
finder_index = options[:finder_index] || options["finder_index"] if options.is_a?(Hash) && finder_index.nil?
|
|
839
|
+
invoke_tester_finder("mouse_hover", finder_id, finder_index: finder_index, timeout: timeout, on_result: on_result)
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
def tester_teardown(timeout: 10, on_result: nil)
|
|
843
|
+
invoke_tester("teardown", timeout: timeout, on_result: on_result)
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
def heavy_impact(timeout: 10, on_result: nil)
|
|
847
|
+
invoke_haptic_feedback("heavy_impact", timeout: timeout, on_result: on_result)
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
def medium_impact(timeout: 10, on_result: nil)
|
|
851
|
+
invoke_haptic_feedback("medium_impact", timeout: timeout, on_result: on_result)
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
def light_impact(timeout: 10, on_result: nil)
|
|
855
|
+
invoke_haptic_feedback("light_impact", timeout: timeout, on_result: on_result)
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
def selection_click(timeout: 10, on_result: nil)
|
|
859
|
+
invoke_haptic_feedback("selection_click", timeout: timeout, on_result: on_result)
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
def vibrate(timeout: 10, on_result: nil)
|
|
863
|
+
invoke_haptic_feedback("vibrate", timeout: timeout, on_result: on_result)
|
|
864
|
+
end
|
|
865
|
+
|
|
394
866
|
def set_clipboard(value, timeout: nil, on_result: nil)
|
|
395
867
|
invoke_clipboard_method(
|
|
396
|
-
"
|
|
868
|
+
"set",
|
|
397
869
|
args: { "data" => value.to_s },
|
|
398
870
|
timeout: timeout,
|
|
399
871
|
on_result: on_result
|
|
@@ -401,7 +873,7 @@ module Ruflet
|
|
|
401
873
|
end
|
|
402
874
|
|
|
403
875
|
def get_clipboard(timeout: nil, on_result: nil)
|
|
404
|
-
invoke_clipboard_method("
|
|
876
|
+
invoke_clipboard_method("get", timeout: timeout, on_result: on_result)
|
|
405
877
|
end
|
|
406
878
|
|
|
407
879
|
def set_clipboard_files(files, timeout: nil, on_result: nil)
|
|
@@ -442,10 +914,94 @@ module Ruflet
|
|
|
442
914
|
invoke_battery_method("get_battery_state", timeout: timeout, on_result: on_result)
|
|
443
915
|
end
|
|
444
916
|
|
|
445
|
-
def
|
|
917
|
+
def is_in_battery_save_mode(timeout: nil, on_result: nil)
|
|
446
918
|
invoke_battery_method("is_in_battery_save_mode", timeout: timeout, on_result: on_result)
|
|
447
919
|
end
|
|
448
920
|
|
|
921
|
+
def battery_save_mode?(timeout: nil, on_result: nil)
|
|
922
|
+
is_in_battery_save_mode(timeout: timeout, on_result: on_result)
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
def accelerometer(**props)
|
|
926
|
+
service(:accelerometer, **props)
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
def gyroscope(**props)
|
|
930
|
+
service(:gyroscope, **props)
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
def user_accelerometer(**props)
|
|
934
|
+
service(:user_accelerometer, **props)
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
def magnetometer(**props)
|
|
938
|
+
service(:magnetometer, **props)
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
def barometer(**props)
|
|
942
|
+
service(:barometer, **props)
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
def shake_detector(**props)
|
|
946
|
+
service(:shake_detector, **props)
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
def semantics_service(**props)
|
|
950
|
+
service(:semantics_service, **props)
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
def screenshot(**props)
|
|
954
|
+
service(:screenshot, **props)
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
def battery(**props)
|
|
958
|
+
service(:battery, **props)
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
def connectivity(**props)
|
|
962
|
+
service(:connectivity, **props)
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
def clipboard(**props)
|
|
966
|
+
service(:clipboard, **props)
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
def file_picker(**props)
|
|
970
|
+
service(:file_picker, **props)
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
def url_launcher(**props)
|
|
974
|
+
service(:url_launcher, **props)
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
def storage_paths(**props)
|
|
978
|
+
service(:storage_paths, **props)
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def share(**props)
|
|
982
|
+
service(:share, **props)
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
def camera(**props)
|
|
986
|
+
service(:camera, **props)
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
def haptic_feedback(**props)
|
|
990
|
+
service(:haptic_feedback, **props)
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
def geolocator(**props)
|
|
994
|
+
service(:geolocator, **props)
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
def permission_handler(**props)
|
|
998
|
+
service(:permission_handler, **props)
|
|
999
|
+
end
|
|
1000
|
+
|
|
1001
|
+
def secure_storage(**props)
|
|
1002
|
+
service(:secure_storage, **props)
|
|
1003
|
+
end
|
|
1004
|
+
|
|
449
1005
|
def get_application_cache_directory(timeout: nil, on_result: nil)
|
|
450
1006
|
invoke_storage_paths("get_application_cache_directory", timeout: timeout, on_result: on_result)
|
|
451
1007
|
end
|
|
@@ -487,7 +1043,7 @@ module Ruflet
|
|
|
487
1043
|
end
|
|
488
1044
|
|
|
489
1045
|
def share_text(
|
|
490
|
-
text
|
|
1046
|
+
text = nil,
|
|
491
1047
|
title: nil,
|
|
492
1048
|
subject: nil,
|
|
493
1049
|
preview_thumbnail: nil,
|
|
@@ -502,7 +1058,7 @@ module Ruflet
|
|
|
502
1058
|
invoke(
|
|
503
1059
|
share,
|
|
504
1060
|
"share_text",
|
|
505
|
-
args:
|
|
1061
|
+
args: compact_service_args(
|
|
506
1062
|
"text" => text,
|
|
507
1063
|
"title" => title,
|
|
508
1064
|
"subject" => subject,
|
|
@@ -511,14 +1067,14 @@ module Ruflet
|
|
|
511
1067
|
"download_fallback_enabled" => download_fallback_enabled,
|
|
512
1068
|
"mail_to_fallback_enabled" => mail_to_fallback_enabled,
|
|
513
1069
|
"excluded_cupertino_activities" => excluded_cupertino_activities
|
|
514
|
-
|
|
1070
|
+
),
|
|
515
1071
|
timeout: timeout,
|
|
516
1072
|
on_result: on_result
|
|
517
1073
|
)
|
|
518
1074
|
end
|
|
519
1075
|
|
|
520
1076
|
def share_uri(
|
|
521
|
-
uri
|
|
1077
|
+
uri = nil,
|
|
522
1078
|
share_position_origin: nil,
|
|
523
1079
|
excluded_cupertino_activities: nil,
|
|
524
1080
|
timeout: nil,
|
|
@@ -528,18 +1084,18 @@ module Ruflet
|
|
|
528
1084
|
invoke(
|
|
529
1085
|
share,
|
|
530
1086
|
"share_uri",
|
|
531
|
-
args:
|
|
1087
|
+
args: compact_service_args(
|
|
532
1088
|
"uri" => uri,
|
|
533
1089
|
"share_position_origin" => share_position_origin,
|
|
534
1090
|
"excluded_cupertino_activities" => excluded_cupertino_activities
|
|
535
|
-
|
|
1091
|
+
),
|
|
536
1092
|
timeout: timeout,
|
|
537
1093
|
on_result: on_result
|
|
538
1094
|
)
|
|
539
1095
|
end
|
|
540
1096
|
|
|
541
1097
|
def share_files(
|
|
542
|
-
files
|
|
1098
|
+
files = nil,
|
|
543
1099
|
text: nil,
|
|
544
1100
|
title: nil,
|
|
545
1101
|
subject: nil,
|
|
@@ -555,17 +1111,17 @@ module Ruflet
|
|
|
555
1111
|
invoke(
|
|
556
1112
|
share,
|
|
557
1113
|
"share_files",
|
|
558
|
-
args:
|
|
559
|
-
"files" => files,
|
|
1114
|
+
args: compact_service_args(
|
|
1115
|
+
"files" => normalize_share_files(files),
|
|
560
1116
|
"text" => text,
|
|
561
1117
|
"title" => title,
|
|
562
1118
|
"subject" => subject,
|
|
563
|
-
"preview_thumbnail" => preview_thumbnail,
|
|
1119
|
+
"preview_thumbnail" => normalize_share_file(preview_thumbnail),
|
|
564
1120
|
"share_position_origin" => share_position_origin,
|
|
565
1121
|
"download_fallback_enabled" => download_fallback_enabled,
|
|
566
1122
|
"mail_to_fallback_enabled" => mail_to_fallback_enabled,
|
|
567
1123
|
"excluded_cupertino_activities" => excluded_cupertino_activities
|
|
568
|
-
|
|
1124
|
+
),
|
|
569
1125
|
timeout: timeout,
|
|
570
1126
|
on_result: on_result
|
|
571
1127
|
)
|
|
@@ -594,11 +1150,22 @@ module Ruflet
|
|
|
594
1150
|
return nil unless dialog_control
|
|
595
1151
|
|
|
596
1152
|
dialog_control.props["open"] = false
|
|
597
|
-
|
|
598
|
-
push_dialogs_update!
|
|
1153
|
+
update(dialog_control, open: false)
|
|
599
1154
|
dialog_control
|
|
600
1155
|
end
|
|
601
1156
|
|
|
1157
|
+
def close_dialog(dialog_control)
|
|
1158
|
+
return self unless dialog_control
|
|
1159
|
+
|
|
1160
|
+
before_dialog_count = @dialogs_container.props["controls"].length
|
|
1161
|
+
dialog_control.props["open"] = false
|
|
1162
|
+
@dialog = nil if @dialog.equal?(dialog_control)
|
|
1163
|
+
remove_dialog_tracking(dialog_control)
|
|
1164
|
+
refresh_dialogs_container!
|
|
1165
|
+
push_dialogs_update!(force_view: @dialogs_container.props["controls"].length < before_dialog_count)
|
|
1166
|
+
self
|
|
1167
|
+
end
|
|
1168
|
+
|
|
602
1169
|
def update(control_or_id = nil, **props)
|
|
603
1170
|
if control_or_id.nil? && props.empty?
|
|
604
1171
|
send_view_patch
|
|
@@ -634,6 +1201,7 @@ module Ruflet
|
|
|
634
1201
|
|
|
635
1202
|
visited = Set.new
|
|
636
1203
|
patch.each_value { |value| register_embedded_value(value, visited) }
|
|
1204
|
+
patch.each { |k, v| control.props[k] = v }
|
|
637
1205
|
|
|
638
1206
|
patch_ops = patch.map { |k, v| [0, 0, k, serialize_patch_value(v)] }
|
|
639
1207
|
|
|
@@ -656,8 +1224,6 @@ module Ruflet
|
|
|
656
1224
|
patch = normalize_props(props || {})
|
|
657
1225
|
patch.each { |k, v| control.props[k] = v }
|
|
658
1226
|
|
|
659
|
-
remove_dialog_tracking(control) if patch.key?("open") && patch["open"] == false
|
|
660
|
-
|
|
661
1227
|
self
|
|
662
1228
|
end
|
|
663
1229
|
|
|
@@ -675,11 +1241,13 @@ module Ruflet
|
|
|
675
1241
|
return unless control
|
|
676
1242
|
|
|
677
1243
|
event = Event.new(name: name, target: target, raw_data: data, page: self, control: control)
|
|
678
|
-
control
|
|
679
|
-
|
|
680
|
-
if name
|
|
681
|
-
push_dialogs_update!
|
|
1244
|
+
apply_event_value_to_control(control, event) if %w[change select select_change].include?(name.to_s)
|
|
1245
|
+
before_dialog_count = @dialogs_container.props["controls"].length
|
|
1246
|
+
if dialog_close_event?(control, name) && remove_dialog_tracking(control)
|
|
1247
|
+
push_dialogs_update!(force_view: @dialogs_container.props["controls"].length < before_dialog_count)
|
|
682
1248
|
end
|
|
1249
|
+
|
|
1250
|
+
control.emit(name, event)
|
|
683
1251
|
end
|
|
684
1252
|
|
|
685
1253
|
def method_missing(name, *args, &block)
|
|
@@ -754,10 +1322,56 @@ module Ruflet
|
|
|
754
1322
|
|
|
755
1323
|
def build_widget(type, **props, &block) = WidgetBuilder.new.control(type, **props, &block)
|
|
756
1324
|
|
|
1325
|
+
def compact_service_args(hash)
|
|
1326
|
+
hash.each_with_object({}) do |(key, value), result|
|
|
1327
|
+
result[key] = normalize_service_value(value) unless value.nil?
|
|
1328
|
+
end
|
|
1329
|
+
end
|
|
1330
|
+
|
|
1331
|
+
def normalize_service_value(value)
|
|
1332
|
+
case value
|
|
1333
|
+
when Array
|
|
1334
|
+
value.map { |item| normalize_service_value(item) }
|
|
1335
|
+
when Hash
|
|
1336
|
+
value.transform_keys(&:to_s).each_with_object({}) do |(key, item), result|
|
|
1337
|
+
next if item.nil?
|
|
1338
|
+
|
|
1339
|
+
result[key] = key == "data" && byte_array?(item) ? item.pack("C*").b : normalize_service_value(item)
|
|
1340
|
+
end
|
|
1341
|
+
else
|
|
1342
|
+
value
|
|
1343
|
+
end
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
def normalize_share_files(files)
|
|
1347
|
+
return nil if files.nil?
|
|
1348
|
+
|
|
1349
|
+
Array(files).map { |file| normalize_share_file(file) }
|
|
1350
|
+
end
|
|
1351
|
+
|
|
1352
|
+
def normalize_share_file(file)
|
|
1353
|
+
case file
|
|
1354
|
+
when nil
|
|
1355
|
+
nil
|
|
1356
|
+
when String
|
|
1357
|
+
{ "path" => file }
|
|
1358
|
+
else
|
|
1359
|
+
normalize_service_value(file)
|
|
1360
|
+
end
|
|
1361
|
+
end
|
|
1362
|
+
|
|
1363
|
+
def byte_array?(value)
|
|
1364
|
+
value.is_a?(Array) && value.all? { |item| item.is_a?(Integer) && item.between?(0, 255) }
|
|
1365
|
+
end
|
|
1366
|
+
|
|
757
1367
|
def widget_helper_method?(name)
|
|
758
1368
|
WIDGET_HELPER_METHODS.include?(name.to_s)
|
|
759
1369
|
end
|
|
760
1370
|
|
|
1371
|
+
def visual_service_type?(type)
|
|
1372
|
+
type.to_s.delete("_") == "camera"
|
|
1373
|
+
end
|
|
1374
|
+
|
|
761
1375
|
def text_maps_to_content?(control, patch)
|
|
762
1376
|
patch.key?("text") && control.type.end_with?("button")
|
|
763
1377
|
end
|
|
@@ -772,6 +1386,14 @@ module Ruflet
|
|
|
772
1386
|
@sender.call(action, payload)
|
|
773
1387
|
end
|
|
774
1388
|
|
|
1389
|
+
def update_view_slot(name, value)
|
|
1390
|
+
if value.nil?
|
|
1391
|
+
@view_props.delete(name)
|
|
1392
|
+
else
|
|
1393
|
+
@view_props[name] = value
|
|
1394
|
+
end
|
|
1395
|
+
end
|
|
1396
|
+
|
|
775
1397
|
def send_view_patch
|
|
776
1398
|
refresh_control_indexes!
|
|
777
1399
|
view_patches = build_view_patches
|
|
@@ -781,10 +1403,13 @@ module Ruflet
|
|
|
781
1403
|
"id" => 1,
|
|
782
1404
|
"patch" => [
|
|
783
1405
|
[0],
|
|
784
|
-
|
|
785
|
-
|
|
1406
|
+
*page_patch_ops,
|
|
1407
|
+
[0, 0, "views", view_patches]
|
|
786
1408
|
]
|
|
787
1409
|
})
|
|
1410
|
+
@overlay_container_mounted = true if @overlay_container.wire_id
|
|
1411
|
+
@dialogs_container_mounted = true if @dialogs_container.wire_id
|
|
1412
|
+
@services_container_mounted = true if @services_container.wire_id
|
|
788
1413
|
end
|
|
789
1414
|
|
|
790
1415
|
def register_control_tree(control, visited = Set.new)
|
|
@@ -895,6 +1520,15 @@ module Ruflet
|
|
|
895
1520
|
"#{base}#{separator}#{query}"
|
|
896
1521
|
end
|
|
897
1522
|
|
|
1523
|
+
def parse_query(route_value)
|
|
1524
|
+
query_string = route_value.to_s.split("?", 2)[1].to_s
|
|
1525
|
+
return {} if query_string.empty?
|
|
1526
|
+
|
|
1527
|
+
CGI.parse(query_string).each_with_object({}) do |(key, values), result|
|
|
1528
|
+
result[key] = values.size == 1 ? values.first : values
|
|
1529
|
+
end
|
|
1530
|
+
end
|
|
1531
|
+
|
|
898
1532
|
def extract_route(data)
|
|
899
1533
|
case data
|
|
900
1534
|
when String
|
|
@@ -910,10 +1544,46 @@ module Ruflet
|
|
|
910
1544
|
handler = @page_event_handlers[name.to_s.sub(/\Aon_/, "")]
|
|
911
1545
|
return unless handler.respond_to?(:call)
|
|
912
1546
|
|
|
913
|
-
event = Event.new(name: name.to_s, target: 1, raw_data: data, page: self, control: nil)
|
|
1547
|
+
event = Ruflet::Event.new(name: name.to_s, target: 1, raw_data: data, page: self, control: nil)
|
|
914
1548
|
handler.call(event)
|
|
915
1549
|
end
|
|
916
1550
|
|
|
1551
|
+
def apply_event_value_to_control(control, event)
|
|
1552
|
+
return unless event.typed_data && event.typed_data.respond_to?(:value)
|
|
1553
|
+
|
|
1554
|
+
value = event.typed_data.value
|
|
1555
|
+
if control.props.key?("start_value") && control.props.key?("end_value")
|
|
1556
|
+
raw = event.typed_data.respond_to?(:raw) ? event.typed_data.raw : event.data
|
|
1557
|
+
range_value = value.is_a?(Hash) ? value : raw
|
|
1558
|
+
if range_value.is_a?(Hash)
|
|
1559
|
+
start_value = range_value["start_value"] || range_value[:start_value]
|
|
1560
|
+
end_value = range_value["end_value"] || range_value[:end_value]
|
|
1561
|
+
control.props["start_value"] = start_value unless start_value.nil?
|
|
1562
|
+
control.props["end_value"] = end_value unless end_value.nil?
|
|
1563
|
+
end
|
|
1564
|
+
return
|
|
1565
|
+
end
|
|
1566
|
+
|
|
1567
|
+
return if value.nil?
|
|
1568
|
+
return if control.type == "selectionarea"
|
|
1569
|
+
|
|
1570
|
+
prop_name =
|
|
1571
|
+
if event.name == "select"
|
|
1572
|
+
control.props.key?("value") ? "value" : "selected"
|
|
1573
|
+
elsif event.name == "select_change" && control.props.key?("selected")
|
|
1574
|
+
"selected"
|
|
1575
|
+
elsif control.props.key?("expanded")
|
|
1576
|
+
"expanded"
|
|
1577
|
+
elsif control.props.key?("selected")
|
|
1578
|
+
"selected"
|
|
1579
|
+
elsif control.props.key?("selected_index")
|
|
1580
|
+
"selected_index"
|
|
1581
|
+
else
|
|
1582
|
+
"value"
|
|
1583
|
+
end
|
|
1584
|
+
control.props[prop_name] = value
|
|
1585
|
+
end
|
|
1586
|
+
|
|
917
1587
|
def page_control_target?(control_or_id)
|
|
918
1588
|
control_or_id == 1 || control_or_id.to_s == "1" || control_or_id.to_s == "page"
|
|
919
1589
|
end
|
|
@@ -927,7 +1597,7 @@ module Ruflet
|
|
|
927
1597
|
when Array
|
|
928
1598
|
value.map { |v| serialize_patch_value(v) }
|
|
929
1599
|
when Hash
|
|
930
|
-
value.
|
|
1600
|
+
value.each_with_object({}) { |(k, v), result| result[k.to_s] = serialize_patch_value(v) }
|
|
931
1601
|
else
|
|
932
1602
|
value
|
|
933
1603
|
end
|
|
@@ -938,7 +1608,7 @@ module Ruflet
|
|
|
938
1608
|
end
|
|
939
1609
|
|
|
940
1610
|
def refresh_dialogs_container!
|
|
941
|
-
dialog_controls = (
|
|
1611
|
+
dialog_controls = (dialog_slots + @dialogs).uniq
|
|
942
1612
|
@dialogs_container.props["controls"] = dialog_controls
|
|
943
1613
|
@page_props["_dialogs"] = @dialogs_container
|
|
944
1614
|
end
|
|
@@ -964,9 +1634,15 @@ module Ruflet
|
|
|
964
1634
|
end
|
|
965
1635
|
end
|
|
966
1636
|
|
|
967
|
-
def push_dialogs_update!
|
|
1637
|
+
def push_dialogs_update!(force_view: false)
|
|
968
1638
|
refresh_control_indexes!
|
|
969
1639
|
|
|
1640
|
+
if force_view || @dialogs_container.props["controls"].empty?
|
|
1641
|
+
@dialogs_container_mounted = false
|
|
1642
|
+
send_view_patch
|
|
1643
|
+
return
|
|
1644
|
+
end
|
|
1645
|
+
|
|
970
1646
|
if @dialogs_container.wire_id
|
|
971
1647
|
send_message(Protocol::ACTIONS[:patch_control], {
|
|
972
1648
|
"id" => @dialogs_container.wire_id,
|
|
@@ -989,6 +1665,11 @@ module Ruflet
|
|
|
989
1665
|
@dialogs.include?(dialog_control) && dialog_control.props["open"] == true
|
|
990
1666
|
end
|
|
991
1667
|
|
|
1668
|
+
def dialog_close_event?(control, name)
|
|
1669
|
+
name = name.to_s
|
|
1670
|
+
name == "dismiss" || (%w[change select select_change].include?(name) && @dialogs.include?(control) && control.props["open"] == false)
|
|
1671
|
+
end
|
|
1672
|
+
|
|
992
1673
|
def remove_dialog_tracking(control)
|
|
993
1674
|
return false unless @dialogs.include?(control)
|
|
994
1675
|
|
|
@@ -997,6 +1678,16 @@ module Ruflet
|
|
|
997
1678
|
true
|
|
998
1679
|
end
|
|
999
1680
|
|
|
1681
|
+
def remove_existing_singleton_dialogs(control)
|
|
1682
|
+
return unless singleton_dialog_control?(control)
|
|
1683
|
+
|
|
1684
|
+
@dialogs.delete_if { |dialog| dialog != control && singleton_dialog_control?(dialog) }
|
|
1685
|
+
end
|
|
1686
|
+
|
|
1687
|
+
def singleton_dialog_control?(control)
|
|
1688
|
+
control.type.to_s.tr("_", "").downcase == "snackbar"
|
|
1689
|
+
end
|
|
1690
|
+
|
|
1000
1691
|
def assign_split_prop(key, value)
|
|
1001
1692
|
if key == "vertical_alignment" || key == "horizontal_alignment"
|
|
1002
1693
|
@page_props[key] = value
|
|
@@ -1024,202 +1715,233 @@ module Ruflet
|
|
|
1024
1715
|
# Keep internal containers stable after initial mount.
|
|
1025
1716
|
# Re-sending them as full objects can replace Control instances with
|
|
1026
1717
|
# same IDs and detach service invoke listeners on the Flutter side.
|
|
1027
|
-
next nil if k == "_overlay" && @
|
|
1028
|
-
next nil if k == "_dialogs" && @
|
|
1718
|
+
next nil if k == "_overlay" && @overlay_container_mounted
|
|
1719
|
+
next nil if k == "_dialogs" && @dialogs_container_mounted
|
|
1720
|
+
next nil if k == "_services" && @services_container_mounted
|
|
1029
1721
|
|
|
1030
1722
|
[0, 0, k, serialize_patch_value(v)]
|
|
1031
1723
|
end
|
|
1032
1724
|
end
|
|
1033
1725
|
|
|
1034
|
-
def
|
|
1035
|
-
|
|
1036
|
-
|
|
1726
|
+
def service_by_type(type)
|
|
1727
|
+
compact_type = type.to_s.downcase.delete("_")
|
|
1728
|
+
services.find do |service|
|
|
1729
|
+
service.is_a?(Control) && service.type.to_s.downcase.delete("_") == compact_type
|
|
1730
|
+
end
|
|
1731
|
+
end
|
|
1037
1732
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
[
|
|
1733
|
+
def service_with_created(type)
|
|
1734
|
+
existing = service_by_type(type)
|
|
1735
|
+
return [existing, false] if existing
|
|
1736
|
+
|
|
1737
|
+
[service(type), true]
|
|
1738
|
+
end
|
|
1739
|
+
|
|
1740
|
+
def ensure_clipboard_service
|
|
1741
|
+
service_with_created(:clipboard)
|
|
1041
1742
|
end
|
|
1042
1743
|
|
|
1043
1744
|
def invoke_clipboard_method(method_name, args: nil, timeout:, on_result:)
|
|
1044
|
-
clipboard,
|
|
1045
|
-
send_view_patch if created
|
|
1046
|
-
sleep(0.05) if created
|
|
1745
|
+
clipboard, = ensure_clipboard_service
|
|
1047
1746
|
invoke(
|
|
1048
1747
|
clipboard,
|
|
1049
1748
|
method_name,
|
|
1050
1749
|
args: args,
|
|
1051
1750
|
timeout: timeout,
|
|
1052
|
-
on_result:
|
|
1053
|
-
message = error.to_s
|
|
1054
|
-
if message.include?("inexistent control")
|
|
1055
|
-
remove_service(clipboard)
|
|
1056
|
-
fresh_clipboard, = ensure_clipboard_service
|
|
1057
|
-
sleep(0.08)
|
|
1058
|
-
invoke(
|
|
1059
|
-
fresh_clipboard,
|
|
1060
|
-
method_name,
|
|
1061
|
-
args: args,
|
|
1062
|
-
timeout: timeout,
|
|
1063
|
-
on_result: on_result
|
|
1064
|
-
)
|
|
1065
|
-
else
|
|
1066
|
-
on_result&.call(result, error)
|
|
1067
|
-
end
|
|
1068
|
-
}
|
|
1751
|
+
on_result: on_result
|
|
1069
1752
|
)
|
|
1070
1753
|
rescue StandardError => e
|
|
1071
1754
|
on_result&.call(nil, e.message)
|
|
1072
1755
|
end
|
|
1073
1756
|
|
|
1074
1757
|
def ensure_url_launcher_service
|
|
1075
|
-
|
|
1076
|
-
|
|
1758
|
+
service(:url_launcher)
|
|
1759
|
+
end
|
|
1077
1760
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
url_launcher
|
|
1761
|
+
def ensure_browser_context_menu_service
|
|
1762
|
+
service(:browser_context_menu)
|
|
1081
1763
|
end
|
|
1082
1764
|
|
|
1083
|
-
def
|
|
1084
|
-
|
|
1085
|
-
|
|
1765
|
+
def invoke_browser_context_menu(method_name, timeout:, on_result:)
|
|
1766
|
+
browser_context_menu = ensure_browser_context_menu_service
|
|
1767
|
+
invoke(browser_context_menu, method_name, timeout: timeout, on_result: on_result)
|
|
1768
|
+
end
|
|
1769
|
+
|
|
1770
|
+
def ensure_window_service
|
|
1771
|
+
service(:window)
|
|
1772
|
+
end
|
|
1773
|
+
|
|
1774
|
+
def invoke_window(method_name, args: nil, timeout:, on_result:)
|
|
1775
|
+
window = ensure_window_service
|
|
1776
|
+
invoke(window, method_name, args: args, timeout: timeout, on_result: on_result)
|
|
1777
|
+
end
|
|
1778
|
+
|
|
1779
|
+
def ensure_tester_service
|
|
1780
|
+
service(:tester)
|
|
1781
|
+
end
|
|
1782
|
+
|
|
1783
|
+
def invoke_tester(method_name, args: nil, timeout:, on_result:)
|
|
1784
|
+
tester = ensure_tester_service
|
|
1785
|
+
invoke(tester, method_name, args: args, timeout: timeout, on_result: on_result)
|
|
1786
|
+
end
|
|
1086
1787
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1788
|
+
def invoke_tester_finder(method_name, finder_id, finder_index:, timeout:, on_result:)
|
|
1789
|
+
invoke_tester(
|
|
1790
|
+
method_name,
|
|
1791
|
+
args: compact_service_args("finder_id" => finder_id, "finder_index" => finder_index),
|
|
1792
|
+
timeout: timeout,
|
|
1793
|
+
on_result: on_result
|
|
1794
|
+
)
|
|
1795
|
+
end
|
|
1796
|
+
|
|
1797
|
+
def invoke_tester_at(method_name, offset, timeout:, on_result:)
|
|
1798
|
+
invoke_tester(
|
|
1799
|
+
method_name,
|
|
1800
|
+
args: compact_service_args("offset" => offset),
|
|
1801
|
+
timeout: timeout,
|
|
1802
|
+
on_result: on_result
|
|
1803
|
+
)
|
|
1804
|
+
end
|
|
1805
|
+
|
|
1806
|
+
def ensure_haptic_feedback_service
|
|
1807
|
+
service(:haptic_feedback)
|
|
1808
|
+
end
|
|
1809
|
+
|
|
1810
|
+
def invoke_haptic_feedback(method_name, timeout:, on_result:)
|
|
1811
|
+
haptic_feedback = ensure_haptic_feedback_service
|
|
1812
|
+
invoke(haptic_feedback, method_name, timeout: timeout, on_result: on_result)
|
|
1813
|
+
end
|
|
1814
|
+
|
|
1815
|
+
def invoke_current_view(method_name, timeout:, on_result:)
|
|
1816
|
+
target_id = @views.last&.wire_id || @view_id
|
|
1817
|
+
invoke_control_id(target_id, method_name, timeout: timeout, on_result: on_result)
|
|
1818
|
+
end
|
|
1819
|
+
|
|
1820
|
+
def invoke_control_id(control_id, method_name, args: nil, timeout: 10, on_result: nil)
|
|
1821
|
+
call_id = "call_#{Ruflet::Control.generate_id}"
|
|
1822
|
+
if on_result.respond_to?(:call)
|
|
1823
|
+
@invoke_waiters_mutex.synchronize { @invoke_callbacks[call_id] = on_result }
|
|
1824
|
+
unless timeout.nil?
|
|
1825
|
+
Thread.new(call_id, timeout.to_f) do |pending_call_id, invoke_timeout|
|
|
1826
|
+
sleep([invoke_timeout, 0.0].max + 0.1)
|
|
1827
|
+
callback = @invoke_waiters_mutex.synchronize { @invoke_callbacks.delete(pending_call_id) }
|
|
1828
|
+
callback&.call(nil, "execution expired")
|
|
1829
|
+
rescue StandardError => e
|
|
1830
|
+
Kernel.warn("invoke timeout callback error: #{e.class}: #{e.message}")
|
|
1831
|
+
end
|
|
1832
|
+
end
|
|
1833
|
+
end
|
|
1834
|
+
|
|
1835
|
+
payload = {
|
|
1836
|
+
"control_id" => control_id,
|
|
1837
|
+
"call_id" => call_id,
|
|
1838
|
+
"name" => method_name.to_s,
|
|
1839
|
+
"args" => args
|
|
1840
|
+
}
|
|
1841
|
+
payload["timeout"] = timeout unless timeout.nil?
|
|
1842
|
+
send_message(Protocol::ACTIONS[:invoke_control_method], payload)
|
|
1843
|
+
|
|
1844
|
+
call_id
|
|
1845
|
+
end
|
|
1846
|
+
|
|
1847
|
+
def ensure_connectivity_service
|
|
1848
|
+
service_with_created(:connectivity)
|
|
1090
1849
|
end
|
|
1091
1850
|
|
|
1092
1851
|
def invoke_connectivity_method(method_name, timeout:, on_result:)
|
|
1093
|
-
connectivity,
|
|
1094
|
-
send_view_patch if created
|
|
1095
|
-
sleep(0.05) if created
|
|
1852
|
+
connectivity, = ensure_connectivity_service
|
|
1096
1853
|
invoke(
|
|
1097
1854
|
connectivity,
|
|
1098
1855
|
method_name,
|
|
1099
1856
|
timeout: timeout,
|
|
1100
|
-
on_result:
|
|
1101
|
-
message = error.to_s
|
|
1102
|
-
if message.include?("inexistent control")
|
|
1103
|
-
remove_service(connectivity)
|
|
1104
|
-
fresh_connectivity, = ensure_connectivity_service
|
|
1105
|
-
sleep(0.08)
|
|
1106
|
-
invoke(
|
|
1107
|
-
fresh_connectivity,
|
|
1108
|
-
method_name,
|
|
1109
|
-
timeout: timeout,
|
|
1110
|
-
on_result: on_result
|
|
1111
|
-
)
|
|
1112
|
-
else
|
|
1113
|
-
on_result&.call(result, error)
|
|
1114
|
-
end
|
|
1115
|
-
}
|
|
1857
|
+
on_result: on_result
|
|
1116
1858
|
)
|
|
1117
1859
|
rescue StandardError => e
|
|
1118
1860
|
on_result&.call(nil, e.message)
|
|
1119
1861
|
end
|
|
1120
1862
|
|
|
1121
1863
|
def ensure_battery_service
|
|
1122
|
-
battery
|
|
1123
|
-
return [battery, false] if battery
|
|
1124
|
-
|
|
1125
|
-
battery = build_widget(:battery)
|
|
1126
|
-
add_service(battery)
|
|
1127
|
-
[battery, true]
|
|
1864
|
+
service_with_created(:battery)
|
|
1128
1865
|
end
|
|
1129
1866
|
|
|
1130
1867
|
def ensure_share_service
|
|
1131
|
-
|
|
1132
|
-
|
|
1868
|
+
service(:share)
|
|
1869
|
+
end
|
|
1870
|
+
|
|
1871
|
+
def ensure_shared_preferences_service
|
|
1872
|
+
service(:shared_preferences)
|
|
1873
|
+
end
|
|
1874
|
+
|
|
1875
|
+
def invoke_shared_preferences(method_name, args: nil, timeout:, on_result:)
|
|
1876
|
+
shared_preferences = ensure_shared_preferences_service
|
|
1877
|
+
invoke(shared_preferences, method_name, args: args, timeout: timeout, on_result: on_result)
|
|
1878
|
+
end
|
|
1879
|
+
|
|
1880
|
+
def ensure_wakelock_service
|
|
1881
|
+
service(:wakelock)
|
|
1882
|
+
end
|
|
1883
|
+
|
|
1884
|
+
def invoke_wakelock(method_name, timeout:, on_result:)
|
|
1885
|
+
wakelock = ensure_wakelock_service
|
|
1886
|
+
invoke(wakelock, method_name, timeout: timeout, on_result: on_result)
|
|
1887
|
+
end
|
|
1888
|
+
|
|
1889
|
+
def ensure_flashlight_service
|
|
1890
|
+
service(:flashlight)
|
|
1891
|
+
end
|
|
1133
1892
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1893
|
+
def invoke_flashlight(method_name, timeout:, on_result:)
|
|
1894
|
+
flashlight = ensure_flashlight_service
|
|
1895
|
+
invoke(flashlight, method_name, timeout: timeout, on_result: on_result)
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
def ensure_screen_brightness_service
|
|
1899
|
+
service(:screen_brightness)
|
|
1900
|
+
end
|
|
1901
|
+
|
|
1902
|
+
def invoke_screen_brightness(method_name, args: nil, timeout:, on_result:)
|
|
1903
|
+
screen_brightness = ensure_screen_brightness_service
|
|
1904
|
+
invoke(screen_brightness, method_name, args: args, timeout: timeout, on_result: on_result)
|
|
1137
1905
|
end
|
|
1138
1906
|
|
|
1139
1907
|
def invoke_battery_method(method_name, timeout:, on_result:)
|
|
1140
|
-
battery,
|
|
1141
|
-
send_view_patch if created
|
|
1142
|
-
sleep(0.05) if created
|
|
1908
|
+
battery, = ensure_battery_service
|
|
1143
1909
|
invoke(
|
|
1144
1910
|
battery,
|
|
1145
1911
|
method_name,
|
|
1146
1912
|
timeout: timeout,
|
|
1147
|
-
on_result:
|
|
1148
|
-
message = error.to_s
|
|
1149
|
-
if message.include?("inexistent control")
|
|
1150
|
-
remove_service(battery)
|
|
1151
|
-
fresh_battery, = ensure_battery_service
|
|
1152
|
-
sleep(0.08)
|
|
1153
|
-
invoke(
|
|
1154
|
-
fresh_battery,
|
|
1155
|
-
method_name,
|
|
1156
|
-
timeout: timeout,
|
|
1157
|
-
on_result: on_result
|
|
1158
|
-
)
|
|
1159
|
-
else
|
|
1160
|
-
on_result&.call(result, error)
|
|
1161
|
-
end
|
|
1162
|
-
}
|
|
1913
|
+
on_result: on_result
|
|
1163
1914
|
)
|
|
1164
1915
|
rescue StandardError => e
|
|
1165
1916
|
on_result&.call(nil, e.message)
|
|
1166
1917
|
end
|
|
1167
1918
|
|
|
1168
1919
|
def ensure_storage_paths_service
|
|
1169
|
-
storage_paths
|
|
1170
|
-
service.is_a?(Control) && %w[storage_paths storagepaths].include?(service.type.to_s)
|
|
1171
|
-
end
|
|
1172
|
-
return [storage_paths, false] if storage_paths
|
|
1173
|
-
|
|
1174
|
-
storage_paths = build_widget(:storage_paths)
|
|
1175
|
-
add_service(storage_paths)
|
|
1176
|
-
[storage_paths, true]
|
|
1920
|
+
service_with_created(:storage_paths)
|
|
1177
1921
|
end
|
|
1178
1922
|
|
|
1179
1923
|
def invoke_storage_paths(method_name, timeout:, on_result:)
|
|
1180
|
-
storage_paths,
|
|
1181
|
-
send_view_patch if created
|
|
1182
|
-
sleep(0.05) if created
|
|
1924
|
+
storage_paths, = ensure_storage_paths_service
|
|
1183
1925
|
invoke(
|
|
1184
1926
|
storage_paths,
|
|
1185
1927
|
method_name,
|
|
1186
1928
|
timeout: timeout,
|
|
1187
|
-
on_result:
|
|
1188
|
-
message = error.to_s
|
|
1189
|
-
if message.include?("inexistent control")
|
|
1190
|
-
remove_service(storage_paths)
|
|
1191
|
-
fresh_storage_paths, = ensure_storage_paths_service
|
|
1192
|
-
sleep(0.08)
|
|
1193
|
-
invoke(
|
|
1194
|
-
fresh_storage_paths,
|
|
1195
|
-
method_name,
|
|
1196
|
-
timeout: timeout,
|
|
1197
|
-
on_result: on_result
|
|
1198
|
-
)
|
|
1199
|
-
else
|
|
1200
|
-
on_result&.call(result, error)
|
|
1201
|
-
end
|
|
1202
|
-
}
|
|
1929
|
+
on_result: on_result
|
|
1203
1930
|
)
|
|
1204
1931
|
rescue StandardError => e
|
|
1205
1932
|
on_result&.call(nil, e.message)
|
|
1206
1933
|
end
|
|
1207
1934
|
|
|
1208
1935
|
def invoke_file_picker(method_name, args, timeout:, on_result:)
|
|
1209
|
-
picker =
|
|
1210
|
-
add_service(picker)
|
|
1936
|
+
picker = service(:file_picker)
|
|
1211
1937
|
invoke(
|
|
1212
1938
|
picker,
|
|
1213
1939
|
method_name,
|
|
1214
1940
|
args: args,
|
|
1215
1941
|
timeout: timeout,
|
|
1216
|
-
on_result:
|
|
1217
|
-
remove_service(picker)
|
|
1218
|
-
on_result&.call(result, error)
|
|
1219
|
-
}
|
|
1942
|
+
on_result: on_result
|
|
1220
1943
|
)
|
|
1221
1944
|
rescue StandardError => e
|
|
1222
|
-
remove_service(picker) if picker
|
|
1223
1945
|
on_result&.call(nil, e.message)
|
|
1224
1946
|
end
|
|
1225
1947
|
end
|