motional 0.1.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.
- data/.gitignore +20 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Guardfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +128 -0
- data/Rakefile +15 -0
- data/app/app_delegate.rb +14 -0
- data/lib/motional.rb +11 -0
- data/lib/motional/asset.rb +426 -0
- data/lib/motional/assets.rb +95 -0
- data/lib/motional/assets_filter.rb +33 -0
- data/lib/motional/core.rb +84 -0
- data/lib/motional/group.rb +245 -0
- data/lib/motional/library.rb +32 -0
- data/lib/motional/representation.rb +101 -0
- data/lib/motional/representations.rb +55 -0
- data/lib/motional/version.rb +3 -0
- data/motional.gemspec +24 -0
- data/resources/sample.jpg +0 -0
- data/resources/sample.mp4 +0 -0
- data/spec/motional/asset_spec.rb +274 -0
- data/spec/motional/assets_spec.rb +53 -0
- data/spec/motional/group_spec.rb +137 -0
- data/spec/motional/library_spec.rb +18 -0
- data/spec/motional/representation_spec.rb +57 -0
- data/spec/motional/representations_spec.rb +43 -0
- data/spec/spec_helper.rb +45 -0
- metadata +130 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
module MotionAL
|
4
|
+
#
|
5
|
+
# A collection of assets in the group.
|
6
|
+
# Assets has to belong to the group.
|
7
|
+
#
|
8
|
+
class Assets
|
9
|
+
attr_reader :group
|
10
|
+
|
11
|
+
# @param group [MotionAL::Group]
|
12
|
+
def initialize(group)
|
13
|
+
@group = group
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create an asset and add it to the group.
|
17
|
+
#
|
18
|
+
# @param source [CGImage, NSData, NSURL] CGImage and NSData for the photo, NSURL for the video.
|
19
|
+
# @param metadata [Hash] Metadata for the photo.
|
20
|
+
# @return [nil]
|
21
|
+
#
|
22
|
+
# @yield [asset, error]
|
23
|
+
# @yieldparam asset [MotionAL::Asset] A created asset.
|
24
|
+
# @yieldparam error [error]
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# group.assets.create(data, meta) do |asset, error|
|
28
|
+
# # asynchronous if a block given
|
29
|
+
# p asset.url.absoluteString
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# group.assets.create(data, meta)
|
33
|
+
def create(source, metadata = nil, &block)
|
34
|
+
Asset.create(source, metadata) do |asset, error|
|
35
|
+
if asset
|
36
|
+
block.call(asset, error)
|
37
|
+
self << asset
|
38
|
+
else
|
39
|
+
raise "Asset creation failed. #{error}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Enumrate assets in the group.
|
45
|
+
#
|
46
|
+
# @param options [Hash]
|
47
|
+
# @option options [Symbol] :filter :all(default), :photo or :video
|
48
|
+
# @option options [Symbol] :order :asc(default) or :desc
|
49
|
+
# @option options [NSIndexSet] :indexset
|
50
|
+
# @return [nil]
|
51
|
+
#
|
52
|
+
# @yield [asset, error]
|
53
|
+
# @yieldparam asset [MotionAL::Asset] A found asset.
|
54
|
+
# @yieldparam error [error]
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# group.assets.each do |asset, error|
|
58
|
+
# # asynchronous
|
59
|
+
# p asset.url.absoluteString
|
60
|
+
# end
|
61
|
+
def each(options = {}, &block)
|
62
|
+
raise "MotionAL::Assets.each does not support :group option. Use MotionAL::Asset.find_all to get other group assets." if options[:group]
|
63
|
+
|
64
|
+
options[:group] = @group
|
65
|
+
|
66
|
+
MotionAL::Asset.find_all(options) do |asset, error|
|
67
|
+
block.call(asset, error)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
alias_method :find_all, :each
|
71
|
+
|
72
|
+
# @param filter [Symbol] :all(default), :photo or :video
|
73
|
+
# @return [Fixnum] Count of assets in the group.
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
# group.assets.count
|
77
|
+
# group.assets.count(:photo)
|
78
|
+
def count(filter = :all)
|
79
|
+
AssetsFilter.set(@group, filter)
|
80
|
+
filtered_count = @group.al_asset_group.numberOfAssets
|
81
|
+
AssetsFilter.reset(@group)
|
82
|
+
|
83
|
+
filtered_count
|
84
|
+
end
|
85
|
+
|
86
|
+
# Add an asset to the group.
|
87
|
+
#
|
88
|
+
# @param asset [MotionAL::Asset]
|
89
|
+
def push(asset)
|
90
|
+
@group.add_asset(asset)
|
91
|
+
self
|
92
|
+
end
|
93
|
+
alias_method "<<", :push
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class MotionAL
|
4
|
+
# For filtering assets in the group by asset type.
|
5
|
+
class AssetsFilter
|
6
|
+
# :all means no filter.
|
7
|
+
DEFAULT_FILTER = :all
|
8
|
+
|
9
|
+
# Set filter.
|
10
|
+
# @param group [MotionAL::Group]
|
11
|
+
# @param filter [Symbol] :all, :photo or :video
|
12
|
+
# @note Set filter once, it is available permanently until calling `reset`.
|
13
|
+
def self.set(group, filter)
|
14
|
+
group.al_asset_group.setAssetsFilter(asset_filters[filter.to_sym])
|
15
|
+
end
|
16
|
+
|
17
|
+
# Reset filter.
|
18
|
+
# In other words set default filter.
|
19
|
+
# @param group [MotionAL::Group]
|
20
|
+
def self.reset(group)
|
21
|
+
group.al_asset_group.setAssetsFilter(asset_filters[DEFAULT_FILTER])
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash] Human readable keys and AssetLibrary Framework constant value.
|
25
|
+
def self.asset_filters
|
26
|
+
{
|
27
|
+
all: ALAssetsFilter.allAssets,
|
28
|
+
photo: ALAssetsFilter.allPhotos,
|
29
|
+
video: ALAssetsFilter.allVideos,
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
module MotionAL
|
4
|
+
class << self
|
5
|
+
def library
|
6
|
+
@library ||= Library.instance
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [Hash] readable key and objective-c constant value
|
10
|
+
def asset_group_types
|
11
|
+
{
|
12
|
+
:library => ALAssetsGroupLibrary,
|
13
|
+
:album => ALAssetsGroupAlbum,
|
14
|
+
:event => ALAssetsGroupEvent,
|
15
|
+
:faces => ALAssetsGroupFaces,
|
16
|
+
:saved_photos => ALAssetsGroupSavedPhotos,
|
17
|
+
:photo_stream => ALAssetsGroupPhotoStream,
|
18
|
+
:all => ALAssetsGroupAll
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Hash] readable key and objective-c constant value
|
23
|
+
def asset_types
|
24
|
+
{
|
25
|
+
:photo => ALAssetTypePhoto,
|
26
|
+
:video => ALAssetTypeVideo,
|
27
|
+
:unknown => ALAssetTypeUnknown
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Hash] readable key and objective-c constant value
|
32
|
+
def asset_orientations
|
33
|
+
{
|
34
|
+
:up => ALAssetOrientationUp,
|
35
|
+
:down => ALAssetOrientationDown,
|
36
|
+
:left => ALAssetOrientationLeft,
|
37
|
+
:right => ALAssetOrientationRight,
|
38
|
+
:up_mirrored => ALAssetOrientationUpMirrored,
|
39
|
+
:down_mirrored => ALAssetOrientationDownMirrored,
|
40
|
+
:left_mirrored => ALAssetOrientationLeftMirrored,
|
41
|
+
:right_mirrored => ALAssetOrientationRightMirrored
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Hash] readable key and objective-c constant value
|
46
|
+
def authorization_statuses
|
47
|
+
{
|
48
|
+
:not_determined => ALAuthorizationStatusNotDetermined,
|
49
|
+
:restricted => ALAuthorizationStatusRestricted,
|
50
|
+
:denied => ALAuthorizationStatusDenied,
|
51
|
+
:authorized => ALAuthorizationStatusAuthorized
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Hash] readable key and objective-c constant value
|
56
|
+
def notification_keys
|
57
|
+
{
|
58
|
+
:updated_assets_key => ALAssetLibraryUpdatedAssetsKey,
|
59
|
+
:inserted_asset_groups_key => ALAssetLibraryInsertedAssetGroupsKey,
|
60
|
+
:updated_asset_groups_key => ALAssetLibraryUpdatedAssetGroupsKey,
|
61
|
+
:deleted_asset_groups_key => ALAssetLibraryDeletedAssetGroupsKey
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Hash] readable key and objective-c constant value
|
66
|
+
def enumeration_options
|
67
|
+
{
|
68
|
+
:asc => NSEnumerationConcurrent,
|
69
|
+
:desc => NSEnumerationReverse
|
70
|
+
}
|
71
|
+
end
|
72
|
+
alias_method :enum_orders, :enumeration_options
|
73
|
+
|
74
|
+
# @return [Boolean] False means that your app cannot access the asset library.
|
75
|
+
def authorized?
|
76
|
+
ALAssetsLibrary.authorizationStatus == authorization_statuses[:authorized]
|
77
|
+
end
|
78
|
+
|
79
|
+
# A simple wrapper of ALAssetsLibrary.disableSharedPhotoStreamsSupport
|
80
|
+
def disable_shared_photo_streams_support
|
81
|
+
ALAssetsLibrary.disableSharedPhotoStreamsSupport
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
module MotionAL
|
4
|
+
#
|
5
|
+
# A wrapper of ALAssetGroup class.
|
6
|
+
#
|
7
|
+
# An ALAssetsGroup object represents an ordered set of the assets managed by the Photos application. The order of the elements is the same as the user sees in the Photos application. An asset can belong to multiple assets groups.
|
8
|
+
# Assets groups themselves are synced via iTunes, created to hold the user’s saved photos or created during camera import. You cannot directly modify the groups using ALAssetsGroup. You can indirectly modify the Saved Photos group by saving images or videos into it using the ALAssetsLibrary class.
|
9
|
+
#
|
10
|
+
# And added some convinience methods.
|
11
|
+
#
|
12
|
+
class Group
|
13
|
+
# An instance of ALAssetGroup.
|
14
|
+
attr_reader :al_asset_group
|
15
|
+
|
16
|
+
# @param al_asset_group [ALAssetsGroup]
|
17
|
+
def initialize(al_asset_group)
|
18
|
+
@al_asset_group = al_asset_group
|
19
|
+
end
|
20
|
+
|
21
|
+
# Create a group.
|
22
|
+
# A group should not be created if a specified name already exists.
|
23
|
+
#
|
24
|
+
# @param group_name [String]
|
25
|
+
# @return [nil]
|
26
|
+
#
|
27
|
+
# @yield [group, error]
|
28
|
+
# @yieldparam group [MotionAL::Group] A created group.
|
29
|
+
# @yieldparam error [error]
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# MotionAL::Group.create('MyAlbum') do |group, error|
|
33
|
+
# # asynchronous if a block given
|
34
|
+
# p group.name
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# MotionAL::Group.create('MyAlbum')
|
38
|
+
def self.create(group_name, &block)
|
39
|
+
self.origin_create(group_name, block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Find a group by a specified group_url.
|
43
|
+
#
|
44
|
+
# @param group_url [NSURL, String]
|
45
|
+
# @return [nil]
|
46
|
+
#
|
47
|
+
# @yield [group, error]
|
48
|
+
# @yieldparam group [MotionAL::Group] A found group.
|
49
|
+
# @yieldparam error [error]
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# MotionAL::group.find_by_url(url) do |group, error|
|
53
|
+
# # asynchronous
|
54
|
+
# p group.name
|
55
|
+
# end
|
56
|
+
def self.find_by_url(group_url, &block)
|
57
|
+
url = group_url.is_a?(String) ? NSURL.alloc.initWithString(group_url) : group_url
|
58
|
+
origin_find_by_url(url, block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Find a group by a specified group name.
|
62
|
+
#
|
63
|
+
# @param group_name [String]
|
64
|
+
# @return [nil]
|
65
|
+
#
|
66
|
+
# @yield [group, error]
|
67
|
+
# @yieldparam group [MotionAL::Group] A found group.
|
68
|
+
# @yieldparam error [error]
|
69
|
+
#
|
70
|
+
# @note It is recommended to use find_by_url instead of this. Because a group could be renamed.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# MotionAL::Group.find_by_name('MyAlbum') do |group, error|
|
74
|
+
# p group.name
|
75
|
+
# end
|
76
|
+
def self.find_by_name(group_name, &block)
|
77
|
+
group_name = /^#{group_name}$/ if group_name.kind_of? String
|
78
|
+
find_all do |group, error|
|
79
|
+
block.call(group, error) if group.name =~ group_name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Find the Camera Roll(built-in default group)
|
84
|
+
#
|
85
|
+
# @return [nil]
|
86
|
+
#
|
87
|
+
# @yield [group, error]
|
88
|
+
# @yieldparam group [MotionAL::Group] 'Camera Roll' or 'Saved Photos'
|
89
|
+
# @yieldparam error [error]
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# MotionAL::Group.find_camera_roll do |group, error|
|
93
|
+
# p group.name #=> 'Camera Roll' or 'Saved Photos'
|
94
|
+
# end
|
95
|
+
def self.find_camera_roll(&block)
|
96
|
+
find_by_name(/Camera Roll|Saved Photos/) {|group, error| block.call(group, error) }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Find the Photo Library(synced from iTunes)
|
100
|
+
#
|
101
|
+
# @return [nil]
|
102
|
+
#
|
103
|
+
# @yield [group, error]
|
104
|
+
# @yieldparam group [MotionAL::Group] 'Photo Library'
|
105
|
+
# @yieldparam error [error]
|
106
|
+
#
|
107
|
+
# @example
|
108
|
+
# MotionAL::Group.find_photo_library do |group, error|
|
109
|
+
# p group.name #=> 'Photo Library'
|
110
|
+
# end
|
111
|
+
def self.find_photo_library(&block)
|
112
|
+
find_all({group_type: :library}) { |group, error| block.call(group, error) }
|
113
|
+
end
|
114
|
+
|
115
|
+
# Find and enumerate all groups in the AssetLibrary.
|
116
|
+
#
|
117
|
+
# @param options [Hash]
|
118
|
+
# @option options :group_type [Symbol] An asset group type. default: :all.
|
119
|
+
# @return [nil]
|
120
|
+
#
|
121
|
+
# @yield [group, error]
|
122
|
+
# @yieldparam group [MotionAL::Group] A found group.
|
123
|
+
# @yieldparam error [error]
|
124
|
+
#
|
125
|
+
# @see MotionAL.asset_group_types
|
126
|
+
# @note group_type :all includes all groups except 'Photo Library'
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# MotionAL::group.find_all do |group, error|
|
130
|
+
# # asynchronous
|
131
|
+
# p group.name
|
132
|
+
# end
|
133
|
+
def self.find_all(options = {}, &block)
|
134
|
+
origin_find_all(options, block)
|
135
|
+
end
|
136
|
+
class << self
|
137
|
+
alias_method :each, :find_all
|
138
|
+
end
|
139
|
+
|
140
|
+
# The collection of assets in the group.
|
141
|
+
# @return [MotionAL::Assets] An instance of MotionAL::Assets belongs to the group.
|
142
|
+
def assets
|
143
|
+
@assets ||= Assets.new(self)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return true if your app has write access for the group.
|
147
|
+
# In other words true means your app can add assets to the group.
|
148
|
+
#
|
149
|
+
# @return [Boolean]
|
150
|
+
def editable?
|
151
|
+
@al_asset_group.editable?
|
152
|
+
end
|
153
|
+
|
154
|
+
# @return [CGImageRef] The group's poster image.
|
155
|
+
def poster_image
|
156
|
+
@al_asset_group.posterImage
|
157
|
+
end
|
158
|
+
|
159
|
+
# Add an asset to the group.
|
160
|
+
#
|
161
|
+
# @param asset [MotionAL::Asset]
|
162
|
+
# @return [Boolean] true if asset was added successfully, otherwise false
|
163
|
+
#
|
164
|
+
# @note cannot remove ALAsset from ALAssetGroup by yor app
|
165
|
+
def add_asset(asset)
|
166
|
+
@al_asset_group.addAsset(asset.al_asset)
|
167
|
+
end
|
168
|
+
|
169
|
+
# wrapper of valueForProperty
|
170
|
+
class << self
|
171
|
+
private
|
172
|
+
# wrapper for valueForProperty
|
173
|
+
# @!macro [attach] make_wrapper
|
174
|
+
# The gruop's $1
|
175
|
+
# @method $1
|
176
|
+
# @return [$3] The value for the property $2.
|
177
|
+
# @return [nil] The property is empty.
|
178
|
+
def make_wrapper_for_property(method_name, property_name, type_of_return)
|
179
|
+
|
180
|
+
define_method(method_name) do
|
181
|
+
@al_asset_group.valueForProperty(property_name)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
make_wrapper_for_property(:name, ALAssetsGroupPropertyName, "String")
|
186
|
+
make_wrapper_for_property(:persistent_id, ALAssetsGroupPropertyPersistentID, "String")
|
187
|
+
make_wrapper_for_property(:url, ALAssetsGroupPropertyURL, "NSURL")
|
188
|
+
|
189
|
+
# The type of the group.
|
190
|
+
#
|
191
|
+
# @return [Symbol] :library, :album, :event, :faces, :photos, :photo_stream or :all
|
192
|
+
def asset_group_type
|
193
|
+
MotionAL.asset_group_types.key(@al_asset_group.valueForProperty(ALAssetsGroupPropertyType))
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
def self.origin_create(group_name, callback = nil)
|
198
|
+
MotionAL.library.al_asset_library.addAssetsGroupAlbumWithName(
|
199
|
+
group_name,
|
200
|
+
resultBlock: lambda { |al_asset_group|
|
201
|
+
if !al_asset_group.nil?
|
202
|
+
created_group = Group.new(al_asset_group)
|
203
|
+
end
|
204
|
+
|
205
|
+
callback.call(created_group, nil) if callback
|
206
|
+
},
|
207
|
+
failureBlock: lambda { |error|
|
208
|
+
callback.call(nil, error) if callback
|
209
|
+
}
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.origin_find_by_url(group_url, callback = nil)
|
214
|
+
MotionAL.library.al_asset_library.groupForURL(
|
215
|
+
group_url,
|
216
|
+
resultBlock: lambda { |al_asset_group|
|
217
|
+
if !al_asset_group.nil?
|
218
|
+
found_group = Group.new(al_asset_group)
|
219
|
+
end
|
220
|
+
|
221
|
+
callback.call(found_group, nil)
|
222
|
+
},
|
223
|
+
failureBlock: lambda { |error|
|
224
|
+
callback.call(nil, error)
|
225
|
+
}
|
226
|
+
)
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.origin_find_all(options, callback = nil)
|
230
|
+
options[:group_type] ||= :all
|
231
|
+
MotionAL.library.al_asset_library.enumerateGroupsWithTypes(
|
232
|
+
MotionAL.asset_group_types[options[:group_type].to_sym],
|
233
|
+
usingBlock: lambda { |al_asset_group, stop|
|
234
|
+
if !al_asset_group.nil?
|
235
|
+
group = Group.new(al_asset_group)
|
236
|
+
callback.call(group, nil) if callback
|
237
|
+
end
|
238
|
+
},
|
239
|
+
failureBlock: lambda { |error|
|
240
|
+
callback.call(nil, error) if callback
|
241
|
+
}
|
242
|
+
)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|