motion-prime 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +14 -6
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +10 -8
  6. data/ROADMAP.md +9 -10
  7. data/Rakefile +1 -1
  8. data/doc/code/getting_started.rb +3 -3
  9. data/doc/code/screens.rb +25 -10
  10. data/doc/code/sections.rb +41 -0
  11. data/doc/docs/getting_started.html +8 -3
  12. data/doc/docs/screens.html +58 -19
  13. data/doc/docs/sections.html +134 -0
  14. data/files/Gemfile +7 -1
  15. data/files/Gemfile.lock +18 -9
  16. data/files/Rakefile +2 -11
  17. data/files/app/app_delegate.rb +2 -2
  18. data/files/app/config/base.rb +0 -4
  19. data/files/app/screens/application_screen.rb +2 -2
  20. data/files/app/screens/home_screen.rb +2 -0
  21. data/files/app/screens/sidebar_screen.rb +3 -3
  22. data/files/app/sections/home/section.rb +3 -0
  23. data/files/app/sections/sidebar/action.rb +1 -1
  24. data/files/app/styles/home.rb +9 -0
  25. data/files/app/styles/sidebar.rb +3 -3
  26. data/lib/motion-prime.rb +9 -0
  27. data/motion-prime/api_client.rb +5 -1
  28. data/motion-prime/app_delegate.rb +40 -45
  29. data/motion-prime/core_ext/kernel.rb +8 -0
  30. data/motion-prime/elements/_content_text_mixin.rb +3 -1
  31. data/motion-prime/elements/_text_mixin.rb +1 -1
  32. data/motion-prime/elements/base_element.rb +6 -5
  33. data/motion-prime/elements/draw/image.rb +6 -1
  34. data/motion-prime/elements/view_with_section.rb +7 -0
  35. data/motion-prime/helpers/has_style_chain_builder.rb +4 -1
  36. data/motion-prime/models/_association_mixin.rb +139 -0
  37. data/motion-prime/models/_base_mixin.rb +184 -0
  38. data/motion-prime/models/_dirty_mixin.rb +31 -0
  39. data/motion-prime/models/_finder_mixin.rb +208 -0
  40. data/motion-prime/models/{bag.rb → _nano_bag_mixin.rb} +4 -4
  41. data/motion-prime/models/{sync.rb → _sync_mixin.rb} +75 -76
  42. data/motion-prime/models/json.rb +6 -9
  43. data/motion-prime/models/model.rb +24 -172
  44. data/motion-prime/{mp.rb → prime.rb} +0 -1
  45. data/motion-prime/screens/_base_mixin.rb +9 -10
  46. data/motion-prime/screens/_navigation_mixin.rb +12 -17
  47. data/motion-prime/screens/extensions/_indicators_mixin.rb +1 -1
  48. data/motion-prime/screens/extensions/_navigation_bar_mixin.rb +3 -3
  49. data/motion-prime/screens/{base_screen.rb → screen.rb} +11 -5
  50. data/motion-prime/sections/_cell_section_mixin.rb +13 -0
  51. data/motion-prime/sections/_draw_section_mixin.rb +17 -0
  52. data/motion-prime/sections/base_section.rb +51 -16
  53. data/motion-prime/sections/form/base_field_section.rb +27 -16
  54. data/motion-prime/sections/form/base_header_section.rb +4 -3
  55. data/motion-prime/sections/form/password_field_section.rb +4 -0
  56. data/motion-prime/sections/form/select_field_section.rb +4 -0
  57. data/motion-prime/sections/form/string_field_section.rb +4 -0
  58. data/motion-prime/sections/form/submit_field_section.rb +4 -0
  59. data/motion-prime/sections/form/text_field_section.rb +4 -0
  60. data/motion-prime/sections/form.rb +7 -1
  61. data/motion-prime/sections/tabbed.rb +1 -1
  62. data/motion-prime/sections/table/table_delegate.rb +5 -0
  63. data/motion-prime/sections/table.rb +71 -51
  64. data/motion-prime/services/logger.rb +37 -0
  65. data/motion-prime/support/mp_cell_with_section.rb +9 -4
  66. data/motion-prime/support/tab_bar_controller.rb +2 -1
  67. data/motion-prime/version.rb +1 -1
  68. data/motion-prime/views/layout.rb +1 -1
  69. data/motion-prime/views/view_builder.rb +7 -0
  70. data/motion-prime.gemspec +1 -1
  71. data/spec/delegate/{base_delegate_spec.rb → delegate_spec.rb} +1 -1
  72. data/spec/helpers/{base_delegate.rb → delegates.rb} +0 -0
  73. data/spec/helpers/models.rb +11 -18
  74. data/spec/helpers/{base_screen.rb → screens.rb} +1 -1
  75. data/spec/models/{association_spec.rb → associations_spec.rb} +1 -1
  76. data/spec/models/bag_spec.rb +1 -1
  77. data/spec/models/errors_spec.rb +1 -1
  78. data/spec/models/finder_spec.rb +1 -1
  79. data/spec/models/json.rb +87 -0
  80. data/spec/models/model_spec.rb +23 -3
  81. data/spec/models/store_extension_spec.rb +1 -1
  82. data/spec/models/store_spec.rb +1 -1
  83. data/spec/screens/{base_screen_spec.rb → screen_spec.rb} +5 -1
  84. metadata +52 -43
  85. data/motion-prime/models/association.rb +0 -134
  86. data/motion-prime/models/base.rb +0 -27
  87. data/motion-prime/models/finder.rb +0 -202
  88. data/motion-prime/screens/sidebar_container_screen.rb +0 -80
