ProMotion 0.7.8 → 1.0.0

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 (91) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +1 -1
  3. data/ProMotion.gemspec +2 -0
  4. data/README.md +51 -449
  5. data/Rakefile +11 -1
  6. data/app/screens/basic_screen.rb +0 -24
  7. data/lib/ProMotion/cocoatouch/{NavigationController.rb → navigation_controller.rb} +0 -0
  8. data/lib/ProMotion/cocoatouch/split_view_controller.rb +29 -0
  9. data/lib/ProMotion/cocoatouch/tab_bar_controller.rb +43 -0
  10. data/lib/ProMotion/cocoatouch/{TableViewCell.rb → table_view_cell.rb} +0 -1
  11. data/lib/ProMotion/cocoatouch/{TableViewController.rb → table_view_controller.rb} +0 -0
  12. data/lib/ProMotion/cocoatouch/{ViewController.rb → view_controller.rb} +6 -1
  13. data/lib/ProMotion/{screen_helpers → containers}/split_screen.rb +0 -2
  14. data/lib/ProMotion/containers/tabs.rb +95 -0
  15. data/lib/ProMotion/delegate/delegate.rb +2 -13
  16. data/lib/ProMotion/delegate/{delegate_helper.rb → delegate_module.rb} +29 -16
  17. data/lib/ProMotion/delegate/delegate_notifications.rb +17 -8
  18. data/lib/ProMotion/delegate/delegate_parent.rb +11 -0
  19. data/lib/ProMotion/extensions/conversions.rb +20 -0
  20. data/lib/ProMotion/{helpers/logger.rb → logger.rb} +0 -0
  21. data/lib/ProMotion/map/map_screen.rb +6 -0
  22. data/lib/ProMotion/map/map_screen_annotation.rb +56 -0
  23. data/lib/ProMotion/map/map_screen_module.rb +207 -0
  24. data/lib/ProMotion/{push_notifications → push_notification}/push_notification.rb +13 -6
  25. data/lib/ProMotion/{screens → screen}/screen.rb +1 -1
  26. data/lib/ProMotion/{screens/_screen_module.rb → screen/screen_module.rb} +76 -51
  27. data/lib/ProMotion/{screen_helpers → screen}/screen_navigation.rb +8 -12
  28. data/lib/ProMotion/{screens/_tables → table/cell}/table_view_cell_module.rb +18 -27
  29. data/lib/ProMotion/table/data/table_data.rb +98 -0
  30. data/lib/ProMotion/table/extensions/indexable.rb +9 -0
  31. data/lib/ProMotion/table/extensions/refreshable.rb +45 -0
  32. data/lib/ProMotion/table/extensions/searchable.rb +61 -0
  33. data/lib/ProMotion/table/grouped_table.rb +9 -0
  34. data/lib/ProMotion/table/grouped_table_screen.rb +6 -0
  35. data/lib/ProMotion/table/table.rb +312 -0
  36. data/lib/ProMotion/table/table_screen.rb +6 -0
  37. data/lib/ProMotion/{screens/_compatibility → thirdparty}/formotion_screen.rb +18 -5
  38. data/lib/ProMotion/version.rb +1 -1
  39. data/lib/ProMotion/view/styling.rb +137 -0
  40. data/lib/ProMotion/web/web_screen.rb +6 -0
  41. data/lib/ProMotion/web/web_screen_module.rb +155 -0
  42. data/resources/WebScreen.html +6 -0
  43. data/resources/test.jpeg +0 -0
  44. data/spec/functional/func_map_screen_spec.rb +105 -0
  45. data/spec/functional/func_screen_spec.rb +54 -7
  46. data/spec/functional/func_searchable_table_spec.rb +1 -1
  47. data/spec/functional/func_tab_bar_spec.rb +78 -0
  48. data/spec/functional/func_table_screen_spec.rb +61 -14
  49. data/spec/functional/func_web_screen_spec.rb +51 -0
  50. data/spec/helpers/map_screen.rb +51 -0
  51. data/spec/helpers/present_screen.rb +26 -0
  52. data/spec/helpers/tab_screen.rb +4 -0
  53. data/spec/helpers/table_screen.rb +12 -3
  54. data/spec/helpers/table_screen_formotion.rb +25 -0
  55. data/spec/helpers/table_screen_indexable.rb +13 -0
  56. data/spec/helpers/test_delegate.rb +28 -0
  57. data/spec/helpers/web_screen.rb +22 -0
  58. data/spec/unit/delegate_spec.rb +53 -4
  59. data/spec/unit/map_spec.rb +48 -0
  60. data/spec/unit/screen_helpers_spec.rb +24 -16
  61. data/spec/unit/screen_spec.rb +22 -18
  62. data/spec/unit/split_screen_in_tab_bar_spec.rb +2 -2
  63. data/spec/unit/split_screen_open_screen_spec.rb +15 -10
  64. data/spec/unit/split_screen_spec.rb +2 -2
  65. data/spec/unit/tab_spec.rb +41 -0
  66. data/spec/unit/tables/formotion_screen_spec.rb +16 -0
  67. data/spec/unit/tables/table_indexable_spec.rb +12 -0
  68. data/spec/unit/tables/table_module_spec.rb +24 -9
  69. data/spec/unit/tables/table_screen_spec.rb +1 -1
  70. data/spec/unit/tables/table_view_cell_spec.rb +9 -8
  71. data/spec/unit/view_helper_spec.rb +2 -2
  72. data/spec/unit/web_spec.rb +106 -0
  73. metadata +96 -35
  74. data/lib/ProMotion/cocoatouch/SplitViewController.rb +0 -23
  75. data/lib/ProMotion/helpers/console.rb +0 -29
  76. data/lib/ProMotion/helpers/measure_helper.rb +0 -20
  77. data/lib/ProMotion/helpers/system_helper.rb +0 -29
  78. data/lib/ProMotion/helpers/view_helper.rb +0 -82
  79. data/lib/ProMotion/screen_helpers/screen_elements.rb +0 -36
  80. data/lib/ProMotion/screen_helpers/screen_tabs.rb +0 -95
  81. data/lib/ProMotion/screens/_table_screen_module.rb +0 -47
  82. data/lib/ProMotion/screens/_tables/_refreshable_table.rb +0 -45
  83. data/lib/ProMotion/screens/_tables/_searchable_table.rb +0 -60
  84. data/lib/ProMotion/screens/_tables/_sectioned_table.rb +0 -5
  85. data/lib/ProMotion/screens/_tables/_table.rb +0 -169
  86. data/lib/ProMotion/screens/_tables/grouped_table.rb +0 -16
  87. data/lib/ProMotion/screens/_tables/plain_table.rb +0 -17
  88. data/lib/ProMotion/screens/_tables/table_data.rb +0 -175
  89. data/lib/ProMotion/screens/behaves_like_screen.rb +0 -10
  90. data/lib/ProMotion/screens/table_screen.rb +0 -16
  91. data/spec/unit/ios_version_spec.rb +0 -28
