ProMotion 1.2.1 → 2.0.0.rc1

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -10
  3. data/lib/ProMotion.rb +11 -2
  4. data/lib/ProMotion/cocoatouch/ns_string.rb +5 -0
  5. data/lib/ProMotion/cocoatouch/ns_url.rb +5 -0
  6. data/lib/ProMotion/cocoatouch/tab_bar_controller.rb +5 -7
  7. data/lib/ProMotion/cocoatouch/table_view_cell.rb +0 -16
  8. data/lib/ProMotion/cocoatouch/table_view_controller.rb +2 -3
  9. data/lib/ProMotion/cocoatouch/view_controller.rb +3 -6
  10. data/lib/ProMotion/delegate/delegate.rb +0 -3
  11. data/lib/ProMotion/delegate/delegate_module.rb +24 -20
  12. data/lib/ProMotion/{containers → ipad}/split_screen.rb +30 -32
  13. data/lib/ProMotion/{logger.rb → logger/logger.rb} +6 -5
  14. data/lib/ProMotion/screen/nav_bar_module.rb +126 -0
  15. data/lib/ProMotion/screen/screen.rb +0 -3
  16. data/lib/ProMotion/screen/screen_module.rb +54 -177
  17. data/lib/ProMotion/screen/screen_navigation.rb +29 -40
  18. data/lib/ProMotion/{view → styling}/styling.rb +17 -47
  19. data/lib/ProMotion/table/cell/table_view_cell_module.rb +76 -123
  20. data/lib/ProMotion/table/data/table_data.rb +1 -1
  21. data/lib/ProMotion/table/extensions/longpressable.rb +24 -0
  22. data/lib/ProMotion/table/extensions/refreshable.rb +1 -0
  23. data/lib/ProMotion/table/grouped_table_screen.rb +0 -5
  24. data/lib/ProMotion/table/table.rb +63 -83
  25. data/lib/ProMotion/table/table_screen.rb +0 -4
  26. data/lib/ProMotion/{containers → tabs}/tabs.rb +20 -21
  27. data/lib/ProMotion/version.rb +1 -1
  28. data/lib/ProMotion/web/web_screen.rb +0 -4
  29. data/lib/ProMotion/web/web_screen_module.rb +8 -5
  30. data/spec/functional/func_screen_spec.rb +14 -18
  31. data/spec/functional/func_split_screen_spec.rb +2 -2
  32. data/spec/functional/func_table_screen_spec.rb +54 -40
  33. data/spec/functional/func_web_screen_spec.rb +12 -17
  34. data/spec/helpers/test_helper.rb +27 -0
  35. data/spec/unit/delegate_spec.rb +4 -67
  36. data/spec/unit/image_title_screen.rb +9 -0
  37. data/spec/unit/image_view_title_screen.rb +9 -0
  38. data/spec/unit/load_view_spec.rb +27 -0
  39. data/spec/unit/main_spec.rb +0 -6
  40. data/spec/unit/screen_helpers_spec.rb +23 -17
  41. data/spec/unit/screen_spec.rb +21 -17
  42. data/spec/unit/searchable_table_spec.rb +55 -0
  43. data/spec/unit/split_screen_in_tab_bar_spec.rb +5 -5
  44. data/spec/unit/split_screen_spec.rb +4 -4
  45. data/spec/unit/tab_bar_spec.rb +79 -0
  46. data/spec/unit/tab_spec.rb +11 -5
  47. data/spec/unit/tables/table_module_spec.rb +22 -8
  48. data/spec/unit/tables/table_screen_spec.rb +1 -1
  49. data/spec/unit/tables/table_view_cell_spec.rb +16 -16
  50. data/spec/unit/view_helper_spec.rb +6 -81
  51. data/spec/unit/view_title_screen.rb +10 -0
  52. data/spec/unit/web_spec.rb +31 -37
  53. metadata +37 -111
  54. data/.gitignore +0 -33
  55. data/.travis.yml +0 -4
  56. data/CONTRIBUTING.md +0 -20
  57. data/Gemfile +0 -5
  58. data/LICENSE +0 -22
  59. data/ProMotion.gemspec +0 -30
  60. data/Rakefile +0 -66
  61. data/app/app_delegate.rb +0 -7
  62. data/app/screens/basic_screen.rb +0 -15
  63. data/lib/ProMotion/delegate/delegate_notifications.rb +0 -70
  64. data/lib/ProMotion/extensions/conversions.rb +0 -20
  65. data/lib/ProMotion/map/map_screen.rb +0 -10
  66. data/lib/ProMotion/map/map_screen_annotation.rb +0 -65
  67. data/lib/ProMotion/map/map_screen_module.rb +0 -212
  68. data/lib/ProMotion/push_notification/push_notification.rb +0 -58
  69. data/resources/WebScreen.html +0 -6
  70. data/resources/list.png +0 -0
  71. data/resources/test.png +0 -0
  72. data/spec/functional/func_image_title_screen.rb +0 -20
  73. data/spec/functional/func_image_view_title_screen.rb +0 -20
  74. data/spec/functional/func_map_screen_spec.rb +0 -162
  75. data/spec/functional/func_searchable_table_spec.rb +0 -56
  76. data/spec/functional/func_tab_bar_spec.rb +0 -78
  77. data/spec/functional/func_view_title_screen.rb +0 -21
  78. data/spec/helpers/basic_screen.rb +0 -3
  79. data/spec/helpers/custom_title_view.rb +0 -4
  80. data/spec/helpers/detail_screen.rb +0 -3
  81. data/spec/helpers/dummy_class.rb +0 -3
  82. data/spec/helpers/functional_screen.rb +0 -15
  83. data/spec/helpers/home_screen.rb +0 -19
  84. data/spec/helpers/image_title_screen.rb +0 -15
  85. data/spec/helpers/image_view_title_screen.rb +0 -15
  86. data/spec/helpers/map_screen.rb +0 -53
  87. data/spec/helpers/master_screen.rb +0 -3
  88. data/spec/helpers/present_screen.rb +0 -26
  89. data/spec/helpers/screen_module_view_controller.rb +0 -55
  90. data/spec/helpers/tab_screen.rb +0 -4
  91. data/spec/helpers/table_screen.rb +0 -117
  92. data/spec/helpers/table_screen_indexable.rb +0 -18
  93. data/spec/helpers/table_screen_refreshable.rb +0 -11
  94. data/spec/helpers/table_screen_searchable.rb +0 -72
  95. data/spec/helpers/test_delegate.rb +0 -34
  96. data/spec/helpers/test_delegate_colors.rb +0 -17
  97. data/spec/helpers/view_title_screen.rb +0 -15
  98. data/spec/helpers/web_screen.rb +0 -23
  99. data/spec/unit/map_spec.rb +0 -71