@@ -1,5 +1,7 @@
1
1
  module MotionPrime
2
- module ModelSyncMethods
2
+ module ModelSyncMixin
3
+ extend ::MotionSupport::Concern
4
+
3
5
  def self.included(base)
4
6
  base.class_attribute :_sync_url
5
7
  base.class_attribute :_updatable_attributes
@@ -21,54 +23,47 @@ module MotionPrime
21
23
  delete
22
24
  end
23
25
 
24
- # sync with server and save on local
25
- def sync!(sync_options = {}, &block)
26
- sync(sync_options.merge(save: true), &block)
26
+ # fetch from server and save on local
27
+ def fetch!(options = {}, &block)
28
+ fetch(options.merge(save: true), &block)
27
29
  end
28
30
 
29
- # sync with with server
30
- # TODO: order of fetch/update should be based on updated time?
31
- def sync(sync_options = {}, &block)
31
+ # fetch from server
32
+ def fetch(options = {}, &block)
32
33
  use_callback = block_given?
33
- should_fetch = sync_options[:fetch]
34
- should_update = sync_options[:update]
35
- should_fetch_associations = if sync_options.has_key?(:fetch_associations)
36
- sync_options[:fetch_associations]
37
- else # do not need to fetch unless this is a GET request
38
- should_fetch
39
- end
34
+ method = options[:method] || :get
35
+ url = sync_url(method, options)
40
36
 
41
- should_fetch = persisted? if should_fetch.nil?
42
- should_update ||= new_record? unless should_fetch
43
-
44
- method = sync_options[:method]
45
- method ||= if should_update
46
- persisted? ? :put : :post
47
- else
48
- :get
49
- end
50
- url = sync_url(method, sync_options)
51
-
52
- if url.blank?
53
- should_fetch = false
54
- should_update = false
55
- end
37
+ will_fetch_model = !url.blank?
38
+ will_fetch_associations = !options.has_key?(:associations) || options[:associations]
56
39
 
57
40
  fetch_with_url url do |data, status_code|
58
- save if sync_options[:save]
59
- block.call(data, status_code, data) if use_callback
60
- end if should_fetch
41
+ save if options[:save]
42
+ block.call(data, status_code, data) if use_callback && !will_fetch_associations
43
+ end if will_fetch_model
61
44
 
