motion-prime 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +8 -9
- data/ROADMAP.md +4 -5
- data/bin/prime +19 -14
- data/files/Rakefile +0 -1
- data/files/app/app_delegate.rb +0 -12
- data/files/app/config/base.rb +1 -12
- data/files/app/screens/application.rb +1 -5
- data/files/app/sections/.gitkeep +0 -0
- data/files/app/styles/.gitkeep +0 -0
- data/files/resources/Default-568h@2x.png +0 -0
- data/files/resources/Default.png +0 -0
- data/files/resources/Default@2x.png +0 -0
- data/motion-prime/api_client.rb +2 -1
- data/motion-prime/config/base.rb +8 -3
- data/motion-prime/config/config.rb +18 -0
- data/motion-prime/elements/_text_mixin.rb +0 -4
- data/motion-prime/elements/base_element.rb +64 -51
- data/motion-prime/elements/draw/image.rb +3 -2
- data/motion-prime/elements/draw/label.rb +9 -2
- data/motion-prime/helpers/has_search_bar.rb +10 -1
- data/motion-prime/screens/_base_mixin.rb +1 -1
- data/motion-prime/screens/_sections_mixin.rb +8 -4
- data/motion-prime/sections/__section_with_container_mixin.rb +52 -0
- data/motion-prime/sections/_cell_section_mixin.rb +7 -21
- data/motion-prime/sections/_delegate_mixin.rb +12 -0
- data/motion-prime/sections/_draw_section_mixin.rb +4 -21
- data/motion-prime/sections/base_section.rb +7 -7
- data/motion-prime/sections/form.rb +7 -0
- data/motion-prime/sections/form/base_field_section.rb +9 -0
- data/motion-prime/sections/form/date_field_section.rb +1 -1
- data/motion-prime/sections/form/form_delegate.rb +0 -1
- data/motion-prime/sections/form/password_field_section.rb +1 -1
- data/motion-prime/sections/form/select_field_section.rb +1 -1
- data/motion-prime/sections/form/string_field_section.rb +1 -1
- data/motion-prime/sections/form/submit_field_section.rb +1 -1
- data/motion-prime/sections/form/switch_field_section.rb +1 -1
- data/motion-prime/sections/form/text_field_section.rb +1 -1
- data/motion-prime/sections/tabbed.rb +7 -0
- data/motion-prime/sections/table.rb +20 -7
- data/motion-prime/sections/table/table_delegate.rb +1 -9
- data/motion-prime/styles/base.rb +1 -1
- data/motion-prime/styles/form.rb +7 -7
- data/motion-prime/version.rb +1 -1
- data/motion-prime/views/layout.rb +4 -2
- metadata +6 -14
- data/files/app/screens/help.rb +0 -6
- data/files/app/screens/home.rb +0 -8
- data/files/app/screens/sidebar.rb +0 -14
- data/files/app/sections/home/section.rb +0 -3
- data/files/app/sections/sidebar/action.rb +0 -5
- data/files/app/sections/sidebar/table.rb +0 -20
- data/files/app/styles/home.rb +0 -9
- data/files/resources/fonts/ubuntu.ttf +0 -0
- data/files/resources/images/arrow.png +0 -0
- data/files/resources/images/menu_button.png +0 -0
- data/files/resources/images/menu_button@2x.png +0 -0
- data/motion-prime/styles/sidebar.rb +0 -23
@@ -66,14 +66,15 @@ module MotionPrime
|
|
66
66
|
|
67
67
|
def load_image
|
68
68
|
return if image_data || !computed_options[:url]
|
69
|
+
# TODO: why so many references?
|
70
|
+
@strong_refs = section.strong_references + [screen.main_controller.strong_ref]
|
69
71
|
BW::Reactor.schedule do
|
70
72
|
manager = SDWebImageManager.sharedManager
|
71
|
-
@strong_refs = section.strong_references
|
72
73
|
manager.downloadWithURL(computed_options[:url],
|
73
74
|
options: 0,
|
74
75
|
progress: lambda{ |r_size, e_size| },
|
75
76
|
completed: lambda{ |image, error, type, finished|
|
76
|
-
if !image || screen.retainCount == 1 || section.retainCount == 1
|
77
|
+
if !image || screen.main_controller.retainCount == 1 || section.retainCount == 1
|
77
78
|
@strong_refs = nil
|
78
79
|
return
|
79
80
|
end
|
@@ -41,6 +41,8 @@ module MotionPrime
|
|
41
41
|
draw_in_context(UIGraphicsGetCurrentContext())
|
42
42
|
end
|
43
43
|
|
44
|
+
# using hack for bug described here: http://stackoverflow.com/questions/19232850/nsattributedstring-drawinrect-disappears-when-the-frame-is-offset
|
45
|
+
# TODO: check it in iOS 7.1 and remove CGContext manuplations (pass innerRect/topLeftCorner) if fixed
|
44
46
|
def draw_in_context(context)
|
45
47
|
return if computed_options[:hidden]
|
46
48
|
size_to_fit_if_needed
|
@@ -53,11 +55,16 @@ module MotionPrime
|
|
53
55
|
if options[:is_html] || options[:line_spacing] || options[:line_height] || options[:underline]
|
54
56
|
prepared_text = options[:is_html] ? html_string(options) : attributed_string(options)
|
55
57
|
|
58
|
+
CGContextSaveGState(context)
|
56
59
|
if options[:inner_rect]
|
57
|
-
|
60
|
+
rect = options[:inner_rect]
|
61
|
+
CGContextTranslateCTM(context, *rect.origin.to_a)
|
62
|
+
prepared_text.drawInRect(CGRectMake(0, 0, *rect.size.to_a))
|
58
63
|
else
|
59
|
-
|
64
|
+
CGContextTranslateCTM(context, *options[:top_left_corner].to_a)
|
65
|
+
prepared_text.drawAtPoint(CGPointMake(0, 0))
|
60
66
|
end
|
67
|
+
CGContextRestoreGState(context)
|
61
68
|
else
|
62
69
|
# regular string
|
63
70
|
prepared_text = options[:text]
|
@@ -2,6 +2,7 @@
|
|
2
2
|
module MotionPrime
|
3
3
|
module HasSearchBar
|
4
4
|
def add_search_bar(options = {}, &block)
|
5
|
+
@_search_timeout = options.delete(:timeout)
|
5
6
|
target = options.delete(:target)
|
6
7
|
|
7
8
|
@_search_bar = create_search_bar(options)
|
@@ -20,6 +21,7 @@ module MotionPrime
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def dealloc
|
24
|
+
BW::Reactor.cancel_timer(@_search_timer) if @_search_timer
|
23
25
|
@_search_bar.try(:setDelegate, nil)
|
24
26
|
@_search_bar = nil
|
25
27
|
super
|
@@ -35,10 +37,17 @@ module MotionPrime
|
|
35
37
|
end
|
36
38
|
|
37
39
|
def searchBar(search_bar, textDidChange: text)
|
38
|
-
|
40
|
+
BW::Reactor.cancel_timer(@_search_timer) if @_search_timer
|
41
|
+
if @_search_timeout
|
42
|
+
@_search_timer = BW::Reactor.add_timer(@_search_timeout.to_f/1000, proc{ @search_callback.call(text) }.weak!)
|
43
|
+
else
|
44
|
+
@search_callback.call(text)
|
45
|
+
end
|
39
46
|
end
|
40
47
|
|
41
48
|
def searchBarSearchButtonClicked(search_bar)
|
49
|
+
BW::Reactor.cancel_timer(@_search_timer) if @_search_timer
|
50
|
+
@search_callback.call(search_bar.text)
|
42
51
|
search_bar.resignFirstResponder
|
43
52
|
end
|
44
53
|
end
|
@@ -12,7 +12,7 @@ module MotionPrime
|
|
12
12
|
include MotionPrime::ScreenNavigationMixin
|
13
13
|
include MotionPrime::ScreenSectionsMixin
|
14
14
|
|
15
|
-
attr_accessor :parent_screen, :modal, :params, :
|
15
|
+
attr_accessor :parent_screen, :modal, :params, :options, :tab_bar
|
16
16
|
class_attribute :current_screen
|
17
17
|
|
18
18
|
def app_delegate
|
@@ -14,6 +14,10 @@ module MotionPrime
|
|
14
14
|
render_sections
|
15
15
|
end
|
16
16
|
|
17
|
+
def all_sections
|
18
|
+
@sections.values
|
19
|
+
end
|
20
|
+
|
17
21
|
def create_sections
|
18
22
|
section_options = self.class._section_options
|
19
23
|
return unless section_options
|
@@ -31,16 +35,16 @@ module MotionPrime
|
|
31
35
|
|
32
36
|
def render_sections
|
33
37
|
return unless @sections
|
34
|
-
if
|
35
|
-
@main_section = MotionPrime::TableSection.new(model:
|
38
|
+
if all_sections.count > 1
|
39
|
+
@main_section = MotionPrime::TableSection.new(model: all_sections, screen: self)
|
36
40
|
@main_section.render
|
37
41
|
else
|
38
|
-
|
42
|
+
all_sections.first.render
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
46
|
def main_section
|
43
|
-
@main_section ||
|
47
|
+
@main_section || all_sections.first
|
44
48
|
end
|
45
49
|
|
46
50
|
module ClassMethods
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module MotionPrime
|
2
|
+
module SectionWithContainerMixin
|
3
|
+
extend ::MotionSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :container_element_options
|
7
|
+
end
|
8
|
+
|
9
|
+
def container_view
|
10
|
+
container_element.try(:view)
|
11
|
+
end
|
12
|
+
|
13
|
+
def init_container_element(options = {})
|
14
|
+
@container_element ||= begin
|
15
|
+
options.merge!({
|
16
|
+
screen: screen,
|
17
|
+
section: self.weak_ref,
|
18
|
+
has_drawn_content: true
|
19
|
+
})
|
20
|
+
container_element_options = self.class.container_element_options.clone
|
21
|
+
type = container_element_options.delete(:type)
|
22
|
+
options.merge!(container_element_options)
|
23
|
+
MotionPrime::BaseElement.factory(type, options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_container_with_elements(options = {})
|
28
|
+
init_container_element(options[:container] || {})
|
29
|
+
@container_element.compute_options! unless @container_element.computed_options
|
30
|
+
compute_element_options(options[:elements] || {})
|
31
|
+
|
32
|
+
if respond_to?(:prerender_elements_for_state) && prerender_enabled?
|
33
|
+
prerender_elements_for_state(:normal)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def compute_element_options(options = {})
|
39
|
+
self.elements.values.each do |element|
|
40
|
+
element.size_to_fit_if_needed if element.is_a?(LabelDrawElement)
|
41
|
+
element.compute_options! if element.respond_to?(:computed_options) && !element.computed_options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
def container_element(options)
|
48
|
+
self.container_element_options = options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -3,11 +3,14 @@ module MotionPrime
|
|
3
3
|
module CellSectionMixin
|
4
4
|
extend ::MotionSupport::Concern
|
5
5
|
|
6
|
+
include SectionWithContainerMixin
|
7
|
+
|
6
8
|
attr_writer :table
|
7
9
|
attr_reader :pending_display
|
8
10
|
|
9
11
|
included do
|
10
12
|
class_attribute :custom_cell_name
|
13
|
+
container_element type: :table_view_cell
|
11
14
|
end
|
12
15
|
|
13
16
|
def table
|
@@ -42,27 +45,10 @@ module MotionPrime
|
|
42
45
|
end
|
43
46
|
|
44
47
|
def init_container_element(options = {})
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
has_drawn_content: true
|
50
|
-
})
|
51
|
-
options[:styles] ||= []
|
52
|
-
options[:styles] = [:"#{table.name}_first_cell"] if table.data.first == self
|
53
|
-
options[:styles] = [:"#{table.name}_last_cell"] if table.data.last == self
|
54
|
-
MotionPrime::BaseElement.factory(:table_view_cell, options)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# FIXME: Why this duplicates functionality from other parts, e.g. draw_in?
|
59
|
-
def load_container_element(options = {})
|
60
|
-
init_container_element(options)
|
61
|
-
load_elements
|
62
|
-
@container_element.compute_options! unless @container_element.computed_options
|
63
|
-
if respond_to?(:prerender_elements_for_state) && prerender_enabled?
|
64
|
-
prerender_elements_for_state(:normal)
|
65
|
-
end
|
48
|
+
options[:styles] ||= []
|
49
|
+
options[:styles] = [:"#{table.name}_first_cell"] if table.data.first == self
|
50
|
+
options[:styles] = [:"#{table.name}_last_cell"] if table.data.last == self
|
51
|
+
super(options)
|
66
52
|
end
|
67
53
|
|
68
54
|
def pending_display!
|
@@ -4,30 +4,13 @@ module MotionPrime
|
|
4
4
|
|
5
5
|
include HasStyles
|
6
6
|
include FrameCalculatorMixin
|
7
|
+
include SectionWithContainerMixin
|
8
|
+
|
7
9
|
attr_accessor :container_element, :container_gesture_recognizers, :cached_draw_image
|
10
|
+
|
8
11
|
included do
|
9
12
|
class_attribute :prerender_enabled
|
10
|
-
|
11
|
-
|
12
|
-
def container_view
|
13
|
-
container_element.try(:view)
|
14
|
-
end
|
15
|
-
|
16
|
-
def init_container_element(options = {})
|
17
|
-
@container_element ||= begin
|
18
|
-
options.merge!({
|
19
|
-
screen: screen,
|
20
|
-
section: self.weak_ref,
|
21
|
-
has_drawn_content: true
|
22
|
-
})
|
23
|
-
options[:styles] ||= []
|
24
|
-
MotionPrime::BaseElement.factory(:view_with_section, options)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def load_container_element(options = {})
|
29
|
-
init_container_element(options)
|
30
|
-
@container_element.compute_options! unless @container_element.computed_options
|
13
|
+
container_element type: :view_with_section
|
31
14
|
end
|
32
15
|
|
33
16
|
def draw_in(rect, state = :normal)
|
@@ -19,6 +19,7 @@ module MotionPrime
|
|
19
19
|
include HasNormalizer
|
20
20
|
include HasClassFactory
|
21
21
|
include DrawSectionMixin
|
22
|
+
include DelegateMixin
|
22
23
|
|
23
24
|
attr_accessor :screen, :model, :name, :options, :elements, :section_styles
|
24
25
|
class_attribute :elements_options, :container_options, :keyboard_close_bindings
|
@@ -145,13 +146,6 @@ module MotionPrime
|
|
145
146
|
self.instance_eval(&@options_block) if @options_block.is_a?(Proc)
|
146
147
|
end
|
147
148
|
|
148
|
-
def load_elements
|
149
|
-
self.elements.values.each do |element|
|
150
|
-
element.size_to_fit_if_needed if element.is_a?(LabelDrawElement)
|
151
|
-
element.compute_options! if element.respond_to?(:computed_options) && !element.computed_options
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
149
|
def add_element(key, options = {})
|
156
150
|
return unless render_element?(key)
|
157
151
|
opts = options.clone
|
@@ -334,6 +328,12 @@ module MotionPrime
|
|
334
328
|
end
|
335
329
|
|
336
330
|
class << self
|
331
|
+
def inherited(subclass)
|
332
|
+
subclass.elements_options = self.elements_options.try(:clone)
|
333
|
+
subclass.container_options = self.container_options.try(:clone)
|
334
|
+
subclass.keyboard_close_bindings = self.keyboard_close_bindings.try(:clone)
|
335
|
+
end
|
336
|
+
|
337
337
|
def element(name, options = {}, &block)
|
338
338
|
options[:name] ||= name
|
339
339
|
options[:type] ||= :label
|
@@ -210,6 +210,13 @@ module MotionPrime
|
|
210
210
|
end
|
211
211
|
|
212
212
|
class << self
|
213
|
+
def inherited(subclass)
|
214
|
+
super
|
215
|
+
subclass.fields_options = self.fields_options.try(:clone)
|
216
|
+
subclass.text_field_limits = self.text_field_limits.try(:clone)
|
217
|
+
subclass.text_view_limits = self.text_view_limits.try(:clone)
|
218
|
+
end
|
219
|
+
|
213
220
|
def field(name, options = {}, &block)
|
214
221
|
options[:name] = name
|
215
222
|
options[:type] ||= :string
|
@@ -103,6 +103,15 @@ module MotionPrime
|
|
103
103
|
NSLog("can't blur on element #{self.class_name_without_kvo}")
|
104
104
|
end
|
105
105
|
|
106
|
+
def default_label_options
|
107
|
+
label_options = options[:label]
|
108
|
+
if label_options.has_key?(:text)
|
109
|
+
label_options
|
110
|
+
else
|
111
|
+
{text: options[:name].to_s.titleize}.merge(label_options)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
106
115
|
def bind_text_input
|
107
116
|
view(:input).on :change do |view|
|
108
117
|
focus
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MotionPrime
|
2
2
|
class PasswordFieldSection < BaseFieldSection
|
3
3
|
element :label, type: :label do
|
4
|
-
|
4
|
+
default_label_options
|
5
5
|
end
|
6
6
|
element :input, type: :text_field, delegate: proc { form.table_delegate } do
|
7
7
|
{secure_text_entry: true}.merge(options[:input] || {})
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MotionPrime
|
2
2
|
class SubmitFieldSection < BaseFieldSection
|
3
3
|
element :submit, type: :button do
|
4
|
-
{title: options[:
|
4
|
+
{title: options[:name].to_s.titleize}.merge(options[:button] || {})
|
5
5
|
end
|
6
6
|
element :error_message, type: :error_message, text: proc { all_errors.join("\n") if observing_errors? }
|
7
7
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MotionPrime
|
2
2
|
class TextFieldSection < BaseFieldSection
|
3
3
|
element :label, type: :label do
|
4
|
-
|
4
|
+
default_label_options
|
5
5
|
end
|
6
6
|
element :input, type: :text_view, delegate: proc { form.table_delegate } do
|
7
7
|
{editable: true}.merge(options[:input] || {})
|
@@ -85,6 +85,13 @@ module MotionPrime
|
|
85
85
|
end
|
86
86
|
|
87
87
|
class << self
|
88
|
+
def inherited(subclass)
|
89
|
+
super
|
90
|
+
subclass.tabs_options = self.tabs_options.try(:clone)
|
91
|
+
subclass.tabs_default = self.tabs_default.try(:clone)
|
92
|
+
subclass.tabs_indexes = self.tabs_indexes.try(:clone)
|
93
|
+
end
|
94
|
+
|
88
95
|
def tab(id, options = {})
|
89
96
|
options[:name] ||= id.to_s.titleize
|
90
97
|
options[:id] = id
|
@@ -58,6 +58,13 @@ module MotionPrime
|
|
58
58
|
@preloader_queue[-1] = :cancelled if @preloader_queue.present?
|
59
59
|
end
|
60
60
|
|
61
|
+
def add_cells(cells)
|
62
|
+
prepare_table_cells(cells)
|
63
|
+
@data ||= []
|
64
|
+
@data += cells
|
65
|
+
reload_table_data
|
66
|
+
end
|
67
|
+
|
61
68
|
def reload_cell(section)
|
62
69
|
section.elements.values.each(&:compute_options!)
|
63
70
|
section.cached_draw_image = nil
|
@@ -307,7 +314,7 @@ module MotionPrime
|
|
307
314
|
def load_cell_by_index(index, options = {})
|
308
315
|
section = rows_for_section(index.section)[index.row]
|
309
316
|
if section.load_section && options[:preload] && !section.container_element && async_data? # perform only if just loaded
|
310
|
-
section.
|
317
|
+
section.load_container_with_elements(container: container_element_options_for(index))
|
311
318
|
end
|
312
319
|
section
|
313
320
|
end
|
@@ -387,17 +394,17 @@ module MotionPrime
|
|
387
394
|
@preloader_queue ||= []
|
388
395
|
@strong_refs ||= []
|
389
396
|
|
390
|
-
# TODO: do
|
391
|
-
|
392
|
-
|
393
|
-
|
397
|
+
# TODO: we do we need to keep screen ref too?
|
398
|
+
queue_id = @preloader_queue.count
|
399
|
+
@strong_refs[queue_id] = [screen.strong_ref, screen.main_controller.strong_ref]
|
400
|
+
@preloader_queue[queue_id] = :in_progress
|
401
|
+
BW::Reactor.schedule(queue_id) do |queue_id|
|
394
402
|
result = load_count.times do |offset|
|
395
403
|
if @preloader_queue[queue_id] == :cancelled
|
396
404
|
@strong_refs[queue_id] = nil
|
397
405
|
break
|
398
406
|
end
|
399
|
-
|
400
|
-
if screen.retainCount == 1
|
407
|
+
if screen.main_controller.retainCount == 1
|
401
408
|
@strong_refs[queue_id] = nil
|
402
409
|
@preloader_queue[queue_id] = :dealloc
|
403
410
|
break
|
@@ -423,6 +430,12 @@ module MotionPrime
|
|
423
430
|
end
|
424
431
|
|
425
432
|
class << self
|
433
|
+
def inherited(subclass)
|
434
|
+
super
|
435
|
+
subclass.async_data_options = self.async_data_options.try(:clone)
|
436
|
+
subclass.section_header_options = self.section_header_options.try(:clone)
|
437
|
+
end
|
438
|
+
|
426
439
|
def async_table_data(options = {})
|
427
440
|
self.async_data_options = options
|
428
441
|
end
|