@@ -1,9 +1,5 @@
1
- motion_require '../extensions/conversions'
2
-
3
1
  module ProMotion
4
2
  module Styling
5
- include Conversions
6
-
7
3
  def set_attributes(element, args = {})
8
4
  args = get_attributes_from_symbol(args)
9
5
  args.each { |k, v| set_attribute(element, k, v) }
@@ -13,7 +9,9 @@ module ProMotion
13
9
  def set_attribute(element, k, v)
14
10
  return element unless element
15
11
 
16
- if v.is_a?(Hash) && element.respond_to?(k)
12
+ if !element.is_a?(CALayer) && v.is_a?(Hash) && element.respond_to?("#{k}=")
13
+ element.send("#{k}=", v)
14
+ elsif v.is_a?(Hash) && element.respond_to?(k)
17
15
  sub_element = element.send(k)
18
16
  set_attributes(sub_element, v) if sub_element
19
17
  elsif element.respond_to?("#{k}=")
@@ -22,35 +20,13 @@ module ProMotion
22
20
  element.send("#{k}", *v)
23
21
  else
24
22
  # Doesn't respond. Check if snake case.
25
- if k.to_s.include?("_")
26
- set_attribute(element, objective_c_method_name(k), v)
27
- end
23
+ set_attribute(element, camelize(k), v) if k.to_s.include?("_")
28
24
  end
29
25
  element
30
26
  end
31
27
 
32
- def set_easy_attributes(parent, element, args={})
33
- attributes = {}
34
-
35
- if args[:resize]
36
- attributes[:autoresizingMask] = UIViewAutoresizingNone
37
- args[:resize].each { |r| attributes[:autoresizingMask] |= map_resize_symbol(r) }
38
- end
39
-
40
- args[:left] = args.delete(:x) if args[:x]
41
- args[:top] = args.delete(:y) if args[:y]
42
- if [:left, :top, :width, :height].select{ |a| args[a] && args[a] != :auto }.length == 4
43
- attributes[:frame] = CGRectMake(args[:left], args[:top], args[:width], args[:height])
44
- end
45
-
46
- set_attributes element, attributes
47
- element
48
- end
49
-
50
28
  def content_max(view, mode = :height)
51
- return 0 if view.subviews.empty?
52
-
53
- sizes = view.subviews.map do |sub_view|
29
+ view.subviews.map do |sub_view|
54
30
  if sub_view.isHidden
55
31
  0
56
32
  elsif mode == :height
