Update downloads activity

pull/189/head
Koitharu 4 years ago
parent 523ee1e2a9
commit 57929f62ad
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -108,34 +108,6 @@ sealed interface DownloadState {
} }
} }
@Deprecated("TODO: remove")
class WaitingForNetwork(
override val startId: Int,
override val manga: Manga,
override val cover: Drawable?,
) : DownloadState {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as WaitingForNetwork
if (startId != other.startId) return false
if (manga != other.manga) return false
if (cover != other.cover) return false
return true
}
override fun hashCode(): Int {
var result = startId
result = 31 * result + manga.hashCode()
result = 31 * result + (cover?.hashCode() ?: 0)
return result
}
}
class Done( class Done(
override val startId: Int, override val startId: Int,
override val manga: Manga, override val manga: Manga,
@ -252,4 +224,4 @@ sealed interface DownloadState {
return result return result
} }
} }
} }

@ -12,15 +12,13 @@ import org.koitharu.kotatsu.databinding.ItemDownloadBinding
import org.koitharu.kotatsu.download.domain.DownloadState import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.parsers.util.format import org.koitharu.kotatsu.parsers.util.format
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.*
import org.koitharu.kotatsu.utils.progress.ProgressJob
fun downloadItemAD( fun downloadItemAD(
scope: CoroutineScope, scope: CoroutineScope,
coil: ImageLoader, coil: ImageLoader,
) = adapterDelegateViewBinding<ProgressJob<DownloadState>, ProgressJob<DownloadState>, ItemDownloadBinding>( ) = adapterDelegateViewBinding<DownloadItem, DownloadItem, ItemDownloadBinding>(
{ inflater, parent -> ItemDownloadBinding.inflate(inflater, parent, false) } { inflater, parent -> ItemDownloadBinding.inflate(inflater, parent, false) },
) { ) {
var job: Job? = null var job: Job? = null
val percentPattern = context.resources.getString(R.string.percent_string_pattern) val percentPattern = context.resources.getString(R.string.percent_string_pattern)
@ -44,6 +42,8 @@ fun downloadItemAD(
binding.progressBar.isVisible = true binding.progressBar.isVisible = true
binding.textViewPercent.isVisible = false binding.textViewPercent.isVisible = false
binding.textViewDetails.isVisible = false binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = false
binding.buttonResume.isVisible = false
} }
is DownloadState.Done -> { is DownloadState.Done -> {
binding.textViewStatus.setText(R.string.download_complete) binding.textViewStatus.setText(R.string.download_complete)
@ -51,6 +51,8 @@ fun downloadItemAD(
binding.progressBar.isVisible = false binding.progressBar.isVisible = false
binding.textViewPercent.isVisible = false binding.textViewPercent.isVisible = false
binding.textViewDetails.isVisible = false binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = false
binding.buttonResume.isVisible = false
} }
is DownloadState.Error -> { is DownloadState.Error -> {
binding.textViewStatus.setText(R.string.error_occurred) binding.textViewStatus.setText(R.string.error_occurred)
@ -59,6 +61,8 @@ fun downloadItemAD(
binding.textViewPercent.isVisible = false binding.textViewPercent.isVisible = false
binding.textViewDetails.text = state.error.getDisplayMessage(context.resources) binding.textViewDetails.text = state.error.getDisplayMessage(context.resources)
binding.textViewDetails.isVisible = true binding.textViewDetails.isVisible = true
binding.buttonCancel.isVisible = state.canRetry
binding.buttonResume.isVisible = state.canRetry
} }
is DownloadState.PostProcessing -> { is DownloadState.PostProcessing -> {
binding.textViewStatus.setText(R.string.processing_) binding.textViewStatus.setText(R.string.processing_)
@ -66,6 +70,8 @@ fun downloadItemAD(
binding.progressBar.isVisible = true binding.progressBar.isVisible = true
binding.textViewPercent.isVisible = false binding.textViewPercent.isVisible = false
binding.textViewDetails.isVisible = false binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = false
binding.buttonResume.isVisible = false
} }
is DownloadState.Preparing -> { is DownloadState.Preparing -> {
binding.textViewStatus.setText(R.string.preparing_) binding.textViewStatus.setText(R.string.preparing_)
@ -73,6 +79,8 @@ fun downloadItemAD(
binding.progressBar.isVisible = true binding.progressBar.isVisible = true
binding.textViewPercent.isVisible = false binding.textViewPercent.isVisible = false
binding.textViewDetails.isVisible = false binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = true
binding.buttonResume.isVisible = false
} }
is DownloadState.Progress -> { is DownloadState.Progress -> {
binding.textViewStatus.setText(R.string.manga_downloading_) binding.textViewStatus.setText(R.string.manga_downloading_)
@ -83,6 +91,8 @@ fun downloadItemAD(
binding.textViewPercent.text = percentPattern.format((state.percent * 100f).format(1)) binding.textViewPercent.text = percentPattern.format((state.percent * 100f).format(1))
binding.textViewPercent.isVisible = true binding.textViewPercent.isVisible = true
binding.textViewDetails.isVisible = false binding.textViewDetails.isVisible = false
binding.buttonCancel.isVisible = true
binding.buttonResume.isVisible = false
} }
is DownloadState.Queued -> { is DownloadState.Queued -> {
binding.textViewStatus.setText(R.string.queued) binding.textViewStatus.setText(R.string.queued)
@ -90,13 +100,8 @@ fun downloadItemAD(
binding.progressBar.isVisible = false binding.progressBar.isVisible = false
binding.textViewPercent.isVisible = false binding.textViewPercent.isVisible = false
binding.textViewDetails.isVisible = false binding.textViewDetails.isVisible = false
} binding.buttonCancel.isVisible = true
is DownloadState.WaitingForNetwork -> { binding.buttonResume.isVisible = false
binding.textViewStatus.setText(R.string.waiting_for_network)
binding.progressBar.isIndeterminate = false
binding.progressBar.isVisible = false
binding.textViewPercent.isVisible = false
binding.textViewDetails.isVisible = false
} }
} }
}.launchIn(scope) }.launchIn(scope)
@ -106,4 +111,4 @@ fun downloadItemAD(
job?.cancel() job?.cancel()
job = null job = null
} }
} }

