PlayerAndroid/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt

149 lines
4.9 KiB
Kotlin

/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.repository
import android.content.ContentResolver
import android.database.Cursor
import android.provider.BaseColumns
import android.provider.MediaStore.Audio.Genres
import code.name.monkey.retromusic.Constants.IS_MUSIC
import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.getString
import code.name.monkey.retromusic.extensions.getStringOrNull
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
interface GenreRepository {
fun genres(): List<Genre>
fun songs(genreId: Long): List<Song>
fun song(genreId: Long): Song
}
// TODO: move genre info into song model
class RealGenreRepository(
private val contentResolver: ContentResolver,
private val songRepository: RealSongRepository
) : GenreRepository {
override fun genres(): List<Genre> {
return getGenresFromCursor(makeGenreCursor())
}
override fun songs(genreId: Long): List<Song> {
// The genres table only stores songs that have a genre specified,
// so we need to get songs without a genre a different way.
return if (genreId == -1L) {
getSongsWithNoGenre()
} else songRepository.songs()
}
override fun song(genreId: Long): Song {
return songRepository.song(SongQuery())
}
private fun getGenreFromCursor(cursor: Cursor): Genre {
val id = cursor.getLong(Genres._ID)
val name = cursor.getStringOrNull(Genres.NAME)
val songCount = songs(id).size
return Genre(id, name ?: "", songCount)
}
private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre {
val id = cursor.getLong(Genres._ID)
val name = cursor.getString(Genres.NAME)
return Genre(id, name, -1)
}
private fun getSongsWithNoGenre(): List<Song> {
// TODO: do this somehow (probably by actually storing genres on songs in our model)
val selection =
BaseColumns._ID + " NOT IN " + "(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)"
return songRepository.songs()
}
private fun makeGenreSongCursor(genreId: Long): Cursor? {
return try {
contentResolver.query(
Genres.Members.getContentUri("external", genreId),
baseProjection,
IS_MUSIC,
null,
PreferenceUtil.songSortOrder
)
} catch (e: SecurityException) {
return null
}
}
private fun getGenresFromCursor(cursor: Cursor?): ArrayList<Genre> {
val genres = arrayListOf<Genre>()
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
val genre = getGenreFromCursor(cursor)
if (genre.songCount > 0) {
genres.add(genre)
} else {
// try to remove the empty genre from the media store
try {
contentResolver.delete(
Genres.EXTERNAL_CONTENT_URI,
Genres._ID + " == " + genre.id,
null
)
} catch (e: Exception) {
e.printStackTrace()
}
}
} while (cursor.moveToNext())
}
cursor.close()
}
return genres
}
private fun getGenresFromCursorForSearch(cursor: Cursor?): List<Genre> {
val genres = mutableListOf<Genre>()
if (cursor != null && cursor.moveToFirst()) {
do {
genres.add(getGenreFromCursorWithOutSongs(cursor))
} while (cursor.moveToNext())
}
cursor?.close()
return genres
}
private fun makeGenreCursor(): Cursor? {
val projection = arrayOf(Genres._ID, Genres.NAME)
return try {
contentResolver.query(
Genres.EXTERNAL_CONTENT_URI,
projection,
null,
null,
PreferenceUtil.genreSortOrder
)
} catch (e: SecurityException) {
return null
}
}
}