@@ -58,9 +34,7 @@ module ProMotion
58
34
  else
59
35
  sub_view.frame.origin.x + sub_view.frame.size.width
60
36
  end
61
- end
62
-
63
- sizes.max
37
+ end.max.to_f
64
38
  end
65
39
 
66
40
  def content_height(view)
@@ -71,8 +45,9 @@ module ProMotion
71
45
  content_max(view, :width)
72
46
  end
73
47
 
48
+ # iterate up the view hierarchy to find the parent element
49
+ # of "type" containing this view
74
50
  def closest_parent(type, this_view = nil)
75
- # iterate up the view hierarchy to find the parent element of "type" containing this view
76
51
  this_view ||= view_or_self.superview
77
52
  while this_view != nil do
78
53
  return this_view if this_view.is_a? type
@@ -84,23 +59,16 @@ module ProMotion
84
59
  def add(element, attrs = {})
85
60
  add_to view_or_self, element, attrs
86
61
  end
87
- alias :add_element :add
88
- alias :add_view :add
89
62
 
90
63
  def remove(elements)
91
64
  Array(elements).each(&:removeFromSuperview)
92
65
  end
93
- alias :remove_element :remove
94
- alias :remove_view :remove
95
66
 
96
67
  def add_to(parent_element, elements, attrs = {})
97
68
  attrs = get_attributes_from_symbol(attrs)
98
69
  Array(elements).each do |element|
99
70
  parent_element.addSubview element
100
- if attrs && attrs.length > 0
101
- set_attributes(element, attrs)
102
- set_easy_attributes(parent_element, element, attrs)
103
- end
71
+ set_attributes(element, attrs) if attrs && attrs.length > 0
104
72
  end
105
73
  elements
106
74
  end
@@ -130,14 +98,16 @@ module ProMotion
130
98
  raise ArgumentError
131
99
  end
132
100
 
133
- if colors.size == 3
134
- rgb_color(colors[0], colors[1], colors[2])
135
- else
136
- raise ArgumentError
137
- end
101
+ raise ArgumentError unless colors.size == 3
102
+ rgb_color(colors[0], colors[1], colors[2])
103
+ end
104
+
105
+ # Turns a snake_case string into a camelCase string.
106
+ def camelize(str)
107
+ str.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
138
108
  end
139
109
 
140
- protected
110
+ protected
141
111
 
142
112
  def get_attributes_from_symbol(attrs)
143
113
  return attrs if attrs.is_a?(Hash)
@@ -1,5 +1,3 @@
1
- motion_require '../../view/styling'
2
-
3
1
  module ProMotion
4
2
  module TableViewCellModule
5
3
  include Styling
@@ -10,163 +8,118 @@ module ProMotion
10
8
  self.table_screen = WeakRef.new(screen)
11
9
  self.data_cell = data_cell
12
10
 
13
- # TODO: Some of these need to go away. Unnecessary overhead.
14
- set_cell_attributes
15
- set_accessory_view
11
+ check_deprecated_styles
12
+ set_styles
13
+ set_title
16
14
  set_subtitle
17
15
  set_image
18
16
  set_remote_image
19
- set_subviews
20
- set_details
21
- set_styles
17
+ set_accessory_view
22
18
  set_selection_style
23
-
24
- self
25
19
  end
26
20
 
27
- def set_cell_attributes
28
- data_cell_attributes = data_cell.dup
29
- [:image, :accessory_action, :editing_style].each { |k| data_cell_attributes.delete(k) }
30
- set_attributes self, data_cell_attributes
31
- self
32
- end
21
+ protected
33
22
 
