ruflet_core 0.0.21 → 0.0.22

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ruflet/version.rb +1 -1
  3. data/lib/ruflet_ui/ruflet/dsl.rb +76 -0
  4. data/lib/ruflet_ui/ruflet/event.rb +3 -2
  5. data/lib/ruflet_ui/ruflet/events/gesture_events.rb +2 -1
  6. data/lib/ruflet_ui/ruflet/page.rb +242 -4
  7. data/lib/ruflet_ui/ruflet/ui/control_factory.rb +2 -0
  8. data/lib/ruflet_ui/ruflet/ui/control_methods.rb +4 -0
  9. data/lib/ruflet_ui/ruflet/ui/control_registry.rb +20 -1
  10. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheet_control.rb +1 -1
  11. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheetaction_control.rb +1 -1
  12. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactivityindicator_control.rb +1 -1
  13. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoalertdialog_control.rb +1 -1
  14. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoappbar_control.rb +1 -1
  15. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobottomsheet_control.rb +1 -1
  16. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobutton_control.rb +1 -1
  17. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocheckbox_control.rb +1 -1
  18. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenu_control.rb +1 -1
  19. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenuaction_control.rb +1 -1
  20. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodatepicker_control.rb +1 -1
  21. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodialogaction_control.rb +1 -1
  22. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinofilledbutton_control.rb +1 -1
  23. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinolisttile_control.rb +1 -1
  24. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinonavigationbar_control.rb +1 -1
  25. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinopicker_control.rb +1 -1
  26. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoradio_control.rb +1 -1
  27. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinosegmentedbutton_control.rb +1 -1
  28. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslider_control.rb +1 -1
  29. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslidingsegmentedbutton_control.rb +1 -1
  30. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoswitch_control.rb +1 -1
  31. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotextfield_control.rb +1 -1
  32. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotimerpicker_control.rb +1 -1
  33. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotintedbutton_control.rb +1 -1
  34. data/lib/ruflet_ui/ruflet/ui/controls/materials/ad_controls.rb +45 -0
  35. data/lib/ruflet_ui/ruflet/ui/controls/materials/animation_extension_controls.rb +29 -0
  36. data/lib/ruflet_ui/ruflet/ui/controls/materials/chart_controls.rb +56 -279
  37. data/lib/ruflet_ui/ruflet/ui/controls/materials/code_editor_control.rb +42 -0
  38. data/lib/ruflet_ui/ruflet/ui/controls/materials/color_picker_controls.rb +34 -0
  39. data/lib/ruflet_ui/ruflet/ui/controls/materials/datatable2_controls.rb +41 -0
  40. data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownm2_control.rb +1 -1
  41. data/lib/ruflet_ui/ruflet/ui/controls/materials/map_control.rb +80 -0
  42. data/lib/ruflet_ui/ruflet/ui/controls/materials/ruflet_controls.rb +62 -0
  43. data/lib/ruflet_ui/ruflet/ui/controls/materials/video_control.rb +1 -2
  44. data/lib/ruflet_ui/ruflet/ui/controls/materials/webview_control.rb +5 -30
  45. data/lib/ruflet_ui/ruflet/ui/controls/ruflet_controls.rb +60 -0
  46. data/lib/ruflet_ui/ruflet/ui/controls/shared/browsercontextmenu_control.rb +17 -0
  47. data/lib/ruflet_ui/ruflet/ui/controls/shared/ruflet_app_control.rb +3 -3
  48. data/lib/ruflet_ui/ruflet/ui/controls/shared/serviceregistry_control.rb +5 -1
  49. data/lib/ruflet_ui/ruflet/ui/cupertino_control_methods.rb +2 -0
  50. data/lib/ruflet_ui/ruflet/ui/material_control_methods.rb +110 -6
  51. data/lib/ruflet_ui/ruflet/ui/material_control_registry.rb +23 -8
  52. data/lib/ruflet_ui/ruflet/ui/platform_control_contracts.rb +392 -0
  53. data/lib/ruflet_ui/ruflet/ui/platform_control_methods.rb +35 -0
  54. data/lib/ruflet_ui/ruflet/ui/services/current_service_methods.rb +220 -0
  55. data/lib/ruflet_ui/ruflet/ui/services/ruflet/camera_control.rb +88 -0
  56. data/lib/ruflet_ui/ruflet/ui/services/ruflet_services.rb +4 -0
  57. data/lib/ruflet_ui/ruflet/ui/shared_control_forwarders.rb +75 -0
  58. metadata +9 -1