@@ -8,13 +8,11 @@ module ProMotion
8
8
  screen = set_up_screen_for_open(screen, args)
9
9
  ensure_wrapper_controller_in_place(screen, args)
10
10
 
11
- screen.send(:on_load) if screen.respond_to?(:on_load)
12
-
13
11
  if args[:in_detail] && self.split_screen
14
12
  self.split_screen.detail_screen = screen
15
13
 
16
14
  elsif args[:in_master] && self.split_screen
17
- self.split_screen.master_screen = screen
15
+ self.split_screen.master_screen = screen
18
16
 
19
17
  elsif args[:close_all]
20
18
  open_root_screen screen
@@ -29,10 +27,11 @@ module ProMotion
29
27
  push_view_controller screen
30
28
 
31
29
  else
32
- open_root_screen screen.pm_main_controller
30
+ open_root_screen (screen.navigationController || screen)
33
31
 
34
32
  end
35
33
 
34
+ screen
36
35
  end
37
36
  alias :open :open_screen
38
37
 
@@ -77,11 +76,6 @@ module ProMotion
77
76
  end
78
77
  end
79
78
 
80
- def open_view_controller(screen)
81
- PM.logger.deprecated "Use `open_root_screen` instead of the more ambiguous `open_view_controller`."
82
- open_root_screen screen
83
- end
84
-
85
79
  def push_view_controller(vc, nav_controller=nil)
