Skip to content

Commit

Permalink
chore: Use Thumbnails module
Browse files Browse the repository at this point in the history
  • Loading branch information
tevincent committed Feb 14, 2025
1 parent f6277b2 commit ae5c640
Show file tree
Hide file tree
Showing 5 changed files with 6 additions and 154 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ dependencies {
implementation project(path: ':Core:Legacy')
implementation project(path: ':Core:Legacy:AppLock')
implementation project(path: ':Core:Legacy:Stores')
implementation project(path: ':Core:Thumbnails')

def work_version = '2.9.1' // Keep the same version as the one in Core
implementation "androidx.work:work-runtime-ktx:$work_version"
Expand Down
111 changes: 3 additions & 108 deletions app/src/main/java/com/infomaniak/drive/utils/FileItemUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,12 @@
*/
package com.infomaniak.drive.utils

import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
import android.media.ThumbnailUtils
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Size
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.graphics.toColorInt
import androidx.core.net.toFile
import androidx.core.net.toUri
import androidx.core.view.forEachIndexed
import androidx.core.view.isGone
Expand All @@ -41,6 +31,7 @@ import androidx.core.view.isVisible
import androidx.viewbinding.ViewBinding
import coil.load
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.infomaniak.core.thumbnails.ThumbnailsUtils.getLocalThumbnail
import com.infomaniak.drive.R
import com.infomaniak.drive.data.api.ApiRoutes
import com.infomaniak.drive.data.cache.DriveInfosController
Expand All @@ -56,7 +47,6 @@ import com.infomaniak.drive.views.CategoryIconView
import com.infomaniak.drive.views.ProgressLayoutView
import com.infomaniak.lib.core.utils.context
import com.infomaniak.lib.core.utils.format
import io.sentry.Sentry
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -143,7 +133,8 @@ private fun ImageView.displayFileIcon(
file.isFromUploads && isGraphic -> {
scaleType = ImageView.ScaleType.CENTER_CROP
CoroutineScope(Dispatchers.IO).launch {
val bitmap = context.getLocalThumbnail(file)
val isVideo = file.getMimeType().contains("video")
val bitmap = context.getLocalThumbnail(file.path.toUri(), isVideo, 100)
withContext(Dispatchers.Main) {
if (isVisible && context != null) loadAny(bitmap, fileType.icon)
}
Expand Down Expand Up @@ -216,102 +207,6 @@ fun File.getFolderIcon(): Pair<Int, String?> {
}
}

suspend fun Context.getLocalThumbnail(file: File): Bitmap? = withContext(Dispatchers.IO) {
val fileUri = file.path.toUri()
val thumbnailSize = 100
return@withContext if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
getThumbnailAfterAndroidPie(file, fileUri, thumbnailSize)
} else {
getThumbnailUntilAndroidPie(file, fileUri, thumbnailSize)
}
}

private fun Context.getThumbnailAfterAndroidPie(file: File, fileUri: Uri, thumbnailSize: Int): Bitmap? {
return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
val size = Size(thumbnailSize, thumbnailSize)
try {
if (fileUri.scheme.equals(ContentResolver.SCHEME_FILE)) {
if (file.getMimeType().contains("video")) {
ThumbnailUtils.createVideoThumbnail(fileUri.toFile(), size, null)
} else {
ThumbnailUtils.createImageThumbnail(fileUri.toFile(), size, null)
}
} else {
contentResolver.loadThumbnail(fileUri, size, null)
}
} catch (e: Exception) {
null
}
} else {
null
}
}

private fun Context.getThumbnailUntilAndroidPie(file: File, fileUri: Uri, thumbnailSize: Int): Bitmap? {
val isSchemeFile = fileUri.scheme.equals(ContentResolver.SCHEME_FILE)
val localFile = fileUri.lastPathSegment?.split(":")?.let { list ->
list.getOrNull(1)?.let { path -> IOFile(path) }
}
val externalRealPath = getExternalRealPath(fileUri, isSchemeFile, localFile)

return if (isSchemeFile || externalRealPath.isNotBlank()) {
getBitmapFromPath(file, fileUri, thumbnailSize, externalRealPath)
} else {
getBitmapFromFileId(fileUri, thumbnailSize)
}
}

private fun Context.getExternalRealPath(fileUri: Uri, isSchemeFile: Boolean, localFile: IOFile?): String {
return when {
!isSchemeFile && localFile?.exists() == true -> {
Sentry.captureMessage("Uri contains absolute path")
localFile.absolutePath
}
fileUri.authority == "com.android.externalstorage.documents" -> {
Utils.getRealPathFromExternalStorage(this, fileUri)
}
else -> ""
}
}

private fun getBitmapFromPath(file: File, fileUri: Uri, thumbnailSize: Int, externalRealPath: String): Bitmap? {
val path = externalRealPath.ifBlank { fileUri.path ?: return null }

return if (file.getMimeType().contains("video")) {
ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MICRO_KIND)
} else {
Utils.extractThumbnail(path, thumbnailSize, thumbnailSize)
}
}

