ProMotion 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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