motion-prime 0.3.2 → 0.3.3

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 (59) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +3 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +10 -0
  5. data/doc/code/getting_started.rb +61 -0
  6. data/doc/docs/docco.css +500 -0
  7. data/doc/docs/getting_started.html +177 -0
  8. data/doc/docs/public/fonts/aller-bold.eot +0 -0
  9. data/doc/docs/public/fonts/aller-bold.ttf +0 -0
  10. data/doc/docs/public/fonts/aller-bold.woff +0 -0
  11. data/doc/docs/public/fonts/aller-light.eot +0 -0
  12. data/doc/docs/public/fonts/aller-light.ttf +0 -0
  13. data/doc/docs/public/fonts/aller-light.woff +0 -0
  14. data/doc/docs/public/fonts/novecento-bold.eot +0 -0
  15. data/doc/docs/public/fonts/novecento-bold.ttf +0 -0
  16. data/doc/docs/public/fonts/novecento-bold.woff +0 -0
  17. data/doc/docs/public/stylesheets/normalize.css +375 -0
  18. data/files/app/sections/sidebar/action.rb +1 -1
  19. data/motion-prime/app_delegate.rb +8 -2
  20. data/motion-prime/elements/_content_padding_mixin.rb +12 -12
  21. data/motion-prime/elements/_content_text_mixin.rb +65 -0
  22. data/motion-prime/elements/base.rb +51 -19
  23. data/motion-prime/elements/button.rb +1 -1
  24. data/motion-prime/elements/draw.rb +26 -113
  25. data/motion-prime/elements/draw/_draw_background_mixin.rb +26 -0
  26. data/motion-prime/elements/draw/image.rb +10 -1
  27. data/motion-prime/elements/draw/label.rb +61 -42
  28. data/motion-prime/elements/draw/view.rb +14 -0
  29. data/motion-prime/elements/error_message.rb +1 -1
  30. data/motion-prime/elements/label.rb +1 -1
  31. data/motion-prime/elements/text_field.rb +2 -2
  32. data/motion-prime/elements/text_view.rb +3 -0
  33. data/motion-prime/helpers/has_style_chain_builder.rb +1 -1
  34. data/motion-prime/helpers/has_styles.rb +28 -0
  35. data/motion-prime/models/bag.rb +1 -1
  36. data/motion-prime/models/sync.rb +4 -4
  37. data/motion-prime/screens/_base_mixin.rb +1 -1
  38. data/motion-prime/screens/extensions/_navigation_bar_mixin.rb +7 -0
  39. data/motion-prime/screens/sidebar_container_screen.rb +8 -2
  40. data/motion-prime/sections/_cell_section_mixin.rb +25 -0
  41. data/motion-prime/sections/base.rb +17 -16
  42. data/motion-prime/sections/draw.rb +32 -10
  43. data/motion-prime/sections/form.rb +27 -17
  44. data/motion-prime/sections/form/base_field_section.rb +0 -1
  45. data/motion-prime/sections/form/base_header_section.rb +3 -2
  46. data/motion-prime/sections/form/password_field_section.rb +1 -1
  47. data/motion-prime/sections/table.rb +31 -10
  48. data/motion-prime/sections/table/base_cell_section.rb +1 -22
  49. data/motion-prime/sections/table/draw_cell_section.rb +5 -0
  50. data/motion-prime/styles/form.rb +12 -4
  51. data/motion-prime/support/_key_value_store.rb +0 -2
  52. data/motion-prime/support/dm_text_field.rb +2 -2
  53. data/motion-prime/support/tab_bar_controller.rb +28 -0
  54. data/motion-prime/version.rb +1 -1
  55. data/motion-prime/views/_frame_calculator_mixin.rb +75 -0
  56. data/motion-prime/views/view_styler.rb +36 -94
  57. metadata +23 -4
  58. data/motion-prime/elements/_field_dimensions_mixin.rb +0 -59
  59. data/motion-prime/elements/_text_dimensions_mixin.rb +0 -35
@@ -1,4 +1,4 @@
1
- class SidebarActionSection < Prime::BaseSection
1
+ class SidebarActionSection < Prime::BaseCellSection
2
2
  container height: 43
3
3
  element :title, text: proc { model[:title] }
4
4
  element :arrow, type: :image
@@ -20,9 +20,10 @@ module MotionPrime
20
20
  end
21
21
 
22
22
  def open_screen(screen, options = {})
23
+ screen = create_tab_bar(screen) if screen.is_a?(Array)
23
24
  if options[:sidebar]
24
25
  open_with_sidebar(screen, options.delete(:sidebar), options)
