motion-prime 1.0.4 → 1.0.5

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/Gemfile.lock +2 -2
  4. data/ROADMAP.md +1 -0
  5. data/files/Gemfile +1 -1
  6. data/motion-prime/api_client.rb +3 -3
  7. data/motion-prime/elements/_content_text_mixin.rb +1 -0
  8. data/motion-prime/elements/_text_mixin.rb +5 -0
  9. data/motion-prime/elements/draw.rb +21 -6
  10. data/motion-prime/elements/draw/_draw_background_mixin.rb +68 -4
  11. data/motion-prime/elements/draw/image.rb +4 -6
  12. data/motion-prime/elements/draw/label.rb +20 -12
  13. data/motion-prime/elements/draw/view.rb +1 -0
  14. data/motion-prime/models/_association_mixin.rb +4 -3
  15. data/motion-prime/models/_sync_mixin.rb +2 -1
  16. data/motion-prime/models/association_collection.rb +2 -5
  17. data/motion-prime/screens/_navigation_mixin.rb +1 -1
  18. data/motion-prime/screens/controllers/tab_bar_controller.rb +4 -4
  19. data/motion-prime/screens/extensions/_navigation_bar_mixin.rb +15 -5
  20. data/motion-prime/sections/_async_table_mixin.rb +8 -2
  21. data/motion-prime/sections/_draw_section_mixin.rb +1 -1
  22. data/motion-prime/sections/_section_with_container_mixin.rb +1 -0
  23. data/motion-prime/sections/abstract_collection.rb +7 -0
  24. data/motion-prime/sections/base_section.rb +1 -1
  25. data/motion-prime/sections/form.rb +0 -8
  26. data/motion-prime/sections/form/base_field_section.rb +1 -1
  27. data/motion-prime/sections/form/form_delegate.rb +0 -32
  28. data/motion-prime/sections/table.rb +1 -1
  29. data/motion-prime/sections/table/table_delegate.rb +31 -0
  30. data/motion-prime/support/consts.rb +8 -1
  31. data/motion-prime/version.rb +1 -1
  32. data/motion-prime/views/_frame_calculator_mixin.rb +0 -1
  33. data/motion-prime/views/view_builder.rb +7 -5
  34. data/motion-prime/views/view_styler.rb +8 -5
  35. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c05d314976c62a856091891705c135ec7efcec22
4
- data.tar.gz: c36d99bc5fbd5c2220d0eac3677d87dbc0acf4b8
3
+ metadata.gz: 45140a3e0294c388e06a65d8984b3178d3a61860
4
+ data.tar.gz: bbdb962a185668be9c8788616fd562697b4dc80f
5
5
  SHA512:
6
- metadata.gz: 89864fab09b0b64a7c1ad1610300141c5ae60296a4a858e7abb83ceecf1277ebd3ff027886a061e1e022e1df551e9270b24f435a12f33d34973e7d4940d72e35
7
- data.tar.gz: 6c83f9726a57b620a1d2f93fd0e8e8b2089d3e71de9f5bea27acd279f98ad9a9f536bd247d1b4fd42822cc31341510d3ce82316eba8b49314ca8a71ee7dc5829
6
+ metadata.gz: 29e217defff9f85b314495158591cd4bb0215d58f86e3bee2e7660fd4e70e36668c035917f9589345425527d3f10edfd02d57255bfd7608937279b09203682cc
7
+ data.tar.gz: a459b509909885a8b77d71f94a4cb02cb12e91f56b9c9f91c24b1e1c863d9ba073b105258908fc6648da2487d8225638a98bc34b3bc479ec55f30a7c3f29b78d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ === 1.0.5
2
+ * Bug fixes
3
+
1
4
  === 1.0.4
2
5
  * Multiple bug fixes
3
6
  * Model#save will be performed on main thread (now you can fetch models in thread)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- motion-prime (1.0.4)
4
+ motion-prime (1.0.5)
5
5
  activesupport
6
6
  afmotion (~> 2.1.0)
7
7
  bubble-wrap (~> 1.6.0)
@@ -51,7 +51,7 @@ GEM
51
51
  fuzzy_match (2.0.4)
52
52
  i18n (0.6.9)
53
53
  json_pure (1.8.1)
54
- methadone (1.4.0)
54
+ methadone (1.5.1)
55
55
  bundler
56
56
  motion-cocoapods (1.4.1)
57
57
  cocoapods (>= 0.32.1)
data/ROADMAP.md CHANGED
@@ -15,6 +15,7 @@
15
15
  * create "display_network_error" extension.
16
16
  * add different templates. some templates should be more like final app.
17
17
  * add size_to_fit support for images.
18
+ * simplify border radius for common case
18
19
 
19
20
  === 1.2.0
20
21
  * Move api_client and model sync mixin to prime_model_sync gem.
data/files/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  gem 'motion-cocoapods', '~> 1.4.1'
4
- gem 'motion-prime', '1.0.4'
4
+ gem 'motion-prime', '1.0.5'
5
5
 
6
6
  # add reside menu for sidebar support
7
7
  # gem 'prime_reside_menu', '~> 0.1.4'