62
- update_with_url url, sync_options do |data, status_code|
63
- save if sync_options[:save] && status_code.to_s =~ /20\d/
45
+ fetch_associations(options) do |data, status_code|
64
46
  # run callback only if it wasn't run on fetch
65
- block.call(data, status_code, data) if use_callback && !should_fetch
66
- end if should_update
47
+ block.call(data, status_code, data) if use_callback
48
+ end if will_fetch_associations
49
+ end
67
50
 
68
- fetch_associations(sync_options) do |data, status_code|
69
- # run callback only if it wasn't run on fetch or update
70
- block.call(data, status_code, data) if use_callback && !should_fetch && !should_update
71
- end if should_fetch_associations
51
+ # update on server and save response on local
52
+ def update!(options = {}, &block)
53
+ update(options.merge(save_response: true), &block)
54
+ end
55
+
56
+ # update on server
57
+ def update(options = {}, &block)
58
+ use_callback = block_given?
59
+
60
+ method = options[:method] || (persisted? ? :put : :post)
61
+ url = sync_url(method, options)
62
+ will_update_model = !url.blank?
63
+
64
+ update_with_url url, options do |data, status_code|
65
+ block.call(data, status_code, data) if use_callback
66
+ end if will_update_model
72
67
  end
73
68
 
74
69
  # fetch from server using url
@@ -81,22 +76,23 @@ module MotionPrime
81
76
  end
82
77
 
83
78
  # update on server using url
84
- def update_with_url(url, sync_options = nil, &block)
79
+ def update_with_url(url, options = {}, &block)
85
80
  use_callback = block_given?
86
- filtered_attributes = filtered_updatable_attributes(sync_options)
81
+ filtered_attributes = filtered_updatable_attributes(options)
87
82
 
88
- post_data = sync_options[:params_root] || {}
83
+ post_data = options[:params_root] || {}
89
84
  post_data[:files] = {}
90
85
  filtered_attributes.delete(:files).each do |file_name, file|
91
86
  post_data[:files][[model_name, file_name].join] = file
92
87
  end
93
88
  post_data[model_name] = filtered_attributes
94
89
 
95
- method = sync_options[:method] || (id ? :put : :post)
90
+ method = options[:method] || (persisted? ? :put : :post)
96
91
  api_client.send(method, url, post_data) do |data, status_code|
97
- update_from_response = sync_options.has_key?(:update_from_response) ? sync_options[:update_from_response] : true
98
- if update_from_response && status_code.to_s =~ /20\d/ && data.is_a?(Hash)
92
+ save_response = !options.has_key?(:save_response) || options[:save_response]
93
+ if save_response && status_code.to_s =~ /20\d/ && data.is_a?(Hash)
99
94
  set_attributes_from_response(data)
95
+ save
100
96
  end
101
97
  block.call(data, status_code, data) if use_callback
102
98
  end
@@ -109,11 +105,13 @@ module MotionPrime
109
105
 
110
106
  # set attributes, using fetch
111
107
  def fetch_with_attributes(attrs)
112
- attrs.each do |key, value|
113
- if respond_to?(:"fetch_#{key}")
114
- self.send(:"fetch_#{key}", value)
115
- elsif respond_to?(:"#{key}=")
116
- self.send(:"#{key}=", value)
108
+ track_changed_attributes do
109
+ attrs.each do |key, value|
110
+ if respond_to?(:"fetch_#{key}")
111
+ self.send(:"fetch_#{key}", value)
112
+ elsif respond_to?(:"#{key}=")
113
+ self.send(:"#{key}=", value)
114
+ end
117
115
  end
118
116
  end
119
117
  self
@@ -156,16 +154,17 @@ module MotionPrime
156
154
  NSLog("SYNC: started sync for #{key} in #{self.class_name_without_kvo}")
157
155
  api_client.get normalize_sync_url(options[:sync_url]) do |response, status_code|
158
156
  data = options[:sync_key] && response ? response[options[:sync_key]] : response
157
+ model_class = key.classify.constantize
159
158
  if data
