ruby-macrodroid 0.8.12 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35ba502f49880d0b2036510866095ff532a03311c4b503099305b943ed5dd77f
4
- data.tar.gz: c604614f382e0bdf812ca7426fc74cd5339e16b821e272b3d31c85663a5f34fe
3
+ metadata.gz: 341332647c11b1d70151aab4625ffefced825585c4814eed7d7aefaf7c96703e
4
+ data.tar.gz: ac8f26a27b1f9d394174f1d887e8af27a6c551dc55d4cffa89b8fb04f6b1927d
5
5
  SHA512:
6
- metadata.gz: c36b8205504f1e76b467fe13e3e752213a0bff61e1312f507ce30ecc79904070e3004e5f82efb3e3dae9e0c22edfe5e5c7f19c421d87119ede851ab103f5d64e
7
- data.tar.gz: ab08df04436246ea37ade91f8a3509749923c1e017fb33163b591cc72f78410f3a4dcf78715669217897032362ed0a17935d4eb8858133d766a2bb712465232e
6
+ metadata.gz: debe33514bbcd6cbc508c6d6a3d647cd37861bc61168743ed15cb1f1d7cf142cd883fb6059b2b7ad901659314f1dadee8f7610dbc03074f79fc3b95c8abc2f27
7
+ data.tar.gz: 50e36ff27c737d50b0686610398feae034f21a4cfab3a15b0c6367e278305a5bdc4ed6f699c0a220f0794dcf89cd3a2ec5ae0bdaf25f0d18aa49309206c03659
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -38,269 +38,14 @@ require 'rxfhelper'
38
38
  require 'chronic_cron'
39
39
 
40
40
 
41
+ # PASTE_START
42
+
41
43
  MODEL =<<EOF
42
44
  device
43
45
  connectivity
44
46
  airplane_mode is disabled
45
47
  EOF
46
48
 
