ProMotion 2.3.1 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22dee782b5f904dab39ce97ce900fe1012daf866
4
- data.tar.gz: 92a7e426f1d01a67fa8a8431d23f912109e14322
3
+ metadata.gz: 78d4da42d437262fe73051ce835ad8753426509b
4
+ data.tar.gz: eddb27a4dea01d3e8bca74b058516d7440a31f05
5
5
  SHA512:
6
- metadata.gz: ad1fd5927fa02167ecb552141242827953fc22288e625ab342ec592ff2ef26da757f76c37f7d88657cb5df7968873ca97188fd99f3abd7d545f324d4328cdc0b
7
- data.tar.gz: 773bb526a2679efdc727e460e59b087cdb8d599c3264c6838279605af19117ba0cbd2bf600c8849cffe2ee90a54732dc39608e67f616033d7edd8cffe6ea0b68
6
+ metadata.gz: db287d8260bf8fd89f2a2652e381ef11731694c81bec03cb0b0478286f5dbc70d22c919378e25679fe6bd4c180e77c826d22c6371a501c9817c5787d86900945
7
+ data.tar.gz: d5a780fa6df0bd7daab53f072d6f063f4fffd3f1eb1f0dc4a00e3f546b0b5827dd625a9fa851e1d2a36ad89f1949197cd22aa984484001e9d7e9ddac8b9296a9
data/README.md CHANGED
@@ -91,6 +91,16 @@ end
91
91
 
92
92
  # Changelog
93
93
 
94
+ ## Version 2.4.0
95
+
96
+ This release includes several new features and is backwards compatible with all 2.x releases.
97
+
98
+ * PR #686 Adds :searchable to the whitelisted properties a cell can have so that a warning is not generated.
99
+ * PR #688 Adds support for SDWebImage and takes preference over JMImageCache. _JMImageCache will still be supported till ProMotion 3.0 but we highly recommend you switch to SDWebImage._
100
+ * PR #679 Extract methods from tablescreen for reuse in modules for [redpotion](https://github.com/infinitered/redpotion).
101
+ * PR #677 Added `add_child_screen` and `remove_child_screen` methods to `PM::Screen`.
102
+ * PR #687 Adds persisting tab order when changed by the user for tab bars over 5 screens.
103
+
94
104
  ## Version 2.3.0
95
105
 
96
106
  This release includes several new features and is backwards compatible with all 2.x releases.
@@ -24,8 +24,13 @@ Motion::Project::App.setup do |app|
24
24
  ],
25
25
  "#{core_lib}/screen/screen.rb" => [ "#{core_lib}/screen/screen_module.rb" ],
26
26
  "#{core_lib}/screen/screen_module.rb" => [ "#{core_lib}/screen/screen_navigation.rb" ],
