Class: MotionPrime::TableSection

Inherits:
Section
  • Object
show all
Includes:
HasSearchBar, HasStyleChainBuilder, TableSectionRefreshMixin
Defined in:
motion-prime/sections/table.rb

Direct Known Subclasses

FormSection

Constant Summary

Constants inherited from Section

Section::DEFAULT_CONTENT_HEIGHT, Section::KEYBOARD_HEIGHT_LANDSCAPE, Section::KEYBOARD_HEIGHT_PORTRAIT

Instance Attribute Summary collapse

Attributes inherited from Section

#elements, #model, #name, #options, #screen, #section_styles

Attributes included from DrawSectionMixin

#cached_draw_image, #container_element, #container_gesture_recognizers

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HasSearchBar

#add_search_bar, #create_search_bar, #searchBar, #searchBarSearchButtonClicked

Methods included from HasStyleChainBuilder

#build_styles_chain

Methods included from TableSectionRefreshMixin

#add_pull_to_refresh, #finish_pull_to_refresh

Methods inherited from Section

#add_element, after_initialize, after_render, before_initialize, before_render, bind_keyboard_close, #bind_keyboard_events, #build_element, #cell, container, #container_bounds, #container_height, #container_options, #create_elements, #default_name, element, #element, #elements_options, #elements_to_draw, #elements_to_render, #hide_keyboard, #initialize, #keyboard_will_hide, #keyboard_will_show, #load_elements, #load_section, #load_section!, #on_keyboard_hide, #on_keyboard_show, #reload_section, #render, #render!, #render_container, #render_element?, #view

Methods included from DrawSectionMixin

#bind_gesture_on_container_for, #container_view, #draw_in, #init_container_element, #load_container_element, #prerender_elements_for_state, #prerender_enabled?, #strong_references

Methods included from FrameCalculatorMixin

#calculate_frome_for

Methods included from HasStyles

#prepare_gradient

Methods included from HasClassFactory

#camelize_factory, #class_factory, #low_camelize_factory

Methods included from HasNormalizer

#normalize_object, #normalize_options

Methods included from HasAuthorization

#api_client, #current_user, #reset_current_user, #user_signed_in?

Constructor Details

This class inherits a constructor from MotionPrime::Section

Instance Attribute Details

#deceleratingObject (readonly)

Returns the value of attribute decelerating.



13
14
15
# File 'motion-prime/sections/table.rb', line 13

def decelerating
  @decelerating
end

#did_appearObject

Returns the value of attribute did_appear.



12
13
14
# File 'motion-prime/sections/table.rb', line 12

def did_appear
  @did_appear
end

#section_header_optionsObject

Returns the value of attribute section_header_options.



12
13
14
# File 'motion-prime/sections/table.rb', line 12

def section_header_options
  @section_header_options
end

#section_headersObject

Returns the value of attribute section_headers.



12
13
14
# File 'motion-prime/sections/table.rb', line 12

def section_headers
  @section_headers
end

#table_elementObject

Returns the value of attribute table_element.



12
13
14
# File 'motion-prime/sections/table.rb', line 12

def table_element
  @table_element
end

Class Method Details

.async_table_data(options = {}) ⇒ Object



426
427
428
# File 'motion-prime/sections/table.rb', line 426

def async_table_data(options = {})
  self.async_data_options = options
end

.group_header(name, options) ⇒ Object



430
431
432
433
434
435
# File 'motion-prime/sections/table.rb', line 430

def group_header(name, options)
  options[:name] = name
  self.section_header_options ||= []
  section = options.delete(:id)
  self.section_header_options[section] = options
end

.pull_to_refresh(&block) ⇒ Object



437
438
439
# File 'motion-prime/sections/table.rb', line 437

def pull_to_refresh(&block)
  self.pull_to_refresh_block = block
end

Instance Method Details

#async_data?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'motion-prime/sections/table.rb', line 29

def async_data?
  self.class.async_data_options
end

#cell_for_index(table, index) ⇒ Object



210
211
212
213
214
215
216
217
218
# File 'motion-prime/sections/table.rb', line 210

def cell_for_index(table, index)
  cell = cached_cell(index, table) || render_cell(index, table)

  # run table view is appeared callback if needed
  if !@did_appear && index.row == rows_for_section(index.section).size - 1
    on_appear
  end
  cell.is_a?(UIView) ? cell : cell.view
end

#cell_name(table, index) ⇒ Object



193
194
195
196
197
198
199
200
201
# File 'motion-prime/sections/table.rb', line 193

def cell_name(table, index)
  record = row_by_index(index)
  if record && record.model &&
     record.model.respond_to?(:id) && record.model.id.present?
    "cell_#{record.model.id}_#{data_stamp_for("#{index.section}_#{index.row}")}"
  else
    "cell_#{index.section}_#{index.row}_#{data_stamp_for("#{index.section}_#{index.row}")}"
  end