@@ -0,0 +1,392 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "controls/ruflet_controls"
4
+
5
+ module Ruflet
6
+ module UI
7
+ # One Ruby protocol contract for controls whose visual implementation is
8
+ # selected by the Flet client. These schemas deliberately accept the union
9
+ # of the Material and Cupertino properties: Ruby describes intent and the
10
+ # platform renderer decides how that intent looks.
11
+ module PlatformControlContracts
12
+ module Components
13
+ class PlatformControl < Ruflet::Control
14
+ def initialize(id: nil, **props)
15
+ props = platform_defaults.merge(props)
16
+ validate_platform_props!(props)
17
+ compact = {}
18
+ props.each do |key, value|
19
+ raise ArgumentError, "unknown keyword: :#{key}" unless self.class::KEYWORDS.include?(key)
20
+
21
+ value = normalize_platform_prop(key, value)
22
+ compact[key] = value unless value.nil?
23
+ end
24
+ super(type: self.class::TYPE, id: id, **compact)
25
+ end
26
+
27
+ private
28
+
29
+ def platform_defaults = {}
30
+ def validate_platform_props!(_props); end
31
+ def normalize_platform_prop(_key, value) = value
32
+
33
+ def require_control_prop!(props, name)
34
+ value = props[name]
35
+ raise ArgumentError, "#{self.class::TYPE} requires #{name}" if value.nil?
36
+ end
37
+ end
38
+
39
+ class ButtonControl < PlatformControl
40
+ TYPE = "button".freeze
41
+ WIRE = "Button".freeze
42
+ KEYWORDS = (
43
+ Controls::RufletComponents::ButtonControl::KEYWORDS +
44
+ Controls::RufletComponents::CupertinoButtonControl::KEYWORDS +
45
+ %i[default destructive]
46
+ ).uniq.freeze
47
+
48
+ end
49
+
50
+ class FilledButtonControl < PlatformControl
51
+ TYPE = "filledbutton".freeze
52
+ WIRE = "FilledButton".freeze
53
+ KEYWORDS = (
54
+ Controls::RufletComponents::FilledButtonControl::KEYWORDS +
55
+ Controls::RufletComponents::CupertinoFilledButtonControl::KEYWORDS
56
+ ).uniq.freeze
57
+
58
+ private
59
+
60
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
61
+ end
62
+
63
+ class FilledTonalButtonControl < PlatformControl
64
+ TYPE = "filledtonalbutton".freeze
65
+ WIRE = "FilledTonalButton".freeze
66
+ KEYWORDS = (
67
+ Controls::RufletComponents::FilledTonalButtonControl::KEYWORDS +
68
+ Controls::RufletComponents::CupertinoTintedButtonControl::KEYWORDS
69
+ ).uniq.freeze
70
+
71
+ private
72
+
73
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
74
+ end
75
+
76
+ class OutlinedButtonControl < PlatformControl
77
+ TYPE = "outlinedbutton".freeze
78
+ WIRE = "OutlinedButton".freeze
79
+ KEYWORDS = (
80
+ Controls::RufletComponents::OutlinedButtonControl::KEYWORDS +
81
+ Controls::RufletComponents::CupertinoButtonControl::KEYWORDS
82
+ ).uniq.freeze
83
+
84
+ private
85
+
86
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
87
+ end
88
+
89
+ class TextButtonControl < PlatformControl
90
+ TYPE = "textbutton".freeze
91
+ WIRE = "TextButton".freeze
92
+ KEYWORDS = (
93
+ Controls::RufletComponents::TextButtonControl::KEYWORDS +
94
+ Controls::RufletComponents::CupertinoButtonControl::KEYWORDS
95
+ ).uniq.freeze
96
+
97
+ private
98
+
99
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
100
+ end
101
+
102
+ class TextFieldControl < PlatformControl
103
+ TYPE = "textfield".freeze
104
+ WIRE = "TextField".freeze
105
+ KEYWORDS = (
106
+ Controls::RufletComponents::TextFieldControl::KEYWORDS +
107
+ Controls::RufletComponents::CupertinoTextFieldControl::KEYWORDS
108
+ ).uniq.freeze
109
+ end
110
+
111
+ class CheckboxControl < PlatformControl
112
+ TYPE = "checkbox".freeze
113
+ WIRE = "Checkbox".freeze
114
+ KEYWORDS = (
115
+ Controls::RufletComponents::CheckboxControl::KEYWORDS +
116
+ Controls::RufletComponents::CupertinoCheckboxControl::KEYWORDS
117
+ ).uniq.freeze
118
+ end
119
+
120
+ class RadioControl < PlatformControl
121
+ TYPE = "radio".freeze
122
+ WIRE = "Radio".freeze
123
+ KEYWORDS = (
124
+ Controls::RufletComponents::RadioControl::KEYWORDS +
125
+ Controls::RufletComponents::CupertinoRadioControl::KEYWORDS
126
+ ).uniq.freeze
127
+ end
128
+
129
+ class SliderControl < PlatformControl
130
+ TYPE = "slider".freeze
131
+ WIRE = "Slider".freeze
132
+ KEYWORDS = (
133
+ Controls::RufletComponents::SliderControl::KEYWORDS +
134
+ Controls::RufletComponents::CupertinoSliderControl::KEYWORDS
135
+ ).uniq.freeze
136
+ end
137
+
138
+ class SwitchControl < PlatformControl
139
+ TYPE = "switch".freeze
140
+ WIRE = "Switch".freeze
141
+ KEYWORDS = (
142
+ Controls::RufletComponents::SwitchControl::KEYWORDS +
143
+ Controls::RufletComponents::CupertinoSwitchControl::KEYWORDS
144
+ ).uniq.freeze
145
+ end
146
+
147
+ class AlertDialogControl < PlatformControl
148
+ TYPE = "alertdialog".freeze
149
+ WIRE = "AlertDialog".freeze
150
+ KEYWORDS = (
151
+ Controls::RufletComponents::AlertDialogControl::KEYWORDS +
152
+ %i[inset_animation]
153
+ ).uniq.freeze
154
+ end
155
+
156
+ class BottomSheetControl < PlatformControl
157
+ TYPE = "bottomsheet".freeze
158
+ WIRE = "BottomSheet".freeze
159
+ KEYWORDS = %i[
160
+ adaptive animation_style badge barrier_color bgcolor clip_behavior col content data
161
+ disabled dismissible draggable elevation expand expand_loose fullscreen height key
162
+ maintain_bottom_view_insets_padding modal opacity open padding rtl scrollable shape
163
+ show_drag_handle size_constraints tooltip use_safe_area visible on_dismiss
164
+ ].freeze
165
+
166
+ private
167
+
168
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
169
+ end
170
+
171
+ class AppBarControl < PlatformControl
172
+ TYPE = "appbar".freeze
173
+ WIRE = "AppBar".freeze
174
+ KEYWORDS = (
175
+ Controls::RufletComponents::AppBarControl::KEYWORDS + %i[
176
+ automatic_background_visibility automatically_imply_title border brightness
177
+ enable_background_filter_blur large padding previous_page_title trailing
178
+ transition_between_routes
179
+ ]
180
+ ).uniq.freeze
181
+ end
182
+
183
+ class ListTileControl < PlatformControl
184
+ TYPE = "listtile".freeze
185
+ WIRE = "ListTile".freeze
186
+ KEYWORDS = (
187
+ Controls::RufletComponents::ListTileControl::KEYWORDS +
188
+ Controls::RufletComponents::CupertinoListTileControl::KEYWORDS
189
+ ).uniq.freeze
190
+
191
+ private
192
+
193
+ def validate_platform_props!(props) = require_control_prop!(props, :title)
194
+ end
195
+
196
+ class NavigationBarControl < PlatformControl
197
+ TYPE = "navigationbar".freeze
198
+ WIRE = "NavigationBar".freeze
199
+ KEYWORDS = (
200
+ Controls::RufletComponents::NavigationBarControl::KEYWORDS +
201
+ Controls::RufletComponents::CupertinoNavigationBarControl::KEYWORDS
202
+ ).uniq.freeze
203
+ end
204
+
205
+ class ProgressRingControl < PlatformControl
206
+ TYPE = "progressring".freeze
207
+ WIRE = "ProgressRing".freeze
208
+ KEYWORDS = (
209
+ Controls::RufletComponents::ProgressRingControl::KEYWORDS +
210
+ Controls::RufletComponents::CupertinoActivityIndicatorControl::KEYWORDS
211
+ ).uniq.freeze
212
+ end
213
+
214
+ class SegmentedButtonControl < PlatformControl
215
+ TYPE = "segmentedbutton".freeze
216
+ WIRE = "SegmentedButton".freeze
217
+ KEYWORDS = (
218
+ Controls::RufletComponents::SegmentedButtonControl::KEYWORDS +
219
+ Controls::RufletComponents::CupertinoSegmentedButtonControl::KEYWORDS +
220
+ Controls::RufletComponents::CupertinoSlidingSegmentedButtonControl::KEYWORDS
221
+ ).uniq.freeze
222
+ end
223
+
224
+ class ContextMenuControl < PlatformControl
225
+ TYPE = "contextmenu".freeze
226
+ WIRE = "ContextMenu".freeze
227
+ KEYWORDS = (
228
+ Controls::RufletComponents::ContextMenuControl::KEYWORDS +
229
+ %i[actions adaptive enable_haptic_feedback]
230
+ ).uniq.freeze
231
+
232
+ def open(position: nil, timeout: 10, on_result: nil)
233
+ args = {}
234
+ args["position"] = stringify_hash_keys(position) unless position.nil?
235
+ runtime_page&.invoke(self, "open", args: args, timeout: timeout, on_result: on_result)
236
+ end
237
+
238
+ private
239
+
240
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
241
+
242
+ def stringify_hash_keys(value)
243
+ return value.map { |item| stringify_hash_keys(item) } if value.is_a?(Array)
244
+ if value.is_a?(Hash)
245
+ return value.each_with_object({}) do |(key, child), result|
246
+ result[key.to_s] = stringify_hash_keys(child)
247
+ end
248
+ end
249
+
250
+ value
251
+ end
252
+ end
253
+
254
+ class ContextMenuActionControl < PlatformControl
255
+ TYPE = "contextmenuaction".freeze
256
+ WIRE = "ContextMenuAction".freeze
257
+ KEYWORDS = %i[
258
+ adaptive align animate_align animate_margin animate_offset animate_opacity
259
+ animate_position animate_rotation animate_scale animate_size aspect_ratio badge bottom
260
+ checked col content data default destructive disabled expand expand_loose height icon key
261
+ left margin mouse_cursor offset opacity right rotate rtl scale size_change_interval
262
+ tooltip top trailing_icon value visible width on_animation_end on_click on_size_change
263
+ ].freeze
264
+
265
+ private
266
+
267
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
268
+ end
269
+
270
+ class ActionSheetControl < PlatformControl
271
+ TYPE = "actionsheet".freeze
272
+ WIRE = "ActionSheet".freeze
273
+ KEYWORDS = Controls::RufletComponents::CupertinoActionSheetControl::KEYWORDS
274
+ end
275
+
276
+ class ActionSheetActionControl < PlatformControl
277
+ TYPE = "actionsheetaction".freeze
278
+ WIRE = "ActionSheetAction".freeze
279
+ KEYWORDS = Controls::RufletComponents::CupertinoActionSheetActionControl::KEYWORDS
280
+
281
+ private
282
+
283
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
284
+ end
285
+
286
+ class DatePickerControl < PlatformControl
287
+ TYPE = "datepicker".freeze
288
+ WIRE = "DatePicker".freeze
289
+ KEYWORDS = (
290
+ Controls::RufletComponents::DatePickerControl::KEYWORDS +
291
+ Controls::RufletComponents::CupertinoDatePickerControl::KEYWORDS
292
+ ).uniq.freeze
293
+
294
+ private
295
+
296
+ def normalize_platform_prop(key, value)
297
+ return value unless %i[value first_date last_date current_date].include?(key)
298
+
299
+ Ruflet::Protocol.date_time(value)
300
+ end
301
+ end
302
+
303
+ class PickerControl < PlatformControl
304
+ TYPE = "picker".freeze
305
+ WIRE = "Picker".freeze
306
+ KEYWORDS = Controls::RufletComponents::CupertinoPickerControl::KEYWORDS
307
+ end
308
+
309
+ class TimerPickerControl < PlatformControl
310
+ TYPE = "timerpicker".freeze
311
+ WIRE = "TimerPicker".freeze
312
+ KEYWORDS = Controls::RufletComponents::CupertinoTimerPickerControl::KEYWORDS
313
+ end
314
+
315
+ class DropdownControl < PlatformControl
316
+ TYPE = "dropdown".freeze
317
+ WIRE = "Dropdown".freeze
318
+ KEYWORDS = (
319
+ Controls::RufletComponents::DropdownControl::KEYWORDS +
320
+ Controls::RufletComponents::Dropdown2Control::KEYWORDS
321
+ ).uniq.freeze
322
+ end
323
+ end
324
+
325
+ CANONICAL_CLASS_MAP = {
326
+ %w[button elevated_button elevatedbutton] => Components::ButtonControl,
327
+ %w[filled_button filledbutton] => Components::FilledButtonControl,
328
+ %w[filled_tonal_button filledtonalbutton] => Components::FilledTonalButtonControl,
329
+ %w[outlined_button outlinedbutton] => Components::OutlinedButtonControl,
330
+ %w[text_button textbutton] => Components::TextButtonControl,
331
+ %w[text_field textfield] => Components::TextFieldControl,
332
+ %w[checkbox] => Components::CheckboxControl,
333
+ %w[radio] => Components::RadioControl,
334
+ %w[slider] => Components::SliderControl,
335
+ %w[switch] => Components::SwitchControl,
336
+ %w[alert_dialog alertdialog] => Components::AlertDialogControl,
337
+ %w[bottom_sheet bottomsheet] => Components::BottomSheetControl,
338
+ %w[app_bar appbar] => Components::AppBarControl,
339
+ %w[list_tile listtile] => Components::ListTileControl,
340
+ %w[navigation_bar navigationbar] => Components::NavigationBarControl,
341
+ %w[progress_ring progressring] => Components::ProgressRingControl,
342
+ %w[segmented_button segmentedbutton] => Components::SegmentedButtonControl,
343
+ %w[context_menu contextmenu] => Components::ContextMenuControl,
344
+ %w[context_menu_action contextmenuaction] => Components::ContextMenuActionControl,
345
+ %w[action_sheet actionsheet] => Components::ActionSheetControl,
346
+ %w[action_sheet_action actionsheetaction] => Components::ActionSheetActionControl,
347
+ %w[date_picker datepicker] => Components::DatePickerControl,
348
+ %w[picker] => Components::PickerControl,
349
+ %w[timer_picker timerpicker] => Components::TimerPickerControl,
350
+ %w[dropdown dropdown_m2 dropdownm2] => Components::DropdownControl,
351
+ }.each_with_object({}) do |(names, klass), map|
352
+ names.each { |name| map[name] = klass }
353
+ end.freeze
354
+
355
+ LEGACY_CLASS_MAP = {
356
+ %w[cupertino_button cupertinobutton] => Controls::RufletComponents::CupertinoButtonControl,
357
+ %w[cupertino_filled_button cupertinofilledbutton] => Controls::RufletComponents::CupertinoFilledButtonControl,
358
+ %w[cupertino_tinted_button cupertinotintedbutton] => Controls::RufletComponents::CupertinoTintedButtonControl,
359
+ %w[cupertino_text_field cupertinotextfield] => Controls::RufletComponents::CupertinoTextFieldControl,
360
+ %w[cupertino_checkbox cupertinocheckbox] => Controls::RufletComponents::CupertinoCheckboxControl,
361
+ %w[cupertino_radio cupertinoradio] => Controls::RufletComponents::CupertinoRadioControl,
362
+ %w[cupertino_slider cupertinoslider] => Controls::RufletComponents::CupertinoSliderControl,
363
+ %w[cupertino_switch cupertinoswitch] => Controls::RufletComponents::CupertinoSwitchControl,
364
+ %w[cupertino_alert_dialog cupertinoalertdialog] => Controls::RufletComponents::CupertinoAlertDialogControl,
365
+ %w[cupertino_bottom_sheet cupertinobottomsheet] => Controls::RufletComponents::CupertinoBottomSheetControl,
366
+ %w[cupertino_app_bar cupertinoappbar] => Controls::RufletComponents::CupertinoAppBarControl,
367
+ %w[cupertino_list_tile cupertinolisttile] => Controls::RufletComponents::CupertinoListTileControl,
368
+ %w[cupertino_navigation_bar cupertinonavigationbar] => Controls::RufletComponents::CupertinoNavigationBarControl,
369
+ %w[cupertino_activity_indicator cupertinoactivityindicator] => Controls::RufletComponents::CupertinoActivityIndicatorControl,
370
+ %w[cupertino_segmented_button cupertinosegmentedbutton] => Controls::RufletComponents::CupertinoSegmentedButtonControl,
371
+ %w[cupertino_sliding_segmented_button cupertinoslidingsegmentedbutton] => Controls::RufletComponents::CupertinoSlidingSegmentedButtonControl,
372
+ %w[cupertino_context_menu cupertinocontextmenu] => Controls::RufletComponents::CupertinoContextMenuControl,
373
+ %w[cupertino_context_menu_action cupertinocontextmenuaction] => Controls::RufletComponents::CupertinoContextMenuActionControl,
374
+ %w[cupertino_action_sheet cupertinoactionsheet] => Controls::RufletComponents::CupertinoActionSheetControl,
375
+ %w[cupertino_action_sheet_action cupertinoactionsheetaction] => Controls::RufletComponents::CupertinoActionSheetActionControl,
376
+ %w[cupertino_date_picker cupertinodatepicker] => Controls::RufletComponents::CupertinoDatePickerControl,
377
+ %w[cupertino_picker cupertinopicker] => Controls::RufletComponents::CupertinoPickerControl,
378
+ %w[cupertino_timer_picker cupertinotimerpicker] => Controls::RufletComponents::CupertinoTimerPickerControl,
379
+ %w[cupertino_dialog_action cupertinodialogaction] => Controls::RufletComponents::CupertinoDialogActionControl,
380
+ %w[popup_menu_item popupmenuitem] => Controls::RufletComponents::PopupMenuItemControl
381
+ }.each_with_object({}) do |(names, klass), map|
382
+ names.each { |name| map[name] = klass }
383
+ end.freeze
384
+
385
+ CLASS_MAP = CANONICAL_CLASS_MAP.merge(LEGACY_CLASS_MAP).freeze
386
+
387
+ TYPE_MAP = CLASS_MAP.each_with_object({}) do |(name, klass), map|
388
+ map[name] = klass::WIRE
389
+ end.freeze
390
+ end
391
+ end
392
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruflet
4
+ module UI
5
+ # Canonical DSL entry points for controls whose renderer is selected by
6
+ # the Flet client. There is no design-system choice in this API.
7
+ module PlatformControlMethods
8
+ def context_menu_action(content = nil, **props)
9
+ mapped = props.dup
10
+ mapped[:content] = content unless content.nil?
11
+ build_widget(:contextmenuaction, **mapped)
12
+ end
13
+ def contextmenuaction(content = nil, **props) = context_menu_action(content, **props)
14
+
15
+ def action_sheet(**props) = build_widget(:actionsheet, **props)
16
+ def actionsheet(**props) = action_sheet(**props)
17
+
18
+ def action_sheet_action(content = nil, **props)
19
+ mapped = props.dup
20
+ mapped[:content] = content unless content.nil?
21
+ build_widget(:actionsheetaction, **mapped)
22
+ end
23
+ def actionsheetaction(content = nil, **props) = action_sheet_action(content, **props)
24
+
25
+ def picker(children = nil, **props)
26
+ mapped = props.dup
27
+ mapped[:controls] = children unless children.nil?
28
+ build_widget(:picker, **mapped)
29
+ end
30
+
31
+ def timer_picker(**props) = build_widget(:timerpicker, **props)
32
+ def timerpicker(**props) = timer_picker(**props)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruflet
4
+ module UI
5
+ module Services
6
+ module CurrentServiceMethods
7
+ private
8
+
9
+ def invoke_service_method(method_name, args: nil, timeout: 10, on_result: nil)
10
+ runtime_page&.invoke(self, method_name, args: args, timeout: timeout, on_result: on_result)
11
+ end
12
+
13
+ def service_args(values)
14
+ values.each_with_object({}) do |(key, value), result|
15
+ result[key.to_s] = service_value(value, key.to_s) unless value.nil?
16
+ end
17
+ end
18
+
19
+ def service_value(value, parent_key = nil)
20
+ if parent_key == "data" && byte_array?(value)
21
+ return value.pack("C*").b
22
+ end
23
+
24
+ case value
25
+ when Array
26
+ value.map { |item| service_value(item) }
27
+ when Hash
28
+ value.each_with_object({}) do |(key, item), result|
29
+ result[key.to_s] = service_value(item, key.to_s) unless item.nil?
30
+ end
31
+ when Symbol
32
+ value.to_s
33
+ else
34
+ value.respond_to?(:to_h) ? service_value(value.to_h) : value
35
+ end
36
+ end
37
+
38
+ def byte_array?(value)
39
+ value.is_a?(Array) && value.all? { |item| item.is_a?(Integer) && item.between?(0, 255) }
40
+ end
41
+ end
42
+
43
+ module NoArgumentServiceMethods
44
+ def define_no_argument_service_methods(*method_names)
45
+ method_names.each do |method_name|
46
+ define_method(method_name) do |timeout: 10, on_result: nil|
47
+ invoke_service_method(method_name, timeout: timeout, on_result: on_result)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ components = RufletServicesComponents
54
+
55
+ [
56
+ [components::BatteryControl, %w[get_battery_level get_battery_state is_in_battery_save_mode]],
57
+ [components::ConnectivityControl, %w[get_connectivity]],
58
+ [components::FlashlightControl, %w[on off is_available]],
59
+ [components::HapticFeedbackControl, %w[heavy_impact light_impact medium_impact vibrate selection_click]],
60
+ [components::StoragePathsControl, %w[
61
+ get_application_cache_directory get_application_documents_directory
62
+ get_application_support_directory get_downloads_directory
63
+ get_external_cache_directories get_external_storage_directories
64
+ get_library_directory get_external_storage_directory
65
+ get_temporary_directory get_console_log_filename
66
+ ]],
67
+ [components::WakelockControl, %w[enable disable is_enabled]]
68
+ ].each do |klass, method_names|
69
+ klass.include(CurrentServiceMethods)
70
+ klass.extend(NoArgumentServiceMethods)
71
+ klass.define_no_argument_service_methods(*method_names)
72
+ end
73
+
74
+ class RufletServicesComponents::FilePickerControl
75
+ include CurrentServiceMethods
76
+
77
+ def upload(files, timeout: 10, on_result: nil)
78
+ invoke_service_method("upload", args: { "files" => service_value(files) }, timeout: timeout, on_result: on_result)
79
+ end
80
+
81
+ def get_directory_path(dialog_title: nil, initial_directory: nil, timeout: 10, on_result: nil)
82
+ invoke_service_method("get_directory_path", args: service_args(dialog_title: dialog_title, initial_directory: initial_directory), timeout: timeout, on_result: on_result)
83
+ end
84
+
85
+ def save_file(dialog_title: nil, file_name: nil, initial_directory: nil, file_type: :any,
86
+ allowed_extensions: nil, src_bytes: nil, timeout: 10, on_result: nil)
87
+ args = service_args(
88
+ dialog_title: dialog_title,
89
+ file_name: file_name,
90
+ initial_directory: initial_directory,
91
+ file_type: file_type,
92
+ allowed_extensions: allowed_extensions
93
+ )
94
+ args["src_bytes"] = src_bytes.pack("C*").b if byte_array?(src_bytes)
95
+ args["src_bytes"] = src_bytes unless src_bytes.nil? || byte_array?(src_bytes)
96
+ invoke_service_method("save_file", args: args, timeout: timeout, on_result: on_result)
97
+ end
98
+
99
+ def pick_files(dialog_title: nil, initial_directory: nil, file_type: :any,
100
+ allowed_extensions: nil, allow_multiple: false, with_data: false,
101
+ timeout: 10, on_result: nil)
102
+ invoke_service_method(
103
+ "pick_files",
104
+ args: service_args(
105
+ dialog_title: dialog_title,
106
+ initial_directory: initial_directory,
107
+ file_type: file_type,
108
+ allowed_extensions: allowed_extensions,
109
+ allow_multiple: allow_multiple,
110
+ with_data: with_data
111
+ ),
112
+ timeout: timeout,
113
+ on_result: on_result
114
+ )
115
+ end
116
+ end
117
+
118
+ class RufletServicesComponents::ScreenBrightnessControl
119
+ include CurrentServiceMethods
120
+
121
+ %w[
122
+ get_system_screen_brightness can_change_system_screen_brightness
123
+ get_application_screen_brightness reset_application_screen_brightness
124
+ is_animate is_auto_reset
125
+ ].each do |method_name|
126
+ define_method(method_name) do |timeout: 10, on_result: nil|
127
+ invoke_service_method(method_name, timeout: timeout, on_result: on_result)
128
+ end
129
+ end
130
+
131
+ def set_system_screen_brightness(brightness, timeout: 10, on_result: nil)
132
+ invoke_service_method("set_system_screen_brightness", args: { "brightness" => brightness }, timeout: timeout, on_result: on_result)
133
+ end
134
+
135
+ def set_application_screen_brightness(brightness, timeout: 10, on_result: nil)
136
+ invoke_service_method("set_application_screen_brightness", args: { "brightness" => brightness }, timeout: timeout, on_result: on_result)
137
+ end
138
+
139
+ def set_animate(animate, timeout: 10, on_result: nil)
140
+ invoke_service_method("set_animate", args: { "animate" => animate }, timeout: timeout, on_result: on_result)
141
+ end
142
+
143
+ def set_auto_reset(auto_reset, timeout: 10, on_result: nil)
144
+ invoke_service_method("set_auto_reset", args: { "auto_reset" => auto_reset }, timeout: timeout, on_result: on_result)
145
+ end
146
+ end
147
+
148
+ class RufletServicesComponents::ShareControl
149
+ include CurrentServiceMethods
150
+
151
+ def share_text(text, title: nil, subject: nil, preview_thumbnail: nil,
152
+ share_position_origin: nil, download_fallback_enabled: true,
153
+ mail_to_fallback_enabled: true, excluded_cupertino_activities: nil,
154
+ timeout: 10, on_result: nil)
155
+ invoke_service_method(
156
+ "share_text",
157
+ args: service_args(
158
+ text: text, title: title, subject: subject, preview_thumbnail: preview_thumbnail,
159
+ share_position_origin: share_position_origin,
160
+ download_fallback_enabled: download_fallback_enabled,
161
+ mail_to_fallback_enabled: mail_to_fallback_enabled,
162
+ excluded_cupertino_activities: excluded_cupertino_activities
163
+ ),
164
+ timeout: timeout,
165
+ on_result: on_result
166
+ )
167
+ end
168
+
169
+ def share_uri(uri, share_position_origin: nil, excluded_cupertino_activities: nil, timeout: 10, on_result: nil)
170
+ invoke_service_method("share_uri", args: service_args(uri: uri, share_position_origin: share_position_origin, excluded_cupertino_activities: excluded_cupertino_activities), timeout: timeout, on_result: on_result)
171
+ end
172
+
173
+ def share_files(files, title: nil, text: nil, subject: nil, preview_thumbnail: nil,
174
+ share_position_origin: nil, download_fallback_enabled: true,
175
+ mail_to_fallback_enabled: true, excluded_cupertino_activities: nil,
176
+ timeout: 10, on_result: nil)
177
+ invoke_service_method(
178
+ "share_files",
179
+ args: service_args(
180
+ files: files, title: title, text: text, subject: subject,
181
+ preview_thumbnail: preview_thumbnail, share_position_origin: share_position_origin,
182
+ download_fallback_enabled: download_fallback_enabled,
183
+ mail_to_fallback_enabled: mail_to_fallback_enabled,
184
+ excluded_cupertino_activities: excluded_cupertino_activities
185
+ ),
186
+ timeout: timeout,
187
+ on_result: on_result
188
+ )
189
+ end
190
+ end
191
+
192
+ class RufletServicesComponents::SharedPreferencesControl
193
+ include CurrentServiceMethods
194
+
195
+ def set(key, value, timeout: 10, on_result: nil) = invoke_service_method("set", args: { "key" => key, "value" => service_value(value) }, timeout: timeout, on_result: on_result)
196
+ def get(key, timeout: 10, on_result: nil) = invoke_service_method("get", args: { "key" => key }, timeout: timeout, on_result: on_result)
197
+ def contains_key(key, timeout: 10, on_result: nil) = invoke_service_method("contains_key", args: { "key" => key }, timeout: timeout, on_result: on_result)
198
+ def remove(key, timeout: 10, on_result: nil) = invoke_service_method("remove", args: { "key" => key }, timeout: timeout, on_result: on_result)
199
+ def get_keys(key_prefix, timeout: 10, on_result: nil) = invoke_service_method("get_keys", args: { "key_prefix" => key_prefix }, timeout: timeout, on_result: on_result)
200
+ def clear(timeout: 10, on_result: nil) = invoke_service_method("clear", timeout: timeout, on_result: on_result)
201
+ end
202
+
203
+ class RufletServicesComponents::UrlLauncherControl
204
+ include CurrentServiceMethods
205
+
206
+ def launch_url(url, mode: :platform_default, web_view_configuration: nil,
207
+ browser_configuration: nil, web_only_window_name: nil,
208
+ timeout: 10, on_result: nil)
209
+ invoke_service_method("launch_url", args: service_args(url: url, mode: mode, web_view_configuration: web_view_configuration, browser_configuration: browser_configuration, web_only_window_name: web_only_window_name), timeout: timeout, on_result: on_result)
210
+ end
211
+
212
+ def can_launch_url(url, timeout: 10, on_result: nil) = invoke_service_method("can_launch_url", args: { "url" => url.to_s }, timeout: timeout, on_result: on_result)
213
+ def close_in_app_web_view(timeout: 10, on_result: nil) = invoke_service_method("close_in_app_web_view", timeout: timeout, on_result: on_result)
214
+ def open_window(url, title: nil, width: nil, height: nil, timeout: 10, on_result: nil) = invoke_service_method("open_window", args: service_args(url: url, title: title, width: width, height: height), timeout: timeout, on_result: on_result)
215
+ def supports_launch_mode(mode, timeout: 10, on_result: nil) = invoke_service_method("supports_launch_mode", args: { "mode" => service_value(mode) }, timeout: timeout, on_result: on_result)
216
+ def supports_close_for_launch_mode(mode, timeout: 10, on_result: nil) = invoke_service_method("supports_close_for_launch_mode", args: { "mode" => service_value(mode) }, timeout: timeout, on_result: on_result)
217
+ end
218
+ end
219
+ end
220
+ end