@@ -80,7 +80,7 @@ class ApiClient
80
80
  elsif progress
81
81
  # handle progress
82
82
  elsif !response.success? && allow_queue?(method, path, options)
83
- queue(method: method, path: path, params: params)
83
+ queue(method: method, path: path, params: data)
84
84
  elsif response.operation.response.nil?
85
85
  block.call if use_callback
86
86
  else
@@ -123,9 +123,9 @@ class ApiClient
123
123
  end
124
124
 
125
125
  def queue(item)
126
- queue_list = user_defaults['api_client_queue'].clone || []
126
+ queue_list = MotionPrime::JSON.parse(user_defaults['api_client_queue']) || []
127
127
  queue_list.push(item)
128
- user_defaults['api_client_queue'] = queue_list
128
+ user_defaults['api_client_queue'] = MotionPrime::JSON.generate(queue_list)
129
129
  end
130
130
 
131
131
  # TODO: temporary solution, add real caching system here
@@ -115,6 +115,7 @@ module MotionPrime
115
115
  normalize_object(font, section || self)
116
116
  end
117
117
 
118
+ # FIXME: does not work when #update_with_options is called
118
119
  def input_value_text
119
120
  view && !is_a?(DrawElement) ? view.text : (computed_options[:html] || computed_options[:text])
120
121
  end
@@ -33,6 +33,7 @@ module MotionPrime
33
33
  prepared_text = NSMutableAttributedString.alloc.initWithString(options[:text].to_s, attributes: attributes)
34
34
  underline_range = options[:underline]
35
35
  fragment_color = options[:fragment_color]
36
+ fragment_font = options[:fragment_font]
36
37
  if paragrah_style && (underline_range || fragment_color) && options.fetch(:number_of_lines, 1) == 1
37
38
  Prime.logger.debug "If attributed text has paragraph style and underline - you must set number of lines != 1"
38
39
  end
@@ -44,6 +45,10 @@ module MotionPrime
44
45
  if fragment_color
45
46
  prepared_text.addAttributes({NSForegroundColorAttributeName => fragment_color[:color].uicolor}, range: fragment_color[:range])
46
47
  end
48
+ if fragment_font
49
+ prepared_text.addAttributes({NSFontAttributeName => fragment_font[:font].uifont}, range: fragment_font[:range])
50
+ end
51
+
47
52
  prepared_text
48
53
  end
49
54
 
@@ -10,18 +10,32 @@ module MotionPrime
10
10
  def draw_options
11
11
  options = computed_options
12
12
  background_color = options[:background_color].try(:uicolor)
13
+ layer_options = options[:layer] || {}
14
+ corner_radius = layer_options[:corner_radius].to_f
15
+
16
+ layer_options.delete(:masks_to_bounds) if layer_options[:masks_to_bounds].nil?
17
+ options.delete(:clips_to_bounds) if options[:clips_to_bounds].nil?
18
+ masks_to_bounds = layer_options.fetch(:masks_to_bounds, options.fetch(:clips_to_bounds, corner_radius > 0))
13
19
  {
14
20
  rect: CGRectMake(frame_left, frame_top, frame_outer_width, frame_outer_height),
15
21
  background_color: background_color,
16
- masks_to_bounds: options[:layer].try(:[], :masks_to_bounds) || options[:clips_to_bounds],
17
- corner_radius: options[:layer].try(:[], :corner_radius).to_f,
18
- border_width: options[:layer].try(:[], :border_width).to_f,
19
- border_color: options[:layer].try(:[], :border_color).try(:uicolor) || background_color,
20
- border_sides: options[:layer].try(:[], :border_sides),
21
- dashes: options[:layer].try(:[], :dashes),
22
+ masks_to_bounds: masks_to_bounds,
23
+ corner_radius: corner_radius,
24
+ rounded_corners: layer_options[:rounded_corners],
25
+ border_width: layer_options[:border_width].to_f,
26
+ border_color: layer_options[:border_color].try(:uicolor) || background_color,
27
+ border_sides: layer_options[:border_sides],
28
+ dashes: layer_options[:dashes]
22
29
  }
23
30
  end
24
31
 
32
+ def draw_in(rect)
33
+ if @_prev_rect_size && @_prev_rect_size != rect.size
34
+ reset_computed_values
35
+ end
36
+ @_prev_rect_size = rect.size
37
+ end
38
+
25
39
  def render!; end
26
40
 
27
41
  def on_container_render
@@ -59,6 +73,7 @@ module MotionPrime
59
73
  end
60
74
 
61
75
  def rerender!(changed_options = [])
76
+ @_original_options = nil
62
77
  section.cached_draw_image = nil
63
78
  view.try(:setNeedsDisplay)
64
79
  end
@@ -3,7 +3,7 @@ module MotionPrime
3
3
  def draw_background_in_context(context = nil)
4
4
  context ||= UIGraphicsGetCurrentContext()
5
5
  options = draw_options
