Skip to content

Commit

Permalink
Improve image load performance
Browse files Browse the repository at this point in the history
  • Loading branch information
ismartcoding committed Jun 25, 2024
1 parent 92a5fed commit c509a8b
Show file tree
Hide file tree
Showing 159 changed files with 898 additions and 625 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ android {
else -> 0
}

val vCode = 313
val vCode = 316
versionCode = vCode - singleAbiNum
versionName = "1.3.0"
versionName = "1.3.1"

ndk {
//noinspection ChromeOsAbiSupport
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ismartcoding.lib.extensions
package com.ismartcoding.plain.extensions

import android.content.Context
import android.graphics.Bitmap
Expand All @@ -15,6 +15,12 @@ import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
import com.bumptech.glide.load.resource.bitmap.Downsampler
import com.bumptech.glide.request.RequestOptions
import com.caverock.androidsvg.SVG
import com.ismartcoding.lib.extensions.compress
import com.ismartcoding.lib.extensions.getMediaContentUri
import com.ismartcoding.lib.extensions.isAudioFast
import com.ismartcoding.lib.extensions.isPartialSupportVideo
import com.ismartcoding.lib.extensions.isVideoFast
import com.ismartcoding.lib.extensions.pathToMediaStoreUri
import com.ismartcoding.lib.isQPlus
import com.ismartcoding.lib.logcat.LogCat
import java.io.ByteArrayOutputStream
Expand Down Expand Up @@ -147,4 +153,4 @@ fun File.getDuration(context: Context): Long {
val time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
retriever.release()
return (time?.toLong()?.div(1000)) ?: 0L
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.ismartcoding.lib.extensions
package com.ismartcoding.plain.extensions

import android.widget.ImageView
import com.bumptech.glide.Glide
import com.ismartcoding.lib.extensions.isPartialSupportVideo
import com.ismartcoding.lib.helpers.CoroutinesHelper.coMain
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
import java.io.File
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ismartcoding.lib.extensions
package com.ismartcoding.plain.extensions

import android.util.TypedValue
import android.view.View
Expand Down
47 changes: 31 additions & 16 deletions app/src/main/java/com/ismartcoding/plain/features/NoteHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,27 @@ object NoteHelper {
suspend fun count(query: String): Int {
var sql = "SELECT COUNT(id) FROM notes"
val where = ContentWhere()
parseQuery(where, query)
sql += " WHERE ${where.toSelection()}"

return noteDao.count(SimpleSQLiteQuery(sql, where.args.toTypedArray()))
}

suspend fun getIdsAsync(query: String): Set<String> {
var sql = "SELECT id FROM notes"
val where = ContentWhere()
if (query.isNotEmpty()) {
parseQuery(where, query)
sql += " WHERE ${where.toSelection()}"
}

return noteDao.count(SimpleSQLiteQuery(sql, where.args.toTypedArray()))
return noteDao.getIds(SimpleSQLiteQuery(sql, where.args.toTypedArray())).map { it.id }.toSet()
}

suspend fun getIdsAsync(query: String): Set<String> {
suspend fun getTrashedIdsAsync(query: String): Set<String> {
var sql = "SELECT id FROM notes"
val where = ContentWhere()
where.trash = true
if (query.isNotEmpty()) {
parseQuery(where, query)
sql += " WHERE ${where.toSelection()}"
Expand All @@ -42,10 +52,8 @@ object NoteHelper {
): List<DNote> {
var sql = "SELECT * FROM notes"
val where = ContentWhere()
if (query.isNotEmpty()) {
parseQuery(where, query)
sql += " WHERE ${where.toSelection()}"
}
parseQuery(where, query)
sql += " WHERE ${where.toSelection()}"

sql += if (limit == Int.MAX_VALUE) {
" ORDER BY updated_at DESC"
Expand Down Expand Up @@ -124,7 +132,7 @@ object NoteHelper {
noteDao.trash(ids, now, now)
}

fun untrashAsync(ids: Set<String>) {
fun restoreAsync(ids: Set<String>) {
noteDao.trash(ids, null, Clock.System.now())
}

Expand All @@ -137,17 +145,24 @@ object NoteHelper {
query: String,
) {
QueryHelper.parseAsync(query).forEach {
if (it.name == "text") {
where.addLike("content", it.value)
} else if (it.name == "ids") {
where.addIn("id", it.value.split(","))
} else if (it.name == "trash") {
if (it.value == "true") {
where.add("deleted_at IS NOT NULL")
} else {
where.add("deleted_at IS NULL")
when (it.name) {
"text" -> {
where.addLike("content", it.value)
}

"ids" -> {
where.addIn("id", it.value.split(","))
}

"trash" -> {
where.trash = it.value.toBooleanStrictOrNull()
}
}
}
if (where.trash == true) {
where.add("deleted_at IS NOT NULL")
} else {
where.add("deleted_at IS NULL")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import android.os.StatFs
import android.os.storage.StorageManager
import android.provider.MediaStore
import android.text.TextUtils
import com.ismartcoding.lib.extensions.getDirectChildrenCount
import com.ismartcoding.plain.extensions.getDirectChildrenCount
import com.ismartcoding.lib.isRPlus
import com.ismartcoding.plain.R
import com.ismartcoding.plain.extensions.sorted
Expand All @@ -17,6 +17,7 @@ import kotlinx.datetime.Instant
import java.io.File
import java.util.Collections
import java.util.Locale
import java.util.PriorityQueue
import java.util.regex.Pattern

object FileSystemHelper {
Expand Down Expand Up @@ -121,8 +122,7 @@ object FileSystemHelper {
var rootDirs: Array<File>? = null
for (storageVolume in storageVolumes) {
if (storageVolume.isRemovable) {
var path = ""
path =
val path =
if (isRPlus()) {
storageVolume.directory.toString()
} else {
Expand Down Expand Up @@ -261,7 +261,6 @@ object FileSystemHelper {
}



fun getAllVolumeNames(context: Context): List<String> {
val volumeNames = mutableListOf(MediaStore.VOLUME_EXTERNAL_PRIMARY)
context.getExternalFilesDirs(null)
Expand All @@ -274,7 +273,37 @@ object FileSystemHelper {
return volumeNames
}

fun getRecentFiles(): List<File> {
val externalStorageDir = Environment.getExternalStorageDirectory()

val recentFilesQueue = PriorityQueue<File>(100) { f1, f2 ->
f1.lastModified().compareTo(f2.lastModified())
}

gatherRecentFiles(externalStorageDir, recentFilesQueue)

return recentFilesQueue.sortedByDescending { it.lastModified() }
}

private fun gatherRecentFiles(directory: File, recentFilesQueue: PriorityQueue<File>) {
val files = directory.listFiles()
if (files != null) {
for (file in files) {
if (file.isDirectory) {
gatherRecentFiles(file, recentFilesQueue)
} else {
if (recentFilesQueue.size < 100) {
recentFilesQueue.add(file)
} else {
if (file.lastModified() > (recentFilesQueue.peek()?.lastModified() ?: Long.MIN_VALUE)) {
recentFilesQueue.poll()
recentFilesQueue.add(file)
}
}
}
}
}
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ object AudioMediaStoreHelper : BaseMediaContentHelper() {
"artist" -> {
where.addEqual(MediaStore.Audio.Media.ARTIST, it.value)
}

"trash" -> {
where.trash = it.value.toBooleanStrictOrNull()
}
}
}
return where
Expand All @@ -80,7 +84,7 @@ object AudioMediaStoreHelper : BaseMediaContentHelper() {
val path = cursor.getStringValue(MediaStore.Audio.Media.DATA, cache)
val bucketId = cursor.getStringValue(MediaStore.Audio.Media.BUCKET_ID, cache)
val albumId = cursor.getStringValue(MediaStore.Audio.Media.ALBUM_ID, cache)
DAudio(id, title, artist, path, duration, size, bucketId,albumId, createdAt, updatedAt)
DAudio(id, title, artist, path, duration, size, bucketId, albumId, createdAt, updatedAt)
} ?: emptyList()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.ismartcoding.plain.features.media

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.BaseColumns
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import com.ismartcoding.lib.content.ContentWhere
import com.ismartcoding.lib.data.SortBy
import com.ismartcoding.lib.extensions.count
Expand Down Expand Up @@ -102,6 +106,17 @@ abstract class BaseMediaContentHelper {
}?.toSet() ?: emptySet()
}

suspend fun getTrashedIdsAsync(
context: Context,
query: String,
): Set<String> {
return context.contentResolver.getSearchCursor(
uriExternal, arrayOf(BaseColumns._ID), buildWhere(query).apply { trash = true }
)?.map { cursor, cache ->
cursor.getStringValue(BaseColumns._ID, cache)
}?.toSet() ?: emptySet()
}

protected suspend fun getSearchCursorAsync(
context: Context,
query: String,
Expand All @@ -114,12 +129,14 @@ abstract class BaseMediaContentHelper {
fun deleteRecordsAndFilesByIdsAsync(
context: Context,
ids: Set<String>,
trash: Boolean? = null,
): Set<String> {
val paths = mutableSetOf<String>()
val projection = arrayOf(BaseColumns._ID, MediaStore.MediaColumns.DATA)
ids.chunked(500).forEach { chunk ->
val where = ContentWhere()
where.addIn(BaseColumns._ID, chunk)
where.trash = trash
context.contentResolver.getSearchCursor(uriExternal, projection, where)?.forEach { cursor, cache ->
val id = cursor.getStringValue(BaseColumns._ID, cache)
val path = cursor.getStringValue(MediaStore.MediaColumns.DATA, cache)
Expand All @@ -143,6 +160,52 @@ abstract class BaseMediaContentHelper {
return paths
}

fun getPathsByIdsAsync(
context: Context,
ids: Set<String>,
): Set<String> {
val paths = mutableSetOf<String>()
val projection = arrayOf(BaseColumns._ID, MediaStore.MediaColumns.DATA)
ids.chunked(500).forEach { chunk ->
val where = ContentWhere()
where.addIn(BaseColumns._ID, chunk)
context.contentResolver.getSearchCursor(uriExternal, projection, where)?.forEach { cursor, cache ->
val path = cursor.getStringValue(MediaStore.MediaColumns.DATA, cache)
paths.add(path)
}
}

return paths
}

@RequiresApi(Build.VERSION_CODES.R)
fun trashByIdsAsync(
context: Context,
ids: Set<String>,
) {
val contentValues = ContentValues().apply {
// put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Trash")
put(MediaStore.MediaColumns.IS_TRASHED, 1)
}
ids.forEach { id ->
context.contentResolver.update(getItemUri(id), contentValues, null, null)
}
}

@RequiresApi(Build.VERSION_CODES.R)
fun restoreByIdsAsync(
context: Context,
ids: Set<String>,
) {
val contentValues = ContentValues().apply {
// put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Trash")
put(MediaStore.MediaColumns.IS_TRASHED, 0)
}
ids.forEach { id ->
context.contentResolver.update(getItemUri(id), contentValues, null, null)
}
}

fun getBucketsAsync(context: Context): List<DMediaBucket> {
val bucketMap = mutableMapOf<String, DMediaBucket>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,15 @@ object FileMediaStoreHelper : BaseContentHelper() {
return items.sorted(sortBy)
}

suspend fun getRecentFilesAsync(context: Context, query: String): List<DFile> {
suspend fun getRecentFilesAsync(context: Context): List<DFile> {
val where = ContentWhere()
where.addNotEqual(MediaStore.Files.FileColumns.MIME_TYPE, "vnd.android.document/directory")
return context.contentResolver.getPagingCursor(
uriExternal, getProjection(), buildWhereAsync(query),
uriExternal, getProjection(), where,
100, 0, FileSortBy.DATE_DESC.toFileSortBy()
)?.map { cursor, cache ->
cursorToFile(cursor, cache)
}?.filter { !it.isDir }?.take(50) ?: emptyList()
} ?: emptyList()
}

private fun cursorToFile(cursor: Cursor, cache: MutableMap<String, Int>): DFile {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ object ImageMediaStoreHelper : BaseMediaContentHelper() {
if (it.name == "text") {
where.add("${MediaStore.Images.Media.TITLE} LIKE ?", "%${it.value}%")
} else if (it.name == "bucket_id") {
where.add("${MediaStore.Images.Media.BUCKET_ID} = ?", it.value)
where.addEqual(MediaStore.Images.Media.BUCKET_ID, it.value)
} else if (it.name == "trash") {
where.trash = it.value.toBooleanStrictOrNull()
}
}
return where
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ object VideoMediaStoreHelper : BaseMediaContentHelper() {
if (it.name == "text") {
where.add("${MediaStore.Video.Media.TITLE} LIKE ?", "%${it.value}%")
} else if (it.name == "bucket_id") {
where.add("${MediaStore.Video.Media.BUCKET_ID} = ?", it.value)
where.addEqual(MediaStore.Video.Media.BUCKET_ID, it.value)
} else if (it.name == "trash") {
where.trash = it.value.toBooleanStrictOrNull()
}
}
return where
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.ismartcoding.lib.helpers
package com.ismartcoding.plain.helpers

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import com.ismartcoding.lib.extensions.getBitmapAsync
import com.ismartcoding.plain.extensions.getBitmapAsync
import java.io.File

object BitmapHelper {
fun decodeBitmapFromFileAsync(
suspend fun decodeBitmapFromFileAsync(
context: Context,
path: String,
reqWidth: Int,
Expand Down
Loading

0 comments on commit c509a8b

Please sign in to comment.