motion-prime 0.9.9 → 0.9.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +8 -2
  3. data/Gemfile.lock +2 -2
  4. data/ROADMAP.md +1 -3
  5. data/files/Gemfile +1 -1
  6. data/generators/templates/scaffold/table.rb +1 -1
  7. data/generators/templates/table.rb +1 -1
  8. data/motion-prime/config/base.rb +2 -2
  9. data/motion-prime/elements/_content_text_mixin.rb +1 -1
  10. data/motion-prime/elements/base_element.rb +14 -7
  11. data/motion-prime/elements/collection_view_cell.rb +7 -0
  12. data/motion-prime/elements/draw/image.rb +7 -2
  13. data/motion-prime/elements/table_view_cell.rb +1 -1
  14. data/motion-prime/helpers/has_normalizer.rb +1 -1
  15. data/motion-prime/helpers/has_search_bar.rb +1 -1
  16. data/motion-prime/models/_nano_bag_mixin.rb +1 -1
  17. data/motion-prime/models/model.rb +8 -8
  18. data/motion-prime/models/store.rb +1 -1
  19. data/motion-prime/screens/screen.rb +3 -3
  20. data/motion-prime/sections/_async_form_mixin.rb +2 -2
  21. data/motion-prime/sections/_async_table_mixin.rb +7 -7
  22. data/motion-prime/sections/_cell_section_mixin.rb +16 -11
  23. data/motion-prime/sections/_draw_section_mixin.rb +1 -0
  24. data/motion-prime/sections/{__section_with_container_mixin.rb → _section_with_container_mixin.rb} +2 -2
  25. data/motion-prime/sections/abstract_collection.rb +291 -0
  26. data/motion-prime/sections/base_section.rb +2 -2
  27. data/motion-prime/sections/collection/collection_delegate.rb +62 -0
  28. data/motion-prime/sections/form.rb +22 -18
  29. data/motion-prime/sections/form/base_field_section.rb +7 -7
  30. data/motion-prime/sections/form/form_delegate.rb +1 -1
  31. data/motion-prime/sections/form/form_header_section.rb +1 -1
  32. data/motion-prime/sections/form/password_field_section.rb +1 -1
  33. data/motion-prime/sections/form/static_field_section.rb +1 -1
  34. data/motion-prime/sections/form/string_field_section.rb +1 -1
  35. data/motion-prime/sections/form/text_field_section.rb +1 -1
  36. data/motion-prime/sections/grid.rb +92 -0
  37. data/motion-prime/sections/table.rb +26 -260
  38. data/motion-prime/sections/table/refresh_mixin.rb +3 -3
  39. data/motion-prime/sections/table/table_delegate.rb +1 -0
  40. data/motion-prime/styles/_mixins.rb +1 -1
  41. data/motion-prime/styles/base.rb +20 -6
  42. data/motion-prime/styles/form.rb +1 -1
  43. data/motion-prime/support/_control_content_alignment.rb +39 -0
  44. data/motion-prime/support/mp_button.rb +5 -13
  45. data/motion-prime/support/mp_collection_cell_with_section.rb +12 -0
  46. data/motion-prime/support/{mp_cell_content_view.rb → mp_table_cell_content_view.rb} +0 -0
  47. data/motion-prime/support/{mp_cell_with_section.rb → mp_table_cell_with_section.rb} +1 -1
  48. data/motion-prime/support/mp_text_field.rb +24 -18
  49. data/motion-prime/support/mp_text_view.rb +1 -0
  50. data/motion-prime/version.rb +1 -1
  51. data/motion-prime/views/_frame_calculator_mixin.rb +15 -11
  52. data/motion-prime/views/layout.rb +6 -4
  53. data/motion-prime/views/view_builder.rb +10 -0
  54. data/motion-prime/views/view_styler.rb +5 -1
  55. data/spec/factories/scaffold/sections/tasks/index_table.rb +1 -1
  56. data/spec/unit/support/filter_mixin_spec.rb +7 -3
  57. data/spec/unit/support/frame_calculator_mixin_spec.rb +43 -0
  58. metadata +13 -5
