ruflet_core 0.0.13 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f384022aa476f52d7aa7e1315e1a5da2e71071cab839f04f7a0331cdb7da21f
4
- data.tar.gz: f21fb7e4b2a9f401ef521d278128ac5b436d912182f2d1ddbcbb4b7597f4dfca
3
+ metadata.gz: d10c0b00cedaedd9a12709dd513e56aef545f9ba61b5756481e50b270ca647ce
4
+ data.tar.gz: 9a247d9aefdee2f5c667c3c5ae55235d17eb1a709c4dc402b0c794ecd5f0a752
5
5
  SHA512:
6
- metadata.gz: f5ffaad8c7cee45c8b756d66d567e3a9e04c13dbb672dedb3c18545f7ecd6374af89b7267fc715711d73f8dc4b1fe3b9f597f5b62ca2fd9181f7dabb336178da
7
- data.tar.gz: b52faf7ed1f6aa8980ba4c03e64c34c6b13760375261ef1e6121cf52eb774c035d8940d5d9cbb74f86de5174a768d758bba724fafa2f48a77aa1bc6a6d726524
6
+ metadata.gz: 18548e0fe324df386b50cb0d5320e70283d64385244f8cf2101c0add56dd62e9a2ae5a8a29fccb86bc058eef18ccd511efc8218305121d58dba7ba40de73639d
7
+ data.tar.gz: da7f855ee5f0721dbfb9ac249b6f34a7857e4a1e5e9ad2846fbb5954ae92b7c528aea6551796e6f1bcc2cec5ef7ad47aa75a7bdda48d18da3d82f6c94f9ceb56
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruflet
4
- VERSION = "0.0.13" unless const_defined?(:VERSION)
4
+ VERSION = "0.0.14" unless const_defined?(:VERSION)
5
5
  end
@@ -160,6 +160,8 @@ module Ruflet
160
160
  @root_controls = []
161
161
  @views = []
162
162
  @dialogs = []
163
+ @overlay_container_mounted = false
164
+ @dialogs_container_mounted = false
163
165
  @services_container_mounted = false
164
166
  @visual_service_controls = {}
165
167
  @page_event_handlers = {}
@@ -248,10 +250,10 @@ module Ruflet
248
250
  controls.each { |c| register_control_tree(c, visited) }
249
251
  @root_controls = controls
250
252
 
251
- @view_props["appbar"] = appbar if appbar
252
- @view_props["bottom_appbar"] = bottom_appbar if bottom_appbar
253
- @view_props["floating_action_button"] = floating_action_button if floating_action_button
254
- @view_props["navigation_bar"] = navigation_bar if navigation_bar
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)
255
257
  @dialog = dialog if dialog
256
258
  @snack_bar = snack_bar if snack_bar
257
259
  @bottom_sheet = bottom_sheet if bottom_sheet
@@ -482,11 +484,13 @@ module Ruflet
482
484
  def dialog=(value)
483
485
  @dialog = value
484
486
  refresh_dialogs_container!
487
+ push_dialogs_update! if @dialogs_container_mounted
485
488
  end
486
489
 
487
490
  def snack_bar=(value)
488
491
  @snack_bar = value
489
492
  refresh_dialogs_container!
493
+ push_dialogs_update! if @dialogs_container_mounted
490
494
  end
491
495
 
492
496
  def snackbar=(value)
@@ -508,6 +512,7 @@ module Ruflet
508
512
  return self if dialog_open?(dialog_control)
509
513
 
510
514
  dialog_control.props["open"] = true
515
+ remove_existing_singleton_dialogs(dialog_control)
511
516
  @dialogs << dialog_control unless @dialogs.include?(dialog_control)
512
517
  refresh_dialogs_container!
513
518
  send_view_patch unless @dialogs_container.wire_id
@@ -1145,11 +1150,22 @@ module Ruflet
1145
1150
  return nil unless dialog_control
1146
1151
 
1147
1152
  dialog_control.props["open"] = false
1148
- refresh_dialogs_container!
1149
- push_dialogs_update!
1153
+ update(dialog_control, open: false)
1150
1154
  dialog_control
