motion-prime 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/ROADMAP.md +9 -4
- data/doc/code/getting_started.rb +1 -2
- data/doc/code/screens.rb +54 -0
- data/doc/docs/getting_started.html +27 -6
- data/doc/docs/screens.html +166 -0
- data/files/Gemfile +1 -1
- data/files/Gemfile.lock +64 -0
- data/files/app/environment.rb +10 -0
- data/files/app/styles/sidebar.rb +3 -10
- data/files/resources/images/menu_button.png +0 -0
- data/files/resources/images/menu_button@2x.png +0 -0
- data/motion-prime/app_delegate.rb +19 -0
- data/motion-prime/core_ext/kernel.rb +4 -0
- data/motion-prime/elements/_content_text_mixin.rb +23 -11
- data/motion-prime/elements/_text_mixin.rb +54 -0
- data/motion-prime/elements/base_element.rb +19 -14
- data/motion-prime/elements/draw.rb +22 -1
- data/motion-prime/elements/draw/_draw_background_mixin.rb +28 -28
- data/motion-prime/elements/draw/image.rb +67 -48
- data/motion-prime/elements/draw/label.rb +59 -49
- data/motion-prime/elements/draw/view.rb +5 -3
- data/motion-prime/helpers/has_style_chain_builder.rb +1 -3
- data/motion-prime/models/association_collection.rb +8 -0
- data/motion-prime/models/finder.rb +8 -0
- data/motion-prime/mp.rb +4 -0
- data/motion-prime/screens/_navigation_mixin.rb +4 -0
- data/motion-prime/screens/base_screen.rb +7 -0
- data/motion-prime/screens/sidebar_container_screen.rb +2 -2
- data/motion-prime/sections/_cell_section_mixin.rb +44 -5
- data/motion-prime/sections/_draw_section_mixin.rb +120 -0
- data/motion-prime/sections/base_section.rb +29 -24
- data/motion-prime/sections/form.rb +48 -65
- data/motion-prime/sections/form/base_field_section.rb +2 -2
- data/motion-prime/sections/table.rb +143 -82
- data/motion-prime/sections/table/table_delegate.rb +48 -0
- data/motion-prime/styles/form.rb +1 -1
- data/motion-prime/support/mp_cell_with_section.rb +6 -2
- data/motion-prime/support/mp_view_with_section.rb +1 -1
- data/motion-prime/version.rb +1 -1
- data/motion-prime/views/_frame_calculator_mixin.rb +4 -8
- data/motion-prime/views/layout.rb +1 -0
- data/motion-prime/views/view_styler.rb +3 -12
- metadata +34 -26
- data/motion-prime/sections/_draw_mixin.rb +0 -66
@@ -18,20 +18,33 @@ module MotionPrime
|
|
18
18
|
include HasAuthorization
|
19
19
|
include HasNormalizer
|
20
20
|
include HasClassFactory
|
21
|
-
include
|
21
|
+
include DrawSectionMixin
|
22
22
|
|
23
23
|
attr_accessor :screen, :model, :name, :options, :elements, :section_styles
|
24
|
-
class_attribute :elements_options, :container_options, :keyboard_close_bindings
|
24
|
+
class_attribute :elements_options, :container_options, :keyboard_close_bindings
|
25
25
|
define_callbacks :render
|
26
26
|
|
27
27
|
def initialize(options = {})
|
28
28
|
@options = options
|
29
|
-
self.screen = options[:screen]
|
29
|
+
self.screen = options[:screen].try(:weak_ref)
|
30
30
|
@model = options[:model]
|
31
31
|
@name = options[:name] ||= default_name
|
32
32
|
@options_block = options[:block]
|
33
33
|
end
|
34
34
|
|
35
|
+
def dealloc
|
36
|
+
pp 'deallocating section. elements count: ', self.elements.try(:count)
|
37
|
+
self.elements = nil
|
38
|
+
|
39
|
+
NSNotificationCenter.defaultCenter.removeObserver self
|
40
|
+
self.delegate = nil if self.respond_to?(:delegate)
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def container_bounds
|
45
|
+
options[:container_bounds] or raise "You must pass `container bounds` option to prerender base section"
|
46
|
+
end
|
47
|
+
|
35
48
|
def container_options
|
36
49
|
compute_container_options! unless @container_options
|
37
50
|
@container_options
|
@@ -58,6 +71,7 @@ module MotionPrime
|
|
58
71
|
@section_loading = true
|
59
72
|
create_elements
|
60
73
|
@section_loading = false
|
74
|
+
|
61
75
|
return @section_loaded = true
|
62
76
|
end
|
63
77
|
|
@@ -75,7 +89,7 @@ module MotionPrime
|
|
75
89
|
|
76
90
|
if @table && !self.is_a?(BaseFieldSection)
|
77
91
|
cell.setNeedsDisplay
|
78
|
-
@table.
|
92
|
+
@table.reload_table_data
|
79
93
|
end
|
80
94
|
end
|
81
95
|
|
@@ -90,7 +104,7 @@ module MotionPrime
|
|
90
104
|
def load_elements
|
91
105
|
self.elements.values.each do |element|
|
92
106
|
element.size_to_fit_if_needed if element.is_a?(LabelDrawElement)
|
93
|
-
element.
|
107
|
+
element.compute_options! if element.respond_to?(:computed_options) && !element.computed_options
|
94
108
|
end
|
95
109
|
end
|
96
110
|
|
@@ -127,9 +141,8 @@ module MotionPrime
|
|
127
141
|
end
|
128
142
|
|
129
143
|
def render(container_options = {})
|
130
|
-
self.container_options.merge!(container_options)
|
131
144
|
load_section
|
132
|
-
|
145
|
+
self.container_options.merge!(container_options)
|
133
146
|
run_callbacks :render do
|
134
147
|
render!
|
135
148
|
end
|
@@ -170,12 +183,6 @@ module MotionPrime
|
|
170
183
|
def keyboard_will_show; end
|
171
184
|
def keyboard_will_hide; end
|
172
185
|
|
173
|
-
def dealloc
|
174
|
-
NSNotificationCenter.defaultCenter.removeObserver self
|
175
|
-
self.delegate = nil if self.respond_to?(:delegate)
|
176
|
-
super
|
177
|
-
end
|
178
|
-
|
179
186
|
def bind_keyboard_events
|
180
187
|
NSNotificationCenter.defaultCenter.addObserver self,
|
181
188
|
selector: :on_keyboard_show,
|
@@ -203,6 +210,14 @@ module MotionPrime
|
|
203
210
|
views.compact.each(&:resignFirstResponder)
|
204
211
|
end
|
205
212
|
|
213
|
+
def elements_to_draw
|
214
|
+
self.elements.select { |key, element| element.is_a?(DrawElement) }
|
215
|
+
end
|
216
|
+
|
217
|
+
def elements_to_render
|
218
|
+
self.elements.select { |key, element| element.is_a?(BaseElement) }
|
219
|
+
end
|
220
|
+
|
206
221
|
protected
|
207
222
|
def bind_keyboard_close
|
208
223
|
return unless self.class.keyboard_close_bindings.present?
|
@@ -216,20 +231,13 @@ module MotionPrime
|
|
216
231
|
def keyboard_close_bindings_options
|
217
232
|
@keyboard_close_bindings_options ||= normalize_options(self.class.keyboard_close_bindings.clone, self)
|
218
233
|
end
|
219
|
-
def elements_to_draw
|
220
|
-
self.elements.select { |key, element| element.is_a?(DrawElement) }
|
221
|
-
end
|
222
|
-
|
223
|
-
def elements_to_render
|
224
|
-
self.elements.select { |key, element| element.is_a?(BaseElement) }
|
225
|
-
end
|
226
234
|
|
227
235
|
def build_options_for_element(opts)
|
228
236
|
# we should clone options to prevent overriding options
|
229
237
|
# in next element with same name in another class
|
230
238
|
options = opts.clone
|
231
239
|
options[:type] ||= (options[:text] || options[:attributed_text_options]) ? :label : :view
|
232
|
-
options.merge(screen: screen, section: self)
|
240
|
+
options.merge(screen: screen.try(:weak_ref), section: self.weak_ref)
|
233
241
|
end
|
234
242
|
|
235
243
|
private
|
@@ -269,9 +277,6 @@ module MotionPrime
|
|
269
277
|
def bind_keyboard_close(options)
|
270
278
|
self.keyboard_close_bindings = options
|
271
279
|
end
|
272
|
-
def set_cell_name(value)
|
273
|
-
self.cell_name = value
|
274
|
-
end
|
275
280
|
end
|
276
281
|
after_render :bind_keyboard_events
|
277
282
|
after_render :bind_keyboard_close
|
@@ -18,42 +18,17 @@ module MotionPrime
|
|
18
18
|
# end
|
19
19
|
#
|
20
20
|
|
21
|
-
class_attribute :text_field_limits, :text_view_limits
|
22
|
-
|
23
|
-
attr_accessor :fields, :field_indexes, :keyboard_visible, :rendered_views, :section_headers, :section_header_options
|
21
|
+
class_attribute :fields_options, :text_field_limits, :text_view_limits
|
22
|
+
attr_accessor :fields, :field_indexes, :keyboard_visible, :rendered_views, :grouped_data
|
24
23
|
|
25
24
|
def table_data
|
26
|
-
if
|
27
|
-
|
28
|
-
data = fields.inject([]) do |result, (key, field)|
|
29
|
-
section = self.class.fields_options[key][:group].to_i
|
30
|
-
section_indexes[section] ||= 0
|
31
|
-
result[section] ||= []
|
32
|
-
result[section][section_indexes[section]] = field
|
33
|
-
section_indexes[section] += 1
|
34
|
-
result
|
35
|
-
end
|
36
|
-
self.section_header_options.delete_if.each_with_index { |opts, id| data[id].nil? }
|
37
|
-
data.compact
|
25
|
+
if has_many_sections?
|
26
|
+
grouped_data.compact
|
38
27
|
else
|
39
28
|
fields.values
|
40
29
|
end
|
41
30
|
end
|
42
31
|
|
43
|
-
def data
|
44
|
-
@data ||= table_data
|
45
|
-
end
|
46
|
-
|
47
|
-
def render_table
|
48
|
-
init_form_fields
|
49
|
-
options = {
|
50
|
-
styles: table_styles.values.flatten,
|
51
|
-
delegate: self,
|
52
|
-
dataSource: self,
|
53
|
-
style: (UITableViewStyleGrouped unless flat_data?)}
|
54
|
-
self.table_element = screen.table_view(options)
|
55
|
-
end
|
56
|
-
|
57
32
|
def reload_cell(section)
|
58
33
|
field = section.name.to_sym
|
59
34
|
index = field_indexes[field].split('_').map(&:to_i)
|
@@ -223,27 +198,46 @@ module MotionPrime
|
|
223
198
|
end
|
224
199
|
end
|
225
200
|
|
226
|
-
def
|
227
|
-
|
228
|
-
|
201
|
+
def reload_data
|
202
|
+
@groups_count = nil
|
203
|
+
reset_data
|
204
|
+
init_form_fields
|
205
|
+
reload_table_data
|
206
|
+
end
|
207
|
+
|
208
|
+
def reset_data
|
209
|
+
super
|
210
|
+
self.fields.values.each(&:clear_observers)
|
211
|
+
end
|
212
|
+
|
213
|
+
def has_many_sections?
|
214
|
+
section_header_options.present? || grouped_data.count > 1
|
229
215
|
end
|
230
216
|
|
231
|
-
def
|
232
|
-
self.
|
233
|
-
|
217
|
+
def render_table
|
218
|
+
init_form_fields unless self.fields.present?
|
219
|
+
super
|
234
220
|
end
|
235
221
|
|
236
|
-
def
|
237
|
-
return unless
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
header.render
|
222
|
+
def reload_table_data
|
223
|
+
return super unless async_data?
|
224
|
+
sections = NSMutableIndexSet.new
|
225
|
+
number_of_sections.times do |section_id|
|
226
|
+
sections.addIndex(section_id)
|
242
227
|
end
|
228
|
+
table_view.reloadSections sections, withRowAnimation: UITableViewRowAnimationFade
|
243
229
|
end
|
244
230
|
|
245
|
-
|
246
|
-
|
231
|
+
# Table View Delegate
|
232
|
+
# ---------------------
|
233
|
+
|
234
|
+
def number_of_sections(table = nil)
|
235
|
+
has_many_sections? ? grouped_data.compact.count : 1
|
236
|
+
end
|
237
|
+
|
238
|
+
def height_for_index(table, index)
|
239
|
+
section = load_cell_by_index(index, preload: false)
|
240
|
+
section.container_height
|
247
241
|
end
|
248
242
|
|
249
243
|
class << self
|
@@ -256,13 +250,6 @@ module MotionPrime
|
|
256
250
|
self.fields_options[name]
|
257
251
|
end
|
258
252
|
|
259
|
-
def group_header(name, options)
|
260
|
-
options[:name] = name
|
261
|
-
self.section_header_options ||= []
|
262
|
-
section = options.delete(:id)
|
263
|
-
self.section_header_options[section] = options
|
264
|
-
end
|
265
|
-
|
266
253
|
def limit_text_field_length(name, limit)
|
267
254
|
self.text_field_limits ||= {}
|
268
255
|
self.text_field_limits[name] = limit
|
@@ -273,40 +260,36 @@ module MotionPrime
|
|
273
260
|
end
|
274
261
|
end
|
275
262
|
|
276
|
-
def reload_data
|
277
|
-
@groups_count = nil
|
278
|
-
reset_data
|
279
|
-
init_form_fields
|
280
|
-
table_view.reloadData
|
281
|
-
end
|
282
|
-
|
283
|
-
def reset_data
|
284
|
-
super
|
285
|
-
self.fields.values.each(&:clear_observers)
|
286
|
-
end
|
287
|
-
|
288
263
|
private
|
264
|
+
def load_sections; end
|
265
|
+
|
289
266
|
def init_form_fields
|
290
267
|
self.fields = {}
|
291
268
|
self.field_indexes = {}
|
269
|
+
self.grouped_data = []
|
292
270
|
section_indexes = []
|
293
271
|
(self.class.fields_options || {}).each do |key, field|
|
294
272
|
next unless render_field?(key, field)
|
295
273
|
section_id = field[:group].to_i
|
296
274
|
@groups_count = [@groups_count || 1, section_id + 1].max
|
297
|
-
self.fields[key] = load_field(field)
|
298
275
|
|
276
|
+
grouped_data[section_id] ||= []
|
299
277
|
section_indexes[section_id] ||= 0
|
278
|
+
|
279
|
+
section = load_field(field)
|
280
|
+
self.fields[key] = section
|
300
281
|
self.field_indexes[key] = "#{section_id}_#{section_indexes[section_id]}"
|
282
|
+
grouped_data[section_id][section_indexes[section_id]] = section
|
283
|
+
|
301
284
|
section_indexes[section_id] += 1
|
302
285
|
end
|
303
286
|
init_form_headers
|
304
|
-
@has_groups = section_header_options.present? || @groups_count > 1
|
305
287
|
reset_data_stamps
|
306
288
|
end
|
307
289
|
|
308
290
|
def init_form_headers
|
309
|
-
|
291
|
+
options = Array.wrap(self.class.section_header_options).clone
|
292
|
+
self.section_header_options = options.delete_if.each_with_index { |opts, id| grouped_data[id].nil? }
|
310
293
|
end
|
311
294
|
end
|
312
295
|
end
|
@@ -7,7 +7,7 @@ module MotionPrime
|
|
7
7
|
after_render :on_section_render
|
8
8
|
|
9
9
|
def initialize(options = {})
|
10
|
-
@form = options[:table]
|
10
|
+
@form = options[:table].try(:weak_ref)
|
11
11
|
@errors_observer_options = normalize_options(options.delete(:observe_errors).clone, self) if options[:observe_errors]
|
12
12
|
super
|
13
13
|
observe_model_errors
|
@@ -37,7 +37,7 @@ module MotionPrime
|
|
37
37
|
reload_section
|
38
38
|
else
|
39
39
|
load_section!
|
40
|
-
form.
|
40
|
+
form.reload_table_data
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -1,14 +1,24 @@
|
|
1
1
|
motion_require './table/refresh_mixin'
|
2
|
+
motion_require './table/table_delegate'
|
3
|
+
|
2
4
|
module MotionPrime
|
3
5
|
class TableSection < BaseSection
|
4
6
|
include TableSectionRefreshMixin
|
5
7
|
include HasStyleChainBuilder
|
6
8
|
include HasSearchBar
|
7
9
|
|
8
|
-
class_attribute :async_data_options
|
9
|
-
attr_accessor :table_element, :did_appear
|
10
|
+
class_attribute :async_data_options, :section_header_options
|
11
|
+
attr_accessor :table_element, :did_appear, :section_headers, :section_header_options
|
12
|
+
attr_reader :decelerating
|
10
13
|
before_render :render_table
|
11
14
|
|
15
|
+
def dealloc
|
16
|
+
pp 'deallocating table. sections count:', @data.try(:count)
|
17
|
+
@data = nil
|
18
|
+
@async_loaded_data = nil
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
12
22
|
def table_data
|
13
23
|
[]
|
14
24
|
end
|
@@ -24,11 +34,15 @@ module MotionPrime
|
|
24
34
|
def reload_data
|
25
35
|
reset_data
|
26
36
|
@async_loaded_data = table_data if async_data?
|
37
|
+
reload_table_data
|
38
|
+
end
|
39
|
+
|
40
|
+
def reload_table_data
|
27
41
|
table_view.reloadData
|
28
42
|
end
|
29
43
|
|
30
44
|
def refresh_if_needed
|
31
|
-
|
45
|
+
reload_table_data if @data.nil?
|
32
46
|
end
|
33
47
|
|
34
48
|
def reset_data
|
@@ -36,14 +50,16 @@ module MotionPrime
|
|
36
50
|
@data = nil
|
37
51
|
@async_loaded_data = nil
|
38
52
|
@next_portion_starts_from = nil
|
53
|
+
@preloader_cancelled = false
|
39
54
|
@data_stamp = nil
|
55
|
+
@queue_states[-1] = :cancelled if @queue_states.present?
|
40
56
|
end
|
41
57
|
|
42
58
|
def table_styles
|
43
59
|
type = self.is_a?(FormSection) ? :base_form : :base_table
|
44
60
|
|
45
61
|
base_styles = [type]
|
46
|
-
base_styles << :"#{type}_with_sections" unless flat_data?
|
62
|
+
base_styles << :"#{type}_with_sections" #unless flat_data?
|
47
63
|
item_styles = [name.to_sym]
|
48
64
|
item_styles << @styles if @styles.present?
|
49
65
|
{common: base_styles, specific: item_styles}
|
@@ -92,10 +108,11 @@ module MotionPrime
|
|
92
108
|
end
|
93
109
|
|
94
110
|
def render_table
|
111
|
+
delegate = TableDelegate.new(section: self)
|
95
112
|
options = {
|
96
113
|
styles: table_styles.values.flatten,
|
97
|
-
delegate:
|
98
|
-
data_source:
|
114
|
+
delegate: delegate,
|
115
|
+
data_source: delegate,
|
99
116
|
style: (UITableViewStyleGrouped unless flat_data?)
|
100
117
|
}
|
101
118
|
if async_data? && self.class.async_data_options.has_key?(:estimated_row_height)
|
@@ -118,38 +135,71 @@ module MotionPrime
|
|
118
135
|
|
119
136
|
def render_cell(index, table)
|
120
137
|
section = rows_for_section(index.section)[index.row]
|
121
|
-
|
122
|
-
|
123
|
-
|
138
|
+
element = section.container_element || section.init_container_element(container_element_options_for(index))
|
139
|
+
|
140
|
+
view = element.render do
|
141
|
+
rows_for_section(index.section)[index.row].render
|
124
142
|
end
|
125
143
|
|
126
|
-
@rendered_cells[index.section][index.row] =
|
127
|
-
on_row_render(
|
144
|
+
@rendered_cells[index.section][index.row] = view
|
145
|
+
on_row_render(view, index)
|
128
146
|
|
129
147
|
preload_sections_for(index)
|
130
148
|
|
131
|
-
|
149
|
+
view
|
150
|
+
end
|
151
|
+
|
152
|
+
def render_header(section)
|
153
|
+
return unless options = self.section_header_options.try(:[], section)
|
154
|
+
self.section_headers[section] ||= BaseHeaderSection.new(options.merge(screen: screen, table: self))
|
155
|
+
end
|
156
|
+
|
157
|
+
def header_for_section(section)
|
158
|
+
self.section_headers ||= []
|
159
|
+
self.section_headers[section] || render_header(section)
|
132
160
|
end
|
133
161
|
|
134
162
|
def on_row_render(cell, index); end
|
135
163
|
def on_appear; end
|
136
164
|
def on_click(table, index); end
|
137
165
|
|
138
|
-
|
139
|
-
|
166
|
+
def has_many_sections?
|
167
|
+
section_header_options.present? || data.try(:first).is_a?(Array)
|
168
|
+
end
|
169
|
+
|
170
|
+
def flat_data?
|
171
|
+
!has_many_sections?
|
172
|
+
end
|
173
|
+
|
174
|
+
def rows_for_section(section)
|
175
|
+
flat_data? ? data : data[section]
|
176
|
+
end
|
177
|
+
|
178
|
+
def row_by_index(index)
|
179
|
+
rows_for_section(index.section)[index.row]
|
180
|
+
end
|
181
|
+
|
182
|
+
def on_async_data_loaded; end
|
183
|
+
def on_async_data_preloaded(loaded_index); end
|
184
|
+
|
185
|
+
def cell_name(table, index)
|
186
|
+
record = row_by_index(index)
|
187
|
+
if record && record.model &&
|
188
|
+
record.model.respond_to?(:id) && record.model.id.present?
|
189
|
+
"cell_#{record.model.id}_#{data_stamp_for("#{index.section}_#{index.row}")}"
|
190
|
+
else
|
191
|
+
"cell_#{index.section}_#{index.row}_#{data_stamp_for("#{index.section}_#{index.row}")}"
|
192
|
+
end
|
193
|
+
end
|
140
194
|
|
141
|
-
#
|
142
|
-
#
|
143
|
-
# end
|
144
|
-
# def tableView(table, heightForFooterInSection: section)
|
145
|
-
# 0.1
|
146
|
-
# end
|
195
|
+
# Table View Delegate
|
196
|
+
# ---------------------
|
147
197
|
|
148
|
-
def
|
149
|
-
|
198
|
+
def number_of_sections(table = nil)
|
199
|
+
has_many_sections? ? data.count : 1
|
150
200
|
end
|
151
201
|
|
152
|
-
def
|
202
|
+
def cell_for_index(table, index)
|
153
203
|
@rendered_cells ||= []
|
154
204
|
@rendered_cells[index.section] ||= []
|
155
205
|
|
@@ -162,58 +212,48 @@ module MotionPrime
|
|
162
212
|
cell.is_a?(UIView) ? cell : cell.view
|
163
213
|
end
|
164
214
|
|
165
|
-
def
|
166
|
-
|
215
|
+
def height_for_index(table, index)
|
216
|
+
section = load_cell_by_index(index, preload: true)
|
217
|
+
section.container_height
|
167
218
|
end
|
168
219
|
|
169
|
-
def
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
def tableView(table, heightForRowAtIndexPath: index)
|
174
|
-
load_cell_by_index(index)
|
175
|
-
cell = rows_for_section(index.section)[index.row]
|
176
|
-
cell.container_height
|
177
|
-
end
|
220
|
+
def view_for_header_in_section(table, section)
|
221
|
+
return unless header = header_for_section(section)
|
178
222
|
|
179
|
-
|
180
|
-
|
181
|
-
|
223
|
+
reuse_identifier = "header_#{section}"
|
224
|
+
cached = table.dequeueReusableHeaderFooterViewWithIdentifier(reuse_identifier)
|
225
|
+
return cached if cached.present?
|
182
226
|
|
183
|
-
|
184
|
-
|
227
|
+
styles = cell_styles(header).values.flatten
|
228
|
+
wrapper = MotionPrime::BaseElement.factory(:table_view_header_footer_view, screen: screen, styles: styles, parent_view: table_view, reuse_identifier: reuse_identifier)
|
229
|
+
wrapper.render do |container_view, container_element|
|
230
|
+
header.container_element = container_element
|
231
|
+
header.render
|
232
|
+
end
|
185
233
|
end
|
186
234
|
|
187
|
-
def
|
188
|
-
|
235
|
+
def height_for_header_in_section(table, section)
|
236
|
+
header_for_section(section).try(:container_height) || 0
|
189
237
|
end
|
190
238
|
|
191
|
-
def
|
192
|
-
|
239
|
+
def scroll_view_will_begin_dragging(scroll)
|
240
|
+
@decelerating = true
|
193
241
|
end
|
194
242
|
|
195
|
-
def
|
196
|
-
|
243
|
+
def scroll_view_did_end_decelerating(scroll)
|
244
|
+
@decelerating = false
|
245
|
+
display_pending_cells
|
197
246
|
end
|
198
247
|
|
199
|
-
def
|
200
|
-
|
248
|
+
def scroll_view_did_end_dragging(scroll, willDecelerate: will_decelerate)
|
249
|
+
display_pending_cells unless @decelerating = will_decelerate
|
201
250
|
end
|
202
251
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
def cell_name(table, index)
|
207
|
-
record = row_by_index(index)
|
208
|
-
if record && record.model &&
|
209
|
-
record.model.respond_to?(:id) && record.model.id.present?
|
210
|
-
"cell_#{record.model.id}_#{data_stamp_for("#{index.section}_#{index.row}")}"
|
211
|
-
else
|
212
|
-
"cell_#{index.section}_#{index.row}_#{data_stamp_for("#{index.section}_#{index.row}")}"
|
252
|
+
private
|
253
|
+
def display_pending_cells
|
254
|
+
table_view.visibleCells.each { |cell_view| cell_view.section.display if cell_view.section.pending_display }
|
213
255
|
end
|
214
|
-
end
|
215
256
|
|
216
|
-
private
|
217
257
|
def set_table_data
|
218
258
|
cells = async_data? ? load_sections_async : table_data
|
219
259
|
prepare_table_cells(cells)
|
@@ -228,7 +268,7 @@ module MotionPrime
|
|
228
268
|
BW::Reactor.schedule_on_main do
|
229
269
|
@async_loaded_data = table_data
|
230
270
|
@data = nil
|
231
|
-
|
271
|
+
reload_table_data
|
232
272
|
on_async_data_loaded
|
233
273
|
end
|
234
274
|
[]
|
@@ -240,31 +280,29 @@ module MotionPrime
|
|
240
280
|
table.dequeueReusableCellWithIdentifier(cell_name(table, index))
|
241
281
|
end
|
242
282
|
|
243
|
-
def prepare_table_cells(
|
244
|
-
|
245
|
-
cell.
|
246
|
-
|
247
|
-
cell.
|
283
|
+
def prepare_table_cells(cell)
|
284
|
+
if cell.is_a?(Array)
|
285
|
+
cell.each { |c| prepare_table_cells(c) }
|
286
|
+
else
|
287
|
+
cell.class.send(:include, CellSectionMixin)
|
288
|
+
cell.screen ||= screen
|
289
|
+
cell.table ||= WeakRef.new(self) if cell.respond_to?(:table=)
|
248
290
|
end
|
249
291
|
end
|
250
292
|
|
251
|
-
def load_cell_by_index(index)
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
if async_data?
|
256
|
-
container_element = container_element_for(index)
|
257
|
-
container_element.computed_options # compute options
|
293
|
+
def load_cell_by_index(index, options = {})
|
294
|
+
section = rows_for_section(index.section)[index.row]
|
295
|
+
if section.load_section && options[:preload] && !section.container_element && async_data? # perform only if just loaded
|
296
|
+
section.load_container_element(container_element_options_for(index))
|
258
297
|
end
|
298
|
+
section
|
259
299
|
end
|
260
300
|
|
261
|
-
def
|
262
|
-
|
263
|
-
options = {
|
301
|
+
def container_element_options_for(index)
|
302
|
+
{
|
264
303
|
reuse_identifier: cell_name(table_view, index),
|
265
304
|
parent_view: table_view
|
266
305
|
}
|
267
|
-
cell.load_container_element(options)
|
268
306
|
end
|
269
307
|
|
270
308
|
def data_stamp_for(id)
|
@@ -295,7 +333,7 @@ module MotionPrime
|
|
295
333
|
if flat_data?
|
296
334
|
data.each(&:load_section)
|
297
335
|
else
|
298
|
-
data.
|
336
|
+
data.each { |section_data| section_data.each(&:load_section) }
|
299
337
|
end
|
300
338
|
end
|
301
339
|
|
@@ -306,7 +344,6 @@ module MotionPrime
|
|
306
344
|
load_limit = self.class.async_data_options.try(:[], :preload_rows_count)
|
307
345
|
@next_portion_starts_from ||= index
|
308
346
|
start_preload_when_index_loaded = service.sum_index(@next_portion_starts_from, load_limit ? -load_limit/2 : 0)
|
309
|
-
|
310
347
|
if service.compare_indexes(index, start_preload_when_index_loaded) >= 0
|
311
348
|
section = @next_portion_starts_from.section
|
312
349
|
next_row = @next_portion_starts_from.row
|
@@ -315,12 +352,23 @@ module MotionPrime
|
|
315
352
|
load_count = [left_to_load, load_limit].compact.min
|
316
353
|
|
317
354
|
next_index = @next_portion_starts_from
|
318
|
-
|
319
|
-
|
320
|
-
|
355
|
+
@preloader_cancelled = false
|
356
|
+
|
357
|
+
@queue_states ||= []
|
358
|
+
|
359
|
+
BW::Reactor.schedule(@queue_states.count) do |queue_id|
|
360
|
+
@queue_states[queue_id] = :in_progress
|
361
|
+
|
362
|
+
result = load_count.times do |offset|
|
363
|
+
break if @queue_states[queue_id] == :cancelled
|
364
|
+
load_cell_by_index(next_index, preload: true)
|
321
365
|
next_index = service.sum_index(next_index, 1) unless offset == load_count - 1
|
322
366
|
end
|
323
|
-
|
367
|
+
|
368
|
+
if result
|
369
|
+
on_async_data_preloaded(next_index)
|
370
|
+
@queue_states[queue_id] = :completed
|
371
|
+
end
|
324
372
|
end
|
325
373
|
|
326
374
|
@next_portion_starts_from = service.sum_index(@next_portion_starts_from, load_count, false)
|
@@ -330,5 +378,18 @@ module MotionPrime
|
|
330
378
|
def index_service
|
331
379
|
TableDataIndexes.new(@data)
|
332
380
|
end
|
381
|
+
|
382
|
+
class << self
|
383
|
+
def async_table_data(options = {})
|
384
|
+
self.async_data_options = options
|
385
|
+
end
|
386
|
+
|
387
|
+
def group_header(name, options)
|
388
|
+
options[:name] = name
|
389
|
+
self.section_header_options ||= []
|
390
|
+
section = options.delete(:id)
|
391
|
+
self.section_header_options[section] = options
|
392
|
+
end
|
393
|
+
end
|
333
394
|
end
|
334
395
|
end
|