end

#cell_styles(cell) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'motion-prime/sections/table.rb', line 77

def cell_styles(cell)
  # type = [`cell`, `header`, `field`]

  # UserFormSection example: field :email, type: :string
  # form_name = `user`
  # type = `field`
  # field_name = `email`
  # field_type = `string_field`

  # CategoriesTableSection example: table is a `CategoryTableSection`, cell is a `CategoryTitleSection`, element :icon, type: :image
  # table_name = `categories`
  # type = `cell` (always true)
  # table_cell_name = `title`
  type = cell.respond_to?(:cell_type) ? cell.cell_type : 'cell'
  suffixes = [type]
  if cell.is_a?(BaseFieldSection)
    suffixes << cell.default_name
  end

  styles = {}
  # table: base_table_<type>
  # form: base_form_<type>, base_form_<field_type>
  styles[:common] = build_styles_chain(table_styles[:common], suffixes)
  if cell.is_a?(BaseFieldSection)
    # form cell: _<type>_<field_name> = `_field_email`
    suffixes << :"#{type}_#{cell.name}" if cell.name
  elsif cell.respond_to?(:cell_name) # cell section came from table
    # table cell: _<table_cell_name> = `_title`
    suffixes << cell.cell_name
  end
  # table: <table_name>_table_<type>, <table_name>_table_<table_cell_name> = `categories_table_cell`, `categories_table_title`
  # form: <form_name>_form_<type>, <form_name>_form_<field_type>, user_form_<type>_email = `user_form_field`, `user_form_string_field`, `user_form_field_email`
  styles[:specific] = build_styles_chain(table_styles[:specific], suffixes)

  container_options_styles = cell.container_options[:styles]
  if container_options_styles.present?
    styles[:specific] += Array.wrap(container_options_styles)
  end

  styles
end

#dataObject



33
34
35
# File 'motion-prime/sections/table.rb', line 33

def data
  @data || set_table_data
end

#deallocObject



22
23
24
25
26
27
# File 'motion-prime/sections/table.rb', line 22

def dealloc
  Prime.logger.dealloc_message :table, self, self.table_view.to_s
  table_delegate.clear_delegated
  table_view.setDataSource nil
  super
end

#flat_data?Boolean

Returns:

  • (Boolean)


178
179
180
# File 'motion-prime/sections/table.rb', line 178

def flat_data?
  !has_many_sections?
end

#has_many_sections?Boolean

Returns:

  • (Boolean)


174
175
176
# File 'motion-prime/sections/table.rb', line 174

def has_many_sections?
  section_header_options.present? || data.try(:first).is_a?(Array)
end

#header_for_section(section) ⇒ Object



165
166
167
168
# File 'motion-prime/sections/table.rb', line 165

def header_for_section(section)
  self.section_headers ||= []
  self.section_headers[section] || render_header(section)
end

#height_for_header_in_section(table, section) ⇒ Object



240
241
242
# File 'motion-prime/sections/table.rb', line 240

def height_for_header_in_section(table, section)
  header_for_section(section).try(:container_height) || 0
end

#height_for_index(table, index) ⇒ Object



220
221
222
223
# File 'motion-prime/sections/table.rb', line 220

def height_for_index(table, index)
  section = load_cell_by_index(index, preload: true)
  section.container_height
end

#hideObject



140
141
142
# File 'motion-prime/sections/table.rb', line 140

def hide
  table_view.try(:hide)
end

#number_of_sections(table = nil) ⇒ Object

Table View Delegate




206
207
208
# File 'motion-prime/sections/table.rb', line 206

def number_of_sections(table = nil)
  has_many_sections? ? data.count : 1
end

#on_appearObject



171
# File 'motion-prime/sections/table.rb', line 171

def on_appear; end

#on_async_data_loadedObject



190
# File 'motion-prime/sections/table.rb', line 190

def on_async_data_loaded; end

#on_async_data_preloaded(loaded_index) ⇒ Object



191
# File 'motion-prime/sections/table.rb', line 191

def on_async_data_preloaded(loaded_index); end

#on_click(table, index) ⇒ Object



172
# File 'motion-prime/sections/table.rb', line 172

def on_click(table, index); end

#on_row_render(cell, index) ⇒ Object



170
# File 'motion-prime/sections/table.rb', line 170

def on_row_render(cell, index); end

#refresh_if_neededObject



47
48
49
# File 'motion-prime/sections/table.rb', line 47

def refresh_if_needed
  reload_table_data if @data.nil?
end

#reload_cell(section) ⇒ Object



61
62
63
64
65
# File 'motion-prime/sections/table.rb', line 61

def reload_cell(section)
  section.elements.values.each(&:compute_options!)
  section.cached_draw_image = nil
  # TODO: reset date stamps, reload row
end

#reload_dataObject



37
38
39
40
41
# File 'motion-prime/sections/table.rb', line 37