25
- elsif options[:root]
26
+ elsif options[:root] || !self.window
26
27
  open_root_screen(screen)
27
28
  else
28
29
  open_content_screen(screen)
@@ -59,7 +60,7 @@ module MotionPrime
59
60
  end
60
61
 
61
62
  def sidebar?
62
- self.window.rootViewController.is_a?(SidebarContainerScreen)
63
+ self.window && self.window.rootViewController.is_a?(SidebarContainerScreen)
63
64
  end
64
65
 
65
66
  def show_sidebar
@@ -81,5 +82,10 @@ module MotionPrime
81
82
  @current_user = nil
82
83
  NSNotificationCenter.defaultCenter.postNotificationName(:on_current_user_reset, object: user_was)
83
84
  end
85
+
86
+ private
87
+ def create_tab_bar(screens)
88
+ MotionPrime::TabBarController.new(screens)
89
+ end
84
90
  end
85
91
  end
@@ -1,31 +1,27 @@
1
1
  module MotionPrime
2
2
  module ElementContentPaddingMixin
3
3
  def content_padding_left
4
- view.try(:padding_left) ||
5
- computed_options[:padding_left] ||
4
+ computed_options[:padding_left] ||
6
5
  computed_options[:padding] ||
7
- view_class.constantize.default_padding_left || 0
6
+ default_padding_for(:left) || 0
8
7
  end
9
8
 
10
9
  def content_padding_right
11
- view.try(:padding_right) ||
12
- computed_options[:padding_right] ||
10
+ computed_options[:padding_right] ||
13
11
  computed_options[:padding] ||
14
- view_class.constantize.default_padding_right || 0
12
+ default_padding_for(:right) || 0
15
13
  end
16
14
 
17
15
  def content_padding_top
18
- view.try(:padding_top) ||
19
- computed_options[:padding_top] ||
16
+ computed_options[:padding_top] ||
20
17
  computed_options[:padding] ||
21
- view_class.constantize.default_padding_top || 0
18
+ default_padding_for(:top) || 0
22
19
  end
23
20
 
24
21
  def content_padding_bottom
25
- view.try(:padding_bottom) ||
26
- computed_options[:padding_bottom] ||
22
+ computed_options[:padding_bottom] ||
27
23
  computed_options[:padding] ||
28
- view_class.constantize.default_padding_bottom || 0
24
+ default_padding_for(:bottom) || 0
29
25
  end
30
26
 
31
27
  def content_padding_height
@@ -45,5 +41,9 @@ module MotionPrime
45
41
  width = content_padding_width + content_width
46
42
  [[width, computed_options[:min_outer_width]].compact.max, computed_options[:max_outer_width]].compact.min
47
43
  end
44
+
45
+ def default_padding_for(side)
46
+ view_class.constantize.send(:"default_padding_#{side}")
47
+ end
48
48
  end
49
49
  end
@@ -0,0 +1,65 @@
1
+ module MotionPrime
2
+ module ElementContentTextMixin
3
+ def content_text
4
+ (is_a?(ButtonElement) ? button_content_text : input_content_text).to_s
5
+ end
6
+
7
+ def content_font
8
+ (is_a?(ButtonElement) ? button_content_font : input_content_font) || :system.uifont
9
+ end
10
+
11
+ def content_width
12
+ min, max = computed_options[:min_width].to_f, computed_options[:max_width]
13
+ return min if content_text.blank?
14
+
15
+ rect = get_content_rect(Float::MAX)
16
+ [[rect.size.width.ceil, max].compact.min, min].max.ceil
17
+ end
18
+
19
+ def content_height
20
+ min, max = computed_options[:min_height].to_f, computed_options[:max_height]
21
+ return min if content_text.blank?
22
+ rect = get_content_rect(computed_options[:width])
23
+ [[rect.size.height.ceil, max].compact.min, min].max.ceil
24
+ end
25
+
26
+ private
27
+ def get_content_rect(width)
28
+ raise "Please set element width for content size calculation" unless width
29
+ attributes = {NSFontAttributeName => content_font }
30
+ if computed_options[:line_spacing]
31
+ paragrahStyle = NSMutableParagraphStyle.alloc.init
32
+ paragrahStyle.setLineSpacing(computed_options[:line_spacing])
33
+ attributes[NSParagraphStyleAttributeName] = paragrahStyle
34
+ end
35
+ attributed_text = NSAttributedString.alloc.initWithString(content_text, attributes: attributes)
36
+ attributed_text.boundingRectWithSize(
37
+ [width, Float::MAX], options:NSStringDrawingUsesLineFragmentOrigin, context:nil
38
+ )
39
+ end
40
+
41
+ def button_content_text
42
+ view ? view.titleLabel.text : computed_options[:title]
43
+ end
44
+
45
+ def button_content_font
46
+ computed_options[:title_label][:font]
47
+ end
48
+
49
+ def input_content_text
50
+ input_value_text.blank? ? input_placeholder_text : input_value_text
51
+ end
52
+
53
+ def input_content_font
54
+ input_value_text.blank? ? computed_options[:placeholder_font] : computed_options[:font]
55
+ end
56
+
57
+ def input_value_text
58
+ view && !is_a?(DrawElement) ? view.text : computed_options[:text]
59
+ end
60
+
61
+ def input_placeholder_text
62
+ computed_options[:placeholder]
63
+ end
64
+ end
65
+ end
@@ -59,30 +59,62 @@ module MotionPrime
59
59
  end