27
- "#{core_lib}/table/data/table_data.rb" => [ "#{core_lib}/table/table.rb" ],
27
+ "#{core_lib}/table/data/table_data.rb" => [
28
+ "#{core_lib}/table/data/table_data_builder.rb",
29
+ "#{core_lib}/table/table.rb"
30
+ ],
28
31
  "#{core_lib}/table/table.rb" => [
32
+ "#{core_lib}/table/table_class_methods.rb",
33
+ "#{core_lib}/table/table_builder.rb",
29
34
  "#{core_lib}/table/table_utils.rb",
30
35
  "#{core_lib}/table/extensions/searchable.rb",
31
36
  "#{core_lib}/table/extensions/refreshable.rb",
@@ -1,7 +1,6 @@
1
1
  module ProMotion
2
2
  class TabBarController < UITabBarController
3
-
4
- attr_accessor :pm_tab_delegate
3
+ attr_accessor :pm_tab_delegate, :name
5
4
 
6
5
  def self.new(*screens)
7
6
  tab_bar_controller = alloc.init
@@ -17,10 +16,25 @@ module ProMotion
17
16
  end
18
17
 
19
18
  tab_bar_controller.viewControllers = view_controllers
19
+ name = ""
20
20
  tab_bar_controller.delegate = tab_bar_controller
21
21
  tab_bar_controller
22
22
  end
23
23
 
24
+ def name=(n)
25
+ @name = n
26
+ tab_bar_order = NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_#{@name}")
27
+ if tab_bar_order
28
+ sorted_controllers = []
29
+ unsorted_controllers = self.viewControllers.copy
30
+ tab_bar_order.each do |order|
31
+ sorted_controllers << unsorted_controllers[order]
32
+ end
33
+ self.viewControllers = sorted_controllers
34
+ open_tab(0) # Open the tab on the far left
35
+ end
36
+ end
37
+
24
38
  def open_tab(tab)
25
39
  if tab.is_a? String
26
40
  selected_tab_vc = find_tab(tab)
@@ -48,6 +62,14 @@ module ProMotion
48
62
  on_tab_selected_try(vc)
49
63
  end
50
64
 
65
+ def tabBarController(tbc, didEndCustomizingViewControllers:vcs, changed:changed)
66
+ if changed
67
+ tab_order = vcs.map{ |vc| vc.tabBarItem.tag }
68
+ NSUserDefaults.standardUserDefaults.setObject(tab_order, forKey:"tab_bar_order_#{@name}")
69
+ NSUserDefaults.standardUserDefaults.synchronize
70
+ end
71
+ end
72
+
51
73
  def shouldAutorotate
52
74
  current_view_controller_try(:shouldAutorotate)
53
75
  end
@@ -25,45 +25,6 @@ module ProMotion
25
25
  self.modal == true
26
26
  end
27
27
 
28
- def resolve_title
29
- case self.class.title_type
30
- when :text then self.title = self.class.title
31
- when :view then self.navigationItem.titleView = self.class.title
32
- when :image then self.navigationItem.titleView = UIImageView.alloc.initWithImage(self.class.title)
33
- else
34
- PM.logger.warn("title expects string, UIView, or UIImage, but #{self.class.title.class.to_s} given.")
35
- end
36
- end
37
-
38
- def resolve_status_bar
39
- case self.class.status_bar_type
40
- when :none
41
- status_bar_hidden true
42
- when :light
43
- status_bar_hidden false
44
- status_bar_style UIStatusBarStyleLightContent
45
- when :dark
46
- status_bar_hidden false
47
- status_bar_style UIStatusBarStyleDefault
48
- else
49
- status_bar_hidden false
50
- global_style = NSBundle.mainBundle.objectForInfoDictionaryKey("UIStatusBarStyle")
51
- status_bar_style global_style ? Object.const_get(global_style) : UIStatusBarStyleDefault
52
- end
53
- end
54
-
55
- def add_nav_bar_buttons
56
- set_nav_bar_button(self.class.get_nav_bar_button[:side], self.class.get_nav_bar_button) if self.class.get_nav_bar_button
57
- end
58
-
59
- def status_bar_hidden(hidden)
60
- UIApplication.sharedApplication.setStatusBarHidden(hidden, withAnimation:self.class.status_bar_animation)
61
- end
62
-
63
- def status_bar_style(style)
64
- UIApplication.sharedApplication.setStatusBarStyle(style)
65
- end
66
-
67
28
  def parent_screen=(parent)
68
29
  @parent_screen = WeakRef.new(parent)
69
30
  end
@@ -176,10 +137,64 @@ module ProMotion
176
137
  return self.view_or_self.frame
177
138
  end
178
139
 
140
+ def add_child_screen(screen)
141
+ screen = screen.new if screen.respond_to?(:new)
142
+ addChildViewController(screen)
143
+ screen.parent_screen = WeakRef.new(self)
144
+ screen.didMoveToParentViewController(self) # Required
145
+ screen
146
+ end
147
+
148
+ def remove_child_screen(screen)
149
+ screen.parent_screen = nil
150
+ screen.willMoveToParentViewController(nil) # Required
151
+ screen.removeFromParentViewController
152
+ screen
153
+ end
154
+
179
155
  private
180
156
 
157
+ def resolve_title
158
+ case self.class.title_type
159
+ when :text then self.title = self.class.title
160
+ when :view then self.navigationItem.titleView = self.class.title
161
+ when :image then self.navigationItem.titleView = UIImageView.alloc.initWithImage(self.class.title)
162
+ else
163
+ PM.logger.warn("title expects string, UIView, or UIImage, but #{self.class.title.class.to_s} given.")
164
+ end
165
+ end
166
+
167
+ def resolve_status_bar
168
+ case self.class.status_bar_type
169
+ when :none
170
+ status_bar_hidden true
171
+ when :light
172
+ status_bar_hidden false
173
+ status_bar_style UIStatusBarStyleLightContent
174
+ when :dark
175
+ status_bar_hidden false
176
+ status_bar_style UIStatusBarStyleDefault
177
+ else
178
+ status_bar_hidden false
179
+ global_style = NSBundle.mainBundle.objectForInfoDictionaryKey("UIStatusBarStyle")
180
+ status_bar_style global_style ? Object.const_get(global_style) : UIStatusBarStyleDefault
181
+ end
182
+ end
183
+
184
+ def add_nav_bar_buttons
185
+ set_nav_bar_button(self.class.get_nav_bar_button[:side], self.class.get_nav_bar_button) if self.class.get_nav_bar_button
186
+ end
187
+
188
+ def status_bar_hidden(hidden)
189
+ UIApplication.sharedApplication.setStatusBarHidden(hidden, withAnimation:self.class.status_bar_animation)
190
+ end
191
+
192
+ def status_bar_style(style)
193
+ UIApplication.sharedApplication.setStatusBarStyle(style)
194
+ end
195
+
181
196
  def apply_properties(args)
182
- reserved_args = [ :nav_bar, :hide_nav_bar, :hide_tab_bar, :animated, :close_all, :in_tab, :in_detail, :in_master, :to_screen ]
197
+ reserved_args = [ :nav_bar, :hide_nav_bar, :hide_tab_bar, :animated, :close_all, :in_tab, :in_detail, :in_master, :to_screen, :toolbar ]
183
198
  set_attributes self, args.dup.delete_if { |k,v| reserved_args.include?(k) }
184
199
  end
185
200
 
@@ -23,7 +23,7 @@ module ProMotion
23
23
 
24
24
  # TODO: Remove this in ProMotion 2.1. Just for migration purposes.
25
25
  def check_deprecated_styles
26
- whitelist = [ :title, :subtitle, :image, :remote_image, :accessory, :selection_style, :action, :long_press_action, :arguments, :cell_style, :cell_class, :cell_identifier, :editing_style, :moveable, :search_text, :keep_selection, :height, :accessory_type, :style, :properties ]
26
+ whitelist = [ :title, :subtitle, :image, :remote_image, :accessory, :selection_style, :action, :long_press_action, :arguments, :cell_style, :cell_class, :cell_identifier, :editing_style, :moveable, :search_text, :keep_selection, :height, :accessory_type, :style, :properties, :searchable ]
27
27
  if (data_cell.keys - whitelist).length > 0
28
28
  PM.logger.deprecated("In #{self.table_screen.class.to_s}#table_data, you should set :#{(data_cell.keys - whitelist).join(", :")} in a `properties:` hash. See TableScreen documentation.")
29
29
  end
@@ -46,13 +46,26 @@ module ProMotion
46
46
  end
47
47
 
48
48
  def set_remote_image
49
- return unless data_cell[:remote_image] && jm_image_cache?
49
+ return unless data_cell[:remote_image] && (sd_web_image? || jm_image_cache?)
50
50
 
51
51
  self.imageView.image = remote_placeholder
52
- JMImageCache.sharedCache.imageForURL(data_cell[:remote_image][:url].to_url, completionBlock:proc { |downloaded_image|
53
- self.imageView.image = downloaded_image
54
- self.setNeedsLayout
55
- })
52
+
53
+ if sd_web_image?
54
+ @remote_image_operation = SDWebImageManager.sharedManager.downloadWithURL(data_cell[:remote_image][:url].to_url,
55
+ options:SDWebImageRefreshCached,
56
+ progress:nil,
57
+ completed: -> image, error, cacheType, finished {
58
+ self.imageView.image = image unless image.nil?
59
+ })
60
+ elsif jm_image_cache?
61
+ PM.logger.warning "'JMImageCache' is known to have issues with ProMotion. Please consider switching to 'SDWebImage'. 'JMImageCache' support will be deprecated in the next major version."
62
+ JMImageCache.sharedCache.imageForURL(data_cell[:remote_image][:url].to_url, completionBlock:proc { |downloaded_image|
63
+ self.imageView.image = downloaded_image
64
+ self.setNeedsLayout
65
+ })
66
+ else
67
+ PM.logger.error "To use remote_image with TableScreen you need to include the CocoaPod 'SDWebImage'."
68
+ end
56
69
 
57
70
  self.imageView.layer.masksToBounds = true
58
71
  self.imageView.layer.cornerRadius = data_cell[:remote_image][:radius] if data_cell[:remote_image][:radius]
@@ -89,12 +102,25 @@ module ProMotion
89
102
  self.accessoryType = map_accessory_type_symbol(data_cell[:accessory_type]) if data_cell[:accessory_type]
90
103
  end
91
104
 
105
+ def prepareForReuse
106
+ super
107
+ if @remote_image_operation && @remote_image_operation.respond_to?(:cancel)
108
+ @remote_image_operation.cancel
109
+ @remote_image_operation = nil
110
+ end
111
+ self.send(:prepare_for_reuse) if self.respond_to?(:prepare_for_reuse)
112
+ end
113
+
92
114
  private
93
115
 
116
+ def sd_web_image?
117
+ return false if RUBYMOTION_ENV == 'test'
118
+ !!defined?(SDWebImageManager)
119
+ end
120
+
94
121
  def jm_image_cache?
95
122
  return false if RUBYMOTION_ENV == 'test'
96
- return true if self.imageView.respond_to?("setImageWithURL:placeholder:")
97
- PM.logger.error "ProMotion Warning: to use remote_image with TableScreen you need to include the CocoaPod 'JMImageCache'."
123
+ !!defined?(JMImageCache)
98
124
  false
99
125
  end
100
126
 
@@ -1,6 +1,7 @@
1
1
  module ProMotion
2
2
  class TableData
3
3
  include ProMotion::Table::Utils
4
+ include ProMotion::TableDataBuilder
4
5
 
5
6
  attr_accessor :data, :filtered_data, :search_string, :original_search_string, :filtered, :table_view, :search_params
6
7
 
@@ -73,34 +74,6 @@ module ProMotion
73
74
  self.original_search_string = false
74
75
  end
75
76
 
76
- def set_data_cell_defaults(data_cell)
77
- data_cell[:cell_style] ||= begin
78
- data_cell[:subtitle] ? UITableViewCellStyleSubtitle : UITableViewCellStyleDefault
79
- end
80
- data_cell[:cell_class] ||= PM::TableViewCell
81
- data_cell[:cell_identifier] ||= build_cell_identifier(data_cell)
82
- data_cell[:properties] ||= data_cell[:style] || data_cell[:styles]
83
-
84
- data_cell[:accessory] = {
85
- view: data_cell[:accessory],
86
- value: data_cell[:accessory_value],
87
- action: data_cell[:accessory_action],
88
- arguments: data_cell[:accessory_arguments]
89
- } unless data_cell[:accessory].nil? || data_cell[:accessory].is_a?(Hash)
90
-
91
- data_cell
92
- end
93
-
94
- def build_cell_identifier(data_cell)
95
- ident = "#{data_cell[:cell_class].to_s}"
96
- ident << "-#{data_cell[:stylename].to_s}" if data_cell[:stylename] # For Teacup
97
- ident << "-accessory" if data_cell[:accessory]
98
- ident << "-subtitle" if data_cell[:subtitle]
99
- ident << "-remoteimage" if data_cell[:remote_image]
100
- ident << "-image" if data_cell[:image]
101
- ident
102
- end
103
-
104
77
  private
105
78
 
106
79
  def start_searching(search_string)
@@ -0,0 +1,31 @@
1
+ module ProMotion
2
+ module TableDataBuilder
3
+ def set_data_cell_defaults(data_cell)
4
+ data_cell[:cell_style] ||= begin
5
+ data_cell[:subtitle] ? UITableViewCellStyleSubtitle : UITableViewCellStyleDefault
6
+ end
7
+ data_cell[:cell_class] ||= PM::TableViewCell
8
+ data_cell[:cell_identifier] ||= build_cell_identifier(data_cell)
9
+ data_cell[:properties] ||= data_cell[:style] || data_cell[:styles]
10
+
11
+ data_cell[:accessory] = {
12
+ view: data_cell[:accessory],
13
+ value: data_cell[:accessory_value],
14
+ action: data_cell[:accessory_action],
15
+ arguments: data_cell[:accessory_arguments]
16
+ } unless data_cell[:accessory].nil? || data_cell[:accessory].is_a?(Hash)
17
+
18
+ data_cell
19
+ end
20
+
21
+ def build_cell_identifier(data_cell)
22
+ ident = "#{data_cell[:cell_class].to_s}"
23
+ ident << "-#{data_cell[:stylename].to_s}" if data_cell[:stylename] # For Teacup
24
+ ident << "-accessory" if data_cell[:accessory]
25
+ ident << "-subtitle" if data_cell[:subtitle]
26
+ ident << "-remoteimage" if data_cell[:remote_image]
27
+ ident << "-image" if data_cell[:image]
28
+ ident
29
+ end
30
+ end
31
+ end
@@ -1,6 +1,7 @@
1
1
  module ProMotion
2
2
  class GroupedTableScreen < TableViewController
3
3
  include ProMotion::ScreenModule
4
+ include ProMotion::TableBuilder
4
5
  include ProMotion::Table
5
6
  include ProMotion::Table::Utils # Workaround until https://hipbyte.freshdesk.com/support/tickets/2086 is fixed.
6
7
  include ProMotion::GroupedTable
@@ -6,6 +6,7 @@ module ProMotion
6
6
  include ProMotion::Table::Indexable
7
7
  include ProMotion::Table::Longpressable
8
8
  include ProMotion::Table::Utils
9
+ include ProMotion::TableBuilder
9
10
 
10
11
  attr_reader :promotion_table_data
11
12
 
@@ -129,15 +130,6 @@ module ProMotion
129
130
  @table_search_display_controller.searchResultsTableView.reloadData if searching?
130
131
  end
131
132
 
132
- def trigger_action(action, arguments, index_path)
133
- return PM.logger.info "Action not implemented: #{action.to_s}" unless self.respond_to?(action)
134
- case self.method(action).arity
135
- when 0 then self.send(action) # Just call the method
136
- when 2 then self.send(action, arguments, index_path) # Send arguments and index path
137
- else self.send(action, arguments) # Send arguments
138
- end
139
- end
140
-
141
133
  def accessory_toggled_switch(switch)
142
134
  table_cell = closest_parent(UITableViewCell, switch)
143
135
  index_path = closest_parent(UITableView, table_cell).indexPathForCell(table_cell)
@@ -162,29 +154,6 @@ module ProMotion
162
154
  table_view.deleteRowsAtIndexPaths(deletable_index_paths, withRowAnimation: map_row_animation_symbol(animation)) if deletable_index_paths.length > 0
163
155
  end
164
156
 
165
- def create_table_cell(data_cell)
166
- new_cell = nil
167
- table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier]) || begin
168
- new_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:data_cell[:cell_identifier])
169
- new_cell.extend(PM::TableViewCellModule) unless new_cell.is_a?(PM::TableViewCellModule)
170
- new_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
171
- new_cell.clipsToBounds = true # fix for changed default in 7.1
172
- on_cell_created new_cell, data_cell
173
- new_cell
174
- end
175
- table_cell.setup(data_cell, self) if table_cell.respond_to?(:setup)
176
- on_cell_reused(table_cell, data_cell) if !new_cell
177
- table_cell
178
- end
179
-
180
- def on_cell_created(new_cell, data_cell)
181
- new_cell.send(:on_load) if new_cell.respond_to?(:on_load)
182
- end
183
-
184
- def on_cell_reused(cell, data)
185
- cell.send(:on_reuse) if cell.respond_to?(:on_reuse)
186
- end
187
-
188
157
  def update_table_data(args = {})