def reload_data
  reset_data
  @async_loaded_data = table_data if async_data?
  reload_table_data
end

#reload_table_dataObject



43
44
45
# File 'motion-prime/sections/table.rb', line 43

def reload_table_data
  table_view.reloadData
end

#render_cell(index, table) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
# File 'motion-prime/sections/table.rb', line 148

def render_cell(index, table)
  section = rows_for_section(index.section)[index.row]
  element = section.container_element || section.init_container_element(container_element_options_for(index))

  view = element.render do
    section.render
  end
  on_row_render(view, index)
  preload_sections_after(index)
  view
end

#render_header(section) ⇒ Object



160
161
162
163
# File 'motion-prime/sections/table.rb', line 160

def render_header(section)
  return unless options = self.section_header_options.try(:[], section)
  self.section_headers[section] ||= BaseHeaderSection.new(options.merge(screen: screen, table: self.weak_ref))
end

#render_tableObject



123
124
125
126
127
128
129
130
131
132
133
134
# File 'motion-prime/sections/table.rb', line 123

def render_table
  options = {
    styles: table_styles.values.flatten,
    delegate: table_delegate,
    data_source: table_delegate,
    style: (UITableViewStyleGrouped unless flat_data?)
  }
  if async_data? && self.class.async_data_options.has_key?(:estimated_row_height)
    options[:estimated_row_height] = self.class.async_data_options[:estimated_row_height]
  end
  self.table_element = screen.table_view(options)
end

#reset_dataObject



51
52
53
54
55
56
57
58
59
# File 'motion-prime/sections/table.rb', line 51

def reset_data
  @did_appear = false
  @data = nil
  @async_loaded_data = nil
  @preloader_next_starts_from = nil
  @preloader_cancelled = false
  @data_stamp = nil
  @preloader_queue[-1] = :cancelled if @preloader_queue.present?
end

#row_by_index(index) ⇒ Object



186
187
188
# File 'motion-prime/sections/table.rb', line 186

def row_by_index(index)
  rows_for_section(index.section)[index.row]
end

#rows_for_section(section) ⇒ Object



182
183
184
# File 'motion-prime/sections/table.rb', line 182

def rows_for_section(section)
  flat_data? ? data : data[section]
end

#scroll_view_did_end_decelerating(scroll) ⇒ Object



248
249
250
251
# File 'motion-prime/sections/table.rb', line 248

def scroll_view_did_end_decelerating(scroll)
  @decelerating = false
  display_pending_cells
end

#scroll_view_did_end_dragging(scroll, willDecelerate: will_decelerate) ⇒ Object



256
257
258
# File 'motion-prime/sections/table.rb', line 256

def scroll_view_did_end_dragging(scroll, willDecelerate: will_decelerate)
  display_pending_cells unless @decelerating = will_decelerate
end

#scroll_view_did_scroll(scroll) ⇒ Object



253
254
# File 'motion-prime/sections/table.rb', line 253

def scroll_view_did_scroll(scroll)
end

#scroll_view_will_begin_dragging(scroll) ⇒ Object



244
245
246
# File 'motion-prime/sections/table.rb', line 244

def scroll_view_will_begin_dragging(scroll)
  @decelerating = true
end

#showObject



144
145
146
# File 'motion-prime/sections/table.rb', line 144

def show
  table_view.try(:show)
end

#table_dataObject



18
19
20
# File 'motion-prime/sections/table.rb', line 18

def table_data
  @model || []
end

#table_delegateObject



119
120
121
# File 'motion-prime/sections/table.rb', line 119

def table_delegate
  @table_delegate ||= TableDelegate.new(section: self)
end

#table_stylesObject



67
68
69
70
71
72
73
74
75
# File 'motion-prime/sections/table.rb', line 67

def table_styles
  type = self.is_a?(FormSection) ? :base_form : :base_table

  base_styles = [type]
  base_styles << :"#{type}_with_sections" unless flat_data?
  item_styles = [name.to_sym]
  item_styles << @styles if @styles.present?
  {common: base_styles, specific: item_styles}
end

#table_viewObject



136
137
138
# File 'motion-prime/sections/table.rb', line 136

def table_view
  table_element.view
end

#view_for_header_in_section(table, section) ⇒ Object



225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'motion-prime/sections/table.rb', line 225

def view_for_header_in_section(table, section)
  return unless header = header_for_section(section)

  reuse_identifier = "header_#{section}"
  cached = table.dequeueReusableHeaderFooterViewWithIdentifier(reuse_identifier)
  return cached if cached.present?

  styles = cell_styles(header).values.flatten
  wrapper = MotionPrime::BaseElement.factory(:table_view_header_footer_view, screen: screen, styles: styles, parent_view: table_view, reuse_identifier: reuse_identifier)
  wrapper.render do |container_view, container_element|
    header.container_element = container_element
    header.render
  end
end