34
- def set_accessory_view
35
- if data_cell[:accessory]
36
- if data_cell[:accessory][:view] == :switch
37
- switch_view = UISwitch.alloc.initWithFrame(CGRectZero)
38
- switch_view.setAccessibilityLabel(data_cell[:accessory][:accessibility_label] || data_cell[:title])
39
- switch_view.addTarget(self.table_screen, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
40
- switch_view.on = !!data_cell[:accessory][:value]
41
- self.accessoryView = switch_view
42
- elsif data_cell[:accessory][:view]
43
- self.accessoryView = data_cell[:accessory][:view]
44
- self.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
45
- end
46
- else
47
- self.accessoryView = nil
23
+ # TODO: Remove this in ProMotion 2.1. Just for migration purposes.
24
+ def check_deprecated_styles
25
+ whitelist = [ :title, :subtitle, :image, :remote_image, :accessory, :selection_style, :action, :arguments, :cell_style, :cell_class, :cell_identifier, :editing_style, :search_text, :keep_selection, :height ]
26
+ if (data_cell.keys - whitelist).length > 0
27
+ PM.logger.deprecated("In #{self.table_screen.class.to_s}#table_data, you should set :#{(data_cell.keys - whitelist).join(", :")} in a `styles:` hash. See TableScreen documentation.")
48
28
  end
29
+ end
30
+
31
+ def set_styles
32
+ set_attributes self, data_cell[:style] if data_cell[:style]
33
+ end
49
34
 
50
- self
35
+ def set_title
36
+ set_attributed_text(self.textLabel, data_cell[:title])
51
37
  end
52
38
 
53
39
  def set_subtitle
54
- if data_cell[:subtitle] && self.detailTextLabel
55
- if data_cell[:subtitle].is_a? NSAttributedString
56
- self.detailTextLabel.attributedText = data_cell[:subtitle]
57
- else
58
- self.detailTextLabel.text = data_cell[:subtitle]
59
- end
60
- self.detailTextLabel.backgroundColor = UIColor.clearColor
61
- self.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth
62
- end
63
- self
40
+ return unless data_cell[:subtitle] && self.detailTextLabel
41
+ set_attributed_text(self.detailTextLabel, data_cell[:subtitle])
42
+ self.detailTextLabel.backgroundColor = UIColor.clearColor
43
+ self.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth
64
44
  end
65
45
 
66
46
  def set_remote_image
67
- if data_cell[:remote_image]
68
- if self.imageView.respond_to?("setImageWithURL:placeholder:")
69
- url = data_cell[:remote_image][:url]
70
- url = NSURL.URLWithString(url) unless url.is_a?(NSURL)
71
- placeholder = data_cell[:remote_image][:placeholder]
72
- placeholder = UIImage.imageNamed(placeholder) if placeholder.is_a?(String)
73
-
74
- self.image_size = data_cell[:remote_image][:size] if data_cell[:remote_image][:size] && self.respond_to?("image_size=")
75
- self.imageView.setImageWithURL(url, placeholder: placeholder)
76
- self.imageView.layer.masksToBounds = true
77
- self.imageView.layer.cornerRadius = data_cell[:remote_image][:radius] if data_cell[:remote_image].has_key?(:radius)
78
- self.imageView.contentMode = map_content_mode_symbol(data_cell[:remote_image][:content_mode]) if data_cell[:remote_image].has_key?(:content_mode)
79
- elsif self.imageView.respond_to?("setImageWithURL:placeholderImage:")
80
- # TODO - Remove this in next major release
81
- PM.logger.deprecated "The SDWebImage cocoapod is deprecated. Please replace it with 'JMImageCache'."
82
- else
83
- PM.logger.error "ProMotion Warning: to use remote_image with TableScreen you need to include the CocoaPod 'JMImageCache'."
84
- end
85
- end
86
- self
47
+ return unless data_cell[:remote_image] && jm_image_cache?
48
+
49
+ self.imageView.image = remote_placeholder
50
+ JMImageCache.sharedCache.imageForURL(data_cell[:remote_image][:url].to_url, completionBlock:proc { |downloaded_image|
51
+ self.imageView.image = downloaded_image
52
+ self.setNeedsLayout
53
+ })
54
+
55
+ self.imageView.layer.masksToBounds = true
56
+ self.imageView.layer.cornerRadius = data_cell[:remote_image][:radius] if data_cell[:remote_image][:radius]
57
+ self.imageView.contentMode = map_content_mode_symbol(data_cell[:remote_image][:content_mode]) if data_cell[:remote_image][:content_mode]
87
58
  end
88
59
 
89
60
  def set_image
90
- if data_cell[:image]
91
-
92
- cell_image = data_cell[:image].is_a?(Hash) ? data_cell[:image][:image] : data_cell[:image]
93
- cell_image = UIImage.imageNamed(cell_image) if cell_image.is_a?(String)
61
+ return unless data_cell[:image]
62
+ cell_image = data_cell[:image].is_a?(Hash) ? data_cell[:image][:image] : data_cell[:image]
63
+ cell_image = UIImage.imageNamed(cell_image) if cell_image.is_a?(String)
64
+ self.imageView.layer.masksToBounds = true
65
+ self.imageView.image = cell_image
66
+ self.imageView.layer.cornerRadius = data_cell[:image][:radius] if data_cell[:image].is_a?(Hash) && data_cell[:image][:radius]
67
+ end
94
68
 
95
- self.imageView.layer.masksToBounds = true
96
- self.imageView.image = cell_image
97
- self.imageView.layer.cornerRadius = data_cell[:image][:radius] if data_cell[:image].is_a?(Hash) && data_cell[:image][:radius]
69
+ def set_accessory_view
70
+ return self.accessoryView = nil unless data_cell[:accessory] && data_cell[:accessory][:view]
71
+ if data_cell[:accessory][:view] == :switch
72
+ self.accessoryView = switch_view
73
+ else
74
+ self.accessoryView = data_cell[:accessory][:view]
75
+ self.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
98
76
  end
99
- self
100
77
  end
101
78
 
102
- def set_subviews
103
- tag_number = 0
104
- Array(data_cell[:subviews]).each do |view|
105
- # Remove an existing view at that tag number
106
- tag_number += 1
107
- existing_view = self.viewWithTag(tag_number)
108
- existing_view.removeFromSuperview if existing_view
109
-
110
- # Add the subview if it exists
111
- if view
112
- view.tag = tag_number
113
- self.addSubview view
114
- end
115
- end
116
- self
79
+ def set_selection_style
80
+ self.selectionStyle = map_selection_style_symbol(data_cell[:selection_style]) if data_cell[:selection_style]
117
81
  end
118
82
 
119
- def set_details
120
- if data_cell[:details]
121
- self.addSubview data_cell[:details][:image]
122
- end
123
- self
83
+ private
84
+
85
+ def jm_image_cache?
86
+ return true if self.imageView.respond_to?("setImageWithURL:placeholder:")
87
+ PM.logger.error "ProMotion Warning: to use remote_image with TableScreen you need to include the CocoaPod 'JMImageCache'."
88
+ false
124
89
  end
125
90
 
126
- def set_styles
127
- if data_cell[:styles] && data_cell[:styles][:label] && data_cell[:styles][:label][:frame]
128
- ui_label = false
129
- self.contentView.subviews.each do |view|
130
- if view.is_a? UILabel
131
- ui_label = true
132
- view.text = data_cell[:styles][:label][:text]
133
- end
134
- end
135
-
136
- unless ui_label == true
137
- label ||= UILabel.alloc.initWithFrame(CGRectZero)
138
- set_attributes label, data_cell[:styles][:label]
139
- self.contentView.addSubview label
140
- end
141
-
142
- # TODO: What is this and why is it necessary?
143
- self.textLabel.textColor = UIColor.clearColor
144
- else
145
- cell_title = data_cell[:title]
146
- cell_title ||= ""
147
- self.textLabel.backgroundColor = UIColor.clearColor
148
- if cell_title.is_a? NSAttributedString
149
- self.textLabel.attributedText = cell_title
150
- else
151
- self.textLabel.text = cell_title
152
- end
153
- end
91
+ def remote_placeholder
92
+ UIImage.imageNamed(data_cell[:remote_image][:placeholder]) if data_cell[:remote_image][:placeholder].is_a?(String)
93
+ end
154
94
 
155
- self
95
+ def switch_view
96
+ switch = UISwitch.alloc.initWithFrame(CGRectZero)
97
+ switch.setAccessibilityLabel(data_cell[:accessory][:accessibility_label] || data_cell[:title])
98
+ switch.addTarget(self.table_screen, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
99
+ switch.on = !!data_cell[:accessory][:value]
100
+ switch
156
101
  end
157
102
 
158
- def set_selection_style
159
- self.selectionStyle = UITableViewCellSelectionStyleNone if data_cell[:no_select]
103
+ def set_attributed_text(label, text)
104
+ text.is_a?(NSAttributedString) ? label.attributedText = text : label.text = text
160
105
  end
161
106
 
162
107
  def map_content_mode_symbol(symbol)
163
- content_mode = {
108
+ {
164
109
  scale_to_fill: UIViewContentModeScaleToFill,
165
110
  scale_aspect_fit: UIViewContentModeScaleAspectFit,
166
111
  scale_aspect_fill: UIViewContentModeScaleAspectFill,
167
112
  mode_redraw: UIViewContentModeRedraw
168
- }[symbol] if symbol.is_a?(Symbol)
169
- content_mode || symbol
113
+ }[symbol] || symbol
114
+ end
115
+
116
+ def map_selection_style_symbol(symbol)
117
+ {
118
+ none: UITableViewCellSelectionStyleNone,
119
+ blue: UITableViewCellSelectionStyleBlue,
120
+ gray: UITableViewCellSelectionStyleGray,
121
+ default: UITableViewCellSelectionStyleDefault
122
+ }[symbol] || symbol
170
123
  end
171
124
  end
172
125
  end
@@ -4,7 +4,7 @@ module ProMotion
4
4
 
5
5
  def initialize(data, table_view)
6
6
  self.data = data
7
- self.table_view = table_view
7
+ self.table_view = WeakRef.new(table_view)
8
8
  end
9
9
 
10
10
  def section(index)
@@ -0,0 +1,24 @@
1
+ module ProMotion
2
+ module Table
3
+ module Longpressable
4
+ def make_longpressable(params={})
5
+ params = {
6
+ min_duration: 1.0
7
+ }.merge(params)
8
+
9
+ long_press_gesture = UILongPressGestureRecognizer.alloc.initWithTarget(self, action:"on_long_press:")
10
+ long_press_gesture.minimumPressDuration = params[:min_duration]
11
+ long_press_gesture.delegate = self
12
+ self.table_view.addGestureRecognizer(long_press_gesture)
13
+ end
14
+
15
+ def on_long_press(gesture)
16
+ return unless gesture.state == UIGestureRecognizerStateBegan
17
+ gesture_point = gesture.locationInView(table_view)
18
+ index_path = table_view.indexPathForRowAtPoint(gesture_point)
19
+ data_cell = self.promotion_table_data.cell(index_path: index_path)
20
+ trigger_action(data_cell[:long_press_action], data_cell[:arguments]) if data_cell[:long_press_action]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,7 @@
1
1
  module ProMotion
2
2
  module Table
3
3
  module Refreshable
4
+
4
5
  def make_refreshable(params={})
5
6
  pull_message = params[:pull_message] || "Pull to refresh"
6
7
  @refreshing = params[:refreshing] || "Refreshing data..."
@@ -1,8 +1,3 @@
1
- motion_require '../cocoatouch/table_view_controller'
2
- motion_require '../screen/screen_module'
3
- motion_require 'table'
4
- motion_require 'grouped_table'
5
-
6
1
  module ProMotion
7
2
  class GroupedTableScreen < TableViewController
8
3
  include ProMotion::ScreenModule
@@ -1,15 +1,10 @@
1
- motion_require '../view/styling'
2
- motion_require 'extensions/searchable'
3
- motion_require 'extensions/refreshable'
4
- motion_require 'extensions/indexable'
5
-
6
1
  module ProMotion
7
2
  module Table
8
-
9
3
  include ProMotion::Styling
10
4
  include ProMotion::Table::Searchable
11
5
  include ProMotion::Table::Refreshable
12
6
  include ProMotion::Table::Indexable
7
+ include ProMotion::Table::Longpressable
13
8
 
14
9
  attr_reader :promotion_table_data
15
10
 
@@ -21,6 +16,7 @@ module ProMotion
21
16
  check_table_data
22
17
  set_up_searchable
23
18
  set_up_refreshable
19
+ set_up_longpressable
24
20
  end
25
21
 
26
22
  def check_table_data
@@ -47,6 +43,12 @@ module ProMotion
47
43
  end
48
44
  end
49
45
 
46
+ def set_up_longpressable
47
+ if self.class.respond_to?(:get_longpressable) && self.class.get_longpressable
48
+ self.make_longpressable(self.class.get_longpressable_params)
49
+ end
50
+ end
51
+
50
52
  def searching?
51
53
  self.promotion_table_data.filtered
52
54
  end
@@ -62,31 +64,13 @@ module ProMotion
62
64
  def update_table_view_data(data)
63
65
  self.promotion_table_data.data = data
64
66
  table_view.reloadData
65
- end
66
-
67
- # Methods to retrieve data
68
-
69
- def section_at_index(index)
70
- self.promotion_table_data.section(index)
71
- end
72
-
73
- def cell_at_section_and_index(section, index)
74
- self.promotion_table_data.cell(section: section, index: index)
67
+ @table_search_display_controller.searchResultsTableView.reloadData if searching?
75
68
  end
76
69
 
77
70
  def trigger_action(action, arguments)
78
- if self.respond_to?(action)
79
- expected_arguments = self.method(action).arity
80
- if expected_arguments == 0
81
- self.send(action)
82
- elsif expected_arguments == 1 || expected_arguments == -1
83
- self.send(action, arguments)
84
- else
85
- PM.logger.warn "#{action} expects #{expected_arguments} arguments. Maximum number of required arguments for an action is 1."
86
- end
87
- else
88
- PM.logger.info "Action not implemented: #{action.to_s}"
89
- end
71
+ return PM.logger.info "Action not implemented: #{action.to_s}" unless self.respond_to?(action)
72
+ return self.send(action) if self.method(action).arity == 0
73
+ self.send(action, arguments)
90
74
  end
91
75
 
92
76
  def accessory_toggled_switch(switch)
@@ -94,20 +78,16 @@ module ProMotion
94
78
  index_path = closest_parent(UITableView, table_cell).indexPathForCell(table_cell)
95
79
 
96
80
  if index_path
97
- data_cell = cell_at_section_and_index(index_path.section, index_path.row)
81
+ data_cell = promotion_table_data.cell(section: index_path.section, index: index_path.row)
98
82
  data_cell[:accessory][:arguments] ||= {}
99
83
  data_cell[:accessory][:arguments][:value] = switch.isOn if data_cell[:accessory][:arguments].is_a?(Hash)
100
-
101
84
  trigger_action(data_cell[:accessory][:action], data_cell[:accessory][:arguments]) if data_cell[:accessory][:action]
102
85
  end
103
86
  end
104
87
 
105
88
  def delete_row(index_paths, animation = nil)
106
- animation = map_row_animation_symbol(animation)
107
- index_paths = [index_paths] if index_paths.kind_of?(NSIndexPath)
108
89
  deletable_index_paths = []
109
-
110
- index_paths.each do |index_path|
90
+ Array(index_paths).each do |index_path|
111
91
  delete_cell = false
112
92
  delete_cell = send(:on_cell_deleted, self.promotion_table_data.cell(index_path: index_path)) if self.respond_to?("on_cell_deleted:")
113
93
  unless delete_cell == false
@@ -115,45 +95,44 @@ module ProMotion
115
95
  deletable_index_paths << index_path
116
96
  end
117
97
  end
118
- table_view.deleteRowsAtIndexPaths(deletable_index_paths, withRowAnimation:animation) if deletable_index_paths.length > 0
98
+ table_view.deleteRowsAtIndexPaths(deletable_index_paths, withRowAnimation:map_row_animation_symbol(animation)) if deletable_index_paths.length > 0
119
99
  end
120
100
 
121
101
  def table_view_cell(params={})
102
+ params = index_path_to_section_index(params)
103
+ data_cell = self.promotion_table_data.cell(section: params[:section], index: params[:index])
104
+ return UITableViewCell.alloc.init unless data_cell
105
+ create_table_cell(data_cell)
106
+ end
107
+
108
+ def index_path_to_section_index(params)
122
109
  if params[:index_path]
123
110
  params[:section] = params[:index_path].section
124
111
  params[:index] = params[:index_path].row
125
112
  end
126
-
127
- data_cell = self.promotion_table_data.cell(section: params[:section], index: params[:index])
128
- return UITableViewCell.alloc.init unless data_cell # No data?
129
-
130
- table_cell = create_table_cell(data_cell)
131
-
132
- table_cell
113
+ params
133
114
  end
134
115
 
135
116
  def create_table_cell(data_cell)
136
- table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier])
137
-
138
- unless table_cell
117
+ table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier]) || begin
139
118
  table_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:data_cell[:cell_identifier])
