diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ImageHelper.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ImageHelper.kt index 174c449c..2ce33a51 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ImageHelper.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ImageHelper.kt @@ -11,6 +11,7 @@ import org.moire.ultrasonic.util.Util */ class ImageHelper(context: Context) { + lateinit var errorImage: Drawable lateinit var starHollowDrawable: Drawable lateinit var starDrawable: Drawable lateinit var pinImage: Drawable @@ -39,6 +40,7 @@ class ImageHelper(context: Context) { starDrawable = Util.getDrawableFromAttribute(context, R.attr.star_full) pinImage = Util.getDrawableFromAttribute(context, R.attr.pin) downloadedImage = Util.getDrawableFromAttribute(context, R.attr.downloaded) + errorImage = Util.getDrawableFromAttribute(context, R.attr.error) downloadingImage = Util.getDrawableFromAttribute(context, R.attr.downloading) playingImage = Util.getDrawableFromAttribute(context, R.attr.media_play_small) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/MultiTypeDiffAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/MultiTypeDiffAdapter.kt index 31de8366..0a40fbc5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/MultiTypeDiffAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/MultiTypeDiffAdapter.kt @@ -1,7 +1,6 @@ package org.moire.ultrasonic.adapters import android.annotation.SuppressLint -import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.recyclerview.widget.AdapterListUpdateCallback import androidx.recyclerview.widget.AsyncDifferConfig @@ -145,6 +144,14 @@ class MultiTypeDiffAdapter : MultiTypeAdapter() { selectionRevision.postValue(selectionRevision.value!! + 1) } + fun notifyChanged() { + // When the download state of an entry was changed by an external process, + // increase the revision counter in order to update the UI + + selectionRevision.postValue(selectionRevision.value!! + 1) + } + + fun setSelectionStatusOfAll(select: Boolean): Int { // Clear current selection selectedSet.clear() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt index d79fb10c..54c5cb12 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt @@ -78,13 +78,14 @@ class TrackViewBinder( // Observe download status downloadFile.status.observe(lifecycleOwner, { Timber.w("CAUGHT STATUS CHANGE") - holder.updateDownloadStatus(downloadFile) + holder.updateStatus(it) + holder.adapter.notifyChanged() } ) downloadFile.progress.observe(lifecycleOwner, { Timber.w("CAUGHT PROGRESS CHANGE") - holder.updateDownloadStatus(downloadFile) + holder.updateProgress(it) } ) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt index a7547b46..d455d630 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt @@ -9,7 +9,6 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import androidx.core.view.isVisible -import androidx.lifecycle.findViewTreeLifecycleOwner import androidx.recyclerview.widget.RecyclerView import org.koin.core.component.KoinComponent import org.koin.core.component.get @@ -21,6 +20,7 @@ import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.featureflags.Feature import org.moire.ultrasonic.featureflags.FeatureStorage import org.moire.ultrasonic.service.DownloadFile +import org.moire.ultrasonic.service.DownloadStatus import org.moire.ultrasonic.service.MediaPlayerController import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.util.Settings @@ -47,7 +47,7 @@ class TrackViewHolder(val view: View, var adapter: MultiTypeDiffAdapter { + statusImage = imageHelper.downloadedImage + progress.text = null + } + DownloadStatus.PINNED -> { + statusImage = imageHelper.pinImage + progress.text = null + } + DownloadStatus.FAILED, + DownloadStatus.ABORTED -> { + statusImage = imageHelper.errorImage + progress.text = null + } + DownloadStatus.DOWNLOADING -> { + statusImage = imageHelper.downloadingImage + } + else -> { + statusImage = null } - } else { - leftImageType = ImageType.None - leftImage = null } - val rightImageType: ImageType - val rightImage: Drawable? + updateImages() + } - if (downloadFile.isDownloading && !downloadFile.isDownloadCancelled) { - status.text = Util.formatPercentage(downloadFile.progress.value!!) - - rightImageType = ImageType.Downloading - rightImage = imageHelper.downloadingImage - } else { - rightImageType = ImageType.None - rightImage = null - - val statusText = status.text - if (!statusText.isNullOrEmpty()) status.text = null + fun updateProgress(p: Int) { + if (cachedStatus == DownloadStatus.DOWNLOADING) { + progress.text = Util.formatPercentage(p) + } else { + progress.text = null } + } - if (previousLeftImageType != leftImageType || previousRightImageType != rightImageType) { - previousLeftImageType = leftImageType - previousRightImageType = rightImageType + private fun updateImages() { + progress.setCompoundDrawablesWithIntrinsicBounds( + null, null, statusImage, null + ) - status.setCompoundDrawablesWithIntrinsicBounds( - leftImage, null, rightImage, null - ) - - if (rightImage === imageHelper.downloadingImage) { - // FIXME - val frameAnimation = rightImage as AnimationDrawable? - - frameAnimation?.setVisible(true, true) - frameAnimation?.start() - } + if (statusImage === imageHelper.downloadingImage) { + val frameAnimation = statusImage as AnimationDrawable? + frameAnimation?.setVisible(true, true) + frameAnimation?.start() } } @@ -293,11 +295,4 @@ class TrackViewHolder(val view: View, var adapter: MultiTypeDiffAdapter = MutableLiveData(0) - val status: MutableLiveData = MutableLiveData(DownloadStatus.IDLE) + val status: MutableLiveData init { + val state: DownloadStatus + partialFile = File(saveFile.parent, FileUtil.getPartialFile(saveFile.name)) completeFile = File(saveFile.parent, FileUtil.getCompleteFile(saveFile.name)) + + when { + saveFile.exists() -> { + state = DownloadStatus.PINNED + } + completeFile.exists() -> { + state = DownloadStatus.DONE + } + else -> { + state = DownloadStatus.IDLE + } + } + + status = MutableLiveData(state) + } /** @@ -143,13 +165,14 @@ class DownloadFile( fun unpin() { if (saveFile.exists()) { - if (!saveFile.renameTo(completeFile)) { + if (saveFile.renameTo(completeFile)) { + status.postValue(DownloadStatus.DONE) + } else { Timber.w( "Renaming file failed. Original file: %s; Rename to: %s", saveFile.name, completeFile.name ) } - status.postValue(DownloadStatus.DONE) } } @@ -212,23 +235,23 @@ class DownloadFile( try { if (saveFile.exists()) { Timber.i("%s already exists. Skipping.", saveFile) - status.postValue(DownloadStatus.DONE) - Timber.i("UPDATING STATUS") + status.postValue(DownloadStatus.PINNED) return } if (completeFile.exists()) { + var newStatus: DownloadStatus = DownloadStatus.DONE if (shouldSave) { if (isPlaying) { saveWhenDone = true } else { Util.renameFile(completeFile, saveFile) + newStatus = DownloadStatus.PINNED } } else { Timber.i("%s already exists. Skipping.", completeFile) } - status.postValue(DownloadStatus.DONE) - Timber.i("UPDATING STATUS") + status.postValue(newStatus) return } @@ -285,8 +308,6 @@ class DownloadFile( } downloadAndSaveCoverArt() - - status.postValue(DownloadStatus.DONE) } if (isPlaying) { @@ -294,9 +315,11 @@ class DownloadFile( } else { if (shouldSave) { Util.renameFile(partialFile, saveFile) + status.postValue(DownloadStatus.PINNED) Util.scanMedia(saveFile) } else { Util.renameFile(partialFile, completeFile) + status.postValue(DownloadStatus.DONE) } } } catch (all: Exception) { @@ -378,7 +401,6 @@ class DownloadFile( private fun setProgress(totalBytesCopied: Long) { if (song.size != null) { progress.postValue((totalBytesCopied * 100 / song.size!!).toInt()) - Timber.i("UPDATING PROGESS") } } @@ -414,6 +436,7 @@ class DownloadFile( override val id: String get() = song.id + override val longId: Long by lazy { id.hashCode().toLong() } @@ -424,5 +447,5 @@ class DownloadFile( } enum class DownloadStatus { - IDLE, DOWNLOADING, RETRYING, FAILED, ABORTED, DONE + IDLE, DOWNLOADING, RETRYING, FAILED, ABORTED, DONE, PINNED, UNKNOWN } diff --git a/ultrasonic/src/main/res/drawable/ic_baseline_error_dark.xml b/ultrasonic/src/main/res/drawable/ic_baseline_error_dark.xml new file mode 100644 index 00000000..4c9185e3 --- /dev/null +++ b/ultrasonic/src/main/res/drawable/ic_baseline_error_dark.xml @@ -0,0 +1,9 @@ + + + diff --git a/ultrasonic/src/main/res/drawable/ic_baseline_error_light.xml b/ultrasonic/src/main/res/drawable/ic_baseline_error_light.xml new file mode 100644 index 00000000..2f22d456 --- /dev/null +++ b/ultrasonic/src/main/res/drawable/ic_baseline_error_light.xml @@ -0,0 +1,9 @@ + + + diff --git a/ultrasonic/src/main/res/layout/song_details.xml b/ultrasonic/src/main/res/layout/song_details.xml index 30cb9f5a..2b592b0a 100644 --- a/ultrasonic/src/main/res/layout/song_details.xml +++ b/ultrasonic/src/main/res/layout/song_details.xml @@ -39,7 +39,7 @@ a:layout_height="wrap_content" a:layout_gravity="right|center_vertical" a:drawablePadding="6dip" - a:paddingEnd="6dip"/> + a:paddingEnd="12dip"/> + diff --git a/ultrasonic/src/main/res/values/themes.xml b/ultrasonic/src/main/res/values/themes.xml index 4e23d827..bf6a0b1b 100644 --- a/ultrasonic/src/main/res/values/themes.xml +++ b/ultrasonic/src/main/res/values/themes.xml @@ -34,6 +34,7 @@ @drawable/ic_menu_share_dark @drawable/ic_menu_download_dark @drawable/stat_sys_download_anim_0_dark + @drawable/ic_baseline_error_dark @drawable/stat_sys_download_dark @drawable/media_backward_normal_dark @drawable/media_forward_normal_dark @@ -99,6 +100,7 @@ @drawable/ic_menu_share_dark @drawable/ic_menu_download_dark @drawable/stat_sys_download_anim_0_dark + @drawable/ic_baseline_error_dark @drawable/stat_sys_download_dark @drawable/media_backward_normal_dark @drawable/media_forward_normal_dark @@ -163,6 +165,7 @@ @drawable/ic_menu_share_light @drawable/ic_menu_download_light @drawable/stat_sys_download_anim_0_light + @drawable/ic_baseline_error_light @drawable/stat_sys_download_light @drawable/media_backward_normal_light @drawable/media_forward_normal_light