@@ -3,13 +3,13 @@ module MotionPrime
3
3
  def add_pull_to_refresh(options = {}, &block)
4
4
  screen.automaticallyAdjustsScrollViewInsets = false
5
5
 
6
- table_view.addPullToRefreshWithActionHandler(block) # block must be a variable
7
- screen.set_options_for table_view.pullToRefreshView, styles: [:base_pull_to_refresh]
6
+ collection_view.addPullToRefreshWithActionHandler(block) # block must be a variable
7
+ screen.set_options_for collection_view.pullToRefreshView, styles: [:base_pull_to_refresh]
8
8
  end
9
9
 
10
10
  def finish_pull_to_refresh
11
11
  reload_data
12
- table_view.pullToRefreshView.stopAnimating
12
+ collection_view.pullToRefreshView.stopAnimating
13
13
  end
14
14
  end
15
15
  end
@@ -2,6 +2,7 @@ module MotionPrime
2
2
  class TableDelegate
3
3
  include DelegateMixin
4
4
  attr_accessor :table_section
5
+
5
6
  def initialize(options)
6
7
  self.table_section = options[:section].try(:weak_ref)
7
8
  @section_instance = table_section.to_s
@@ -1,4 +1,4 @@
1
- motion_require '../views/styles.rb'
1
+ motion_require '../views/styles'
2
2
  MotionPrime::Styles.define :_mixin do
3
3
  style :label_reset,
4
4
  top: nil, left: nil, height: nil, right: nil, bottom: nil, top: nil,
@@ -1,4 +1,4 @@
1
- motion_require '../views/styles.rb'
1
+ motion_require '../views/styles'
2
2
  MotionPrime::Styles.define :base do
3
3
  # basic screen styles
4
4
  style :screen,
@@ -9,17 +9,23 @@ MotionPrime::Styles.define :base do
9
9
  style :table,
10
10
  top: 0,
11
11
  left: 0,
12
- width: 320,
12
+ right: 0,
13
13
  bottom: 0,
14
14
  separator_inset: 0
15
15
 
16
+ style :collection,
17
+ top: 0,
18
+ left: 0,
19
+ right: 0,
20
+ bottom: 0
21
+
16
22
  style :table_cell,
17
23
  background_color: :clear
18
24
 
19
25
  # basic form styles
20
26
  # ----------
21
27
  style :form,
22
- width: 320,
28
+ right: 0,
23
29
  left: 0,
24
30
  top: 0,
25
31
  right: 0,
@@ -41,14 +47,22 @@ MotionPrime::Styles.define :base do
41
47
  height: 44
42
48
 
43
49
  style :segmented_control,
44
- height: 40, width: 320, top: 0
50
+ height: 40,
51
+ left: 0,
52
+ right: 0,
53
+ top: 0
45
54
 
46
55
  style :google_map,
47
- top: 0, left: 0, right: 0, bottom: 0
56
+ top: 0,
57
+ left: 0,
58
+ right: 0,
59
+ bottom: 0
48
60
 
49
61
  style :spinner,
50
62
  annular: true,
51
- center: proc { screen.view.center }, width: 37, height: 37,
63
+ center: proc { screen.view.center },
64
+ width: 37,
65
+ height: 37,
52
66
  progress_tint_color: :app_base.uicolor,
53
67
  background_tint_color: :black.uicolor(0.05),
54
68
  progress: 0.25
@@ -1,4 +1,4 @@
1
- motion_require '../views/styles.rb'
1
+ motion_require '../views/styles'
2
2
  MotionPrime::Styles.define :base_form do
3
3
  style :header, container: {height: 25}
4
4
  style :header_label, mixins: [:multiline],
