motion-prime 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +6 -6
  4. data/README.md +1 -10
  5. data/Rakefile +0 -1
  6. data/app/app_delegate.rb +1 -1
  7. data/bin/prime +1 -1
  8. data/files/Gemfile +1 -1
  9. data/motion-prime/api_client.rb +87 -31
  10. data/motion-prime/config/base.rb +20 -11
  11. data/motion-prime/config/config.rb +9 -3
  12. data/motion-prime/core_ext/kernel.rb +2 -1
  13. data/motion-prime/core_ext/nil_class.rb +5 -0
  14. data/motion-prime/delegate/app_delegate.rb +5 -0
  15. data/motion-prime/elements/base_element.rb +21 -2
  16. data/motion-prime/elements/draw.rb +6 -16
  17. data/motion-prime/helpers/has_authorization.rb +1 -1
  18. data/motion-prime/models/_base_mixin.rb +1 -1
  19. data/motion-prime/prime.rb +4 -0
  20. data/motion-prime/screens/extensions/_indicators_mixin.rb +16 -10
  21. data/motion-prime/screens/screen.rb +1 -1
  22. data/motion-prime/sections/_async_table_mixin.rb +1 -2
  23. data/motion-prime/sections/_draw_section_mixin.rb +3 -1
  24. data/motion-prime/sections/base_section.rb +37 -26
  25. data/motion-prime/sections/form.rb +23 -8
  26. data/motion-prime/sections/form/base_field_section.rb +1 -15
  27. data/motion-prime/sections/form/date_field_section.rb +1 -1
  28. data/motion-prime/sections/form/password_field_section.rb +1 -1
  29. data/motion-prime/sections/form/select_field_section.rb +1 -1
  30. data/motion-prime/sections/form/string_field_section.rb +1 -1
  31. data/motion-prime/sections/form/submit_field_section.rb +1 -1
  32. data/motion-prime/sections/form/text_field_section.rb +1 -1
  33. data/motion-prime/sections/table.rb +58 -27
  34. data/motion-prime/sections/table/refresh_mixin.rb +1 -1
  35. data/motion-prime/services/logger.rb +60 -21
  36. data/motion-prime/support/consts.rb +11 -0
  37. data/motion-prime/version.rb +1 -1
  38. data/motion-prime/views/layout.rb +5 -4
  39. data/motion-prime/views/view_styler.rb +3 -0
  40. data/spec/{helpers → factories}/delegates.rb +0 -3
  41. data/spec/{helpers → factories}/init.rb +0 -0
  42. data/spec/{helpers → factories}/models.rb +0 -0
  43. data/spec/factories/scaffold/models/task.rb +4 -0
  44. data/spec/factories/scaffold/screens/tasks.rb +45 -0
  45. data/spec/factories/scaffold/sections/tasks/form.rb +31 -0
  46. data/spec/factories/scaffold/sections/tasks/index_cell.rb +4 -0
  47. data/spec/factories/scaffold/sections/tasks/index_table.rb +12 -0
  48. data/spec/factories/scaffold/sections/tasks/show.rb +3 -0
  49. data/spec/factories/scaffold/styles/tasks.rb +18 -0
  50. data/spec/{helpers → factories}/screens.rb +0 -0
  51. data/spec/factories/sections.rb +9 -0
  52. data/spec/features/scaffold/index.rb +14 -0
  53. data/spec/features/screens/open_screen.rb +14 -2
  54. data/spec/helpers/has_content.rb +25 -0
  55. data/spec/unit/models/dirty_spec.rb +0 -1
  56. data/spec/unit/models/model_spec.rb +2 -0
  57. data/spec/unit/prime/logger.rb +49 -0
  58. data/spec/unit/sections/section_spec.rb +59 -0
  59. data/travis.sh +1 -1
  60. metadata +36 -41
  61. data/doc/FAQ.md +0 -2
  62. data/doc/SECTION.md +0 -7
  63. data/doc/STYLE.md +0 -39
  64. data/doc/code/getting_started.rb +0 -106
  65. data/doc/code/models.rb +0 -36
  66. data/doc/code/screens.rb +0 -93
  67. data/doc/code/sections.rb +0 -65
  68. data/doc/code/tables.rb +0 -54
  69. data/doc/docs/docco.css +0 -337
  70. data/doc/docs/getting_started.html +0 -195
  71. data/doc/docs/index.html +0 -205
  72. data/doc/docs/models.html +0 -115
  73. data/doc/docs/public/fonts/aller-bold.eot +0 -0
  74. data/doc/docs/public/fonts/aller-bold.ttf +0 -0
  75. data/doc/docs/public/fonts/aller-bold.woff +0 -0
  76. data/doc/docs/public/fonts/aller-light.eot +0 -0
  77. data/doc/docs/public/fonts/aller-light.ttf +0 -0
  78. data/doc/docs/public/fonts/aller-light.woff +0 -0
  79. data/doc/docs/public/fonts/fleurons.eot +0 -0
  80. data/doc/docs/public/fonts/fleurons.ttf +0 -0
  81. data/doc/docs/public/fonts/fleurons.woff +0 -0
  82. data/doc/docs/public/fonts/novecento-bold.eot +0 -0
  83. data/doc/docs/public/fonts/novecento-bold.ttf +0 -0
  84. data/doc/docs/public/fonts/novecento-bold.woff +0 -0
  85. data/doc/docs/public/images/gray.png +0 -0
  86. data/doc/docs/public/stylesheets/normalize.css +0 -375
  87. data/doc/docs/screens.html +0 -187
  88. data/doc/docs/sections.html +0 -138
  89. data/doc/docs/tables.html +0 -128
  90. data/spec/helpers/sections.rb +0 -3
