motion-prime 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|