6
- rect, background_color, border_width, border_color, border_sides, corner_radius, dashes_array = options.slice(:rect, :background_color, :border_width, :border_color, :border_sides, :corner_radius, :dashes).values
6
+ rect, background_color, border_width, border_color, border_sides, corner_radius, dashes_array, rounded_corners = options.slice(:rect, :background_color, :border_width, :border_color, :border_sides, :corner_radius, :dashes, :rounded_corners).values
7
7
 
8
8
  return unless background_color || border_width > 0
9
9
 
@@ -15,7 +15,7 @@ module MotionPrime
15
15
  dashes_array.each_with_index { |length, i| dashes[i] = length }
16
16
  end
17
17
 
18
- if corner_radius > 0
18
+ if corner_radius > 0 && !rounded_corners
19
19
  bezier_path = UIBezierPath.bezierPathWithRoundedRect rect, cornerRadius: corner_radius
20
20
  UIGraphicsPushContext(context)
21
21
  bezier_path.setLineDash(dashes, count: dashes_array.count, phase: 0) if dashes
@@ -29,11 +29,24 @@ module MotionPrime
29
29
  bezier_path.fill
30
30
  end
31
31
  UIGraphicsPopContext()
32
+ elsif corner_radius > 0
33
+ CGContextSetLineDash(context, dashes_array.count, dashes, 0) if dashes
34
+ CGContextSetLineWidth(context, border_width) if border_width > 0
35
+ CGContextSetStrokeColorWithColor(context, border_color.uicolor.cgcolor) if border_color
36
+ draw_rect_in_context(context, rect: rect, radius: corner_radius, rounded_corners: rounded_corners)
37
+ CGContextSaveGState(context)
38
+ CGContextClip(context)
39
+ if background_color
40
+ CGContextSetFillColorWithColor(context, background_color.uicolor.cgcolor)
41
+ CGContextFillRect(context, rect)
42
+ end
43
+ CGContextRestoreGState(context)
32
44
  else
33
45
  if border_width > 0 && border_color
34
46
  CGContextSetLineDash(context, dashes_array.count, dashes, 0) if dashes
35
47
  CGContextSetLineWidth(context, border_width)
36
48
  CGContextSetStrokeColorWithColor(context, border_color.uicolor.cgcolor)
49
+
37
50
  if border_sides.present?
38
51
  points = [
39
52
  [rect.origin.x, rect.origin.y],
@@ -67,9 +80,60 @@ module MotionPrime
67
80
  CGContextStrokeRect(context, rect)
68
81
  end
69
82
  end
70
- CGContextSetFillColorWithColor(context, background_color.uicolor.cgcolor) if background_color
71
- CGContextFillRect(context, rect) if background_color
83
+
84
+ if background_color
85
+ CGContextSetFillColorWithColor(context, background_color.uicolor.cgcolor)
86
+ CGContextFillRect(context, rect)
87
+ end
72
88
  end
73
89
  end
90
+
91
+ def draw_rect_in_context(context, options)
92
+ rect = options.fetch(:rect)
93
+ radius = options.fetch(:radius, 0)
94
+ rounded_corners = options[:rounded_corners] || [:top_left, :top_right, :bottom_right, :bottom_left]
95
+
96
+ CGContextBeginPath(context)
97
+
98
+ x_left = rect.origin.x
99
+ x_left_center = x_left + radius
100
+ x_right_center = x_left + rect.size.width - radius
101
+ x_right = x_left + rect.size.width
102
+ y_top = rect.origin.y
103
+ y_top_center = y_top + radius
104
+ y_bottom_center = y_top + rect.size.height - radius
105
+ y_bottom = y_top + rect.size.height
106
+ CGContextMoveToPoint(context, x_left, y_top_center)
107
+
108
+ if rounded_corners.include?(:top_left)
109
+ CGContextAddArcToPoint(context, x_left, y_top, x_left_center, y_top, radius)
110
+ else
111
+ CGContextAddLineToPoint(context, x_left, y_top)
112
+ end
113
+ CGContextAddLineToPoint(context, x_right_center, y_top)
114
+
115
+ if rounded_corners.include?(:top_right)
116
+ CGContextAddArcToPoint(context, x_right, y_top, x_right, y_top_center, radius)
117
+ else
118
+ CGContextAddLineToPoint(context, x_right, y_top)
119
+ end
120
+ CGContextAddLineToPoint(context, x_right, y_bottom_center)
121
+
122
+ if rounded_corners.include?(:bottom_right)
123
+ CGContextAddArcToPoint(context, x_right, y_bottom, x_right_center, y_bottom, radius)
124
+ else
125
+ CGContextAddLineToPoint(context, x_right, y_bottom)
126
+ end
127
+ CGContextAddLineToPoint(context, x_left_center, y_bottom)
128
+
129
+ if rounded_corners.include?(:bottom_left)
130
+ CGContextAddArcToPoint(context, x_left, y_bottom, x_left, y_bottom_center, radius)
131
+ else
132
+ CGContextAddLineToPoint(context, x_left, y_bottom)
133
+ end
134
+ CGContextAddLineToPoint(context, x_left, y_top_center)
135
+
136
+ CGContextClosePath(context)
137
+ end
74
138
  end
75
139
  end
@@ -17,10 +17,11 @@ module MotionPrime
17
17
 
18
18
  def draw_in(rect)
19
19
  return if computed_options[:hidden]
20
- draw_background_in_context(UIGraphicsGetCurrentContext())
20
+ super
21
21
  if computed_options[:draw_in_rect]
22
22
  draw_in_context(UIGraphicsGetCurrentContext())
23
23
  else
24
+ draw_background_in_context(UIGraphicsGetCurrentContext())
24
25
  draw_with_layer
25
26
  end
26
27
  load_image
@@ -37,12 +38,9 @@ module MotionPrime
37
38
  inset = border_width > 0 ? (border_width - 1 ).abs*0.5 : 0
38
39
  rect = CGRectInset(options[:inner_rect], inset, inset)
39
40
  radius = options[:corner_radius].to_f if options[:corner_radius] && options[:masks_to_bounds]
40
-
41
41
  UIGraphicsPushContext(context)
42
42
  if radius
43
- CGContextBeginPath(context)
44
- CGContextAddArc(context, rect.origin.x + rect.size.width/2, rect.origin.y + rect.size.height/2, radius, 0, 2*Math::PI, 0) # FIXME
45
- CGContextClosePath(context)
43
+ draw_rect_in_context(context, rect: rect, radius: radius, rounded_corners: options[:rounded_corners])
46
44
  CGContextSaveGState(context)
47
45
  CGContextClip(context)
48
46
  image.drawInRect(rect)
@@ -58,6 +56,7 @@ module MotionPrime
58
56
  @layer.try(:removeFromSuperlayer)
59
57
  return unless image = options[:image]
60
58
  rect = options[:inner_rect]
59
+
61
60
  radius = options[:corner_radius].to_f if options[:corner_radius] && options[:masks_to_bounds]
62
61
 
63
62
  @layer = CALayer.layer
@@ -94,7 +93,6 @@ module MotionPrime
94
93
  end
95
94
 
96
95
  self.image_data = image
97
-
98
96
  section.cached_draw_image = nil
99
97
  if section.respond_to?(:cell_section_name)
100
98
  section.pending_display!
@@ -34,12 +34,15 @@ module MotionPrime
34
34
  line_spacing: options[:line_spacing],
35
35
  line_height: options[:line_height],
36
36
  underline: options[:underline],
37
+ fragment_color: options[:fragment_color],
38
+ fragment_font: options[:fragment_font],
37
39
  top_left_corner: top_left_corner,
38
40
  inner_rect: inner_rect
39
41
  })