60
60
 
61
61
  def compute_style_options(*style_sources)
62
- @styles = []
63
- base_styles = {common: [], specific: []}
64
- suffixes = {common: [@view_name.to_sym, name.try(:to_sym)].compact, specific: []}
62
+ has_errors = section.respond_to?(:observing_errors?) && observing_errors? && has_errors?
63
+ is_cell_section = section.is_a?(BaseCellSection) || section.is_a?(DrawCellSection)
65
64
 
66
- if section
67
- cell_section = section.is_a?(BaseCellSection)
68
- if cell_section
69
- section.section_styles.each { |type, values| base_styles[type] += values }
65
+ @styles = []
66
+ if is_cell_section
67
+ base_styles = {common: [], specific: []}
68
+ suffixes = {common: [], specific: []}
69
+
70
+ # following example in Prime::TableSection#cell_styles
71
+ # form element/cell: <base|user>_form_field, <base|user>_form_string_field, user_form_field_email
72
+ # table element/cell: <base|categories>_table_cell, categories_table_title
73
+ section.section_styles.each { |type, values| base_styles[type] += values }
74
+ if %w[base table_view_cell].exclude?(@view_name.to_s)
75
+ # form element: _input
76
+ # table element: _image
77
+ suffixes[:common] << @view_name.to_sym
78
+ suffixes[:common] << :"#{@view_name}_with_errors" if has_errors
79
+ end
80
+ if name && name.to_s != @view_name.to_s
81
+ # form element: _input
82
+ # table element: _icon
83
+ suffixes[:specific] << name.to_sym
84
+ suffixes[:specific] << :"#{name}_with_errors" if has_errors
70
85
  end
71
- if section.respond_to?(:observing_errors?) && observing_errors? && has_errors?
72
- suffixes[:common] += [:"#{name}_with_errors", :"#{@view_name}_with_errors"]
86
+ # form cell: base_form_field, base_form_string_field
87
+ # form element: base_form_field_string_field, base_form_string_field_text_field
88
+ # table cell: base_table_cell
89
+ # table element: base_table_cell_image
90
+ common_styles = if suffixes[:common].any?
91
+ build_styles_chain(base_styles[:common], suffixes[:common])
92
+ elsif suffixes[:specific].any?
93
+ build_styles_chain(base_styles[:common], suffixes[:specific])
94
+ elsif @view_name.to_s == 'table_view_cell'
95
+ base_styles[:common]
73
96
  end
97
+ @styles += Array.wrap(common_styles)
98
+
99
+ # form cell: user_form_field, user_form_string_field, user_form_field_email
100
+ # form element: user_form_field_text_field, user_form_string_field_text_field, user_form_field_email_text_field
101
+ # table cell: categories_table_cell, categories_table_title
102
+ # table element: categories_table_cell_image, categories_table_title_image
103
+ specific_base_common_suffix_styles = if suffixes[:common].any?
104
+ build_styles_chain(base_styles[:specific], suffixes[:common])
105
+ elsif suffixes[:specific].empty? && @view_name.to_s == 'table_view_cell'
106
+ base_styles[:specific]
107
+ end
108
+ @styles += Array.wrap(specific_base_common_suffix_styles)
109
+ # form element: user_form_field_input, user_form_string_field_input, user_form_field_email_input
110
+ # table element: categories_table_cell_icon, categories_table_title_icon
111
+ @styles += build_styles_chain(base_styles[:specific], suffixes[:specific])
74
112
  end