@@ -36,36 +36,27 @@ module MotionPrime
36
36
 
37
37
  def bind_gesture(action, receiver = nil, target = nil)
38
38
  target ||= section
39
- target.bind_gesture_on_container_for(self, action, receiver)
39
+ target.bind_gesture_on_container_for(self, action, receiver.weak_ref)
40
40
  end
41
41
 
42
42
  def hide
43
43
  return if computed_options[:hidden]
44
44
  computed_options[:hidden] = true
45
- section.cached_draw_image = nil
46
- view.setNeedsDisplay
45
+ rerender!
47
46
  end
48
47
 
49
48
  def show
50
49
  return if !computed_options[:hidden]
51
50
  computed_options[:hidden] = false
52
- section.cached_draw_image = nil
53
- view.setNeedsDisplay
51
+ rerender!
54
52
  end
55
53
 
56
- def reload!
57
- reset_computed_values
58
- compute_options!
54
+ def rerender!
59
55
  section.cached_draw_image = nil
60
- end
61
-
62
- def update_with_options(new_options = {})
63
- options.merge!(new_options)
64
- reload!
65
56
  view.setNeedsDisplay
66
57
  end
67
58
 
68
- private
59
+ protected
69
60
  def frame_outer_width; computed_frame.size.width end
70
61
  def frame_width; frame_outer_width - content_padding_width end
71
62
 
@@ -85,8 +76,7 @@ module MotionPrime
85
76
  def frame_inner_right; frame_right - content_padding_right end
86
77
 
87
78
  def reset_computed_values
88
- @content_height = nil
89
- @content_width = nil
79
+ super
90
80
  @computed_frame = nil
91
81
  end
92
82
 
@@ -10,7 +10,7 @@ module MotionPrime
10
10
  current_user.present?
11
11
  end
12
12
  def api_client
13
- @api_client ||= ApiClient.new(access_token: current_user.try(:access_token))
13
+ App.delegate.api_client
14
14
  end
15
15
  end
16
16
  end
@@ -49,7 +49,7 @@ module MotionPrime
49
49
  elsif options[:validate_attribute_presence]
50
50
  raise(StoreError, "unknown attribute: '#{k}'")
51
51
  else
52
- NSLog("unknown attribute: #{k}")
52
+ Prime.logger.info("unknown attribute: #{k}")
53
53
  end
54
54
  end
55
55
  end
@@ -18,5 +18,9 @@ module MotionPrime
18
18
  def self.logger
19
19
  @logger ||= MotionPrime::Logger.new
20
20
  end
21
+
22
+ def self.logger=(value)
23
+ @logger = value
24
+ end
21
25
  end
22
26
  ::Prime = MotionPrime unless defined?(::Prime)
@@ -1,17 +1,23 @@
1
1
  module MotionPrime
2
2
  module ScreenIndicatorsMixin
3
- def show_activity_indicator
4
- if @activity_indicator_view.nil?
5
- @activity_indicator_view = UIActivityIndicatorView.gray
6
- @activity_indicator_view.center = CGPointMake(view.center.x, view.center.y)
7
- view.addSubview @activity_indicator_view
3
+ def show_activity_indicator(render_target = nil, options = {})
4
+ render_target ||= view
5
+ @activity_indicator_view ||= {}
6
+ indicator = @activity_indicator_view[render_target.object_id] ||= begin
7
+ indicator = UIActivityIndicatorView.gray
8
+ render_target.addSubview(indicator)
9
+ indicator
8
10
  end
