Skip to content

Commit

Permalink
Better playlist screen
Browse files Browse the repository at this point in the history
  • Loading branch information
maxrave-dev committed Jul 13, 2024
1 parent fe998dc commit c4c6d49
Show file tree
Hide file tree
Showing 10 changed files with 473 additions and 287 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import com.maxrave.simpmusic.data.model.browse.album.Track
import com.maxrave.simpmusic.databinding.ItemPopularSongBinding
import com.maxrave.simpmusic.extension.connectArtists
import com.maxrave.simpmusic.extension.toListName
import com.maxrave.simpmusic.extension.toVideoIdList

class PlaylistItemAdapter(private var playlistItemList: ArrayList<Any>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private lateinit var mListener: OnItemClickListener
Expand All @@ -35,12 +34,12 @@ class PlaylistItemAdapter(private var playlistItemList: ArrayList<Any>): Recycle
optionListener = listener
}

private var downloadedList = arrayListOf<SongEntity>()
private var downloadedList = arrayListOf<String>()
private var playingTrackVideoId: String? = null
fun setDownloadedList(downloadedList: ArrayList<SongEntity>?) {
val oldList = arrayListOf<SongEntity>()
fun setDownloadedList(downloadedList: Collection<String>?) {
val oldList = arrayListOf<String>()
oldList.addAll(this.downloadedList)
this.downloadedList = downloadedList ?: arrayListOf()
this.downloadedList = (downloadedList ?: arrayListOf()) as ArrayList<String>
playlistItemList.mapIndexed { index, result ->
if (result is SongEntity || result is Track) {
val videoId = when (result) {
Expand All @@ -49,12 +48,10 @@ class PlaylistItemAdapter(private var playlistItemList: ArrayList<Any>): Recycle
else -> null
}
if (downloadedList != null) {
if (downloadedList.toVideoIdList().contains(videoId) && !oldList.toVideoIdList()
.contains(videoId)
if (downloadedList.contains(videoId) && !oldList.contains(videoId)
) {
notifyItemChanged(index)
} else if (!downloadedList.toVideoIdList()
.contains(videoId) && oldList.toVideoIdList().contains(videoId)
} else if (!downloadedList.contains(videoId) && oldList.contains(videoId)
) {
notifyItemChanged(index)
}
Expand Down Expand Up @@ -103,7 +100,7 @@ class PlaylistItemAdapter(private var playlistItemList: ArrayList<Any>): Recycle
binding.ivThumbnail.load(track.thumbnails?.last()?.url)
binding.tvSongTitle.isSelected = true
binding.tvSongArtist.isSelected = true
if (downloadedList.toVideoIdList().contains(track.videoId)) {
if (downloadedList.contains(track.videoId)) {
binding.ivDownloaded.visibility = View.VISIBLE
} else {
binding.ivDownloaded.visibility = View.GONE
Expand Down Expand Up @@ -132,7 +129,7 @@ class PlaylistItemAdapter(private var playlistItemList: ArrayList<Any>): Recycle
binding.tvSongTitle.isSelected = true
binding.tvSongArtist.isSelected = true
binding.ivThumbnail.load(song.thumbnails)
if (downloadedList.toVideoIdList().contains(song.videoId)) {
if (downloadedList.contains(song.videoId)) {
binding.ivDownloaded.visibility = View.VISIBLE
} else {
binding.ivDownloaded.visibility = View.GONE
Expand All @@ -147,13 +144,15 @@ class PlaylistItemAdapter(private var playlistItemList: ArrayList<Any>): Recycle
}
}
fun updateList(newList: ArrayList<Any>){
Log.d("PlaylistItemAdapter", "updateList: $newList")
playlistItemList.clear()
newList.forEach {
playlistItemList.add(it)
if (newList != playlistItemList) {
Log.d("PlaylistItemAdapter", "updateList: $newList")
playlistItemList.clear()
newList.forEach {
playlistItemList.add(it)
}
Log.d("PlaylistItemAdapter", "updateList: $playlistItemList")
notifyDataSetChanged()
}
Log.d("PlaylistItemAdapter", "updateList: $playlistItemList")
notifyDataSetChanged()
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ interface DatabaseDao {
@Query("SELECT * FROM song WHERE downloadState = 3")
suspend fun getDownloadedSongs(): List<SongEntity>?

@Query("SELECT * FROM song WHERE downloadState = 3")
fun getDownloadedSongsAsFlow(): Flow<List<SongEntity>?>
@Query("SELECT * FROM song WHERE downloadState = 3 LIMIT 1000 OFFSET :offset")
fun getDownloadedSongsAsFlow(offset: Int): Flow<List<SongEntity>?>

@Query("SELECT * FROM song WHERE downloadState = 1 OR downloadState = 2")
suspend fun getDownloadingSongs(): List<SongEntity>?
Expand All @@ -188,6 +188,9 @@ interface DatabaseDao {
offset: Int,
): List<SongEntity>

@Query("SELECT videoId FROM song WHERE videoId IN (:primaryKeyList) AND downloadState = 3")
fun getDownloadedVideoIdByListVideoId(primaryKeyList: List<String>): Flow<List<String>>

// Artist
@Query("SELECT * FROM artist")
suspend fun getAllArtists(): List<ArtistEntity>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ class LocalDataSource

suspend fun getDownloadedSongs() = databaseDao.getDownloadedSongs()

suspend fun getDownloadedSongsAsFlow() = databaseDao.getDownloadedSongsAsFlow()
fun getDownloadedSongsAsFlow(offset: Int) = databaseDao.getDownloadedSongsAsFlow(offset)

fun getDownloadedVideoIdListFromListVideoIdAsFlow(listVideoId: List<String>) =
databaseDao.getDownloadedVideoIdByListVideoId(listVideoId)

suspend fun getDownloadingSongs() = databaseDao.getDownloadingSongs()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class MainRepository

suspend fun getDownloadedSongs(): Flow<List<SongEntity>?> = flow { emit(localDataSource.getDownloadedSongs()) }.flowOn(Dispatchers.IO)

suspend fun getDownloadedSongsAsFlow() = localDataSource.getDownloadedSongsAsFlow()
fun getDownloadedSongsAsFlow(offset: Int) = localDataSource.getDownloadedSongsAsFlow(offset)

suspend fun getDownloadingSongs(): Flow<List<SongEntity>?> = flow { emit(localDataSource.getDownloadingSongs()) }.flowOn(Dispatchers.IO)

Expand All @@ -162,6 +162,9 @@ class MainRepository
emit(localDataSource.getPreparingSongs())
}.flowOn(Dispatchers.IO)

fun getDownloadedVideoIdListFromListVideoIdAsFlow(listVideoId: List<String>) =
localDataSource.getDownloadedVideoIdListFromListVideoIdAsFlow(listVideoId)

suspend fun getLikedSongs(): Flow<List<SongEntity>> =
flow {
emit(localDataSource.getLikedSongs())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,22 @@ import androidx.media3.datasource.cache.SimpleCache
import androidx.media3.exoplayer.offline.Download
import androidx.media3.exoplayer.offline.DownloadManager
import androidx.media3.exoplayer.offline.DownloadNotificationHelper
import com.maxrave.simpmusic.common.DownloadState
import com.maxrave.simpmusic.data.repository.MainRepository
import com.maxrave.simpmusic.di.DownloadCache
import com.maxrave.simpmusic.di.PlayerCache
import com.maxrave.simpmusic.service.test.download.MusicDownloadService.Companion.CHANNEL_ID
import com.maxrave.simpmusic.service.test.source.MergingMediaSourceFactory
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.concurrent.Executors
import javax.inject.Inject
Expand All @@ -39,7 +43,7 @@ class DownloadUtils @Inject constructor(
private val mainRepository: MainRepository,
databaseProvider: DatabaseProvider
) {

private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

private val dataSourceFactory = ResolvingDataSource.Factory(
CacheDataSource.Factory()
Expand Down Expand Up @@ -107,11 +111,10 @@ class DownloadUtils @Inject constructor(
)
}
val downloads = MutableStateFlow<Map<String, Download>>(emptyMap())
val downloadingVideoIds = MutableStateFlow<MutableSet<String>>(mutableSetOf())

fun getDownload(songId: String): Flow<Download?> = downloads.map { it[songId] }

fun getAllDownloads(): Flow<List<Download>> = downloads.map { it.values.toList() }

init {
val result = mutableMapOf<String, Download>()
val cursor = downloadManager.downloadIndex.getDownloads()
Expand All @@ -126,6 +129,95 @@ class DownloadUtils @Inject constructor(
download: Download,
finalException: Exception?
) {
download.request.id.let { id ->
val songId = if (id.contains(MergingMediaSourceFactory.isVideo)) {
id.removePrefix(MergingMediaSourceFactory.isVideo)
} else {
id
}
when(download.state) {
Download.STATE_COMPLETED -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
remove(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_DOWNLOADED)
}
playerCache.removeResource(id)
}

Download.STATE_DOWNLOADING -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
add(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_DOWNLOADING)
}
}

Download.STATE_FAILED -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
remove(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_NOT_DOWNLOADED)
}
}

Download.STATE_QUEUED -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
add(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_PREPARING)
}
}

Download.STATE_REMOVING -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
remove(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_NOT_DOWNLOADED)
}
}

Download.STATE_RESTARTING -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
add(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_DOWNLOADING)
}
}

Download.STATE_STOPPED -> {
coroutineScope.launch {
downloadingVideoIds.update {
it.apply {
remove(songId)
}
}
mainRepository.updateDownloadState(songId, DownloadState.STATE_NOT_DOWNLOADED)
}
}
else -> {

}
}
}
downloads.update { map ->
map.toMutableMap().apply {
val id = download.request.id
Expand All @@ -137,12 +229,7 @@ class DownloadUtils @Inject constructor(
}
}
}
if (download.state == Download.STATE_COMPLETED && playerCache.keys.contains(
download.request.id
)
) {
playerCache.removeResource(download.request.id)
}

}
}
)
Expand Down
Loading

0 comments on commit c4c6d49

Please sign in to comment.