189
158
  args = { index_paths: args } unless args.is_a?(Hash)
190
159
 
@@ -371,85 +340,6 @@ module ProMotion
371
340
  }[symbol] || symbol || UITableViewRowAnimationAutomatic
372
341
  end
373
342
 
374
- module TableClassMethods
375
- def table_style
376
- UITableViewStylePlain
377
- end
378
-
379
- def row_height(height, args={})
380
- if height == :auto
381
- if UIDevice.currentDevice.systemVersion.to_f < 8.0
382
- height = args[:estimated] || 44.0
383
- PM.logger.warn "Using `row_height :auto` is not supported in iOS 7 apps. Setting to #{height}."
384
- else
385
- height = UITableViewAutomaticDimension
386
- end
387
- end
388
- args[:estimated] ||= height unless height == UITableViewAutomaticDimension
389
- @row_height = { height: height, estimated: args[:estimated] || 44.0 }
390
- end
391
-
392
- def get_row_height
393
- @row_height ||= nil
394
- end
395
-
396
- # Searchable
397
- def searchable(params={})
398
- @searchable_params = params
399
- @searchable = true
400
- end
401
-
402
- def get_searchable_params
403
- @searchable_params ||= nil
404
- end
405
-
406
- def get_searchable
407
- @searchable ||= false
408
- end
409
-
410
- # Refreshable
411
- def refreshable(params = {})
412
- @refreshable_params = params
413
- @refreshable = true
414
- end
415
-
416
- def get_refreshable
417
- @refreshable ||= false
418
- end
419
-
420
- def get_refreshable_params
421
- @refreshable_params ||= nil
422
- end
423
-
424
- # Indexable
425
- def indexable(params = {})
426
- @indexable_params = params
427
- @indexable = true
428
- end
429
-
430
- def get_indexable
431
- @indexable ||= false
432
- end
433
-
434
- def get_indexable_params
435
- @indexable_params ||= nil
436
- end
437
-
438
- # Longpressable
439
- def longpressable(params = {})
440
- @longpressable_params = params
441
- @longpressable = true
442
- end
443
-
444
- def get_longpressable
445
- @longpressable ||= false
446
- end
447
-
448
- def get_longpressable_params
449
- @longpressable_params ||= nil
450
- end
451
- end
452
-
453
343
  def self.included(base)
