feat(reader): Download from reader chapter list (#1110)
* Download from reader * Fix for localsource * Fix actions for merged entries * fix spotless * refactor code * catching Exception instead of Throwable --------- Co-authored-by: Cuong-Tran <cuongtran.tm@gmail.com>
This commit is contained in:
parent
46f0e26dd3
commit
5280caa60d
4 changed files with 101 additions and 10 deletions
|
|
@ -13,6 +13,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.components.AdaptiveSheet
|
||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
||||
import eu.kanade.presentation.manga.components.MangaChapterListItem
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
|
|
@ -42,6 +43,9 @@ fun ChapterListDialog(
|
|||
onClickChapter: (Chapter) -> Unit,
|
||||
onBookmark: (Chapter) -> Unit,
|
||||
dateRelativeTime: Boolean,
|
||||
// KMK -->
|
||||
onDownloadAction: ((Chapter, ChapterDownloadAction) -> Unit)? = null,
|
||||
// KMK <--
|
||||
) {
|
||||
val manga by screenModel.mangaFlow.collectAsState()
|
||||
val context = LocalContext.current
|
||||
|
|
@ -106,14 +110,22 @@ fun ChapterListDialog(
|
|||
read = chapterItem.chapter.read,
|
||||
bookmark = chapterItem.chapter.bookmark,
|
||||
selected = false,
|
||||
downloadIndicatorEnabled = false,
|
||||
// KMK -->
|
||||
downloadIndicatorEnabled = onDownloadAction != null,
|
||||
// KMK <--
|
||||
downloadStateProvider = { downloadState },
|
||||
downloadProgressProvider = { progress },
|
||||
chapterSwipeStartAction = LibraryPreferences.ChapterSwipeAction.ToggleBookmark,
|
||||
chapterSwipeEndAction = LibraryPreferences.ChapterSwipeAction.ToggleBookmark,
|
||||
onLongClick = { /*TODO*/ },
|
||||
onClick = { onClickChapter(chapterItem.chapter) },
|
||||
onDownloadClick = null,
|
||||
// KMK -->
|
||||
onDownloadClick = if (onDownloadAction != null) {
|
||||
{ action -> onDownloadAction(chapterItem.chapter, action) }
|
||||
} else {
|
||||
null
|
||||
},
|
||||
// KMK <--
|
||||
onChapterSwipe = {
|
||||
onBookmark(chapterItem.chapter)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil.NOMEDIA_FILE
|
||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import exh.source.isEhBasedSource
|
||||
import exh.util.DataSaver
|
||||
import exh.util.DataSaver.Companion.getImage
|
||||
|
|
@ -281,6 +282,11 @@ class Downloader(
|
|||
if (chapters.isEmpty()) return
|
||||
|
||||
val source = sourceManager.get(manga.source) as? HttpSource ?: return
|
||||
|
||||
// KMK -->
|
||||
if (source.id == MERGED_SOURCE_ID) return
|
||||
// KMK <--
|
||||
|
||||
val wasEmpty = queueState.value.isEmpty()
|
||||
val chaptersToQueue = chapters.asSequence()
|
||||
// Filter out those already downloaded.
|
||||
|
|
@ -330,6 +336,10 @@ class Downloader(
|
|||
* @param download the chapter to be downloaded.
|
||||
*/
|
||||
private suspend fun downloadChapter(download: Download) {
|
||||
// KMK -->
|
||||
if (download.source.id == MERGED_SOURCE_ID) return
|
||||
// KMK <--
|
||||
|
||||
val mangaDir = provider.getMangaDir(/* SY --> */ download.manga.ogTitle /* SY <-- */, download.source).getOrElse { e ->
|
||||
download.status = Download.State.ERROR
|
||||
notifier.onError(e.message, download.chapter.name, download.manga.title, download.manga.id)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.reader
|
|||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.UiModeManager
|
||||
import android.app.assist.AssistContent
|
||||
import android.content.ClipData
|
||||
|
|
@ -209,7 +208,7 @@ class ReaderActivity : BaseActivity() {
|
|||
registerSecureActivity(this)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
overrideActivityTransition(
|
||||
Activity.OVERRIDE_TRANSITION_OPEN,
|
||||
OVERRIDE_TRANSITION_OPEN,
|
||||
R.anim.shared_axis_x_push_enter,
|
||||
R.anim.shared_axis_x_push_exit,
|
||||
)
|
||||
|
|
@ -355,7 +354,7 @@ class ReaderActivity : BaseActivity() {
|
|||
super.finish()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
overrideActivityTransition(
|
||||
Activity.OVERRIDE_TRANSITION_CLOSE,
|
||||
OVERRIDE_TRANSITION_CLOSE,
|
||||
R.anim.shared_axis_x_pop_enter,
|
||||
R.anim.shared_axis_x_pop_exit,
|
||||
)
|
||||
|
|
@ -689,6 +688,11 @@ class ReaderActivity : BaseActivity() {
|
|||
}.toImmutableList()
|
||||
},
|
||||
state.dateRelativeTime,
|
||||
// KMK -->
|
||||
onDownloadAction = { chapter, action ->
|
||||
viewModel.handleDownloadAction(chapter, action)
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
// SY -->
|
||||
|
|
@ -1061,7 +1065,7 @@ class ReaderActivity : BaseActivity() {
|
|||
try {
|
||||
readingModeToast?.cancel()
|
||||
readingModeToast = toast(ReadingMode.fromPreference(mode).stringRes)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
} catch (_: ArrayIndexOutOfBoundsException) {
|
||||
logcat(LogPriority.ERROR) { "Unknown reading mode: $mode" }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import eu.kanade.domain.sync.SyncPreferences
|
|||
import eu.kanade.domain.track.interactor.TrackChapter
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
|
|
@ -72,6 +73,7 @@ import kotlinx.coroutines.flow.mapLatest
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.common.preference.toggle
|
||||
|
|
@ -169,6 +171,69 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
field = value
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
fun handleDownloadAction(chapter: Chapter, action: ChapterDownloadAction) {
|
||||
when (action) {
|
||||
ChapterDownloadAction.START -> downloadChapter(chapter)
|
||||
ChapterDownloadAction.START_NOW -> downloadManager.startDownloadNow(chapter.id)
|
||||
ChapterDownloadAction.CANCEL -> cancelDownload(chapter.id)
|
||||
ChapterDownloadAction.DELETE -> deleteChapter(chapter)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chapter the chapter to download.
|
||||
*/
|
||||
private fun downloadChapter(chapter: Chapter) {
|
||||
viewModelScope.launch {
|
||||
val manga = manga?.let {
|
||||
if (it.source == MERGED_SOURCE_ID) {
|
||||
state.value.mergedManga?.get(chapter.mangaId) ?: return@launch
|
||||
} else {
|
||||
it
|
||||
}
|
||||
} ?: return@launch
|
||||
downloadManager.downloadChapters(manga, listOf(chapter))
|
||||
downloadManager.startDownloads()
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelDownload(chapterId: Long) {
|
||||
viewModelScope.launch {
|
||||
val activeDownload = downloadManager.getQueuedDownloadOrNull(chapterId) ?: return@launch
|
||||
downloadManager.cancelQueuedDownloads(listOf(activeDownload))
|
||||
// TODO: updateDownloadState(activeDownload.apply { status = Download.State.NOT_DOWNLOADED })
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteChapter(chapter: Chapter) {
|
||||
viewModelScope.launchNonCancellable {
|
||||
try {
|
||||
val manga = if (manga?.source == MERGED_SOURCE_ID) {
|
||||
state.value.mergedManga?.get(chapter.mangaId) ?: return@launchNonCancellable
|
||||
} else {
|
||||
manga ?: return@launchNonCancellable
|
||||
}
|
||||
val source = sourceManager.get(manga.source) ?: return@launchNonCancellable
|
||||
downloadManager.deleteChapters(
|
||||
listOf(chapter),
|
||||
manga,
|
||||
source,
|
||||
ignoreCategoryExclusion = true,
|
||||
)
|
||||
// // KMK -->
|
||||
// if (source.isLocal()) {
|
||||
// // TODO: Refresh chapters state for Local source
|
||||
// fetchChaptersFromSource()
|
||||
// }
|
||||
// // KMK <--
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
/**
|
||||
* The chapter loader for the loaded manga. It'll be null until [manga] is set.
|
||||
*/
|
||||
|
|
@ -662,7 +727,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
* if setting is enabled and [currentChapter] is queued for download
|
||||
*/
|
||||
private fun cancelQueuedDownloads(currentChapter: ReaderChapter): Download? {
|
||||
return downloadManager.getQueuedDownloadOrNull(currentChapter.chapter.id!!.toLong())?.also {
|
||||
return downloadManager.getQueuedDownloadOrNull(currentChapter.chapter.id!!)?.also {
|
||||
downloadManager.cancelQueuedDownloads(listOf(it))
|
||||
}
|
||||
}
|
||||
|
|
@ -864,7 +929,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
viewModelScope.launchNonCancellable {
|
||||
updateChapter.await(
|
||||
ChapterUpdate(
|
||||
id = chapter.id!!.toLong(),
|
||||
id = chapter.id!!,
|
||||
bookmark = bookmarked,
|
||||
),
|
||||
)
|
||||
|
|
@ -997,7 +1062,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
val chapter = page.chapter.chapter
|
||||
val filenameSuffix = " - ${page.number}"
|
||||
return DiskUtil.buildValidFilename(
|
||||
"${manga.title} - ${chapter.name}".takeBytes(DiskUtil.MAX_FILE_NAME_BYTES - filenameSuffix.byteSize()),
|
||||
"${manga.title} - ${chapter.name}".takeBytes(MAX_FILE_NAME_BYTES - filenameSuffix.byteSize()),
|
||||
) + filenameSuffix
|
||||
}
|
||||
|
||||
|
|
@ -1293,7 +1358,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
} else {
|
||||
SetAsCoverResult.AddToLibraryFirst
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
SetAsCoverResult.Error
|
||||
}
|
||||
eventChannel.send(Event.SetCoverResult(result))
|
||||
|
|
|
|||
Loading…
Reference in a new issue