40
42
  end
41
43
 
42
44
  def draw_in(rect)
45
+ super
43
46
  draw_in_context(UIGraphicsGetCurrentContext())
44
47
  end
45
48
 
@@ -54,8 +57,7 @@ module MotionPrime
54
57
 
55
58
  UIGraphicsPushContext(context)
56
59
  options = draw_options
57
- if options[:is_html] || options[:line_spacing] ||
58
- options[:line_height] || options[:underline] || options[:force_attributed]
60
+ if options.slice(:is_html, :line_spacing, :line_height, :underline, :force_attributed, :fragment_color, :fragment_font).any?
59
61
  prepared_text = options[:is_html] ? html_string(options) : attributed_string(options)
60
62
 
61
63
  CGContextSaveGState(context)
@@ -90,27 +92,33 @@ module MotionPrime
90
92
  end
91
93
 
92
94
  def size_to_fit_if_needed
93
- if computed_options[:size_to_fit]
94
- computed_options[:width] ||= cached_content_outer_width
95
- computed_options[:height] ||= cached_content_outer_height
95
+ if original_options[:size_to_fit]
96
+ computed_options[:width] = cached_content_outer_width unless original_options[:width]
97
+ computed_options[:height] = cached_content_outer_height unless original_options[:height]
96
98
  reset_computed_values
97
- elsif computed_options.slice(:width, :left, :right).values.none?
98
- computed_options[:width] ||= cached_content_outer_width
99
+ elsif !original_options[:width] && (!original_options[:left] || !original_options[:right])
100
+ computed_options[:width] = cached_content_outer_width unless original_options[:width]
99
101
  reset_computed_values
100
- elsif computed_options.slice(:height, :top, :bottom).values.none?
101
- computed_options[:height] ||= cached_content_outer_height
102
+ elsif original_options.slice(:height, :top, :bottom).values.none?
103
+ computed_options[:height] = cached_content_outer_height unless original_options[:height]
102
104
  reset_computed_values
103
105
  end
104
106
  end
105
107
 
106
108
  def set_text_position
107
- if computed_options.slice(:padding_top, :padding_bottom, :padding).values.none?
109
+ # FIXME: there is a bug when overriding this method for custom fonts (adjust @padding_top), you must set 'padding' to 0
110
+ if original_options.slice(:padding_top, :padding_bottom, :padding, :size_to_fit).values.none?
108
111
  computed_options[:width] ||= frame_width
112
+ frame_height = computed_options[:height] || frame_outer_height
109
113
  content_height = cached_content_height
110
- content_height = frame_outer_height if content_height > frame_outer_height
111
- @padding_top = (frame_outer_height - content_height)/2
114
+ content_height = frame_height if content_height > frame_height
115
+ @padding_top = (frame_height - content_height)/2
112
116
  # @padding_top += 1 unless @padding_top.zero?
