motion-prime 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +7 -3
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/ROADMAP.md +12 -0
  6. data/motion-prime/api_client.rb +1 -0
  7. data/motion-prime/app_delegate.rb +1 -1
  8. data/motion-prime/elements/_content_padding_mixin.rb +49 -0
  9. data/motion-prime/elements/_field_dimensions_mixin.rb +37 -21
  10. data/motion-prime/elements/_text_dimensions_mixin.rb +0 -4
  11. data/motion-prime/elements/base.rb +20 -7
  12. data/motion-prime/elements/button.rb +2 -1
  13. data/motion-prime/elements/draw/label.rb +19 -8
  14. data/motion-prime/elements/error_message.rb +2 -1
  15. data/motion-prime/elements/image.rb +1 -0
  16. data/motion-prime/elements/label.rb +10 -10
  17. data/motion-prime/elements/text_field.rb +2 -0
  18. data/motion-prime/models/bag.rb +8 -3
  19. data/motion-prime/models/model.rb +1 -1
  20. data/motion-prime/models/sync.rb +17 -8
  21. data/motion-prime/screens/_aliases_mixin.rb +2 -0
  22. data/motion-prime/screens/_base_mixin.rb +19 -52
  23. data/motion-prime/screens/_navigation_mixin.rb +31 -29
  24. data/motion-prime/screens/base_screen.rb +8 -0
  25. data/motion-prime/screens/extensions/_indicators_mixin.rb +26 -0
  26. data/motion-prime/screens/{_navigation_bar_mixin.rb → extensions/_navigation_bar_mixin.rb} +0 -0
  27. data/motion-prime/screens/sidebar_container_screen.rb +1 -1
  28. data/motion-prime/sections/base.rb +1 -1
  29. data/motion-prime/sections/form.rb +5 -2
  30. data/motion-prime/sections/form/base_field_section.rb +2 -2
  31. data/motion-prime/support/_key_value_store.rb +1 -1
  32. data/motion-prime/support/_padding_attribute.rb +60 -0
  33. data/motion-prime/support/dm_button.rb +20 -20
  34. data/motion-prime/support/dm_text_field.rb +12 -17
  35. data/motion-prime/support/dm_text_view.rb +1 -1
  36. data/motion-prime/support/mp_label.rb +9 -0
  37. data/motion-prime/version.rb +1 -1
  38. data/motion-prime/views/layout.rb +1 -0
  39. data/motion-prime/views/styles.rb +1 -1
  40. data/motion-prime/views/view_styler.rb +5 -1
  41. data/spec/helpers/models.rb +8 -1
  42. data/travis.sh +1 -3
  43. metadata +8 -3
@@ -74,7 +74,7 @@ module MotionPrime
74
74
  # User.new(name: "Bob", age: 10)
75
75
  #
76
76
  # @return MotionPrime::BaseModel unsaved model