1151
1155
  end
1152
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
+
1153
1169
  def update(control_or_id = nil, **props)
1154
1170
  if control_or_id.nil? && props.empty?
1155
1171
  send_view_patch
@@ -1185,6 +1201,7 @@ module Ruflet
1185
1201
 
1186
1202
  visited = Set.new
1187
1203
  patch.each_value { |value| register_embedded_value(value, visited) }
1204
+ patch.each { |k, v| control.props[k] = v }
1188
1205
 
1189
1206
  patch_ops = patch.map { |k, v| [0, 0, k, serialize_patch_value(v)] }
1190
1207
 
@@ -1207,8 +1224,6 @@ module Ruflet
1207
1224
  patch = normalize_props(props || {})
1208
1225
  patch.each { |k, v| control.props[k] = v }
1209
1226
 
1210
- remove_dialog_tracking(control) if patch.key?("open") && patch["open"] == false
1211
-
1212
1227
  self
1213
1228
  end
1214
1229
 
@@ -1227,11 +1242,12 @@ module Ruflet
1227
1242
 
1228
1243
  event = Event.new(name: name, target: target, raw_data: data, page: self, control: control)
1229
1244
  apply_event_value_to_control(control, event) if %w[change select select_change].include?(name.to_s)
1230
- control.emit(name, event)
1231
-
1232
- if name.to_s == "dismiss" && remove_dialog_tracking(control)
1233
- push_dialogs_update!
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)
1234
1248
  end
1249
+
1250
+ control.emit(name, event)
1235
1251
  end
1236
1252
 
1237
1253
  def method_missing(name, *args, &block)
@@ -1370,6 +1386,14 @@ module Ruflet
1370
1386
  @sender.call(action, payload)
1371
1387
  end
1372
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
+
1373
1397
  def send_view_patch
1374
1398
  refresh_control_indexes!
1375
1399
  view_patches = build_view_patches
@@ -1379,10 +1403,12 @@ module Ruflet
1379
1403
  "id" => 1,
1380
1404
  "patch" => [
1381
1405
  [0],
1382
- [0, 0, "views", view_patches],
1383
- *page_patch_ops
1406
+ *page_patch_ops,
1407
+ [0, 0, "views", view_patches]
1384
1408
  ]
1385
1409
  })
1410
+ @overlay_container_mounted = true if @overlay_container.wire_id
1411
+ @dialogs_container_mounted = true if @dialogs_container.wire_id
1386
1412
  @services_container_mounted = true if @services_container.wire_id
1387
1413
  end
1388
1414
 
@@ -1534,8 +1560,8 @@ module Ruflet
1534
1560
  end_value = range_value["end_value"] || range_value[:end_value]
1535
1561
  control.props["start_value"] = start_value unless start_value.nil?
1536
1562
  control.props["end_value"] = end_value unless end_value.nil?
1537
- return
1538
1563
  end
1564
+ return
1539
1565
  end
1540
1566
 
1541
1567
  return if value.nil?
@@ -1582,7 +1608,7 @@ module Ruflet
1582
1608
  end
1583
1609
 
1584
1610
  def refresh_dialogs_container!
1585
- dialog_controls = (@dialogs + dialog_slots).uniq
1611
+ dialog_controls = (dialog_slots + @dialogs).uniq
1586
1612
  @dialogs_container.props["controls"] = dialog_controls
1587
1613
  @page_props["_dialogs"] = @dialogs_container
1588
1614
  end
@@ -1608,9 +1634,15 @@ module Ruflet
1608
1634
  end
1609
1635
  end
1610
1636
 
1611
- def push_dialogs_update!
1637
+ def push_dialogs_update!(force_view: false)
1612
1638
  refresh_control_indexes!
1613
1639
 
1640
+ if force_view || @dialogs_container.props["controls"].empty?
1641
+ @dialogs_container_mounted = false
1642
+ send_view_patch
1643
+ return
1644
+ end
1645
+
1614
1646
  if @dialogs_container.wire_id