@ -5,12 +5,14 @@ import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import org.koitharu.kotatsu.download.domain.DownloadState import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.utils.progress.ProgressJob import org.koitharu.kotatsu.utils.progress.PausingProgressJob
typealias DownloadItem = PausingProgressJob<DownloadState>
class DownloadsAdapter( class DownloadsAdapter(
scope: CoroutineScope, scope: CoroutineScope,
coil: ImageLoader, coil: ImageLoader,
) : AsyncListDifferDelegationAdapter<ProgressJob<DownloadState>>(DiffCallback()) { ) : AsyncListDifferDelegationAdapter<DownloadItem>(DiffCallback()) {
init { init {
delegatesManager.addDelegate(downloadItemAD(scope, coil)) delegatesManager.addDelegate(downloadItemAD(scope, coil))
@ -21,20 +23,24 @@ class DownloadsAdapter(
return items[position].progressValue.startId.toLong() return items[position].progressValue.startId.toLong()
} }
private class DiffCallback : DiffUtil.ItemCallback<ProgressJob<DownloadState>>() { private class DiffCallback : DiffUtil.ItemCallback<DownloadItem>() {
override fun areItemsTheSame( override fun areItemsTheSame(
oldItem: ProgressJob<DownloadState>, oldItem: DownloadItem,
newItem: ProgressJob<DownloadState>, newItem: DownloadItem,
): Boolean { ): Boolean {
return oldItem.progressValue.startId == newItem.progressValue.startId return oldItem.progressValue.startId == newItem.progressValue.startId
} }
override fun areContentsTheSame( override fun areContentsTheSame(
oldItem: ProgressJob<DownloadState>, oldItem: DownloadItem,
newItem: ProgressJob<DownloadState>, newItem: DownloadItem,
): Boolean { ): Boolean {
return oldItem.progressValue == newItem.progressValue return oldItem.progressValue == newItem.progressValue && oldItem.isPaused == newItem.isPaused
}
override fun getChangePayload(oldItem: DownloadItem, newItem: DownloadItem): Any {
return Unit
} }
} }
} }

@ -41,14 +41,14 @@ class DownloadNotification(private val context: Context, startId: Int) {
context, context,
startId * 2 + 1, startId * 2 + 1,
DownloadService.getResumeIntent(startId), DownloadService.getResumeIntent(startId),
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE PendingIntent.FLAG_CANCEL_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE,
) ),
) )
private val listIntent = PendingIntent.getActivity( private val listIntent = PendingIntent.getActivity(
context, context,
REQUEST_LIST, REQUEST_LIST,
DownloadsActivity.newIntent(context), DownloadsActivity.newIntent(context),
PendingIntentCompat.FLAG_IMMUTABLE PendingIntentCompat.FLAG_IMMUTABLE,
) )
init { init {
@ -142,13 +142,6 @@ class DownloadNotification(private val context: Context, startId: Int) {
builder.setOngoing(true) builder.setOngoing(true)
builder.addAction(cancelAction) builder.addAction(cancelAction)
} }
is DownloadState.WaitingForNetwork -> {
builder.setProgress(0, 0, false)
builder.setContentText(context.getString(R.string.waiting_for_network))
builder.setStyle(null)
builder.setOngoing(true)
builder.addAction(cancelAction)
}
} }
return builder.build() return builder.build()
} }

