Class: MotionPrime::Section

Inherits:
Object
  • Object
show all
Includes:
DelegateMixin, DrawSectionMixin, HasAuthorization, HasClassFactory, HasNormalizer, MotionSupport::Callbacks
Defined in:
motion-prime/sections/base_section.rb

Constant Summary collapse

KEYBOARD_HEIGHT_PORTRAIT =

Basic Sample

class MySection < MotionPrime::Section

element :title, text: "Hello World"
element :avatar, type: :image, image: 'defaults/avatar.jpg'

end

216
KEYBOARD_HEIGHT_LANDSCAPE =
162
DEFAULT_CONTENT_HEIGHT =
65

Instance Attribute Summary collapse

Attributes included from DrawSectionMixin

#cached_draw_image, #container_element, #container_gesture_recognizers

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DelegateMixin

#clear_delegated, #delegated_by

Methods included from DrawSectionMixin

#bind_gesture_on_container_for, #clear_gesture_for_receiver, #draw_in, #prerender_elements_for_state, #prerender_enabled?

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

#initialize(options = {}) ⇒ Section

Returns a new instance of Section.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'motion-prime/sections/base_section.rb', line 28

def initialize(options = {})
  @options = options

  run_callbacks :initialize do
    @options[:screen] = @options[:screen].try(:weak_ref)
    self.screen = options[:screen]
    @model = options[:model]
    @name = options[:name] ||= default_name
    @options_block = options[:block]
  end

  if Prime.env.development?
    @_section_info = "#{@name} #{screen.try(:class)}"
    @@_allocated_sections ||= []
    @@_allocated_sections << @_section_info
  end
end

Instance Attribute Details

#elementsObject

Returns the value of attribute elements.



24
25
26
# File 'motion-prime/sections/base_section.rb', line 24

def elements
  @elements
end

#modelObject

Returns the value of attribute model.



24
25
26
# File 'motion-prime/sections/base_section.rb', line 24

def model
  @model
end

#nameObject

Returns the value of attribute name.



24
25
26
# File 'motion-prime/sections/base_section.rb', line 24

def name
  @name
end

#optionsObject

Returns the value of attribute options.



24
25
26
# File 'motion-prime/sections/base_section.rb', line 24

def options
  @options
end

#screenObject

Returns the value of attribute screen.



24
25
26
# File 'motion-prime/sections/base_section.rb', line 24

def screen
  @screen
end

#section_stylesObject

Returns the value of attribute section_styles.



24
25
26
# File 'motion-prime/sections/base_section.rb', line 24

def section_styles
  @section_styles
end

Class Method Details

.after_initialize(*method_names, &block) ⇒ Object



399
400
401
# File 'motion-prime/sections/base_section.rb', line 399

def after_initialize(*method_names, &block)
  set_callback :initialize, :after, *method_names, &block
end

.after_render(*method_names, &block) ⇒ Object



393
394
395
# File 'motion-prime/sections/base_section.rb', line 393

def after_render(*method_names, &block)
  set_callback :render, :after, *method_names, &block
end

.before_initialize(*method_names, &block) ⇒ Object



396
397
398
# File 'motion-prime/sections/base_section.rb', line 396

def before_initialize(*method_names, &block)
  set_callback :initialize, :before, *method_names, &block
end

.before_render(*method_names, &block) ⇒ Object



390
391
392
# File 'motion-prime/sections/base_section.rb', line 390

def before_render(*method_names, &block)
  set_callback :render, :before, *method_names, &block
end

.bind_keyboard_close(options) ⇒ Object



402
403
404
# File 'motion-prime/sections/base_section.rb', line 402

def bind_keyboard_close(options)
  self.keyboard_close_bindings = options
end

.container(options) ⇒ Object



387
388
389
# File 'motion-prime/sections/base_section.rb', line 387

def container(options)
  self.container_options = options
end

.element(name, options = {}, &block) ⇒ Object



379
380
381
382
383
384
385
386
# File 'motion-prime/sections/base_section.rb', line 379

def element(name, options = {}, &block)
  options[:name] ||= name
  options[:type] ||= :label
  options[:block] = block
  self.elements_options ||= {}
  self.elements_options[name] = options
  self.elements_options[name]
end

.inherited(subclass) ⇒ Object



373
374
375
376
377
# File 'motion-prime/sections/base_section.rb', line 373