@@ -0,0 +1,39 @@
1
+ module MotionPrime
2
+ module SupportControlContentAlignment
3
+ VERTICAL_ALIGNMENT_CONSTS = {
4
+ UIControlContentVerticalAlignmentCenter => :center,
5
+ UIControlContentVerticalAlignmentTop => :top,
6
+ UIControlContentVerticalAlignmentBottom => :bottom,
7
+ UIControlContentVerticalAlignmentFill => :fill # TODO: handle this value
8
+ }
9
+ def setContentVerticalAlignment(value)
10
+ return unless @_content_vertical_alignment = VERTICAL_ALIGNMENT_CONSTS[value]
11
+ super
12
+ end
13
+
14
+ def padding_top
15
+ padding_top = self.paddingTop || self.padding
16
+ if @_content_vertical_alignment == :bottom
17
+ padding_bottom = self.paddingBottom || self.padding
18
+ bounds_height - padding_bottom.to_i - line_height
19
+ elsif @_content_vertical_alignment == :top
20
+ padding_top.to_i
21
+ else # center label
22
+ padding_top_offset = padding_top.to_i - (self.paddingBottom || self.padding).to_i
23
+ (bounds_height - line_height)/2 + 1 + padding_top_offset
24
+ end
25
+ end
26
+
27
+ def padding_bottom
28
+ (bounds_height - (line_height + padding_top))
29
+ end
30
+
31
+ def line_height
32
+ @_line_height || self.font.pointSize
33
+ end
34
+
35
+ def bounds_height
36
+ self.bounds.size.height
37
+ end
38
+ end
39
+ end
@@ -1,8 +1,11 @@
1
- motion_require '../support/_key_value_store'
2
- motion_require '../support/_padding_attribute'
1
+ motion_require '_key_value_store'
2
+ motion_require '_padding_attribute'
3
+ motion_require '_control_content_alignment'
3
4
  class MPButton < UIButton
4
5
  include MotionPrime::SupportKeyValueStore
5
6
  include MotionPrime::SupportPaddingAttribute
7
+ include MotionPrime::SupportControlContentAlignment
8
+
6
9
  attr_accessor :sizeToFit
7
10
 
8
11
  def setTitle(value)
@@ -26,17 +29,6 @@ class MPButton < UIButton
26
29
  5
27
30
  end
28
31
 
29
- def padding_top # to center title label
30
- self.paddingTop || self.padding || begin
31
- single_line_height = self.font.pointSize
32
- (self.bounds.size.height - single_line_height)/2 + 1
33
- end
34
- end
35
-
36
- def padding_bottom
37
- self.bounds.size.height - (self.font.pointSize + padding_top)
38
- end
39
-
40
32
  def apply_padding!(rect)
41
33
  self.setTitleEdgeInsets(padding_insets)
42
34
  end
@@ -0,0 +1,12 @@
1
+ class MPCollectionCellWithSection < UICollectionViewCell
2
+ attr_reader :section
3
+
4
+ def setSection(section)
5
+ @section = section.try(:weak_ref)
6
+ end
7
+
8
+ def drawRect(rect)
9
+ section.try(:draw_in, rect)
10
+ super
11
+ end
12
+ end
@@ -1,4 +1,4 @@
1
- class MPCellWithSection < UITableViewCell
1
+ class MPTableCellWithSection < UITableViewCell
2
2
  attr_reader :section
3
3
  attr_accessor :scroll_view, :content_view
4
4
 
@@ -1,13 +1,15 @@
1
1
  # This class have some modifications for UITextField:
2
2
  # * support padding, padding_left, padding_right options
3
3
  # * support placeholder_color, placeholder_font options
4
- motion_require '../support/_key_value_store'
5
- motion_require '../support/_padding_attribute'
4
+ motion_require '_key_value_store'
5
+ motion_require '_padding_attribute'
6
+ motion_require '_control_content_alignment'
6
7
  class MPTextField < UITextField
7
8
  include MotionPrime::SupportKeyValueStore
8
9
  include MotionPrime::SupportPaddingAttribute
9
- attr_accessor :placeholderColor, :placeholderFont, :readonly, :placeholderAlignment
10
+ include MotionPrime::SupportControlContentAlignment
10
11
 
