Refactor downloading-related classes

pull/367/head
Koitharu 3 years ago
parent 42df607f52
commit ac9680b5c0
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -102,6 +102,12 @@ dependencies {
implementation 'com.google.android.material:material:1.9.0' implementation 'com.google.android.material:material:1.9.0'
//noinspection LifecycleAnnotationProcessorWithJava8 //noinspection LifecycleAnnotationProcessorWithJava8
kapt 'androidx.lifecycle:lifecycle-compiler:2.6.1' kapt 'androidx.lifecycle:lifecycle-compiler:2.6.1'
/**
* TODO: check
* https://issuetracker.google.com/issues/270245927
* https://issuetracker.google.com/issues/280504155
*/
implementation 'androidx.work:work-runtime-ktx:2.8.1' implementation 'androidx.work:work-runtime-ktx:2.8.1'
//noinspection GradleDependency //noinspection GradleDependency
implementation('com.google.guava:guava:31.1-android') { implementation('com.google.guava:guava:31.1-android') {

@ -6,7 +6,7 @@ import org.koitharu.kotatsu.local.data.LocalManga
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import java.util.Date import java.util.Date
data class DownloadState2( data class DownloadState(
val manga: Manga, val manga: Manga,
val isIndeterminate: Boolean, val isIndeterminate: Boolean,
val isPaused: Boolean = false, val isPaused: Boolean = false,
@ -46,6 +46,50 @@ data class DownloadState2(
.putBoolean(DATA_PAUSED, isPaused) .putBoolean(DATA_PAUSED, isPaused)
.build() .build()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as DownloadState
if (manga != other.manga) return false
if (isIndeterminate != other.isIndeterminate) return false
if (isPaused != other.isPaused) return false
if (isStopped != other.isStopped) return false
if (error != other.error) return false
if (totalChapters != other.totalChapters) return false
if (currentChapter != other.currentChapter) return false
if (totalPages != other.totalPages) return false
if (currentPage != other.currentPage) return false
if (eta != other.eta) return false
if (localManga != other.localManga) return false
if (!downloadedChapters.contentEquals(other.downloadedChapters)) return false
if (timestamp != other.timestamp) return false
if (max != other.max) return false
if (progress != other.progress) return false
return percent == other.percent
}
override fun hashCode(): Int {
var result = manga.hashCode()
result = 31 * result + isIndeterminate.hashCode()
result = 31 * result + isPaused.hashCode()
result = 31 * result + isStopped.hashCode()
result = 31 * result + (error?.hashCode() ?: 0)
result = 31 * result + totalChapters
result = 31 * result + currentChapter
result = 31 * result + totalPages
result = 31 * result + currentPage
result = 31 * result + eta.hashCode()
result = 31 * result + (localManga?.hashCode() ?: 0)
result = 31 * result + downloadedChapters.contentHashCode()
result = 31 * result + timestamp.hashCode()
result = 31 * result + max
result = 31 * result + progress
result = 31 * result + percent.hashCode()
return result
}
companion object { companion object {
private const val DATA_MANGA_ID = "manga_id" private const val DATA_MANGA_ID = "manga_id"

@ -19,7 +19,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.MangaDataRepository import org.koitharu.kotatsu.base.domain.MangaDataRepository
import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.DateTimeAgo import org.koitharu.kotatsu.core.ui.DateTimeAgo
import org.koitharu.kotatsu.download.domain.DownloadState2 import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
@ -173,21 +173,21 @@ class DownloadsViewModel @Inject constructor(
private suspend fun WorkInfo.toUiModel(): DownloadItemModel? { private suspend fun WorkInfo.toUiModel(): DownloadItemModel? {
val workData = if (outputData == Data.EMPTY) progress else outputData val workData = if (outputData == Data.EMPTY) progress else outputData
val mangaId = DownloadState2.getMangaId(workData) val mangaId = DownloadState.getMangaId(workData)
if (mangaId == 0L) return null if (mangaId == 0L) return null
val manga = getManga(mangaId) ?: return null val manga = getManga(mangaId) ?: return null
return DownloadItemModel( return DownloadItemModel(
id = id, id = id,
workState = state, workState = state,
manga = manga, manga = manga,
error = DownloadState2.getError(workData), error = DownloadState.getError(workData),
isIndeterminate = DownloadState2.isIndeterminate(workData), isIndeterminate = DownloadState.isIndeterminate(workData),
isPaused = DownloadState2.isPaused(workData), isPaused = DownloadState.isPaused(workData),
max = DownloadState2.getMax(workData), max = DownloadState.getMax(workData),
progress = DownloadState2.getProgress(workData), progress = DownloadState.getProgress(workData),
eta = DownloadState2.getEta(workData), eta = DownloadState.getEta(workData),
timestamp = DownloadState2.getTimestamp(workData), timestamp = DownloadState.getTimestamp(workData),
totalChapters = DownloadState2.getDownloadedChapters(workData).size, totalChapters = DownloadState.getDownloadedChapters(workData).size,
) )
} }

@ -25,7 +25,7 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.domain.DownloadState2 import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.download.ui.list.DownloadsActivity import org.koitharu.kotatsu.download.ui.list.DownloadsActivity
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
@ -100,7 +100,7 @@ class DownloadNotificationFactory @AssistedInject constructor(
builder.priority = NotificationCompat.PRIORITY_DEFAULT builder.priority = NotificationCompat.PRIORITY_DEFAULT
} }
suspend fun create(state: DownloadState2?): Notification = mutex.withLock { suspend fun create(state: DownloadState?): Notification = mutex.withLock {
builder.setContentTitle(state?.manga?.title ?: context.getString(R.string.preparing_)) builder.setContentTitle(state?.manga?.title ?: context.getString(R.string.preparing_))
builder.setContentText(context.getString(R.string.manga_downloading_)) builder.setContentText(context.getString(R.string.manga_downloading_))
builder.setProgress(1, 0, true) builder.setProgress(1, 0, true)

@ -39,8 +39,7 @@ import org.koitharu.kotatsu.base.domain.MangaDataRepository
import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.download.domain.DownloadState2 import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.download.ui.service.PausingHandle
import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.LocalManga
import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.LocalStorageChanges
import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.data.PagesCache
@ -52,6 +51,7 @@ import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.await import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.utils.Throttler
import org.koitharu.kotatsu.utils.WorkManagerHelper import org.koitharu.kotatsu.utils.WorkManagerHelper
import org.koitharu.kotatsu.utils.ext.deleteAwait import org.koitharu.kotatsu.utils.ext.deleteAwait
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
@ -83,8 +83,8 @@ class DownloadWorker @AssistedInject constructor(
private val notificationManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val notificationManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@Volatile @Volatile
private var lastPublishedState: DownloadState2? = null private var lastPublishedState: DownloadState? = null
private val currentState: DownloadState2 private val currentState: DownloadState
get() = checkNotNull(lastPublishedState) get() = checkNotNull(lastPublishedState)
private val pausingHandle = PausingHandle() private val pausingHandle = PausingHandle()
@ -98,7 +98,7 @@ class DownloadWorker @AssistedInject constructor(
val manga = mangaDataRepository.findMangaById(mangaId) ?: return Result.failure() val manga = mangaDataRepository.findMangaById(mangaId) ?: return Result.failure()
val chaptersIds = inputData.getLongArray(CHAPTERS_IDS)?.takeUnless { it.isEmpty() } val chaptersIds = inputData.getLongArray(CHAPTERS_IDS)?.takeUnless { it.isEmpty() }
val downloadedIds = getDoneChapters() val downloadedIds = getDoneChapters()
lastPublishedState = DownloadState2(manga, isIndeterminate = true) lastPublishedState = DownloadState(manga, isIndeterminate = true)
return try { return try {
downloadMangaImpl(chaptersIds, downloadedIds) downloadMangaImpl(chaptersIds, downloadedIds)
Result.success(currentState.toWorkData()) Result.success(currentState.toWorkData())
@ -291,7 +291,7 @@ class DownloadWorker @AssistedInject constructor(
return file return file
} }
private suspend fun publishState(state: DownloadState2) { private suspend fun publishState(state: DownloadState) {
val previousState = currentState val previousState = currentState
lastPublishedState = state lastPublishedState = state
if (previousState.isParticularProgress && state.isParticularProgress) { if (previousState.isParticularProgress && state.isParticularProgress) {
@ -314,7 +314,7 @@ class DownloadWorker @AssistedInject constructor(
private suspend fun getDoneChapters(): LongArray { private suspend fun getDoneChapters(): LongArray {
val work = WorkManagerHelper(WorkManager.getInstance(applicationContext)).getWorkInfoById(id) val work = WorkManagerHelper(WorkManager.getInstance(applicationContext)).getWorkInfoById(id)
?: return LongArray(0) ?: return LongArray(0)
return DownloadState2.getDownloadedChapters(work.progress) return DownloadState.getDownloadedChapters(work.progress)
} }
private fun getChapters( private fun getChapters(

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.download.ui.service package org.koitharu.kotatsu.download.ui.worker
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow

@ -7,7 +7,6 @@ import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.PatternMatcher import android.os.PatternMatcher
import androidx.core.app.PendingIntentCompat import androidx.core.app.PendingIntentCompat
import org.koitharu.kotatsu.download.ui.service.PausingHandle
import org.koitharu.kotatsu.utils.ext.toUUIDOrNull import org.koitharu.kotatsu.utils.ext.toUUIDOrNull
import java.util.UUID import java.util.UUID

@ -26,7 +26,7 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSONTo
import org.koitharu.kotatsu.sync.data.SyncAuthApi import org.koitharu.kotatsu.sync.data.SyncAuthApi
import org.koitharu.kotatsu.sync.data.SyncAuthenticator import org.koitharu.kotatsu.sync.data.SyncAuthenticator
import org.koitharu.kotatsu.sync.data.SyncInterceptor import org.koitharu.kotatsu.sync.data.SyncInterceptor
import org.koitharu.kotatsu.utils.GZipInterceptor import org.koitharu.kotatsu.core.network.GZipInterceptor
import org.koitharu.kotatsu.utils.ext.parseJsonOrNull import org.koitharu.kotatsu.utils.ext.parseJsonOrNull
import org.koitharu.kotatsu.utils.ext.toContentValues import org.koitharu.kotatsu.utils.ext.toContentValues
import org.koitharu.kotatsu.utils.ext.toJson import org.koitharu.kotatsu.utils.ext.toJson

@ -1,14 +0,0 @@
package org.koitharu.kotatsu.utils
import okhttp3.Interceptor
import okhttp3.Response
import org.koitharu.kotatsu.core.network.CommonHeaders.CONTENT_ENCODING
class GZipInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val newRequest = chain.request().newBuilder()
newRequest.addHeader(CONTENT_ENCODING, "gzip")
return chain.proceed(newRequest.build())
}
}

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.download.ui.worker package org.koitharu.kotatsu.utils
import android.os.SystemClock import android.os.SystemClock

@ -3,7 +3,7 @@ package org.koitharu.kotatsu.utils.progress
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import org.koitharu.kotatsu.download.ui.service.PausingHandle import org.koitharu.kotatsu.download.ui.worker.PausingHandle
class PausingProgressJob<P>( class PausingProgressJob<P>(
job: Job, job: Job,
@ -23,4 +23,4 @@ class PausingProgressJob<P>(
@AnyThread @AnyThread
fun resume() = pausingHandle.resume() fun resume() = pausingHandle.resume()
} }

Loading…
Cancel
Save