def inherited(subclass)
  subclass.elements_options = self.elements_options.try(:clone)
  subclass.container_options = self.container_options.try(:clone)
  subclass.keyboard_close_bindings = self.keyboard_close_bindings.try(:clone)
end

Instance Method Details

#add_element(key, options = {}) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'motion-prime/sections/base_section.rb', line 173

def add_element(key, options = {})
  return unless render_element?(key)
  opts = options.clone
  index = opts.delete(:at)
  options = build_options_for_element(opts)
  options[:name] ||= key
  element = build_element(options)
  if index
    new_elements_array = elements.to_a.insert(index, [key, element])
    self.elements = Hash[new_elements_array]
  else
    self.elements[key] = element
  end
  element
end

#bind_keyboard_eventsObject



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'motion-prime/sections/base_section.rb', line 257

def bind_keyboard_events
  NSNotificationCenter.defaultCenter.addObserver self,
                                     selector: :on_keyboard_show,
                                         name: UIKeyboardDidShowNotification,
                                       object: nil
  NSNotificationCenter.defaultCenter.addObserver self,
                                     selector: :on_keyboard_hide,
                                         name: UIKeyboardDidHideNotification,
                                       object: nil
  NSNotificationCenter.defaultCenter.addObserver self,
                                     selector: :keyboard_will_show,
                                         name: UIKeyboardWillShowNotification,
                                       object: nil
  NSNotificationCenter.defaultCenter.addObserver self,
                                     selector: :keyboard_will_hide,
                                         name: UIKeyboardWillHideNotification,
                                       object: nil
end

#cellObject



193
194
195
196
197
198
# File 'motion-prime/sections/base_section.rb', line 193

def cell
  container_view || begin
    first_element = elements.values.first
    first_element.view.superview.superview
  end
end

#container_boundsObject



60
61
62
# File 'motion-prime/sections/base_section.rb', line 60

def container_bounds
  options[:container_bounds] or raise "You must pass `container bounds` option to prerender base section"
end

#container_heightObject

Get computed container height

Examples:

class MySection < Prime::Section
  container height: proc { element(:title).content_outer_height }
  element :title, text: 'Hello world'
end
section = MySection.new
section.container_height # => 46


87
88
89
# File 'motion-prime/sections/base_section.rb', line 87

def container_height
  container_options[:height] || DEFAULT_CONTENT_HEIGHT
end

#container_optionsObject

Get computed container options



71
72
73
74
# File 'motion-prime/sections/base_section.rb', line 71

def container_options
  compute_container_options! unless @container_options
  @container_options
end

#create_elementsObject

Create elements if they are not created yet. This will not cause rendering elements, they will be rendered immediately after that or rendered async later, based on type of section.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'motion-prime/sections/base_section.rb', line 122

def create_elements
  return if @section_loaded
  if @section_loading
    sleep 0.1
    return @section_loaded ? false : create_elements
  end
  @section_loading = true

  self.elements = {}
  elements_options.each do |key, opts|
    add_element(key, opts)
  end
  self.instance_eval(&@options_block) if @options_block.is_a?(Proc)

  @section_loading = false
  return @section_loaded = true
end

#current_input_view_heightObject



294
295
296
# File 'motion-prime/sections/base_section.rb', line 294

def current_input_view_height
  App.shared.windows.last.subviews.first.try(:height) || KEYBOARD_HEIGHT_PORTRAIT
end

#deallocObject



46
47
48
49
50
51
52
53
54
# File 'motion-prime/sections/base_section.rb', line 46

def dealloc
  if Prime.env.development?
    index = @@_allocated_sections.index(@_section_info)
    @@_allocated_sections.delete_at(index)
  end
  Prime.logger.dealloc_message :section, self, self.name
  NSNotificationCenter.defaultCenter.removeObserver self # unbinding events created in bind_keyboard_events
  super
end

#default_nameObject

Get section default name, based on class name

Examples:

class ProfileSection < Prime::Section
end

section = ProfileSection.new
section.default_name # => 'profile'
section.name         # => 'profile'

another_section = ProfileSection.new(name: 'another')
another_section.default_name # => 'profile'
another_section.name         # => 'another'


106
107
108
# File 'motion-prime/sections/base_section.rb', line 106