12
+ attr_accessor :placeholderColor, :placeholderFont, :readonly, :placeholderAlignment
11
13
 
12
14
  def self.default_padding_left
13
15
  5
@@ -19,38 +21,42 @@ class MPTextField < UITextField
19
21
 
20
22
  # placeholder position
21
23
  def textRectForBounds(bounds)
22
- calculate_rect_for(bounds)
24
+ @_line_height = placeholder_font.pointSize
25
+ rect = calculate_rect_for(bounds)
26
+ @_line_height = nil
27
+ rect
23
28
  end
24
29
 
25
30
  # text position
26
31
  def editingRectForBounds(bounds)
27
- calculate_rect_for(bounds)
32
+ @_line_height = self.font.pointSize
33
+ rect = calculate_rect_for(bounds)
34
+ @_line_height = nil
35
+ rect
28
36
  end
29
37
 
30
38
  def drawPlaceholderInRect(rect)
31
39
  color = self.placeholderColor || :gray.uicolor
32
40
  color.setFill
33
- font = self.placeholderFont || self.font || :system.uifont(16)
34
41
 
35
42
  truncation = :tail_truncation.uilinebreakmode
36
- alignment = (placeholderAlignment || :left)
37
- alignment = alignment.nstextalignment if alignment.is_a?(Symbol)
38
- self.placeholder.drawInRect(rect, withFont: font, lineBreakMode: truncation, alignment: alignment)
43
+ alignment = (placeholderAlignment || :left.nstextalignment)
44
+ self.placeholder.drawInRect(rect, withFont: placeholder_font, lineBreakMode: truncation, alignment: alignment)
39
45
  end
40
46
 
41
- def padding_top # to center title label
42
- self.paddingTop || self.padding || begin
43
- single_line_height = self.font.pointSize
44
- (self.bounds.size.height - single_line_height)/2 + 1
47
+ private
48
+ def placeholder_font
49
+ self.placeholderFont || self.font || :system.uifont(16)
45
50
  end
46
- end
47
51
 
48
- private
49
52
  def calculate_rect_for(bounds)
50
- height_diff = self.bounds.size.height - (self.font.pointSize + padding_top + padding_bottom)
53
+ height_diff = self.bounds.size.height - (line_height + padding_top + padding_bottom)
51
54
  bounds = CGRectMake(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height - height_diff)
52
55
  CGRectMake(
53
- bounds.origin.x + padding_left, bounds.origin.y + padding_top,
54
- bounds.size.width - (padding_left + padding_right), bounds.size.height - (padding_top + padding_bottom))
56
+ bounds.origin.x + padding_left,
57
+ bounds.origin.y + padding_top,
58
+ bounds.size.width - (padding_left + padding_right),
59
+ bounds.size.height - (padding_top + padding_bottom)
60
+ )
55
61
  end
56
62
  end
@@ -6,6 +6,7 @@ motion_require '../support/_padding_attribute'
6
6
  class MPTextView < UITextView
7
7
  include MotionPrime::SupportKeyValueStore
8
8
  include MotionPrime::SupportPaddingAttribute
9
+
9
10
  attr_accessor :placeholderColor, :placeholderFont, :placeholder
10
11
 
11
12
  def self.default_padding_left
@@ -1,3 +1,3 @@
1
1
  module MotionPrime
2
- VERSION = "0.9.9"
2
+ VERSION = "0.9.9.1"
3
3
  end
@@ -19,8 +19,8 @@ module MotionPrime
19
19
 
20
20
  max_width = parent_bounds.size.width
21
21
  max_height = parent_bounds.size.height
22
- width = 0.0 if width.nil?
23
- height = 0.0 if height.nil?
22
+ temp_width = width || 0.0
23
+ temp_height = height || 0.0
24
24
 
25
25
  if left && left > 0 && left <= 1 && value_type != 'absolute' && left.is_a?(Float)
26
26
  left = max_width * left
@@ -41,7 +41,7 @@ module MotionPrime
41
41
  end
42
42
 
