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_section, #load_section!, #on_keyboard_hide, #on_keyboard_show, #reload_section, #render, #render!, #render_container, #render_element?, #view

Methods included from DelegateMixin

#clear_delegated, #delegated_by

Methods included from DrawSectionMixin

#bind_gesture_on_container_for, #draw_in, #prerender_elements_for_state, #prerender_enabled?, #strong_references

Methods included from SectionWithContainerMixin

#container_view, #init_container_element, #load_container_with_elements

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



439
440
441
# File 'motion-prime/sections/table.rb', line 439

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

.group_header(name, options) ⇒ Object



443
444
445
446
447
448
# File 'motion-prime/sections/table.rb', line 443

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

.inherited(subclass) ⇒ Object



433
434
435
436
437
# File 'motion-prime/sections/table.rb', line 433

def inherited(subclass)
  super
  subclass.async_data_options = self.async_data_options.try(:clone)
  subclass.section_header_options = self.section_header_options.try(:clone)
end

.pull_to_refresh(&block) ⇒ Object



450
451
452
# File 'motion-prime/sections/table.rb', line 450

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

Instance Method Details

#add_cells(cells) ⇒ Object



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

def add_cells(cells)
  prepare_table_cells(cells)
  @data ||= []
  @data += cells
  reload_table_data
end

#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



217
218
219
220
221
222
223
224
225
# File 'motion-prime/sections/table.rb', line 217

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



200
201
202
203
204
205
206
207
208
# File 'motion-prime/sections/table.rb', line 200

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



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
118
119
120
121
122
123
124
# File 'motion-prime/sections/table.rb', line 84

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)


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

def flat_data?
  !has_many_sections?
end

#has_many_sections?Boolean

Returns:

  • (Boolean)


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

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

#header_for_section(section) ⇒ Object



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

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

#height_for_header_in_section(table, section) ⇒ Object



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

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

#height_for_index(table, index) ⇒ Object



227
228
229
230
# File 'motion-prime/sections/table.rb', line 227

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

#hideObject



147
148
149
# File 'motion-prime/sections/table.rb', line 147

def hide
  table_view.try(:hide)
end

#number_of_sections(table = nil) ⇒ Object

Table View Delegate




213
214
215
# File 'motion-prime/sections/table.rb', line 213

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

#on_appearObject



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

def on_appear; end

#on_async_data_loadedObject



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

def on_async_data_loaded; end

#on_async_data_preloaded(loaded_index) ⇒ Object



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

def on_async_data_preloaded(loaded_index); end

#on_click(table, index) ⇒ Object



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

def on_click(table, index); end

#on_row_render(cell, index) ⇒ Object



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

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



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

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



155
156
157
158
159
160
161
162
163
164
165
# File 'motion-prime/sections/table.rb', line 155

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



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

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



130
131
132
133
134
135
136
137
138
139
140
141
# File 'motion-prime/sections/table.rb', line 130

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



193
194
195
# File 'motion-prime/sections/table.rb', line 193

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

#rows_for_section(section) ⇒ Object



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

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

#scroll_view_did_end_decelerating(scroll) ⇒ Object



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

def scroll_view_did_end_decelerating(scroll)
  @decelerating = false
  display_pending_cells
end

#scroll_view_did_end_dragging(scroll, willDecelerate: will_decelerate) ⇒ Object



263
264
265
# File 'motion-prime/sections/table.rb', line 263

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

#scroll_view_did_scroll(scroll) ⇒ Object



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

def scroll_view_did_scroll(scroll)
end

#scroll_view_will_begin_dragging(scroll) ⇒ Object



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

def scroll_view_will_begin_dragging(scroll)
  @decelerating = true
end

#showObject



151
152
153
# File 'motion-prime/sections/table.rb', line 151

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



126
127
128
# File 'motion-prime/sections/table.rb', line 126

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

#table_stylesObject



74
75
76
77
78
79
80
81
82
# File 'motion-prime/sections/table.rb', line 74

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



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

def table_view
  table_element.view
end

#view_for_header_in_section(table, section) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'motion-prime/sections/table.rb', line 232

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