expo-media-library 18.1.2-canary-20250912-b5ce2a8 → 18.3.0-canary-20250919-7a31b96
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.
- package/CHANGELOG.md +13 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/medialibrary/next/MediaLibraryNextModule.kt +73 -0
- package/android/src/main/java/expo/modules/medialibrary/next/exceptions/QueryExceptions.kt +6 -0
- package/android/src/main/java/expo/modules/medialibrary/next/extensions/resolver/AlbumExtensions.kt +9 -0
- package/android/src/main/java/expo/modules/medialibrary/next/extensions/resolver/AssetExtensions.kt +5 -5
- package/android/src/main/java/expo/modules/medialibrary/next/objects/album/AlbumQuery.kt +22 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/asset/Asset.kt +2 -1
- package/android/src/main/java/expo/modules/medialibrary/next/objects/asset/delegates/AssetDelegate.kt +2 -1
- package/android/src/main/java/expo/modules/medialibrary/next/objects/asset/delegates/AssetLegacyDelegate.kt +13 -8
- package/android/src/main/java/expo/modules/medialibrary/next/objects/asset/delegates/AssetModernDelegate.kt +13 -8
- package/android/src/main/java/expo/modules/medialibrary/next/objects/asset/factories/AssetLegacyFactory.kt +1 -1
- package/android/src/main/java/expo/modules/medialibrary/next/objects/query/MediaStoreQueryFormatter.kt +31 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/query/Query.kt +108 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/query/builder/QueryExecutor.kt +8 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/query/builder/QueryLegacyExecutor.kt +73 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/query/builder/QueryModernExecutor.kt +72 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/wrappers/MediaType.kt +55 -0
- package/android/src/main/java/expo/modules/medialibrary/next/objects/wrappers/MimeType.kt +10 -3
- package/android/src/main/java/expo/modules/medialibrary/next/objects/wrappers/RelativePath.kt +2 -1
- package/android/src/main/java/expo/modules/medialibrary/next/records/AssetField.kt +23 -0
- package/android/src/main/java/expo/modules/medialibrary/next/records/SortDescriptor.kt +14 -0
- package/build/next/ExpoMediaLibraryNext.d.ts +4 -1
- package/build/next/ExpoMediaLibraryNext.d.ts.map +1 -1
- package/build/next/ExpoMediaLibraryNext.js.map +1 -1
- package/build/next/MediaLibraryNext.types.d.ts +4 -2
- package/build/next/MediaLibraryNext.types.d.ts.map +1 -1
- package/build/next/MediaLibraryNext.types.js +4 -2
- package/build/next/MediaLibraryNext.types.js.map +1 -1
- package/build/next/index.d.ts +14 -2
- package/build/next/index.d.ts.map +1 -1
- package/build/next/index.js +19 -2
- package/build/next/index.js.map +1 -1
- package/build/next/types/Album.d.ts +38 -17
- package/build/next/types/Album.d.ts.map +1 -1
- package/build/next/types/Album.js.map +1 -1
- package/build/next/types/Asset.d.ts +21 -25
- package/build/next/types/Asset.d.ts.map +1 -1
- package/build/next/types/Asset.js.map +1 -1
- package/build/next/types/AssetField.d.ts +18 -0
- package/build/next/types/AssetField.d.ts.map +1 -0
- package/build/next/types/AssetField.js +10 -0
- package/build/next/types/AssetField.js.map +1 -0
- package/build/next/types/GranularPermission.d.ts +2 -0
- package/build/next/types/GranularPermission.d.ts.map +1 -0
- package/build/next/types/GranularPermission.js +2 -0
- package/build/next/types/GranularPermission.js.map +1 -0
- package/build/next/types/MediaType.d.ts +7 -0
- package/build/next/types/MediaType.d.ts.map +1 -0
- package/build/next/types/MediaType.js +8 -0
- package/build/next/types/MediaType.js.map +1 -0
- package/build/next/types/Query.d.ts +93 -0
- package/build/next/types/Query.d.ts.map +1 -0
- package/build/next/types/Query.js +2 -0
- package/build/next/types/Query.js.map +1 -0
- package/build/next/types/SortDescriptor.d.ts +6 -0
- package/build/next/types/SortDescriptor.d.ts.map +1 -0
- package/build/next/types/SortDescriptor.js +2 -0
- package/build/next/types/SortDescriptor.js.map +1 -0
- package/expo-module.config.json +1 -1
- package/ios/next/MediaLibraryNextModule.swift +74 -8
- package/ios/next/exceptions/Exceptions.swift +24 -0
- package/ios/next/extensions/DateExtensions.swift +8 -0
- package/ios/next/objects/Query/AssetField.swift +27 -0
- package/ios/next/objects/Query/PredicateBuilder.swift +50 -0
- package/ios/next/objects/Query/Query.swift +135 -0
- package/ios/next/objects/Query/SortDescriptor.swift +11 -0
- package/ios/next/objects/asset/Asset.swift +7 -7
- package/ios/next/objects/asset/MediaType.swift +38 -0
- package/ios/next/repository/AssetCollectionRepository.swift +12 -0
- package/ios/next/repository/AssetRepository.swift +18 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/{18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8-sources.jar → 18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96-sources.jar} +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96-sources.jar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96-sources.jar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96-sources.jar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96-sources.jar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.aar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.aar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.aar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.aar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/{18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.module → 18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.module} +22 -22
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.module.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/{18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.pom → 18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.pom} +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.3.0-canary-20250919-7a31b96/expo.modules.medialibrary-18.3.0-canary-20250919-7a31b96.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/maven-metadata.xml.sha512 +1 -1
- package/package.json +3 -3
- package/src/next/ExpoMediaLibraryNext.ts +4 -1
- package/src/next/MediaLibraryNext.types.ts +4 -2
- package/src/next/index.ts +24 -4
- package/src/next/types/Album.ts +39 -21
- package/src/next/types/Asset.ts +30 -19
- package/src/next/types/AssetField.ts +19 -0
- package/src/next/types/GranularPermission.ts +1 -0
- package/src/next/types/MediaType.ts +6 -0
- package/src/next/types/Query.ts +96 -0
- package/src/next/types/SortDescriptor.ts +6 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8-sources.jar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8-sources.jar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8-sources.jar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8-sources.jar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.aar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.aar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.aar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.aar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.module.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.module.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.module.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.module.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.pom.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.pom.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.pom.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.medialibrary/18.1.2-canary-20250912-b5ce2a8/expo.modules.medialibrary-18.1.2-canary-20250912-b5ce2a8.pom.sha512 +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,10 +6,23 @@
|
|
|
6
6
|
|
|
7
7
|
### 🎉 New features
|
|
8
8
|
|
|
9
|
+
- [next] Add `Album.get(title)` ([#39717](https://github.com/expo/expo/pull/39717) by [@Wenszel](https://github.com/Wenszel))
|
|
10
|
+
|
|
9
11
|
### 🐛 Bug fixes
|
|
10
12
|
|
|
13
|
+
- [next][android] Change default root directory to Pictures ([#39716](https://github.com/expo/expo/pull/39716) by [@Wenszel](https://github.com/Wenszel))
|
|
14
|
+
- [next] Fix `asset.getModificationTime` to return milliseconds ([#39715](https://github.com/expo/expo/pull/39715) by [@Wenszel](https://github.com/Wenszel))
|
|
15
|
+
|
|
11
16
|
### 💡 Others
|
|
12
17
|
|
|
18
|
+
- [next] Add documentation ([#39754](https://github.com/expo/expo/pull/39754) by [@Wenszel](https://github.com/Wenszel))
|
|
19
|
+
|
|
20
|
+
## 18.2.0 — 2025-09-16
|
|
21
|
+
|
|
22
|
+
### 🎉 New features
|
|
23
|
+
|
|
24
|
+
- [next] Add Query ([#39559](https://github.com/expo/expo/pull/39559) by [@Wenszel](https://github.com/Wenszel))
|
|
25
|
+
|
|
13
26
|
## 18.1.1 — 2025-09-10
|
|
14
27
|
|
|
15
28
|
### 💡 Others
|
package/android/build.gradle
CHANGED
|
@@ -4,13 +4,13 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '18.
|
|
7
|
+
version = '18.3.0-canary-20250919-7a31b96'
|
|
8
8
|
|
|
9
9
|
android {
|
|
10
10
|
namespace "expo.modules.medialibrary"
|
|
11
11
|
defaultConfig {
|
|
12
12
|
versionCode 37
|
|
13
|
-
versionName "18.
|
|
13
|
+
versionName "18.3.0-canary-20250919-7a31b96"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -11,15 +11,22 @@ import expo.modules.kotlin.modules.ModuleDefinition
|
|
|
11
11
|
import expo.modules.kotlin.types.Either
|
|
12
12
|
import expo.modules.kotlin.types.toKClass
|
|
13
13
|
import expo.modules.medialibrary.next.objects.album.Album
|
|
14
|
+
import expo.modules.medialibrary.next.objects.album.AlbumQuery
|
|
14
15
|
import expo.modules.medialibrary.next.objects.asset.Asset
|
|
15
16
|
import expo.modules.medialibrary.next.objects.album.factories.AlbumModernFactory
|
|
16
17
|
import expo.modules.medialibrary.next.objects.album.factories.AlbumLegacyFactory
|
|
17
18
|
import expo.modules.medialibrary.next.objects.asset.factories.AssetModernFactory
|
|
18
19
|
import expo.modules.medialibrary.next.objects.asset.factories.AssetLegacyFactory
|
|
20
|
+
import expo.modules.medialibrary.next.objects.query.MediaStoreQueryFormatter
|
|
21
|
+
import expo.modules.medialibrary.next.objects.query.Query
|
|
22
|
+
import expo.modules.medialibrary.next.objects.wrappers.MediaType
|
|
19
23
|
import expo.modules.medialibrary.next.permissions.MediaStorePermissionsDelegate
|
|
20
24
|
import expo.modules.medialibrary.next.permissions.SystemPermissionsDelegate
|
|
21
25
|
import expo.modules.medialibrary.next.permissions.enums.GranularPermission
|
|
26
|
+
import expo.modules.medialibrary.next.records.AssetField
|
|
27
|
+
import expo.modules.medialibrary.next.records.SortDescriptor
|
|
22
28
|
|
|
29
|
+
@OptIn(EitherType::class)
|
|
23
30
|
class MediaLibraryNextModule : Module() {
|
|
24
31
|
private val context
|
|
25
32
|
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
|
|
@@ -32,6 +39,10 @@ class MediaLibraryNextModule : Module() {
|
|
|
32
39
|
MediaStorePermissionsDelegate(appContext)
|
|
33
40
|
}
|
|
34
41
|
|
|
42
|
+
private val albumQuery by lazy {
|
|
43
|
+
AlbumQuery(context)
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
private val albumFactory by lazy {
|
|
36
47
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
37
48
|
AlbumModernFactory(assetFactory, context)
|
|
@@ -141,6 +152,63 @@ class MediaLibraryNextModule : Module() {
|
|
|
141
152
|
}
|
|
142
153
|
}
|
|
143
154
|
|
|
155
|
+
Class(Query::class) {
|
|
156
|
+
Constructor {
|
|
157
|
+
Query(context)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
Function("limit") { self: Query, limit: Int ->
|
|
161
|
+
self.limit(limit)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
Function("offset") { self: Query, offset: Int ->
|
|
165
|
+
self.offset(offset)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Function("album") { self: Query, album: Album ->
|
|
169
|
+
self.album(album)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Function("eq") { self: Query, field: AssetField, value: Either<MediaType, Long> ->
|
|
173
|
+
self.eq(field, MediaStoreQueryFormatter.parse(field, value))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
Function("within") { self: Query, field: AssetField, values: List<Either<MediaType, Long>> ->
|
|
177
|
+
val stringValues = values.map { value -> MediaStoreQueryFormatter.parse(field, value) }
|
|
178
|
+
self.within(field, stringValues)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Function("gt") { self: Query, field: AssetField, value: Long ->
|
|
182
|
+
self.gt(field, MediaStoreQueryFormatter.parse(field, value))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Function("gte") { self: Query, field: AssetField, value: Long ->
|
|
186
|
+
self.gte(field, MediaStoreQueryFormatter.parse(field, value))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
Function("lt") { self: Query, field: AssetField, value: Long ->
|
|
190
|
+
self.lt(field, MediaStoreQueryFormatter.parse(field, value))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
Function("lte") { self: Query, field: AssetField, value: Long ->
|
|
194
|
+
self.lte(field, MediaStoreQueryFormatter.parse(field, value))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
Function("orderBy") { self: Query, sortDescriptorRef: Either<AssetField, SortDescriptor> ->
|
|
198
|
+
if (sortDescriptorRef.`is`(AssetField::class)) {
|
|
199
|
+
val assetField = sortDescriptorRef.get(AssetField::class)
|
|
200
|
+
val descriptor = SortDescriptor(assetField)
|
|
201
|
+
return@Function self.orderBy(descriptor)
|
|
202
|
+
}
|
|
203
|
+
val descriptor = sortDescriptorRef.get(SortDescriptor::class)
|
|
204
|
+
return@Function self.orderBy(descriptor)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
AsyncFunction("exe") Coroutine { self: Query ->
|
|
208
|
+
return@Coroutine self.exe()
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
144
212
|
AsyncFunction("createAsset") Coroutine { filePath: Uri, album: Album? ->
|
|
145
213
|
systemPermissionsDelegate.requireSystemPermissions(true)
|
|
146
214
|
return@Coroutine assetFactory.create(filePath, album?.getRelativePath())
|
|
@@ -158,6 +226,11 @@ class MediaLibraryNextModule : Module() {
|
|
|
158
226
|
return@Coroutine albumFactory.createFromFilePaths(name, assetPaths)
|
|
159
227
|
}
|
|
160
228
|
|
|
229
|
+
AsyncFunction("getAlbum") Coroutine { title: String ->
|
|
230
|
+
systemPermissionsDelegate.requireSystemPermissions(false)
|
|
231
|
+
albumQuery.getAlbum(title)
|
|
232
|
+
}
|
|
233
|
+
|
|
161
234
|
AsyncFunction("deleteAlbums") Coroutine { albums: List<Album> ->
|
|
162
235
|
systemPermissionsDelegate.requireSystemPermissions(true)
|
|
163
236
|
albums.forEach { album -> album.delete() }
|
package/android/src/main/java/expo/modules/medialibrary/next/extensions/resolver/AlbumExtensions.kt
CHANGED
|
@@ -48,6 +48,15 @@ suspend fun ContentResolver.queryAlbumId(relativePath: RelativePath): String? =
|
|
|
48
48
|
arrayOf(relativePath.value)
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
+
suspend fun ContentResolver.queryAlbumId(name: String): String? =
|
|
52
|
+
queryOne(
|
|
53
|
+
EXTERNAL_CONTENT_URI,
|
|
54
|
+
MediaStore.Files.FileColumns.BUCKET_ID,
|
|
55
|
+
Cursor::getString,
|
|
56
|
+
"${MediaStore.MediaColumns.BUCKET_DISPLAY_NAME} = ?",
|
|
57
|
+
arrayOf(name)
|
|
58
|
+
)
|
|
59
|
+
|
|
51
60
|
suspend fun ContentResolver.queryAlbumAssetsContentUris(bucketId: String): List<Uri> =
|
|
52
61
|
withContext(Dispatchers.IO) {
|
|
53
62
|
val projection = arrayOf(
|
package/android/src/main/java/expo/modules/medialibrary/next/extensions/resolver/AssetExtensions.kt
CHANGED
|
@@ -17,26 +17,26 @@ import kotlinx.coroutines.withContext
|
|
|
17
17
|
suspend fun ContentResolver.queryAssetDisplayName(contentUri: Uri): String? =
|
|
18
18
|
queryOne(contentUri, MediaStore.MediaColumns.DISPLAY_NAME, Cursor::getString)
|
|
19
19
|
|
|
20
|
-
suspend fun ContentResolver.
|
|
20
|
+
suspend fun ContentResolver.queryAssetCreationTime(contentUri: Uri): Long? =
|
|
21
21
|
queryOne(contentUri, MediaStore.Images.Media.DATE_TAKEN, Cursor::getLong)
|
|
22
22
|
|
|
23
23
|
suspend fun ContentResolver.queryAssetModificationTime(contentUri: Uri): Long? =
|
|
24
|
-
queryOne(contentUri, MediaStore.
|
|
24
|
+
queryOne(contentUri, MediaStore.MediaColumns.DATE_MODIFIED, Cursor::getLong)
|
|
25
25
|
|
|
26
26
|
suspend fun ContentResolver.queryAssetDuration(contentUri: Uri): Long? =
|
|
27
27
|
queryOne(contentUri, MediaStore.Video.VideoColumns.DURATION, Cursor::getLong)
|
|
28
28
|
|
|
29
29
|
suspend fun ContentResolver.queryAssetWidth(contentUri: Uri): Int? =
|
|
30
|
-
queryOne(contentUri, MediaStore.
|
|
30
|
+
queryOne(contentUri, MediaStore.MediaColumns.WIDTH, Cursor::getInt)
|
|
31
31
|
|
|
32
32
|
suspend fun ContentResolver.queryAssetHeight(contentUri: Uri): Int? =
|
|
33
|
-
queryOne(contentUri, MediaStore.
|
|
33
|
+
queryOne(contentUri, MediaStore.MediaColumns.HEIGHT, Cursor::getInt)
|
|
34
34
|
|
|
35
35
|
suspend fun ContentResolver.queryAssetPath(contentUri: Uri): String? =
|
|
36
36
|
queryOne(contentUri, MediaStore.Files.FileColumns.DATA, Cursor::getString)
|
|
37
37
|
|
|
38
38
|
suspend fun ContentResolver.queryAssetBucketId(contentUri: Uri): Int? =
|
|
39
|
-
queryOne(contentUri, MediaStore.
|
|
39
|
+
queryOne(contentUri, MediaStore.MediaColumns.BUCKET_ID, Cursor::getInt)
|
|
40
40
|
|
|
41
41
|
suspend fun ContentResolver.insertPendingAsset(
|
|
42
42
|
displayName: String,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package expo.modules.medialibrary.next.objects.album
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import expo.modules.medialibrary.next.exceptions.ContentResolverNotObtainedException
|
|
5
|
+
import expo.modules.medialibrary.next.extensions.getOrThrow
|
|
6
|
+
import expo.modules.medialibrary.next.extensions.resolver.queryAlbumId
|
|
7
|
+
import java.lang.ref.WeakReference
|
|
8
|
+
|
|
9
|
+
class AlbumQuery(context: Context) {
|
|
10
|
+
private val contextRef = WeakReference(context)
|
|
11
|
+
|
|
12
|
+
private val contentResolver
|
|
13
|
+
get() = contextRef
|
|
14
|
+
.getOrThrow()
|
|
15
|
+
.contentResolver ?: throw ContentResolverNotObtainedException()
|
|
16
|
+
|
|
17
|
+
suspend fun getAlbum(title: String): Album? {
|
|
18
|
+
val id = contentResolver.queryAlbumId(title)
|
|
19
|
+
?: return null
|
|
20
|
+
return Album(id, contextRef.getOrThrow())
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -8,6 +8,7 @@ import expo.modules.medialibrary.next.extensions.getOrThrow
|
|
|
8
8
|
import expo.modules.medialibrary.next.objects.wrappers.RelativePath
|
|
9
9
|
import expo.modules.medialibrary.next.objects.asset.delegates.AssetLegacyDelegate
|
|
10
10
|
import expo.modules.medialibrary.next.objects.asset.delegates.AssetModernDelegate
|
|
11
|
+
import expo.modules.medialibrary.next.objects.wrappers.MediaType
|
|
11
12
|
import expo.modules.medialibrary.next.objects.wrappers.MimeType
|
|
12
13
|
import kotlinx.coroutines.Dispatchers
|
|
13
14
|
import kotlinx.coroutines.withContext
|
|
@@ -42,7 +43,7 @@ class Asset(contentUri: Uri, context: Context) : SharedObject() {
|
|
|
42
43
|
suspend fun getWidth(): Int =
|
|
43
44
|
assetDelegate.getWidth()
|
|
44
45
|
|
|
45
|
-
suspend fun getMediaType():
|
|
46
|
+
suspend fun getMediaType(): MediaType =
|
|
46
47
|
assetDelegate.getMediaType()
|
|
47
48
|
|
|
48
49
|
suspend fun getModificationTime(): Long? =
|
|
@@ -3,6 +3,7 @@ package expo.modules.medialibrary.next.objects.asset.delegates
|
|
|
3
3
|
import android.net.Uri
|
|
4
4
|
import expo.modules.medialibrary.next.objects.wrappers.RelativePath
|
|
5
5
|
import expo.modules.medialibrary.next.objects.asset.Asset
|
|
6
|
+
import expo.modules.medialibrary.next.objects.wrappers.MediaType
|
|
6
7
|
import expo.modules.medialibrary.next.objects.wrappers.MimeType
|
|
7
8
|
|
|
8
9
|
interface AssetDelegate {
|
|
@@ -12,7 +13,7 @@ interface AssetDelegate {
|
|
|
12
13
|
suspend fun getFilename(): String
|
|
13
14
|
suspend fun getHeight(): Int
|
|
14
15
|
suspend fun getWidth(): Int
|
|
15
|
-
suspend fun getMediaType():
|
|
16
|
+
suspend fun getMediaType(): MediaType
|
|
16
17
|
suspend fun getModificationTime(): Long?
|
|
17
18
|
suspend fun getUri(): Uri
|
|
18
19
|
suspend fun getMimeType(): MimeType
|
|
@@ -19,16 +19,19 @@ import expo.modules.medialibrary.next.extensions.resolver.queryAssetHeight
|
|
|
19
19
|
import expo.modules.medialibrary.next.extensions.resolver.queryAssetModificationTime
|
|
20
20
|
import expo.modules.medialibrary.next.extensions.resolver.queryAssetPath
|
|
21
21
|
import expo.modules.medialibrary.next.extensions.resolver.queryAssetWidth
|
|
22
|
-
import expo.modules.medialibrary.next.extensions.resolver.
|
|
22
|
+
import expo.modules.medialibrary.next.extensions.resolver.queryAssetCreationTime
|
|
23
23
|
import expo.modules.medialibrary.next.extensions.safeCopy
|
|
24
24
|
import expo.modules.medialibrary.next.extensions.safeMove
|
|
25
25
|
import expo.modules.medialibrary.next.objects.wrappers.RelativePath
|
|
26
26
|
import expo.modules.medialibrary.next.objects.asset.Asset
|
|
27
|
+
import expo.modules.medialibrary.next.objects.wrappers.MediaType
|
|
27
28
|
import expo.modules.medialibrary.next.objects.wrappers.MimeType
|
|
28
29
|
import kotlinx.coroutines.Dispatchers
|
|
29
30
|
import kotlinx.coroutines.withContext
|
|
30
31
|
import java.io.File
|
|
31
32
|
import java.lang.ref.WeakReference
|
|
33
|
+
import kotlin.time.DurationUnit
|
|
34
|
+
import kotlin.time.toDuration
|
|
32
35
|
|
|
33
36
|
@DeprecatedSinceApi(Build.VERSION_CODES.Q)
|
|
34
37
|
class AssetLegacyDelegate(contentUri: Uri, context: Context) : AssetDelegate {
|
|
@@ -49,7 +52,7 @@ class AssetLegacyDelegate(contentUri: Uri, context: Context) : AssetDelegate {
|
|
|
49
52
|
|
|
50
53
|
override suspend fun getCreationTime(): Long? {
|
|
51
54
|
return contentResolver
|
|
52
|
-
.
|
|
55
|
+
.queryAssetCreationTime(contentUri)
|
|
53
56
|
.takeIf { it != 0L }
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -71,7 +74,7 @@ class AssetLegacyDelegate(contentUri: Uri, context: Context) : AssetDelegate {
|
|
|
71
74
|
val height = contentResolver.queryAssetHeight(contentUri)
|
|
72
75
|
?: throw AssetPropertyNotFoundException("Height")
|
|
73
76
|
// If height is not saved to the database
|
|
74
|
-
if (getMediaType().
|
|
77
|
+
if (getMediaType() == MediaType.IMAGE && height <= 0) {
|
|
75
78
|
return downloadBitmapAndGet { it.outHeight }
|
|
76
79
|
}
|
|
77
80
|
return height
|
|
@@ -80,7 +83,7 @@ class AssetLegacyDelegate(contentUri: Uri, context: Context) : AssetDelegate {
|
|
|
80
83
|
override suspend fun getWidth(): Int {
|
|
81
84
|
val width = contentResolver.queryAssetWidth(contentUri)
|
|
82
85
|
?: throw AssetPropertyNotFoundException("Width")
|
|
83
|
-
if (getMediaType().
|
|
86
|
+
if (getMediaType() == MediaType.IMAGE && width <= 0) {
|
|
84
87
|
return downloadBitmapAndGet { it.outWidth }
|
|
85
88
|
}
|
|
86
89
|
return width
|
|
@@ -93,12 +96,14 @@ class AssetLegacyDelegate(contentUri: Uri, context: Context) : AssetDelegate {
|
|
|
93
96
|
return extract(options)
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
override suspend fun getMediaType():
|
|
97
|
-
|
|
98
|
-
?: throw AssetPropertyNotFoundException("MediaType")
|
|
99
|
+
override suspend fun getMediaType(): MediaType =
|
|
100
|
+
MediaType.fromContentUri(contentUri)
|
|
99
101
|
|
|
100
102
|
override suspend fun getModificationTime(): Long? =
|
|
101
|
-
contentResolver.queryAssetModificationTime(contentUri)
|
|
103
|
+
contentResolver.queryAssetModificationTime(contentUri)
|
|
104
|
+
?.takeIf { it != 0L }
|
|
105
|
+
?.toDuration(DurationUnit.SECONDS)
|
|
106
|
+
?.inWholeMilliseconds
|
|
102
107
|
|
|
103
108
|
override suspend fun getMimeType(): MimeType {
|
|
104
109
|
return contentResolver.getType(contentUri)?.let { MimeType(it) }
|
|
@@ -18,15 +18,18 @@ import expo.modules.medialibrary.next.extensions.resolver.queryAssetHeight
|
|
|
18
18
|
import expo.modules.medialibrary.next.extensions.resolver.queryAssetModificationTime
|
|
19
19
|
import expo.modules.medialibrary.next.extensions.resolver.queryAssetPath
|
|
20
20
|
import expo.modules.medialibrary.next.extensions.resolver.queryAssetWidth
|
|
21
|
-
import expo.modules.medialibrary.next.extensions.resolver.
|
|
21
|
+
import expo.modules.medialibrary.next.extensions.resolver.queryAssetCreationTime
|
|
22
22
|
import expo.modules.medialibrary.next.extensions.resolver.updateRelativePath
|
|
23
23
|
import expo.modules.medialibrary.next.objects.wrappers.RelativePath
|
|
24
24
|
import expo.modules.medialibrary.next.objects.asset.Asset
|
|
25
|
+
import expo.modules.medialibrary.next.objects.wrappers.MediaType
|
|
25
26
|
import expo.modules.medialibrary.next.objects.wrappers.MimeType
|
|
26
27
|
import kotlinx.coroutines.Dispatchers
|
|
27
28
|
import kotlinx.coroutines.withContext
|
|
28
29
|
import java.io.File
|
|
29
30
|
import java.lang.ref.WeakReference
|
|
31
|
+
import kotlin.time.DurationUnit
|
|
32
|
+
import kotlin.time.toDuration
|
|
30
33
|
|
|
31
34
|
@RequiresApi(Build.VERSION_CODES.Q)
|
|
32
35
|
class AssetModernDelegate(override val contentUri: Uri, context: Context) : AssetDelegate {
|
|
@@ -39,7 +42,7 @@ class AssetModernDelegate(override val contentUri: Uri, context: Context) : Asse
|
|
|
39
42
|
|
|
40
43
|
override suspend fun getCreationTime(): Long? {
|
|
41
44
|
return contentResolver
|
|
42
|
-
.
|
|
45
|
+
.queryAssetCreationTime(contentUri)
|
|
43
46
|
.takeIf { it != 0L }
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -61,7 +64,7 @@ class AssetModernDelegate(override val contentUri: Uri, context: Context) : Asse
|
|
|
61
64
|
val height = contentResolver.queryAssetHeight(contentUri)
|
|
62
65
|
?: throw AssetPropertyNotFoundException("Height")
|
|
63
66
|
// If height is not saved to the database
|
|
64
|
-
if (getMediaType().
|
|
67
|
+
if (getMediaType() == MediaType.IMAGE && height <= 0) {
|
|
65
68
|
return downloadBitmapAndGet { it.outHeight }
|
|
66
69
|
}
|
|
67
70
|
return height
|
|
@@ -70,7 +73,7 @@ class AssetModernDelegate(override val contentUri: Uri, context: Context) : Asse
|
|
|
70
73
|
override suspend fun getWidth(): Int {
|
|
71
74
|
val width = contentResolver.queryAssetWidth(contentUri)
|
|
72
75
|
?: throw AssetPropertyNotFoundException("Width")
|
|
73
|
-
if (getMediaType().
|
|
76
|
+
if (getMediaType() == MediaType.IMAGE && width <= 0) {
|
|
74
77
|
return downloadBitmapAndGet { it.outWidth }
|
|
75
78
|
}
|
|
76
79
|
return width
|
|
@@ -83,12 +86,14 @@ class AssetModernDelegate(override val contentUri: Uri, context: Context) : Asse
|
|
|
83
86
|
return extract(options)
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
override suspend fun getMediaType():
|
|
87
|
-
|
|
88
|
-
?: throw AssetPropertyNotFoundException("MediaType")
|
|
89
|
+
override suspend fun getMediaType(): MediaType =
|
|
90
|
+
MediaType.fromContentUri(contentUri)
|
|
89
91
|
|
|
90
92
|
override suspend fun getModificationTime(): Long? =
|
|
91
|
-
contentResolver.queryAssetModificationTime(contentUri)
|
|
93
|
+
contentResolver.queryAssetModificationTime(contentUri)
|
|
94
|
+
?.takeIf { it != 0L }
|
|
95
|
+
?.toDuration(DurationUnit.SECONDS)
|
|
96
|
+
?.inWholeMilliseconds
|
|
92
97
|
|
|
93
98
|
override suspend fun getUri(): Uri {
|
|
94
99
|
// e.g. storage/emulated/0/Android/data/expo/files/[ROOT_ALBUM]/[ALBUM_NAME]
|
|
@@ -35,7 +35,7 @@ class AssetLegacyFactory(context: Context) : AssetFactory {
|
|
|
35
35
|
val baseDir = if (relativePath != null) {
|
|
36
36
|
File(relativePath.toFilePath())
|
|
37
37
|
} else {
|
|
38
|
-
mimeType.
|
|
38
|
+
mimeType.externalStorageAssetDirectory()
|
|
39
39
|
}
|
|
40
40
|
baseDir.mkdirs()
|
|
41
41
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package expo.modules.medialibrary.next.objects.query
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.apifeatures.EitherType
|
|
4
|
+
import expo.modules.kotlin.types.Either
|
|
5
|
+
import expo.modules.medialibrary.next.objects.wrappers.MediaType
|
|
6
|
+
import expo.modules.medialibrary.next.records.AssetField
|
|
7
|
+
import kotlin.time.DurationUnit
|
|
8
|
+
import kotlin.time.toDuration
|
|
9
|
+
|
|
10
|
+
@OptIn(EitherType::class)
|
|
11
|
+
class MediaStoreQueryFormatter {
|
|
12
|
+
companion object {
|
|
13
|
+
fun parse(field: AssetField, value: Either<MediaType, Long>): String {
|
|
14
|
+
if (value.`is`(MediaType::class)) {
|
|
15
|
+
return parse(value.get(MediaType::class))
|
|
16
|
+
}
|
|
17
|
+
return parse(field, value.get(Long::class))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fun parse(field: AssetField, value: Long): String {
|
|
21
|
+
if (field == AssetField.MODIFICATION_TIME) {
|
|
22
|
+
return value.toDuration(DurationUnit.MILLISECONDS).inWholeSeconds.toString()
|
|
23
|
+
}
|
|
24
|
+
return value.toString()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun parse(value: MediaType): String {
|
|
28
|
+
return value.toMediaStoreValue().toString()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
package expo.modules.medialibrary.next.objects.query
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import android.provider.MediaStore
|
|
6
|
+
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
7
|
+
import expo.modules.medialibrary.next.exceptions.ContentResolverNotObtainedException
|
|
8
|
+
import expo.modules.medialibrary.next.extensions.asIterable
|
|
9
|
+
import expo.modules.medialibrary.next.extensions.getOrThrow
|
|
10
|
+
import expo.modules.medialibrary.next.extensions.resolver.extractAssetContentUri
|
|
11
|
+
import expo.modules.medialibrary.next.objects.album.Album
|
|
12
|
+
import expo.modules.medialibrary.next.objects.asset.Asset
|
|
13
|
+
import expo.modules.medialibrary.next.objects.query.builder.QueryLegacyExecutor
|
|
14
|
+
import expo.modules.medialibrary.next.objects.query.builder.QueryModernExecutor
|
|
15
|
+
import expo.modules.medialibrary.next.records.AssetField
|
|
16
|
+
import expo.modules.medialibrary.next.records.SortDescriptor
|
|
17
|
+
import kotlinx.coroutines.Dispatchers
|
|
18
|
+
import kotlinx.coroutines.ensureActive
|
|
19
|
+
import kotlinx.coroutines.withContext
|
|
20
|
+
import java.lang.ref.WeakReference
|
|
21
|
+
import kotlin.collections.joinToString
|
|
22
|
+
|
|
23
|
+
class Query(context: Context) : SharedObject() {
|
|
24
|
+
private val contextRef = WeakReference(context)
|
|
25
|
+
|
|
26
|
+
private val contentResolver
|
|
27
|
+
get() = contextRef
|
|
28
|
+
.getOrThrow()
|
|
29
|
+
.contentResolver ?: throw ContentResolverNotObtainedException()
|
|
30
|
+
|
|
31
|
+
private val clauses = mutableListOf<String>()
|
|
32
|
+
private val args = mutableListOf<String>()
|
|
33
|
+
private val orderBy = mutableListOf<SortDescriptor>()
|
|
34
|
+
|
|
35
|
+
private var limit: Int? = null
|
|
36
|
+
private var offset: Int? = null
|
|
37
|
+
|
|
38
|
+
fun eq(field: AssetField, value: String) = apply {
|
|
39
|
+
clauses.add("${field.toMediaStoreColumn()} = ?")
|
|
40
|
+
args.add(value)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fun within(field: AssetField, values: List<String>) = apply {
|
|
44
|
+
val questionMarks = values.joinToString(", ") { "?" }
|
|
45
|
+
clauses.add("${field.toMediaStoreColumn()} IN ($questionMarks)")
|
|
46
|
+
args.addAll(values)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fun gt(field: AssetField, value: String) = apply {
|
|
50
|
+
clauses.add("${field.toMediaStoreColumn()} > ?")
|
|
51
|
+
args.add(value)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fun gte(field: AssetField, value: String) = apply {
|
|
55
|
+
clauses.add("${field.toMediaStoreColumn()} >= ?")
|
|
56
|
+
args.add(value)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fun lt(field: AssetField, value: String) = apply {
|
|
60
|
+
clauses.add("${field.toMediaStoreColumn()} < ?")
|
|
61
|
+
args.add(value)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fun lte(field: AssetField, value: String) = apply {
|
|
65
|
+
clauses.add("${field.toMediaStoreColumn()} <= ?")
|
|
66
|
+
args.add(value)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fun limit(limit: Int) = apply {
|
|
70
|
+
this.limit = limit
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fun album(album: Album) = apply {
|
|
74
|
+
clauses.add("${MediaStore.MediaColumns.BUCKET_ID} = ?")
|
|
75
|
+
args.add(album.id)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fun offset(count: Int) = apply {
|
|
79
|
+
this.offset = count
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fun orderBy(descriptor: SortDescriptor) = apply {
|
|
83
|
+
orderBy.add(descriptor)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
suspend fun exe(): List<Asset> = withContext(Dispatchers.IO) {
|
|
87
|
+
val queryExecutor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
88
|
+
QueryModernExecutor(clauses, args, orderBy, limit, offset)
|
|
89
|
+
} else {
|
|
90
|
+
QueryLegacyExecutor(clauses, args, orderBy, limit, offset)
|
|
91
|
+
}
|
|
92
|
+
val projection = arrayOf(
|
|
93
|
+
MediaStore.Files.FileColumns._ID,
|
|
94
|
+
MediaStore.Files.FileColumns.MEDIA_TYPE
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
val cursor = queryExecutor.exe(projection, contentResolver)
|
|
98
|
+
return@withContext cursor.use {
|
|
99
|
+
ensureActive()
|
|
100
|
+
val idColumn = it.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)
|
|
101
|
+
val typeColumn = it.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE)
|
|
102
|
+
it.asIterable()
|
|
103
|
+
.map { row -> row.extractAssetContentUri(idColumn, typeColumn) }
|
|
104
|
+
.map { uri -> Asset(uri, contextRef.getOrThrow()) }
|
|
105
|
+
.toList()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
package expo.modules.medialibrary.next.objects.query.builder
|
|
2
|
+
|
|
3
|
+
import android.content.ContentResolver
|
|
4
|
+
import android.database.Cursor
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import android.provider.MediaStore
|
|
7
|
+
import androidx.annotation.DeprecatedSinceApi
|
|
8
|
+
import expo.modules.medialibrary.next.exceptions.QueryCouldNotBeExecuted
|
|
9
|
+
import expo.modules.medialibrary.next.extensions.resolver.EXTERNAL_CONTENT_URI
|
|
10
|
+
import expo.modules.medialibrary.next.records.SortDescriptor
|
|
11
|
+
import kotlinx.coroutines.Dispatchers
|
|
12
|
+
import kotlinx.coroutines.withContext
|
|
13
|
+
|
|
14
|
+
@DeprecatedSinceApi(Build.VERSION_CODES.Q)
|
|
15
|
+
class QueryLegacyExecutor(
|
|
16
|
+
private val clauses: MutableList<String>,
|
|
17
|
+
private val args: MutableList<String>,
|
|
18
|
+
private val sortDescriptors: MutableList<SortDescriptor>,
|
|
19
|
+
private val limit: Int?,
|
|
20
|
+
private val offset: Int?
|
|
21
|
+
) : QueryExecutor {
|
|
22
|
+
override suspend fun exe(
|
|
23
|
+
projection: Array<String>,
|
|
24
|
+
contentResolver: ContentResolver
|
|
25
|
+
): Cursor = withContext(Dispatchers.IO) {
|
|
26
|
+
val selection = buildSelection()
|
|
27
|
+
val sortOrder = buildSortOrder()
|
|
28
|
+
val selectionArgs = args.toTypedArray()
|
|
29
|
+
return@withContext contentResolver.query(EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder)
|
|
30
|
+
?: throw QueryCouldNotBeExecuted("Cursor is null")
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private fun buildSortOrder(): String {
|
|
34
|
+
var sortOrder = buildOrderBy()
|
|
35
|
+
sortOrder = addLimit(sortOrder)
|
|
36
|
+
return addOffset(sortOrder)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private fun buildSelection(): String {
|
|
40
|
+
return clauses.joinToString(" AND ")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun buildOrderBy(): String? {
|
|
44
|
+
return if (!sortDescriptors.isEmpty()) {
|
|
45
|
+
sortDescriptors.joinToString(", ") { it.toMediaStoreQueryString() }
|
|
46
|
+
} else {
|
|
47
|
+
null
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private fun addLimit(sortOrder: String?): String {
|
|
52
|
+
return if (limit != null) {
|
|
53
|
+
requireNotEmptySortOrder(sortOrder) + " LIMIT $limit"
|
|
54
|
+
} else if (offset != null) {
|
|
55
|
+
// SQLITE: limit is required to perform offset
|
|
56
|
+
requireNotEmptySortOrder(sortOrder) + " LIMIT -1"
|
|
57
|
+
} else {
|
|
58
|
+
sortOrder ?: ""
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private fun requireNotEmptySortOrder(sortOrder: String?): String {
|
|
63
|
+
return sortOrder ?: MediaStore.Files.FileColumns._ID
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private fun addOffset(orderBy: String): String {
|
|
67
|
+
return if (offset != null) {
|
|
68
|
+
"$orderBy OFFSET $offset"
|
|
69
|
+
} else {
|
|
70
|
+
orderBy
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|