9
- @activity_indicator_view.startAnimating
11
+
12
+ center = options[:center] || {}
13
+ indicator.center = CGPointMake(center.fetch(:x, render_target.center.x), center.fetch(:y, render_target.center.y))
14
+ indicator.startAnimating
10
15
  end
11
16
 
12
- def hide_activity_indicator
13
- return unless @activity_indicator_view
14
- @activity_indicator_view.stopAnimating
17
+ def hide_activity_indicator(render_target = nil)
18
+ @activity_indicator_view ||= {}
19
+ render_target ||= view
20
+ @activity_indicator_view[render_target.object_id].try(:stopAnimating)
15
21
  end
16
22
 
17
23
  def show_progress_indicator(text = nil, options = {})
@@ -24,7 +30,7 @@ module MotionPrime
24
30
  options[:add_to_view] ||= self.view
25
31
  @progress_indicator_view = self.progress_hud(options).view
26
32
  else
27
- self.set_options(@progress_indicator_view, options.except(:add_to_view))
33
+ self.update_options_for(@progress_indicator_view, options.except(:add_to_view))
28
34
  @progress_indicator_view.show options.has_key?(:animated) ? options[:animatetd] : true
29
35
  end
30
36
  end
@@ -35,7 +35,7 @@ module MotionPrime
35
35
  @visible = true
36
36
  @on_appear_happened ||= {}
37
37
  unless @on_appear_happened[view.object_id]
38
- set_options view, styles: default_styles do
38
+ set_options_for view, styles: default_styles do
39
39
  run_callbacks :render do
40
40
  send((action).to_sym)
41
41
  end
@@ -24,7 +24,7 @@ module Prime
24
24
  # Reset async loaded table data and preloader queue.
25
25
  #
26
26
  # @return [Boolean] true
27
- def reset_data
27
+ def reset_table_data
28
28
  super # must be before to update fixed_table_data
29
29
  @async_loaded_data = async_data? ? fixed_table_data : nil
30
30
  Array.wrap(@preloader_queue).each { |queue| queue[:state] = :cancelled }
@@ -175,7 +175,6 @@ module Prime
175
175
 
176
176
  def preload_section_by_index(index)
177
177
  section = cell_section_by_index(index)
178
-
179
178
  if section.create_elements && !section.container_element && async_data? # perform only if just loaded
180
179
  section.load_container_with_elements(container: container_element_options_for(index))
181
180
  section
@@ -37,7 +37,9 @@ module MotionPrime
37
37
 
38
38
  def clear_gesture_for_receiver(receiver)
39
39
  return unless self.container_gesture_recognizers
40
- self.container_gesture_recognizers.delete_if { |recognizer| recognizer[:receiver] == receiver }
40
+ self.container_gesture_recognizers.delete_if { |recognizer|
41
+ !recognizer[:receiver].weakref_alive? || recognizer[:receiver] == receiver
42
+ }
41
43
  end
42
44
 
43
45
  def prerender_elements_for_state(state = :normal)
@@ -22,7 +22,7 @@ module MotionPrime
22
22
  include DelegateMixin
23
23
 
24
24
  attr_accessor :screen, :model, :name, :options, :elements, :section_styles
25
- class_attribute :elements_options, :container_options, :keyboard_close_bindings
25
+ class_attribute :elements_options, :container_options, :keyboard_close_bindings, :elements_callbacks
26
26
  define_callbacks :render, :initialize
27
27
 
28
28
  def initialize(options = {})
@@ -139,22 +139,17 @@ module MotionPrime
139
139
 
140
140
  # Force reload section, will also re-render elements.
141
141
  # For table view cells will also reload it's table data.
142
+ # Useful on some cases, but in common case please use #reload.
142
143
  #
143
144
  # @return [Boolean] true
144
- def reload_section
145
+ def hard_reload_section
145
146
  # reload Base Elements
146
- # TODO: probably should use update_with_options for Base elements too?
147
147
  self.elements_to_render.values.map(&:view).flatten.each do |view|
148
148
  view.removeFromSuperview if view
149
149
  end
150
- create_elements!
151
- run_callbacks :render do
152
- render!
153
- end
150
+ render({}, true)
154
151
  # reload Draw Elements
155
- elements_to_draw.each do |key, element|
156
- element.update_with_options
157
- end
152
+ elements_to_draw.values.each(&:update)
158
153
 
159
154
  if @table && !self.is_a?(BaseFieldSection)
160
155
  cell.setNeedsDisplay
@@ -163,11 +158,23 @@ module MotionPrime
163
158
  true