43
43
  # calculate top and bottom if height is relative, e.g 0.7
44
- if height && height > 0 && height <= 1 && value_type != 'absolute' && width.is_a?(Float)
44
+ if height && height > 0 && height <= 1 && value_type != 'absolute' && height.is_a?(Float)
45
45
  if bottom.nil?
46
46
  top ||= 0
47
47
  bottom = max_height - max_height * height
@@ -52,27 +52,31 @@ module MotionPrime
52
52
 
53
53
  if !left.nil? && !right.nil?
54
54
  frame.origin.x = left
55
- width = max_width - left - right if options[:height_to_fit].nil?
55
+ if options[:height_to_fit].nil? && width.nil?
56
+ width = max_width - left - right
57
+ end
56
58
  elsif !right.nil?
57
- frame.origin.x = max_width - width - right
59
+ frame.origin.x = max_width - temp_width - right
58
60
  elsif !left.nil?
59
61
  frame.origin.x = left
60
62
  else
61
- frame.origin.x = max_width / 2 - width / 2
63
+ frame.origin.x = max_width / 2 - temp_width / 2
62
64
  end
63
- frame.size.width = width
65
+ frame.size.width = width || 0.0
64
66
 
65
67
  if !top.nil? && !bottom.nil?
66
68
  frame.origin.y = top
67
- height = max_height - top - bottom if options[:height_to_fit].nil?
69
+ if options[:height_to_fit].nil? && height.nil?
70
+ height = max_height - top - bottom
71
+ end
68
72
  elsif !bottom.nil?
69
- frame.origin.y = max_height - height - bottom
73
+ frame.origin.y = max_height - temp_height - bottom
70
74
  elsif !top.nil?
71
75
  frame.origin.y = top
72
76
  else
73
- frame.origin.y = max_height / 2 - height / 2
77
+ frame.origin.y = max_height / 2 - temp_height / 2
74
78
  end
75
- frame.size.height = height
79
+ frame.size.height = height || 0.0
76
80
 
77
81
  frame
78
82
  rescue => e
@@ -1,5 +1,6 @@
1
1
  # TODO: make it part of Sections
2
- motion_require '../support/mp_cell_with_section'
2
+ motion_require '../support/mp_table_cell_with_section'
3
+ motion_require '../support/mp_collection_cell_with_section'
3
4
  motion_require '../support/mp_spinner'
4
5
  motion_require '../support/mp_button'
5
6
  motion_require '../support/mp_label'
@@ -17,7 +18,7 @@ module MotionPrime
17
18
  else
18
19
  view_stack.last.bounds
19
20
  end
20
- builder = ViewBuilder.new(klass, options)
21
+ builder = ViewBuilder.new(klass, options.merge(parent_bounds: parent_bounds))
21
22
  options = builder.options.merge(calculate_frame: true, parent_bounds: parent_bounds)
22
23
  view = builder.view
23
24
  insert_index = options.delete(:at_index)
@@ -51,8 +52,9 @@ module MotionPrime
51
52
  base.class_eval do
52
53
  [::UIActionSheet, ::UIActivityIndicatorView, ::MPButton, ::UIDatePicker, ::UIImageView, ::MPLabel,
53
54
  ::UIPageControl, ::UIPickerView, ::UIProgressView, ::UIScrollView, ::UISearchBar, ::UISegmentedControl,
54
- ::UISlider, ::UIStepper, ::UISwitch, ::UITabBar, ::UITableView, ::UITableViewCell, ::MPTextField, ::MPTextView,
55
- ::UIToolbar, ::UIWebView, ::UINavigationBar, ::MPCellWithSection, ::MBProgressHUD, ::MPSpinner].each do |klass|
55
+ ::UISlider, ::UIStepper, ::UISwitch, ::UITabBar, ::UICollectionView, ::UITableView, ::UITableViewCell,
56
+ ::MPTextField, ::MPTextView, ::UIToolbar, ::UIWebView, ::UINavigationBar,
57
+ ::MPTableCellWithSection, ::MPCollectionCellWithSection, ::MBProgressHUD, ::MPSpinner].each do |klass|
56
58
 