47
- class TriggersNlp
48
- include AppRoutes
49
-
50
- def initialize(macro=nil)
51
-
52
- super()
53
- params = {macro: macro}
54
- triggers(params)
55
-
56
- end
57
-
58
- def triggers(params)
59
-
60
- # e.g. at 7:30pm daily
61
- get /^(?:at )?(\d+:\d+(?:[ap]m)?) daily/i do |time, days|
62
- [TimerTrigger, {time: time,
63
- days: %w(Mon Tue Wed Thu Fri Sat Sun).join(', ')}]
64
- end
65
-
66
- get /^(?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)/i do |time, days|
67
- [TimerTrigger, {time: time, days: days}]
68
- end
69
-
70
- # time.is? 'at 18:30pm on Mon or Tue'
71
- get /^time.is\? ['"](?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)['"]/i do |time, days|
72
- [TimerTrigger, {time: time, days: days.gsub(' or ',', ')}]
73
- end
74
-
75
- get /^shake[ _]device\??$/i do
76
- [ShakeDeviceTrigger, {}]
77
- end
78
-
79
- get /^Flip Device (.*)$/i do |motion|
80
- facedown = motion =~ /Face Up (?:->|to) Face Down/i
81
- [FlipDeviceTrigger, {face_down: facedown }]
82
- end
83
-
84
- get /^flip_device_down\?$/i do
85
- [FlipDeviceTrigger, {face_down: true }]
86
- end
87
-
88
- get /^flip_device_up\?$/i do
89
- [FlipDeviceTrigger, {face_down: false }]
90
- end
91
-
92
- get /^Failed Login Attempt$/i do
93
- [FailedLoginTrigger, {}]
94
- end
95
-
96
- get /^failed_login?$/i do
97
- [FailedLoginTrigger, {}]
98
- end
99
-
100
- get /^Geofence (Entry|Exit) \(([^\)]+)/i do |direction, name|
101
- enter_area = direction.downcase.to_sym == :entry
102
- [GeofenceTrigger, {name: name, enter_area: enter_area}]
103
- end
104
-
105
- get /^location (entered|exited) \(([^\)]+)/i do |direction, name|
106
- enter_area = direction.downcase.to_sym == :entered
107
- [GeofenceTrigger, {name: name, enter_area: enter_area}]
108
- end
109
-
110
- # eg. Proximity Sensor (Near)
111
- #
112
- get /^Proximity Sensor \(([^\)]+)\)/i do |distance|
113
-
114
- [ProximityTrigger, {distance: distance}]
115
- end
116
-
117
- get /^WebHook \(Url\)/i do
118
- [WebHookTrigger, params]
119
- end
120
-
121
- get /^WebHook/i do
122
- [WebHookTrigger, params]
123
- end
124
-
125
- get /^wh/i do
126
- [WebHookTrigger, params]
127
- end
128
-
129
-
130
- end
131
-
132
- alias find_trigger run_route
133
-
134
- def to_s(colour: false)
135
- 'TriggersNlp ' + @h.inspect
136
- end
137
-
138
- alias to_summary to_s
139
- end
140
-
141
- class ActionsNlp
142
- include AppRoutes
143
-
144
- def initialize()
145
-
146
- super()
147
- params = {}
148
- actions(params)
149
-
150
- end
151
-
152
- def actions(params)
153
-
154
- # e.g. message popup: hello world!
155
- get /^message popup: (.*)/i do |msg|
156
- [ToastAction, {msg: msg}]
157
- end
158
-
159
- # e.g. Popup Message 'hello world!'
160
- get /^Popup[ _]Message ['"]([^'"]+)/i do |msg|
161
- [ToastAction, {msg: msg}]
162
- end
163
-
164
- # e.g. Popup Message\n hello world!
165
- get /^Popup Message\n\s+(.*)/im do |msg|
166
- [ToastAction, {msg: msg}]
167
- end
168
-
169
- # e.g. Popup Message
170
- get /^Popup Message$/i do
171
- [ToastAction, {}]
172
- end
173
-
174
- # e.g. say current time
175
- get /^say current[ _]time/i do
176
- [SayTimeAction, {}]
177
- end
178
-
179
- get /^Torch :?(.*)/i do |onoffstate|
180
- state = %w(on off toggle).index onoffstate.downcase
181
- [CameraFlashLightAction, {state: state}]
182
- end
183
-
184
- get /^Take Picture/i do
185
- [TakePictureAction, {}]
186
- end
187
-
188
- get /^take_picture/i do
189
- [TakePictureAction, {}]
190
- end
191
-
192
- # e.g. Display Notification: Hi there: This is the body of the message
193
- get /^Display Notification: ([^:]+): [^$]+$/i do |subject, text|
194
- [NotificationAction, {subject: subject, text: text}]
195
- end
196
-
197
-
198
- # e.g. Enable Wifi
199
- get /^(Enable|Disable) Wifi$/i do |raw_state|
200
-
201
- state = raw_state.downcase.to_sym == :enable ? 0 : 1
202
- [SetWifiAction, {state: state}]
203
-
204
- end
205
-
206
- # e.g. Play: Altair
207
- get /^Play: (.*)$/i do |name|
208
-
209
- [PlaySoundAction, {file_path: name}]
210
-
211
- end
212
-
213
- # e.g. Launch Settings
214
- get /^Launch (.*)$/i do |application|
215
-
216
- h = {
217
- application_name: application,
218
- package_to_launch: 'com.android.' + application.downcase
219
- }
220
- [LaunchActivityAction, h]
221
-
222
- end
223
-
224
- # e.g. HTTP GET http://someurl.com/something
225
- get /^HTTP GET ([^$]+)$/i do |url|
226
-
227
- [OpenWebPageAction, url_to_open: url]
228
-
229
- end
230
-
231
- # e.g. webhook entered_kitchen
232
- #
233
- get /webhook|HTTP GET/i do
234
- [OpenWebPageAction, {}]
235
- end
236
-
237
- #a: Keep Device Awake Screen On Until Disabled
238
- #
239
- get /Keep Device Awake Screen On Until Disabled/i do
240
- [KeepAwakeAction, {enabled: true, permanent: true, screen_option: 0}]
241
- end
242
-
243
-
244
- #a: Keep Device Awake Screen On 1h 1m 1s
245
- #
246
- get /Keep Device Awake Screen On ([^$]+)/i do |duration|
247
-
248
- a = duration.split.map(&:to_i)
249
- secs = Subunit.new(units={minutes:60, hours:60, seconds: 60}, a).to_i
250
-
251
- h = {
252
- permanent: true, screen_option: 0, seconds_to_stay_awake_for: secs
253
- }
254
- [KeepAwakeAction, h]
255
- end
256
-
257
- #a: Disable Keep Awake
258
- #
259
- get /Disable Keep Awake/i do
260
- [KeepAwakeAction, {enabled: false, screen_option: 0}]
261
- end
262
-
263
- #e.g a: if Airplane mode enabled
264
- #
265
- get /if (.*)/i do
266
- [IfConditionAction, {}]
267
- end
268
-
269
- get /End If/i do
270
- [EndIfAction, {}]
271
- end
272
-
273
- end
274
-
275
- alias find_action run_route
276
-
277
-
278
- end
279
-
280
- class ConstraintsNlp
281
- include AppRoutes
282
-
283
- def initialize()
284
-
285
- super()
286
- params = {}
287
- constraints(params)
288
-
289
- end
290
-
291
- def constraints(params)
292
-
293
- get /^airplane mode (.*)/i do |state|
294
- [AirplaneModeConstraint, {enabled: (state =~ /^enabled|on$/i) == 0}]
295
- end
296
-
297
- end
298
-
299
- alias find_constraint run_route
300
-
301
- end
302
-
303
-
304
49
  module Params
305
50
 
306
51
  refine Hash do
@@ -330,16 +75,16 @@ module Params
330
75
  end
331
76
 
332
77
  # turns keys from snake_case to CamelCase
333
- def to_camel_case(h=self)
78
+ def to_camelcase(h=self)
334
79
 
335
80
  h.inject({}) do |r,x|
336
81
 
337
82
  key, value = x
338
83
 
339
84
  val = if value.is_a?(Hash) then
340
- to_camel_case(value)
85
+ to_camelcase(value)
341
86
  elsif value.is_a?(Array) and value.first.is_a? Hash
342
- value.map {|row| to_camel_case(row)}
87
+ value.map {|row| to_camelcase(row)}
343
88
  else
344
89
  value
345
90
  end
@@ -356,8 +101,6 @@ end
356
101
 
357
102
 
358
103
 
359
-
360
-
361
104
  class MacroDroidError < Exception
362
105
  end
363
106
 
@@ -367,14 +110,14 @@ class MacroDroid
367
110
  using Params
368
111
 
369
112
  attr_reader :macros, :geofences, :yaml
370
- attr_accessor :deviceid
113
+ attr_accessor :deviceid, :remote_url
371
114
 
372
115
  # note: The deviceid can only be found from an existing Webhook trigger,
373
116
  # generated from MacroDroid itself.
374
117
 
375
- def initialize(obj=nil, deviceid: nil, debug: false)
118
+ def initialize(obj=nil, deviceid: nil, remote_url: nil, debug: false)
376
119
 
377
- @deviceid, @debug = deviceid, debug
120
+ @deviceid, @remote_url, @debug = deviceid, remote_url, debug
378
121
 
379
122
  @geofences = {}
380
123
 
@@ -403,8 +146,9 @@ class MacroDroid
403
146
  puts 'before RowX.new' if @debug
404
147
 
405
148
  s2 = s.gsub(/^g:/,'geofence:').gsub(/^m:/,'macro:')\
406
- .gsub(/^v:/,'variable:').gsub(/^t:/,'trigger:')\
407
- .gsub(/^a:/,'action:').gsub(/^c:/,'constraint:').gsub(/^#.*/,'')
149
+ .gsub(/^d:/,'description:').gsub(/^v:/,'variable:')\
150
+ .gsub(/^t:/,'trigger:').gsub(/^a:/,'action:')\
151
+ .gsub(/^c:/,'constraint:').gsub(/^#.*/,'')
408
152
 
409
153
  a = s2.split(/(?=^macro:)/)
410
154
 
@@ -424,7 +168,7 @@ class MacroDroid
424
168
 
425
169
  end
426
170
 
427
- xml = RowX.new(raw_macros).to_xml
171
+ xml = RowX.new(raw_macros, allow_lonely_keyfield: true).to_xml
428
172
  puts 'xml: ' + xml if @debug
429
173
  import_rowxml(xml)
430
174
 
@@ -499,7 +243,7 @@ class MacroDroid
499
243
  },
500
244
  macro_list: @macros.map(&:to_h)
501
245
  }
502
- @h.merge(h).to_camel_case
246
+ @h.merge(h).to_camelcase
503
247
 
504
248
  end
505
249
 
@@ -590,7 +334,7 @@ class MacroDroid
590
334
  # puts '@geofences: ' + @geofences.inspect if @debug
591
335
 
592
336
  m = Macro.new(geofences: @geofences.map(&:last), deviceid: @deviceid,
593
- debug: @debug )
337
+ remote_url: @remote_url, debug: @debug )
594
338
  m.import_h(macro)