1615
1647
  send_message(Protocol::ACTIONS[:patch_control], {
1616
1648
  "id" => @dialogs_container.wire_id,
@@ -1633,6 +1665,11 @@ module Ruflet
1633
1665
  @dialogs.include?(dialog_control) && dialog_control.props["open"] == true
1634
1666
  end
1635
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
+
1636
1673
  def remove_dialog_tracking(control)
1637
1674
  return false unless @dialogs.include?(control)
1638
1675
 
@@ -1641,6 +1678,16 @@ module Ruflet
1641
1678
  true
1642
1679
  end
1643
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
+
1644
1691
  def assign_split_prop(key, value)
1645
1692
  if key == "vertical_alignment" || key == "horizontal_alignment"
1646
1693
  @page_props[key] = value
@@ -1668,8 +1715,8 @@ module Ruflet
1668
1715
  # Keep internal containers stable after initial mount.
1669
1716
  # Re-sending them as full objects can replace Control instances with
1670
1717
  # same IDs and detach service invoke listeners on the Flutter side.
1671
- next nil if k == "_overlay" && @overlay_container.wire_id
1672
- next nil if k == "_dialogs" && @dialogs_container.wire_id
1718
+ next nil if k == "_overlay" && @overlay_container_mounted
1719
+ next nil if k == "_dialogs" && @dialogs_container_mounted
1673
1720
  next nil if k == "_services" && @services_container_mounted
1674
1721
 
1675
1722
  [0, 0, k, serialize_patch_value(v)]
@@ -44,10 +44,8 @@ module Ruflet
44
44
  runtime_page&.invoke(self, "pause", timeout: timeout, on_result: on_result)
45
45
  end
46
46
 
47
- def play(position: nil, timeout: 10, on_result: nil)
48
- args = {}
49
- args["position"] = position unless position.nil?
50
- runtime_page&.invoke(self, "play", args: args.empty? ? nil : args, timeout: timeout, on_result: on_result)
47
+ def play(position: 0, timeout: 10, on_result: nil)
48
+ runtime_page&.invoke(self, "play", args: { "position" => position }, timeout: timeout, on_result: on_result)
51
49
  end
52
50
 
53
51
  def release(timeout: 10, on_result: nil)
@@ -4,14 +4,37 @@ module Ruflet
4
4
  module UI
5
5
  module Controls
6
6
  module RufletComponents
7
+ module MapValueNormalizer
8
+ private
9
+
10
+ def normalize_map_coordinate(value)
11
+ case value
12
+ when Array
13
+ if value.length == 2 && value.all? { |item| item.is_a?(Numeric) }
14
+ { "latitude" => value[0], "longitude" => value[1] }
15
+ else
16
+ value.map { |item| normalize_map_coordinate(item) }
17
+ end
18
+ when Hash
19
+ value.transform_keys(&:to_s).each_with_object({}) do |(key, item), result|
20
+ result[key] = normalize_map_coordinate(item)
21
+ end
22
+ else
23
+ value.respond_to?(:to_h) ? normalize_map_coordinate(value.to_h) : value
24
+ end
25
+ end
26
+ end
27
+
7
28
  class MapControl < Ruflet::Control
29
+ include MapValueNormalizer
30
+
8
31
  TYPE = "map".freeze
9
32
  WIRE = "Map".freeze
10
33
 
11
34
  def initialize(id: nil, layers: nil, initial_center: nil, initial_zoom: nil, min_zoom: nil, max_zoom: nil, interaction_configuration: nil, keep_alive: nil, bgcolor: nil, data: nil, expand: nil, height: nil, key: nil, visible: nil, width: nil, on_init: nil, on_long_press: nil, on_position_change: nil, on_secondary_tap: nil, on_tap: nil)
12
35
  props = {}
13
36
  props[:layers] = layers unless layers.nil?
14
- props[:initial_center] = initial_center unless initial_center.nil?
37
+ props[:initial_center] = normalize_map_coordinate(initial_center) unless initial_center.nil?
15
38
  props[:initial_zoom] = initial_zoom unless initial_zoom.nil?
16
39
  props[:min_zoom] = min_zoom unless min_zoom.nil?
17
40
  props[:max_zoom] = max_zoom unless max_zoom.nil?
@@ -32,12 +55,52 @@ module Ruflet
32
55
  super(type: TYPE, id: id, **props)
33
56
  end
34
57
 
35
- def center_on(coordinates, zoom: nil, timeout: 10, on_result: nil)
36
- invoke_map("center_on", args: compact_args("coordinates" => coordinates, "zoom" => zoom), timeout: timeout, on_result: on_result)
58
+ def center_on(point = nil, coordinates: nil, zoom: nil, duration: nil, curve: nil, cancel_ongoing_animations: nil, timeout: 10, on_result: nil)
59
+ point ||= coordinates
60
+ invoke_map(
61
+ "center_on",
62
+ args: compact_args(
63
+ "point" => normalize_map_coordinate(point),
64
+ "zoom" => zoom,
65
+ "duration" => duration,
66
+ "curve" => curve,
67
+ "cancel_ongoing_animations" => cancel_ongoing_animations
68
+ ),
69
+ timeout: timeout,
70
+ on_result: on_result
71
+ )
72
+ end
73
+
74
+ def move_to(destination = nil, coordinates: nil, zoom: nil, rotation: nil, offset: nil, duration: nil, curve: nil, cancel_ongoing_animations: nil, timeout: 10, on_result: nil)
75
+ destination ||= coordinates
76
+ invoke_map(
77
+ "move_to",
78
+ args: compact_args(
79
+ "destination" => normalize_map_coordinate(destination),
80
+ "zoom" => zoom,
81
+ "rotation" => rotation,
82
+ "offset" => offset,
83
+ "duration" => duration,
84
+ "curve" => curve,
85
+ "cancel_ongoing_animations" => cancel_ongoing_animations
86
+ ),
87
+ timeout: timeout,
88
+ on_result: on_result
89
+ )
37
90
  end
38
91
 
39
- def move_to(coordinates, zoom: nil, timeout: 10, on_result: nil)
40
- invoke_map("move_to", args: compact_args("coordinates" => coordinates, "zoom" => zoom), timeout: timeout, on_result: on_result)
92
+ def zoom_to(zoom, duration: nil, curve: nil, cancel_ongoing_animations: nil, timeout: 10, on_result: nil)
93
+ invoke_map(
94
+ "zoom_to",
95
+ args: compact_args(
96
+ "zoom" => zoom,
97
+ "duration" => duration,
98
+ "curve" => curve,
99
+ "cancel_ongoing_animations" => cancel_ongoing_animations
100
+ ),
101
+ timeout: timeout,
102
+ on_result: on_result
103
+ )
41
104
  end
42
105
 
43
106
  def zoom_in(delta: nil, timeout: 10, on_result: nil)
@@ -118,12 +181,14 @@ module Ruflet
118
181
  end
119
182
 
120
183
  class MarkerControl < Ruflet::Control
184
+ include MapValueNormalizer
185
+
121
186
  TYPE = "marker".freeze
122
187
  WIRE = "Marker".freeze
123
188
 
124
189
  def initialize(id: nil, coordinates: nil, content: nil, height: nil, rotate: nil, width: nil, alignment: nil)
125
190
  props = {}
126
- props[:coordinates] = coordinates unless coordinates.nil?
191
+ props[:coordinates] = normalize_map_coordinate(coordinates) unless coordinates.nil?
127
192
  props[:content] = content unless content.nil?
128
193
  props[:height] = height unless height.nil?
129
194
  props[:rotate] = rotate unless rotate.nil?
@@ -146,12 +211,14 @@ module Ruflet
146
211
  end
147
212
 
148
213
  class CircleMarkerControl < Ruflet::Control
214
+ include MapValueNormalizer
215
+
149
216
  TYPE = "circlemarker".freeze
150
217
  WIRE = "CircleMarker".freeze
151
218
 
152
219
  def initialize(id: nil, coordinates: nil, radius: nil, color: nil, border_color: nil, border_stroke_width: nil, use_radius_in_meter: nil)
153
220
  props = {}
154
- props[:coordinates] = coordinates unless coordinates.nil?
221
+ props[:coordinates] = normalize_map_coordinate(coordinates) unless coordinates.nil?
155
222
  props[:radius] = radius unless radius.nil?
156
223
  props[:color] = color unless color.nil?
157
224
  props[:border_color] = border_color unless border_color.nil?
@@ -174,12 +241,14 @@ module Ruflet
174
241
  end
175
242
 
176
243
  class PolylineMarkerControl < Ruflet::Control
244
+ include MapValueNormalizer
245
+
177
246
  TYPE = "polylinemarker".freeze
178
247
  WIRE = "PolylineMarker".freeze
179
248
 
180
249
  def initialize(id: nil, coordinates: nil, color: nil, stroke_width: nil, border_color: nil, border_stroke_width: nil, gradient_colors: nil, stroke_cap: nil, stroke_join: nil)
181
250
  props = {}
182
- props[:coordinates] = coordinates unless coordinates.nil?
251
+ props[:coordinates] = normalize_map_coordinate(coordinates) unless coordinates.nil?
183
252
  props[:color] = color unless color.nil?
184
253
  props[:stroke_width] = stroke_width unless stroke_width.nil?
185
254
  props[:border_color] = border_color unless border_color.nil?
@@ -204,12 +273,14 @@ module Ruflet
204
273
  end
205
274
 
206
275
  class PolygonMarkerControl < Ruflet::Control
276
+ include MapValueNormalizer
277
+
207
278
  TYPE = "polygonmarker".freeze
208
279
  WIRE = "PolygonMarker".freeze
209
280
 
210
281
  def initialize(id: nil, coordinates: nil, color: nil, border_color: nil, border_stroke_width: nil, disable_holes_border: nil, label: nil)
211
282
  props = {}
212
- props[:coordinates] = coordinates unless coordinates.nil?
283
+ props[:coordinates] = normalize_map_coordinate(coordinates) unless coordinates.nil?
213
284
  props[:color] = color unless color.nil?
214
285
  props[:border_color] = border_color unless border_color.nil?
215
286
  props[:border_stroke_width] = border_stroke_width unless border_stroke_width.nil?
@@ -8,7 +8,7 @@ module Ruflet
8
8
  TYPE = "audiorecorder".freeze
9
9
  WIRE = "AudioRecorder".freeze
10
10
 
11
- def initialize(id: nil, configuration: nil, data: nil, key: nil, on_state_change: nil, on_stream: nil, on_upload: nil)
11
+ def initialize(id: nil, configuration: {}, data: nil, key: nil, on_state_change: nil, on_stream: nil, on_upload: nil)
12
12
  props = {}
13
13
  props[:configuration] = configuration unless configuration.nil?
14
14
  props[:data] = data unless data.nil?
@@ -43,7 +43,7 @@ module Ruflet
43
43
  )
44
44
  end
45
45
 
46
- def start_recording(output_path: nil, configuration: nil, upload: nil, timeout: 10, on_result: nil)
46
+ def start_recording(output_path: nil, configuration: {}, upload: nil, timeout: 10, on_result: nil)
47
47
  invoke_audio_recorder(
48
48
  "start_recording",
49
49
  args: compact_args(
@@ -44,6 +44,8 @@ module Ruflet
44
44
  end
45
45
 
46
46
  def normalize_service_value(value)
47
+ return value.to_s if value.is_a?(Symbol)
48
+
47
49
  value.respond_to?(:to_h) ? value.to_h.transform_keys(&:to_s) : value
48
50
  end
49
51
  end
@@ -23,6 +23,8 @@ module Ruflet
23
23
  end
24
24
 
25
25
  def set(key, value, **options)
26
+ raise ArgumentError, "value must not be nil" if value.nil?
27
+
26
28
  invoke_secure_storage("set", args: option_args(options).merge("key" => key, "value" => value), **invoke_options(options))
27
29
  end
28
30
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruflet_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - AdamMusa