160
159
  # Update/Create existing records
161
160
  data.each do |attributes|
162
161
  model = old_collection.detect{ |model| model.id == attributes[:id]}
163
162
  unless model
164
- model = key.classify.constantize.new
163
+ model = model_class.new
165
164
  self.send(:"#{key}_bag") << model
166
165
  end
167
166
  model.fetch_with_attributes(attributes)
168
- model.save if sync_options[:save]
167
+ model.save if sync_options[:save] && model.has_changed?
169
168
  end
170
169
  old_collection.each do |old_model|
171
170
  model = data.detect{ |model| model[:id] == old_model.id}
@@ -238,36 +237,36 @@ module MotionPrime
238
237
  def normalize_sync_url(url)
239
238
  url.to_s.gsub(':id', id.to_s)
240
239
  end
241
- end
242
240
 
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)
241
+ module ClassMethods
242
+ def new(data = {}, options = {})
243
+ model = super
244
+ if fetch_attributes = options[:fetch_attributes]
245
+ model.fetch_with_attributes(fetch_attributes)
246
+ end
247
+ model
248
248
  end
249
- model
250
- end
251
249
 
252
- def sync_url(url = nil, &block)
253
- if url || block_given?
254
- self._sync_url = url || block
255
- else
256
- self._sync_url
250
+ def sync_url(url = nil, &block)
251
+ if url || block_given?
252
+ self._sync_url = url || block
253
+ else
254
+ self._sync_url
255
+ end
257
256
  end
258
- end
259
257
 
260
- def updatable_attributes(*attrs)
261
- return self._updatable_attributes if attrs.blank?
262
- attrs.each do |attribute|
263
- updatable_attribute attribute
258
+ def updatable_attributes(*attrs)
259
+ return self._updatable_attributes if attrs.blank?
260
+ attrs.each do |attribute|
261
+ updatable_attribute attribute
262
+ end
264
263
  end
265
- end
266
264
 
267
- def updatable_attribute(attribute, options = {}, &block)
268
- options[:block] = block if block_given?
269
- self._updatable_attributes ||= {}
270
- self._updatable_attributes[attribute] = options
265
+ def updatable_attribute(attribute, options = {}, &block)
266
+ options[:block] = block if block_given?
267
+ self._updatable_attributes ||= {}
268
+ self._updatable_attributes[attribute] = options
269
+ end
271
270
  end
272
271
  end
273
272
  end
@@ -1,12 +1,13 @@
1
1
  module MotionPrime
2
- module JSON
2
+ class JsonParseError < StandardError; end
3
+
4
+ class JSON
3
5
  PARAMETRIZE_CLASSES = [Time, Date]
4
- class ParserError < StandardError; end
5
6
 
6
7
  # Parses a string or data object and converts it in data structure.
7
8
  #
8
9
  # @param [String, NSData] str_data the string or data to convert.
9
- # @raise [ParserError] If the parsing of the passed string/data isn't valid.
10
+ # @raise [JsonParseError] If the parsing of the passed string/data isn't valid.
10
11
  # @return [Hash, Array, NilClass] the converted data structure, nil if the incoming string isn't valid.
11
12
  def self.parse(str_data, &block)
12
13
  return nil unless str_data
@@ -14,12 +15,8 @@ module MotionPrime
14
15
  opts = NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves | NSJSONReadingAllowFragments
15
16
  error = Pointer.new(:id)
16
17
  obj = NSJSONSerialization.JSONObjectWithData(data, options: opts, error: error)
17
- raise ParserError, error[0].description if error[0]
18
- if block_given?
19
- yield obj
20
- else
21
- obj
22
- end
18
+ raise JsonParseError, error[0].description if error[0]
19
+ obj
23
20
  end
24
21
 
25
22
  # Generates a string from data structure.