595
339
  m
596
340
 
@@ -612,7 +356,7 @@ class MacroDroid
612
356
  @macros = doc.root.xpath('item').map do |node|
613
357
  puts ('geofences: ' + geofences.inspect).highlight if @debug
614
358
  Macro.new(geofences: geofences.map(&:last), deviceid: @deviceid,
615
- debug: @debug).import_xml(node)
359
+ remote_url: @remote_url, debug: @debug).import_xml(node)
616
360
 
617
361
  end
618
362
 
@@ -835,65 +579,7 @@ class DroidSim
835
579
 
836
580
  end
837
581
 
838
- RD_MACROS =<<EOF
839
- m: Torch
840
- t: webhook
841
- a: Torch toggle
842
- EOF
843
-
844
- module RemoteDroid
845
-
846
- class Service
847
- def initialize(callback)
848
- @callback = callback
849
- end
850
- end
851
-
852
- class Bluetooth
853
- def enable()
854
- end
855
- end
856
-
857
- class Torch < Service
858
-
859
- def toggle()
860
- @callback.call :torch
861
- end
862
-
863
- end
864
-
865
- class Control
866
-
867
- def initialize(deviceid: nil)
868
- @deviceid = deviceid
869
- @torch = Torch.new(self)
870
- end
871
-
872
- def bluetooth()
873
- @bluetooth
874
- end
875
-
876
- def call(command)
877
- url = "https://trigger.macrodroid.com/%s/%s" % [@deviceid, command]
878
- puts 'url: ' + url.inspect
879
- s = open(url).read
880
- end
881
-
882
- def torch()
883
- @torch
884
- end
885
-
886
- def write(s)
887
-
888
- MacroDroid.new(RD_MACROS, deviceid: @deviceid).export s
889
-
890
- end
891
-
892
- alias export write
893
-
894
- end
895
-
896
- end
582
+ # PASTE_END
897
583
 