def default_name
  self.class_name_without_kvo.demodulize.underscore.gsub(/\_section$/, '')
end

#element(name) ⇒ Object



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

def element(name)
  self.elements ||= {}
  self.elements[name.to_sym]
end

#elements_optionsObject

Get section elements options, where the key is element name.



113
114
115
# File 'motion-prime/sections/base_section.rb', line 113

def elements_options
  self.class.elements_options || {}
end

#elements_to_drawObject



286
287
288
# File 'motion-prime/sections/base_section.rb', line 286

def elements_to_draw
  self.elements.select { |key, element| element.is_a?(DrawElement) }
end

#elements_to_renderObject



290
291
292
# File 'motion-prime/sections/base_section.rb', line 290

def elements_to_render
  self.elements.except(*elements_to_draw.keys)
end

#has_container_bounds?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'motion-prime/sections/base_section.rb', line 64

def has_container_bounds?
  options[:container_bounds].present?
end

#hideObject



236
237
238
239
240
241
242
# File 'motion-prime/sections/base_section.rb', line 236

def hide
  if container_view
    container_view.hidden = true
  else
    elements.values.each(&:hide)
  end
end

#hide_keyboardObject



276
277
278
279
280
281
282
283
284
# File 'motion-prime/sections/base_section.rb', line 276

def hide_keyboard
  elements = Array.wrap(keyboard_close_bindings_options[:elements])
  views = Array.wrap(keyboard_close_bindings_options[:views])

  elements.each do |el|
    views << el.view if el.try(:view) && %w[text_field text_view].include?(el.view_name)
  end
  views.compact.each(&:resignFirstResponder)
end

#keyboard_will_hideObject



255
# File 'motion-prime/sections/base_section.rb', line 255

def keyboard_will_hide; end

#keyboard_will_showObject



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

def keyboard_will_show; end

#on_keyboard_hideObject



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

def on_keyboard_hide; end

#on_keyboard_showObject



252
# File 'motion-prime/sections/base_section.rb', line 252

def on_keyboard_show; end

#reloadBoolean

Alias for reload_section

Returns:

  • (Boolean)

    true



169
170
171
# File 'motion-prime/sections/base_section.rb', line 169

def reload
  reload_section
end

#reload_sectionBoolean

Force reload section, will also re-render elements. For table view cells will also reload it’s table data.

Returns:

  • (Boolean)

    true



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'motion-prime/sections/base_section.rb', line 144

def reload_section
  # reload Base Elements
  # TODO: probably should use update_with_options for Base elements too?
  self.elements_to_render.values.map(&:view).flatten.each do |view|
    view.removeFromSuperview if view
  end
  create_elements!
  run_callbacks :render do
    render!
  end
  # reload Draw Elements
  elements_to_draw.each do |key, element|
    element.update_with_options
  end

  if @table && !self.is_a?(BaseFieldSection)
    cell.setNeedsDisplay
    @table.reload_table_data
  end
  true
end

#render(container_options = {}) ⇒ Object



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

def render(container_options = {})
  create_elements
  self.container_options.merge!(container_options)
  run_callbacks :render do
    render!
  end
end

#render!Object



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

def render!
  render_container(container_options) do
    elements_to_render.each do |key, element|
      element.render
    end
  end
end

#render_container(options = {}, &block) ⇒ Object



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

def render_container(options = {}, &block)
  if should_render_container? && !self.container_element.try(:view)
    element = self.init_container_element(options)
    element.render do
      block.call
    end
  else
    block.call
  end
end

#render_element?(element_name) ⇒ Boolean

Returns:

  • (Boolean)


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

def render_element?(element_name)
  true
end

#screen?Boolean

Returns:

  • (Boolean)


298
299
300
# File 'motion-prime/sections/base_section.rb', line 298

def screen?
  screen && screen.weakref_alive?
end

#showObject



244
245
246
247
248
249
250
# File 'motion-prime/sections/base_section.rb', line 244

def show
  if container_view
    container_view.hidden = false
  else
    elements.values.each(&:show)
  end
end

#strong_referencesObject



56
57
58
# File 'motion-prime/sections/base_section.rb', line 56

def strong_references
  [screen, screen.main_controller]
end

#view(name) ⇒ Object



232
233
234
# File 'motion-prime/sections/base_section.rb', line 232

def view(name)
  element(name).view
end