140
- table_cell.extend PM::TableViewCellModule unless table_cell.is_a?(PM::TableViewCellModule)
119
+ table_cell.extend(PM::TableViewCellModule) unless table_cell.is_a?(PM::TableViewCellModule)
141
120
  table_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
142
121
  table_cell.clipsToBounds = true # fix for changed default in 7.1
122
+ table_cell
143
123
  end
144
-
145
124
  table_cell.setup(data_cell, self)
146
-
147
125
  table_cell
148
126
  end
149
127
 
150
128
  def update_table_data
151
129
  self.update_table_view_data(self.table_data)
130
+ self.promotion_table_data.search(search_string) if searching?
152
131
  end
153
132
 
154
133
  ########## Cocoa touch methods #################
155
134
  def numberOfSectionsInTableView(table_view)
156
- Array(self.promotion_table_data.data).length
135
+ self.promotion_table_data.sections.length
157
136
  end
158
137
 
159
138
  # Number of cells
@@ -162,8 +141,8 @@ module ProMotion
162
141
  end
163
142
 
164
143
  def tableView(table_view, titleForHeaderInSection:section)
165
- section = section_at_index(section) || return
166
- section[:title]
144
+ section = promotion_table_data.section(section)
145
+ section && section[:title]
167
146
  end
168
147
 