86
80
  unless self.navigation_controller
87
81
  PM.logger.error "You need a nav_bar if you are going to push #{vc.to_s} onto it."
@@ -98,7 +92,7 @@ module ProMotion
98
92
 
99
93
  # Instantiate screen if given a class
100
94
  screen = screen.new if screen.respond_to?(:new)
101
-
95
+
102
96
  # Set parent
103
97
  screen.parent_screen = self if screen.respond_to?(:parent_screen=)
104
98
 
@@ -125,7 +119,7 @@ module ProMotion
125
119
  end
126
120
 
127
121
  def present_modal_view_controller(screen, animated)
128
- self.presentModalViewController(screen.pm_main_controller, animated:animated)
122
+ self.presentModalViewController((screen.navigationController || screen), animated:animated)
129
123
  end
130
124
 
131
125
  def present_view_controller_in_tab_bar_controller(screen, tab_name)
@@ -155,7 +149,9 @@ module ProMotion
155
149
 
156
150
  def close_nav_screen(args={})
157
151
  args[:animated] = true unless args.has_key?(:animated)
158
- if args[:to_screen] && args[:to_screen].is_a?(UIViewController)
152
+ if args[:to_screen] == :root
153
+ self.navigation_controller.popToRootViewControllerAnimated args[:animated]
154
+ elsif args[:to_screen] && args[:to_screen].is_a?(UIViewController)
159
155
  self.parent_screen = args[:to_screen]
160
156
  self.navigation_controller.popToViewController(args[:to_screen], animated: args[:animated])
161
157
  else
@@ -1,16 +1,15 @@
1
1
  module ProMotion
2
2
  module TableViewCellModule
3
- include ViewHelper
3
+ include Styling
4
4
 
5
- attr_accessor :data_cell
5
+ attr_accessor :data_cell, :table_screen
6
6
 
7
- def setup(data_cell)
7
+ def setup(data_cell, screen)
8
+ self.table_screen = WeakRef.new(screen)
8
9
  self.data_cell = data_cell
9
10
 
10
11
  # TODO: Some of these need to go away. Unnecessary overhead.
11
12
  set_cell_attributes
12
- set_background_color
13
- set_class_attributes
14
13
  set_accessory_view
15
14
  set_subtitle
16
15
  set_image
@@ -25,33 +24,25 @@ module ProMotion
25
24
 
26
25
  def set_cell_attributes
27
26
  data_cell_attributes = data_cell.dup
28
- [:image, :accessory_action].each { |k| data_cell_attributes.delete(k) }
27
+ [:image, :accessory_action, :editing_style].each { |k| data_cell_attributes.delete(k) }
29
28
  set_attributes self, data_cell_attributes
30
29
  self
31
30
  end
32
31
 
33
- def set_background_color
34
- self.backgroundView = UIView.new.tap{|v| v.backgroundColor = data_cell[:background_color]} if data_cell[:background_color]
35
- end
36
-
37
- def set_class_attributes
38
- if data_cell[:cell_class_attributes]
39
- PM.logger.deprecated "`cell_class_attributes` is deprecated. Just add the attributes you want to set right into your cell hash."
40
- set_attributes self, data_cell[:cell_class_attributes]
41
- end
42
- self
43
- end
44
-
45
32
  def set_accessory_view
