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.
@@ -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