169
148
  # Set table_data_index if you want the right hand index column (jumplist)
@@ -179,8 +158,9 @@ module ProMotion
179
158
 
180
159
  def tableView(table_view, willDisplayCell: table_cell, forRowAtIndexPath: index_path)
181
160
  data_cell = self.promotion_table_data.cell(index_path: index_path)
182
- table_cell.backgroundColor = data_cell[:background_color] || UIColor.whiteColor
183
- table_cell.send(:restyle!) if table_cell.respond_to?(:restyle!)
161
+ set_attributes table_cell, data_cell[:style] if data_cell[:style]
162
+ table_cell.send(:will_display) if table_cell.respond_to?(:will_display)
163
+ table_cell.send(:restyle!) if table_cell.respond_to?(:restyle!) # Teacup compatibility
184
164
  end
185
165
 
186
166
  def tableView(table_view, heightForRowAtIndexPath:index_path)
@@ -190,26 +170,12 @@ module ProMotion
190
170
  def tableView(table_view, didSelectRowAtIndexPath:index_path)
191
171
  data_cell = self.promotion_table_data.cell(index_path: index_path)
192
172
  table_view.deselectRowAtIndexPath(index_path, animated: true) unless data_cell[:keep_selection] == true
193
-
194
- data_cell[:arguments] ||= {}
195
- data_cell[:arguments][:cell] = data_cell if data_cell[:arguments].is_a?(Hash) # TODO: Should we really do this?
196
-
197
173
  trigger_action(data_cell[:action], data_cell[:arguments]) if data_cell[:action]