75
-
76
- # common + specific base - common suffixes
77
- @styles += build_styles_chain(base_styles[:common], suffixes[:common])
78
- @styles << [section.name, name].compact.join('_').to_sym if section
79
- @styles += build_styles_chain(base_styles[:specific], suffixes[:common])
80
- # specific base - specific suffixes
81
- @styles += build_styles_chain(base_styles[:specific], suffixes[:specific])
82
- if cell_section && section.table.present?
83
- @styles << [section.table.name, section.cell_type, section.name, name].compact.join('_').to_sym
113
+ if section
114
+ # using for base sections
115
+ @styles << [section.name, name].compact.join('_').to_sym
84
116
  end
85
- # custom style (from options or block options)
117
+ # custom style (from options or block options), using for TableViews as well
86
118
  custom_styles = style_sources.map do |source|
87
119
  normalize_object(source.delete(:styles), section)
88
120
  end.compact.flatten
@@ -1,7 +1,7 @@
1
1
  module MotionPrime
2
2
  class ButtonElement < BaseElement
3
3
  include MotionPrime::ElementContentPaddingMixin
4
- include MotionPrime::ElementFieldDimensionsMixin
4
+ include MotionPrime::ElementContentTextMixin
5
5
 
6
6
  after_render :size_to_fit
7
7
 
@@ -1,142 +1,55 @@
1
+ motion_require '../views/_frame_calculator_mixin'
1
2
  module MotionPrime
2
3
  class DrawElement < BaseElement
3
4
  # MotionPrime::DrawElement is container for drawRect method options.
4
5
  # Elements are located inside Sections
5
6
 
6
- def render!
7
- end
7
+ include FrameCalculatorMixin
8
+ include ElementContentPaddingMixin
9
+
10
+ def render!; end
8
11
 
9
12
  def view
10
13
  @view ||= section.container_view
11
14
  end
12
15
 
13
- def computed_max_width
14
- view.bounds.size.width
15
- end
16
-
17
- def computed_max_height
18
- view.bounds.size.height
19
- end
20
-
21
- def computed_padding_left
22
- computed_options[:padding_left] ||
23
- computed_options[:padding] || 0
24
- end
25
-
26
- def computed_padding_right
27
- computed_options[:padding_right] ||
28
- computed_options[:padding] || 0
29
- end
30
-
31
- def computed_padding_top
32
- computed_options[:padding_top] ||
33
- computed_options[:padding] || 0
34
- end
35
-
36
- def computed_padding_bottom
37
- computed_options[:padding_bottom] ||
38
- computed_options[:padding] || 0
39
- end
40
-
41
- def computed_width
42
- @computed_width ||= begin
43
- width = computed_options[:width]
44
- width = 0.0 if width.nil?
45
-
46
- # calculate width if width is relative, e.g 0.7
47
- if width > 0 && width <= 1
48
- width * computed_max_width
49
- else
50
- width > computed_max_width ? computed_max_width : width
51
- end
52
- end
53
- end
54
-
55
- # content width + content padding
56
- def computed_outer_width
57
- @computed_outer_width ||= begin
58
- computed_width + computed_padding_left + computed_padding_right
59
- end
60
- end
61
-
62
- def computed_height
63
- @computed_height ||= begin
64
- height = computed_options[:height]
65
- height = 0.0 if height.nil?
66
-
67
- # calculate height if height is relative, e.g 0.7
68
- if height > 0 && height <= 1
69
- height * computed_max_height
70
- else
71
- height > computed_max_height ? computed_max_height : height
72
- end
73
- end
16
+ def computed_frame
17
+ @computed_frame ||= calculate_frome_for(view.bounds, computed_options)
74
18
  end
75
19
 
76
- # content height + content padding
77
- def computed_outer_height
78
- @computed_outer_height ||= begin
79
- computed_height + computed_padding_top + computed_padding_bottom
80
- end
20
+ def default_padding_for(side)
21
+ 0
81
22
  end
82
23
 
83
- def computed_left
84
- @computed_left ||= begin
85
- left = computed_options[:left]
86
- right = computed_options[:right]
87
- return left if left
88
- return 0 if right.nil?
89
-
90
- computed_max_width - (computed_width + right)
91
- end
24
+ def computed_max_width
25
+ view.bounds.size.width
92
26
  end
93
27
 
94
- # content left + content padding
95
- def computed_inner_left
96
- @computed_inner_left ||= begin
97
- computed_left + computed_padding_left
98
- end
28
+ def computed_max_height
29
+ view.bounds.size.height
99
30
  end
100
31
 
101
- def computed_top
102
- @computed_top ||= begin
103
- top = computed_options[:top]
104
- bottom = computed_options[:bottom]
105
- return top if top
106
- return 0 if bottom.nil?
32
+ def computed_outer_width; computed_frame.size.width end
33
+ def computed_width; computed_outer_width - content_padding_width end
107
34
 