164
159
  end
165
160
 
166
- # Alias for reload_section
161
+ # Reload section, will re-render elements.
167
162
  #
168
163
  # @return [Boolean] true
169
164
  def reload
170
- reload_section
165
+ elements.values.each(&:update)
166
+ true
167
+ end
168
+
169
+ def render_container(options = {}, &block)
170
+ if should_render_container? && !self.container_element.try(:view)
171
+ element = self.init_container_element(options)
172
+ element.render do
173
+ block.call
174
+ end
175
+ else
176
+ block.call
177
+ end
171
178
  end
172
179
 
173
180
  def add_element(key, options = {})
@@ -190,33 +197,30 @@ module MotionPrime
190
197
  true
191
198
  end
192
199
 
193
- def render(container_options = {})
194
- create_elements
200
+ def render(container_options = {}, force = false)
201
+ force ? create_elements! : create_elements
195
202
  self.container_options.merge!(container_options)
196
203
  run_callbacks :render do
197
204
  render!
198
205
  end
199
206
  end
200
207
 
201
- def render_container(options = {}, &block)
202
- if should_render_container? && !self.container_element.try(:view)
203
- element = self.init_container_element(options)
204
- element.render do
205
- block.call
206
- end
207
- else
208
- block.call
209
- end
210
- end
211
-
212
208
  def render!
213
209
  render_container(container_options) do
214
210
  elements_to_render.each do |key, element|
215
211
  element.render
212
+ on_element_render(element)
216
213
  end
217
214
  end
218
215
  end
219
216
 
217
+ def on_element_render(element)
218
+ return unless callbacks = elements_callbacks.try(:[], element.name)
219
+ callbacks.each do |options|
220
+ options[:method].to_proc.call(options[:target] || self)
221
+ end
222
+ end
223
+
220
224
  def element(name)
221
225
  self.elements ||= {}
222
226
  self.elements[name.to_sym]
@@ -305,7 +309,7 @@ module MotionPrime
305
309
  end
306
310
 
307
311
  def screen?
308
- screen && screen.weakref_alive?
312
+ screen.weakref_alive?
309
313
  end
310
314
 
311
315
  protected
@@ -387,6 +391,7 @@ module MotionPrime
387
391
 
388
392
  class << self
389
393
  def inherited(subclass)
394
+ subclass.elements_callbacks = self.elements_callbacks.try(:clone)
390
395
  subclass.elements_options = self.elements_options.try(:clone)
391
396
  subclass.container_options = self.container_options.try(:clone)
392
397
  subclass.keyboard_close_bindings = self.keyboard_close_bindings.try(:clone)
@@ -415,6 +420,12 @@ module MotionPrime
415
420
  def after_initialize(*method_names, &block)
416
421
  set_callback :initialize, :after, *method_names, &block
417
422
  end
423
+ def after_element_render(element_name, method, options = {})
424
+ options.merge!(method: method)
425
+ self.elements_callbacks ||= {}
426
+ self.elements_callbacks[element_name] ||= []
427
+ self.elements_callbacks[element_name] << options
428
+ end
418
429
  def bind_keyboard_close(options)
419
430
  self.keyboard_close_bindings = options
420
431
  end
@@ -18,18 +18,18 @@ module MotionPrime
18
18
  # end
19
19
  #
20
20
 
21
- class_attribute :fields_options, :text_field_limits, :text_view_limits
21
+ class_attribute :fields_options, :text_field_limits, :text_view_limits, :fields_callbacks
22
22
  attr_accessor :fields, :field_indexes, :keyboard_visible, :rendered_views, :grouped_data
23
23
 
24
24
  def table_data
25
25
  if has_many_sections?
26
- grouped_data.compact
26
+ grouped_data.reject(&:nil?)
27
27
  else
28
28
  fields.values
29
29
  end
30
30
  end
31
31
 
32
- def reload_cell_section(section)
32
+ def hard_reload_cell_section(section)
33
33
  field = section.name.to_sym
34
34
  path = field_indexes[field]
35
35
  section.cell.try(:removeFromSuperview)
@@ -43,10 +43,7 @@ module MotionPrime
43
43
  end
44
44
 
45
45
  set_data_stamp(fields[field].object_id)
46
-
47
- # table_view.beginUpdates
48
46
  table_view.reloadRowsAtIndexPaths([path], withRowAnimation: UITableViewRowAnimationNone)
49
- # table_view.endUpdates
50
47
  end
51
48
 
52
49
  # Returns element based on field name and element name
@@ -173,7 +170,7 @@ module MotionPrime
173
170
  def reload_data
