mirror of
https://github.com/zhigang1992/ProMotion.git
synced 2026-06-02 06:49:45 +08:00
Merge pull request #101 from clearsightstudio/feature/table_cleanup
TableScreen Refactor
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
module ProMotion
|
||||
class TableViewCell < UITableViewCell
|
||||
include TableViewCellModule
|
||||
|
||||
attr_accessor :image_size
|
||||
|
||||
|
||||
# TODO: Is this necessary?
|
||||
def layoutSubviews
|
||||
super
|
||||
|
||||
@@ -12,5 +15,6 @@ module ProMotion
|
||||
self.imageView.frame = CGRectInset(f, size_inset_x, size_inset_y)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -11,10 +11,10 @@ module ProMotion
|
||||
if v.is_a?(Hash) && element.respond_to?(k)
|
||||
sub_element = element.send(k)
|
||||
set_attributes(sub_element, v) if sub_element
|
||||
elsif v.is_a?(Array) && element.respond_to?("#{k}")
|
||||
element.send("#{k}", *v)
|
||||
elsif element.respond_to?("#{k}=")
|
||||
element.send("#{k}=", v)
|
||||
elsif v.is_a?(Array) && element.respond_to?("#{k}") && element.method("#{k}").arity == v.length
|
||||
element.send("#{k}", *v)
|
||||
else
|
||||
# Doesn't respond. Check if snake case.
|
||||
if k.to_s.include?("_")
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
module ProMotion::MotionTable
|
||||
module SectionedTable
|
||||
include ProMotion::ViewHelper
|
||||
|
||||
def table_setup
|
||||
PM.logger.error "Missing #table_data method in TableScreen #{self.class.to_s}." unless self.respond_to?(:table_data)
|
||||
|
||||
self.view = self.create_table_view_from_data(self.table_data)
|
||||
|
||||
if self.class.respond_to?(:get_searchable) && self.class.get_searchable
|
||||
self.make_searchable(content_controller: self, search_bar: self.class.get_searchable_params)
|
||||
end
|
||||
if self.class.respond_to?(:get_refreshable) && self.class.get_refreshable
|
||||
if defined?(UIRefreshControl)
|
||||
self.make_refreshable(self.class.get_refreshable_params)
|
||||
else
|
||||
PM.logger.warn "To use the refresh control on < iOS 6, you need to include the CocoaPod 'CKRefreshControl'."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @param [Array] Array of table data
|
||||
# @returns [UITableView] delegated to self
|
||||
def create_table_view_from_data(data)
|
||||
set_table_view_data data
|
||||
return table_view
|
||||
end
|
||||
alias :createTableViewFromData :create_table_view_from_data
|
||||
|
||||
def update_table_view_data(data)
|
||||
set_table_view_data data
|
||||
self.table_view.reloadData
|
||||
end
|
||||
alias :updateTableViewData :update_table_view_data
|
||||
|
||||
def set_table_view_data(data)
|
||||
@mt_table_view_groups = data
|
||||
end
|
||||
alias :setTableViewData :set_table_view_data
|
||||
|
||||
def section_at_index(index)
|
||||
if @mt_filtered
|
||||
@mt_filtered_data.at(index)
|
||||
else
|
||||
@mt_table_view_groups.at(index)
|
||||
end
|
||||
end
|
||||
|
||||
def cell_at_section_and_index(section, index)
|
||||
if section_at_index(section) && section_at_index(section)[:cells]
|
||||
return section_at_index(section)[:cells].at(index)
|
||||
end
|
||||
end
|
||||
alias :cellAtSectionAndIndex :cell_at_section_and_index
|
||||
|
||||
def trigger_action(action, arguments)
|
||||
if self.respond_to?(action)
|
||||
expected_arguments = self.method(action).arity
|
||||
if expected_arguments == 0
|
||||
self.send(action)
|
||||
elsif expected_arguments == 1 || expected_arguments == -1
|
||||
self.send(action, arguments)
|
||||
else
|
||||
PM.logger.warn "#{action} expects #{expected_arguments} arguments. Maximum number of required arguments for an action is 1."
|
||||
end
|
||||
else
|
||||
PM.logger.info "Action not implemented: #{action.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
def accessory_toggled_switch(switch)
|
||||
table_cell = switch.superview
|
||||
index_path = table_cell.superview.indexPathForCell(table_cell)
|
||||
|
||||
data_cell = cell_at_section_and_index(index_path.section, index_path.row)
|
||||
data_cell[:arguments] = {} unless data_cell[:arguments]
|
||||
data_cell[:arguments][:value] = switch.isOn if data_cell[:arguments].is_a? Hash
|
||||
data_cell[:accessory_action] ||= data_cell[:accessoryAction] # For legacy support
|
||||
|
||||
trigger_action(data_cell[:accessory_action], data_cell[:arguments]) if data_cell[:accessory_action]
|
||||
end
|
||||
|
||||
########## Cocoa touch methods, leave as-is #################
|
||||
def numberOfSectionsInTableView(table_view)
|
||||
if @mt_filtered
|
||||
return @mt_filtered_data.length if @mt_filtered_data
|
||||
else
|
||||
return @mt_table_view_groups.length if @mt_table_view_groups
|
||||
end
|
||||
0
|
||||
end
|
||||
|
||||
# Number of cells
|
||||
def tableView(table_view, numberOfRowsInSection:section)
|
||||
return section_at_index(section)[:cells].length if section_at_index(section) && section_at_index(section)[:cells]
|
||||
0
|
||||
end
|
||||
|
||||
def tableView(table_view, titleForHeaderInSection:section)
|
||||
return section_at_index(section)[:title] if section_at_index(section) && section_at_index(section)[:title]
|
||||
end
|
||||
|
||||
# Set table_data_index if you want the right hand index column (jumplist)
|
||||
def sectionIndexTitlesForTableView(table_view)
|
||||
if self.respond_to?(:table_data_index)
|
||||
self.table_data_index
|
||||
end
|
||||
end
|
||||
|
||||
def remap_data_cell(data_cell)
|
||||
# Re-maps legacy data cell calls
|
||||
mappings = {
|
||||
cell_style: :cellStyle,
|
||||
cell_identifier: :cellIdentifier,
|
||||
cell_class: :cellClass,
|
||||
masks_to_bounds: :masksToBounds,
|
||||
background_color: :backgroundColor,
|
||||
selection_style: :selectionStyle,
|
||||
cell_class_attributes: :cellClassAttributes,
|
||||
accessory_view: :accessoryView,
|
||||
accessory_type: :accessoryType,
|
||||
accessory_checked: :accessoryDefault,
|
||||
remote_image: :remoteImage,
|
||||
subviews: :subViews
|
||||
}
|
||||
mappings.each_pair do |n, old|
|
||||
if data_cell[old]
|
||||
warn "[DEPRECATION] `:#{old}` is deprecated in TableScreens. Use `:#{n}`"
|
||||
data_cell[n] = data_cell[old]
|
||||
end
|
||||
end
|
||||
if data_cell[:styles] && data_cell[:styles][:textLabel]
|
||||
warn "[DEPRECATION] `:textLabel` is deprecated in TableScreens. Use `:label`"
|
||||
data_cell[:styles][:label] = data_cell[:styles][:textLabel]
|
||||
end
|
||||
data_cell
|
||||
end
|
||||
|
||||
def tableView(table_view, cellForRowAtIndexPath:index_path)
|
||||
data_cell = cell_at_section_and_index(index_path.section, index_path.row)
|
||||
return UITableViewCell.alloc.init unless data_cell
|
||||
|
||||
data_cell = self.remap_data_cell(data_cell)
|
||||
|
||||
data_cell[:cell_style] ||= UITableViewCellStyleDefault
|
||||
data_cell[:cell_identifier] ||= "Cell"
|
||||
cell_identifier = data_cell[:cell_identifier]
|
||||
data_cell[:cell_class] ||= ProMotion::TableViewCell
|
||||
|
||||
table_cell = table_view.dequeueReusableCellWithIdentifier(cell_identifier)
|
||||
unless table_cell
|
||||
table_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:cell_identifier)
|
||||
|
||||
data_cell[:layer] ||= {}
|
||||
data_cell[:layer][:masksToBounds] = data_cell[:masks_to_bounds] # TODO: Deprecate and then remove this.
|
||||
|
||||
table_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
|
||||
set_attributes table_cell, data_cell
|
||||
end
|
||||
|
||||
### Catch any custom class labels ###
|
||||
if data_cell[:cell_class]
|
||||
data_cell.select{|k| k =~ /_label$/}.each_pair do |k, v|
|
||||
cell = table_cell.send(k)
|
||||
cell.setText v
|
||||
cell.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
end
|
||||
end
|
||||
|
||||
if data_cell[:cell_class_attributes]
|
||||
set_attributes table_cell, data_cell[:cell_class_attributes]
|
||||
end
|
||||
|
||||
if data_cell[:accessory_view]
|
||||
table_cell.accessoryView = data_cell[:accessory_view]
|
||||
table_cell.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
end
|
||||
|
||||
if data_cell[:accessory_type]
|
||||
table_cell.accessoryType = data_cell[:accessory_type]
|
||||
end
|
||||
|
||||
if data_cell[:accessory] && data_cell[:accessory] == :switch
|
||||
switch_view = UISwitch.alloc.initWithFrame(CGRectZero)
|
||||
switch_view.addTarget(self, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
|
||||
switch_view.on = true if data_cell[:accessory_checked]
|
||||
table_cell.accessoryView = switch_view
|
||||
end
|
||||
|
||||
if data_cell[:subtitle] and table_cell.detailTextLabel
|
||||
table_cell.detailTextLabel.text = data_cell[:subtitle]
|
||||
table_cell.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
end
|
||||
|
||||
table_cell.selectionStyle = UITableViewCellSelectionStyleNone if data_cell[:no_select]
|
||||
|
||||
if data_cell[:remote_image]
|
||||
if table_cell.imageView.respond_to?("setImageWithURL:placeholderImage:")
|
||||
url = data_cell[:remote_image][:url]
|
||||
url = NSURL.URLWithString(url) unless url.is_a?(NSURL)
|
||||
placeholder = data_cell[:remote_image][:placeholder]
|
||||
placeholder = UIImage.imageNamed(placeholder) if placeholder.is_a?(String)
|
||||
|
||||
table_cell.image_size = data_cell[:remote_image][:size] if data_cell[:remote_image][:size] && table_cell.respond_to?("image_size=")
|
||||
table_cell.imageView.setImageWithURL(url, placeholderImage: placeholder)
|
||||
table_cell.imageView.layer.masksToBounds = true
|
||||
table_cell.imageView.layer.cornerRadius = data_cell[:remote_image][:radius] if data_cell[:remote_image].has_key?(:radius)
|
||||
else
|
||||
PM.logger.error "ProMotion Warning: to use remote_image with TableScreen you need to include the CocoaPod 'SDWebImage'."
|
||||
end
|
||||
elsif data_cell[:image]
|
||||
table_cell.imageView.layer.masksToBounds = true
|
||||
table_cell.imageView.image = data_cell[:image][:image]
|
||||
table_cell.imageView.layer.cornerRadius = data_cell[:image][:radius] if data_cell[:image][:radius]
|
||||
end
|
||||
|
||||
if data_cell[:subviews]
|
||||
tag_number = 0
|
||||
data_cell[:subviews].each do |view|
|
||||
# Remove an existing view at that tag number
|
||||
tag_number += 1
|
||||
existing_view = table_cell.viewWithTag(tag_number)
|
||||
existing_view.removeFromSuperview if existing_view
|
||||
|
||||
# Add the subview if it exists
|
||||
if view
|
||||
view.tag = tag_number
|
||||
table_cell.addSubview view
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if data_cell[:details]
|
||||
table_cell.addSubview data_cell[:details][:image]
|
||||
end
|
||||
|
||||
if data_cell[:styles] && data_cell[:styles][:label] && data_cell[:styles][:label][:frame]
|
||||
ui_label = false
|
||||
table_cell.contentView.subviews.each do |view|
|
||||
if view.is_a? UILabel
|
||||
ui_label = true
|
||||
view.text = data_cell[:styles][:label][:text]
|
||||
end
|
||||
end
|
||||
|
||||
unless ui_label == true
|
||||
label ||= UILabel.alloc.initWithFrame(CGRectZero)
|
||||
set_attributes label, data_cell[:styles][:label]
|
||||
table_cell.contentView.addSubview label
|
||||
end
|
||||
# hackery
|
||||
table_cell.textLabel.textColor = UIColor.clearColor
|
||||
else
|
||||
cell_title = data_cell[:title]
|
||||
cell_title ||= ""
|
||||
table_cell.textLabel.text = cell_title
|
||||
end
|
||||
|
||||
return table_cell
|
||||
end
|
||||
|
||||
def tableView(tableView, heightForRowAtIndexPath:index_path)
|
||||
cell = cell_at_section_and_index(index_path.section, index_path.row)
|
||||
if cell[:height]
|
||||
cell[:height].to_f
|
||||
else
|
||||
tableView.rowHeight
|
||||
end
|
||||
end
|
||||
|
||||
def tableView(table_view, didSelectRowAtIndexPath:index_path)
|
||||
cell = cell_at_section_and_index(index_path.section, index_path.row)
|
||||
table_view.deselectRowAtIndexPath(index_path, animated: true)
|
||||
cell[:arguments] ||= {}
|
||||
cell[:arguments][:cell] = cell if cell[:arguments].is_a?(Hash)
|
||||
trigger_action(cell[:action], cell[:arguments]) if cell[:action]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,14 +0,0 @@
|
||||
module ProMotion::MotionTable
|
||||
module GroupedTable
|
||||
include SectionedTable
|
||||
include RefreshableTable
|
||||
|
||||
def table_view
|
||||
@table_view ||= UITableView.alloc.initWithFrame(self.view.frame, style:UITableViewStyleGrouped)
|
||||
@table_view.dataSource = self;
|
||||
@table_view.delegate = self;
|
||||
return @table_view
|
||||
end
|
||||
alias :tableView :table_view
|
||||
end
|
||||
end
|
||||
@@ -1,15 +0,0 @@
|
||||
module ProMotion::MotionTable
|
||||
module PlainTable
|
||||
include SectionedTable
|
||||
include SearchableTable
|
||||
include RefreshableTable
|
||||
|
||||
def table_view
|
||||
@table_view ||= UITableView.alloc.initWithFrame(self.view.frame, style:UITableViewStylePlain)
|
||||
@table_view.dataSource = self;
|
||||
@table_view.delegate = self;
|
||||
return @table_view
|
||||
end
|
||||
alias :tableView :table_view
|
||||
end
|
||||
end
|
||||
@@ -13,7 +13,6 @@ module ProMotion
|
||||
raise StandardError.new("ERROR: Screens must extend UIViewController or a subclass of UIViewController.")
|
||||
end
|
||||
|
||||
|
||||
self.title = self.class.send(:get_title)
|
||||
|
||||
args.each do |k, v|
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
module ProMotion
|
||||
module TableScreenModule
|
||||
include MotionTable::PlainTable
|
||||
include MotionTable::SearchableTable
|
||||
include MotionTable::RefreshableTable
|
||||
include ProMotion::ScreenModule
|
||||
include PlainTable
|
||||
include SearchableTable
|
||||
include RefreshableTable
|
||||
include ScreenModule
|
||||
|
||||
def update_table_data
|
||||
self.update_table_view_data(table_data)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module ProMotion::MotionTable
|
||||
module ProMotion
|
||||
module RefreshableTable
|
||||
def make_refreshable(params={})
|
||||
pull_message = params[:pull_message] || "Pull to refresh"
|
||||
@@ -39,4 +39,4 @@ module ProMotion::MotionTable
|
||||
@refresh_control.endRefreshing
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,18 +1,10 @@
|
||||
module ProMotion::MotionTable
|
||||
module ProMotion
|
||||
module SearchableTable
|
||||
|
||||
def make_searchable(params={})
|
||||
params[:content_controller] ||= params[:contentController]
|
||||
params[:data_source] ||= params[:searchResultsDataSource]
|
||||
params[:search_results_delegate] ||= params[:searchResultsDelegate]
|
||||
params = set_searchable_param_defaults(params)
|
||||
|
||||
params[:frame] ||= CGRectMake(0, 0, 320, 44) # TODO: Don't hardcode this...
|
||||
params[:content_controller] ||= self
|
||||
params[:delegate] ||= self
|
||||
params[:data_source] ||= self
|
||||
params[:search_results_delegate] ||= self
|
||||
|
||||
search_bar = UISearchBar.alloc.initWithFrame(params[:frame])
|
||||
search_bar.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
search_bar = create_search_bar(params)
|
||||
|
||||
if params[:search_bar] && params[:search_bar][:placeholder]
|
||||
search_bar.placeholder = params[:search_bar][:placeholder]
|
||||
@@ -26,41 +18,44 @@ module ProMotion::MotionTable
|
||||
self.table_view.tableHeaderView = search_bar
|
||||
end
|
||||
alias :makeSearchable :make_searchable
|
||||
|
||||
def set_searchable_param_defaults(params)
|
||||
params[:content_controller] ||= params[:contentController]
|
||||
params[:data_source] ||= params[:searchResultsDataSource]
|
||||
params[:search_results_delegate] ||= params[:searchResultsDelegate]
|
||||
|
||||
params[:frame] ||= CGRectMake(0, 0, 320, 44) # TODO: Don't hardcode this...
|
||||
params[:content_controller] ||= self
|
||||
params[:delegate] ||= self
|
||||
params[:data_source] ||= self
|
||||
params[:search_results_delegate] ||= self
|
||||
params
|
||||
end
|
||||
|
||||
def create_search_bar(params)
|
||||
search_bar = UISearchBar.alloc.initWithFrame(params[:frame])
|
||||
search_bar.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
search_bar
|
||||
end
|
||||
|
||||
######### iOS methods, headless camel case #######
|
||||
|
||||
def searchDisplayController(controller, shouldReloadTableForSearchString:search_string)
|
||||
@mt_filtered_data = nil
|
||||
@mt_filtered_data = []
|
||||
|
||||
@mt_table_view_groups.each do |section|
|
||||
new_section = {}
|
||||
new_section[:cells] = []
|
||||
|
||||
section[:cells].each do |cell|
|
||||
if cell[:title].to_s.downcase.strip.include?(search_string.downcase.strip)
|
||||
new_section[:cells] << cell
|
||||
end
|
||||
end
|
||||
|
||||
if new_section[:cells] && new_section[:cells].length > 0
|
||||
new_section[:title] = section[:title]
|
||||
@mt_filtered_data << new_section
|
||||
end
|
||||
end
|
||||
@promotion_table_data.search(search_string)
|
||||
true
|
||||
end
|
||||
|
||||
def searchDisplayControllerWillEndSearch(controller)
|
||||
@mt_filtered = false
|
||||
@mt_filtered_data = nil
|
||||
@promotion_table_data.stop_searching
|
||||
@promotion_table_data_data = nil
|
||||
self.table_view.setScrollEnabled true
|
||||
end
|
||||
|
||||
def searchDisplayControllerWillBeginSearch(controller)
|
||||
@mt_filtered = true
|
||||
@mt_filtered_data = []
|
||||
@promotion_table_data = true
|
||||
@motion_table_filtered_data = []
|
||||
self.table_view.setScrollEnabled false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
5
lib/ProMotion/screens/_tables/_sectioned_table.rb
Normal file
5
lib/ProMotion/screens/_tables/_sectioned_table.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module ProMotion
|
||||
module SectionedTable
|
||||
include Table
|
||||
end
|
||||
end
|
||||
129
lib/ProMotion/screens/_tables/_table.rb
Normal file
129
lib/ProMotion/screens/_tables/_table.rb
Normal file
@@ -0,0 +1,129 @@
|
||||
module ProMotion
|
||||
module Table
|
||||
include ProMotion::ViewHelper
|
||||
|
||||
def table_setup
|
||||
check_table_data
|
||||
set_up_table_view
|
||||
set_up_searchable
|
||||
set_up_refreshable
|
||||
end
|
||||
|
||||
def check_table_data
|
||||
PM.logger.error "Missing #table_data method in TableScreen #{self.class.to_s}." unless self.respond_to?(:table_data)
|
||||
end
|
||||
|
||||
def set_up_table_view
|
||||
self.view = self.create_table_view_from_data(self.table_data)
|
||||
end
|
||||
|
||||
def set_up_searchable
|
||||
if self.class.respond_to?(:get_searchable) && self.class.get_searchable
|
||||
self.make_searchable(content_controller: self, search_bar: self.class.get_searchable_params)
|
||||
end
|
||||
end
|
||||
|
||||
def set_up_refreshable
|
||||
if self.class.respond_to?(:get_refreshable) && self.class.get_refreshable
|
||||
if defined?(UIRefreshControl)
|
||||
self.make_refreshable(self.class.get_refreshable_params)
|
||||
else
|
||||
PM.logger.warn "To use the refresh control on < iOS 6, you need to include the CocoaPod 'CKRefreshControl'."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_table_view_from_data(data)
|
||||
@promotion_table_data = TableData.new(data, table_view)
|
||||
table_view
|
||||
end
|
||||
|
||||
def update_table_view_data(data)
|
||||
@promotion_table_data.data = data
|
||||
table_view.reloadData
|
||||
end
|
||||
|
||||
# Methods to retrieve data
|
||||
|
||||
def section_at_index(index)
|
||||
@promotion_table_data.section(index)
|
||||
end
|
||||
|
||||
def cell_at_section_and_index(section, index)
|
||||
@promotion_table_data.cell(section: section, index: index)
|
||||
end
|
||||
|
||||
def trigger_action(action, arguments)
|
||||
if self.respond_to?(action)
|
||||
expected_arguments = self.method(action).arity
|
||||
if expected_arguments == 0
|
||||
self.send(action)
|
||||
elsif expected_arguments == 1 || expected_arguments == -1
|
||||
self.send(action, arguments)
|
||||
else
|
||||
PM.logger.warn "#{action} expects #{expected_arguments} arguments. Maximum number of required arguments for an action is 1."
|
||||
end
|
||||
else
|
||||
PM.logger.info "Action not implemented: #{action.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
def accessory_toggled_switch(switch)
|
||||
table_cell = switch.superview
|
||||
index_path = table_cell.superview.indexPathForCell(table_cell)
|
||||
|
||||
data_cell = cell_at_section_and_index(index_path.section, index_path.row)
|
||||
data_cell[:arguments] = {} unless data_cell[:arguments]
|
||||
data_cell[:arguments][:value] = switch.isOn if data_cell[:arguments].is_a? Hash
|
||||
data_cell[:accessory_action] ||= data_cell[:accessoryAction] # For legacy support
|
||||
|
||||
trigger_action(data_cell[:accessory_action], data_cell[:arguments]) if data_cell[:accessory_action]
|
||||
end
|
||||
|
||||
########## Cocoa touch methods #################
|
||||
def numberOfSectionsInTableView(table_view)
|
||||
return Array(@promotion_table_data.data).length
|
||||
end
|
||||
|
||||
# Number of cells
|
||||
def tableView(table_view, numberOfRowsInSection:section)
|
||||
return @promotion_table_data.section_length(section)
|
||||
0
|
||||
end
|
||||
|
||||
def tableView(table_view, titleForHeaderInSection:section)
|
||||
return section_at_index(section)[:title] if section_at_index(section) && section_at_index(section)[:title]
|
||||
end
|
||||
|
||||
# Set table_data_index if you want the right hand index column (jumplist)
|
||||
def sectionIndexTitlesForTableView(table_view)
|
||||
self.table_data_index if self.respond_to?(:table_data_index)
|
||||
end
|
||||
|
||||
def tableView(table_view, cellForRowAtIndexPath:index_path)
|
||||
@promotion_table_data.table_view_cell(index_path: index_path)
|
||||
end
|
||||
|
||||
def tableView(table_view, heightForRowAtIndexPath:index_path)
|
||||
(@promotion_table_data.cell(index_path: index_path)[:height] || table_view.rowHeight).to_f
|
||||
end
|
||||
|
||||
def tableView(table_view, didSelectRowAtIndexPath:index_path)
|
||||
cell = @promotion_table_data.cell(index_path: index_path)
|
||||
table_view.deselectRowAtIndexPath(index_path, animated: true)
|
||||
|
||||
cell[:arguments] ||= {}
|
||||
cell[:arguments][:cell] = cell if cell[:arguments].is_a?(Hash) # TODO: Should we really do this?
|
||||
|
||||
trigger_action(cell[:action], cell[:arguments]) if cell[:action]
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Old aliases, deprecated, will be removed
|
||||
alias :createTableViewFromData :create_table_view_from_data
|
||||
alias :updateTableViewData :update_table_view_data
|
||||
alias :cellAtSectionAndIndex :cell_at_section_and_index
|
||||
|
||||
end
|
||||
end
|
||||
16
lib/ProMotion/screens/_tables/grouped_table.rb
Normal file
16
lib/ProMotion/screens/_tables/grouped_table.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module ProMotion
|
||||
module GroupedTable
|
||||
include Table
|
||||
include RefreshableTable
|
||||
|
||||
def table_view
|
||||
@table_view ||= begin
|
||||
t = UITableView.alloc.initWithFrame(self.view.frame, style:UITableViewStyleGrouped)
|
||||
t.dataSource = self
|
||||
t.delegate = self
|
||||
t
|
||||
end
|
||||
end
|
||||
alias :tableView :table_view
|
||||
end
|
||||
end
|
||||
17
lib/ProMotion/screens/_tables/plain_table.rb
Normal file
17
lib/ProMotion/screens/_tables/plain_table.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
module ProMotion
|
||||
module PlainTable
|
||||
include Table
|
||||
include SearchableTable
|
||||
include RefreshableTable
|
||||
|
||||
def table_view
|
||||
@table_view ||= begin
|
||||
t = UITableView.alloc.initWithFrame(self.view.frame, style:UITableViewStylePlain)
|
||||
t.dataSource = self
|
||||
t.delegate = self
|
||||
t
|
||||
end
|
||||
end
|
||||
alias :tableView :table_view
|
||||
end
|
||||
end
|
||||
139
lib/ProMotion/screens/_tables/table_data.rb
Normal file
139
lib/ProMotion/screens/_tables/table_data.rb
Normal file
@@ -0,0 +1,139 @@
|
||||
module ProMotion
|
||||
class TableData
|
||||
attr_accessor :data, :filtered_data, :filtered, :table_view
|
||||
|
||||
def initialize(data, table_view)
|
||||
self.data = data
|
||||
self.table_view = table_view
|
||||
end
|
||||
|
||||
def section(index)
|
||||
s = sections.at(index)
|
||||
s || { title: nil, cells: [] }
|
||||
end
|
||||
|
||||
def sections
|
||||
self.filtered ? self.filtered_data : self.data
|
||||
end
|
||||
|
||||
def section_length(index)
|
||||
section(index)[:cells].length
|
||||
end
|
||||
|
||||
def cell(params={})
|
||||
if params[:index_path]
|
||||
params[:section] = params[:index_path].section
|
||||
params[:index] = params[:index_path].row
|
||||
end
|
||||
|
||||
table_section = self.section(params[:section])
|
||||
return table_section[:cells].at(params[:index].to_i)
|
||||
nil
|
||||
end
|
||||
|
||||
def search(search_string)
|
||||
self.filtered_data = []
|
||||
self.filtered = true
|
||||
|
||||
search_string = search_string.downcase.strip
|
||||
|
||||
self.data.each do |section|
|
||||
new_section = {}
|
||||
new_section[:cells] = []
|
||||
|
||||
new_section[:cells] = section[:cells].map do |cell|
|
||||
cell[:title].to_s.downcase.strip.include?(search_string) ? cell : nil
|
||||
end.compact
|
||||
|
||||
if new_section[:cells] && new_section[:cells].length > 0
|
||||
new_section[:title] = section[:title]
|
||||
self.filtered_data << new_section
|
||||
end
|
||||
end
|
||||
|
||||
self.filtered_data
|
||||
end
|
||||
|
||||
def stop_searching
|
||||
self.filtered_data = []
|
||||
self.filtered = false
|
||||
end
|
||||
|
||||
def table_view_cell(params={})
|
||||
if params[:index_path]
|
||||
params[:section] = params[:index_path].section
|
||||
params[:index] = params[:index_path].row
|
||||
end
|
||||
|
||||
data_cell = self.cell(section: params[:section], index: params[:index])
|
||||
return UITableViewCell.alloc.init unless data_cell # No data?
|
||||
|
||||
data_cell = self.remap_data_cell(data_cell) # TODO: Deprecated, remove in version 1.0
|
||||
data_cell = self.set_data_cell_defaults(data_cell)
|
||||
|
||||
table_cell = self.create_table_cell(data_cell)
|
||||
|
||||
table_cell
|
||||
end
|
||||
|
||||
def set_data_cell_defaults(data_cell)
|
||||
data_cell[:cell_style] ||= UITableViewCellStyleDefault
|
||||
data_cell[:cell_identifier] ||= "Cell"
|
||||
data_cell[:cell_class] ||= ProMotion::TableViewCell
|
||||
data_cell
|
||||
end
|
||||
|
||||
def remap_data_cell(data_cell)
|
||||
# Re-maps legacy data cell calls
|
||||
mappings = {
|
||||
cell_style: :cellStyle,
|
||||
cell_identifier: :cellIdentifier,
|
||||
cell_class: :cellClass,
|
||||
masks_to_bounds: :masksToBounds,
|
||||
background_color: :backgroundColor,
|
||||
selection_style: :selectionStyle,
|
||||
cell_class_attributes: :cellClassAttributes,
|
||||
accessory_view: :accessoryView,
|
||||
accessory_type: :accessoryType,
|
||||
accessory_checked: :accessoryDefault,
|
||||
remote_image: :remoteImage,
|
||||
subviews: :subViews
|
||||
}
|
||||
|
||||
if data_cell[:masks_to_bounds]
|
||||
PM.logger.deprecated "masks_to_bounds: (value) is deprecated. Use layer: { masks_to_bounds: (value) } instead."
|
||||
data_cell[:layer] ||= {}
|
||||
data_cell[:layer][:masks_to_bounds] = data_cell[:masks_to_bounds] # TODO: Deprecate and then remove this.
|
||||
end
|
||||
|
||||
mappings.each_pair do |n, old|
|
||||
if data_cell[old]
|
||||
warn "[DEPRECATION] `:#{old}` is deprecated in TableScreens. Use `:#{n}`"
|
||||
data_cell[n] = data_cell[old]
|
||||
end
|
||||
end
|
||||
|
||||
if data_cell[:styles] && data_cell[:styles][:textLabel]
|
||||
warn "[DEPRECATION] `:textLabel` is deprecated in TableScreens. Use `:label`"
|
||||
data_cell[:styles][:label] = data_cell[:styles][:textLabel]
|
||||
end
|
||||
|
||||
data_cell
|
||||
end
|
||||
|
||||
def create_table_cell(data_cell)
|
||||
table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier])
|
||||
|
||||
unless table_cell
|
||||
table_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:data_cell[:cell_identifier])
|
||||
table_cell.extend ProMotion::TableViewCellModule unless table_cell.is_a?(ProMotion::TableViewCellModule)
|
||||
table_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
|
||||
end
|
||||
|
||||
table_cell.setup(data_cell)
|
||||
|
||||
table_cell
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
150
lib/ProMotion/screens/_tables/table_view_cell_module.rb
Normal file
150
lib/ProMotion/screens/_tables/table_view_cell_module.rb
Normal file
@@ -0,0 +1,150 @@
|
||||
module ProMotion
|
||||
module TableViewCellModule
|
||||
include ViewHelper
|
||||
|
||||
attr_accessor :data_cell
|
||||
|
||||
def setup(data_cell)
|
||||
self.data_cell = data_cell
|
||||
|
||||
# TODO: Some of these need to go away. Unnecessary overhead.
|
||||
set_cell_attributes
|
||||
set_background_color
|
||||
set_class_attributes
|
||||
set_accessory_view
|
||||
set_subtitle
|
||||
set_image
|
||||
set_remote_image
|
||||
set_subviews
|
||||
set_details
|
||||
set_styles
|
||||
set_selection_style
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def set_cell_attributes
|
||||
set_attributes self, data_cell
|
||||
self
|
||||
end
|
||||
|
||||
def set_background_color
|
||||
self.backgroundView = UIView.new.tap{|v| v.backgroundColor = data_cell[:background_color]} if data_cell[:background_color]
|
||||
end
|
||||
|
||||
def set_class_attributes
|
||||
if data_cell[:cell_class_attributes]
|
||||
PM.logger.deprecated "`cell_class_attributes` is deprecated. Just add the attributes you want to set right into your cell hash."
|
||||
set_attributes self, data_cell[:cell_class_attributes]
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def set_accessory_view
|
||||
if data_cell[:accessory_view]
|
||||
self.accessoryView = data_cell[:accessory_view]
|
||||
self.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
end
|
||||
|
||||
if data_cell[:accessory] && data_cell[:accessory] == :switch
|
||||
switch_view = UISwitch.alloc.initWithFrame(CGRectZero)
|
||||
switch_view.addTarget(self, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
|
||||
switch_view.on = true if data_cell[:accessory_checked]
|
||||
self.accessoryView = switch_view
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def set_subtitle
|
||||
if data_cell[:subtitle] && self.detailTextLabel
|
||||
self.detailTextLabel.text = data_cell[:subtitle]
|
||||
self.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def set_remote_image
|
||||
if data_cell[:remote_image]
|
||||
if self.imageView.respond_to?("setImageWithURL:placeholderImage:")
|
||||
url = data_cell[:remote_image][:url]
|
||||
url = NSURL.URLWithString(url) unless url.is_a?(NSURL)
|
||||
placeholder = data_cell[:remote_image][:placeholder]
|
||||
placeholder = UIImage.imageNamed(placeholder) if placeholder.is_a?(String)
|
||||
|
||||
self.image_size = data_cell[:remote_image][:size] if data_cell[:remote_image][:size] && self.respond_to?("image_size=")
|
||||
self.imageView.setImageWithURL(url, placeholderImage: placeholder)
|
||||
self.imageView.layer.masksToBounds = true
|
||||
self.imageView.layer.cornerRadius = data_cell[:remote_image][:radius] if data_cell[:remote_image].has_key?(:radius)
|
||||
else
|
||||
PM.logger.error "ProMotion Warning: to use remote_image with TableScreen you need to include the CocoaPod 'SDWebImage'."
|
||||
end
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def set_image
|
||||
if data_cell[:image]
|
||||
self.imageView.layer.masksToBounds = true
|
||||
self.imageView.image = data_cell[:image][:image]
|
||||
self.imageView.layer.cornerRadius = data_cell[:image][:radius] if data_cell[:image][:radius]
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def set_subviews
|
||||
tag_number = 0
|
||||
Array(data_cell[:subviews]).each do |view|
|
||||
# Remove an existing view at that tag number
|
||||
tag_number += 1
|
||||
existing_view = self.viewWithTag(tag_number)
|
||||
existing_view.removeFromSuperview if existing_view
|
||||
|
||||
# Add the subview if it exists
|
||||
if view
|
||||
view.tag = tag_number
|
||||
self.addSubview view
|
||||
end
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def set_details
|
||||
if data_cell[:details]
|
||||
self.addSubview data_cell[:details][:image]
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def set_styles
|
||||
if data_cell[:styles] && data_cell[:styles][:label] && data_cell[:styles][:label][:frame]
|
||||
ui_label = false
|
||||
self.contentView.subviews.each do |view|
|
||||
if view.is_a? UILabel
|
||||
ui_label = true
|
||||
view.text = data_cell[:styles][:label][:text]
|
||||
end
|
||||
end
|
||||
|
||||
unless ui_label == true
|
||||
label ||= UILabel.alloc.initWithFrame(CGRectZero)
|
||||
set_attributes label, data_cell[:styles][:label]
|
||||
self.contentView.addSubview label
|
||||
end
|
||||
|
||||
# TODO: What is this and why is it necessary?
|
||||
self.textLabel.textColor = UIColor.clearColor
|
||||
else
|
||||
cell_title = data_cell[:title]
|
||||
cell_title ||= ""
|
||||
self.textLabel.text = cell_title
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def set_selection_style
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone if data_cell[:no_select]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,13 +3,14 @@ module ProMotion
|
||||
# Just make sure to implement the Obj-C methods in cocoatouch/TableViewController.rb.
|
||||
class TableScreen < TableViewController
|
||||
include ProMotion::TableScreenModule
|
||||
# Includes PM::PlainTable already
|
||||
end
|
||||
|
||||
class GroupedTableScreen < TableScreen
|
||||
include ProMotion::MotionTable::GroupedTable
|
||||
include ProMotion::GroupedTable
|
||||
end
|
||||
|
||||
class SectionedTableScreen < TableScreen
|
||||
include ProMotion::MotionTable::SectionedTable
|
||||
include ProMotion::SectionedTable
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,10 @@
|
||||
describe "ProMotion::TableScreen functionality" do
|
||||
tests PM::TableScreen
|
||||
describe "ProMotion::TestTableScreen functionality" do
|
||||
tests PM::TestTableScreen
|
||||
|
||||
# Override controller to properly instantiate
|
||||
def controller
|
||||
rotate_device to: :portrait, button: :bottom
|
||||
@controller ||= TableScreen.new(nav_bar: true)
|
||||
@controller ||= TestTableScreen.new(nav_bar: true)
|
||||
@controller.on_load
|
||||
@controller.main_controller
|
||||
end
|
||||
@@ -14,7 +14,7 @@ describe "ProMotion::TableScreen functionality" do
|
||||
end
|
||||
|
||||
it "should have a navigation bar" do
|
||||
@controller.navigationController.is_a?(UINavigationController).should == true
|
||||
@controller.navigationController.should.be.kind_of(UINavigationController)
|
||||
end
|
||||
|
||||
it "should increment the tap counter on tap" do
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
class TableScreen < ProMotion::SectionedTableScreen
|
||||
class TestTableScreen < ProMotion::SectionedTableScreen
|
||||
|
||||
def promotion_table_data
|
||||
@promotion_table_data
|
||||
end
|
||||
|
||||
def on_load
|
||||
@tap_counter ||= 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class TableScreenRefreshable < TableScreen
|
||||
class TableScreenRefreshable < TestTableScreen
|
||||
attr_accessor :on_refresh_called
|
||||
|
||||
refreshable
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class TableScreenSearchable < TableScreen
|
||||
class TableScreenSearchable < TestTableScreen
|
||||
|
||||
searchable
|
||||
|
||||
|
||||
108
spec/unit/tables/table_module_spec.rb
Normal file
108
spec/unit/tables/table_module_spec.rb
Normal file
@@ -0,0 +1,108 @@
|
||||
describe "PM::Table module" do
|
||||
|
||||
def cell_factory(args={})
|
||||
{ title: "Basic", action: :basic_cell_tapped, arguments: { id: 1 } }.merge!(args)
|
||||
end
|
||||
|
||||
def custom_cell
|
||||
cell_factory({
|
||||
title: "Crazy Full Featured Cell",
|
||||
subtitle: "This is way too huge..see note",
|
||||
arguments: { data: [ "lots", "of", "data" ] },
|
||||
action: :tapped_cell_1,
|
||||
height: 50, # manually changes the cell's height
|
||||
cell_style: UITableViewCellStyleSubtitle,
|
||||
cell_identifier: "Cell",
|
||||
cell_class: PM::TableViewCell,
|
||||
masks_to_bounds: true,
|
||||
background_color: UIColor.whiteColor,
|
||||
selection_style: UITableViewCellSelectionStyleGray,
|
||||
cell_class_attributes: {
|
||||
# any Obj-C attributes to set on the cell
|
||||
backgroundColor: UIColor.whiteColor
|
||||
},
|
||||
accessory: :switch, # currently only :switch is supported
|
||||
accessory_view: @some_accessory_view,
|
||||
accessory_type: UITableViewCellAccessoryCheckmark,
|
||||
accessory_checked: true, # whether it's "checked" or not
|
||||
image: { image: UIImage.imageNamed("something"), radius: 15 },
|
||||
remote_image: { # remote image, requires SDWebImage CocoaPod
|
||||
url: "http://placekitten.com/200/300", placeholder: "some-local-image",
|
||||
size: 50, radius: 15
|
||||
},
|
||||
subviews: [ @some_view, @some_other_view ] # arbitrary views added to the cell
|
||||
})
|
||||
end
|
||||
|
||||
before do
|
||||
@subject = TestTableScreen.new
|
||||
@subject.mock! :table_data do
|
||||
[{
|
||||
title: "Table cell group 1", cells: [ ]
|
||||
},{
|
||||
title: "Table cell group 2", cells: [ cell_factory ]
|
||||
},{
|
||||
title: "Table cell group 3", cells: [ cell_factory(title: "3-1"), cell_factory(title: "3-2") ]
|
||||
},{
|
||||
title: "Table cell group 4", cells: [ custom_cell, cell_factory(title: "4-2"), cell_factory(title: "4-3"), cell_factory(title: "4-4") ]
|
||||
}]
|
||||
end
|
||||
|
||||
@subject.on_load
|
||||
|
||||
@ip = NSIndexPath.indexPathForRow(1, inSection: 2) # Cell 3-2
|
||||
@custom_ip = NSIndexPath.indexPathForRow(0, inSection: 3) # Cell "Crazy Full Featured Cell"
|
||||
|
||||
@subject.update_table_data
|
||||
end
|
||||
|
||||
it "should have the right number of sections" do
|
||||
@subject.numberOfSectionsInTableView(@subject.table_view).should == 4
|
||||
end
|
||||
|
||||
it "should set the section titles" do
|
||||
@subject.tableView(@subject.table_view, titleForHeaderInSection:0).should == "Table cell group 1"
|
||||
@subject.tableView(@subject.table_view, titleForHeaderInSection:1).should == "Table cell group 2"
|
||||
@subject.tableView(@subject.table_view, titleForHeaderInSection:2).should == "Table cell group 3"
|
||||
@subject.tableView(@subject.table_view, titleForHeaderInSection:3).should == "Table cell group 4"
|
||||
end
|
||||
|
||||
it "should create the right number of cells" do
|
||||
@subject.tableView(@subject.table_view, numberOfRowsInSection:0).should == 0
|
||||
@subject.tableView(@subject.table_view, numberOfRowsInSection:1).should == 1
|
||||
@subject.tableView(@subject.table_view, numberOfRowsInSection:2).should == 2
|
||||
@subject.tableView(@subject.table_view, numberOfRowsInSection:3).should == 4
|
||||
end
|
||||
|
||||
it "should create the jumplist" do
|
||||
@subject.mock! :table_data_index, do
|
||||
Array("A".."Z")
|
||||
end
|
||||
|
||||
@subject.sectionIndexTitlesForTableView(@subject.table_view).should == Array("A".."Z")
|
||||
end
|
||||
|
||||
it "should return the proper cell" do
|
||||
cell = @subject.tableView(@subject.table_view, cellForRowAtIndexPath: @ip)
|
||||
cell.should.be.kind_of(UITableViewCell)
|
||||
cell.textLabel.text.should == "3-2"
|
||||
end
|
||||
|
||||
it "should return the table's cell height if none is given" do
|
||||
@subject.tableView(@subject.table_view, heightForRowAtIndexPath:@ip).should == 44.0 # Built-in default
|
||||
end
|
||||
|
||||
it "should allow setting a custom cell height" do
|
||||
@subject.tableView(@subject.table_view, heightForRowAtIndexPath:@custom_ip).should.be > 0.0
|
||||
@subject.tableView(@subject.table_view, heightForRowAtIndexPath:@custom_ip).should == custom_cell[:height].to_f
|
||||
end
|
||||
|
||||
it "should trigger the right action on select and pass in the right arguments" do
|
||||
@subject.mock! :tapped_cell_1 do |args|
|
||||
args[:data].should == [ "lots", "of", "data" ]
|
||||
end
|
||||
|
||||
@subject.tableView(@subject.table_view, didSelectRowAtIndexPath:@custom_ip)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -3,19 +3,25 @@ describe "table screens" do
|
||||
describe "basic functionality" do
|
||||
|
||||
before do
|
||||
@screen = TableScreen.new
|
||||
@screen = TestTableScreen.new
|
||||
@screen.on_load
|
||||
end
|
||||
|
||||
it "should display 2 sections" do
|
||||
@screen.tableView.numberOfSections.should == 2
|
||||
@screen.promotion_table_data.sections.should.be.kind_of(Array)
|
||||
end
|
||||
|
||||
it "should have proper cell numbers" do
|
||||
@screen.tableView.numberOfRowsInSection(0).should == 3
|
||||
@screen.tableView.numberOfRowsInSection(1).should == 2
|
||||
@screen.tableView(@screen.tableView, numberOfRowsInSection:0).should == 3
|
||||
@screen.tableView(@screen.tableView, numberOfRowsInSection:1).should == 2
|
||||
end
|
||||
|
||||
it "should return a UITableViewCell" do
|
||||
index_path = NSIndexPath.indexPathForRow(1, inSection: 1)
|
||||
|
||||
@screen.tableView(@screen.tableView, cellForRowAtIndexPath: index_path).should.be.kind_of UITableViewCell
|
||||
end
|
||||
|
||||
it "should have a placeholder image in the last cell" do
|
||||
index_path = NSIndexPath.indexPathForRow(1, inSection: 1)
|
||||
|
||||
106
spec/unit/tables/table_view_cell_spec.rb
Normal file
106
spec/unit/tables/table_view_cell_spec.rb
Normal file
@@ -0,0 +1,106 @@
|
||||
describe "PM::TableViewCellModule" do
|
||||
|
||||
def custom_cell
|
||||
{
|
||||
title: "Crazy Full Featured Cell",
|
||||
subtitle: "This is way too huge...",
|
||||
arguments: { data: [ "lots", "of", "data" ] },
|
||||
action: :tapped_cell_1,
|
||||
height: 50, # manually changes the cell's height
|
||||
cell_style: UITableViewCellStyleSubtitle,
|
||||
cell_identifier: "Cell",
|
||||
cell_class: PM::TableViewCell,
|
||||
layer: { masks_to_bounds: true },
|
||||
background_color: UIColor.redColor,
|
||||
selection_style: UITableViewCellSelectionStyleGray,
|
||||
accessory: :switch, # currently only :switch is supported
|
||||
accessory_checked: true, # whether it's "checked" or not
|
||||
image: { image: UIImage.imageNamed("list"), radius: 15 },
|
||||
subviews: [ UIView.alloc.initWithFrame(CGRectZero), UILabel.alloc.initWithFrame(CGRectZero) ] # arbitrary views added to the cell
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
@screen = TestTableScreen.new
|
||||
button = UIButton.buttonWithType(UIButtonTypeRoundedRect).tap{|b| b.titleLabel.text = "ACC" }
|
||||
@screen.mock! :table_data do
|
||||
[
|
||||
{ title: "", cells: [] },
|
||||
{ title: "", cells: [
|
||||
{title: "Test 1", accessory_type: UITableViewCellStateShowingEditControlMask },
|
||||
custom_cell,
|
||||
{ title: "Test2", accessory_view: button } ] }
|
||||
]
|
||||
end
|
||||
|
||||
@screen.on_load
|
||||
|
||||
custom_ip = NSIndexPath.indexPathForRow(1, inSection: 1) # Cell "Crazy Full Featured Cell"
|
||||
|
||||
@screen.update_table_data
|
||||
|
||||
@subject = @screen.tableView(@screen.table_view, cellForRowAtIndexPath: custom_ip)
|
||||
end
|
||||
|
||||
it "should be a PM::TableViewCell" do
|
||||
@subject.should.be.kind_of(PM::TableViewCell)
|
||||
end
|
||||
|
||||
it "should have the right title" do
|
||||
@subject.textLabel.text.should == "Crazy Full Featured Cell"
|
||||
end
|
||||
|
||||
it "should have the right subtitle" do
|
||||
@subject.detailTextLabel.text.should == "This is way too huge..."
|
||||
end
|
||||
|
||||
it "should have the right re-use identifier" do
|
||||
@subject.reuseIdentifier.should == "Cell"
|
||||
end
|
||||
|
||||
it "should set the layer.masksToBounds" do
|
||||
@subject.layer.masksToBounds.should == true
|
||||
end
|
||||
|
||||
it "should set the background color" do
|
||||
@subject.backgroundView.backgroundColor.should == UIColor.redColor
|
||||
end
|
||||
|
||||
it "should set the selection color style" do
|
||||
@subject.selectionStyle.should == UITableViewCellSelectionStyleGray
|
||||
end
|
||||
|
||||
it "should set the accessory view to a switch" do
|
||||
@subject.accessoryView.should.be.kind_of(UISwitch)
|
||||
end
|
||||
|
||||
it "should set the accessory view to a button" do
|
||||
ip = NSIndexPath.indexPathForRow(2, inSection: 1)
|
||||
subject = @screen.tableView(@screen.table_view, cellForRowAtIndexPath: ip)
|
||||
subject.accessoryView.should.be.kind_of(UIRoundedRectButton)
|
||||
end
|
||||
|
||||
it "should set the accessory type to edit" do
|
||||
ip = NSIndexPath.indexPathForRow(0, inSection: 1)
|
||||
subject = @screen.tableView(@screen.table_view, cellForRowAtIndexPath: ip)
|
||||
subject.accessoryView.should.be.nil
|
||||
subject.accessoryType.should == UITableViewCellStateShowingEditControlMask
|
||||
end
|
||||
|
||||
it "should set an image with a radius" do
|
||||
@subject.imageView.should.be.kind_of(UIImageView)
|
||||
@subject.imageView.image.should == UIImage.imageNamed("list")
|
||||
@subject.imageView.layer.cornerRadius.should == 15.0
|
||||
end
|
||||
|
||||
it "should create two extra subviews" do
|
||||
@subject.subviews.length.should == 4
|
||||
@subject.subviews[2].class.should == UIView
|
||||
@subject.subviews[3].class.should == UILabel
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user