private fun Context.getBitmapFromFileId(fileUri: Uri, thumbnailSize: Int): Bitmap? {
return try {
ContentUris.parseId(fileUri)
} catch (e: Exception) {
fileUri.lastPathSegment?.split(":")?.let { it.getOrNull(1)?.toLongOrNull() }
}?.let { fileId ->
val options = BitmapFactory.Options().apply {
outWidth = thumbnailSize
outHeight = thumbnailSize
}
if (contentResolver.getType(fileUri)?.contains("video") == true) {
MediaStore.Video.Thumbnails.getThumbnail(
contentResolver,
fileId,
MediaStore.Video.Thumbnails.MICRO_KIND,
options,
)
} else {
MediaStore.Images.Thumbnails.getThumbnail(
contentResolver,
fileId,
MediaStore.Images.Thumbnails.MICRO_KIND,
options,
)
}
}
}

fun ProgressLayoutView.setupFileProgress(file: File, containsProgress: Boolean = false) {
when {
!containsProgress && file.isMarkedAsOffline -> {
Expand Down
44 changes: 0 additions & 44 deletions app/src/main/java/com/infomaniak/drive/utils/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,8 @@ import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.view.LayoutInflater
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.DrawableRes
Expand Down Expand Up @@ -69,7 +65,6 @@ import com.infomaniak.lib.core.utils.DownloadManagerUtils
import com.infomaniak.lib.core.utils.showKeyboard
import com.infomaniak.lib.core.utils.showToast
import java.util.Date
import kotlin.math.min
import kotlin.math.pow

object Utils {
Expand Down Expand Up @@ -415,45 +410,6 @@ object Utils {
return outputFile.toUri()
}

/**
* From file path
*/
@Deprecated(message = "Only for API 28 and below, otherwise use ThumbnailUtils.createImageThumbnail()")
fun extractThumbnail(filePath: String, width: Int, height: Int): Bitmap? {
val bitmapOptions = BitmapFactory.Options()
bitmapOptions.inJustDecodeBounds = true
BitmapFactory.decodeFile(filePath, bitmapOptions)

val widthScale = bitmapOptions.outWidth.toFloat() / width
val heightScale = bitmapOptions.outHeight.toFloat() / height
val scale = min(widthScale, heightScale)
var sampleSize = 1
while (sampleSize < scale) {
sampleSize *= 2
}
bitmapOptions.inSampleSize = sampleSize
bitmapOptions.inJustDecodeBounds = false

return BitmapFactory.decodeFile(filePath, bitmapOptions)
}

fun getRealPathFromExternalStorage(context: Context, uri: Uri): String {
// ExternalStorageProvider
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split.first()
val relativePath = split.getOrNull(1) ?: return ""
val external = context.externalMediaDirs
return when {
"primary".equals(type, true) -> Environment.getExternalStorageDirectory().toString() + "/" + relativePath
external.size > 1 -> {
val filePath = external[1].absolutePath
filePath.substring(0, filePath.indexOf("Android")) + relativePath
}
else -> ""
}
}

fun createProgressDialog(context: Context, title: Int): AlertDialog {
return MaterialAlertDialogBuilder(context, R.style.DialogStyle).apply {
setTitle(title)
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ dependencyResolutionManagement {
}

rootProject.name = "kDrive"
include ':app', ':Core:Legacy', ':Core:Legacy:AppLock', ':Core:Legacy:Stores'
include ':app', ':Core:Legacy', ':Core:Legacy:AppLock', ':Core:Legacy:Stores', ':Core:Thumbnails'

0 comments on commit ae5c640

Please sign in to comment.