Support multiple branches in saved manga
This commit is contained in:
@@ -41,6 +41,7 @@ import org.koitharu.kotatsu.details.ui.adapter.BranchesAdapter
|
|||||||
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
||||||
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
|
||||||
|
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||||
import org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity
|
import org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity
|
||||||
@@ -193,23 +194,9 @@ class DetailsActivity :
|
|||||||
R.id.action_save -> {
|
R.id.action_save -> {
|
||||||
viewModel.manga.value?.let {
|
viewModel.manga.value?.let {
|
||||||
val chaptersCount = it.chapters?.size ?: 0
|
val chaptersCount = it.chapters?.size ?: 0
|
||||||
if (chaptersCount > 5) {
|
val branches = viewModel.branches.value.orEmpty()
|
||||||
MaterialAlertDialogBuilder(this)
|
if (chaptersCount > 5 || branches.size > 1) {
|
||||||
.setTitle(R.string.save_manga)
|
showSaveConfirmation(it, chaptersCount, branches)
|
||||||
.setMessage(
|
|
||||||
getString(
|
|
||||||
R.string.large_manga_save_confirm,
|
|
||||||
resources.getQuantityString(
|
|
||||||
R.plurals.chapters,
|
|
||||||
chaptersCount,
|
|
||||||
chaptersCount
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.save) { _, _ ->
|
|
||||||
DownloadService.start(this, it)
|
|
||||||
}.show()
|
|
||||||
} else {
|
} else {
|
||||||
DownloadService.start(this, it)
|
DownloadService.start(this, it)
|
||||||
}
|
}
|
||||||
@@ -335,6 +322,36 @@ class DetailsActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showSaveConfirmation(manga: Manga, chaptersCount: Int, branches: List<String?>) {
|
||||||
|
val dialogBuilder = MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.save_manga)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
if (branches.size > 1) {
|
||||||
|
val items = Array(branches.size) { i -> branches[i].orEmpty() }
|
||||||
|
val currentBranch = viewModel.selectedBranchIndex.value ?: -1
|
||||||
|
val checkedIndices = BooleanArray(branches.size) { i -> i == currentBranch }
|
||||||
|
dialogBuilder.setMultiChoiceItems(items, checkedIndices) { _, i, checked ->
|
||||||
|
checkedIndices[i] = checked
|
||||||
|
}.setPositiveButton(R.string.save) { _, _ ->
|
||||||
|
val selectedBranches = branches.filterIndexedTo(HashSet()) { i, _ -> checkedIndices[i] }
|
||||||
|
val chaptersIds = manga.chapters?.mapNotNullToSet { c ->
|
||||||
|
if (c.branch in selectedBranches) c.id else null
|
||||||
|
}
|
||||||
|
DownloadService.start(this, manga, chaptersIds)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dialogBuilder.setMessage(
|
||||||
|
getString(
|
||||||
|
R.string.large_manga_save_confirm,
|
||||||
|
resources.getQuantityString(R.plurals.chapters, chaptersCount, chaptersCount)
|
||||||
|
)
|
||||||
|
).setPositiveButton(R.string.save) { _, _ ->
|
||||||
|
DownloadService.start(this, manga)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialogBuilder.show()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newIntent(context: Context, manga: Manga): Intent {
|
fun newIntent(context: Context, manga: Manga): Intent {
|
||||||
|
|||||||
@@ -267,10 +267,10 @@ class DetailsViewModel(
|
|||||||
val dateFormat = settings.getDateFormat()
|
val dateFormat = settings.getDateFormat()
|
||||||
for (i in sourceChapters.indices) {
|
for (i in sourceChapters.indices) {
|
||||||
val chapter = sourceChapters[i]
|
val chapter = sourceChapters[i]
|
||||||
|
val localChapter = chaptersMap.remove(chapter.id)
|
||||||
if (chapter.branch != branch) {
|
if (chapter.branch != branch) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val localChapter = chaptersMap.remove(chapter.id)
|
|
||||||
result += localChapter?.toListItem(
|
result += localChapter?.toListItem(
|
||||||
isCurrent = i == currentIndex,
|
isCurrent = i == currentIndex,
|
||||||
isUnread = i > currentIndex,
|
isUnread = i > currentIndex,
|
||||||
@@ -289,15 +289,19 @@ class DetailsViewModel(
|
|||||||
}
|
}
|
||||||
if (chaptersMap.isNotEmpty()) { // some chapters on device but not online source
|
if (chaptersMap.isNotEmpty()) { // some chapters on device but not online source
|
||||||
result.ensureCapacity(result.size + chaptersMap.size)
|
result.ensureCapacity(result.size + chaptersMap.size)
|
||||||
chaptersMap.values.mapTo(result) {
|
chaptersMap.values.mapNotNullTo(result) {
|
||||||
it.toListItem(
|
if (it.branch == branch) {
|
||||||
isCurrent = false,
|
it.toListItem(
|
||||||
isUnread = true,
|
isCurrent = false,
|
||||||
isNew = false,
|
isUnread = true,
|
||||||
isMissing = false,
|
isNew = false,
|
||||||
isDownloaded = false,
|
isMissing = false,
|
||||||
dateFormat = dateFormat,
|
isDownloaded = false,
|
||||||
)
|
dateFormat = dateFormat,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.sortBy { it.chapter.number }
|
result.sortBy { it.chapter.number }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class MangaIndex(source: String?) {
|
|||||||
jo.put("uploadDate", chapter.uploadDate)
|
jo.put("uploadDate", chapter.uploadDate)
|
||||||
jo.put("scanlator", chapter.scanlator)
|
jo.put("scanlator", chapter.scanlator)
|
||||||
jo.put("branch", chapter.branch)
|
jo.put("branch", chapter.branch)
|
||||||
jo.put("entries", "%03d\\d{3}".format(chapter.number))
|
jo.put("entries", "%08d_%03d\\d{3}".format(chapter.branch.hashCode(), chapter.number))
|
||||||
chapters.put(chapter.id.toString(), jo)
|
chapters.put(chapter.id.toString(), jo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class CbzMangaOutput(
|
|||||||
|
|
||||||
suspend fun addCover(file: File, ext: String) {
|
suspend fun addCover(file: File, ext: String) {
|
||||||
val name = buildString {
|
val name = buildString {
|
||||||
append(FILENAME_PATTERN.format(0, 0))
|
append(FILENAME_PATTERN.format(0, 0, 0))
|
||||||
if (ext.isNotEmpty() && ext.length <= 4) {
|
if (ext.isNotEmpty() && ext.length <= 4) {
|
||||||
append('.')
|
append('.')
|
||||||
append(ext)
|
append(ext)
|
||||||
@@ -50,7 +50,7 @@ class CbzMangaOutput(
|
|||||||
|
|
||||||
suspend fun addPage(chapter: MangaChapter, file: File, pageNumber: Int, ext: String) {
|
suspend fun addPage(chapter: MangaChapter, file: File, pageNumber: Int, ext: String) {
|
||||||
val name = buildString {
|
val name = buildString {
|
||||||
append(FILENAME_PATTERN.format(chapter.number, pageNumber))
|
append(FILENAME_PATTERN.format(chapter.branch.hashCode(), chapter.number, pageNumber))
|
||||||
if (ext.isNotEmpty() && ext.length <= 4) {
|
if (ext.isNotEmpty() && ext.length <= 4) {
|
||||||
append('.')
|
append('.')
|
||||||
append(ext)
|
append(ext)
|
||||||
@@ -105,7 +105,7 @@ class CbzMangaOutput(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val FILENAME_PATTERN = "%03d%03d"
|
private const val FILENAME_PATTERN = "%08d_%03d%03d"
|
||||||
|
|
||||||
const val ENTRY_NAME_INDEX = "index.json"
|
const val ENTRY_NAME_INDEX = "index.json"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user