898
584
  require 'ruby-macrodroid/base'
899
585
  require 'ruby-macrodroid/triggers'
@@ -34,6 +34,7 @@
34
34
 
35
35
  class Action < MacroObject
36
36
  using Params
37
+ include ObjectX
37
38
 
38
39
  attr_reader :constraints
39
40
 
@@ -49,8 +50,8 @@ class Action < MacroObject
49
50
 
50
51
  end
51
52
 
52
- def invoke(s='')
53
- "%s/%s: %s" % [@group, @type, s]
53
+ def invoke(h={})
54
+ "%s/%s: %s" % [@group, @type, h.to_json]
54
55
  end
55
56
 
56
57
 
@@ -136,26 +137,95 @@ class LaunchShortcutAction < ApplicationAction
136
137
 
137
138
  end
138
139
 
140
+ class OpenWebPageActionError < Exception
141
+ end
142
+
139
143
  # Category: Applications
140
144
  #
141
145
  class OpenWebPageAction < ApplicationAction
142
146
 
143
- def initialize(h={})
147
+ def initialize(obj={}, macro=nil)
148
+
149
+ # puts 'obj: ' + obj[0].xml.inspect
144
150
 
145
- h[:url_to_open] = h[:url] if h[:url]
151
+ h = if obj.is_a? Hash then
152
+
153
+ obj
154
+
155
+ elsif obj.is_a? Array
156
+
157
+ puts 'obj: ' + obj.inspect if $debug
158
+ e, macro = obj
159
+
160
+ a = e.xpath('item/*')
161
+
162
+ h2 = if a.any? then
163
+ a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
164
+ else
165
+ txt = e.text('item/description')
166
+ {url: (txt || e.text)}
167
+ end
168
+
169
+ h2.merge(macro: macro)
170
+
171
+ end
172
+
173
+ puts 'h:' + h.inspect if $debug
174
+
175
+ #h[:url_to_open] = h[:url] if h[:url] and h[:url].length > 1
146
176
 