77
- def new(data = {})
77
+ def new(data = {}, options = {})
78
78
  data.keys.each { |k|
79
79
  unless self.attributes.member? k.to_sym
80
80
  raise StoreError, "'#{k}' is not a defined attribute for this model"
@@ -116,6 +116,7 @@ module MotionPrime
116
116
  self.send(:"#{key}=", value)
117
117
  end
118
118
  end
119
+ self
119
120
  end
120
121
 
121
122
  def fetch_associations(sync_options = {}, &block)
@@ -153,8 +154,8 @@ module MotionPrime
153
154
 
154
155
  use_callback = block_given?
155
156
  puts "SYNC: started sync for #{key} in #{self.class_name_without_kvo}"
156
- api_client.get normalize_sync_url(options[:sync_url]) do |data, status_code|
157
- data = data[options[:sync_key]] if options[:sync_key]
157
+ api_client.get normalize_sync_url(options[:sync_url]) do |response, status_code|
158
+ data = options.has_key?(:sync_key) ? response[options[:sync_key]] : response
158
159
  if data
159
160
  # Update/Create existing records
160
161
  data.each do |attributes|
@@ -174,10 +175,10 @@ module MotionPrime
174
175
  end
175
176
  save if sync_options[:save]
176
177
  puts "SYNC: finished sync for #{key} in #{self.class_name_without_kvo}"
177
- block.call(data, status_code) if use_callback
178
+ block.call(data, status_code, response) if use_callback
178
179
  else
179
180
  puts "SYNC ERROR: failed sync for #{key} in #{self.class_name_without_kvo}"
180
- block.call(data, status_code) if use_callback
181
+ block.call(data, status_code, response) if use_callback
181
182
  end
182
183
  end
183
184
  end
@@ -185,8 +186,8 @@ module MotionPrime
185
186
  def fetch_has_one(key, options = {}, &block)
186
187
  use_callback = block_given?
187
188
  puts "SYNC: started sync for #{key} in #{self.class_name_without_kvo}"
188
- api_client.get normalize_sync_url(options[:sync_url]) do |data, status_code|
189
- data = data[options[:sync_key]] if options[:sync_key]
189
+ api_client.get normalize_sync_url(options[:sync_url]) do |response, status_code|
190
+ data = options.has_key?(:sync_key) ? response[options[:sync_key]] : response
190
191
  if data.present?
191
192
  model = self.send(key)
192
193
  unless model
@@ -195,10 +196,10 @@ module MotionPrime
195
196
  end
196
197
  model.fetch_with_attributes(data)
197
198
  model.save if sync_options[:save]
198
- block.call(data, status_code) if use_callback
199
+ block.call(data, status_code, response) if use_callback
199
200
  else
200
201
  puts "SYNC ERROR: failed sync for #{key} in #{self.class_name_without_kvo}"
201
- block.call(data, status_code) if use_callback
202
+ block.call(data, status_code, response) if use_callback
202
203
  end
203
204
  end
204
205
  end
@@ -240,6 +241,14 @@ module MotionPrime
240
241
  end
241
242
 
242
243
  module ModelSyncClassMethods
244
+ def new(data = {}, options = {})
245
+ model = super
246
+ if fetch_attributes = options[:fetch_attributes]
247
+ model.fetch_with_attributes(fetch_attributes)
248
+ end
249
+ model
250
+ end
251
+
243
252
  def sync_url(url = nil, &block)
244
253
  if url || block_given?
245
254
  self._sync_url = url || block
@@ -28,5 +28,7 @@ module MotionPrime
28
28
  end
29
29
 
30
30
  def on_rotate; end;
31
+
32
+ def on_load; end
31
33
  end
32
34
  end
@@ -1,7 +1,6 @@
1
1
  motion_require "./_aliases_mixin"
2
2
  motion_require "./_orientations_mixin"
3
3
  motion_require "./_navigation_mixin"
4
- motion_require "./_navigation_bar_mixin"
5
4
  module MotionPrime
6
5
  module ScreenBaseMixin
7
6
  extend ::MotionSupport::Concern
@@ -10,16 +9,25 @@ module MotionPrime
10
9
  include MotionPrime::ScreenAliasesMixin
11
10
  include MotionPrime::ScreenOrientationsMixin
12
11
  include MotionPrime::ScreenNavigationMixin
13
- include MotionPrime::ScreenNavigationBarMixin
14
12
 
15
- attr_accessor :parent_screen, :modal, :params, :main_section
13
+ attr_accessor :parent_screen, :modal, :params, :main_section, :options
16
14
  class_attribute :current_screen
17
15
 
18
16
  included do
19
17
  define_callbacks :load
20
18
  end
21
19
 
22
- def on_load; end
20
+ def app_delegate
21
+ UIApplication.sharedApplication.delegate
22
+ end
23
+
24
+ def show_sidebar
25
+ app_delegate.show_sidebar
26
+ end
27
+
28
+ def hide_sidebar
29
+ app_delegate.hide_sidebar
30
+ end
23
31
 
24
32
  def on_screen_load
25
33
  run_callbacks :load do
@@ -27,42 +35,28 @@ module MotionPrime
27
35
  end
28
36
  end
29
37
 
30
- def on_create(args = {})
38
+ # Setup the screen, will be called when you run DMViewController.new
39
+ # @param options [hash] Options passed to setup
40
+ # @return [MotionPrime::BaseScreen] Ready to use screen
41
+ def on_create(options = {})
31
42
  unless self.is_a?(UIViewController)
32
43
  raise StandardError.new("ERROR: Screens must extend UIViewController.")
33
44
  end
34
45
 
35
- self.params = args[:params] || {}
36
- args.each do |k, v|
46
+ self.options = options
47
+ self.params = options[:params] || {}
48
+ options.each do |k, v|
37
49
  self.send("#{k}=", v) if self.respond_to?("#{k}=")
38
50
  end
39
51
 
40
- @wrap_in_navigation = args[:navigation]
41
-
42
52
  self.on_init if respond_to?(:on_init)
43
53
  self
44
54
  end
45
55
 
46
- def wrap_in_navigation?
47
- @wrap_in_navigation
48
- end
49
-
50
56
  def modal?
51
57
  !!self.modal
52
58
  end
53
59
 
54
- def has_navigation?
55
- !navigation_controller.nil?
56
- end
57
-
58
- def navigation_controller
59
- @navigation_controller ||= self.navigationController
60
- end
61
-
62
- def navigation_controller=(val)
63
- @navigation_controller = val
64
- end
65
-
66
60
  def title
67
61
  title = self.class.title
68
62
  title = self.instance_eval(&title) if title.is_a?(Proc)
@@ -71,39 +65,12 @@ module MotionPrime
71
65
 
72
66
  def title=(new_title)
73
67
  self.class.title(new_title)
74
- super
75
68
  end
76
69
 
77
70
  def main_controller
78
71
  has_navigation? ? navigation_controller : self
79
72
  end
80
73
 
81
- # ACTIVITY INDICATOR
82
- # ---------------------
83
-
84
- def show_activity_indicator
85
- if @activity_indicator_view.nil?
86
- @activity_indicator_view = UIActivityIndicatorView.gray
87
- @activity_indicator_view.center = CGPointMake(view.center.x, view.center.y - 50)
88
- view.addSubview @activity_indicator_view
89
- end
90
- @activity_indicator_view.startAnimating
91
- end
92
-
93
- def hide_activity_indicator
94
- return unless @activity_indicator_view
95
- @activity_indicator_view.stopAnimating
96
- end
97
-
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
103
- MBHUDView.hudWithBody message,
104
- type: hud_type, hidesAfter: time, show: true
105
- end
106
-
107
74
  def refresh
108
75
  main_section.try(:reload_data)
109
76
  end
@@ -1,17 +1,14 @@
1
1
  module MotionPrime
2
2
  module ScreenNavigationMixin
3
- def app_delegate
4
- UIApplication.sharedApplication.delegate
5
- end
6
-
7
- def show_sidebar
8
- app_delegate.show_sidebar
9
- end
10
-
11
- def hide_sidebar
12
- app_delegate.hide_sidebar
13
- end
14
-
3
+ # Open screen as child for current screen if current screen have navigation or new screen is modal.
4
+ # Otherwise will create screen using app_delegate.open_screen.
5
+ # Available options:
6
+ # animated: open screen with animation.
7
+ # modal: open screen as model
8
+
9
+ # @param screen [MotionPrime::BaseScreen] Screen to be opened
10
+ # @param args [Hash] Options for opening screen
11
+ # @return [MotionPrime::BaseScreen]
15
12
  def open_screen(screen, args = {})
16
13
  if args[:modal] || has_navigation?
17
14
  screen = setup_screen_for_open(screen, args)
@@ -25,8 +22,10 @@ module MotionPrime
25
22
  else
26
23
  app_delegate.open_screen(screen.main_controller)
27
24
  end
25
+ screen
28
26
  end
29
27
 
28
+
30
29
  def close_screen(args = {})
31
30
  args[:animated] = args.has_key?(:animated) ? args[:animated] : true
32
31
  # Pop current view, maybe with arguments, if in navigation controller
@@ -47,13 +46,28 @@ module MotionPrime
47
46
  end
48
47
  end
49
48
 
50
- def ensure_wrapper_controller_in_place(args = {})
51
- # Wrap in a NavigationController?
52
- if wrap_in_navigation? && !args[:modal]
53
- add_navigation_controller
49
+ def wrap_in_navigation?
50
+ options[:navigation]
51
+ end
52
+
53
+ def wrap_in_navigation
54
+ if wrap_in_navigation?
55
+ wrap_in_navigation!
54
56
  end
55
57
  end
56
58
 
59
+ def has_navigation?
60
+ !navigation_controller.nil?
61
+ end
62
+
63
+ def navigation_controller
64
+ @navigation_controller ||= self.navigationController
65
+ end
66
+
67
+ def navigation_controller=(val)
68
+ @navigation_controller = val
69
+ end
70
+
57
71
  private
58
72
  def setup_screen_for_open(screen, args = {})
59
73
  # Instantiate screen if given a class
@@ -92,19 +106,7 @@ module MotionPrime
92
106
  send_on_return(args)
93
107
  end
94
108
 
95
- def has_navigation?
96
- !navigation_controller.nil?
97
- end
98
-
99
- def navigation_controller
100
- @navigation_controller ||= self.navigationController
101
- end
102
-
103
- def navigation_controller=(val)
104
- @navigation_controller = val
105
- end
106
-
107
- def add_navigation_controller
109
+ def wrap_in_navigation!
108
110
  self.navigation_controller = NavigationController.alloc.initWithRootViewController(self)
109
111
  end
110
112
  end
@@ -1,12 +1,20 @@
1
1
  motion_require '../support/dm_view_controller.rb'
2
2
  motion_require '../views/layout.rb'
3
3
  motion_require '../screens/_base_mixin.rb'
4
+ motion_require './extensions/_indicators_mixin'
5
+ motion_require './extensions/_navigation_bar_mixin'
4
6
  motion_require '../helpers/has_authorization'
5
7
  motion_require '../helpers/has_search_bar'
6
8
  module MotionPrime
7
9
  class BaseScreen < DMViewController
8
10
  include Layout
9
11
  include ScreenBaseMixin
12
+
13
+ # extensions
14
+ include ScreenIndicatorsMixin
15
+ include ScreenNavigationBarMixin
16
+
17
+ # helpers
10
18
  include HasAuthorization
11
19
  include HasSearchBar
12
20
 
@@ -0,0 +1,26 @@
1
+ module MotionPrime
2
+ module ScreenIndicatorsMixin
3
+ def show_activity_indicator
4
+ if @activity_indicator_view.nil?
5
+ @activity_indicator_view = UIActivityIndicatorView.gray
6
+ @activity_indicator_view.center = CGPointMake(view.center.x, view.center.y - 50)
7
+ view.addSubview @activity_indicator_view
8
+ end
9
+ @activity_indicator_view.startAnimating
10
+ end
11
+
12
+ def hide_activity_indicator
13
+ return unless @activity_indicator_view
14
+ @activity_indicator_view.stopAnimating
15
+ end
16
+
17
+ def show_notice(message, time = 1.0, type = :notice)
18
+ hud_type = case type.to_s
19
+ when 'alert' then MBAlertViewHUDTypeExclamationMark
20
+ else MBAlertViewHUDTypeCheckmark
21
+ end
22
+ MBHUDView.hudWithBody message,
23
+ type: hud_type, hidesAfter: time, show: true
24
+ end
25
+ end
26
+ end
@@ -60,7 +60,7 @@ module MotionPrime
60
60
  def prepare_controller(controller)
61
61
  controller = setup_screen_for_open(controller, {})
62
62
  if content_controller.nil?
63
- controller.ensure_wrapper_controller_in_place
63
+ controller.wrap_in_navigation if controller.respond_to?(:wrap_in_navigation)
64
64
  controller.send(:on_screen_load) if controller.respond_to?(:on_screen_load)
65
65
  controller = controller.main_controller if controller.respond_to?(:main_controller)
66
66
  else
@@ -83,7 +83,7 @@ module MotionPrime
83
83
  index = opts.delete(:at)
84
84
  options = build_options_for_element(opts)
85
85
  options[:name] ||= key
86
- options[:type] ||= options[:text] ? :label : :view
86
+ options[:type] ||= (options[:text] || options[:attributed_text_options]) ? :label : :view
87
87
  element = MotionPrime::BaseElement.factory(options.delete(:type), options)
88
88
  if index
89
89
  self.elements = Hash[self.elements.to_a.insert index, [key, element]]
@@ -147,7 +147,7 @@ module MotionPrime
147
147
  end
148
148
 
149
149
  def keyboard_will_show
150
- return if table_view.contentSize.height + table_view.top <= UIScreen.mainScreen.bounds.size.height
150
+ return if table_view.contentSize.height + table_view.top <= UIScreen.mainScreen.bounds.size.height - KEYBOARD_HEIGHT_PORTRAIT
151
151
  current_inset = table_view.contentInset
152
152
  current_inset.bottom = KEYBOARD_HEIGHT_PORTRAIT + (self.table_element.computed_options[:bottom_content_offset] || 0)
153
153
  table_view.contentInset = current_inset
@@ -164,13 +164,16 @@ module MotionPrime
164
164
  def on_input_edit(text_field); end
165
165
  def on_input_return(text_field)
166
166
  text_field.resignFirstResponder
167
- end;
167
+ end
168
168
  def textFieldShouldReturn(text_field)
169
169
  on_input_return(text_field)
170
170
  end
171
171
  def textFieldDidBeginEditing(text_field)
172
172
  on_input_edit(text_field)
173
173
  end
174
+ def textViewDidBeginEditing(text_view)
175
+ on_input_edit(text_view)
176
+ end
174
177
 
175
178
  def textView(text_view, shouldChangeTextInRange:range, replacementText:string)
176
179
  limit = (self.class.text_view_limits || {}).find do |field_name, limit|
@@ -56,8 +56,8 @@ module MotionPrime
56
56
  # focus on text field
57
57
  return unless begin_editing
58
58
  elements.values.each do |element|
59
- if element.view.is_a?(UITextField)
60
- element.view.becomeFirstResponder && return
59
+ if element.view.is_a?(UITextField) || element.view.is_a?(UITextView)
60
+ element.view.becomeFirstResponder and return
61
61
  end
62
62
  end
63
63
  self
@@ -1,5 +1,5 @@
1
1
  module MotionPrime
2
- module KeyValueStore
2
+ module SupportKeyValueStore
3
3
  extend ::MotionSupport::Concern
4
4
 
5
5
  # Key-Value accessors
@@ -0,0 +1,60 @@
1
+ module MotionPrime
2
+ module SupportPaddingAttribute
3
+ extend ::MotionSupport::Concern
4
+
5
+ included do
6
+ attr_accessor :paddingLeft, :paddingRight, :paddingTop, :paddingBottom, :padding
7
+ end
8
+
9
+ module ClassMethods
10
+ def default_padding_top
11
+ 0
12
+ end
13
+
14
+ def default_padding_left
15
+ 0
16
+ end
17
+
18
+ def default_padding_right
19
+ 0
20
+ end
21
+
22
+ def default_padding_bottom
23
+ 0
24
+ end
25
+ end
26
+
27
+ def padding_left
28
+ self.paddingLeft || self.padding || self.class.default_padding_left
29
+ end
30
+
31
+ def padding_right
32
+ self.paddingRight || self.padding || self.class.default_padding_right
33
+ end
34
+
35
+ def padding_top
36
+ self.paddingTop || self.padding || self.class.default_padding_top
37
+ end
38
+
39
+ def padding_bottom
40
+ self.paddingBottom || self.padding || self.class.default_padding_bottom
41
+ end
42
+
43
+ def padding_insets
44
+ UIEdgeInsetsMake(padding_top, padding_left, padding_bottom, padding_right)
45
+ end
46
+
47
+ def apply_padding(rect)
48
+ return unless apply_padding?
49
+ apply_padding!(rect)
50
+ end
51
+
52
+ def apply_padding!(rect)
53
+ raise "requires implementation"
54
+ end
55
+
56
+ def apply_padding?
57
+ ![padding_top, padding_left, padding_right, padding_bottom].all?(&:zero?)
58
+ end
59
+ end
60
+ end