diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/progress/PausingProgressJob.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/progress/PausingProgressJob.kt
deleted file mode 100644
index 7641646f8..000000000
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/progress/PausingProgressJob.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.koitharu.kotatsu.core.util.progress
-
-import androidx.annotation.AnyThread
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.StateFlow
-import org.koitharu.kotatsu.download.ui.worker.PausingHandle
-
-class PausingProgressJob
(
- job: Job,
- progress: StateFlow
,
- private val pausingHandle: PausingHandle,
-) : ProgressJob
(job, progress) {
-
- @get:AnyThread
- val isPaused: Boolean
- get() = pausingHandle.isPaused
-
- @AnyThread
- suspend fun awaitResumed() = pausingHandle.awaitResumed()
-
- @AnyThread
- fun pause() = pausingHandle.pause()
-
- @AnyThread
- fun resume() = pausingHandle.resume()
-}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemAD.kt
index 0dc006845..cc87f160b 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemAD.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemAD.kt
@@ -44,7 +44,8 @@ fun downloadItemAD(
override fun onClick(v: View) {
when (v.id) {
R.id.button_cancel -> listener.onCancelClick(item)
- R.id.button_resume -> listener.onResumeClick(item)
+ R.id.button_resume -> listener.onResumeClick(item, skip = false)
+ R.id.button_skip -> listener.onResumeClick(item, skip = true)
R.id.button_pause -> listener.onPauseClick(item)
R.id.imageView_expand -> listener.onExpandClick(item)
else -> listener.onItemClick(item, v)
@@ -62,6 +63,7 @@ fun downloadItemAD(
binding.buttonCancel.setOnClickListener(clickListener)
binding.buttonPause.setOnClickListener(clickListener)
binding.buttonResume.setOnClickListener(clickListener)
+ binding.buttonSkip.setOnClickListener(clickListener)
binding.imageViewExpand.setOnClickListener(clickListener)
itemView.setOnClickListener(clickListener)
itemView.setOnLongClickListener(clickListener)
@@ -120,6 +122,7 @@ fun downloadItemAD(
binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = true
binding.buttonResume.isVisible = false
+ binding.buttonSkip.isVisible = false
binding.buttonPause.isVisible = false
}
@@ -134,9 +137,10 @@ fun downloadItemAD(
binding.progressBar.setProgressCompat(item.progress, payloads.isNotEmpty())
binding.textViewPercent.text = percentPattern.format((item.percent * 100f).format(1))
binding.textViewPercent.isVisible = true
- binding.textViewDetails.textAndVisible = item.getEtaString()
+ binding.textViewDetails.textAndVisible = if (item.isPaused) item.error else item.getEtaString()
binding.buttonCancel.isVisible = true
binding.buttonResume.isVisible = item.isPaused
+ binding.buttonSkip.isVisible = item.isPaused && item.error != null
binding.buttonPause.isVisible = item.canPause
}
@@ -158,6 +162,7 @@ fun downloadItemAD(
}
binding.buttonCancel.isVisible = false
binding.buttonResume.isVisible = false
+ binding.buttonSkip.isVisible = false
binding.buttonPause.isVisible = false
}
@@ -170,6 +175,7 @@ fun downloadItemAD(
binding.textViewDetails.textAndVisible = item.error
binding.buttonCancel.isVisible = false
binding.buttonResume.isVisible = false
+ binding.buttonSkip.isVisible = false
binding.buttonPause.isVisible = false
}
@@ -182,6 +188,7 @@ fun downloadItemAD(
binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = false
binding.buttonResume.isVisible = false
+ binding.buttonSkip.isVisible = false
binding.buttonPause.isVisible = false
}
}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemListener.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemListener.kt
index 547c64381..449911419 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemListener.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemListener.kt
@@ -8,7 +8,7 @@ interface DownloadItemListener : OnListItemClickListener {
fun onPauseClick(item: DownloadItemModel)
- fun onResumeClick(item: DownloadItemModel)
+ fun onResumeClick(item: DownloadItemModel, skip: Boolean)
fun onExpandClick(item: DownloadItemModel)
}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt
index 6b0051b2e..f0b51a621 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt
@@ -105,8 +105,8 @@ class DownloadsActivity : BaseActivity(),
sendBroadcast(PausingReceiver.getPauseIntent(this, item.id))
}
- override fun onResumeClick(item: DownloadItemModel) {
- sendBroadcast(PausingReceiver.getResumeIntent(this, item.id))
+ override fun onResumeClick(item: DownloadItemModel, skip: Boolean) {
+ sendBroadcast(PausingReceiver.getResumeIntent(this, item.id, skip))
}
override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt
index 987257c8d..559723c4e 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt
@@ -143,7 +143,7 @@ class DownloadsViewModel @Inject constructor(
var isResumed = false
for (work in snapshot) {
if (work.workState == WorkInfo.State.RUNNING && work.isPaused) {
- workScheduler.resume(work.id)
+ workScheduler.resume(work.id, skipError = false)
isResumed = true
}
}
@@ -156,7 +156,7 @@ class DownloadsViewModel @Inject constructor(
val snapshot = works.value ?: return
for (work in snapshot) {
if (work.id.mostSignificantBits in ids) {
- workScheduler.resume(work.id)
+ workScheduler.resume(work.id, skipError = false)
}
}
onActionDone.call(ReversibleAction(R.string.downloads_resumed, null))
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadNotificationFactory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadNotificationFactory.kt
index 7f2e3d564..aa23dc794 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadNotificationFactory.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadNotificationFactory.kt
@@ -82,7 +82,15 @@ class DownloadNotificationFactory @AssistedInject constructor(
NotificationCompat.Action(
R.drawable.ic_action_resume,
context.getString(R.string.resume),
- PausingReceiver.createResumePendingIntent(context, uuid),
+ PausingReceiver.createResumePendingIntent(context, uuid, skipError = false),
+ )
+ }
+
+ private val actionSkip by lazy {
+ NotificationCompat.Action(
+ R.drawable.ic_action_skip,
+ context.getString(R.string.skip),
+ PausingReceiver.createResumePendingIntent(context, uuid, skipError = true),
)
}
@@ -163,6 +171,9 @@ class DownloadNotificationFactory @AssistedInject constructor(
builder.setSmallIcon(R.drawable.ic_stat_paused)
builder.addAction(actionCancel)
builder.addAction(actionResume)
+ if (state.error != null) {
+ builder.addAction(actionSkip)
+ }
}
state.error != null -> { // error, final state
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt
index fe7e50dea..72825f174 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt
@@ -198,7 +198,7 @@ class DownloadWorker @AssistedInject constructor(
}
val pages = runFailsafe {
repo.getPages(chapter)
- }
+ } ?: continue
val pageCounter = AtomicInteger(0)
channelFlow {
val semaphore = Semaphore(MAX_PAGES_PARALLELISM)
@@ -264,7 +264,7 @@ class DownloadWorker @AssistedInject constructor(
private suspend fun runFailsafe(
block: suspend () -> R,
- ): R {
+ ): R? {
checkIsPaused()
var countDown = MAX_FAILSAFE_ATTEMPTS
failsafe@ while (true) {
@@ -284,6 +284,9 @@ class DownloadWorker @AssistedInject constructor(
pausingHandle.pause()
try {
pausingHandle.awaitResumed()
+ if (pausingHandle.skipCurrentError()) {
+ return null
+ }
} finally {
publishState(currentState.copy(isPaused = false, error = null))
}
@@ -448,8 +451,8 @@ class DownloadWorker @AssistedInject constructor(
context.sendBroadcast(intent)
}
- fun resume(id: UUID) {
- val intent = PausingReceiver.getResumeIntent(context, id)
+ fun resume(id: UUID, skipError: Boolean) {
+ val intent = PausingReceiver.getResumeIntent(context, id, skipError)
context.sendBroadcast(intent)
}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingHandle.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingHandle.kt
index c73cd6bbe..0c9eb6653 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingHandle.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingHandle.kt
@@ -10,6 +10,7 @@ import kotlin.coroutines.CoroutineContext
class PausingHandle : AbstractCoroutineContextElement(PausingHandle) {
private val paused = MutableStateFlow(false)
+ private val isSkipError = MutableStateFlow(false)
@get:AnyThread
val isPaused: Boolean
@@ -26,7 +27,8 @@ class PausingHandle : AbstractCoroutineContextElement(PausingHandle) {
}
@AnyThread
- fun resume() {
+ fun resume(skipError: Boolean) {
+ isSkipError.value = skipError
paused.value = false
}
@@ -36,6 +38,8 @@ class PausingHandle : AbstractCoroutineContextElement(PausingHandle) {
}
}
+ fun skipCurrentError(): Boolean = isSkipError.compareAndSet(expect = true, update = false)
+
companion object : CoroutineContext.Key {
suspend fun current() = checkNotNull(currentCoroutineContext()[this]) {
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt
index 8bf4298d0..b86328610 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt
@@ -21,7 +21,7 @@ class PausingReceiver(
return
}
when (intent.action) {
- ACTION_RESUME -> pausingHandle.resume()
+ ACTION_RESUME -> pausingHandle.resume(intent.getBooleanExtra(EXTRA_SKIP_ERROR, false))
ACTION_PAUSE -> pausingHandle.pause()
}
}
@@ -31,6 +31,7 @@ class PausingReceiver(
private const val ACTION_PAUSE = "org.koitharu.kotatsu.download.PAUSE"
private const val ACTION_RESUME = "org.koitharu.kotatsu.download.RESUME"
private const val EXTRA_UUID = "uuid"
+ private const val EXTRA_SKIP_ERROR = "skip"
private const val SCHEME = "workuid"
fun createIntentFilter(id: UUID) = IntentFilter().apply {
@@ -45,10 +46,11 @@ class PausingReceiver(
.setPackage(context.packageName)
.putExtra(EXTRA_UUID, id.toString())
- fun getResumeIntent(context: Context, id: UUID) = Intent(ACTION_RESUME)
+ fun getResumeIntent(context: Context, id: UUID, skipError: Boolean) = Intent(ACTION_RESUME)
.setData(Uri.parse("$SCHEME://$id"))
.setPackage(context.packageName)
.putExtra(EXTRA_UUID, id.toString())
+ .putExtra(EXTRA_SKIP_ERROR, skipError)
fun createPausePendingIntent(context: Context, id: UUID) = PendingIntentCompat.getBroadcast(
context,
@@ -58,12 +60,13 @@ class PausingReceiver(
false,
)
- fun createResumePendingIntent(context: Context, id: UUID) = PendingIntentCompat.getBroadcast(
- context,
- 0,
- getResumeIntent(context, id),
- 0,
- false,
- )
+ fun createResumePendingIntent(context: Context, id: UUID, skipError: Boolean) =
+ PendingIntentCompat.getBroadcast(
+ context,
+ 0,
+ getResumeIntent(context, id, skipError),
+ 0,
+ false,
+ )
}
}
diff --git a/app/src/main/res/drawable/ic_action_skip.xml b/app/src/main/res/drawable/ic_action_skip.xml
new file mode 100644
index 000000000..efe97da86
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_skip.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/layout/item_download.xml b/app/src/main/res/layout/item_download.xml
index 2f6c56686..7743b2c19 100644
--- a/app/src/main/res/layout/item_download.xml
+++ b/app/src/main/res/layout/item_download.xml
@@ -154,7 +154,7 @@
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@id/button_resume"
app:layout_constraintTop_toBottomOf="@id/recyclerView_chapters"
- tools:visibility="visible" />
+ tools:visibility="gone" />
+ app:layout_constraintTop_toBottomOf="@id/recyclerView_chapters"
+ tools:visibility="visible" />
+
+