mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-04-19 10:37:42 +03:00
Fixed updating button states in TrackCollectionFragment according to track states
This commit is contained in:
parent
4be7769cb5
commit
f6f524f5a9
@ -1,6 +1,5 @@
|
||||
package org.moire.ultrasonic.adapters
|
||||
|
||||
import android.graphics.drawable.AnimationDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.widget.Checkable
|
||||
@ -94,8 +93,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
|
||||
setupStarButtons(song, useFiveStarRating)
|
||||
}
|
||||
|
||||
updateStatus(downloader.getDownloadState(song))
|
||||
updateProgress(0)
|
||||
updateStatus(downloader.getDownloadState(song), null)
|
||||
|
||||
if (useFiveStarRating) {
|
||||
setFiveStars(entry?.userRating ?: 0)
|
||||
@ -116,8 +114,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
|
||||
|
||||
rxBusSubscription!! += RxBus.trackDownloadStateObservable.subscribe {
|
||||
if (it.id != song.id) return@subscribe
|
||||
updateStatus(it.state)
|
||||
updateProgress(it.progress)
|
||||
updateStatus(it.state, it.progress)
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,52 +204,49 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateStatus(status: DownloadStatus) {
|
||||
if (status == cachedStatus) return
|
||||
cachedStatus = status
|
||||
private fun updateStatus(status: DownloadStatus, p: Int?) {
|
||||
if (status != cachedStatus) {
|
||||
cachedStatus = status
|
||||
|
||||
when (status) {
|
||||
DownloadStatus.DONE -> {
|
||||
statusImage = imageHelper.downloadedImage
|
||||
progress.text = null
|
||||
}
|
||||
DownloadStatus.PINNED -> {
|
||||
statusImage = imageHelper.pinImage
|
||||
progress.text = null
|
||||
}
|
||||
DownloadStatus.FAILED,
|
||||
DownloadStatus.CANCELLED -> {
|
||||
statusImage = imageHelper.errorImage
|
||||
progress.text = null
|
||||
}
|
||||
DownloadStatus.DOWNLOADING -> {
|
||||
statusImage = imageHelper.downloadingImage
|
||||
}
|
||||
else -> {
|
||||
statusImage = null
|
||||
when (status) {
|
||||
DownloadStatus.DONE -> {
|
||||
statusImage = imageHelper.downloadedImage
|
||||
progress.text = null
|
||||
}
|
||||
DownloadStatus.PINNED -> {
|
||||
statusImage = imageHelper.pinImage
|
||||
progress.text = null
|
||||
}
|
||||
DownloadStatus.FAILED,
|
||||
DownloadStatus.CANCELLED -> {
|
||||
statusImage = imageHelper.errorImage
|
||||
progress.text = null
|
||||
}
|
||||
DownloadStatus.DOWNLOADING -> {
|
||||
statusImage = imageHelper.downloadingImage[0]
|
||||
}
|
||||
else -> {
|
||||
statusImage = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cachedStatus == DownloadStatus.DOWNLOADING && p != null) {
|
||||
progress.text = Util.formatPercentage(p)
|
||||
statusImage =
|
||||
imageHelper.downloadingImage[(imageHelper.downloadingImage.size / 100F * p).toInt()]
|
||||
} else {
|
||||
progress.text = null
|
||||
}
|
||||
|
||||
updateImages()
|
||||
}
|
||||
|
||||
private fun updateProgress(p: Int) {
|
||||
if (cachedStatus == DownloadStatus.DOWNLOADING) {
|
||||
progress.text = Util.formatPercentage(p)
|
||||
} else {
|
||||
progress.text = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateImages() {
|
||||
progress.setCompoundDrawablesWithIntrinsicBounds(
|
||||
null, null, statusImage, null
|
||||
)
|
||||
|
||||
if (statusImage === imageHelper.downloadingImage) {
|
||||
val frameAnimation = statusImage as AnimationDrawable?
|
||||
frameAnimation?.setVisible(true, true)
|
||||
frameAnimation?.start()
|
||||
progress.post {
|
||||
progress.setCompoundDrawablesWithIntrinsicBounds(
|
||||
null, null, statusImage, null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ object Utils {
|
||||
lateinit var errorImage: Drawable
|
||||
lateinit var pinImage: Drawable
|
||||
lateinit var downloadedImage: Drawable
|
||||
lateinit var downloadingImage: Drawable
|
||||
lateinit var downloadingImage: List<Drawable>
|
||||
lateinit var playingImage: Drawable
|
||||
var theme: String
|
||||
|
||||
@ -63,7 +63,15 @@ object Utils {
|
||||
downloadedImage =
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_0)!!
|
||||
errorImage = ContextCompat.getDrawable(context, R.drawable.ic_baseline_error)!!
|
||||
downloadingImage = ContextCompat.getDrawable(context, R.drawable.stat_sys_download)!!
|
||||
downloadingImage = listOf(
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_1)!!,
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_2)!!,
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_3)!!,
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_4)!!,
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_5)!!,
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_6)!!,
|
||||
ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_7)!!,
|
||||
)
|
||||
playingImage = ContextCompat.getDrawable(context, R.drawable.ic_stat_play)!!
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import java.util.Collections
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
@ -39,6 +40,8 @@ import org.moire.ultrasonic.model.TrackCollectionModel
|
||||
import org.moire.ultrasonic.service.DownloadStatus
|
||||
import org.moire.ultrasonic.service.Downloader
|
||||
import org.moire.ultrasonic.service.MediaPlayerController
|
||||
import org.moire.ultrasonic.service.RxBus
|
||||
import org.moire.ultrasonic.service.plusAssign
|
||||
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
||||
import org.moire.ultrasonic.subsonic.ShareHandler
|
||||
import org.moire.ultrasonic.subsonic.VideoPlayer
|
||||
@ -83,6 +86,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
||||
internal var cancellationToken: CancellationToken? = null
|
||||
|
||||
override val listModel: TrackCollectionModel by viewModels()
|
||||
private val rxBusSubscription: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
/**
|
||||
* The id of the main layout
|
||||
@ -143,6 +147,14 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
||||
)
|
||||
)
|
||||
|
||||
// Change the buttons if the status of any selected track changes
|
||||
rxBusSubscription += RxBus.trackDownloadStateObservable.subscribe {
|
||||
if (it.progress != null) return@subscribe
|
||||
val selectedSongs = getSelectedSongs()
|
||||
if (!selectedSongs.any { song -> song.id == it.id }) return@subscribe
|
||||
enableButtons(selectedSongs)
|
||||
}
|
||||
|
||||
enableButtons()
|
||||
|
||||
// Update the buttons when the selection has changed
|
||||
@ -261,6 +273,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
||||
|
||||
override fun onDestroyView() {
|
||||
cancellationToken!!.cancel()
|
||||
rxBusSubscription.dispose()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@ -356,10 +369,12 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
internal open fun enableButtons(selection: List<Track> = getSelectedSongs()) {
|
||||
val enabled = selection.isNotEmpty()
|
||||
var unpinEnabled = false
|
||||
var deleteEnabled = false
|
||||
var downloadEnabled = false
|
||||
val multipleSelection = viewAdapter.hasMultipleSelection()
|
||||
|
||||
var pinnedCount = 0
|
||||
@ -373,6 +388,9 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
||||
pinnedCount++
|
||||
unpinEnabled = true
|
||||
}
|
||||
if (state == DownloadStatus.IDLE || state == DownloadStatus.FAILED) {
|
||||
downloadEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
playNowButton?.isVisible = enabled
|
||||
@ -380,7 +398,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Child>() {
|
||||
playLastButton?.isVisible = enabled && multipleSelection
|
||||
pinButton?.isVisible = (enabled && !isOffline() && selection.size > pinnedCount)
|
||||
unpinButton?.isVisible = (enabled && unpinEnabled)
|
||||
downloadButton?.isVisible = (enabled && !deleteEnabled && !isOffline())
|
||||
downloadButton?.isVisible = (enabled && downloadEnabled && !isOffline())
|
||||
deleteButton?.isVisible = (enabled && deleteEnabled)
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ class Downloader(
|
||||
val existingItem = downloadQueue.firstOrNull { it.track.id == track.id }
|
||||
if (existingItem != null) {
|
||||
existingItem.priority = priority + 1
|
||||
return
|
||||
continue
|
||||
}
|
||||
|
||||
// Set correct priority (the lower the number, the higher the priority)
|
||||
@ -267,7 +267,9 @@ class Downloader(
|
||||
fun downloadBackground(tracks: List<Track>, save: Boolean) {
|
||||
// By using the counter we ensure that the songs are added in the correct order
|
||||
for (track in tracks) {
|
||||
if (downloadQueue.any { t -> t.track.id == track.id }) continue
|
||||
if (downloadQueue.any { t -> t.track.id == track.id } ||
|
||||
activelyDownloading.any { t -> t.key.track.id == track.id }
|
||||
) continue
|
||||
val file = DownloadableTrack(track, save, 0, backgroundPriorityCounter++)
|
||||
downloadQueue.add(file)
|
||||
}
|
||||
@ -281,7 +283,7 @@ class Downloader(
|
||||
Storage.delete(track.getPartialFile())
|
||||
Storage.delete(track.getCompleteFile())
|
||||
Storage.delete(track.getPinnedFile())
|
||||
postState(track, DownloadStatus.IDLE, 0)
|
||||
postState(track, DownloadStatus.IDLE)
|
||||
Util.scanMedia(track.getPinnedFile())
|
||||
}
|
||||
|
||||
@ -295,7 +297,7 @@ class Downloader(
|
||||
if (!Storage.isPathExists(pinnedFile)) return
|
||||
val file = Storage.getFromPath(track.getPinnedFile()) ?: return
|
||||
Storage.rename(file, track.getCompleteFile())
|
||||
postState(track, DownloadStatus.DONE, 100)
|
||||
postState(track, DownloadStatus.DONE)
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
@ -318,7 +320,7 @@ class Downloader(
|
||||
const val REFRESH_INTERVAL = 100
|
||||
}
|
||||
|
||||
private fun postState(track: Track, state: DownloadStatus, progress: Int) {
|
||||
private fun postState(track: Track, state: DownloadStatus, progress: Int? = null) {
|
||||
RxBus.trackDownloadStatePublisher.onNext(
|
||||
RxBus.TrackDownloadState(
|
||||
track.id,
|
||||
@ -340,7 +342,7 @@ class Downloader(
|
||||
try {
|
||||
if (Storage.isPathExists(item.pinnedFile)) {
|
||||
Timber.i("%s already exists. Skipping.", item.pinnedFile)
|
||||
postState(item.track, DownloadStatus.PINNED, 100)
|
||||
postState(item.track, DownloadStatus.PINNED)
|
||||
return
|
||||
}
|
||||
|
||||
@ -365,11 +367,11 @@ class Downloader(
|
||||
} catch (ignore: Exception) {
|
||||
Timber.w(ignore)
|
||||
}
|
||||
postState(item.track, newStatus, 100)
|
||||
postState(item.track, newStatus)
|
||||
return
|
||||
}
|
||||
|
||||
postState(item.track, DownloadStatus.DOWNLOADING, 0)
|
||||
postState(item.track, DownloadStatus.DOWNLOADING)
|
||||
|
||||
// Some devices seem to throw error on partial file which doesn't exist
|
||||
val needsDownloading: Boolean
|
||||
@ -415,7 +417,7 @@ class Downloader(
|
||||
outputStream.close()
|
||||
|
||||
if (isCancelled) {
|
||||
postState(item.track, DownloadStatus.CANCELLED, 0)
|
||||
postState(item.track, DownloadStatus.CANCELLED)
|
||||
throw RuntimeException(
|
||||
String.format(
|
||||
Locale.ROOT, "Download of '%s' was cancelled",
|
||||
@ -436,14 +438,14 @@ class Downloader(
|
||||
item.partialFile,
|
||||
item.pinnedFile
|
||||
)
|
||||
postState(item.track, DownloadStatus.PINNED, 100)
|
||||
postState(item.track, DownloadStatus.PINNED)
|
||||
Util.scanMedia(item.pinnedFile)
|
||||
} else {
|
||||
Storage.rename(
|
||||
item.partialFile,
|
||||
item.completeFile
|
||||
)
|
||||
postState(item.track, DownloadStatus.DONE, 100)
|
||||
postState(item.track, DownloadStatus.DONE)
|
||||
}
|
||||
} catch (all: Exception) {
|
||||
outputStream.safeClose()
|
||||
@ -451,12 +453,12 @@ class Downloader(
|
||||
Storage.delete(item.pinnedFile)
|
||||
if (!isCancelled) {
|
||||
if (item.tryCount < MAX_RETRIES) {
|
||||
postState(item.track, DownloadStatus.RETRYING, 0)
|
||||
postState(item.track, DownloadStatus.RETRYING)
|
||||
item.tryCount++
|
||||
activelyDownloading.remove(item)
|
||||
downloadQueue.add(item)
|
||||
} else {
|
||||
postState(item.track, DownloadStatus.FAILED, 0)
|
||||
postState(item.track, DownloadStatus.FAILED)
|
||||
activelyDownloading.remove(item)
|
||||
downloadQueue.remove(item)
|
||||
failedList.add(item)
|
||||
|
@ -91,7 +91,7 @@ class RxBus {
|
||||
data class TrackDownloadState(
|
||||
val id: String,
|
||||
val state: DownloadStatus,
|
||||
val progress: Int
|
||||
val progress: Int?
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/common/res/drawable/status_icon_background.xml
|
||||
**
|
||||
** Copyright 2008, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<animation-list
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_0" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_1" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_2" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_3" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_4" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_5" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_6" android:duration="200" />
|
||||
<item android:drawable="@drawable/stat_sys_download_anim_7" android:duration="200" />
|
||||
</animation-list>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M15,5V3H9v2"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="M9,5V9H5l7,7 7,-7H15V5M5,18v2h14v-2z"/>
|
||||
</vector>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M15,7V3H9v4"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="M9,7V9H5l7,7 7,-7H15V7M5,18v2h14v-2z"/>
|
||||
</vector>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M15,9V3H9v6"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="M9,9H5l7,7 7,-7H15M5,18v2h14v-2z"/>
|
||||
</vector>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M17,11 L19,9H15V3H9V9H5l2,2"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="m7,11 l5,5 5,-5M5,18v2h14v-2z"/>
|
||||
</vector>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M15,13 L19,9H15V3H9V9H5l4,4"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="m9,13 l3,3 3,-3M5,18v2h14v-2z"/>
|
||||
</vector>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M13,15 L19,9H15V3H9V9H5l6,6"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="m11,15 l1,1 1,-1m-8,3v2h14v-2z"/>
|
||||
</vector>
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M19,9H15V3H9V9H5l7,7z"/>
|
||||
<path
|
||||
android:fillColor="#888"
|
||||
android:fillColor="#FFF"
|
||||
android:fillAlpha="150"
|
||||
android:pathData="m5,18v2h14v-2z"/>
|
||||
</vector>
|
||||
|
Loading…
x
Reference in New Issue
Block a user