147
177
  options = {
148
- variable_to_save_response: {:m_stringValue=>"", :m_name=>"", :m_decimalValue=>0.0, :isLocal=>true, :m_booleanValue=>false, :excludeFromLog=>false, :m_intValue=>0, :m_type=>2},
178
+ variable_to_save_response: {:string_value=>"", :name=>"coords",
179
+ decimal_value: 0.0, isLocal: true, m_boolean_value: false,
180
+ excludeFromLog: false, int_value: 0, type: 2},
149
181
  url_to_open: '',
150
182
  http_get: true,
151
183
  disable_url_encode: false,
152
184
  block_next_action: false
153
185
  }
186
+
187
+ return super(options.merge h) if h[:url_to_open]
188
+
189
+ if h[:macro].remote_url.nil? and (h[:url].nil? or h[:url].empty?) then
190
+ raise OpenWebPageActionError, 'remote_url not found'
191
+ end
192
+
193
+ url = if h[:url] and h[:url].length > 1 then
194
+
195
+ h[:url]
154
196
 
155
- super(options.merge filter(options,h))
197
+ elsif h2 and h[:macro].remote_url and h[:identifier]
198
+
199
+ "%s/%s" % [h[:macro].remote_url.sub(/\/$/,''), h[:identifier]]
200
+
201
+ elsif (h[:identifier].nil? or h[:identifier].empty?)
202
+
203
+ h[:url_to_open] = h[:macro].remote_url.sub(/\/$/,'') + '/' +
204
+ h[:macro].title.downcase.gsub(/ +/,'-')
205
+
206
+ end
207
+
208
+ if h2 then
209
+
210
+ h2.delete :identifier
211
+ h2.delete :url
212
+
213
+ if h2.any? then
214
+ url += '?' + \
215
+ URI.escape(h2.map {|key,value| "%s=%s" % [key, value]}.join('&'))
216
+ end
217
+
218
+ end
219
+
220
+ h[:url_to_open] = url
221
+ super(options.merge h)
156
222
 
157
223
  end
158
224
 
225
+ def invoke()
226
+ super(url: @h[:url_to_open])
227
+ end
228
+
159
229
  def to_s(colour: false, indent: 0)
160
230
  @s = "HTTP GET\nurl: " + @h[:url_to_open]
161
231
  super()
@@ -324,6 +394,7 @@ class IfConditionAction < Action
324
394
  a: true,
325
395
  constraint_list: []
326
396
  }
397
+ puts 'obj: ' + obj.inspect #if $debug
327
398
 
328
399
  if obj.is_a? Hash then
329
400
 
@@ -332,13 +403,19 @@ class IfConditionAction < Action
332
403
  h2 = options.merge(filter(options,h).merge(macro: macro))
333
404
  super(h2)
334
405
 
335
- elsif obj.is_a? Rexle::Element
336
- super()
337
- raw_txt = obj.text('item/description') || obj.text.to_s
338
- puts 'raw_txt: ' + raw_txt.inspect if $debug
406
+ elsif obj.is_a? Array
339
407
 