@@ -1,178 +1,30 @@
1
+ motion_require '../helpers/has_authorization'
2
+ motion_require './_nano_bag_mixin.rb'
3
+ motion_require './_finder_mixin.rb'
4
+ motion_require './_base_mixin.rb'
5
+ motion_require './_sync_mixin.rb'
6
+ motion_require './_association_mixin.rb'
7
+ motion_require './_dirty_mixin.rb'
8
+ motion_require './store.rb'
9
+ motion_require './store_extension.rb'
1
10
  module MotionPrime
2
- module ModelMethods
3
- def self.included(base)
4
- base.class_attribute :default_sort_options
5
- end
6
-
7
- def save
8
- raise StoreError, 'No store provided' unless self.store
9
- error_ptr = Pointer.new(:id)
10
- self.store.addObject(self, error: error_ptr)
11
- raise StoreError, error_ptr[0].description if error_ptr[0]
12
- self
13
- end
14
-
15
- def delete
16
- raise StoreError, 'No store provided' unless self.store
17
-
18
- error_ptr = Pointer.new(:id)
19
- self.store.removeObject(self, error: error_ptr)
20
- raise StoreError, error_ptr[0].description if error_ptr[0]
21
- self
22
- end
23
-
24
- def store
25
- super || self.class.store
26
- end
27
-
28
- def assign_attributes(new_attributes, options = {})
29
- attributes = new_attributes.symbolize_keys
30
- attributes.each do |k, v|
31
- if has_attribute?(k)
32
- assign_attribute(k, v) unless options[:skip_nil_values] && v.nil?
33
- elsif options[:check_attribute_presence]
34
- NSLog("unknown attribute: #{k}")
35
- else
36
- raise(NoMethodError, "unknown attribute: #{k}")
37
- end
38
- end
39
- end
40
-
41
- def assign_attribute(name, value)
42
- self.send("#{name}=", value) if has_attribute?(name)
43
- end
44
-
45
- def has_attribute?(name)
46
- respond_to?("#{name}=")
47
- end
48
-
49
- def attributes_hash
50
- self.info.to_hash.symbolize_keys
51
- end
52
-
53
- def new_record?
54
- id.blank?
55
- end
56
-
57
- def persisted?
58
- !new_record?
59
- end
60
-
61
- def model_name
62
- self.class_name_without_kvo.underscore
63
- end
11
+ class Model < NSFNanoObject
12
+ include MotionPrime::HasAuthorization
13
+ include MotionPrime::ModelBaseMixin
14
+ include MotionPrime::ModelAssociationMixin
15
+ include MotionPrime::ModelSyncMixin
16
+ include MotionPrime::ModelFinderMixin
17
+ include MotionPrime::ModelDirtyMixin
64
18
 
65
- def inspect
66
- "#<#{self.class}:0x#{self.object_id.to_s(16)}> " + MotionPrime::JSON.generate(info)
67
- end
68
- end
69
-
70
- module ModelClassMethods
71
- # Initialize a new object
72
- #
73
- # Examples:
74
- # User.new(name: "Bob", age: 10)
75
- #
76
- # @return MotionPrime::BaseModel unsaved model
77
- def new(data = {}, options = {})
78
- data.keys.each { |k|
79
- unless self.attributes.member? k.to_sym
80
- raise StoreError, "'#{k}' is not a defined attribute for this model"
81
- end
82
- }
83
-
84
- object = self.nanoObjectWithDictionary(data)
85
- object
86
- end
87
-
88
- # Initialize a new object and save it
89
- #
90
- # Examples:
91
- # User.create(name: "Bob", age: 10)
92
- #
93
- # @return MotionPrime::BaseModel saved model
94
- def create(data = {})
95
- object = self.new(data)
96
- object.save
97
- end
98
-
99
- # Define model attribute
100
- #
101
- # Examples:
102
- # class User < MotionPrime::BaseModel
103
- # attribute :name
104
- # attribute :age
105
- # end
106
- #
107
- # @return Nil
108
- def attribute(name, options = {})
109
- attributes << name
110
-
111
- define_method(name) do |*args, &block|
112
- self.info[name]
113
- end
114
-
115
- define_method((name + "=").to_sym) do |*args, &block|
116
- value = args[0]
117
- case options[:type].to_s
118
- when 'integer' then value = value.to_i
119
- when 'float' then value = value.to_f
120
- end unless value.nil?
121
-
122
- self.info[name] = value
123
- end
19
+ attribute :bag_key # need this as we use shared store; each nested resource must belong to parent bag
20
+ attribute :id
124
21
 