198
174
  end
199
175
 
200
176
  def tableView(table_view, editingStyleForRowAtIndexPath: index_path)
201
177
  data_cell = self.promotion_table_data.cell(index_path: index_path)
202
-
203
- case data_cell[:editing_style]
204
- when nil, :none
205
- UITableViewCellEditingStyleNone
206
- when :delete
207
- UITableViewCellEditingStyleDelete
208
- when :insert
209
- UITableViewCellEditingStyleInsert
210
- else
211
- data_cell[:editing_style]
212
- end
178
+ map_cell_editing_style(data_cell[:editing_style])
213
179
  end
214
180
 
215
181
  def tableView(table_view, commitEditingStyle: editing_style, forRowAtIndexPath: index_path)
@@ -236,22 +202,16 @@ module ProMotion
236
202
 
237
203
  # Section view methods
238
204
  def tableView(table_view, viewForHeaderInSection: index)
239
- section = section_at_index(index)
240
-
241
- if section[:title_view]
242
- klass = section[:title_view]
243
- view = klass.new if klass.respond_to?(:new)
244
- view.title = section[:title] if view.respond_to?(:title=)
245
- view
246
- else
247
- nil
248
- end
205
+ section = promotion_table_data.section(index)
206
+ view = nil
207
+ view = section[:title_view].new if section[:title_view].respond_to?(:new)
208
+ view.title = section[:title] if view.respond_to?(:title=)
209
+ view
249
210
  end
