motional 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .repl_history
19
+ build
20
+ .DS_Store
@@ -0,0 +1,5 @@
1
+ language: objective-c
2
+ before_install: rvm use ruby-1.9.3-p392
3
+ script:
4
+ - bundle exec rake spec files=spec_helper
5
+ - bundle exec rake spec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in motional.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'motion' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+
7
+ # RubyMotion App example
8
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
10
+
11
+ # RubyMotion gem example
12
+ watch(%r{^lib/[^/]+/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
13
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 akahige
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,128 @@
1
+ # MotionAL
2
+
3
+ AssetLibrary framework wrapper for RubyMotion.
4
+
5
+ *This gem is a beta quality.*
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'motional'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Setup
18
+
19
+ Add this code to your application's Rakefile.
20
+
21
+ require 'bundler'
22
+ Bundler.require(:development)
23
+
24
+ ## Overview
25
+
26
+ ### Library
27
+
28
+ # singleton for the lifetime.
29
+ library = MotionAL.library # should not call `Motional::Library.new` directly.
30
+
31
+ library.groups # An alias of MotionAL::Group
32
+ library.groups.each do |group|
33
+ # asynchronous
34
+ # enumerate all groups except Photo Library
35
+ end
36
+
37
+ # open Camera Roll
38
+ library.groups.find_camera_roll do |group|
39
+ # asynchronous
40
+ group.assets.each do |asset|
41
+ # enumerate all assets in the camera roll
42
+ end
43
+ end
44
+
45
+ # open Photo Library synced from itunes
46
+ library.groups.find_photo_library {|group| ... # asynchronous }
47
+
48
+ library.al_asset_library # An instance of ALAssetLibrary
49
+
50
+ MotionAL.authorized? # check permission to access Asset Library. see Settings > Privacy > Photos
51
+
52
+ ### Group
53
+
54
+ MotionAL::Group.create('MyAppAlbum') do |group|
55
+ # asynchronous
56
+ group.name #=> 'MyAppAlbum'
57
+ group.url.absoluteString # save this to permanent strage
58
+ end
59
+
60
+ MotionAL::Group.find_by_url(saved_url_absolute_string) do |group|
61
+ # accept NSURL or String
62
+ # asynchronous
63
+ p group.name #=> 'MyAppAlbum'
64
+ end
65
+
66
+ group.assets # An instance of MotionAL::Assets
67
+ group.assets.each {|asset| ... # asynchronous }
68
+ group.assets.create(image_data, metadata) {|asset| ... # asynchronous } # create asset and add to the group
69
+ group.assets << some_asset # an asset add to the group.
70
+
71
+ group.al_asset_group # An instance of ALAssetGroup
72
+
73
+ ### Asset
74
+
75
+ MotionAL::Asset.create(image_data, metadata) do |asset|
76
+ asset.url.absoluteString # save this to permanent strage
77
+ end
78
+
79
+ MotionAL::Asset.find_by_url(saved_url_absolute_string) {|asset| ... # asynchronous }
80
+
81
+ asset.representations # An instance of Representations
82
+ asset.representations.each {|rep| ... # not asynchronous }
83
+
84
+ asset.default_representation # An instance of MotionAL::Representation for default representation.
85
+
86
+ # properties
87
+ asset.location
88
+ asset.media_type # :photo or :video
89
+ MotionAL.asset_types(asset.media_type) # to get objective-c constant value
90
+ asset.orientation # :up, :down, :left...
91
+ MotionAL.asset_orientations(asset.orientation) # to get objective-c constant value
92
+
93
+ # default representation properties
94
+ asset.filename
95
+ asset.metadata
96
+ asset.full_resolution_image
97
+ asset.full_screen_image
98
+
99
+ asset.al_asset # An instance of ALAsset
100
+
101
+ ### Representation
102
+
103
+ # properties
104
+ rep.filename
105
+ rep.metadata
106
+ rep.full_resolution_image
107
+ rep.full_screen_image
108
+
109
+ rep.al_asset_representation # An instance of ALAssetRepresentation
110
+
111
+ ## How to run specs
112
+
113
+ ### Preparing test data
114
+
115
+ rake spec files=spec_helper
116
+
117
+ ### Run specs
118
+
119
+ rake spec
120
+
121
+ ## Contributing
122
+
123
+ 1. Fork it
124
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
125
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
126
+ 4. Check all specs passed on your simurator (`rake spec`)
127
+ 5. Push to the branch (`git push origin my-new-feature`)
128
+ 6. Create new Pull Request
@@ -0,0 +1,15 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ $:.unshift("/Library/RubyMotion/lib")
4
+ $:.unshift("#{File.dirname(__FILE__)}/lib")
5
+ require 'motion/project/template/ios'
6
+ require 'bundler'
7
+
8
+ Bundler.require(:development)
9
+
10
+ require 'motional'
11
+
12
+ Motion::Project::App.setup do |app|
13
+ app.name = 'MotionAL'
14
+ app.redgreen_style = :full # :focused, :full
15
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ # for testing
4
+ class AppDelegate
5
+ def application(application, didFinishLaunchingWithOptions: launchOptions)
6
+ true
7
+ end
8
+
9
+ def test_image
10
+ @path = "#{NSBundle.mainBundle.resourcePath}/sample.jpg"
11
+ @url = NSURL.fileURLWithPath(@path)
12
+ cg_image_source = CGImageSourceCreateWithURL(@url, nil);
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ # -*- encoding : utf-8 -*-
2
+ unless defined?(Motion::Project::Config)
3
+ raise "This file must be required within a RubyMotion project Rakefile."
4
+ end
5
+
6
+ Motion::Project::App.setup do |app|
7
+ app.frameworks += ['AssetsLibrary', 'ImageIO']
8
+ Dir.glob(File.join(File.dirname(__FILE__), 'motional/*rb')).each do |file|
9
+ app.files.unshift(file)
10
+ end
11
+ end
@@ -0,0 +1,426 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module MotionAL
4
+ #
5
+ # A wrapper of ALAsset class.
6
+ #
7
+ # An ALAsset object represents a photo or a video managed by the Photo application.
8
+ # Assets can have multiple representations, for example a photo which was captured in RAW and JPG. Different representations of the same asset may have different dimensions.
9
+ #
10
+ # And added some convinience methods.
11
+ #
12
+ class Asset
13
+ # An instance of ALAsset.
14
+ attr_reader :al_asset
15
+
16
+ # @param al_asset [ALAsset]
17
+ def initialize(al_asset)
18
+ @al_asset = al_asset
19
+ end
20
+
21
+ # @return [MotionAL::Representations] The collection of representations in the asset.
22
+ def representations
23
+ @representations ||= Representations.new(self)
24
+ end
25
+
26
+ # Create an asset.
27
+ #
28
+ # @param source [CGImage, NSData, NSURL] CGImage and NSData for the photo, NSURL for the video.
29
+ # @param metadata [Hash] Metadata for the photo.
30
+ # @return [nil]
31
+ #
32
+ # @yield [asset, error]
33
+ # @yieldparam asset [MotionAL::Asset] A created asset.
34
+ # @yieldparam error [error]
35
+ #
36
+ # @note use `MotionAL::Asset.video_compatible?(video_path_url)` before creating video.
37
+ #
38
+ # @example
39
+ # MotionAL::Asset.create(data, meta) do |asset, error|
40
+ # # asynchronous if a block given
41
+ # p asset.url.absoluteString
42
+ # end
43
+ #
44
+ # MotionAL::Asset.create(data, meta)
45
+ #
46
+ # if MotionAL::Asset.video_compatible?(video_path_url)
47
+ # MotionAL::Asset.create(data, meta)
48
+ # else
49
+ # p "This video contained incompatible data."
50
+ # end
51
+ def self.create(source, metadata = nil, &block)
52
+ if source.kind_of?(NSData)
53
+ self.create_by_image_data(source, metadata, block)
54
+ elsif source.kind_of?(NSURL)
55
+ self.create_by_video_path(source, block)
56
+ else
57
+ self.create_by_cg_image(source, metadata, block)
58
+ end
59
+ end
60
+
61
+ # Find an asset by a specified asset_url.
62
+ #
63
+ # @param asset_url [NSURL]
64
+ # @return [nil]
65
+ #
66
+ # @yield [asset, error]
67
+ # @yieldparam asset [MotionAL::Asset] A found asset.
68
+ # @yieldparam error [error]
69
+ #
70
+ # @example
71
+ # MotionAL::Asset.find_by_url(url) do |asset, error|
72
+ # # asynchronous if a block given
73
+ # p asset.url.absoluteString
74
+ # end
75
+ def self.find_by_url(asset_url, &block)
76
+ url = asset_url.is_a?(String) ? NSURL.alloc.initWithString(asset_url) : asset_url
77
+ self.origin_find_by_url(url, block)
78
+ end
79
+
80
+ # Find and enumerate assets by options.
81
+ #
82
+ # @param options [Hash]
83
+ # @option options [MotionAL::Group] :group Default is the Camera Roll.
84
+ # @option options [Symbol] :filter :all, :photo or :video
85
+ # @option options [Symbol] :order :asc or :desc
86
+ # @option options [NSIndexSet] :indexset
87
+ # @return [nil]
88
+ #
89
+ # @yield [asset, error]
90
+ # @yieldparam asset [MotionAL::Asset] A found asset.
91
+ # @yieldparam error [error]
92
+ #
93
+ # @example
94
+ # MotionAL::Asset.find_all do |asset, error|
95
+ # # asynchronous if a block given
96
+ # p asset.url.absoluteString
97
+ # end
98
+ #
99
+ # MotionAL::find_by_name('MyAppAlbum') do |group|
100
+ # MotionAL::Asset.find_all(group: group, order: :desc, filter: :photo) do |asset|
101
+ # p asset.url.absoluteString
102
+ # end
103
+ # end
104
+ #
105
+ # indexset = NSMutableIndexSet.indexSetWithIndexesInRange(1..3)
106
+ # MotionAL::Asset.find_all(indexset: indexset, order: :desc) do |asset|
107
+ # p asset.url.absoluteString
108
+ # end
109
+ def self.find_all(options = {}, &block)
110
+ self.origin_find_all(options, block)
111
+ end
112
+ class << self
113
+ alias_method :each, :find_all
114
+ end
115
+
116
+ # @return [Boolean] false means ALAssetLibrary cannot treat the video file.
117
+ def self.video_compatible?(video_path_url)
118
+ MotionAL.library.al_asset_library.videoAtPathIsCompatibleWithSavedPhotosAlbum(video_path_url)
119
+ end
120
+
121
+
122
+ # @return [CGImageRef] Returns a thumbnail of the asset.
123
+ def thumbnail
124
+ self.al_asset.thumbnail
125
+ end
126
+
127
+ # @return [CGImageRef] Returns an aspect ratio thumbnail of the asset.
128
+ def aspect_ratio_thumbnail
129
+ self.al_asset.aspectRatioThumbnail
130
+ end
131
+
132
+ # Return true if the app haves write access for the asset.
133
+ # In other words true means the app can call `#update` for the asset.
134
+ #
135
+ # @return [Boolean]
136
+ def editable?
137
+ @al_asset.editable?
138
+ end
139
+
140
+ # The original version of the asset.
141
+ #
142
+ # @return [MotionAL::Asset]
143
+ # @return [nil] The asset has no original asset.
144
+ #
145
+ # @note The original asset was set when the asset was created by `#save_new`
146
+ def original_asset
147
+ original_al_asset = @al_asset.originalAsset
148
+ Asset.new(original_al_asset) if original_al_asset
149
+ end
150
+
151
+ # @return [MotionAL::Representation] The default representation of the asset. A representation is an actual file.
152
+ def default_representation
153
+ @default_representation ||= Representation.new(@asset, @al_asset.defaultRepresentation)
154
+ end
155
+ alias_method :rep, :default_representation
156
+ alias_method :file, :default_representation
157
+ alias_method :representation, :default_representation
158
+
159
+ # wrapper for valueForProperty
160
+ class << self
161
+ private
162
+ # @!macro [attach] make_wrapper
163
+ # The asset's $1
164
+ # @method $1
165
+ # @return [$3] The value for the property $2.
166
+ # @return [nil] The property is empty.
167
+ def make_wrapper_for_property(method_name, property_name, type_of_return)
168
+ define_method(method_name) do
169
+ @al_asset.valueForProperty(property_name)
170
+ end
171
+ end
172
+ end
173
+ make_wrapper_for_property(:location, ALAssetPropertyLocation, "CLLocation")
174
+ make_wrapper_for_property(:duration, ALAssetPropertyDuration, "Float")
175
+ make_wrapper_for_property(:date, ALAssetPropertyDate, "Time")
176
+ make_wrapper_for_property(:url, ALAssetPropertyAssetURL, "NSURL")
177
+ make_wrapper_for_property(:representation_utis, ALAssetPropertyRepresentations, "Array")
178
+ make_wrapper_for_property(:representation_urls, ALAssetPropertyURLs, "Array")
179
+
180
+ alias_method :reps, :representations
181
+ alias_method :files, :representations
182
+
183
+ # The type of the asset.
184
+ #
185
+ # @return [Symbol] :photo or :video
186
+ def asset_type
187
+ MotionAL.asset_types.key(@al_asset.valueForProperty(ALAssetPropertyType))
188
+ end
189
+
190
+ # The orientation of the asset.
191
+ #
192
+ # @return [Symbol] :up, :down :left, :right, :up_mirrored, :down_mirrored, :left_mirrored or :right_mirrored
193
+ def orientation
194
+ MotionAL.asset_orientations.key(@al_asset.valueForProperty(ALAssetPropertyOrientation))
195
+ end
196
+
197
+ class << self
198
+ private
199
+ # wrapper for representation method
200
+ # @!macro [attach] make_wrapper
201
+ # The default representation's $1
202
+ # @method $1
203
+ # @return [$2] The same as the default representation's $1
204
+ # @return [nil] The property is empty.
205
+ def make_wrapper_for_representation_method(method_name, type_of_return)
206
+ define_method(method_name) do
207
+ default_representation.send(method_name)
208
+ end
209
+ end
210
+ end
211
+ make_wrapper_for_representation_method(:full_resolution_image, "CGImageRef")
212
+ make_wrapper_for_representation_method(:full_screen_image, "CGImageRef")
213
+ make_wrapper_for_representation_method(:scale, "Float")
214
+ make_wrapper_for_representation_method(:data, "NSConcreteData")
215
+ make_wrapper_for_representation_method(:cg_image, "CGImageRef")
216
+ make_wrapper_for_representation_method(:dimensions, "CGSize")
217
+ make_wrapper_for_representation_method(:filename, "String")
218
+ make_wrapper_for_representation_method(:size, "Fixnum")
219
+ make_wrapper_for_representation_method(:metadata, "Hash")
220
+
221
+ # Create a new asset forked by the asset.
222
+ #
223
+ # @param source [NSData, NSURL] NSData for the photo, NSURL for the video.
224
+ # @param metadata [Hash] Metadata for the photo.
225
+ # @return [nil]
226
+ #
227
+ # @yield [asset, error]
228
+ # @yieldparam asset [MotionAL::Asset] A created asset.
229
+ # @yieldparam error [error]
230
+ #
231
+ # @note use `MotionAL::Asset.video_compatible?(video_path_url)` before creating video.
232
+ #
233
+ # @example
234
+ # asset_a.save_new(imagedata, meta) do |asset, error| do
235
+ # # asynchronous if a block given
236
+ # p asset.url.absoluteString
237
+ # p asset.original_asset.url.absoluteString
238
+ # end
239
+ #
240
+ # asset_a.create(imagedata, meta)
241
+ def save_new(source, metadata = nil, &block)
242
+ origin_save_new(source, metadata, block)
243
+ end
244
+
245
+ # Update the asset.
246
+ # In other words replacing the asset's representation.
247
+ #
248
+ # @param source [NSData, NSURL] NSData for the photo, NSURL for the video.
249
+ # @param metadata [Hash] Metadata for the photo.
250
+ # @return [nil]
251
+ #
252
+ # @yield [asset, error]
253
+ # @yieldparam asset [MotionAL::Asset] A updated asset.
254
+ # @yieldparam error [error]
255
+ #
256
+ # @note use `MotionAL::Asset.video_compatible?(video_path_url)` before updating video.
257
+ #
258
+ # @example
259
+ # asset_a.update(imagedata, meta) do |asset, error| do
260
+ # # asynchronous if a block given
261
+ # p asset.url.absoluteString
262
+ # end
263
+ #
264
+ # asset_a.update(imagedata, meta)
265
+ def update(source, metadata = nil, &block)
266
+ origin_update(source, metadata, block)
267
+ end
268
+
269
+ private
270
+ def self.create_by_cg_image(cg_image, meta, callback = nil)
271
+ if self.only_orientation?(meta)
272
+ MotionAL.library.al_asset_library.writeImageToSavedPhotosAlbum(
273
+ cg_image,
274
+ orientation: MotionAL.asset_orientations[meta[:orientation]],
275
+ completionBlock: self.completion_block_for_create(callback)
276
+ )
277
+ else
278
+ MotionAL.library.al_asset_library.writeImageToSavedPhotosAlbum(
279
+ cg_image,
280
+ metadata: meta,
281
+ completionBlock: self.completion_block_for_create(callback)
282
+ )
283
+ end
284
+ end
285
+
286
+ def self.only_orientation?(meta)
287
+ meta && meta.size == 1 && meta[:orientation]
288
+ end
289
+
290
+ def self.origin_find_by_url(asset_url, callback = nil)
291
+
292
+ MotionAL.library.al_asset_library.assetForURL(
293
+ asset_url,
294
+ resultBlock: lambda {|al_asset|
295
+ if al_asset
296
+ found_asset = self.new(al_asset)
297
+ callback.call(found_asset, nil) if callback
298
+ end
299
+ },
300
+ failureBlock: lambda {|error|
301
+ callback.call(nil, error) if callback
302
+ }
303
+ )
304
+ end
305
+
306
+ def self.origin_find_all(options = {}, callback = nil)
307
+ if options[:group]
308
+ group_name = options[:group].name
309
+ else
310
+ group_name = /Camera Roll|Saved Photos/
311
+ end
312
+ options[:order] ||= :asc
313
+
314
+ MotionAL::Group.find_by_name(group_name) do |group, error|
315
+ order = MotionAL.enum_orders[options[:order]]
316
+ AssetsFilter.set(group, options[:filter]) if options[:filter]
317
+ if options[:indexset]
318
+ group.al_asset_group.enumerateAssetsAtIndexes(
319
+ options[:indexset],
320
+ options: order,
321
+ usingBlock: using_block_for_all(options, callback)
322
+ )
323
+ elsif options[:order] == :desc
324
+ group.al_asset_group.enumerateAssetsWithOptions(order, usingBlock: using_block_for_all(options, callback))
325
+ else
326
+ group.al_asset_group.enumerateAssetsUsingBlock(using_block_for_all(options, callback))
327
+ end
328
+ AssetsFilter.reset(group) if options[:filter]
329
+ end
330
+ end
331
+
332
+ def self.using_block_for_all(options, callback = nil)
333
+ Proc.new do |al_asset, index, stop|
334
+ if !al_asset.nil?
335
+ asset = Asset.new(al_asset)
336
+ callback.call(asset, nil) if callback
337
+ end
338
+ end
339
+ end
340
+
341
+ def self.create_by_image_data(image_data, meta, callback = nil)
342
+ MotionAL.library.al_asset_library.writeImageDataToSavedPhotosAlbum(
343
+ image_data,
344
+ metadata: meta,
345
+ completionBlock: self.completion_block_for_create(callback)
346
+ )
347
+ end
348
+
349
+ def self.create_by_video_path(video_path_url, callback = nil)
350
+ MotionAL.library.al_asset_library.writeVideoAtPathToSavedPhotosAlbum(
351
+ video_path_url,
352
+ completionBlock: self.completion_block_for_create(callback)
353
+ )
354
+ end
355
+
356
+ def self.completion_block_for_create(callback = nil)
357
+ Proc.new do |asset_url, error|
358
+ MotionAL::Asset.find_by_url(asset_url) do |asset, error|
359
+ callback.call(asset, error) if callback
360
+ end
361
+ end
362
+ end
363
+
364
+ def completion_block_for_save_and_update(callback = nil)
365
+ Proc.new do |asset_url, error|
366
+ MotionAL::Asset.find_by_url(asset_url) do |asset, error|
367
+ @created_asset = asset
368
+ callback.call(@created_asset, error) if callback
369
+ end
370
+ end
371
+ end
372
+
373
+ def origin_save_new(source, metadata, callback = nil)
374
+ case self.asset_type
375
+ when :photo
376
+ save_new_by_image_data(source, metadata) {|asset, error| callback.call(asset, error) if callback }
377
+ when :video
378
+ save_new_by_video_path(source) {|asset, error| callback.call(asset, error) if callback }
379
+ else
380
+ raise "ALAssetTypeUnknown"
381
+ end
382
+ end
383
+
384
+ def save_new_by_image_data(image_data, metadata, &block)
385
+ @al_asset.writeModifiedImageDataToSavedPhotosAlbum(
386
+ image_data,
387
+ metadata: metadata,
388
+ completionBlock: completion_block_for_save_and_update(block)
389
+ )
390
+ end
391
+
392
+ def save_new_by_video_path(video_path, &block)
393
+ @al_asset.writeModifiedVideoAtPathToSavedPhotosAlbum(
394
+ video_path,
395
+ completionBlock: completion_block_for_save_and_update(block)
396
+ )
397
+ end
398
+
399
+ def origin_update(source, metadata = nil, callback = nil)
400
+ case self.asset_type
401
+ when :photo
402
+ update_by_image_data(source, metadata) {|asset, error| callback.call(asset, error) if callback }
403
+ when :video
404
+ update_by_video_path(source) {|asset, error| callback.call(asset, error) if callback}
405
+ else
406
+ raise "ALAssetTypeUnknown"
407
+ end
408
+ end
409
+
410
+ def update_by_image_data(image_data, metadata, &block)
411
+ @al_asset.setImageData(
412
+ image_data,
413
+ metadata: metadata,
414
+ completionBlock: completion_block_for_save_and_update(block)
415
+ )
416
+ end
417
+
418
+ def update_by_video_path(video_path, &block)
419
+ @al_asset.setVideoAtPath(
420
+ video_path,
421
+ completionBlock: completion_block_for_save_and_update(block)
422
+ )
423
+ end
424
+
425
+ end
426
+ end