454
344
  base.extend(TableClassMethods)
455
345
  end
@@ -0,0 +1,35 @@
1
+ module ProMotion
2
+ module TableBuilder
3
+ def trigger_action(action, arguments, index_path)
4
+ return PM.logger.info "Action not implemented: #{action.to_s}" unless self.respond_to?(action)
5
+ case self.method(action).arity
6
+ when 0 then self.send(action) # Just call the method
7
+ when 2 then self.send(action, arguments, index_path) # Send arguments and index path
8
+ else self.send(action, arguments) # Send arguments
9
+ end
10
+ end
11
+
12
+ def create_table_cell(data_cell)
13
+ new_cell = nil
14
+ table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier]) || begin
15
+ new_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:data_cell[:cell_identifier])
16
+ new_cell.extend(PM::TableViewCellModule) unless new_cell.is_a?(PM::TableViewCellModule)
17
+ new_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
18
+ new_cell.clipsToBounds = true # fix for changed default in 7.1
19
+ on_cell_created new_cell, data_cell
20
+ new_cell
21
+ end
22
+ table_cell.setup(data_cell, self) if table_cell.respond_to?(:setup)
23
+ on_cell_reused(table_cell, data_cell) if !new_cell
24
+ table_cell
25
+ end
26
+
27
+ def on_cell_created(new_cell, data_cell)
28
+ new_cell.send(:on_load) if new_cell.respond_to?(:on_load)
29
+ end
30
+
31
+ def on_cell_reused(cell, data)
32
+ cell.send(:on_reuse) if cell.respond_to?(:on_reuse)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,78 @@
1
+ module TableClassMethods
2
+ def table_style
3
+ UITableViewStylePlain
4
+ end
5
+
6
+ def row_height(height, args={})
7
+ if height == :auto
8
+ if UIDevice.currentDevice.systemVersion.to_f < 8.0
9
+ height = args[:estimated] || 44.0
10
+ PM.logger.warn "Using `row_height :auto` is not supported in iOS 7 apps. Setting to #{height}."
11
+ else
12
+ height = UITableViewAutomaticDimension
13
+ end
14
+ end
15
+ args[:estimated] ||= height unless height == UITableViewAutomaticDimension
16
+ @row_height = { height: height, estimated: args[:estimated] || 44.0 }
17
+ end
18
+
19
+ def get_row_height
20
+ @row_height ||= nil
21
+ end
22
+
23
+ # Searchable
24
+ def searchable(params={})
25
+ @searchable_params = params
26
+ @searchable = true
27
+ end
28
+
29
+ def get_searchable_params
30
+ @searchable_params ||= nil
31
+ end
32
+
33
+ def get_searchable
34
+ @searchable ||= false
35
+ end
36
+
37
+ # Refreshable
38
+ def refreshable(params = {})
39
+ @refreshable_params = params
40
+ @refreshable = true
41
+ end
42
+
43
+ def get_refreshable
44
+ @refreshable ||= false
45
+ end
46
+
47
+ def get_refreshable_params
48
+ @refreshable_params ||= nil
49
+ end
50
+
51
+ # Indexable
52
+ def indexable(params = {})
53
+ @indexable_params = params
54
+ @indexable = true
55
+ end
56
+
57
+ def get_indexable
58
+ @indexable ||= false
59
+ end
60
+
61
+ def get_indexable_params
62
+ @indexable_params ||= nil
63
+ end
64
+
65
+ # Longpressable
66
+ def longpressable(params = {})
67
+ @longpressable_params = params
68
+ @longpressable = true
69
+ end
70
+
71
+ def get_longpressable
72
+ @longpressable ||= false
73
+ end
74
+
75
+ def get_longpressable_params
76
+ @longpressable_params ||= nil
77
+ end
78
+ end
@@ -1,6 +1,7 @@
1
1
  module ProMotion