125
- if options[:type].to_s == 'boolean'
126
- define_method("#{name}?") do
127
- !!self.info[name]
128
- end
129
- end
22
+ def errors
23
+ @errors ||= Errors.new(self.weak_ref)
130
24
  end
131
25
 
132
- # Return all model attribute names
133
- #
134
- # @return Array array of attribute names
135
- def attributes(*attrs)
136
- if attrs.size > 0
137
- attrs.each{|attr| attribute attr}
138
- else
139
- @attributes ||= []
140
- end
141
- end
142
-
143
- # Return store associated with model class, or shared store by default
144
- #
145
- # @return MotionPrime::Store store
146
- def store
147
- @store ||= MotionPrime::Store.shared_store
148
- end
149
-
150
- # Define store associated with model class
151
- #
152
- # @param MotionPrime::Store store
153
- # @return MotionPrime::Store store
154
- def store=(store)
155
- @store = store
156
- end
157
-
158
- # Count of models
159
- #
160
- # @return Fixnum count
161
- def count
162
- self.store.count(self)
163
- end
164
-
165
- # Delete objects from store
166
- #
167
- # @param [Array, MotionPrime::BaseModel] objects to delete
168
- # @return [Array] result
169
- def delete(*args)
170
- keys = find_keys(*args)
171
- self.store.delete_keys(keys)
172
- end
173
-
174
- def default_sort(sort_options)
175
- self.default_sort_options = sort_options
176
- end
26
+ # def dealloc
27
+ # pp 'deall model'
28
+ # end
177
29
  end
178
- end
30
+ end
@@ -15,5 +15,4 @@ module MotionPrime
15
15
  ENV['PRIME_ENV'] || ENV['RUBYMOTION_ENV'] || 'development'
16
16
  end
17
17
  end
18
- ::MP = MotionPrime unless defined?(::MP)
19
18
  ::Prime = MotionPrime unless defined?(::Prime)
@@ -21,23 +21,15 @@ module MotionPrime
21
21
  UIApplication.sharedApplication.delegate
22
22
  end
23
23
 
24
- def show_sidebar
25
- app_delegate.show_sidebar
26
- end
27
-
28
- def hide_sidebar
29
- app_delegate.hide_sidebar
30
- end
31
-
32
24
  def on_screen_load
33
25
  run_callbacks :load do
34
26
  on_load
35
27
  end
36
28
  end
37
29
 
38
- # Setup the screen, will be called when you run MPViewController.new
30
+ # Setup the screen, this method will be called when you run MPViewController.new
39
31
  # @param options [hash] Options passed to setup
40
- # @return [MotionPrime::BaseScreen] Ready to use screen
32
+ # @return [MotionPrime::Screen] Ready to use screen
41
33
  def on_create(options = {})
42
34
  unless self.is_a?(UIViewController)
43
35
  raise StandardError.new("ERROR: Screens must extend UIViewController.")
@@ -88,6 +80,13 @@ module MotionPrime
88
80
  def after_load(method_name)
89
81
  set_callback :load, :after, method_name
90
82
  end
83
+ def create_with_options(screen, navigation = true, options = {})
84
+ if screen.is_a?(Symbol)
85
+ options[:navigation] = navigation unless options.has_key?(:navigation)
86
+ screen = class_factory("#{screen}_screen").new(options)
87
+ end
88
+ screen
89
+ end
91
90
  end
92
91
  end
93
92
  end
@@ -6,26 +6,21 @@ module MotionPrime
6
6
  # animated: open screen with animation.
7
7
  # modal: open screen as model
8
8
 
