Animating Download Button (I can't stop)

from downloading to download goes to:
Fill in circle
Fly in a check mark to replace the down arrow (looks like upstream at the moment....am I changing to be like upstream?)
SIKE, it changes right back to the down arrow after a second

...why am I like this

Also I removed the double download completed call to listeners or whatever
oh and cleanup of dlqueue i guess
This commit is contained in:
Jays2Kings 2021-04-16 00:02:37 -04:00
parent 2c143155d6
commit 7f47c5fd4d
9 changed files with 202 additions and 46 deletions

View File

@ -494,7 +494,7 @@ class Downloader(
// Delete successful downloads from queue
if (download.status == Download.DOWNLOADED) {
// remove downloaded chapter from queue
queue.remove(download)
queue.remove(download, false)
}
if (areAllDownloadsFinished()) {
DownloadService.stop(context)

View File

@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadStore
import eu.kanade.tachiyomi.source.model.Page
import rx.Observable
import rx.subjects.PublishSubject
import java.util.concurrent.CopyOnWriteArrayList
@ -32,7 +31,7 @@ class DownloadQueue(
updatedRelay.call(Unit)
}
fun remove(download: Download) {
fun remove(download: Download, callListeners: Boolean = true) {
val removed = queue.remove(download)
store.remove(download)
download.setStatusSubject(null)
@ -40,7 +39,9 @@ class DownloadQueue(
if (download.status == Download.DOWNLOADING || download.status == Download.QUEUE) {
download.status = Download.NOT_DOWNLOADED
}
if (callListeners) {
downloadListeners.forEach { it.updateDownload(download) }
}
if (removed) {
updatedRelay.call(Unit)
}
@ -76,15 +77,6 @@ class DownloadQueue(
updatedRelay.call(Unit)
}
fun getActiveDownloads(): Observable<Download> =
Observable.from(this).filter { download -> download.status == Download.DOWNLOADING }
fun getStatusObservable(): Observable<Download> = statusSubject.onBackpressureBuffer()
fun getUpdatedObservable(): Observable<List<Download>> = updatedRelay.onBackpressureBuffer()
.startWith(Unit)
.map { this }
private fun setPagesFor(download: Download) {
if (download.status == Download.DOWNLOADING) {
if (download.pages != null) {
@ -93,12 +85,12 @@ class DownloadQueue(
callListeners(download)
}
}
downloadListeners.forEach { it.updateDownload(download) }
callListeners(download)
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
setPagesSubject(download.pages, null)
downloadListeners.forEach { it.updateDownload(download) }
callListeners(download)
} else {
downloadListeners.forEach { it.updateDownload(download) }
callListeners(download)
}
}
@ -106,27 +98,6 @@ class DownloadQueue(
downloadListeners.forEach { it.updateDownload(download) }
}
fun getProgressObservable(): Observable<Download> {
return statusSubject.onBackpressureBuffer()
.startWith(getActiveDownloads())
.flatMap { download ->
if (download.status == Download.DOWNLOADING) {
val pageStatusSubject = PublishSubject.create<Int>()
setPagesSubject(download.pages, pageStatusSubject)
downloadListeners.forEach { it.updateDownload(download) }
return@flatMap pageStatusSubject
.onBackpressureBuffer()
.filter { it == Page.READY }
.map { download }
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
setPagesSubject(download.pages, null)
downloadListeners.forEach { it.updateDownload(download) }
}
Observable.just(download)
}
.filter { it.status == Download.DOWNLOADING }
}
private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Int>?) {
if (pages != null) {
for (page in pages) {

View File

@ -1,18 +1,21 @@
package eu.kanade.tachiyomi.ui.download
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.databinding.DownloadButtonBinding
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.visible
import eu.kanade.tachiyomi.widget.EndAnimatorListener
class DownloadButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
FrameLayout(context, attrs) {
@ -55,6 +58,14 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
context,
R.drawable.ic_check_24dp
)?.mutate()
private val filledAnim = AnimatedVectorDrawableCompat.create(
context,
R.drawable.anim_outline_to_filled
)
private val checkAnim = AnimatedVectorDrawableCompat.create(
context,
R.drawable.anim_dl_to_check_to_dl
)
private var isAnimating = false
private var iconAnimation: ObjectAnimator? = null
@ -65,7 +76,7 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
binding = DownloadButtonBinding.bind(this)
}
fun setDownloadStatus(state: Int, progress: Int = 0) {
fun setDownloadStatus(state: Int, progress: Int = 0, animated: Boolean = false) {
if (state != Download.DOWNLOADING) {
iconAnimation?.cancel()
binding.downloadIcon.alpha = 1f
@ -124,9 +135,28 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
binding.downloadProgress.gone()
binding.downloadBorder.visible()
binding.downloadProgressIndeterminate.gone()
binding.downloadBorder.setImageDrawable(filledCircle)
binding.downloadBorder.drawable.setTint(downloadedColor)
if (animated) {
binding.downloadBorder.setImageDrawable(filledAnim)
binding.downloadIcon.setImageDrawable(checkAnim)
filledAnim?.start()
val alphaAnimation = ValueAnimator.ofArgb(disabledColor, downloadedTextColor)
alphaAnimation.addUpdateListener { valueAnimator ->
binding.downloadIcon.drawable.setTint(valueAnimator.animatedValue as Int)
}
alphaAnimation.addListener(
EndAnimatorListener {
binding.downloadIcon.drawable.setTint(downloadedTextColor)
checkAnim?.start()
}
)
alphaAnimation.duration = 150
alphaAnimation.start()
binding.downloadBorder.drawable.setTint(downloadedColor)
} else {
binding.downloadBorder.setImageDrawable(filledCircle)
binding.downloadIcon.drawable.setTint(downloadedTextColor)
}
}
Download.ERROR -> {
binding.downloadProgress.gone()

View File

@ -523,7 +523,8 @@ class MangaDetailsController :
getHolder(download.chapter)?.notifyStatus(
download.status,
presenter.isLockedFromSearch,
download.progress
download.progress,
true
)
}

View File

@ -152,12 +152,12 @@ class ChapterHolder(
if (binding.frontView.translationX != 0f) itemView.post { adapter.notifyItemChanged(flexibleAdapterPosition) }
}
fun notifyStatus(status: Int, locked: Boolean, progress: Int) = with(binding.downloadButton.downloadButton) {
fun notifyStatus(status: Int, locked: Boolean, progress: Int, animated: Boolean = false) = with(binding.downloadButton.downloadButton) {
if (locked) {
gone()
return
}
visibleIf(!localSource)
setDownloadStatus(status, progress)
setDownloadStatus(status, progress, animated)
}
}

View File

@ -138,8 +138,8 @@ class RecentMangaHolder(
return item.mch.history.id != null
}
fun notifyStatus(status: Int, progress: Int, isRead: Boolean) {
binding.downloadButton.downloadButton.setDownloadStatus(status, progress)
fun notifyStatus(status: Int, progress: Int, isRead: Boolean, animated: Boolean = false) {
binding.downloadButton.downloadButton.setDownloadStatus(status, progress, animated)
val isChapterRead =
if (adapter.showDownloads == RecentMangaAdapter.ShowRecentsDLs.UnreadOrDownloaded) isRead else false
binding.downloadButton.downloadButton.isVisible =

View File

@ -415,7 +415,7 @@ class RecentsController(bundle: Bundle? = null) :
binding.downloadBottomSheet.dlBottomSheet.onUpdateDownloadedPages(download)
val id = download.chapter.id ?: return
val holder = binding.recycler.findViewHolderForItemId(id) as? RecentMangaHolder ?: return
holder.notifyStatus(download.status, download.progress, download.chapter.read)
holder.notifyStatus(download.status, download.progress, download.chapter.read, true)
}
private fun refreshItem(chapterId: Long) {

View File

@ -0,0 +1,125 @@
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:name="main_group"
android:pivotX="12"
android:pivotY="12">
<path
android:name="check_dl"
android:pathData="M 21 7 L 9 19 L 3.5 13.5 L 4.91 12.09 L 9 16.17 L 19.59 5.59 L 21 7 Z"
android:fillColor="#000"
android:fillAlpha="0"
android:strokeWidth="1"/>
</group>
<group android:name="start_group">
<path
android:name="start_dl"
android:pathData="M 11 4 L 13 4 L 13 4 L 13 16 L 18.5 10.5 L 19.92 11.92 L 12 19.84 L 4.08 11.92 L 5.5 10.5 L 11 16 L 11 4 L 11 4"
android:fillColor="#000000"/>
<group
android:name="check_group"
android:translateY="12">
<path
android:name="start_check"
android:pathData="M 19.59 5.59 L 21 7 L 21 7 L 10.479 17.521 L 10.479 17.521 L 9 19 L 9 19 L 3.5 13.5 L 4.91 12.09 L 9 16.17 L 19.325 5.855 L 19.59 5.59"
android:fillColor="#000"
android:fillAlpha="0"
android:strokeWidth="1"/>
</group>
</group>
</vector>
</aapt:attr>
<target android:name="check_dl">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:propertyName="pathData"
android:startOffset="1250"
android:duration="450"
android:valueFrom="M 19.59 5.59 L 21 7 L 21 7 L 10.479 17.521 L 10.479 17.521 L 9 19 L 9 19 L 3.5 13.5 L 4.91 12.09 L 9 16.17 L 19.325 5.855 L 19.59 5.59"
android:valueTo="M 11 4 L 13 4 L 13 4 L 13 16 L 18.5 10.5 L 19.92 11.92 L 12 19.84 L 4.08 11.92 L 5.5 10.5 L 11 16 L 11 4 L 11 4"
android:valueType="pathType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="fillAlpha"
android:duration="400"
android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="400"
android:duration="100"
android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</set>
</aapt:attr>
</target>
<target android:name="main_group">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="rotation"
android:startOffset="1250"
android:duration="450"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</aapt:attr>
</target>
<target android:name="start_group">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="translateY"
android:duration="400"
android:valueFrom="0"
android:valueTo="-12"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</aapt:attr>
</target>
<target android:name="start_dl">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="fillAlpha"
android:duration="250"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</aapt:attr>
</target>
<target android:name="start_check">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="150"
android:duration="250"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="400"
android:duration="100"
android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,29 @@
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:name="path"
android:pathData="M 10 0 C 7.349 0 4.804 1.054 2.929 2.929 C 1.054 4.804 0 7.349 0 10 C 0 12.651 1.054 15.196 2.929 17.071 C 4.804 18.946 7.349 20 10 20 C 12.651 20 15.196 18.946 17.071 17.071 C 18.946 15.196 20 12.651 20 10 C 20 7.349 18.946 4.804 17.071 2.929 C 15.196 1.054 12.651 0 10 0 Z M 10 18 C 7.879 18 5.843 17.157 4.343 15.657 C 2.843 14.157 2 12.121 2 10 C 2 7.879 2.843 5.843 4.343 4.343 C 5.843 2.843 7.879 2 10 2 C 12.121 2 14.157 2.843 15.657 4.343 C 17.157 5.843 18 7.879 18 10 C 18 12.121 17.157 14.157 15.657 15.657 C 14.157 17.157 12.121 18 10 18"
android:fillColor="#000"
android:strokeWidth="1"/>
</vector>
</aapt:attr>
<target android:name="path">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="pathData"
android:duration="200"
android:valueFrom="M 10 0 C 7.349 0 4.804 1.054 2.929 2.929 C 1.054 4.804 0 7.349 0 10 C 0 12.651 1.054 15.196 2.929 17.071 C 4.804 18.946 7.349 20 10 20 C 12.651 20 15.196 18.946 17.071 17.071 C 18.946 15.196 20 12.651 20 10 C 20 7.349 18.946 4.804 17.071 2.929 C 15.196 1.054 12.651 0 10 0 Z M 10 18 C 7.879 18 5.843 17.157 4.343 15.657 C 2.843 14.157 2 12.121 2 10 C 2 7.879 2.843 5.843 4.343 4.343 C 5.843 2.843 7.879 2 10 2 C 12.121 2 14.157 2.843 15.657 4.343 C 17.157 5.843 18 7.879 18 10 C 18 12.121 17.157 14.157 15.657 15.657 C 14.157 17.157 12.121 18 10 18"
android:valueTo="M 10 0 C 7.349 0 4.804 1.054 2.929 2.929 C 1.054 4.804 0 7.349 0 10 C 0 12.651 1.054 15.196 2.929 17.071 C 4.804 18.946 7.349 20 10 20 C 12.651 20 15.196 18.946 17.071 17.071 C 18.946 15.196 20 12.651 20 10 C 20 7.349 18.946 4.804 17.071 2.929 C 15.196 1.054 12.651 0 10 0 Z M 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10 C 10 10 10 10 10 10"
android:valueType="pathType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</aapt:attr>
</target>
</animated-vector>