2
2
  class TableScreen < TableViewController
3
3
  include ProMotion::ScreenModule
4
+ include ProMotion::TableBuilder
4
5
  include ProMotion::Table
5
6
  end
6
7
  end
@@ -1,3 +1,3 @@
1
1
  module ProMotion
2
- VERSION = "2.3.1" unless defined?(ProMotion::VERSION)
2
+ VERSION = "2.4.0" unless defined?(ProMotion::VERSION)
3
3
  end
@@ -38,7 +38,33 @@ describe "ProMotion::TableScreen functionality" do
38
38
  end
39
39
  end
40
40
 
41
- end
41
+ it "no cells have fired prepare_for_reuse before scrolling" do
42
+ ip = NSIndexPath.indexPathForRow(0, inSection: 0)
43
+ cell = table_screen.tableView(table_screen.table_view, cellForRowAtIndexPath: ip)
44
+ cell.prepare_for_reuse_fired.should.not == true
45
+ end
42
46
 
47
+ it "cell has fired prepare_for_reuse after scrolling" do
48
+ ip = NSIndexPath.indexPathForRow(10, inSection: 0)
49
+ table_screen.tableView.scrollToRowAtIndexPath(ip, atScrollPosition: UITableViewScrollPositionTop, animated: false)
50
+ wait 0.001 do
51
+ ip = NSIndexPath.indexPathForRow(0, inSection: 0)
52
+ table_screen.tableView.scrollToRowAtIndexPath(ip, atScrollPosition: UITableViewScrollPositionTop, animated: false)
53
+
54
+ cell = views(TestCell).first
55
+ cell.prepare_for_reuse_fired.should == true
56
+ end
57
+ end
43
58
 