340
- clause = raw_txt[/^if (.*)/i,1]
408
+ e, macro = obj
409
+ super()
410
+ puts 'e.xml: ' + e.xml
411
+ puts 'e.text: ' + e.text.to_s.strip
412
+ raw_txt = e.text.to_s.strip[/^if [^$]+/i] || e.text('item/description')
413
+ puts 'raw_txt: ' + raw_txt.inspect #if $debug
414
+
415
+ clause = raw_txt[/^If (.*)/i,1]
416
+ puts 'clause: ' + clause.inspect
341
417
  conditions = clause.split(/\s+\b(?:AND|OR)\b\s+/i)
418
+ puts 'conditions: ' + conditions.inspect
342
419
 
343
420
  cp = ConstraintsNlp.new
344
421
 
@@ -351,6 +428,19 @@ class IfConditionAction < Action
351
428
 
352
429
  end
353
430
  puts '@constraints: ' + @constraints.inspect if $debug
431
+
432
+ # find any nested actions
433
+ item = e.element('item')
434
+
435
+ if item then
436
+
437
+ ap = ActionsNlp.new
438
+ obj2 = action_to_object(ap, item, item, macro)
439
+ puts 'obj2: ' + obj2.inspect
440
+ #macro.add obj2
441
+
442
+ end
443
+
354
444
  {}
355
445
  else
356
446
  # get the constraints
@@ -368,7 +458,7 @@ class IfConditionAction < Action
368
458
  def to_s(colour: false, indent: 0)
369
459
 
370
460
  h = @h.clone
371
- h.delete :macro
461
+ #h.delete :macro
372
462
  @s = 'If '
373
463
  operator = @h[:is_or_condition] ? 'OR' : 'AND'
374
464
  constraints = @constraints.map \
@@ -380,7 +470,8 @@ class IfConditionAction < Action
380
470
  out << s + constraints
381
471
  out.join("\n")
382
472
 
383
- end
473
+ end
474
+
384
475
  end
385
476
 
386
477
  class ElseAction < Action
@@ -448,6 +539,8 @@ class EndIfAction < Action
448
539
  obj
449
540
  elsif obj.is_a? Rexle::Element
450
541
  {}
542
+ else
543
+ {}
451
544
  end
452
545
 
453
546
 
@@ -455,7 +548,7 @@ class EndIfAction < Action
455
548
  constraint_list: []
456
549
  }
457
550
 
458
- super(options.merge h)
551
+ super()
459
552
 
460
553
  end
461
554
 
@@ -700,9 +793,10 @@ class SayTimeAction < DateTimeAction
700
793
  end
701
794
 
702
795
  def invoke()
703
- time = ($env and $env[:time]) ? $env[:time] : Time.now
796
+ #time = ($env and $env[:time]) ? $env[:time] : Time.now
797
+ time = Time.now
704
798
  tformat = @h['12_hour'] ? "%-I:%M%P" : "%H:%M"
705
- super(time.strftime(tformat))
799
+ super(txt: time.strftime(tformat))
706
800
  end
707
801
 
708
802
  def to_pc()
@@ -791,10 +885,18 @@ end
791
885
  #
792
886
  class SpeakTextAction < DeviceAction
793
887
 
