Skip to content

Commit

Permalink
[DynamicDatabaseLoader] redesign to fix orderless results
Browse files Browse the repository at this point in the history
  • Loading branch information
chr56 committed Jan 14, 2025
1 parent 705bf8f commit 018fcde
Showing 1 changed file with 46 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022~2023 chr_56
* Copyright (c) 2022~2025 chr_56
*/
package player.phonograph.repo.mediastore.loaders

Expand All @@ -11,15 +11,23 @@ import player.phonograph.repo.database.SongPlayCountStore
import player.phonograph.repo.mediastore.internal.intoSongs
import player.phonograph.repo.mediastore.internal.querySongs
import android.content.Context
import android.database.Cursor
import android.provider.BaseColumns

class TopTracksLoader(private val songPlayCountStore: SongPlayCountStore) :
DynamicDatabaseLoader(songPlayCountStore) {
DynamicDatabaseLoader(songPlayCountStore, NUMBER_OF_TOP_TRACKS) {

override fun queryCursorImpl(context: Context): Cursor? =
songPlayCountStore.getTopPlayedResults(NUMBER_OF_TOP_TRACKS)
.intoSongCursor(context, SongPlayCountStore.SongPlayCountColumns.ID)
override fun fetch(context: Context): LongArray? {
val cursor = songPlayCountStore.getTopPlayedResults(0)
val results = mutableListOf<Long>()
if (cursor.moveToFirst()) {
val idColumnIndex = cursor.getColumnIndex(SongPlayCountStore.SongPlayCountColumns.ID)
do {
val id = cursor.getLong(idColumnIndex)
results.add(id)
} while (cursor.moveToNext())
}
return results.toLongArray()
}

companion object {
private const val NUMBER_OF_TOP_TRACKS = 150
Expand All @@ -30,71 +38,46 @@ class TopTracksLoader(private val songPlayCountStore: SongPlayCountStore) :
class RecentlyPlayedTracksLoader(private val historyStore: HistoryStore) :
DynamicDatabaseLoader(historyStore) {

override fun queryCursorImpl(context: Context): Cursor? =
historyStore.queryRecentIds()
.intoSongCursor(context, HistoryStore.RecentStoreColumns.ID)
override fun fetch(context: Context): LongArray? {
val cursor = historyStore.queryRecentIds()
val results = mutableListOf<Long>()
if (cursor.moveToFirst()) {
val idColumnIndex = cursor.getColumnIndex(HistoryStore.RecentStoreColumns.ID)
do {
val id = cursor.getLong(idColumnIndex)
results.add(id)
} while (cursor.moveToNext())
}
return results.toLongArray()
}

companion object {
fun get() = GlobalContext.get().get<RecentlyPlayedTracksLoader>()
}
}

abstract class DynamicDatabaseLoader(private val db: Any) {

fun tracks(context: Context): List<Song> = queryCursorAndClear(context).intoSongs()

protected abstract fun queryCursorImpl(context: Context): Cursor?

protected fun queryCursorAndClear(context: Context): Cursor? {

val songCursor = queryCursorImpl(context) ?: return null

abstract class DynamicDatabaseLoader(private val db: Any, private val limit: Int = -1) {

protected abstract fun fetch(context: Context): LongArray?

fun tracks(context: Context): List<Song> {
val ids: LongArray = fetch(context) ?: return emptyList()
val songs = ids.map { id ->
val songs = querySongs(
context,
selection = "${BaseColumns._ID} = ?",
selectionValues = arrayOf(id.toString())
).intoSongs()
if (songs.isNotEmpty()) {
songs.first()
} else {
null
}
}.filterNotNull()
if (db is ShallowDatabase) {
// clean up the databases with any ids not found
val exists = songIds(songCursor)
db.gc(exists)
db.gc(songs.map { it.id })
}

return songCursor
}

private fun songIds(songCursor: Cursor): List<Long> {
val exists = mutableListOf<Long>()
if (songCursor.moveToFirst()) {
val index = songCursor.getColumnIndex(BaseColumns._ID)
do {
val id = songCursor.getLong(index)
if (id > 0) exists.add(id)
} while (songCursor.moveToNext())
}
return exists
}

protected fun Cursor.intoSongCursor(context: Context, idColumnName: String): Cursor? =
use { cursor -> generateSongCursor(context, cursor, idColumnName) }

protected fun generateSongCursor(context: Context, cursor: Cursor, idColumnName: String): Cursor? {
val count = cursor.count
val idColumnIndex = cursor.getColumnIndex(idColumnName)

if (count < 0 || idColumnIndex < 0) return null

cursor.moveToFirst()
val selectionPlaceHolder = when {
count > 1 -> "?" + ",?".repeat(count - 1)
count == 1 -> "?"
else -> return null // empty cursor
}

val ids = Array(count) {
cursor.getLong(idColumnIndex).toString().also { cursor.moveToNext() }
}

return querySongs(
context,
selection = "${BaseColumns._ID} IN ( $selectionPlaceHolder )",
selectionValues = ids
)
return if (limit > 0) songs.take(limit) else songs
}

}

0 comments on commit 018fcde

Please sign in to comment.