motion-prime 0.3.1 → 0.3.2

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 (43) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +7 -3
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/ROADMAP.md +12 -0
  6. data/motion-prime/api_client.rb +1 -0
  7. data/motion-prime/app_delegate.rb +1 -1
  8. data/motion-prime/elements/_content_padding_mixin.rb +49 -0
  9. data/motion-prime/elements/_field_dimensions_mixin.rb +37 -21
  10. data/motion-prime/elements/_text_dimensions_mixin.rb +0 -4
  11. data/motion-prime/elements/base.rb +20 -7
  12. data/motion-prime/elements/button.rb +2 -1
  13. data/motion-prime/elements/draw/label.rb +19 -8
  14. data/motion-prime/elements/error_message.rb +2 -1
  15. data/motion-prime/elements/image.rb +1 -0
  16. data/motion-prime/elements/label.rb +10 -10
  17. data/motion-prime/elements/text_field.rb +2 -0
  18. data/motion-prime/models/bag.rb +8 -3
  19. data/motion-prime/models/model.rb +1 -1
  20. data/motion-prime/models/sync.rb +17 -8
  21. data/motion-prime/screens/_aliases_mixin.rb +2 -0
  22. data/motion-prime/screens/_base_mixin.rb +19 -52
  23. data/motion-prime/screens/_navigation_mixin.rb +31 -29
  24. data/motion-prime/screens/base_screen.rb +8 -0
  25. data/motion-prime/screens/extensions/_indicators_mixin.rb +26 -0
  26. data/motion-prime/screens/{_navigation_bar_mixin.rb → extensions/_navigation_bar_mixin.rb} +0 -0
  27. data/motion-prime/screens/sidebar_container_screen.rb +1 -1
  28. data/motion-prime/sections/base.rb +1 -1
  29. data/motion-prime/sections/form.rb +5 -2
  30. data/motion-prime/sections/form/base_field_section.rb +2 -2
  31. data/motion-prime/support/_key_value_store.rb +1 -1
  32. data/motion-prime/support/_padding_attribute.rb +60 -0
  33. data/motion-prime/support/dm_button.rb +20 -20
  34. data/motion-prime/support/dm_text_field.rb +12 -17
  35. data/motion-prime/support/dm_text_view.rb +1 -1
  36. data/motion-prime/support/mp_label.rb +9 -0
  37. data/motion-prime/version.rb +1 -1
  38. data/motion-prime/views/layout.rb +1 -0
  39. data/motion-prime/views/styles.rb +1 -1
  40. data/motion-prime/views/view_styler.rb +5 -1
  41. data/spec/helpers/models.rb +8 -1
  42. data/travis.sh +1 -3
  43. metadata +8 -3
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MDQ1ZmFmOTg1ZWQ4MTliMDI3ZmY4ZmE0NGM5OTA2YjJjZjk4NmIxYQ==
4
+ MjY2ZDk2NzU1ZmRhZTE4Zjc0OTk5ZmQzYmI3MzdhYmM5ZWM5M2VlOA==
5
5
  data.tar.gz: !binary |-
6
- ODQzMzg0NGZiYzgxMDM5MTMwZGEzNGM4ODcwOTg5ZGEzNWE1OTEwMA==
6
+ OGQxMTU0YWRhZTAzMGQ1YTc3NDdkYTU2NThlOTcwZTMwY2Y4NzJhOQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZjkyZGFmYTg3NzQ3ZDM0ZGRmOTg4MThiNTNlMDNjNGEwZDc3YTI5YmRhZGFi
10
- MGU5ZjQ2MTJiNmIzMzc0YWFmMTg0ZTBhNzY0NzQxMzU3OTFlZDVjNjRkNzA4
11
- YjVlM2EzNmU0MTkyOWYxM2I2MTg0N2VlYjg2NmE0NzY4NzA1NWQ=
9
+ NmQxZGEyNjg5OGVhNGU3OTA4ZWIwNmQ0YTMyMGVjYjZjYzEwYzE4NTlkNzZk
10
+ NjdmOTRmNWUyMjkyOGQ0NTY4MzM3NTgwZDljOGU3MTZhN2Y1NzA2ZWU4N2Nl
11
+ Zjg3Mzk2Zjk0YmQ2NDQ0OGYwOTQ3MjZhOTQ1OWIyNTQyNzNlMGE=
12
12
  data.tar.gz: !binary |-