59
+ it "should fire prepare_for_reuse before on_reuse" do
60
+ ip = NSIndexPath.indexPathForRow(10, inSection: 0)
61
+ table_screen.tableView.scrollToRowAtIndexPath(ip, atScrollPosition: UITableViewScrollPositionTop, animated: false)
62
+ wait 0.001 do
63
+ ip = NSIndexPath.indexPathForRow(0, inSection: 0)
64
+ table_screen.tableView.scrollToRowAtIndexPath(ip, atScrollPosition: UITableViewScrollPositionTop, animated: false)
44
65
 
66
+ cell = views(TestCell).first
67
+ cell.prepare_for_reuse_time.should < cell.on_reuse_time
68
+ end
69
+ end
70
+ end
@@ -316,19 +316,19 @@ describe "screen with toolbar" do
316
316
 
317
317
  it "showing" do
318
318
  # Simulate AppDelegate setup of main screen
319
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
319
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
320
320
  screen.on_load
321
321
  screen.navigationController.toolbarHidden?.should == false
322
322
  end
323
323
 
324
324
  it "hidden" do
325
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: false
325
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: false)
326
326
  screen.on_load
327
327
  screen.navigationController.toolbarHidden?.should == true
328
328
  end
329
329
 
330
330
  it "adds a single item" do
331
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
331
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
332
332
  screen.on_load
333
333
  screen.set_toolbar_button([{title: "Testing Toolbar"}])
334
334
 
@@ -339,7 +339,7 @@ describe "screen with toolbar" do
339
339
  end
340
340
 
341
341
  it "adds multiple items" do
342
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
342
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
343
343
  screen.set_toolbar_buttons [{title: "Testing Toolbar"}, {title: "Another Test"}]
344
344
 
345
345
  screen.navigationController.toolbar.items.should.be.instance_of Array
@@ -349,7 +349,7 @@ describe "screen with toolbar" do
349
349
  end
350
350
 
351
351
  it "shows the toolbar when setting items" do
352
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: false
352
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: false)
353
353
  screen.on_load
354
354
  screen.navigationController.toolbarHidden?.should == true
355
355
  screen.set_toolbar_button([{title: "Testing Toolbar"}], false)
@@ -357,21 +357,21 @@ describe "screen with toolbar" do
357
357
  end
358
358
 
359
359
  it "doesn't show the toolbar when passed nil" do
360
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
360
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
361
361
  screen.on_load
362
362
  screen.set_toolbar_button(nil, false)
363
363
  screen.navigationController.toolbarHidden?.should == true
364
364
  end
365
365
 
366
366
  it "doesn't show the toolbar when passed false" do
367
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
367
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
368
368
  screen.on_load
369
369
  screen.set_toolbar_button(false, false)
370
370
  screen.navigationController.toolbarHidden?.should == true
371
371
  end
372
372
 
373
373
  it "hides the toolbar when passed nil" do
374
- screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
374
+ screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
375
375
  screen.on_load
376
376
  screen.set_toolbar_button([{title: "Testing Toolbar"}], false)
377
377
  screen.navigationController.toolbarHidden?.should == false
@@ -381,9 +381,9 @@ describe "screen with toolbar" do
381
381
 
382
382
  end
383
383
 
384
- describe 'toolbar tinted buttons' do
384
+ describe "toolbar tinted buttons" do
385
385
  before do
