motion-prime 0.2.1 → 0.3.0
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 +8 -8
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +14 -11
- data/README.md +8 -11
- data/Rakefile +2 -1
- data/bin/prime.rb +47 -0
- data/doc/FAQ.md +1 -1
- data/files/app/app_delegate.rb +1 -1
- data/files/app/config/base.rb +8 -4
- data/files/app/screens/application_screen.rb +1 -1
- data/files/app/screens/sidebar_screen.rb +1 -1
- data/files/app/sections/sidebar/action.rb +1 -1
- data/files/app/sections/sidebar/table.rb +1 -1
- data/files/app/styles/sidebar.rb +5 -5
- data/motion-prime.gemspec +1 -0
- data/motion-prime/api_client.rb +81 -0
- data/motion-prime/app_delegate.rb +22 -5
- data/motion-prime/config/base.rb +5 -0
- data/motion-prime/core_ext/kernel.rb +5 -0
- data/motion-prime/elements/_field_dimensions_mixin.rb +43 -0
- data/motion-prime/elements/_text_dimensions_mixin.rb +39 -0
- data/motion-prime/elements/base.rb +40 -17
- data/motion-prime/elements/button.rb +20 -0
- data/motion-prime/elements/draw.rb +2 -2
- data/motion-prime/elements/draw/image.rb +4 -2
- data/motion-prime/elements/draw/label.rb +1 -1
- data/motion-prime/elements/error_message.rb +3 -16
- data/motion-prime/elements/label.rb +13 -2
- data/motion-prime/elements/text_field.rb +1 -0
- data/motion-prime/helpers/cell_section.rb +9 -0
- data/motion-prime/helpers/has_authorization.rb +4 -3
- data/motion-prime/helpers/has_normalizer.rb +20 -6
- data/motion-prime/helpers/has_search_bar.rb +19 -7
- data/motion-prime/helpers/has_style_chain_builder.rb +7 -0
- data/motion-prime/models/association.rb +22 -9
- data/motion-prime/models/association_collection.rb +54 -23
- data/motion-prime/models/bag.rb +13 -12
- data/motion-prime/models/base.rb +2 -0
- data/motion-prime/models/errors.rb +23 -14
- data/motion-prime/models/finder.rb +4 -1
- data/motion-prime/models/model.rb +25 -5
- data/motion-prime/models/store_extension.rb +1 -7
- data/motion-prime/models/sync.rb +75 -43
- data/motion-prime/mp.rb +4 -0
- data/motion-prime/screens/_base_mixin.rb +18 -12
- data/motion-prime/screens/_navigation_bar_mixin.rb +15 -6
- data/motion-prime/screens/_navigation_mixin.rb +15 -16
- data/motion-prime/screens/base_screen.rb +5 -1
- data/motion-prime/screens/sidebar_container_screen.rb +37 -22
- data/motion-prime/sections/base.rb +82 -16
- data/motion-prime/sections/form.rb +144 -26
- data/motion-prime/sections/form/base_field_section.rb +62 -29
- data/motion-prime/sections/form/base_header_section.rb +27 -0
- data/motion-prime/sections/form/date_field_section.rb +2 -17
- data/motion-prime/sections/form/password_field_section.rb +3 -17
- data/motion-prime/sections/form/select_field_section.rb +4 -35
- data/motion-prime/sections/form/string_field_section.rb +3 -29
- data/motion-prime/sections/form/submit_field_section.rb +1 -7
- data/motion-prime/sections/form/switch_field_section.rb +3 -23
- data/motion-prime/sections/form/text_field_section.rb +3 -33
- data/motion-prime/sections/form/text_with_button_field_section.rb +4 -40
- data/motion-prime/sections/tabbed.rb +25 -5
- data/motion-prime/sections/table.rb +86 -22
- data/motion-prime/sections/table/refresh_mixin.rb +3 -1
- data/motion-prime/styles/base.rb +7 -89
- data/motion-prime/styles/form.rb +116 -0
- data/motion-prime/support/dm_button.rb +32 -5
- data/motion-prime/support/dm_text_field.rb +31 -7
- data/motion-prime/support/dm_text_view.rb +6 -3
- data/motion-prime/support/dm_view_controller.rb +3 -3
- data/motion-prime/support/ui_search_bar_custom.rb +1 -1
- data/motion-prime/version.rb +1 -1
- data/motion-prime/views/layout.rb +18 -10
- data/motion-prime/views/styles.rb +19 -9
- data/motion-prime/views/view_builder.rb +18 -2
- data/motion-prime/views/view_styler.rb +59 -5
- data/spec/models/errors_spec.rb +3 -3
- data/travis.sh +3 -2
- metadata +28 -5
- data/motion-prime/elements/_text_height_mixin.rb +0 -17
- data/motion-prime/sections/form/table_field_section.rb +0 -51
data/motion-prime/mp.rb
ADDED
@@ -37,14 +37,16 @@ module MotionPrime
|
|
37
37
|
self.send("#{k}=", v) if self.respond_to?("#{k}=")
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
self.add_navigation_controller
|
42
|
-
end
|
40
|
+
@wrap_in_navigation = args[:navigation]
|
43
41
|
|
44
42
|
self.on_init if respond_to?(:on_init)
|
45
43
|
self
|
46
44
|
end
|
47
45
|
|
46
|
+
def wrap_in_navigation?
|
47
|
+
@wrap_in_navigation
|
48
|
+
end
|
49
|
+
|
48
50
|
def modal?
|
49
51
|
!!self.modal
|
50
52
|
end
|
@@ -61,10 +63,6 @@ module MotionPrime
|
|
61
63
|
@navigation_controller = val
|
62
64
|
end
|
63
65
|
|
64
|
-
def add_navigation_controller
|
65
|
-
self.navigation_controller = NavigationController.alloc.initWithRootViewController(self)
|
66
|
-
end
|
67
|
-
|
68
66
|
def title
|
69
67
|
title = self.class.title
|
70
68
|
title = self.instance_eval(&title) if title.is_a?(Proc)
|
@@ -97,19 +95,27 @@ module MotionPrime
|
|
97
95
|
@activity_indicator_view.stopAnimating
|
98
96
|
end
|
99
97
|
|
100
|
-
def show_notice(message, time = 1.0)
|
98
|
+
def show_notice(message, time = 1.0, type = :notice)
|
99
|
+
hud_type = case type.to_s
|
100
|
+
when 'alert' then MBAlertViewHUDTypeExclamationMark
|
101
|
+
else MBAlertViewHUDTypeCheckmark
|
102
|
+
end
|
101
103
|
MBHUDView.hudWithBody message,
|
102
|
-
type:
|
104
|
+
type: hud_type, hidesAfter: time, show: true
|
103
105
|
end
|
104
106
|
|
105
107
|
def refresh
|
106
|
-
main_section.reload_data
|
108
|
+
main_section.try(:reload_data)
|
107
109
|
end
|
108
110
|
|
109
111
|
# Class methods
|
110
112
|
module ClassMethods
|
111
|
-
def title(t = nil)
|
112
|
-
|
113
|
+
def title(t = nil, &block)
|
114
|
+
if block_given?
|
115
|
+
@title = block
|
116
|
+
else
|
117
|
+
t ? @title = t : @title ||= self.to_s
|
118
|
+
end
|
113
119
|
end
|
114
120
|
def before_load(method_name)
|
115
121
|
set_callback :load, :before, method_name
|
@@ -8,6 +8,10 @@ module MotionPrime
|
|
8
8
|
navigationItem.leftBarButtonItem
|
9
9
|
end
|
10
10
|
|
11
|
+
def remove_navigation_right_button(args = {})
|
12
|
+
navigationItem.setRightBarButtonItem(nil, animated: args[:animated])
|
13
|
+
end
|
14
|
+
|
11
15
|
def set_navigation_right_button(title, args = {})
|
12
16
|
navigationItem.rightBarButtonItem = create_navigation_button(title, args)
|
13
17
|
end
|
@@ -20,11 +24,18 @@ module MotionPrime
|
|
20
24
|
navigationItem.leftBarButtonItem = create_navigation_button(title, {action: :back}.merge(args))
|
21
25
|
end
|
22
26
|
|
27
|
+
def set_navigation_back_or_menu(back_title = 'Back')
|
28
|
+
if parent_screen.is_a?(MotionPrime::SidebarContainerScreen)
|
29
|
+
set_navigation_left_button 'Menu', image: 'images/navigation/menu_button.png', action: :show_sidebar
|
30
|
+
else
|
31
|
+
set_navigation_back_button back_title, icon: 'images/navigation/back_icon.png'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
23
35
|
def create_navigation_button(title, args = {})
|
24
36
|
args[:style] ||= UIBarButtonItemStylePlain
|
25
37
|
args[:target] ||= self
|
26
38
|
args[:action] ||= nil
|
27
|
-
|
28
39
|
# TODO: Find better place for this code, may be just create custom control
|
29
40
|
if args[:image]
|
30
41
|
image = args[:image].uiimage
|
@@ -34,8 +45,7 @@ module MotionPrime
|
|
34
45
|
face.on :touch do
|
35
46
|
args[:action].to_proc.call(self)
|
36
47
|
end
|
37
|
-
|
38
|
-
button
|
48
|
+
UIBarButtonItem.alloc.initWithCustomView(face)
|
39
49
|
elsif args[:icon]
|
40
50
|
image = args[:icon].uiimage
|
41
51
|
face = UIButton.buttonWithType UIButtonTypeCustom
|
@@ -46,11 +56,10 @@ module MotionPrime
|
|
46
56
|
face.on :touch do
|
47
57
|
args[:action].to_proc.call(self)
|
48
58
|
end
|
49
|
-
|
50
|
-
button
|
59
|
+
UIBarButtonItem.alloc.initWithCustomView(face)
|
51
60
|
else
|
52
61
|
UIBarButtonItem.alloc.initWithTitle(title,
|
53
|
-
|
62
|
+
style: args[:style], target: args[:target], action: args[:action])
|
54
63
|
end
|
55
64
|
end
|
56
65
|
end
|
@@ -6,13 +6,14 @@ module MotionPrime
|
|
6
6
|
|
7
7
|
def open_screen(screen, args = {})
|
8
8
|
# Apply properties to instance
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
if args[:modal] || has_navigation?
|
10
|
+
screen = setup_screen_for_open(screen, args)
|
11
|
+
screen.send(:on_screen_load) if screen.respond_to?(:on_screen_load)
|
12
|
+
if args[:modal] || !has_navigation?
|
13
|
+
present_modal_view_controller screen, (args.has_key?(:animated) ? args[:animated] : true)
|
14
|
+
else
|
15
|
+
push_view_controller screen, args
|
16
|
+
end
|
16
17
|
else
|
17
18
|
app_delegate.open_screen(screen.main_controller)
|
18
19
|
end
|
@@ -56,6 +57,13 @@ module MotionPrime
|
|
56
57
|
navigation_controller.pushViewController(vc, animated: (args.has_key?(:animated) ? args[:animated] : true))
|
57
58
|
end
|
58
59
|
|
60
|
+
def ensure_wrapper_controller_in_place(args = {})
|
61
|
+
# Wrap in a NavigationController?
|
62
|
+
if wrap_in_navigation? && !args[:modal]
|
63
|
+
add_navigation_controller
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
59
67
|
protected
|
60
68
|
|
61
69
|
def setup_screen_for_open(screen, args = {})
|
@@ -67,19 +75,10 @@ module MotionPrime
|
|
67
75
|
screen.title = args[:title] if args[:title] && screen.respond_to?("title=")
|
68
76
|
screen.modal = args[:modal] if args[:modal] && screen.respond_to?("modal=")
|
69
77
|
|
70
|
-
# Wrap in a NavigationController?
|
71
|
-
screen.add_navigation if args[:navigation] && screen.respond_to?(:add_navigation)
|
72
|
-
|
73
78
|
# Return modified screen instance
|
74
79
|
screen
|
75
80
|
end
|
76
81
|
|
77
|
-
def ensure_wrapper_controller_in_place(screen, args={})
|
78
|
-
if !args[:modal] && screen.respond_to?(:navigation_controller=)
|
79
|
-
screen.navigation_controller ||= navigation_controller
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
82
|
def present_modal_view_controller(screen, animated)
|
84
83
|
self.presentModalViewController(screen.main_controller, animated: animated)
|
85
84
|
end
|
@@ -13,8 +13,12 @@ module MotionPrime
|
|
13
13
|
def render
|
14
14
|
end
|
15
15
|
|
16
|
+
def default_styles
|
17
|
+
[:base_screen, self.class_name_without_kvo.underscore.to_sym]
|
18
|
+
end
|
19
|
+
|
16
20
|
def on_load
|
17
|
-
setup view, styles:
|
21
|
+
setup view, styles: default_styles do
|
18
22
|
render
|
19
23
|
end
|
20
24
|
end
|
@@ -1,58 +1,73 @@
|
|
1
1
|
module MotionPrime
|
2
|
-
class SidebarContainerScreen <
|
3
|
-
|
2
|
+
class SidebarContainerScreen < RESideMenu
|
4
3
|
include ::MotionPrime::ScreenBaseMixin
|
5
4
|
|
6
5
|
def self.new(menu, content, options={})
|
7
|
-
screen = self.
|
6
|
+
screen = self.alloc.initWithContentViewController(nil, menuViewController: nil)
|
7
|
+
screen.backgroundImage = "images/sidebar/background.png".uiimage
|
8
|
+
|
9
|
+
full_width = UIScreen.mainScreen.bounds.size.width
|
10
|
+
|
11
|
+
if scale = options[:content_scale_value]
|
12
|
+
screen.contentViewScaleValue = scale
|
13
|
+
end
|
14
|
+
x_offset = options[:x_offset] || 45
|
15
|
+
screen.contentViewInPortraitOffsetCenterX = full_width*(1 + screen.contentViewScaleValue/2) - x_offset
|
16
|
+
|
17
|
+
if y_offset = options[:y_offset]
|
18
|
+
screen.contentViewInPortraitOffsetCenterY = UIScreen.mainScreen.bounds.size.height/2 + y_offset
|
19
|
+
end
|
20
|
+
|
8
21
|
screen.on_create(options) if screen.respond_to?(:on_create)
|
9
22
|
screen.menu_controller = menu unless menu.nil?
|
10
23
|
screen.content_controller = content unless content.nil?
|
24
|
+
|
11
25
|
screen
|
12
26
|
end
|
13
27
|
|
14
28
|
def show_sidebar
|
15
|
-
|
29
|
+
self.presentMenuViewController
|
16
30
|
end
|
17
31
|
|
18
32
|
def hide_sidebar
|
19
|
-
|
33
|
+
self.hideMenuViewController
|
20
34
|
end
|
21
35
|
|
22
36
|
def menu_controller=(c)
|
23
|
-
|
24
|
-
focusAfterChange: true, completion: default_completion_block
|
37
|
+
self.setMenuViewController prepare_controller(c)
|
25
38
|
end
|
26
39
|
|
27
40
|
def content_controller=(c)
|
28
|
-
|
29
|
-
|
41
|
+
controller = prepare_controller(c)
|
42
|
+
if content_controller.nil?
|
43
|
+
self.setContentViewController controller
|
44
|
+
else
|
45
|
+
content_controller.viewControllers = [controller]
|
46
|
+
end
|
47
|
+
hide_sidebar
|
30
48
|
end
|
31
49
|
|
32
50
|
def menu_controller
|
33
|
-
self.
|
51
|
+
self.menuViewController
|
34
52
|
end
|
35
53
|
|
36
54
|
def content_controller
|
37
|
-
self.
|
55
|
+
self.contentViewController
|
38
56
|
end
|
39
57
|
|
40
58
|
private
|
41
59
|
|
42
|
-
def show_controller(controller)
|
43
|
-
showViewController controller, animated: true, completion: default_completion_block
|
44
|
-
end
|
45
|
-
|
46
60
|
def prepare_controller(controller)
|
47
|
-
controller.on_screen_load if controller.respond_to?(:on_screen_load)
|
48
61
|
controller = setup_screen_for_open(controller, {})
|
49
|
-
|
50
|
-
|
62
|
+
if content_controller.nil?
|
63
|
+
controller.ensure_wrapper_controller_in_place
|
64
|
+
controller.send(:on_screen_load) if controller.respond_to?(:on_screen_load)
|
65
|
+
controller = controller.main_controller if controller.respond_to?(:main_controller)
|
66
|
+
else
|
67
|
+
controller.navigation_controller = content_controller
|
68
|
+
controller.send(:on_screen_load) if controller.respond_to?(:on_screen_load)
|
69
|
+
end
|
51
70
|
controller
|
52
71
|
end
|
53
|
-
|
54
|
-
def default_completion_block
|
55
|
-
-> (completed) { true }
|
56
|
-
end
|
57
72
|
end
|
58
73
|
end
|
@@ -19,31 +19,73 @@ module MotionPrime
|
|
19
19
|
include MotionPrime::HasNormalizer
|
20
20
|
|
21
21
|
attr_accessor :screen, :model, :name, :options, :elements
|
22
|
-
class_attribute :elements_options, :container_options
|
22
|
+
class_attribute :elements_options, :container_options, :keyboard_close_bindings
|
23
23
|
define_callbacks :render
|
24
24
|
|
25
25
|
def initialize(options = {})
|
26
26
|
@options = options
|
27
27
|
@model = options[:model]
|
28
28
|
@name = options[:name] ||= default_name
|
29
|
-
|
30
|
-
|
29
|
+
@options_block = options[:block]
|
30
|
+
load_section
|
31
|
+
end
|
32
|
+
|
33
|
+
def container_options
|
34
|
+
@normalized_container_options or begin
|
35
|
+
# priority: class; from styles; passed directly
|
36
|
+
raw_container_options = self.class.container_options.try(:clone) || {}
|
37
|
+
passed_container_options = options.delete(:container) || {}
|
38
|
+
raw_container_options.merge!(passed_container_options)
|
39
|
+
@normalized_container_options = normalize_options(raw_container_options)
|
40
|
+
|
41
|
+
style_container_options = style_options.delete(:container) || {}
|
42
|
+
@normalized_container_options.merge!(style_container_options.except(*passed_container_options.keys))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def style_options
|
47
|
+
{}
|
31
48
|
end
|
32
49
|
|
33
50
|
def default_name
|
34
|
-
self.
|
51
|
+
self.class_name_without_kvo.demodulize.underscore.gsub(/\_section$/, '')
|
35
52
|
end
|
36
53
|
|
37
54
|
def elements_options
|
38
55
|
self.class.elements_options || {}
|
39
56
|
end
|
40
57
|
|
58
|
+
def load_section
|
59
|
+
create_elements
|
60
|
+
self.instance_eval(&@options_block) if @options_block.is_a?(Proc)
|
61
|
+
end
|
62
|
+
|
63
|
+
def reload_section
|
64
|
+
self.elements.values.map(&:view).flatten.compact.each { |view| view.removeFromSuperview }
|
65
|
+
load_section
|
66
|
+
run_callbacks :render do
|
67
|
+
render!
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
41
71
|
def create_elements
|
42
72
|
self.elements = {}
|
43
73
|
elements_options.each do |key, opts|
|
44
|
-
|
45
|
-
|
46
|
-
|
74
|
+
add_element(key, opts)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_element(key, opts)
|
79
|
+
return unless render_element?(key)
|
80
|
+
index = opts.delete(:at)
|
81
|
+
options = build_options_for_element(opts)
|
82
|
+
options[:name] ||= key
|
83
|
+
options[:type] ||= :label
|
84
|
+
element = MotionPrime::BaseElement.factory(options.delete(:type), options)
|
85
|
+
if index
|
86
|
+
self.elements = Hash[self.elements.to_a.insert index, [key, element]]
|
87
|
+
else
|
88
|
+
self.elements[key] = element
|
47
89
|
end
|
48
90
|
end
|
49
91
|
|
@@ -60,7 +102,7 @@ module MotionPrime
|
|
60
102
|
|
61
103
|
def cell
|
62
104
|
first_element = elements.values.first
|
63
|
-
first_element.view.superview
|
105
|
+
first_element.view.superview.superview
|
64
106
|
end
|
65
107
|
|
66
108
|
def render(container_options = {})
|
@@ -97,12 +139,6 @@ module MotionPrime
|
|
97
139
|
end
|
98
140
|
end
|
99
141
|
|
100
|
-
def container_options
|
101
|
-
@container_options ||= normalize_options(
|
102
|
-
self.class.container_options.try(:clone) || {}
|
103
|
-
)
|
104
|
-
end
|
105
|
-
|
106
142
|
def container_height
|
107
143
|
container_options[:height] || DEFAULT_CONTENT_HEIGHT
|
108
144
|
end
|
@@ -116,6 +152,12 @@ module MotionPrime
|
|
116
152
|
def keyboard_will_show; end
|
117
153
|
def keyboard_will_hide; end
|
118
154
|
|
155
|
+
def dealloc
|
156
|
+
NSNotificationCenter.defaultCenter.removeObserver self
|
157
|
+
self.delegate = nil if self.respond_to?(:delegate)
|
158
|
+
super
|
159
|
+
end
|
160
|
+
|
119
161
|
def bind_keyboard_events
|
120
162
|
NSNotificationCenter.defaultCenter.addObserver self,
|
121
163
|
selector: :on_keyboard_show,
|
@@ -135,10 +177,31 @@ module MotionPrime
|
|
135
177
|
object: nil
|
136
178
|
end
|
137
179
|
|
180
|
+
def bind_keyboard_close
|
181
|
+
return unless self.class.keyboard_close_bindings.present?
|
182
|
+
Array.wrap(self.instance_eval(&self.class.keyboard_close_bindings[:tap_on])).each do |view|
|
183
|
+
gesture_recognizer = UITapGestureRecognizer.alloc.initWithTarget(self, action: :hide_keyboard)
|
184
|
+
view.addGestureRecognizer(gesture_recognizer)
|
185
|
+
gesture_recognizer.cancelsTouchesInView = false
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def keyboard_close_bindings_options
|
190
|
+
@keyboard_close_bindings_options ||= normalize_options(self.class.keyboard_close_bindings.clone, self)
|
191
|
+
end
|
192
|
+
|
193
|
+
def hide_keyboard
|
194
|
+
elements = Array.wrap(keyboard_close_bindings_options[:elements])
|
195
|
+
views = Array.wrap(keyboard_close_bindings_options[:views])
|
196
|
+
|
197
|
+
elements.each { |el| views << el.view if %w[text_field text_view].include?(el.view_name) && el.view }
|
198
|
+
(views + Array.wrap(keyboard_close_bindings_options[:views])).compact.each(&:resignFirstResponder)
|
199
|
+
end
|
200
|
+
|
138
201
|
class << self
|
139
202
|
def element(name, options = {}, &block)
|
203
|
+
options[:name] ||= name
|
140
204
|
options[:type] ||= :label
|
141
|
-
options[:name] = name
|
142
205
|
options[:block] = block
|
143
206
|
self.elements_options ||= {}
|
144
207
|
self.elements_options[name] = options
|
@@ -153,8 +216,11 @@ module MotionPrime
|
|
153
216
|
def after_render(method_name)
|
154
217
|
set_callback :render, :after, method_name
|
155
218
|
end
|
219
|
+
def bind_keyboard_close(options)
|
220
|
+
self.keyboard_close_bindings = options
|
221
|
+
end
|
156
222
|
end
|
157
223
|
after_render :bind_keyboard_events
|
158
|
-
|
224
|
+
after_render :bind_keyboard_close
|
159
225
|
end
|
160
226
|
end
|