9
- # @param screen [MotionPrime::BaseScreen] Screen to be opened
9
+ # @param screen [MotionPrime::Screen] Screen to be opened
10
10
  # @param args [Hash] Options for opening screen
11
- # @return [MotionPrime::BaseScreen]
11
+ # @return [MotionPrime::Screen]
12
12
  def open_screen(screen, args = {})
13
- if args[:modal] || has_navigation?
14
- screen = setup_screen_for_open(screen, args)
15
- screen.send(:on_screen_load) if screen.respond_to?(:on_screen_load)
16
- args[:animated] = args.has_key?(:animated) ? args[:animated] : true
17
- if args[:modal] || !has_navigation?
18
- open_screen_modal(screen, args)
19
- else
20
- open_screen_navigational(screen, args)
21
- end
13
+ screen = setup_screen_for_open(screen, args)
14
+ screen.send(:on_screen_load) if screen.respond_to?(:on_screen_load)
15
+ args[:animated] = args.has_key?(:animated) ? args[:animated] : true
16
+ if args[:modal] || !has_navigation?
17
+ open_screen_modal(screen, args)
22
18
  else
23
- app_delegate.open_screen(screen.main_controller)
19
+ open_screen_navigational(screen, args)
24
20
  end
25
21
  screen
26
22
  end
27
23
 
28
-
29
24
  def close_screen(args = {})
30
25
  args[:animated] = args.has_key?(:animated) ? args[:animated] : true
31
26
  # Pop current view, maybe with arguments, if in navigation controller
@@ -47,7 +42,7 @@ module MotionPrime
47
42
  end
48
43
 
49
44
  def wrap_in_navigation?
50
- options[:navigation]
45
+ options[:navigation] || options[:navigation].nil?
51
46
  end
52
47
 
53
48
  def wrap_in_navigation
@@ -71,10 +66,10 @@ module MotionPrime
71
66
  private
72
67
  def setup_screen_for_open(screen, args = {})
73
68
  # Instantiate screen if given a class
74
- screen = screen.new if screen.respond_to?(:new)
69
+ screen = Screen.create_with_options(screen, true, args)
75
70
 
76
71
  # Set parent, title & modal properties
77
- screen.parent_screen = self.weak_ref if screen.respond_to?("parent_screen=")
72
+ screen.parent_screen = self if screen.respond_to?("parent_screen=")
78
73
  screen.title = args[:title] if args[:title] && screen.respond_to?("title=")
79
74
  screen.modal = args[:modal] if args[:modal] && screen.respond_to?("modal=")
80
75
 
@@ -98,7 +93,7 @@ module MotionPrime
98
93
 
99
94
  def close_screen_navigational(args = {})
100
95
  if args[:to_screen] && args[:to_screen].is_a?(UIViewController)
101
- self.parent_screen = args[:to_screen].weak_ref
96
+ self.parent_screen = args[:to_screen]
102
97
 
103
98
  screens = self.navigation_controller.childViewControllers
104
99
  self.navigation_controller.popToViewController(args[:to_screen], animated: args[:animated])
@@ -3,7 +3,7 @@ module MotionPrime
3
3
  def show_activity_indicator
4
4
  if @activity_indicator_view.nil?
5
5
  @activity_indicator_view = UIActivityIndicatorView.gray
6
- @activity_indicator_view.center = CGPointMake(view.center.x, view.center.y - 50)
6
+ @activity_indicator_view.center = CGPointMake(view.center.x, view.center.y)
7
7
  view.addSubview @activity_indicator_view
8
8
  end
9
9
  @activity_indicator_view.startAnimating
@@ -24,8 +24,9 @@ module MotionPrime
24
24
  navigationItem.leftBarButtonItem = create_navigation_button(title, {action: :back}.merge(args))
25
25
  end
26
26
 
27
+ # should be extracted to sidebar gem
27
28
  def set_navigation_back_or_menu(back_title = 'Back')