46
- if data_cell[:accessory][:view] == :switch
47
- switch_view = UISwitch.alloc.initWithFrame(CGRectZero)
48
- switch_view.setAccessibilityLabel(data_cell[:accessory][:accessibility_label]) if data_cell[:accessory][:accessibility_label]
49
- switch_view.addTarget(self.closest_parent(UITableView), action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
50
- switch_view.on = true if data_cell[:accessory][:value]
51
- self.accessoryView = switch_view
52
- elsif data_cell[:accessory][:view]
53
- self.accessoryView = data_cell[:accessory][:view]
54
- self.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
33
+ if data_cell[:accessory]
34
+ if data_cell[:accessory][:view] == :switch
35
+ switch_view = UISwitch.alloc.initWithFrame(CGRectZero)
36
+ switch_view.setAccessibilityLabel(data_cell[:accessory][:accessibility_label] || data_cell[:title])
37
+ switch_view.addTarget(self.table_screen, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
38
+ switch_view.on = !!data_cell[:accessory][:value]
39
+ self.accessoryView = switch_view
40
+ elsif data_cell[:accessory][:view]
41
+ self.accessoryView = data_cell[:accessory][:view]
42
+ self.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
43
+ end
44
+ else
45
+ self.accessoryView = nil
55
46
  end
56
47
 
57
48
  self
@@ -0,0 +1,98 @@
1
+ module ProMotion
2
+ class TableData
3
+ attr_accessor :data, :filtered_data, :filtered, :table_view
4
+
5
+ def initialize(data, table_view)
6
+ self.data = data
7
+ self.table_view = table_view
8
+ end
9
+
10
+ def section(index)
11
+ s = sections.at(index)
12
+ s || { title: nil, cells: [] }
13
+ end
14
+
15
+ def sections
16
+ self.filtered ? self.filtered_data : self.data
17
+ end
18
+
19
+ def section_length(index)
20
+ section(index)[:cells].length
21
+ end
22
+
23
+ def cell(params={})
24
+ if params[:index_path]
25
+ params[:section] = params[:index_path].section
26
+ params[:index] = params[:index_path].row
27
+ end
28
+
29
+ table_section = self.section(params[:section])
30
+ c = table_section[:cells].at(params[:index].to_i)
31
+ set_data_cell_defaults c
32
+ end
33
+
34
+ def delete_cell(params={})
35
+ if params[:index_path]
36
+ params[:section] = params[:index_path].section
37
+ params[:index] = params[:index_path].row
38
+ end
39
+
40
+ table_section = self.section(params[:section])
41
+ table_section[:cells].delete_at(params[:index].to_i)
42
+ end
43
+
44
+ def search(search_string)
45
+ self.filtered_data = []
46
+ self.filtered = true
47
+
48
+ search_string = search_string.downcase.strip
49
+
50
+ self.data.compact.each do |section|
51
+ new_section = {}
52
+ new_section[:cells] = []
53
+
54
+ new_section[:cells] = section[:cells].map do |cell|
55
+ cell[:searchable] != false && "#{cell[:title]}\n#{cell[:search_text]}".downcase.strip.include?(search_string) ? cell : nil
56
+ end.compact
57
+
58
+ if new_section[:cells] && new_section[:cells].length > 0
59
+ new_section[:title] = section[:title]
60
+ self.filtered_data << new_section
61
+ end
62
+ end
63
+
64
+ self.filtered_data
65
+ end
66
+
67
+ def stop_searching
68
+ self.filtered_data = []
69
+ self.filtered = false
70
+ end
71
+
72
+ def set_data_cell_defaults(data_cell)
73
+ data_cell[:cell_style] ||= UITableViewCellStyleDefault
74
+ data_cell[:cell_class] ||= PM::TableViewCell
75
+ data_cell[:cell_identifier] ||= build_cell_identifier(data_cell)
76
+
77
+ data_cell[:accessory] = {
78
+ view: data_cell[:accessory],
79
+ value: data_cell[:accessory_value],
80
+ action: data_cell[:accessory_action],
81
+ arguments: data_cell[:accessory_arguments]
82
+ } unless data_cell[:accessory].nil? || data_cell[:accessory].is_a?(Hash)
83
+
84
+ data_cell
85
+ end
86
+
87
+ def build_cell_identifier(data_cell)
88
+ ident = "#{data_cell[:cell_class].to_s}"
89
+ ident << "-#{data_cell[:stylename].to_s}" if data_cell[:stylename] # For Teacup
90
+ ident << "-accessory" if data_cell[:accessory]
91
+ ident << "-subtitle" if data_cell[:subtitle]
92
+ ident << "-remoteimage" if data_cell[:remote_image]
93
+ ident << "-image" if data_cell[:image]
94
+ ident
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,9 @@
1
+ module ProMotion
2
+ module Table
3
+ module Indexable
4
+ def index_from_section_titles
5
+ @promotion_table_data.filtered ? nil : @promotion_table_data.sections.collect{ |section| section[:title][0] }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ module ProMotion
2
+ module Table
3
+ module Refreshable
4
+ def make_refreshable(params={})
5
+ pull_message = params[:pull_message] || "Pull to refresh"
6
+ @refreshing = params[:refreshing] || "Refreshing data..."
7
+ @updated_format = params[:updated_format] || "Last updated at %s"
8
+ @updated_time_format = params[:updated_time_format] || "%l:%M %p"
9
+ @refreshable_callback = params[:callback] || :on_refresh
10
+
11
+ @refresh_control = UIRefreshControl.alloc.init
12
+ @refresh_control.attributedTitle = NSAttributedString.alloc.initWithString(pull_message)
13
+ @refresh_control.addTarget(self, action:'refreshView:', forControlEvents:UIControlEventValueChanged)
14
+ self.refreshControl = @refresh_control
15
+ end
16
+
17
+ def start_refreshing
18
+ return unless @refresh_control
19
+
20
+ @refresh_control.beginRefreshing
21
+ end
22
+ alias :begin_refreshing :start_refreshing
23
+
24
+ def end_refreshing
25
+ return unless @refresh_control
26
+
27
+ @refresh_control.attributedTitle = NSAttributedString.alloc.initWithString(sprintf(@updated_format, Time.now.strftime(@updated_time_format)))
28
+ @refresh_control.endRefreshing
29
+ end
30
+ alias :stop_refreshing :end_refreshing
31
+
32
+ ######### iOS methods, headless camel case #######
33
+
34
+ # UIRefreshControl Delegates
35
+ def refreshView(refresh)
36
+ refresh.attributedTitle = NSAttributedString.alloc.initWithString(@refreshing)
37
+ if @refreshable_callback && self.respond_to?(@refreshable_callback)
38
+ self.send(@refreshable_callback)
39
+ else
40
+ PM.logger.warn "You must implement the '#{@refreshable_callback}' method in your TableScreen."
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,61 @@
1
+ module ProMotion
2
+ module Table
3
+ module Searchable
4
+
5
+ def make_searchable(params={})
6
+ params = set_searchable_param_defaults(params)
7
+
8
+ search_bar = create_search_bar(params)
9
+
10
+ if params[:search_bar] && params[:search_bar][:placeholder]
11
+ search_bar.placeholder = params[:search_bar][:placeholder]
12
+ end
13
+
14
+ @table_search_display_controller = UISearchDisplayController.alloc.initWithSearchBar(search_bar, contentsController: params[:content_controller])
15
+ @table_search_display_controller.delegate = params[:delegate]
16
+ @table_search_display_controller.searchResultsDataSource = params[:data_source]
17
+ @table_search_display_controller.searchResultsDelegate = params[:search_results_delegate]
18
+
19
+ self.table_view.tableHeaderView = search_bar
20
+ end
21
+ alias :makeSearchable :make_searchable
22
+
23
+ def set_searchable_param_defaults(params)
24
+ params[:content_controller] ||= params[:contentController]
25
+ params[:data_source] ||= params[:searchResultsDataSource]
26
+ params[:search_results_delegate] ||= params[:searchResultsDelegate]
27
+
28
+ params[:frame] ||= CGRectMake(0, 0, 320, 44) # TODO: Don't hardcode this...
29
+ params[:content_controller] ||= self
30
+ params[:delegate] ||= self
31
+ params[:data_source] ||= self
32
+ params[:search_results_delegate] ||= self
33
+ params
34
+ end
35
+
36
+ def create_search_bar(params)
37
+ search_bar = UISearchBar.alloc.initWithFrame(params[:frame])
38
+ search_bar.autoresizingMask = UIViewAutoresizingFlexibleWidth
39
+ search_bar
40
+ end
41
+
42
+ ######### iOS methods, headless camel case #######
43
+
44
+ def searchDisplayController(controller, shouldReloadTableForSearchString:search_string)
45
+ @promotion_table_data.search(search_string)
46
+ true
47
+ end
48
+
49
+ def searchDisplayControllerWillEndSearch(controller)
50
+ @promotion_table_data.stop_searching
51
+ @promotion_table_data_data = nil
52
+ self.table_view.setScrollEnabled true
53
+ self.table_view.reloadData
54
+ end
55
+
56
+ def searchDisplayControllerWillBeginSearch(controller)
57
+ self.table_view.setScrollEnabled false
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,9 @@
1
+ module ProMotion
2
+ module GroupedTable
3
+ include ProMotion::Table
4
+
5
+ def table_style
6
+ UITableViewStyleGrouped
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module ProMotion
2
+ class GroupedTableScreen < TableViewController
3
+ include ProMotion::ScreenModule
4
+ include ProMotion::GroupedTable
5
+ end
6
+ end
@@ -0,0 +1,312 @@
1
+ module ProMotion
2
+ module Table
3
+
4
+ include ProMotion::Styling
5
+ include ProMotion::Table::Searchable
6
+ include ProMotion::Table::Refreshable
7
+ include ProMotion::Table::Indexable
8
+
9
+ def table_view
10
+ @table_view ||= begin
11
+ t = UITableView.alloc.initWithFrame(self.view.frame, style: table_style)
12
+ t.dataSource = self
13
+ t.delegate = self
14
+ t
15
+ end
16
+ end
17
+
18
+ def table_style
19
+ UITableViewStylePlain
20
+ end
21
+
22
+ def screen_setup
23
+ check_table_data
24
+ set_up_table_view
25
+ set_up_searchable
26
+ set_up_refreshable
27
+ end
28
+
29
+ def check_table_data
30
+ PM.logger.error "Missing #table_data method in TableScreen #{self.class.to_s}." unless self.respond_to?(:table_data)
31
+ end
32
+
33
+ def set_up_table_view
34
+ self.view = self.create_table_view_from_data(self.table_data)
35
+ end
36
+
37
+ def set_up_searchable
38
+ if self.class.respond_to?(:get_searchable) && self.class.get_searchable
39
+ self.make_searchable(content_controller: self, search_bar: self.class.get_searchable_params)
40
+ end
41
+ end
42
+
43
+ def set_up_refreshable
44
+ if self.class.respond_to?(:get_refreshable) && self.class.get_refreshable
45
+ if defined?(UIRefreshControl)
46
+ self.make_refreshable(self.class.get_refreshable_params)
47
+ else
48
+ PM.logger.warn "To use the refresh control on < iOS 6, you need to include the CocoaPod 'CKRefreshControl'."
49
+ end
50
+ end
51
+ end
52
+
53
+ def create_table_view_from_data(data)
54
+ @promotion_table_data = TableData.new(data, table_view)
55
+ table_view
56
+ end
57
+
58
+ def searching?
59
+ @promotion_table_data.filtered
60
+ end
61
+
62
+ def update_table_view_data(data)
63
+ @promotion_table_data.data = data
64
+ table_view.reloadData
65
+ end
66
+
67
+ # Methods to retrieve data
68
+
69
+ def section_at_index(index)
70
+ @promotion_table_data.section(index)
71
+ end
72
+
73
+ def cell_at_section_and_index(section, index)
74
+ @promotion_table_data.cell(section: section, index: index)
75
+ end
76
+
77
+ 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
90
+ end
91
+
92
+ def accessory_toggled_switch(switch)
93
+ table_cell = closest_parent(UITableViewCell, switch)
94
+ index_path = closest_parent(UITableView, table_cell).indexPathForCell(table_cell)
95
+
96
+ if index_path
97
+ data_cell = cell_at_section_and_index(index_path.section, index_path.row)
98
+ data_cell[:accessory][:arguments] ||= {}
99
+ data_cell[:accessory][:arguments][:value] = switch.isOn if data_cell[:accessory][:arguments].is_a?(Hash)
100
+
101
+ trigger_action(data_cell[:accessory][:action], data_cell[:accessory][:arguments]) if data_cell[:accessory][:action]
102
+ end
103
+ end
104
+
105
+ def delete_row(index_paths, animation = nil)
106
+ animation = map_row_animation_symbol(animation)
107
+ index_paths = Array(index_paths)
108
+ deletable_index_paths = []
109
+
110
+ index_paths.each do |index_path|
111
+ delete_cell = false
112
+ delete_cell = send(:on_cell_deleted, @promotion_table_data.cell(index_path: index_path)) if self.respond_to?("on_cell_deleted:")
113
+ unless delete_cell == false
114
+ @promotion_table_data.delete_cell(index_path: index_path)
115
+ deletable_index_paths << index_path
116
+ end
117
+ end
118
+ table_view.deleteRowsAtIndexPaths(deletable_index_paths, withRowAnimation:animation) if deletable_index_paths.length > 0
119
+ end
120
+
121
+ def table_view_cell(params={})
122
+ if params[:index_path]
123
+ params[:section] = params[:index_path].section
124
+ params[:index] = params[:index_path].row
125
+ end
126
+
127
+ data_cell = @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
133
+ end
134
+
135
+ def create_table_cell(data_cell)
136
+ table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier])
137
+
138
+ unless table_cell
139
+ data_cell[:cell_style] ||= UITableViewCellStyleSubtitle
140
+ table_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:data_cell[:cell_identifier])
141
+ table_cell.extend PM::TableViewCellModule unless table_cell.is_a?(PM::TableViewCellModule)
142
+ table_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
143
+ end
144
+
145
+ table_cell.setup(data_cell, self)
146
+
147
+ table_cell
148
+ end
149
+
150
+ def update_table_data
151
+ self.update_table_view_data(self.table_data)
152
+ end
153
+
154
+ ########## Cocoa touch methods #################
155
+ def numberOfSectionsInTableView(table_view)
156
+ return @promotion_table_data.data.size
157
+ end
158
+
159
+ # Number of cells
160
+ def tableView(table_view, numberOfRowsInSection:section)
161
+ return @promotion_table_data.section_length(section)
162
+ 0
163
+ end
164
+
165
+ def tableView(table_view, titleForHeaderInSection:section)
166
+ return section_at_index(section)[:title] if section_at_index(section) && section_at_index(section)[:title]
167
+ end
168
+
169
+ # Set table_data_index if you want the right hand index column (jumplist)
170
+ def sectionIndexTitlesForTableView(table_view)
171
+ if @promotion_table_data.filtered
172
+ nil
173
+ else
174
+ if self.respond_to?(:table_data_index)
175
+ self.table_data_index
176
+ elsif self.class.get_indexable
177
+ self.index_from_section_titles
178
+ else
179
+ nil
180
+ end
181
+ end
182
+ end
183
+
184
+ def tableView(table_view, cellForRowAtIndexPath:index_path)
185
+ table_view_cell(index_path: index_path)
186
+ end
187
+
188
+ def tableView(table_view, willDisplayCell: table_cell, forRowAtIndexPath: index_path)
189
+ data_cell = @promotion_table_data.cell(index_path: index_path)
190
+ table_cell.backgroundColor = data_cell[:background_color] || UIColor.whiteColor
191
+ table_cell.send(:restyle!) if table_cell.respond_to?(:restyle!)
192
+ end
193
+
194
+ def tableView(table_view, heightForRowAtIndexPath:index_path)
195
+ (@promotion_table_data.cell(index_path: index_path)[:height] || table_view.rowHeight).to_f
196
+ end
197
+
198
+ def tableView(table_view, didSelectRowAtIndexPath:index_path)
199
+ data_cell = @promotion_table_data.cell(index_path: index_path)
200
+ table_view.deselectRowAtIndexPath(index_path, animated: true)
201
+
202
+ data_cell[:arguments] ||= {}
203
+ data_cell[:arguments][:cell] = data_cell if data_cell[:arguments].is_a?(Hash) # TODO: Should we really do this?
204
+
205
+ trigger_action(data_cell[:action], data_cell[:arguments]) if data_cell[:action]
206
+ end
207
+
208
+ def tableView(table_view, editingStyleForRowAtIndexPath: index_path)
209
+ data_cell = @promotion_table_data.cell(index_path: index_path)
210
+
211
+ case data_cell[:editing_style]
212
+ when nil, :none
213
+ UITableViewCellEditingStyleNone
214
+ when :delete
215
+ UITableViewCellEditingStyleDelete
216
+ when :insert
217
+ UITableViewCellEditingStyleInsert
218
+ else
219
+ data_cell[:editing_style]
220
+ end
221
+ end
222
+
223
+ def tableView(table_view, commitEditingStyle: editing_style, forRowAtIndexPath: index_path)
224
+ if editing_style == UITableViewCellEditingStyleDelete
225
+ delete_row(index_path)
226
+ end
227
+ end
228
+
229
+ def tableView(tableView, sectionForSectionIndexTitle:title, atIndex:index)
230
+ return index unless ["{search}", UITableViewIndexSearch].include?(self.table_data_index[0])
231
+
232
+ if index == 0
233
+ tableView.setContentOffset(CGPointZero, animated:false)
234
+ NSNotFound
235
+ else
236
+ index - 1
237
+ end
238
+ end
239
+
240
+ def deleteRowsAtIndexPaths(index_paths, withRowAnimation:animation)
241
+ PM.logger.warn "ProMotion expects you to use 'delete_cell(index_paths, animation)'' instead of 'deleteRowsAtIndexPaths(index_paths, withRowAnimation:animation)'."
242
+ delete_row(index_paths, animation)
243
+ end
244
+
245
+ protected
246
+
247
+ def map_row_animation_symbol(symbol)
248
+ symbol ||= UITableViewRowAnimationAutomatic
249
+ {
250
+ automatic: UITableViewRowAnimationAutomatic,
251
+ fade: UITableViewRowAnimationFade,
252
+ right: UITableViewRowAnimationRight,
253
+ left: UITableViewRowAnimationLeft,
254
+ top: UITableViewRowAnimationTop,
255
+ bottom: UITableViewRowAnimationBottom,
256
+ none: UITableViewRowAnimationNone,
257
+ middle: UITableViewRowAnimationMiddle,
258
+ automatic: UITableViewRowAnimationAutomatic
259
+ }[symbol] || symbol
260
+ end
261
+
262
+ module TableClassMethods
263
+ # Searchable
264
+ def searchable(params={})
265
+ @searchable_params = params
266
+ @searchable = true
267
+ end
268
+
269
+ def get_searchable_params
270
+ @searchable_params ||= nil
271
+ end
272
+
273
+ def get_searchable
274
+ @searchable ||= false
275
+ end
276
+
277
+ # Refreshable
278
+ def refreshable(params = {})
279
+ @refreshable_params = params
280
+ @refreshable = true
281
+ end
282
+
283
+ def get_refreshable
284
+ @refreshable ||= false
285
+ end
286
+
287
+ def get_refreshable_params
288
+ @refreshable_params ||= nil
289
+ end
290
+
291
+ # Indexable
292
+ def indexable(params = {})
293
+ @indexable_params = params
294
+ @indexable = true
295
+ end
296
+
297
+ def get_indexable
298
+ @indexable ||= false
299
+ end
300
+
301
+ def get_indexable_params
302
+ @indexable_params ||= nil
303
+ end
304
+
305
+ end
306
+
307
+ def self.included(base)
308
+ base.extend(TableClassMethods)
309
+ end
310
+
311
+ end
312
+ end