386
- @screen = HomeScreen.new modal: true, nav_bar: true, toolbar: true
386
+ @screen = HomeScreen.new(nav_bar: true, modal: true, toolbar: true)
387
387
  @screen.on_load
388
388
  end
389
389
 
@@ -403,3 +403,28 @@ describe 'toolbar tinted buttons' do
403
403
  end
404
404
 
405
405
  end
406
+
407
+ describe "child screen management" do
408
+ before do
409
+ @screen = HomeScreen.new
410
+ @child = BasicScreen.new
411
+ end
412
+
413
+ it "#add_child_screen" do
414
+ @screen.add_child_screen @child
415
+ @screen.childViewControllers.should.include(@child)
416
+ @screen.childViewControllers.length.should == 1
417
+ @child.parent_screen.should == @screen
418
+ end
419
+
420
+ it "#remove_child_screen" do
421
+ @screen.add_child_screen @child
422
+ @screen.childViewControllers.should.include(@child)
423
+ @screen.remove_child_screen @child
424
+ @screen.childViewControllers.length.should == 0
425
+ @child.parent_screen.should == nil
426
+ end
427
+
428
+ end
429
+
430
+
@@ -3,12 +3,12 @@ describe "tab bar functionality" do
3
3
  before do
4
4
  @app = TestDelegate.new
5
5
 
6
- @tab_1 = TabScreen.new
7
- @tab_2 = BasicScreen.new
8
- @tab_3 = HomeScreen.new
9
- @tab_4 = TestTableScreen.new
6
+ @tab_0 = TabScreen.new
7
+ @tab_1 = BasicScreen.new
8
+ @tab_2 = HomeScreen.new
9
+ @tab_3 = TestTableScreen.new
10
10
 
11
- @tab_bar = @app.open_tab_bar @tab_1, @tab_2, @tab_3, @tab_4
11
+ @tab_bar = @app.open_tab_bar @tab_0, @tab_1, @tab_2, @tab_3
12
12
  end
13
13
 
14
14
  after do
@@ -36,16 +36,85 @@ describe "tab bar functionality" do
36
36
  end
37
37
 
38
38
  it "should allow changing the tab bar item with set_tab_bar_item" do
39
- @tab_1.set_tab_bar_item title: "Custom", item: "test.jpeg"
39
+ @tab_0.set_tab_bar_item title: "Custom", item: "test.jpeg"
40
40
  @tab_bar.tabBar.items.first.title.should == "Custom"
41
41
  end
42
42
 
43
43
  it "should allow replacing a view controller with `open`" do
44
44
  new_screen = BasicScreen.new
45
- @tab_4.open new_screen, in_tab: "Home"
45
+ @tab_3.open new_screen, in_tab: "Home"
46
46
  @tab_bar.viewControllers[2].should == new_screen
47
47
  end
48
48
 
49
- end
49
+ describe "changing tab bar orders" do
50
+ before do
51
+ # Reset the user defaults
52
+ app_domain = NSBundle.mainBundle.bundleIdentifier
53
+ NSUserDefaults.standardUserDefaults.removePersistentDomainForName(app_domain)
54
+ NSUserDefaults.standardUserDefaults.synchronize
55
+
56
+ @tab_0 = TabScreen.new
57
+ @tab_1 = BasicScreen.new
58
+ @tab_2 = HomeScreen.new
59
+ @tab_3 = TestTableScreen.new
60
+ @tab_4 = PresentScreen.new
61
+ @tab_5 = TestWebScreen.new
62
+
63
+ @tab_bar = @app.open_tab_bar @tab_0, @tab_1, @tab_2, @tab_3, @tab_4, @tab_5
64
+ end
65
+
66
+ it "should start without a name" do
67
+ @tab_bar.name.should.be.nil
68
+ end
69
+
70
+ it "should set a name" do
71
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_test_tabs").should.be.nil
72
+ @tab_bar.name = "test_tabs"
73
+ @tab_bar.name.should == "test_tabs"
74
+ end
75
+
76
+ it "should not save the order when not changed" do
77
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_").should.be.nil
78
+ @tab_bar.tabBarController(@tab_bar, didEndCustomizingViewControllers:@tab_bar.viewControllers, changed:false)
79
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_").should.be.nil
80
+ end
81
+
82
+ it "should save an order without a name" do
83
+ @tab_bar.name = ""
84
+ new_order = [@tab_5, @tab_1, @tab_2, @tab_3, @tab_4, @tab_0]
85
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_").should.be.nil
86
+ @tab_bar.tabBarController(@tab_bar, didEndCustomizingViewControllers:new_order, changed:true)
87
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_").nil?.should == false
88
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_").should == [5, 1, 2, 3, 4, 0]
89
+ end
50
90
 
91
+ it "should save an order with a name" do
92
+ new_name = "test_tab_bar"
51
93
 