28
- if parent_screen.is_a?(MotionPrime::SidebarContainerScreen)
29
+ if parent_screen.is_a?(PrimeResideMenu::SidebarContainerScreen)
29
30
  set_navigation_left_button 'Menu', image: 'images/navigation/menu_button.png', action: :show_sidebar
30
31
  else
31
32
  set_navigation_back_button back_title, icon: 'images/navigation/back_icon.png'
@@ -41,7 +42,6 @@ module MotionPrime
41
42
 
42
43
  def create_navigation_button(title, args = {})
43
44
  args[:style] ||= UIBarButtonItemStylePlain
44
- args[:target] = (args[:target] || self).weak_ref
45
45
  args[:action] ||= nil
46
46
  # TODO: Find better place for this code, may be just create custom control
47
47
  if args[:image]
@@ -66,7 +66,7 @@ module MotionPrime
66
66
  UIBarButtonItem.alloc.initWithCustomView(face)
67
67
  else
68
68
  UIBarButtonItem.alloc.initWithTitle(title,
69
- style: args[:style], target: args[:target], action: args[:action])
69
+ style: args[:style], target: args[:target] || self, action: args[:action])
70
70
  end
71
71
  end
72
72
  end
@@ -6,7 +6,7 @@ motion_require './extensions/_navigation_bar_mixin'
6
6
  motion_require '../helpers/has_authorization'
7
7
  motion_require '../helpers/has_search_bar'
8
8
  module MotionPrime
9
- class BaseScreen < MPViewController
9
+ class Screen < MPViewController
10
10
  include Layout
11
11
  include ScreenBaseMixin
12
12
 
@@ -18,6 +18,8 @@ module MotionPrime
18
18
  include HasAuthorization
19
19
  include HasSearchBar
20
20
 
21
+ extend HasClassFactory
22
+
21
23
  def render
22
24
  end
23
25
 
@@ -34,10 +36,14 @@ module MotionPrime
34
36
  @on_appear_happened = true
35
37
  end
36
38
 
37
- # def dealloc
38
- # pp 'Deallocating Screen'
39
- # super
40
- # end
39
+ def dealloc
40
+ pp 'Deallocating Screen'
41
+ @main_section.instance_variable_set(:"@break_preload", true) # TODO: find a better option
42
+ # FIXME: calling instance_eval in title method (_base_screen_mixin) instance variables need to be cleared manually
43
+ # clear_instance_variables cause BAD_ACCESS errors too
44
+ @main_section = nil
45
+ super
46
+ end
41
47
 
42
48
  def visible?
43
49
  self.isViewLoaded && view.window
@@ -1,3 +1,4 @@
1
+ # This Mixin will be included only to sections, which added as cell to table section.
1
2
  module MotionPrime
2
3
  module CellSectionMixin
3
4
  extend ::MotionSupport::Concern
@@ -35,6 +36,11 @@ module MotionPrime
35
36
  @container_bounds ||= CGRectMake(0, 0, table.table_view.bounds.size.width, container_height)
36
37
  end
37
38
 
39
+ # should do nothing, because table section will care about it.
40
+ def render_container(options = {}, &block)
41
+ block.call
42
+ end
43
+
38
44
  def init_container_element(options = {})
39
45
  @container_element ||= begin
40
46
  options.merge!({
@@ -49,6 +55,7 @@ module MotionPrime
49
55
  end
50
56
  end
51
57
 
58
+ # FIXME: Why this duplicates functionality from other parts, e.g. draw_in?
52
59
  def load_container_element(options = {})
53
60
  init_container_element(options)
54
61
  load_elements
@@ -68,6 +75,12 @@ module MotionPrime
68
75
  container_view.setNeedsDisplay
69
76
  end
70
77
 
78
+ def dealloc
79
+ # TODO: remove this when solve this problem: dealloc TableCells on TableView.reloadData (in case when reuseIdentifier has been used)
80
+ container_view.section = nil if container_view.respond_to?(:setSection)
81
+ super
82
+ end
83
+
71
84
  module ClassMethods
72
85
  def set_cell_name(value)
73
86
  self.custom_cell_name = value