108
- computed_max_height - (computed_height + bottom)
109
- end
110
- end
35
+ def computed_outer_height; computed_frame.size.height end
36
+ def computed_height; computed_outer_height - content_padding_height end
111
37
 
112
- # content top + content padding
113
- def computed_inner_top
114
- @computed_inner_top ||= begin
115
- computed_top + computed_padding_top
116
- end
117
- end
38
+ def computed_top; computed_frame.origin.y end
39
+ def computed_inner_top; computed_top + content_padding_top end
118
40
 
119
- def computed_bottom
120
- computed_options[:bottom] || 0
121
- end
41
+ def computed_left; computed_frame.origin.x end
42
+ def computed_inner_left; computed_left + content_padding_left end
122
43
 
123
- def computed_inner_bottom
124
- computed_bottom + computed_padding_bottom
125
- end
44
+ def computed_bottom; computed_top + computed_outer_height end
45
+ def computed_inner_bottom; computed_bottom - content_padding_bottom end
126
46
 
127
- def computed_right
128
- computed_options[:right] || 0
129
- end
47
+ def computed_right; computed_left + computed_width end
48
+ def computed_inner_right; computed_right - content_padding_right end
130
49
 
131
- def computed_inner_right
132
- computed_right + computed_padding_right
133
- end
134
50
 
135
51
  def reset_computed_values
136
- [:left, :top, :right, :bottom, :width, :height].each do |key|
137
- instance_variable_set "@computed_#{key}", nil
138
- instance_variable_set "@computed_inner_#{key}", nil
139
- end
52
+ @computed_frame = nil
140
53
  end
141
54
 
142
55
  class << self
@@ -0,0 +1,26 @@
1
+ module MotionPrime
2
+ module DrawBackgroundMixin
3
+ def draw_background_in(rect, options)
4
+ bg_color = options[:background_color]
5
+ border_radius = options[:layer].try(:[], :corner_radius)
6
+ border_width = options[:layer].try(:[], :border_width).to_f
7
+ border_color = options[:layer].try(:[], :border_color) || bg_color || :black
8
+
9
+ if bg_color || border_width > 0
10
+ context = UIGraphicsGetCurrentContext()
11
+ CGContextSetFillColorWithColor(context, bg_color.uicolor.cgcolor) if bg_color
12
+ CGContextSetLineWidth(context, border_width) if border_width > 0
13
+ CGContextSetStrokeColorWithColor(context, border_color.uicolor.cgcolor) if border_color
14
+
15
+ if border_radius
16
+ bezierPath = UIBezierPath.bezierPathWithRoundedRect rect, cornerRadius: border_radius
17
+ bezierPath.stroke if border_width > 0
18
+ bezierPath.fill if bg_color
19
+ else
20
+ CGContextStrokeRect(context, rect) if border_width > 0
21
+ CGContextFillRect(context, rect) if bg_color
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,15 +1,24 @@
1
1
  motion_require '../draw.rb'
2
2
  module MotionPrime
3
3
  class ImageDrawElement < DrawElement
4
+ include DrawBackgroundMixin
4
5
  attr_accessor :image_data
6
+
5
7
  def draw_in(rect)
6
8
  return if computed_options[:hidden]
9
+ options = computed_options
7
10
  image_rect = CGRectMake(
8
11
  computed_left,
9
12
  computed_top,
10
13
  computed_width,
11
14
  computed_height
12
15
  )
16
+
17
+ image_rect = CGRectInset(image_rect, -0.5, -0.5)
18
+ border_width = options[:layer].try(:[], :border_width).to_f
19
+ background_rect = CGRectInset(image_rect, -(border_width - 1)*0.5, -(border_width - 1)*0.5)
20
+ draw_background_in(background_rect, options)
21
+
13
22
  # draw already initialized image
14
23
  if image_data
15
24
  draw_with_layer(image_data, image_rect)
@@ -48,8 +57,8 @@ module MotionPrime
48
57
  layer.frame = CGRectMake(0, 0, image.size.width, image.size.height)
49
58
  layer.contents = image.CGImage
50
59
 
60
+ layer.masksToBounds = computed_options[:layer][:masks_to_bounds] || computed_options[:clips_to_bounds]
51
61
  if radius = computed_options[:layer][:corner_radius]
52
- layer.masksToBounds = true
53
62
  k = image.size.width / rect.size.width
54
63
  radius = radius * k
55
64
  layer.cornerRadius = radius