57
59
  shorthand = "#{klass}"[2..-1].underscore.to_sym
58
60
 
@@ -86,6 +86,16 @@ module MotionPrime
86
86
  view.tableFooterView = UIView.new
87
87
  view
88
88
  },
89
+ 'UICollectionView' => Proc.new{|klass, options|
90
+ unless layout = options.delete(:layout)
91
+ layout = UICollectionViewFlowLayout.alloc.init
92
+ total_width = options[:parent_bounds].size.width / (options.delete(:grid_size) || 4)
93
+ width = total_width - layout.minimumInteritemSpacing
94
+ layout.setItemSize CGSizeMake(width, options.delete(:item_height) || 100)
95
+ end
96
+ view = klass.alloc.initWithFrame CGRectZero, collectionViewLayout: layout
97
+ view
98
+ },
89
99
  'UITableViewCell' => Proc.new{|klass, options|
90
100
  style = options.delete(:style) || UITableViewCellStyleDefault
91
101
  if options[:has_drawn_content]
@@ -5,6 +5,8 @@ module MotionPrime
5
5
  include HasClassFactory
6
6
  include ElementTextMixin
7
7
 
8
+ ORDER = %w[font placeholder_font text]
9
+
8
10
  attr_reader :view, :options
9
11
 
10
12
  def initialize(view, parent_bounds = CGRectZero, options = {})
@@ -46,7 +48,7 @@ module MotionPrime
46
48
  def prepare_options!
47
49
  if options[:size_to_fit]
48
50
  options[:line_break_mode] ||= :word_wrap
49
- options[:number_of_lines] ||= 0
51
+ options[:number_of_lines] ||= 0 if view.is_a?(UILabel)
50
52
  end
51
53
 
52
54
  if options.slice(:html, :line_spacing, :line_height, :underline, :fragment_color).any?
@@ -63,6 +65,8 @@ module MotionPrime
63
65
  end
64
66
  extract_font_options(options)
65
67
  extract_font_options(options, 'placeholder')
68
+
69
+ @options = Hash[options.sort_by { |k,v| ORDER.index(k.to_s).to_i }]
66
70
  end
67
71
 
68
72
  def extract_font_options(options, prefix = nil)
@@ -1,5 +1,5 @@
1
1
  class TasksIndexTableSection < Prime::TableSection
2
- def table_data
2
+ def collection_data
3
3
  Task.all.map do |model|
4
4
  TasksIndexCellSection.new(model: model)
5
5
  end
@@ -1,4 +1,8 @@
1
1
  describe MotionPrime::FilterMixin do
2
+ before do
3
+ @subject = MotionPrime::FilterMixin.new
4
+ end
5
+
2
6
  def data
3
7
  model_stub = Struct.new(:info, :id) # :id is used for sorting
4
8
  data_array.map do |item|
@@ -11,15 +15,15 @@ describe MotionPrime::FilterMixin do
11
15
  end
12
16
 
13
17
  it "should filter array by inclusion" do
14
- MotionPrime::FilterMixin.new.filter_array(data, {id: %w[4 5]}).count.should.equal 2
18
+ @subject.filter_array(data, {id: %w[4 5]}).count.should.equal 2
15
19
  end
16
20
 
17
21
  it "should find a single record (case sensitive)" do
18
- MotionPrime::FilterMixin.new.filter_array(data, {id: 4, name: 'iPhone'}).count.should.equal 1
22
+ @subject.filter_array(data, {id: 4, name: 'iPhone'}).count.should.equal 1
19
23
  end
20
24
 
21
25
  it "order filtered records" do
22
- result = MotionPrime::FilterMixin.new.filter_array(data, {id: %w[4 5]}, sort: {id: :desc})
26
+ result = @subject.filter_array(data, {id: %w[4 5]}, sort: {id: :desc})
23
27
  result.first[:id].should.equal 5
24
28
  end
25
29
  end