adding skeleton for image gallery folder viewing
This commit is contained in:
parent
debfc5e5f0
commit
6f89c71300
|
@ -1,9 +1,9 @@
|
||||||
package app.dapk.st.home
|
package app.dapk.st.home
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
@ -13,7 +13,6 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
@ -30,19 +29,23 @@ import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import app.dapk.st.core.DapkActivity
|
import app.dapk.st.core.*
|
||||||
import app.dapk.st.core.PermissionResult
|
import app.dapk.st.core.components.CenteredLoading
|
||||||
import app.dapk.st.core.module
|
import app.dapk.st.design.components.Route
|
||||||
import app.dapk.st.core.viewModel
|
import app.dapk.st.design.components.Spider
|
||||||
import app.dapk.st.design.components.Toolbar
|
import app.dapk.st.design.components.SpiderPage
|
||||||
import app.dapk.st.directory.DirectoryModule
|
import app.dapk.st.directory.DirectoryModule
|
||||||
import app.dapk.st.home.gallery.FetchMediaFoldersUseCase
|
import app.dapk.st.home.gallery.FetchMediaFoldersUseCase
|
||||||
|
import app.dapk.st.home.gallery.FetchMediaUseCase
|
||||||
import app.dapk.st.home.gallery.Folder
|
import app.dapk.st.home.gallery.Folder
|
||||||
|
import app.dapk.st.home.gallery.Media
|
||||||
import app.dapk.st.login.LoginModule
|
import app.dapk.st.login.LoginModule
|
||||||
import app.dapk.st.profile.ProfileModule
|
import app.dapk.st.profile.ProfileModule
|
||||||
|
import app.dapk.st.viewmodel.DapkViewModel
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainActivity : DapkActivity() {
|
class MainActivity : DapkActivity() {
|
||||||
|
@ -55,27 +58,31 @@ class MainActivity : DapkActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val state = mutableStateOf(emptyList<Folder>())
|
val viewModel = ImageGalleryViewModel(
|
||||||
|
FetchMediaFoldersUseCase(contentResolver),
|
||||||
|
FetchMediaUseCase(contentResolver),
|
||||||
|
)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
// lifecycleScope.launch {
|
||||||
when (ensurePermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
// when (ensurePermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||||
PermissionResult.Denied -> {
|
// PermissionResult.Denied -> {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
PermissionResult.Granted -> {
|
// PermissionResult.Granted -> {
|
||||||
state.value = FetchMediaFoldersUseCase(contentResolver).fetchFolders()
|
// state.value = FetchMediaFoldersUseCase(contentResolver).fetchFolders()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
PermissionResult.ShowRational -> {
|
// PermissionResult.ShowRational -> {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
Surface {
|
Surface {
|
||||||
ImageGallery(state)
|
ImageGalleryScreen(viewModel) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,56 +120,215 @@ class MainActivity : DapkActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class ImageGalleryState(
|
||||||
|
val page: SpiderPage<out ImageGalleryPage>,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
sealed interface ImageGalleryPage {
|
||||||
|
data class Folders(val content: Lce<List<Folder>>) : ImageGalleryPage
|
||||||
|
data class Files(val content: Lce<List<Media>>) : ImageGalleryPage
|
||||||
|
|
||||||
|
object Routes {
|
||||||
|
val folders = Route<Folders>("Folders")
|
||||||
|
val files = Route<Files>("Files")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sealed interface ImageGalleryEvent
|
||||||
|
|
||||||
|
class ImageGalleryViewModel(
|
||||||
|
private val foldersUseCase: FetchMediaFoldersUseCase,
|
||||||
|
private val fetchMediaUseCase: FetchMediaUseCase,
|
||||||
|
) : DapkViewModel<ImageGalleryState, ImageGalleryEvent>(
|
||||||
|
initialState = ImageGalleryState(page = SpiderPage(route = ImageGalleryPage.Routes.folders, "", null, ImageGalleryPage.Folders(Lce.Loading())))
|
||||||
|
) {
|
||||||
|
|
||||||
|
private var currentPageJob: Job? = null
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
currentPageJob?.cancel()
|
||||||
|
currentPageJob = viewModelScope.launch {
|
||||||
|
val folders = foldersUseCase.fetchFolders()
|
||||||
|
updatePageState<ImageGalleryPage.Folders> { copy(content = Lce.Content(folders)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun goTo(page: SpiderPage<out ImageGalleryPage>) {
|
||||||
|
currentPageJob?.cancel()
|
||||||
|
updateState { copy(page = page) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun selectFolder(folder: Folder) {
|
||||||
|
currentPageJob?.cancel()
|
||||||
|
|
||||||
|
updateState {
|
||||||
|
copy(
|
||||||
|
page = SpiderPage(
|
||||||
|
route = ImageGalleryPage.Routes.files,
|
||||||
|
label = page.label,
|
||||||
|
parent = ImageGalleryPage.Routes.folders,
|
||||||
|
state = ImageGalleryPage.Files(Lce.Loading())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPageJob = viewModelScope.launch {
|
||||||
|
val media = fetchMediaUseCase.getMediaInBucket(folder.bucketId)
|
||||||
|
updatePageState<ImageGalleryPage.Files> {
|
||||||
|
copy(content = Lce.Content(media))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private inline fun <reified S : ImageGalleryPage> updatePageState(crossinline block: S.() -> S) {
|
||||||
|
val page = state.page
|
||||||
|
val currentState = page.state
|
||||||
|
require(currentState is S)
|
||||||
|
updateState { copy(page = (page as SpiderPage<S>).copy(state = block(page.state))) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ImageGallery(state: State<List<Folder>>) {
|
fun ImageGalleryScreen(viewModel: ImageGalleryViewModel, onTopLevelBack: () -> Unit) {
|
||||||
|
LifecycleEffect(onStart = {
|
||||||
|
viewModel.start()
|
||||||
|
})
|
||||||
|
|
||||||
|
val onNavigate: (SpiderPage<out ImageGalleryPage>?) -> Unit = {
|
||||||
|
when (it) {
|
||||||
|
null -> onTopLevelBack()
|
||||||
|
else -> viewModel.goTo(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spider(currentPage = viewModel.state.page, onNavigate = onNavigate) {
|
||||||
|
item(ImageGalleryPage.Routes.folders) {
|
||||||
|
ImageGalleryFolders(it) { folder ->
|
||||||
|
viewModel.selectFolder(folder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item(ImageGalleryPage.Routes.files) {
|
||||||
|
ImageGalleryMedia(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ImageGalleryFolders(state: ImageGalleryPage.Folders, onClick: (Folder) -> Unit) {
|
||||||
|
var boxWidth by remember { mutableStateOf(IntSize.Zero) }
|
||||||
|
val localDensity = LocalDensity.current
|
||||||
|
val screenWidth = LocalConfiguration.current.screenWidthDp
|
||||||
|
|
||||||
|
when (val content = state.content) {
|
||||||
|
is Lce.Loading -> {
|
||||||
|
CenteredLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
is Lce.Content -> {
|
||||||
|
Column {
|
||||||
|
val columns = when {
|
||||||
|
screenWidth > 600 -> 4
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(columns),
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
items(content.value, key = { it.bucketId }) {
|
||||||
|
Box(modifier = Modifier.fillMaxWidth().padding(2.dp)
|
||||||
|
.clickable { onClick(it) }
|
||||||
|
.onGloballyPositioned {
|
||||||
|
boxWidth = it.size
|
||||||
|
}) {
|
||||||
|
Image(
|
||||||
|
painter = rememberAsyncImagePainter(
|
||||||
|
model = ImageRequest.Builder(LocalContext.current)
|
||||||
|
.data(it.thumbnail.toString())
|
||||||
|
.build(),
|
||||||
|
),
|
||||||
|
contentDescription = "123",
|
||||||
|
modifier = Modifier.fillMaxWidth().height(with(localDensity) { boxWidth.width.toDp() }),
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
|
||||||
|
val gradient = Brush.verticalGradient(
|
||||||
|
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.5f)),
|
||||||
|
startY = boxWidth.width.toFloat() * 0.5f,
|
||||||
|
endY = boxWidth.width.toFloat()
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(modifier = Modifier.matchParentSize().background(gradient))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().align(Alignment.BottomStart).padding(4.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(it.title, fontSize = 13.sp, color = Color.White)
|
||||||
|
Text(it.itemCount.toString(), fontSize = 11.sp, color = Color.White)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is Lce.Error -> TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ImageGalleryMedia(state: ImageGalleryPage.Files) {
|
||||||
var boxWidth by remember { mutableStateOf(IntSize.Zero) }
|
var boxWidth by remember { mutableStateOf(IntSize.Zero) }
|
||||||
val localDensity = LocalDensity.current
|
val localDensity = LocalDensity.current
|
||||||
val screenWidth = LocalConfiguration.current.screenWidthDp
|
val screenWidth = LocalConfiguration.current.screenWidthDp
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Toolbar(title = "Send to Awesome Room", onNavigate = {})
|
|
||||||
val columns = when {
|
val columns = when {
|
||||||
screenWidth > 600 -> 4
|
screenWidth > 600 -> 4
|
||||||
else -> 2
|
else -> 2
|
||||||
}
|
}
|
||||||
LazyVerticalGrid(
|
|
||||||
columns = GridCells.Fixed(columns),
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
) {
|
|
||||||
items(state.value, key = { it.bucketId }) {
|
|
||||||
Box(modifier = Modifier.fillMaxWidth().padding(2.dp).onGloballyPositioned {
|
|
||||||
boxWidth = it.size
|
|
||||||
}) {
|
|
||||||
Image(
|
|
||||||
painter = rememberAsyncImagePainter(
|
|
||||||
model = ImageRequest.Builder(LocalContext.current)
|
|
||||||
.data(it.thumbnail.toString())
|
|
||||||
.build(),
|
|
||||||
),
|
|
||||||
contentDescription = "123",
|
|
||||||
modifier = Modifier.fillMaxWidth().height(with(localDensity) { boxWidth.width.toDp() }),
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
|
|
||||||
val gradient = Brush.verticalGradient(
|
when (val content = state.content) {
|
||||||
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.5f)),
|
is Lce.Loading -> {
|
||||||
startY = boxWidth.width.toFloat() * 0.5f,
|
CenteredLoading()
|
||||||
endY = boxWidth.width.toFloat()
|
}
|
||||||
)
|
is Lce.Content -> {
|
||||||
|
LazyVerticalGrid(
|
||||||
Box(modifier = Modifier.matchParentSize().background(gradient))
|
columns = GridCells.Fixed(columns),
|
||||||
Row(
|
modifier = Modifier.fillMaxSize(),
|
||||||
modifier = Modifier.fillMaxWidth().align(Alignment.BottomStart).padding(4.dp),
|
) {
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
items(content.value, key = { it.id }) {
|
||||||
verticalAlignment = Alignment.CenterVertically
|
Box(modifier = Modifier.fillMaxWidth().padding(2.dp).onGloballyPositioned {
|
||||||
) {
|
boxWidth = it.size
|
||||||
Text(it.title, fontSize = 13.sp, color = Color.White)
|
}) {
|
||||||
Text(it.itemCount.toString(), fontSize = 11.sp, color = Color.White)
|
Image(
|
||||||
|
painter = rememberAsyncImagePainter(
|
||||||
|
model = ImageRequest.Builder(LocalContext.current)
|
||||||
|
.data(it.uri.toString())
|
||||||
|
.crossfade(true)
|
||||||
|
.build(),
|
||||||
|
),
|
||||||
|
contentDescription = "123",
|
||||||
|
modifier = Modifier.fillMaxWidth().height(with(localDensity) { boxWidth.width.toDp() }),
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is Lce.Error -> TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,14 @@ class FetchMediaFoldersUseCase(
|
||||||
private val contentResolver: ContentResolver,
|
private val contentResolver: ContentResolver,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
suspend fun fetchFolders(): List<Folder> {
|
suspend fun fetchFolders(): List<Folder> {
|
||||||
val projection = arrayOf(Images.Media._ID, Images.Media.BUCKET_ID, Images.Media.BUCKET_DISPLAY_NAME, Images.Media.DATE_MODIFIED)
|
return withContext(Dispatchers.IO) {
|
||||||
val selection = "${isNotPending()} AND ${Images.Media.BUCKET_ID} AND ${Images.Media.MIME_TYPE} NOT LIKE ?"
|
val projection = arrayOf(Images.Media._ID, Images.Media.BUCKET_ID, Images.Media.BUCKET_DISPLAY_NAME, Images.Media.DATE_MODIFIED)
|
||||||
val sortBy = "${Images.Media.BUCKET_DISPLAY_NAME} COLLATE NOCASE ASC, ${Images.Media.DATE_MODIFIED} DESC"
|
val selection = "${isNotPending()} AND ${Images.Media.BUCKET_ID} AND ${Images.Media.MIME_TYPE} NOT LIKE ?"
|
||||||
|
val sortBy = "${Images.Media.BUCKET_DISPLAY_NAME} COLLATE NOCASE ASC, ${Images.Media.DATE_MODIFIED} DESC"
|
||||||
|
|
||||||
val folders = mutableMapOf<String, Folder>()
|
val folders = mutableMapOf<String, Folder>()
|
||||||
val contentUri = Images.Media.EXTERNAL_CONTENT_URI
|
val contentUri = Images.Media.EXTERNAL_CONTENT_URI
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
contentResolver.query(contentUri, projection, selection, arrayOf("%image/svg%"), sortBy).use { cursor ->
|
contentResolver.query(contentUri, projection, selection, arrayOf("%image/svg%"), sortBy).use { cursor ->
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
val rowId = cursor.getLong(cursor.getColumnIndexOrThrow(projection[0]))
|
val rowId = cursor.getLong(cursor.getColumnIndexOrThrow(projection[0]))
|
||||||
|
@ -32,27 +31,14 @@ class FetchMediaFoldersUseCase(
|
||||||
val bucketId = cursor.getString(cursor.getColumnIndexOrThrow(projection[1]))
|
val bucketId = cursor.getString(cursor.getColumnIndexOrThrow(projection[1]))
|
||||||
val title = cursor.getString(cursor.getColumnIndexOrThrow(projection[2])) ?: ""
|
val title = cursor.getString(cursor.getColumnIndexOrThrow(projection[2])) ?: ""
|
||||||
val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(projection[3]))
|
val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(projection[3]))
|
||||||
|
|
||||||
val folder = folders.getOrPut(bucketId) { Folder(bucketId, title, thumbnail) }
|
val folder = folders.getOrPut(bucketId) { Folder(bucketId, title, thumbnail) }
|
||||||
folder.incrementItemCount()
|
folder.incrementItemCount()
|
||||||
|
|
||||||
// val folder: FolderData = Util.getOrDefault(folders, bucketId, FolderData(thumbnail, localizeTitle(context, title), bucketId))
|
|
||||||
// folder.incrementCount()
|
|
||||||
// folders.put(bucketId, folder)
|
|
||||||
// if (cameraBucketId == null && title == "Camera") {
|
|
||||||
// cameraBucketId = bucketId
|
|
||||||
// }
|
|
||||||
// if (timestamp > thumbnailTimestamp) {
|
|
||||||
// globalThumbnail = thumbnail
|
|
||||||
// thumbnailTimestamp = timestamp
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
folders.values.toList()
|
||||||
}
|
}
|
||||||
return folders.values.toList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNotPending() = if (Build.VERSION.SDK_INT <= 28) Images.Media.DATA + " NOT NULL" else MediaStore.MediaColumns.IS_PENDING + " != 1"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,4 +55,60 @@ data class Folder(
|
||||||
_itemCount++
|
_itemCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FetchMediaUseCase(private val contentResolver: ContentResolver) {
|
||||||
|
|
||||||
|
private val projection = arrayOf(
|
||||||
|
Images.Media._ID,
|
||||||
|
Images.Media.MIME_TYPE,
|
||||||
|
Images.Media.DATE_MODIFIED,
|
||||||
|
Images.Media.ORIENTATION,
|
||||||
|
Images.Media.WIDTH,
|
||||||
|
Images.Media.HEIGHT,
|
||||||
|
Images.Media.SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun getMediaInBucket(bucketId: String): List<Media> {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
|
||||||
|
val media = mutableListOf<Media>()
|
||||||
|
val selection = Images.Media.BUCKET_ID + " = ? AND " + isNotPending() + " AND " + Images.Media.MIME_TYPE + " NOT LIKE ?"
|
||||||
|
val selectionArgs = arrayOf(bucketId, "%image/svg%")
|
||||||
|
val sortBy = Images.Media.DATE_MODIFIED + " DESC"
|
||||||
|
val contentUri = Images.Media.EXTERNAL_CONTENT_URI
|
||||||
|
contentResolver.query(contentUri, projection, selection, selectionArgs, sortBy).use { cursor ->
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
val rowId = cursor.getLong(cursor.getColumnIndexOrThrow(projection[0]))
|
||||||
|
val uri = ContentUris.withAppendedId(contentUri, rowId)
|
||||||
|
val mimetype = cursor.getString(cursor.getColumnIndexOrThrow(Images.Media.MIME_TYPE))
|
||||||
|
val date = cursor.getLong(cursor.getColumnIndexOrThrow(Images.Media.DATE_MODIFIED))
|
||||||
|
val orientation = cursor.getInt(cursor.getColumnIndexOrThrow(Images.Media.ORIENTATION))
|
||||||
|
val width = cursor.getInt(cursor.getColumnIndexOrThrow(getWidthColumn(orientation)))
|
||||||
|
val height = cursor.getInt(cursor.getColumnIndexOrThrow(getHeightColumn(orientation)))
|
||||||
|
val size = cursor.getLong(cursor.getColumnIndexOrThrow(Images.Media.SIZE))
|
||||||
|
media.add(Media(rowId, uri, mimetype, width, height, size, date))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
media
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWidthColumn(orientation: Int) = if (orientation == 0 || orientation == 180) Images.Media.WIDTH else Images.Media.HEIGHT
|
||||||
|
|
||||||
|
private fun getHeightColumn(orientation: Int) = if (orientation == 0 || orientation == 180) Images.Media.HEIGHT else Images.Media.WIDTH
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Media(
|
||||||
|
val id: Long,
|
||||||
|
val uri: Uri,
|
||||||
|
val mimeType: String,
|
||||||
|
val width: Int,
|
||||||
|
val height: Int,
|
||||||
|
val size: Long,
|
||||||
|
val dateModifiedEpochMillis: Long,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun isNotPending() = if (Build.VERSION.SDK_INT <= 28) Images.Media.DATA + " NOT NULL" else MediaStore.MediaColumns.IS_PENDING + " != 1"
|
||||||
|
|
Loading…
Reference in New Issue