94
+ @tab_bar.name = new_name
95
+ new_order = [@tab_5, @tab_4, @tab_3, @tab_2, @tab_1, @tab_0]
96
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_#{new_name}").should.be.nil
97
+ @tab_bar.tabBarController(@tab_bar, didEndCustomizingViewControllers:new_order, changed:true)
98
+ NSUserDefaults.standardUserDefaults.arrayForKey("tab_bar_order_#{new_name}").should == [5, 4, 3, 2, 1, 0]
99
+ end
100
+
101
+ it "should persist order when reopening the tabs" do
102
+ @tab_bar.name = "test_tab_bar"
103
+ new_order = [@tab_5, @tab_4, @tab_3, @tab_2, @tab_1, @tab_0]
104
+ @tab_bar.tabBarController(@tab_bar, didEndCustomizingViewControllers:new_order, changed:true)
105
+
106
+ new_tab_bar = @app.open_tab_bar @tab_0, @tab_1, @tab_2, @tab_3, @tab_4, @tab_5
107
+ new_tab_bar.name = "test_tab_bar"
108
+ new_tab_bar.viewControllers.should == new_order
109
+ end
110
+
111
+ it "should always select the leftmost tab when rearranging tabs" do
112
+ new_order = [@tab_5, @tab_4, @tab_3, @tab_2, @tab_1, @tab_0]
113
+ @tab_bar.tabBarController(@tab_bar, didEndCustomizingViewControllers:new_order, changed:true)
114
+ new_tab_bar = @app.open_tab_bar @tab_0, @tab_1, @tab_2, @tab_3, @tab_4, @tab_5
115
+ new_tab_bar.selectedIndex.should == 0
116
+ end
117
+
118
+ end
119
+
120
+ end
@@ -24,7 +24,7 @@ describe "PM::Table module" do
24
24
  value: true # whether it's "checked" or not
25
25
  },
26
26
  image: { image: @image, radius: 15 },
27
- remote_image: { # remote image, requires JMImageCache CocoaPod
27
+ remote_image: { # remote image, requires SDWebImage CocoaPod
28
28
  url: "http://placekitten.com/200/300",
29
29
  placeholder: "some-local-image",
30
30
  size: 50,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ProMotion
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamon Holmgren
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-05-09 00:00:00.000000000 Z
13
+ date: 2015-05-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: methadone
@@ -119,6 +119,7 @@ files:
119
119
  - lib/ProMotion/support/support.rb
120
120
  - lib/ProMotion/table/cell/table_view_cell_module.rb
121
121
  - lib/ProMotion/table/data/table_data.rb
122
+ - lib/ProMotion/table/data/table_data_builder.rb
122
123
  - lib/ProMotion/table/extensions/indexable.rb
123
124
  - lib/ProMotion/table/extensions/longpressable.rb
124
125
  - lib/ProMotion/table/extensions/refreshable.rb
@@ -126,6 +127,8 @@ files:
126
127
  - lib/ProMotion/table/grouped_table.rb
127
128
  - lib/ProMotion/table/grouped_table_screen.rb
128
129
  - lib/ProMotion/table/table.rb
130
+ - lib/ProMotion/table/table_builder.rb
131
+ - lib/ProMotion/table/table_class_methods.rb
129
132
  - lib/ProMotion/table/table_screen.rb
130
133
  - lib/ProMotion/table/table_utils.rb
131
134
  - lib/ProMotion/tabs/tabs.rb
@@ -140,8 +143,8 @@ files:
140
143
  - spec/functional/func_web_screen_spec.rb
141
144
  - spec/helpers/test_helper.rb
142
145
  - spec/unit/delegate_spec.rb
143
- - spec/unit/image_title_screen.rb
144
- - spec/unit/image_view_title_screen.rb
146
+ - spec/unit/image_title_screen_spec.rb
147
+ - spec/unit/image_view_title_screen_spec.rb
145
148
  - spec/unit/load_view_spec.rb
146
149
  - spec/unit/logger_spec.rb
147
150
  - spec/unit/main_spec.rb
@@ -161,7 +164,7 @@ files:
161
164
  - spec/unit/tables/table_utils_spec.rb
162
165
  - spec/unit/tables/table_view_cell_spec.rb
163
166
  - spec/unit/view_helper_spec.rb
164
- - spec/unit/view_title_screen.rb
167
+ - spec/unit/view_title_screen_spec.rb
165
168
  - spec/unit/web_spec.rb
166
169
  homepage: https://github.com/clearsightstudio/ProMotion
167
170
  licenses:
@@ -183,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
186
  version: '0'
184
187
  requirements: []
185
188
  rubyforge_project:
186
- rubygems_version: 2.4.6
189
+ rubygems_version: 2.2.0
187
190
  signing_key:
188
191
  specification_version: 4
189
192
  summary: ProMotion is a fast way to get started building RubyMotion apps. Instead
@@ -200,8 +203,8 @@ test_files:
200
203
  - spec/functional/func_web_screen_spec.rb
201
204
  - spec/helpers/test_helper.rb
202
205
  - spec/unit/delegate_spec.rb
203
- - spec/unit/image_title_screen.rb
204
- - spec/unit/image_view_title_screen.rb
206
+ - spec/unit/image_title_screen_spec.rb
207
+ - spec/unit/image_view_title_screen_spec.rb
205
208
  - spec/unit/load_view_spec.rb
206
209
  - spec/unit/logger_spec.rb
207
210
  - spec/unit/main_spec.rb
@@ -221,5 +224,5 @@ test_files:
221
224
  - spec/unit/tables/table_utils_spec.rb
222
225
  - spec/unit/tables/table_view_cell_spec.rb
223
226
  - spec/unit/view_helper_spec.rb
224
- - spec/unit/view_title_screen.rb
227
+ - spec/unit/view_title_screen_spec.rb
225
228
  - spec/unit/web_spec.rb