13
- NzEwYTA3NjRkMTUxZGQ1NGQzMjk2MTQzMWFlYWM2NzkxZmZkNzkxN2E5NTAy
14
- OTg2MWY1ZmMzMzcwYzhmNzYyODIyZTFhNzczM2ZlZTY1OGQ0ZWUwM2E0MDcy
15
- ODA2ZTI2MmVkZGRiODljM2NjNmY2MzIzNzRmMTBlNjI1NTFhYjU=
13
+ ZGUxNDFjMTk3MmZkM2ZkMGY3ZDRkMjA5MThjNjA5YTJmN2U1MTE3ODBmZTc5
14
+ NDdlNjNkYzdiZWJiZWZiNGRjZDg4M2I4MjhlOWY0NjQ1ZTJhY2E5N2ZmZjRi
15
+ ODJkMTk0ZDc0ZDdhZTYzNjhjMjM1YmEyZDRmMTg4ZTkyZjFlMzg=
data/CHANGELOG.md CHANGED
@@ -1,10 +1,14 @@
1
- === 0.3.1.beta
1
+ === 0.3.2
2
+ * Refactor screens
3
+ * Fix paddings for draw sections
4
+ * Draw label now supports corner radius
5
+
6
+ === 0.3.1
2
7
  * Added universal AppDelegate#open_screen method for opening screens.
3
8
  * Old AppDelegate#open_screen method renamed to AppDelegate#open_content_screen
4
9
  * Ability to add inherited styles
5
- * Small refactoring
6
10
  * Update project template
7
-
11
+ * Small refactoring
8
12
 
9
13
  === 0.3.0
10
14
  * Added iOS 7 support
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- motion-prime (0.3.1)
4
+ motion-prime (0.3.2)
5
5
  bubble-wrap
6
6
  cocoapods
7
7
  methadone
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # MotionPrime [![Build Status](https://travis-ci.org/droidlabs/motion-prime.png)](https://travis-ci.org/droidlabs/motion-prime)
1
+ # MotionPrime [![Build Status](https://travis-ci.org/droidlabs/motion-prime.png)](https://travis-ci.org/droidlabs/motion-prime) [![Code Climate](https://codeclimate.com/github/droidlabs/motion-prime.png)](https://codeclimate.com/github/droidlabs/motion-prime) [![Roadchange](http://roadchange.com/droidlabs/motion-prime/badge.png)](http://roadchange.com/droidlabs/motion-prime)
2
2
 