113
117
  end
114
118
  end
119
+
120
+ def original_options
121
+ @_original_options ||= computed_options.clone
122
+ end
115
123
  end
116
124
  end
@@ -4,6 +4,7 @@ module MotionPrime
4
4
  include DrawBackgroundMixin
5
5
 
6
6
  def draw_in(rect)
7
+ super
7
8
  draw_in_context(UIGraphicsGetCurrentContext())
8
9
  end
9
10
 
@@ -89,7 +89,7 @@ module MotionPrime
89
89
  define_method("#{association_name}_attributes=") do |value|
90
90
  bags_attributes = self.send(association_name).try(:bags_attributes) || {}
91
91
  self.send(bag_name).clear
92
- association = association_name.classify.constantize.new
92
+ association = options.fetch(:class_name, association_name.classify).constantize.new
93
93
  association.info.merge!(bags_attributes)
94
94
  association.fetch_with_attributes(value)
95
95
  self.send(:"#{bag_name}") << association
@@ -120,7 +120,7 @@ module MotionPrime
120
120
 
121
121
  pending_save_counter = 0
122
122
  collection = value.inject({}) do |result, attrs|
123
- model = association_name.classify.constantize.new
123
+ model = options.fetch(:class_name, association_name.classify).constantize.new
124
124
  model.info.merge!(bags_attributes.fetch(attrs[:id], {}))
125
125
  model.fetch_with_attributes(attrs)
126
126
  unique_key = model.id || "pending_#{pending_save_counter+=1}"
@@ -138,6 +138,7 @@ module MotionPrime
138
138
  bag = self.send(:"#{bag_name}")