794
- def initialize(h={})
795
-
888
+ def initialize(obj=nil)
889
+
890
+ h = if obj.is_a? Hash then
891
+ obj
892
+ elsif obj.is_a? Array
893
+ e, macro = obj
894
+ txt = e.text('item/description')
895
+ {text: (txt || e.text)}
896
+ end
897
+
796
898
  options = {
797
- text_to_say: '',
899
+ text_to_say: h[:text] || '',
798
900
  queue: false,
799
901
  read_numbers_individually: false,
800
902
  specify_audio_stream: false,
@@ -808,8 +910,13 @@ class SpeakTextAction < DeviceAction
808
910
 
809
911
  end
810
912
 
913
+ def invoke()
914
+ super(text: @h[:text_to_say])
915
+ end
916
+
811
917
  def to_s(colour: false, indent: 0)
812
- "Speak Text (%s)" % @h[:text_to_say]
918
+ @s = "Speak Text (%s)" % @h[:text_to_say]
919
+ super()
813
920
  end
814
921
 
815
922
  end
@@ -961,6 +1068,9 @@ class CameraFlashLightAction < DeviceSettingsAction
961
1068
  super(options.merge h)
962
1069
 
963
1070
  end
1071
+ def invoke()
1072
+ super(state: @h[:state])
1073
+ end
964
1074
 
965
1075
  def to_pc()
966
1076
  ['torch :on', 'torch :off', 'torch :toggle'][@h[:state]]
@@ -977,7 +1087,17 @@ end
977
1087
  class VibrateAction < DeviceSettingsAction
978
1088
 
979
1089
  def initialize(h={})
980
-
1090
+
1091
+ pattern = [
1092
+ 'Blip', 'Short Buzz', 'Long Buzz', 'Rapid', 'Slow', 'Increasing',
1093
+ 'Constant', 'Decreasing', 'Final Fantasy', 'Game Over', 'Star Wars',
1094
+ 'Mini Blip', 'Micro Blip'
1095
+ ]
1096
+
1097
+ if h[:pattern] then
1098
+ h[:vibrate_pattern] = pattern.map(&:downcase).index h[:pattern]
1099
+ end
1100
+
981
1101
  options = {
982
1102
  vibrate_pattern: 1
983
1103
  }
@@ -1265,7 +1385,7 @@ class ForceLocationUpdateAction < LocationAction
1265
1385
  end
1266
1386
 
1267
1387
  def to_s(colour: false, indent: 0)
1268
- 'ForceLocationUpdateAction ' + @h.inspect
1388
+ 'Force Location Update' #+ @h.inspect
1269
1389
  end
1270
1390
 
1271
1391
  alias to_summary to_s
@@ -1286,26 +1406,34 @@ end
1286
1406
  #
1287
1407
  class ShareLocationAction < LocationAction
1288
1408
 
1289
- def initialize(h={})
1409
+ def initialize(obj=nil)
1290
1410
 
1291
- super()
1411
+ h = if obj.is_a? Hash then
1412
+ obj
1413
+ elsif obj.is_a? Array
1414
+ e, macro = obj
1415
+ {variable: macro.set_var(e.text('item/description').to_s)}
1416
+
1417
+ end
1418
+
1419
+ #super()
1292
1420
 
1293
1421
  options = {
1294
1422
  email: '',
1295
- variable: {:m_stringValue=>"", :m_name=>"",
1296
- :m_decimalValue=>0.0, :isLocal=>true, :m_booleanValue=>false,
1297
- :excludeFromLog=>false, :m_intValue=>0, :m_type=>2},
1423
+ variable: {:string_value=>"", :name=>"",
1424
+ :decimal_value=>0.0, :is_local=>true, :boolean_value=>false,
1425
+ :exclude_from_log=>false, :int_value=>0, :type=>2},
1298
1426
  sim_id: 0,
1299
1427
  output_channel: 5,
1300
1428
  old_variable_format: true
1301
1429
  }
1302
-
1430
+ #options[:variable].merge! h
1303
1431
  super(options.merge h)
1304
1432
 
1305
1433
  end
1306
1434
 
1307
1435
  def to_s(colour: false, indent: 0)
1308
- @s = 'Share Location' + "\nGPS" # + @h.inspect
1436
+ @s = 'Share Location' + "\n" + @h[:variable][:name] # + @h.inspect
1309
1437
  super()
1310
1438
  end
1311
1439
 
@@ -1500,7 +1628,15 @@ end
1500
1628
  #
1501
1629
  class SetVariableAction < Action
1502
1630
 
1503
- def initialize(h={})
1631
+ def initialize(obj=nil)
1632
+
1633
+ h = if obj.is_a? Hash then
1634
+ obj
1635
+ elsif obj.is_a? Array
1636
+ e, macro = obj
1637
+ node = e.element('item/*')
1638
+ macro.set_var node.name, node.value.to_s
1639
+ end
1504
1640
 
1505
1641
  options = {
1506
1642
  :user_prompt=>true,
@@ -1508,9 +1644,21 @@ class SetVariableAction < Action
1508
1644
  :user_prompt_show_cancel=>true,
1509
1645
  :user_prompt_stop_after_cancel=>true,
1510
1646
  :user_prompt_title=>"Word reverse",
1511
- :name => 'word'
1647
+ :name => 'word',
1648
+ :false_label=>"False", :int_expression=>false, :int_random=>false,
1649
+ :int_random_max=>0, :int_random_min=>0, :int_value_decrement=>false,
1650
+ :int_value_increment=>false, :new_boolean_value=>false,
1651
+ :new_double_value=>0.0, :new_int_value=>0,
1652
+ :new_string_value=>"[battery]", :true_label=>"True",
1653
+ :user_prompt=>false, :user_prompt_show_cancel=>true,
1654
+ :user_prompt_stop_after_cancel=>true,
1655
+ :variable=>{
1656
+ :exclude_from_log=>false, :is_local=>true,
1657
+ :boolean_value=>false, :decimal_value=>0.0,
1658
+ :int_value=>0, :name=>"foo", :string_value=>"52", :type=>2
1659
+ }
1512
1660
  }
1513
- super(h)
1661
+ super(options.merge h)
1514
1662
 
1515
1663
  end
1516
1664
 
@@ -1971,11 +2119,10 @@ class ToastAction < NotificationsAction
1971
2119
 
1972
2120
  h = if obj.is_a? Hash then
1973
2121
  obj
1974
- elsif obj.is_a? Rexle::Element
1975
- txt = obj.text('item/description')
1976
- {msg: (txt || obj.text)}
1977
- else
1978
- {msg: obj}
2122
+ elsif obj.is_a? Array
2123
+ e, macro = obj
2124
+ txt = e.text('item/description')
2125
+ {msg: (txt || e.text)}
1979
2126
  end
1980
2127
 
1981
2128
  if h[:msg] then
@@ -1999,7 +2146,7 @@ class ToastAction < NotificationsAction
1999
2146
  end
2000
2147
 
2001
2148
  def invoke()
2002
- super(@h[:message_text])
2149
+ super(msg: @h[:message_text])
2003
2150
  end
2004
2151
 
2005
2152
  def to_pc()
@@ -2265,8 +2412,46 @@ end
2265
2412
  # disable keep awake => enabled: false
2266
2413
  #
2267
2414
  class KeepAwakeAction < ScreenAction
2415
+ using ColouredText
2268
2416
 
2269
- def initialize(h={})
2417
+ def initialize(obj=nil)
2418
+
2419
+
2420
+ h = if obj.is_a? Hash then
2421
+
2422
+ obj
2423
+
2424
+ elsif obj.is_a? Array
2425
+
2426
+ puts 'obj: ' + obj.inspect if $debug
2427
+ e, macro = obj
2428
+
2429
+ a = e.xpath('item/*')
2430
+
2431
+ txt = e.text('item/description')
2432
+
2433
+ h2 = if txt then
2434
+
2435
+ raw_duration = (txt || e.text).to_s
2436
+ puts 'raw_duration: ' + raw_duration.inspect
2437
+ duration = raw_duration[/Screen On - ([^$]+)/i]
2438
+ {duration: duration}
2439
+
2440
+ elsif a.any? then
2441
+ a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
2442
+ end
2443
+
2444
+ h2.merge(macro: macro)
2445
+
2446
+ end
2447
+
2448
+ puts ('h: ' + h.inspect).debug #if $debug
2449
+
2450
+ if h[:duration] then
2451
+
2452
+ h[:seconds_to_stay_awake_for] = Subunit.hms_to_seconds(h[:duration])
2453
+
2454
+ end
2270
2455
 
2271
2456
  options = {
2272
2457
  enabled: true,