@ -171,7 +171,7 @@ class DownloadService : BaseService() {
class DownloadBinder(private val service: DownloadService) : Binder() { class DownloadBinder(private val service: DownloadService) : Binder() {
val downloads: Flow<Collection<ProgressJob<DownloadState>>> val downloads: Flow<Collection<PausingProgressJob<DownloadState>>>
get() = service.jobCount.mapLatest { service.jobs.values } get() = service.jobCount.mapLatest { service.jobs.values }
} }

@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat.startActivity
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels

@ -1,101 +1,123 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" app:cardCornerRadius="16dp">
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingBottom="6dp">
<com.google.android.material.card.MaterialCardView <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/card_cover" android:layout_width="match_parent"
android:layout_width="48dp" android:layout_height="match_parent"
android:layout_height="48dp" android:minHeight="@dimen/manga_list_details_item_height"
android:layout_margin="8dp" android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent" android:padding="4dp">
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<ImageView <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageView_cover" android:id="@+id/imageView_cover"
android:layout_width="match_parent" android:layout_width="92dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:contentDescription="@null" android:orientation="vertical"
android:scaleType="centerCrop" android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="H,13:18"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover"
tools:src="@tools:sample/backgrounds/scenic" /> tools:src="@tools:sample/backgrounds/scenic" />
</com.google.android.material.card.MaterialCardView> <TextView
android:id="@+id/textView_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceTitleSmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" />
<TextView <com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/textView_title" android:id="@+id/progressBar"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:ellipsize="end" app:layout_constraintEnd_toEndOf="parent"
android:singleLine="true" app:layout_constraintStart_toEndOf="@id/imageView_cover"
android:textAppearance="?attr/textAppearanceBodyLarge" app:layout_constraintTop_toBottomOf="@id/textView_title" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/card_cover"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" />
<com.google.android.material.progressindicator.LinearProgressIndicator <TextView
android:id="@+id/progressBar" android:id="@+id/textView_status"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent" android:ellipsize="end"
app:layout_constraintStart_toEndOf="@id/card_cover" android:singleLine="true"
app:layout_constraintTop_toBottomOf="@id/textView_title" /> android:textAppearance="?attr/textAppearanceBodySmall"
app:layout_constraintEnd_toStartOf="@id/textView_percent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/progressBar"
tools:text="@string/manga_downloading_" />
<TextView <TextView
android:id="@+id/textView_status" android:id="@+id/textView_percent"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginEnd="8dp"
android:layout_marginTop="4dp" android:textAppearance="?attr/textAppearanceBodyMedium"
android:layout_marginEnd="8dp" app:layout_constraintBaseline_toBaselineOf="@id/textView_status"
android:ellipsize="end" app:layout_constraintEnd_toEndOf="parent"
android:singleLine="true" tools:text="25%" />
android:textAppearance="?attr/textAppearanceBodySmall"
app:layout_constraintEnd_toStartOf="@id/textView_percent"
app:layout_constraintStart_toEndOf="@id/card_cover"
app:layout_constraintTop_toBottomOf="@id/progressBar"
tools:text="@string/manga_downloading_" />
<TextView <TextView
android:id="@+id/textView_percent" android:id="@+id/textView_details"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyMedium" android:layout_marginStart="16dp"
app:layout_constraintBaseline_toBaselineOf="@id/textView_status" android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
android:layout_marginEnd="8dp" android:ellipsize="end"
tools:text="25%" /> android:maxLines="4"
android:textAppearance="?attr/textAppearanceBodySmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_status"
tools:text="@tools:sample/lorem[3]" />
<TextView <Button
android:id="@+id/textView_details" android:id="@+id/button_resume"
android:layout_width="0dp" style="@style/Widget.Material3.Button.TextButton"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_marginStart="16dp" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:text="@string/try_again"
android:layout_marginEnd="8dp" android:visibility="gone"
android:ellipsize="end" app:layout_constraintBottom_toBottomOf="parent"
android:maxLines="4" app:layout_constraintEnd_toStartOf="@id/button_cancel"
android:textAppearance="?attr/textAppearanceBodySmall" app:layout_constraintTop_toBottomOf="@id/textView_details"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintVertical_bias="1"
app:layout_constraintStart_toEndOf="@id/card_cover" tools:visibility="visible" />
app:layout_constraintTop_toBottomOf="@id/textView_status"
tools:text="@tools:sample/lorem[3]" />
</androidx.constraintlayout.widget.ConstraintLayout> <Button
android:id="@+id/button_cancel"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/cancel"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView_details"
app:layout_constraintVertical_bias="1"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

Loading…
Cancel
Save