139
139
  collection_options = {
140
140
  association_name: association_name,
141
+ class_name: options.fetch(:class_name, association_name.classify),
141
142
  inverse_relation: {
142
143
  type: :has_one,
143
144
  name: self.class_name_without_kvo.demodulize.underscore,
@@ -152,7 +153,7 @@ module MotionPrime
152
153
  self._associations ||= {}
153
154
  self._associations[association_name] = {
154
155
  type: :belongs_to_one,
155
- class_name: association_name.classify
156
+ class_name: options.fetch(:class_name, association_name.classify)
156
157
  }.merge(options)
157
158
 
158
159
  self.send(:attr_accessor, association_name)
@@ -284,7 +284,8 @@ module MotionPrime
284
284
 
285
285
  track_changed_attributes do
286
286
  old_collection = self.send(key)
287
- model_class = key.classify.constantize
287
+ association_options = associations[key]
288
+ model_class = association_options.fetch(:class_name, key.classify).constantize
288
289
 
289
290
  data.each do |attributes|
290
291
  model = old_collection.detect{ |model| model.id == attributes[:id]}
@@ -2,12 +2,13 @@ module MotionPrime
2
2
  class AssociationCollection < ::Array
3
3
  include FilterMixin
4
4
 
5
- attr_reader :bag, :association_name
5
+ attr_reader :bag, :association_name, :model_class
6
6
  attr_reader :inverse_relation_name, :inverse_relation_key, :model_inverse_relation_name
7
7
 
8
8
  def initialize(bag, options, *args)
9
9
  @bag = bag
10
10
  @association_name = options[:association_name]
11
+ @model_class = options[:class_name].constantize
11
12
  bag.bare_class = model_class
12
13
 
13
14
  inverse_relation_options = options[:inverse_relation]
@@ -91,10 +92,6 @@ module MotionPrime
91
92
  data
92
93
  end
93
94
 
94
- def model_class
95
- @model_class ||= @association_name.classify.constantize
96
- end
97
-
98
95
  # Remove all association records.
99
96
  #
100
97
  # @example:
@@ -23,7 +23,7 @@ module MotionPrime
23
23
 
24
24
  # @return screen [Prime::Screen] screen appearing after close
25
25
  def close_screen(args = {})
26
- args[:animated] = args.has_key?(:animated) ? args[:animated] : true
26
+ args[:animated] = args.fetch(:animated, true)
27
27
  # Pop current view, maybe with arguments, if in navigation controller
28
28
  if modal?
29
29
  close_screen_modal(args)
@@ -53,11 +53,11 @@ module MotionPrime
53
53
  def self.extract_image_from_options(options, with_key: key)
54
54
  image = options.delete(key)
55
55
  return unless image
56
- image = image.uiimage
57
- if options[:translucent] === false
58
- image = image.imageWithRenderingMode UIImageRenderingModeAlwaysOriginal
56
+ ui_image = image.uiimage
57
+ if ui_image && options[:translucent] === false
58
+ ui_image = ui_image.imageWithRenderingMode UIImageRenderingModeAlwaysOriginal
59
59
  end
60
- image
60
+ ui_image
61
61
  end
62
62
  end
63
63
  end
@@ -16,6 +16,12 @@ module MotionPrime
16
16
  navigationItem.rightBarButtonItem = create_navigation_button(title, args, &block)
17
17
  end
18
18
 
19
+ def set_navigation_right_buttons(options)
20
+ navigationItem.rightBarButtonItems = options.map do |button_options|
21
+ create_navigation_button(button_options.delete(:title), button_options)
22
+ end
23
+ end
24
+
19
25
  def set_navigation_left_button(title, args = {}, &block)
20
26
  navigationItem.leftBarButtonItem = create_navigation_button(title, args, &block)
21
27
  end
@@ -65,9 +71,9 @@ module MotionPrime
65
71
  end
66
72
 
67
73
  def create_navigation_button_with_title(title, args)
68
- image = args[:icon].uiimage if args[:icon]
74
+ ui_image = args[:icon].uiimage if args[:icon]
69
75
  face = UIButton.buttonWithType UIButtonTypeCustom
70
- face.setImage(image, forState: UIControlStateNormal) if args[:icon]
76
+ face.setImage(ui_image, forState: UIControlStateNormal) if ui_image
71
77
  face.setTitle(title, forState: UIControlStateNormal)
72
78
  face.setTitleColor((args[:title_color] || :app_navigation_base).uicolor, forState: UIControlStateNormal)
73
79
  face.setContentHorizontalAlignment UIControlContentHorizontalAlignmentLeft
@@ -79,10 +85,14 @@ module MotionPrime
79
85
  end
80
86
 
81
87
  def create_navigation_button_with_image(title, args)
82
- image = args[:image].uiimage
83
88
  face = UIButton.buttonWithType UIButtonTypeCustom
84
- face.bounds = CGRectMake(0, 0, image.size.width, image.size.height)
85
- face.setImage image, forState: UIControlStateNormal
89
+ if ui_image = args[:image].uiimage
90
+ ui_image = ui_image.imageWithRenderingMode(2) if args[:tint_color].present?
91
+ face.bounds = CGRectMake(0, 0, ui_image.size.width, ui_image.size.height)
92
+ face.setImage ui_image, forState: UIControlStateNormal
93
+ end
94
+ face.setTintColor(args[:tint_color].uicolor) if args[:tint_color]
95
+ face.setImageEdgeInsets(UIEdgeInsetsMake(0, args[:offset_x], 0, -args[:offset_x])) if args[:offset_x]
86
96
  face.on :touch do
87
97
  args[:action].to_proc.call(args[:target] || self)
88
98
  end if args[:action]
@@ -55,10 +55,10 @@ module Prime
55
55
  #
56
56
  # @param from_index [NSIndexPath] Value of first index to load if current sheduled index not exists.
57
57
  # @return [NSIndexPath, Boolean] Index of next sheduled index.
58
- def preload_sections_after(from_index)
58
+ def preload_sections_after(from_index, load_limit = nil)
59
59
  return unless async_data?
60
60
  service = preloader_index_service
61
- load_limit = self.class.async_data_options.try(:[], :preload_cells_count)
61
+ load_limit ||= self.class.async_data_options.try(:[], :preload_cells_count)
62
62
 
63
63
  if @preloader_next_starts_from
64
64
  index_to_start_preloading = service.sum_index(@preloader_next_starts_from, load_limit ? -load_limit/2 : 0)
@@ -70,6 +70,7 @@ module Prime
70
70
  current_group = from_index.section
71
71
  left_to_load_in_group = cell_sections_for_group(current_group).count - from_index.row
72
72
  load_count = [left_to_load_in_group, load_limit].compact.min
73
+
73
74
  to_index = service.sum_index(from_index, load_count - 1)
74
75
  @preloader_next_starts_from = to_index
75
76
 
@@ -90,6 +91,11 @@ module Prime
90
91
 
91
92
  load_count = to_index.row - from_index.row + 1
92
93
  preload_sections_schedule_from(from_index, load_count) if load_count > 0
94
+
95
+ # quota_left = (load_limit || 0) - load_count
96
+ # if quota_left > 0 && cell_sections_for_group(current_group + 1).any?
97
+ # preload_sections_after(NSIndexPath.indexPathForRow(0, inSection: current_group + 1), quota_left)
98
+ # end
93
99
  end
94
100
 
95
101
  # Schedules preloading sections starting with given index with given limit.
@@ -86,7 +86,7 @@ module MotionPrime
86
86
 
87
87
  def on_container_tap_gesture(recognizer)
88
88
  target = Array.wrap(container_gesture_recognizers).detect do |gesture_data|
89
- point = recognizer.locationInView(container_view)
89
+ point = recognizer.locationInView(container_view.respond_to?(:content_view) ? container_view.content_view : container_view)
90
90
  element = gesture_data[:element]
91
91
  section = element.section
92
92
  if section.has_container_bounds?
@@ -26,6 +26,7 @@ module MotionPrime
26
26
 
27
27
  def load_container_with_elements(options = {})
28
28
  init_container_element(options[:container] || {})
29
+ # FIXME: does not work for grid sections
29
30
  @container_element.compute_options! unless @container_element.computed_options
30
31
  compute_element_options(options[:elements] || {})
31
32
 
@@ -245,6 +245,13 @@ module MotionPrime
245
245
  display_pending_cells unless @decelerating = will_decelerate
246
246
  end
247
247
 
248
+ def on_input_change(text_field); end
249
+ def on_input_edit_begin(text_field); end
250
+ def on_input_edit_end(text_field); end
251
+ def on_input_return(text_field)
252
+ text_field.resignFirstResponder
253
+ end
254
+
248
255
  private
249
256
  def cached_cell(index)
250
257
  end
@@ -54,7 +54,7 @@ module MotionPrime
54
54
  end
55
55
 
56
56
  def strong_references
57
- [screen, screen.main_controller]
57
+ [screen, screen.try(:main_controller)]
58
58
  end
59
59
 
60
60
  def container_bounds
@@ -140,14 +140,6 @@ module MotionPrime
140
140
  :base_form
141
141
  end
142
142
 
143
- # ALIASES
144
- def on_input_change(text_field); end
145
- def on_input_edit_begin(text_field); end
146
- def on_input_edit_end(text_field); end
147
- def on_input_return(text_field)
148
- text_field.resignFirstResponder
149
- end
150
-
151
143
  def allow_string_replacement?(target, limit, range, string)
152
144
  if string.length.zero? || (range.length + limit - target.text.length) >= string.length
153
145
  true
@@ -130,7 +130,7 @@ module MotionPrime
130
130
  end
131
131
 
132
132
  def observing_errors?
133
- @errors_observer_options.present?
133
+ @errors_observer_options.present? && observing_errors_for.present?
134
134
  end
135
135
 
136
136
  def has_errors?
@@ -1,19 +1,6 @@
1
1
  motion_require '../table/table_delegate'
2
2
  module MotionPrime
3
3
  class FormDelegate < TableDelegate
4
- def textFieldShouldReturn(text_field)
5
- table_section.on_input_return(text_field)
6
- end
7
- def textFieldShouldBeginEditing(text_field)
8
- text_field.respond_to?(:readonly) ? !text_field.readonly : true
9
- end
10
- def textFieldDidBeginEditing(text_field)
11
- table_section.on_input_edit_begin(text_field)
12
- end
13
- def textFieldDidEndEditing(text_field)
14
- table_section.on_input_edit_end(text_field)
15
- end
16
-
17
4
  def textField(text_field, shouldChangeCharactersInRange:range, replacementString:string)
18
5
  limit = (table_section.class.text_field_limits || {}).find do |field_name, limit|
19
6
  table_section.view("#{field_name}:input") == text_field
@@ -22,25 +9,6 @@ module MotionPrime
22
9
  table_section.allow_string_replacement?(text_field, limit, range, string)
23
10
  end
24
11
 
25
- def textViewDidBeginEditing(text_view)
26
- table_section.on_input_edit_begin(text_view)
27
- end
28
- def textViewDidEndEditing(text_view)
29
- table_section.on_input_edit_end(text_view)
30
- end
31
- def textViewDidChange(text_view) # bug in iOS 7 - cursor is out of textView bounds
32
- line = text_view.caretRectForPosition(text_view.selectedTextRange.start)
33
- overflow = line.origin.y + line.size.height -
34
- (text_view.contentOffset.y + text_view.bounds.size.height - text_view.contentInset.bottom - text_view.contentInset.top)
35
- if overflow > 0
36
- offset = text_view.contentOffset
37
- offset.y += overflow + text_view.textContainerInset.bottom
38
- UIView.animate(duration: 0.2) do
39
- text_view.setContentOffset(offset)
40
- end
41
- end
42
- end
43
-
44
12
  def textView(text_view, shouldChangeTextInRange:range, replacementText:string)
45
13
  textField(text_view, shouldChangeCharactersInRange:range, replacementString:string)
46
14
  end
@@ -57,7 +57,7 @@ module MotionPrime
57
57
  index = index_for_cell_section(section)
58
58
  next Prime.logger.debug("Reload section: `#{section.name}` is not in the list") unless index
59
59
  paths << index
60
- block.call(section, index, counter)
60
+ block.call(section, index, counter) if block_given?
61
61
  deque_cell(section, at: index) # deque cached
62
62
  section.reload
63
63
  end
@@ -75,5 +75,36 @@ module MotionPrime
75
75
  def scrollViewDidEndDragging(scroll, willDecelerate: will_decelerate)
76
76
  table_section.scroll_view_did_end_dragging(scroll, willDecelerate: will_decelerate)
77
77
  end
78
+
79
+ def textFieldShouldReturn(text_field)
80
+ table_section.on_input_return(text_field)
81
+ end
82
+ def textFieldShouldBeginEditing(text_field)
83
+ text_field.respond_to?(:readonly) ? !text_field.readonly : true
84
+ end
85
+ def textFieldDidBeginEditing(text_field)
86
+ table_section.on_input_edit_begin(text_field)
87
+ end
88
+ def textFieldDidEndEditing(text_field)
89
+ table_section.on_input_edit_end(text_field)
90
+ end
91
+ def textViewDidBeginEditing(text_view)
92
+ table_section.on_input_edit_begin(text_view)
93
+ end
94
+ def textViewDidEndEditing(text_view)
95
+ table_section.on_input_edit_end(text_view)
96
+ end
97
+ def textViewDidChange(text_view) # bug in iOS 7 - cursor is out of textView bounds
98
+ line = text_view.caretRectForPosition(text_view.selectedTextRange.start)
99
+ overflow = line.origin.y + line.size.height -
100
+ (text_view.contentOffset.y + text_view.bounds.size.height - text_view.contentInset.bottom - text_view.contentInset.top)
101
+ if overflow > 0
102
+ offset = text_view.contentOffset
103
+ offset.y += overflow + text_view.textContainerInset.bottom
104
+ UIView.animate(duration: 0.2) do
105
+ text_view.setContentOffset(offset)
106
+ end
107
+ end
108
+ end
78
109
  end
79
110
  end
@@ -11,6 +11,13 @@ UIControlContentVerticalAlignmentBottom
11
11
  UIControlContentVerticalAlignmentFill
12
12
 
13
13
  if defined?(ALAssetsLibrary)
14
+ ALAssetsLibrary
15
+ end
16
+
17
+ if defined?(ALAuthorizationStatusNotDetermined)
14
18
  ALAuthorizationStatusNotDetermined
19
+ end
20
+
21
+ if defined?(ALAssetsGroupAll)
15
22
  ALAssetsGroupAll
16
- end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module MotionPrime
2
- VERSION = "1.0.4"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -7,7 +7,6 @@ module MotionPrime
7
7
  right = options[:right]
8
8
  bottom = options[:bottom]
9
9
  left = options[:left]
10
-
11
10
  value_type = options[:value_type].to_s # absolute/relative
12
11
 
13
12
  if options[:height_to_fit].present? && height.nil? && (top.nil? || bottom.nil?)
@@ -67,12 +67,12 @@ module MotionPrime
67
67
  if image.nil?
68
68
  klass.alloc.initWithFrame CGRectZero
69
69
  else
70
- image = image.uiimage
71
- image = image.imageWithRenderingMode(2) if options[:tint_color].present?
70
+ ui_image = image.uiimage
71
+ ui_image = ui_image.imageWithRenderingMode(2) if options[:tint_color].present?
72
72
  if highlighted_image.nil?
73
- klass.alloc.initWithImage image.uiimage
73
+ klass.alloc.initWithImage ui_image
74
74
  else
75
- klass.alloc.initWithImage image.uiimage, highlightedImage: highlighted_image.uiimage
75
+ klass.alloc.initWithImage ui_image, highlightedImage: highlighted_image.uiimage
76
76
  end
77
77
  end
78
78
  },
@@ -109,7 +109,9 @@ module MotionPrime
109
109
  'UICollectionView' => Proc.new{|klass, options|
110
110
  unless layout = options.delete(:layout)
111
111
  layout = UICollectionViewFlowLayout.alloc.init
112
- total_width = options[:parent_bounds].size.width / (options.delete(:grid_size) || 3)
112
+
113
+ width = options[:width] || options[:parent_bounds].size.width
114
+ total_width = width / (options.delete(:grid_size) || 3)
113
115
  if horizontal_spacing = options.delete(:horizontal_spacing)
114
116
  layout.setMinimumInteritemSpacing horizontal_spacing
115
117
  end
@@ -135,11 +135,11 @@ module MotionPrime
135
135
  end
136
136
 
137
137
  def set_image_options(key, value)
138
- if key.end_with?('background_image')
138
+ if key.end_with?('background_image') && ui_image = value.uiimage
139
139
  if view.is_a?(UIControl) || view.is_a?(UISearchBar)
140
- view.send :"set#{camelize_factory(key)}:forState", value.uiimage, UIControlStateNormal
140
+ view.send :"set#{camelize_factory(key)}:forState", ui_image, UIControlStateNormal
141
141
  else
142
- view.setBackgroundColor value.uiimage.uicolor
142
+ view.setBackgroundColor ui_image.uicolor
143
143
  end
144
144
  true
145
145
  elsif key.end_with?('background_view')
@@ -152,7 +152,10 @@ module MotionPrime
152
152
  end
153
153
  true
154
154
  elsif key.end_with?('image')
155
- view.setValue value.uiimage, forKey: camelize_factory(key)
155
+ if ui_image = value.uiimage
156
+ ui_image = ui_image.imageWithRenderingMode(2) if options[:tint_color]
157
+ view.setValue ui_image, forKey: camelize_factory(key)
158
+ end
156
159
  true
157
160
  end
158
161
  end
@@ -189,7 +192,7 @@ module MotionPrime
189
192
  current_inset.send("#{key.partition('_').first}=", value)
190
193
  view.contentInset = current_inset
191
194
  true
192
- elsif key.end_with?('inset') || key.end_with?('indicator_insets')
195
+ elsif key.end_with?('inset') || key.end_with?('indicator_insets') || (key.end_with?('insets') && value.is_a?(Array))
193
196
  inset = if value.to_s == 'none'
194
197
  UIEdgeInsetsMake(0, 320, 0, 0)
195
198
  elsif value.is_a?(Array) && value.count == 2
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-prime
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iskander Haziev
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-06 00:00:00.000000000 Z
12
+ date: 2014-08-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake