motion-prime 0.8.1 → 0.8.2
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 +6 -0
- data/Gemfile.lock +1 -1
- data/ROADMAP.md +3 -0
- data/files/Gemfile +1 -1
- data/motion-prime/api_client.rb +5 -2
- data/motion-prime/core_ext/kernel.rb +36 -0
- data/motion-prime/elements/_content_text_mixin.rb +32 -11
- data/motion-prime/elements/base_element.rb +33 -16
- data/motion-prime/elements/draw.rb +10 -4
- data/motion-prime/elements/draw/image.rb +26 -15
- data/motion-prime/elements/map.rb +5 -0
- data/motion-prime/models/_association_mixin.rb +0 -3
- data/motion-prime/models/_base_mixin.rb +24 -3
- data/motion-prime/models/_filter_mixin.rb +28 -0
- data/motion-prime/models/_sync_mixin.rb +13 -10
- data/motion-prime/models/association_collection.rb +41 -16
- data/motion-prime/models/errors.rb +46 -24
- data/motion-prime/models/model.rb +8 -0
- data/motion-prime/screens/_sections_mixin.rb +1 -1
- data/motion-prime/screens/extensions/_indicators_mixin.rb +4 -2
- data/motion-prime/screens/extensions/_navigation_bar_mixin.rb +1 -1
- data/motion-prime/screens/screen.rb +4 -0
- data/motion-prime/sections/_async_form_mixin.rb +12 -0
- data/motion-prime/sections/_async_table_mixin.rb +193 -0
- data/motion-prime/sections/_cell_section_mixin.rb +6 -6
- data/motion-prime/sections/_draw_section_mixin.rb +13 -5
- data/motion-prime/sections/base_section.rb +62 -36
- data/motion-prime/sections/form.rb +19 -35
- data/motion-prime/sections/form/base_field_section.rb +42 -34
- data/motion-prime/sections/form/static_field_section.rb +9 -0
- data/motion-prime/sections/table.rb +143 -201
- data/motion-prime/sections/table/table_delegate.rb +15 -15
- data/motion-prime/services/table_data_indexes.rb +12 -2
- data/motion-prime/styles/base.rb +1 -1
- data/motion-prime/styles/form.rb +6 -6
- data/motion-prime/version.rb +1 -1
- data/motion-prime/views/layout.rb +5 -2
- data/motion-prime/views/view_styler.rb +2 -0
- data/spec/models/association_collection_spec.rb +28 -6
- metadata +6 -2
@@ -78,9 +78,7 @@ module MotionPrime
|
|
78
78
|
|
79
79
|
association = association_name.classify.constantize.new
|
80
80
|
association.fetch_with_attributes(value)
|
81
|
-
association.save
|
82
81
|
self.send(:"#{bag_name}") << association
|
83
|
-
self.send(:"#{bag_name}").save
|
84
82
|
association
|
85
83
|
end
|
86
84
|
define_method("#{association_name}") do
|
@@ -111,7 +109,6 @@ module MotionPrime
|
|
111
109
|
end
|
112
110
|
association_data = collection.values
|
113
111
|
self.send(:"#{bag_name}=", association_data)
|
114
|
-
self.send(:"#{bag_name}").save
|
115
112
|
association_data
|
116
113
|
end
|
117
114
|
define_method("#{association_name}=") do |value|
|
@@ -33,7 +33,7 @@ module MotionPrime
|
|
33
33
|
super || self.class.store
|
34
34
|
end
|
35
35
|
|
36
|
-
# Assigns attributes to model
|
36
|
+
# Assigns attributes to model
|
37
37
|
#
|
38
38
|
# @params attributes [Hash] attributes to be assigned
|
39
39
|
# @params options [Hash] options
|
@@ -53,7 +53,7 @@ module MotionPrime
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
# Assigns attribute to model
|
56
|
+
# Assigns attribute to model
|
57
57
|
#
|
58
58
|
# @params name [String, Symbol] attribute name
|
59
59
|
# @params value [Object] attribute value
|
@@ -105,6 +105,13 @@ module MotionPrime
|
|
105
105
|
"#<#{self.class}:0x#{self.object_id.to_s(16)}> " + MotionPrime::JSON.generate(info)
|
106
106
|
end
|
107
107
|
|
108
|
+
# Returns a clone of the record with empty bags
|
109
|
+
#
|
110
|
+
# @return new [Prime::Model] model
|
111
|
+
def clone
|
112
|
+
self.class.new(self.info.select { |key, value| !key.to_s.ends_with?('_bag') })
|
113
|
+
end
|
114
|
+
|
108
115
|
module ClassMethods
|
109
116
|
# Initialize a new object
|
110
117
|
#
|
@@ -167,7 +174,7 @@ module MotionPrime
|
|
167
174
|
define_method((name + "=").to_sym) do |*args, &block|
|
168
175
|
value = args[0]
|
169
176
|
case options[:type].to_s
|
170
|
-
when 'integer'
|
177
|
+
when 'integer'
|
171
178
|
value = value.to_i
|
172
179
|
when 'float'
|
173
180
|
value = value.to_f
|
@@ -178,6 +185,20 @@ module MotionPrime
|
|
178
185
|
self.info[name] = value
|
179
186
|
end
|
180
187
|
|
188
|
+
define_method(name.to_sym) do
|
189
|
+
value = self.info[name]
|
190
|
+
case options[:type].to_s
|
191
|
+
when 'integer'
|
192
|
+
value.to_i
|
193
|
+
when 'float'
|
194
|
+
value.to_f
|
195
|
+
when 'time' && !value.is_a?(String)
|
196
|
+
value.to_short_iso8601
|
197
|
+
else
|
198
|
+
value
|
199
|
+
end
|
200
|
+
end if options[:convert]
|
201
|
+
|
181
202
|
if options[:type].to_s == 'boolean'
|
182
203
|
define_method("#{name}?") do
|
183
204
|
!!self.info[name]
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module MotionPrime
|
2
|
+
module FilterMixin
|
3
|
+
def filter_array(data, find_options = {}, sort_options = nil)
|
4
|
+
data = data.select do |entity|
|
5
|
+
find_options.all? { |field, value| entity.info[field] == value }
|
6
|
+
end if find_options.present?
|
7
|
+
|
8
|
+
data.sort! do |a, b|
|
9
|
+
left_part = []
|
10
|
+
right_part = []
|
11
|
+
|
12
|
+
sort_options[:sort].each do |(k,v)|
|
13
|
+
left = a.send(k)
|
14
|
+
right = b.send(k)
|
15
|
+
if left.class != right.class
|
16
|
+
left = left.to_s
|
17
|
+
right = right.to_s
|
18
|
+
end
|
19
|
+
left, right = right, left if v.to_s == 'desc'
|
20
|
+
left_part << left
|
21
|
+
right_part << right
|
22
|
+
end
|
23
|
+
left_part <=> right_part
|
24
|
+
end if sort_options.try(:[], :sort).present?
|
25
|
+
data
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -50,7 +50,7 @@ module MotionPrime
|
|
50
50
|
#
|
51
51
|
# @param options [Hash] fetch options
|
52
52
|
# @option options [Symbol] :method Http method to calculate url, `:get` by default
|
53
|
-
# @option options [Boolean] :associations Also fetch associations
|
53
|
+
# @option options [Boolean or Array] :associations Also fetch associations
|
54
54
|
# @option options [Boolean] :save Save model after fetch
|
55
55
|
# @param block [Proc] block to be executed after fetch
|
56
56
|
def fetch(options = {}, &block)
|
@@ -59,8 +59,8 @@ module MotionPrime
|
|
59
59
|
url = sync_url(method, options)
|
60
60
|
|
61
61
|
will_fetch_model = !url.blank?
|
62
|
-
will_fetch_associations =
|
63
|
-
will_fetch_associations = false unless has_associations_to_fetch?
|
62
|
+
will_fetch_associations = options.fetch(:associations, true)
|
63
|
+
will_fetch_associations = false unless has_associations_to_fetch?(options)
|
64
64
|
|
65
65
|
fetch_with_url url, options do |data, status_code|
|
66
66
|
save if options[:save]
|
@@ -176,13 +176,13 @@ module MotionPrime
|
|
176
176
|
@associations ||= (self.class._associations || {}).clone
|
177
177
|
end
|
178
178
|
|
179
|
-
def associations_to_fetch
|
180
|
-
|
179
|
+
def associations_to_fetch(options = {})
|
180
|
+
associations.select { |key, v| fetch_association?(key, options) }
|
181
181
|
end
|
182
182
|
|
183
183
|
def fetch_associations(sync_options = {}, &block)
|
184
184
|
use_callback = block_given?
|
185
|
-
associations_to_fetch.keys.each_with_index do |key, index|
|
185
|
+
associations_to_fetch(sync_options).keys.each_with_index do |key, index|
|
186
186
|
if use_callback && associations.count - 1 == index
|
187
187
|
fetch_association(key, sync_options, &block)
|
188
188
|
else
|
@@ -191,22 +191,25 @@ module MotionPrime
|
|
191
191
|
end
|
192
192
|
end
|
193
193
|
|
194
|
-
def has_associations_to_fetch?
|
195
|
-
associations_to_fetch.present?
|
194
|
+
def has_associations_to_fetch?(options = {})
|
195
|
+
associations_to_fetch(options).present?
|
196
196
|
end
|
197
197
|
|
198
198
|
def has_association?(key)
|
199
199
|
!associations[key.to_sym].nil?
|
200
200
|
end
|
201
201
|
|
202
|
-
def fetch_association?(key)
|
202
|
+
def fetch_association?(key, options = {})
|
203
|
+
allowed_associations = options[:associations].map(&:to_sym) if options[:associations].is_a?(Array)
|
204
|
+
return false if allowed_associations.try(:exclude?, key.to_sym)
|
205
|
+
|
203
206
|
options = associations[key.to_sym]
|
204
207
|
return false if options[:if] && !options[:if].to_proc.call(self)
|
205
208
|
association_sync_url(key, options).present?
|
206
209
|
end
|
207
210
|
|
208
211
|
def fetch_association(key, sync_options = {}, &block)
|
209
|
-
return unless fetch_association?(key)
|
212
|
+
return unless fetch_association?(key, sync_options)
|
210
213
|
options = associations[key.to_sym]
|
211
214
|
if options[:type] == :many
|
212
215
|
fetch_has_many(key, options, sync_options, &block)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module MotionPrime
|
2
2
|
class AssociationCollection < ::Array
|
3
|
+
include FilterMixin
|
4
|
+
|
3
5
|
attr_reader :bag, :association_name
|
4
6
|
attr_reader :inverse_relation_name, :inverse_relation_key, :model_inverse_relation_name
|
5
7
|
|
6
|
-
delegate :<<, to: :bag
|
7
|
-
|
8
8
|
def initialize(bag, options, *args)
|
9
9
|
@bag = bag
|
10
10
|
@association_name = options[:association_name]
|
@@ -17,7 +17,8 @@ module MotionPrime
|
|
17
17
|
options[:class_name] == inverse_relation.class_name_without_kvo
|
18
18
|
end.try(:first)
|
19
19
|
|
20
|
-
|
20
|
+
data = bag.store.present? ? find(*args) : filter(*args)
|
21
|
+
super data
|
21
22
|
end
|
22
23
|
|
23
24
|
# Initialize a new object and add to collection.
|
@@ -28,9 +29,7 @@ module MotionPrime
|
|
28
29
|
# @params attributes [Hash] attributes beeing assigned to model
|
29
30
|
# @return MotionPrime::Model unsaved model
|
30
31
|
def new(attributes = {})
|
31
|
-
record = model_class.new(attributes)
|
32
|
-
set_inverse_relation_for(model)
|
33
|
-
end
|
32
|
+
record = model_class.new(attributes)
|
34
33
|
add(record)
|
35
34
|
end
|
36
35
|
|
@@ -42,30 +41,50 @@ module MotionPrime
|
|
42
41
|
# @params record [Prime::Model] model which will be added to collection.
|
43
42
|
# @return MotionPrime::Model model
|
44
43
|
def add(record)
|
44
|
+
set_inverse_relation_for(record)
|
45
45
|
self.bag << record
|
46
46
|
record
|
47
47
|
end
|
48
|
+
alias_method :<<, :add
|
48
49
|
|
49
50
|
# Return all association records.
|
50
51
|
#
|
51
52
|
# @example:
|
52
53
|
# project.users.all
|
53
|
-
#
|
54
|
+
#
|
55
|
+
# @return Array<MotionPrime::Model> association records
|
56
|
+
def all
|
57
|
+
data = bag.to_a
|
58
|
+
set_inverse_relation_for(data)
|
59
|
+
data
|
60
|
+
end
|
61
|
+
alias_method :to_a, :all
|
62
|
+
|
63
|
+
# Find association records.
|
64
|
+
#
|
65
|
+
# @example:
|
66
|
+
# project.users.find(age: 10)
|
54
67
|
#
|
55
68
|
# @params find_options [Hash] finder options.
|
56
69
|
# @params sort_options [Hash] sorting options.
|
57
70
|
# @return Array<MotionPrime::Model> association records
|
58
|
-
def
|
71
|
+
def find(find_options = {}, sort_options = nil)
|
72
|
+
raise "Use `filter` method when bag has not been saved yet" unless bag.store.present?
|
73
|
+
|
59
74
|
find_options = build_find_options(find_options)
|
60
75
|
sort_options = build_sort_options(sort_options)
|
61
76
|
|
62
|
-
data =
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
77
|
+
data = bag.find(find_options, sort_options)
|
78
|
+
set_inverse_relation_for(data)
|
79
|
+
data
|
80
|
+
end
|
81
|
+
|
82
|
+
def filter(find_options = {}, sort_options = nil)
|
83
|
+
find_options = build_find_options(find_options)
|
84
|
+
sort_options = build_sort_options(sort_options)
|
85
|
+
|
86
|
+
data = filter_array(bag.to_a, find_options, sort_options)
|
87
|
+
|
69
88
|
set_inverse_relation_for(data)
|
70
89
|
data
|
71
90
|
end
|
@@ -96,7 +115,13 @@ module MotionPrime
|
|
96
115
|
end
|
97
116
|
|
98
117
|
def build_sort_options(options)
|
99
|
-
options ||
|
118
|
+
options || begin
|
119
|
+
{sort: model_class.default_sort_options} if has_default_sort?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def has_default_sort?
|
124
|
+
model_class.default_sort_options.present?
|
100
125
|
end
|
101
126
|
|
102
127
|
def set_inverse_relation_for(models)
|
@@ -1,41 +1,39 @@
|
|
1
1
|
module MotionPrime
|
2
2
|
class Errors
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :info
|
4
|
+
attr_reader :changes
|
4
5
|
|
5
6
|
def initialize(model)
|
6
|
-
@
|
7
|
+
@info = MotionSupport::HashWithIndifferentAccess.new
|
8
|
+
@changes = MotionSupport::HashWithIndifferentAccess.new
|
7
9
|
@model = model
|
8
10
|
model.class.attributes.map(&:to_sym).each do |key|
|
9
11
|
initialize_for_key key
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize_for_key(key)
|
18
|
-
unique_key = unique_key(key)
|
19
|
-
|
20
|
-
return if @_unique_keys.include?(unique_key)
|
21
|
-
@_unique_keys << unique_key
|
22
|
-
instance_variable_set("@#{unique_key}", [])
|
23
|
-
self.class.send :attr_accessor, unique_key
|
15
|
+
def to_hash
|
16
|
+
@info
|
24
17
|
end
|
25
18
|
|
26
19
|
def get(key)
|
27
20
|
initialize_for_key(key)
|
28
|
-
|
21
|
+
to_hash[key]
|
29
22
|
end
|
30
23
|
|
31
|
-
def set(key, errors)
|
24
|
+
def set(key, errors, options = {})
|
32
25
|
initialize_for_key(key)
|
33
|
-
|
26
|
+
|
27
|
+
track_changed options do
|
28
|
+
to_hash[key] = Array.wrap(errors)
|
29
|
+
end
|
34
30
|
end
|
35
31
|
|
36
|
-
def add(key, error)
|
32
|
+
def add(key, error, options = {})
|
37
33
|
initialize_for_key(key)
|
38
|
-
|
34
|
+
track_changed do
|
35
|
+
to_hash[key] << error
|
36
|
+
end
|
39
37
|
end
|
40
38
|
|
41
39
|
def [](key)
|
@@ -46,22 +44,26 @@ module MotionPrime
|
|
46
44
|
set(key, errors)
|
47
45
|
end
|
48
46
|
|
49
|
-
def reset_for(key)
|
50
|
-
|
47
|
+
def reset_for(key, options = {})
|
48
|
+
track_changed options do
|
49
|
+
to_hash[key] = []
|
50
|
+
end
|
51
51
|
end
|
52
52
|
|
53
53
|
def reset
|
54
|
-
|
55
|
-
|
54
|
+
track_changed do
|
55
|
+
to_hash.keys.each do |key|
|
56
|
+
reset_for(key, silent: true)
|
57
|
+
end
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
59
61
|
def messages
|
60
|
-
|
62
|
+
to_hash.values.flatten
|
61
63
|
end
|
62
64
|
|
63
65
|
def blank?
|
64
|
-
messages.
|
66
|
+
messages.none?
|
65
67
|
end
|
66
68
|
|
67
69
|
def present?
|
@@ -71,5 +73,25 @@ module MotionPrime
|
|
71
73
|
def to_s
|
72
74
|
messages.join(';')
|
73
75
|
end
|
76
|
+
|
77
|
+
def track_changed(options = {})
|
78
|
+
return yield if options[:silent]
|
79
|
+
@changes = MotionSupport::HashWithIndifferentAccess.new
|
80
|
+
saved_info = to_hash.clone
|
81
|
+
willChangeValueForKey(:info)
|
82
|
+
yield
|
83
|
+
to_hash.each do |key, value|
|
84
|
+
@changes[key] = [value, saved_info[key]] unless value == saved_info[key]
|
85
|
+
end
|
86
|
+
didChangeValueForKey(:info)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def initialize_for_key(key)
|
91
|
+
key = key.to_sym
|
92
|
+
return if @info.has_key?(key)
|
93
|
+
|
94
|
+
to_hash[key] ||= []
|
95
|
+
end
|
74
96
|
end
|
75
97
|
end
|
@@ -24,6 +24,14 @@ module MotionPrime
|
|
24
24
|
@errors ||= Errors.new(self.weak_ref)
|
25
25
|
end
|
26
26
|
|
27
|
+
def set_errors(data)
|
28
|
+
errors.track_changed do
|
29
|
+
data.symbolize_keys.each do |key, error_messages|
|
30
|
+
errors.set(key, error_messages, silent: true) if error_messages.present?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
27
35
|
def dealloc
|
28
36
|
Prime.logger.dealloc_message :model, self
|
29
37
|
super
|
@@ -38,8 +38,10 @@ module MotionPrime
|
|
38
38
|
when 'alert' then MBAlertViewHUDTypeExclamationMark
|
39
39
|
else MBAlertViewHUDTypeCheckmark
|
40
40
|
end
|
41
|
-
|
42
|
-
|
41
|
+
|
42
|
+
unless time === false
|
43
|
+
MBHUDView.hudWithBody(message, type: hud_type, hidesAfter: time, show: true)
|
44
|
+
end
|
43
45
|
end
|
44
46
|
|
45
47
|
def show_spinner(message = nil)
|
@@ -58,8 +58,8 @@ module MotionPrime
|
|
58
58
|
face = UIButton.buttonWithType UIButtonTypeCustom
|
59
59
|
face.setImage(image, forState: UIControlStateNormal)
|
60
60
|
face.setTitle(title, forState: UIControlStateNormal)
|
61
|
-
face.bounds = CGRectMake(0, 0, 100, 60)
|
62
61
|
face.setContentHorizontalAlignment UIControlContentHorizontalAlignmentLeft
|
62
|
+
face.sizeToFit
|
63
63
|
face.on :touch do
|
64
64
|
args[:action].to_proc.call(self)
|
65
65
|
end
|