3
3
  ![Prime](https://s3-us-west-2.amazonaws.com/webmate/assets/prime.jpg)
4
4
 
data/ROADMAP.md ADDED
@@ -0,0 +1,12 @@
1
+ === 0.4.0
2
+ * rename support/dm_* to support/mp_*
3
+ * "id" attribute should always be added to model by default
4
+ * add DSL for ViewStyles#setValue conditions
5
+ * add auto-symbol-value for Prime::Config.color items
6
+
7
+ === 0.5.0
8
+ * add testing framework
9
+ * add auth backends to ApiClient: password auth and facebook auth
10
+
11
+ === 0.6.0
12
+ * add sections/screens/models generator
@@ -52,6 +52,7 @@ class ApiClient
52
52
  end
53
53
 
54
54
  def resource_url(path)
55
+ # return if path.blank?
55
56
  "#{MotionPrime::Config.api.base}#{path}"
56
57
  end
57
58
 
@@ -32,7 +32,7 @@ module MotionPrime
32
32
  # TODO: move to private methods
33
33
  def open_root_screen(screen)
34
34
  screen.send(:on_screen_load) if screen.respond_to?(:on_screen_load)
35
- screen.ensure_wrapper_controller_in_place if screen.respond_to?(:ensure_wrapper_controller_in_place)
35
+ screen.wrap_in_navigation if screen.respond_to?(:wrap_in_navigation)
36
36
 
37
37
  screen = screen.main_controller if screen.respond_to?(:main_controller)
38
38
 
@@ -0,0 +1,49 @@
1
+ module MotionPrime
2
+ module ElementContentPaddingMixin
3
+ def content_padding_left
4
+ view.try(:padding_left) ||
5
+ computed_options[:padding_left] ||
6
+ computed_options[:padding] ||
7
+ view_class.constantize.default_padding_left || 0
8
+ end
9
+
10
+ def content_padding_right
11
+ view.try(:padding_right) ||
12
+ computed_options[:padding_right] ||
13
+ computed_options[:padding] ||
14
+ view_class.constantize.default_padding_right || 0
15
+ end
16
+
17
+ def content_padding_top
18
+ view.try(:padding_top) ||
19
+ computed_options[:padding_top] ||
20
+ computed_options[:padding] ||
21
+ view_class.constantize.default_padding_top || 0
22
+ end
23
+
24
+ def content_padding_bottom
25
+ view.try(:padding_bottom) ||
26
+ computed_options[:padding_bottom] ||
27
+ computed_options[:padding] ||
28
+ view_class.constantize.default_padding_bottom || 0
29
+ end
30
+
31
+ def content_padding_height
32
+ content_padding_top + content_padding_bottom
33
+ end
34
+
35
+ def content_padding_width
36
+ content_padding_left + content_padding_right
37
+ end
38
+
39
+ def content_outer_height
40
+ height = content_padding_height + content_height
41
+ [[height, computed_options[:min_outer_height]].compact.max, computed_options[:max_outer_height]].compact.min
42
+ end
43
+
44
+ def content_outer_width
45
+ width = content_padding_width + content_width
46
+ [[width, computed_options[:min_outer_width]].compact.max, computed_options[:max_outer_width]].compact.min
47
+ end
48
+ end
49
+ end
@@ -1,43 +1,59 @@
1
1
  module MotionPrime
2
2
  module ElementFieldDimensionsMixin
3
3
  def text_value
4
- text = view ? view.text : computed_options[:text].to_s
5
- text.empty? ? computed_options[:placeholder] : text
4
+ if button?
5
+ text = view ? view.titleLabel.text : computed_options[:title]
6
+ else
7
+ text = view ? view.text : computed_options[:text]
8
+ end.to_s
6
9
  end
7
10
 
8
- def font
9
- computed_options[:font] || :system.uifont
11
+ def content_text
12
+ text = text_value
13
+ if !button? && text.empty?
14
+ text = computed_options[:placeholder]
15
+ end
16
+ text.to_s
10
17
  end
11
18
 
12
- def computed_width
13
- min_width = computed_options[:min_width] || 20
14
- return min_width if text_value.to_s.empty?
19
+ def font
20
+ if button?
21
+ font = computed_options[:title_label][:font]
22
+ else
23
+ font = computed_options[:placeholder_font] if text_value.empty?
24
+ font ||= computed_options[:font]
25
+ end
26
+ font || :system.uifont
27
+ end
15
28
 
16
- padding_left = view.try(:padding_left) || computed_options[:padding_left] || computed_options[:padding] || view_class.constantize::DEFAULT_PADDING_LEFT
17
- padding_right = view.try(:padding_right) || computed_options[:padding_right] || padding_left
18
- max_width = computed_options[:max_width] || Float::MAX
29
+ def content_width
30
+ min_width = computed_options[:min_width].to_f
31
+ return min_width if content_text.empty?
19
32
 
20
- attributed_text = NSAttributedString.alloc.initWithString(text_value, attributes: {NSFontAttributeName => font })
33
+ attributed_text = NSAttributedString.alloc.initWithString(content_text, attributes: {NSFontAttributeName => font })
21
34
  rect = attributed_text.boundingRectWithSize([Float::MAX, Float::MAX], options:NSStringDrawingUsesLineFragmentOrigin, context:nil)
22
35
 
23
- width = (rect.size.width + padding_left + padding_right).ceil
24
- [[width, max_width].min, min_width].max
36
+ width = rect.size.width.ceil
37
+ [[width, computed_options[:max_width]].compact.min, min_width].max
25
38
  end
26
39
 
27
- def computed_height
28
- text = view ? view.titleLabel.text : computed_options[:title]
29
- return 0 if text.blank?
40
+ def content_height
41
+ min_height = computed_options[:min_height].to_f
42
+ return min_height if content_text.blank?
30
43
 
31
44
  width = computed_options[:width]
32
- font = computed_options[:title_label][:font] || :system.uifont
33
45
  raise "Please set element width for height calculation" unless width
34
46
 
35
47
  attributes = {NSFontAttributeName => font }
36
- attributed_text = NSAttributedString.alloc.initWithString(text, attributes: attributes)
48
+ attributed_text = NSAttributedString.alloc.initWithString(content_text, attributes: attributes)
37
49
  rect = attributed_text.boundingRectWithSize([width, Float::MAX], options:NSStringDrawingUsesLineFragmentOrigin, context:nil)
38
-
39
- padding_top = computed_options[:padding_top] || computed_options[:padding] || view.try(:default_padding_top)
40
- rect.size.height + padding_top*2
50
+ height = rect.size.height.ceil
51
+ [[height, computed_options[:max_height]].compact.min, min_height].max
41
52
  end
53
+
54
+ private
55
+ def button?
56
+ self.is_a?(ButtonElement)
57
+ end
42
58
  end
43
59
  end
@@ -31,9 +31,5 @@ module MotionPrime
31
31
 
32
32
  rect.size.width
33
33
  end
34
-
35
- def content_outer_height
36
- content_height + computed_inner_top + computed_inner_bottom
37
- end
38
34
  end
39
35
  end
@@ -16,11 +16,10 @@ module MotionPrime
16
16
 
17
17
  def initialize(options = {})
18
18
  @options = options
19
- @section = options.delete(:section)
20
-
19
+ @section = options[:section]
21
20
  @name = options[:name]
22
- @block = options.delete(:block)
23
- @view_class = options.delete(:view_class) || "UIView"
21
+ @block = options[:block]
22
+ @view_class = options[:view_class] || "UIView"
24
23
  @view_name = self.class_name_without_kvo.demodulize.underscore.gsub('_element', '')
25
24
  end
26
25
 
@@ -46,9 +45,9 @@ module MotionPrime
46
45
  @computed_options ||= {}
47
46
  block_options = compute_block_options || {}
48
47
  compute_style_options(options, block_options)
49
- @computed_options.merge!(options)
48
+ @computed_options.merge!(options.except(:section, :name, :block, :view_class))
50
49
  @computed_options.merge!(block_options)
51
- normalize_options(@computed_options, section, %w[text font title_label padding padding_left padding_right max_width width left right])
50
+ normalize_options(@computed_options, section, %w[text placeholder font title_label padding padding_left padding_right min_width min_outer_width max_width max_outer_width width left right])
52
51
  end
53
52
 
54
53
  # Compute options sent inside block, e.g.
@@ -96,7 +95,21 @@ module MotionPrime
96
95
  Styles.for(styles)
97
96
  end
98
97
 
99
- private
98
+ def update_with_options(new_options = {})
99
+ options.merge!(new_options)
100
+ compute_options!
101
+ view.try(:removeFromSuperview)
102
+ @view = nil
103
+ render(to: screen)
104
+ end
105
+
106
+ def hide
107
+ view.hidden = true
108
+ end
109
+
110
+ def show
111
+ view.hidden = false
112
+ end
100
113
 
101
114
  class << self
102
115
  def factory(type, options = {})
@@ -1,5 +1,6 @@
1
1
  module MotionPrime
2
2
  class ButtonElement < BaseElement
3
+ include MotionPrime::ElementContentPaddingMixin
3
4
  include MotionPrime::ElementFieldDimensionsMixin
4
5
 
5
6
  after_render :size_to_fit
@@ -7,7 +8,7 @@ module MotionPrime
7
8
  def size_to_fit
8
9
  if computed_options[:size_to_fit] || style_options[:size_to_fit]
9
10
  if computed_options[:width]
10
- view.setHeight computed_height
11
+ view.setHeight content_outer_height
11
12
  end
12
13
  end
13
14
  end
@@ -2,6 +2,7 @@ motion_require '../draw.rb'
2
2
  module MotionPrime
3
3
  class LabelDrawElement < DrawElement
4
4
  include MotionPrime::ElementTextDimensionsMixin
5
+ include MotionPrime::ElementContentPaddingMixin
5
6
 
6
7
  def draw_in(rect)
7
8
  options = computed_options
@@ -13,19 +14,29 @@ module MotionPrime
13
14
  bg_color = options[:background_color]
14
15
  if bg_color
15
16
  rect = CGRectMake(
16
- computed_left, computed_top, computed_outer_width, computed_outer_height
17
+ computed_left, computed_top, computed_width, computed_height
17
18
  )
18
- bg_color.uicolor.setFill
19
- UIRectFill(rect)
19
+
20
+ if computed_options[:layer] && radius = options[:layer][:corner_radius]
21
+ bezierPath = UIBezierPath.bezierPathWithRoundedRect rect, cornerRadius: radius
22
+ context = UIGraphicsGetCurrentContext()
23
+ CGContextSetStrokeColorWithColor(context, bg_color.uicolor.cgcolor)
24
+ CGContextSetFillColorWithColor(context, bg_color.uicolor.cgcolor)
25
+ bezierPath.stroke
26
+ bezierPath.fill
27
+ else
28
+ bg_color.uicolor.setFill
29
+ UIRectFill(rect)
30
+ end
20
31
  end
21
32
 
22
33
  # render text
23
- color = options[:text_color]
24
- color.uicolor.set if color
34
+ color = options[:text_color] || :black
35
+ color.uicolor.set
25
36
  font = options[:font] || :system
26
37
  if options[:number_of_lines] != 0
27
38
  options[:text].to_s.drawAtPoint(
28
- CGPointMake(computed_left, computed_top),
39
+ CGPointMake(computed_inner_left, computed_inner_top),
29
40
  withFont: font.uifont
30
41
  )
31
42
  else
@@ -45,9 +56,9 @@ module MotionPrime
45
56
 
46
57
  def size_to_fit_if_needed
47
58
  if computed_options[:size_to_fit]
48
- @computed_options[:width] = content_width
59
+ @computed_options[:width] = content_outer_width
49
60
  if computed_options[:width]
50
- @computed_options[:height] = content_height
61
+ @computed_options[:height] = content_outer_height
51
62
  end
52
63
  reset_computed_values
53
64
  end
@@ -1,10 +1,11 @@
1
1
  motion_require './label'
2
2
  module MotionPrime
3
3
  class ErrorMessageElement < LabelElement
4
+ include MotionPrime::ElementContentPaddingMixin
4
5
  include MotionPrime::ElementTextDimensionsMixin
5
6
 
6
7
  def view_class
7
- "UILabel"
8
+ "MPLabel"
8
9
  end
9
10
  end
10
11
  end
@@ -7,6 +7,7 @@ module MotionPrime
7
7
 
8
8
  def fetch_image
9
9
  return unless computed_options[:url]
10
+ raise "You must set default image for `#{name}`" unless computed_options[:default]
10
11
  view.setImageWithURL NSURL.URLWithString(computed_options[:url]),
11
12
  placeholderImage: computed_options[:default].uiimage
12
13
  end
@@ -1,32 +1,32 @@
1
1
  module MotionPrime
2
2
  class LabelElement < BaseElement
3
+ include MotionPrime::ElementContentPaddingMixin
3
4
  include MotionPrime::ElementTextDimensionsMixin
4
5
 
5
6
  before_render :size_to_fit_if_needed
6
7
  after_render :size_to_fit
7
8
 
9
+ def view_class
10
+ "MPLabel"
11
+ end
12
+
8
13
  def size_to_fit
9
14
  if computed_options[:size_to_fit] || style_options[:size_to_fit]
10
15
  if computed_options[:width]
11
- view.setHeight content_height + 2 # TODO maybe set width too as it can be wider
16
+ view.setHeight([content_outer_height, computed_options[:height]].compact.min)
12
17
  else
13
18
  view.sizeToFit
19
+ # we should re-set values, because sizeToFit do not use padding
20
+ view.setWidth(view.bounds.size.width + content_padding_width)
21
+ view.setHeight(view.bounds.size.height + content_padding_height)
14
22
  end
15
23
  end
16
24
  end
17
25
 
18
26
  def size_to_fit_if_needed
19
27
  if computed_options[:size_to_fit] && computed_options[:width]
20
- @computed_options[:height_to_fit] = content_height
28
+ @computed_options[:height_to_fit] = content_outer_height
21
29
  end
22
30
  end
23
-
24
- def computed_inner_top
25
- computed_options[:top].to_i
26
- end
27
-
28
- def computed_inner_bottom
29
- computed_options[:bottom].to_i
30
- end
31
31
  end
32
32
  end
@@ -1,6 +1,8 @@
1
1
  module MotionPrime
2
2
  class TextFieldElement < BaseElement
3
+ include MotionPrime::ElementContentPaddingMixin
3
4
  include MotionPrime::ElementFieldDimensionsMixin
5
+
4
6
  def view_class
5
7
  "DMTextField"
6
8
  end
@@ -32,10 +32,12 @@ module MotionPrime
32
32
  # @return self
33
33
  def add(object_or_array)
34
34
  error_ptr = Pointer.new(:id)
35
+ prepared = prepare_for_store(object_or_array)
36
+
35
37
  if object_or_array.is_a?(Array)
36
- self.addObjectsFromArray(prepare_for_store(object_or_array), error:error_ptr)
38
+ self.addObjectsFromArray(prepared, error:error_ptr)
37
39
  else
38
- self.addObject(prepare_for_store(object_or_array), error:error_ptr)
40
+ self.addObject(prepared, error:error_ptr)
39
41
  end
40
42
  raise StoreError, error_ptr[0].description if error_ptr[0]
41
43
  self
@@ -45,9 +47,12 @@ module MotionPrime
45
47
 
46
48
  def prepare_for_store(object)
47
49
  if object.is_a?(Array)
48
- object.map { |entity| prepare_for_store(entity) }
50
+ object.map { |entity| prepare_for_store(entity) }.compact
49
51
  else
50
52
  object.bag_key = self.key
53
+ if object.id.present? && self.store && self.find(id: object.id).any?
54
+ raise StoreError, "duplicated item added `#{object.class_name_without_kvo}` with `id` = #{object.id}"
55
+ end
51
56
  object
52
57
  end
53
58
  end