174
171
  @groups_count = nil
175
172
  init_form_fields # must be before resetting to reflect changes on @data
176
- reset_data
173
+ reset_table_data
177
174
  reload_table_data
178
175
  end
179
176
 
@@ -191,6 +188,13 @@ module MotionPrime
191
188
  if options && options[:after_render]
192
189
  self.send(options[:after_render])
193
190
  end
191
+
192
+ section = cell_section_by_index(index)
193
+ if callbacks = fields_callbacks.try(:[], section.name)
194
+ callbacks.each do |options|
195
+ options[:method].to_proc.call(options[:target] || self)
196
+ end
197
+ end
194
198
  super
195
199
  end
196
200
 
@@ -198,13 +202,14 @@ module MotionPrime
198
202
  # ---------------------
199
203
 
200
204
  def number_of_groups(table = nil)
201
- has_many_sections? ? grouped_data.compact.count : 1
205
+ has_many_sections? ? grouped_data.reject(&:nil?).count : 1
202
206
  end
203
207
 
204
208
  class << self
205
209
  def inherited(subclass)
206
210
  super
207
211
  subclass.fields_options = self.fields_options.try(:clone)
212
+ subclass.fields_callbacks = self.fields_callbacks.try(:clone)
208
213
  subclass.text_field_limits = self.text_field_limits.try(:clone)
209
214
  subclass.text_view_limits = self.text_view_limits.try(:clone)
210
215
  end
@@ -223,6 +228,13 @@ module MotionPrime
223
228
  self.fields_options[name]
224
229
  end
225
230
 
231
+ def after_field_render(field_name, method, options = {})
232
+ options.merge!(method: method)
233
+ self.fields_callbacks ||= {}
234
+ self.fields_callbacks[field_name] ||= []
235
+ self.fields_callbacks[field_name] << options
236
+ end
237
+
226
238
  def limit_text_field_length(name, limit)
227
239
  self.text_field_limits ||= {}
228
240
  self.text_field_limits[name] = limit
@@ -252,6 +264,9 @@ module MotionPrime
252
264
  section_indexes[section_id] ||= 0
253
265
 
254
266
  section = load_field(field)
267
+ if section.options[:after_render].present?
268
+ puts "DEPRECATION: form field's option :after_render is deprecated, please use Prime::Section#after_field_render instead"
269
+ end
255
270
  self.fields[key] = section
256
271
  self.field_indexes[key] = NSIndexPath.indexPathForRow(section_indexes[section_id], inSection: section_id)
257
272
  grouped_data[section_id][section_indexes[section_id]] = section
@@ -30,19 +30,6 @@ module MotionPrime
30
30
  end
31
31
  end
32
32
 
33
- # Changes height of the field (the cell in table) with animation.
34
- #
35
- # @param height [Integet] new height of field
36
- # @return [MotionPrime::BaseFieldSection]
37
- def update_height(height)
38
- return if container_options[:height] == height
39
- container_options[:height] = height
40
- index = form.field_indexes[name]
41
- form.send :set_data_stamp, self.object_id
42
- form.table_view.reloadRowsAtIndexPaths([index], withRowAnimation: UITableViewRowAnimationFade)
43
- self
44
- end
45
-
46
33
  def on_section_render
47
34
  @status_for_updated = :rendered
48
35
  form.register_elements_from_section(self)
@@ -171,14 +158,13 @@ module MotionPrime
171
158
 
172
159
  def reload_section
173
160
  clear_observers
174
- form.reload_cell_section(self)
161
+ form.hard_reload_cell_section(self)
175
162
  end
176
163
 
177
164
  def clear_observers
178
165
  return unless observing_errors?
179
166
  # unobserve_all cause double dealloc, following code is a replacement
180
167
  unobserve observing_errors_for.errors, :info
181
- # TODO: clear 'on' events
182
168
  end
183
169
 
184
170
  def container_height
@@ -8,7 +8,7 @@ module MotionPrime
8
8
  options[:input] || {}
9
9
  end
10
10
 
11
- after_render :bind_input
11
+ after_element_render :input, :bind_input
12
12
 
13
13
  def bind_input
14
14
  picker = view(:input)
@@ -7,7 +7,7 @@ module MotionPrime
7
7
  {secure_text_entry: true}.merge(options[:input] || {})
8
8
  end
9
9
  element :error_message, type: :error_message, text: proc { |field| field.all_errors.join("\n") if field.observing_errors? }
10
- after_render :bind_text_input
10
+ after_element_render :input, :bind_text_input
11
11
 
12
12
  def value
13
13
  view(:input).text