250
211
 
251
212
  def tableView(table_view, heightForHeaderInSection: index)
252
- section = section_at_index(index)
253
-
254
- if section[:title_view] || (section[:title] && !section[:title].empty?)
213
+ section = promotion_table_data.section(index)
214
+ if section[:title_view] || section[:title].to_s.length > 0
255
215
  section[:title_view_height] || tableView.sectionHeaderHeight
256
216
  else
257
217
  0.0
@@ -260,10 +220,17 @@ module ProMotion
260
220
 
261
221
  protected
262
222
 
223
+ def map_cell_editing_style(symbol)
224
+ {
225
+ none: UITableViewCellEditingStyleNone,
226
+ delete: UITableViewCellEditingStyleDelete,
227
+ insert: UITableViewCellEditingStyleInsert
228
+ }[symbol] || symbol || UITableViewCellEditingStyleNone
229
+ end
230
+
263
231
  def map_row_animation_symbol(symbol)
264
232
  symbol ||= UITableViewRowAnimationAutomatic
265
233
  {
266
- automatic: UITableViewRowAnimationAutomatic,
267
234
  fade: UITableViewRowAnimationFade,
268
235
  right: UITableViewRowAnimationRight,
269
236
  left: UITableViewRowAnimationLeft,
@@ -272,7 +239,7 @@ module ProMotion
272
239
  none: UITableViewRowAnimationNone,
273
240
  middle: UITableViewRowAnimationMiddle,
274
241
  automatic: UITableViewRowAnimationAutomatic
275
- }[symbol] || symbol
242
+ }[symbol] || symbol || UITableViewRowAnimationAutomatic
276
243
  end
277
244
 
278
245
  module TableClassMethods
@@ -322,6 +289,19 @@ module ProMotion
322
289
  @indexable_params ||= nil
323
290
  end
324
291
 
292
+ # Longpressable
293
+ def longpressable(params = {})
294
+ @longpressable_params = params
295
+ @longpressable = true
296
+ end
297
+
298
+ def get_longpressable
299
+ @longpressable ||= false
300
+ end
301
+
302
+ def get_longpressable_params
303
+ @longpressable_params ||= nil
304
+ end
325
305
  end
326
306
 
327
307
  def self.included(base)