Support batch chapter update api

This commit is contained in:
Syer10
2022-11-15 14:27:46 -05:00
parent 49bee53a67
commit fab3907d08
14 changed files with 473 additions and 65 deletions

View File

@@ -6,9 +6,9 @@ object Config {
// Tachidesk-Server version
const val tachideskVersion = "v0.6.5"
// Match this to the Tachidesk-Server commit count
const val serverCode = 1148
const val serverCode = 1156
const val preview = true
const val previewCommit = "2195c3df765c3e1e435595d9edbec8ad3590bf46"
const val previewCommit = "67e09e2e1d452e041c46a334f1b473f38c5fc25b"
val desktopJvmTarget = JavaVersion.VERSION_17
val androidJvmTarget = JavaVersion.VERSION_11

View File

@@ -0,0 +1,250 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.chapter.interactor
import ca.gosyer.jui.domain.chapter.model.Chapter
import ca.gosyer.jui.domain.chapter.model.ChapterBatchEditInput
import ca.gosyer.jui.domain.chapter.model.ChapterChange
import ca.gosyer.jui.domain.chapter.model.MangaChapterBatchEditInput
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
import ca.gosyer.jui.domain.manga.model.Manga
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
import kotlin.jvm.JvmName
class BatchUpdateChapter @Inject constructor(private val chapterRepository: ChapterRepository) {
@JvmName("awaitChapters")
suspend fun await(
mangaId: Long,
chapters: List<Chapter>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(mangaId, chapters, isRead, isBookmarked, lastPageRead, delete)
.catch {
onError(it)
log.warn(it) { "Failed to update multiple chapters of $mangaId" }
}
.collect()
suspend fun await(
mangaId: Long,
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(mangaId, chapterIds, isRead, isBookmarked, lastPageRead, delete)
.catch {
onError(it)
log.warn(it) { "Failed to update multiple chapters of $mangaId" }
}
.collect()
@JvmName("awaitChapters")
suspend fun await(
manga: Manga,
chapters: List<Chapter>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(manga, chapters, isRead, isBookmarked, lastPageRead, delete)
.catch {
onError(it)
log.warn(it) { "Failed to update multiple chapters of ${manga.title}(${manga.id})" }
}
.collect()
suspend fun await(
manga: Manga,
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(manga, chapterIds, isRead, isBookmarked, lastPageRead, delete)
.catch {
onError(it)
log.warn(it) { "Failed to update multiple chapters of ${manga.title}(${manga.id})" }
}
.collect()
@JvmName("awaitChapters")
suspend fun await(
chapters: List<Chapter>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(chapters, isRead, isBookmarked, lastPageRead, delete)
.catch {
onError(it)
log.warn(it) { "Failed to update multiple chapters" }
}
.collect()
suspend fun await(
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(chapterIds, isRead, isBookmarked, lastPageRead, delete)
.catch {
onError(it)
log.warn(it) { "Failed to update update multiple chapters" }
}
.collect()
@JvmName("asFlowChapters")
fun asFlow(
mangaId: Long,
chapters: List<Chapter>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = getFlow(
mangaId = mangaId,
chapterIds = chapters.map { it.id },
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
fun asFlow(
mangaId: Long,
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = getFlow(
mangaId = mangaId,
chapterIds = chapterIds,
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
@JvmName("asFlowChapters")
fun asFlow(
manga: Manga,
chapters: List<Chapter>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = getFlow(
mangaId = manga.id,
chapterIds = chapters.map { it.id },
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
fun asFlow(
manga: Manga,
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = getFlow(
mangaId = manga.id,
chapterIds = chapterIds,
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
@JvmName("asFlowChapters")
fun asFlow(
chapters: List<Chapter>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = getFlow(
mangaId = null,
chapterIds = chapters.map { it.id },
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
fun asFlow(
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = getFlow(
mangaId = null,
chapterIds = chapterIds,
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
private fun getFlow(
mangaId: Long?,
chapterIds: List<Long>,
isRead: Boolean? = null,
isBookmarked: Boolean? = null,
lastPageRead: Int? = null,
delete: Boolean? = null
) = if (mangaId != null) {
chapterRepository.batchUpdateChapter(
mangaId,
MangaChapterBatchEditInput(
chapterIds = chapterIds,
change = ChapterChange(
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
)
)
} else {
chapterRepository.batchUpdateChapter(
ChapterBatchEditInput(
chapterIds = chapterIds,
change = ChapterChange(
isRead = isRead,
isBookmarked = isBookmarked,
lastPageRead = lastPageRead,
delete = delete
)
)
)
}
companion object {
private val log = logging()
}
}

View File

@@ -0,0 +1,15 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.chapter.model
import kotlinx.serialization.Serializable
@Serializable
data class ChapterBatchEditInput(
val chapterIds: List<Long>? = null,
val change: ChapterChange?
)

View File

@@ -0,0 +1,17 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.chapter.model
import kotlinx.serialization.Serializable
@Serializable
data class ChapterChange(
val isRead: Boolean? = null,
val isBookmarked: Boolean? = null,
val lastPageRead: Int? = null,
val delete: Boolean? = null
)

View File

@@ -0,0 +1,16 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.chapter.model
import kotlinx.serialization.Serializable
@Serializable
data class MangaChapterBatchEditInput(
val chapterIds: List<Long>? = null,
val chapterIndexes: List<Int>? = null,
val change: ChapterChange?
)

View File

@@ -7,11 +7,16 @@
package ca.gosyer.jui.domain.chapter.service
import ca.gosyer.jui.domain.chapter.model.Chapter
import ca.gosyer.jui.domain.chapter.model.ChapterBatchEditInput
import ca.gosyer.jui.domain.chapter.model.MangaChapterBatchEditInput
import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.DELETE
import de.jensklingenberg.ktorfit.http.Field
import de.jensklingenberg.ktorfit.http.FormUrlEncoded
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.Headers
import de.jensklingenberg.ktorfit.http.PATCH
import de.jensklingenberg.ktorfit.http.POST
import de.jensklingenberg.ktorfit.http.Path
import de.jensklingenberg.ktorfit.http.Query
import de.jensklingenberg.ktorfit.http.ReqBuilder
@@ -44,6 +49,19 @@ interface ChapterRepository {
@Field("markPrevRead") markPreviousRead: Boolean? = null
): Flow<HttpResponse>
@POST("api/v1/manga/{mangaId}/chapter/batch")
@Headers("Content-Type: application/json")
fun batchUpdateChapter(
@Path("mangaId") mangaId: Long,
@Body input: MangaChapterBatchEditInput
): Flow<HttpResponse>
@POST("api/v1/chapter/batch")
@Headers("Content-Type: application/json")
fun batchUpdateChapter(
@Body input: ChapterBatchEditInput
): Flow<HttpResponse>
@GET("api/v1/manga/{mangaId}/chapter/{chapterIndex}/page/{pageNum}")
fun getPage(
@Path("mangaId") mangaId: Long,

View File

@@ -0,0 +1,39 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.manga.interactor
import ca.gosyer.jui.domain.manga.model.Manga
import ca.gosyer.jui.domain.manga.service.MangaRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.singleOrNull
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class GetMangaFull @Inject constructor(private val mangaRepository: MangaRepository) {
suspend fun await(mangaId: Long, onError: suspend (Throwable) -> Unit = {}) = asFlow(mangaId)
.catch {
onError(it)
log.warn(it) { "Failed to get full manga $mangaId" }
}
.singleOrNull()
suspend fun await(manga: Manga, onError: suspend (Throwable) -> Unit = {}) = asFlow(manga)
.catch {
onError(it)
log.warn(it) { "Failed to get full manga ${manga.title}(${manga.id})" }
}
.singleOrNull()
fun asFlow(mangaId: Long) = mangaRepository.getMangaFull(mangaId)
fun asFlow(manga: Manga) = mangaRepository.getMangaFull(manga.id)
companion object {
private val log = logging()
}
}

View File

@@ -0,0 +1,39 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.manga.interactor
import ca.gosyer.jui.domain.manga.model.Manga
import ca.gosyer.jui.domain.manga.service.MangaRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.singleOrNull
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class RefreshMangaFull @Inject constructor(private val mangaRepository: MangaRepository) {
suspend fun await(mangaId: Long, onError: suspend (Throwable) -> Unit = {}) = asFlow(mangaId)
.catch {
onError(it)
log.warn(it) { "Failed to refresh full manga $mangaId" }
}
.singleOrNull()
suspend fun await(manga: Manga, onError: suspend (Throwable) -> Unit = {}) = asFlow(manga)
.catch {
onError(it)
log.warn(it) { "Failed to refresh full manga ${manga.title}(${manga.id})" }
}
.singleOrNull()
fun asFlow(mangaId: Long) = mangaRepository.getMangaFull(mangaId, true)
fun asFlow(manga: Manga) = mangaRepository.getMangaFull(manga.id, true)
companion object {
private val log = logging()
}
}

View File

@@ -8,6 +8,7 @@ package ca.gosyer.jui.domain.manga.model
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import ca.gosyer.jui.domain.chapter.model.Chapter
import ca.gosyer.jui.domain.source.model.Source
import ca.gosyer.jui.i18n.MR
import dev.icerock.moko.resources.StringResource
@@ -33,14 +34,15 @@ data class Manga(
val freshData: Boolean,
val meta: MangaMeta,
val realUrl: String?,
val lastFetchedAt: Long? = 0, // todo remove default
val chaptersLastFetchedAt: Long? = 0, // todo remove default
val lastFetchedAt: Long?,
val chaptersLastFetchedAt: Long?,
val inLibraryAt: Long,
val unreadCount: Int?,
val downloadCount: Int?,
val chapterCount: Int? = null, // todo remove default
val age: Long? = null, // todo remove default
val chaptersAge: Long? = null // todo remove default
val chapterCount: Int?,
var lastChapterRead: Chapter?,
val age: Long?,
val chaptersAge: Long?
)
@Serializable

View File

@@ -26,6 +26,12 @@ interface MangaRepository {
@Query("onlineFetch") refresh: Boolean = false
): Flow<Manga>
@GET("api/v1/manga/{mangaId}/full")
fun getMangaFull(
@Path("mangaId") mangaId: Long,
@Query("onlineFetch") refresh: Boolean = false
): Flow<Manga>
@GET("api/v1/manga/{mangaId}/thumbnail")
fun getMangaThumbnail(
@Path("mangaId") mangaId: Long,

View File

@@ -87,6 +87,10 @@ data class ChapterDownloadItem(
_downloadState.value = ChapterDownloadState.NotDownloaded
}
fun setNotDownloaded() {
_downloadState.value = ChapterDownloadState.NotDownloaded
}
fun isSelected(selectedItems: List<Long>): Boolean {
return (chapter.id in selectedItems).also { _isSelected.value = it }
}

View File

@@ -13,12 +13,11 @@ import ca.gosyer.jui.domain.category.interactor.GetCategories
import ca.gosyer.jui.domain.category.interactor.GetMangaCategories
import ca.gosyer.jui.domain.category.interactor.RemoveMangaFromCategory
import ca.gosyer.jui.domain.category.model.Category
import ca.gosyer.jui.domain.chapter.interactor.BatchUpdateChapter
import ca.gosyer.jui.domain.chapter.interactor.DeleteChapterDownload
import ca.gosyer.jui.domain.chapter.interactor.GetChapters
import ca.gosyer.jui.domain.chapter.interactor.RefreshChapters
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterBookmarked
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterMarkPreviousRead
import ca.gosyer.jui.domain.chapter.interactor.UpdateChapterRead
import ca.gosyer.jui.domain.chapter.model.Chapter
import ca.gosyer.jui.domain.download.interactor.BatchChapterDownload
import ca.gosyer.jui.domain.download.interactor.QueueChapterDownload
@@ -60,8 +59,7 @@ class MangaScreenViewModel @Inject constructor(
private val refreshManga: RefreshManga,
private val getChapters: GetChapters,
private val refreshChapters: RefreshChapters,
private val updateChapterRead: UpdateChapterRead,
private val updateChapterBookmarked: UpdateChapterBookmarked,
private val batchUpdateChapter: BatchUpdateChapter,
private val updateChapterMarkPreviousRead: UpdateChapterMarkPreviousRead,
private val queueChapterDownload: QueueChapterDownload,
private val stopChapterDownload: StopChapterDownload,
@@ -229,35 +227,29 @@ class MangaScreenViewModel @Inject constructor(
}
}
private fun findChapter(index: Int) = chapters.value.find { it.chapter.index == index }?.chapter
private fun setRead(index: Int, read: Boolean) {
val chapter = findChapter(index) ?: return
if (chapter.read == read) return
private fun setRead(chapterIds: List<Long>, read: Boolean) {
scope.launch {
manga.value?.let { manga ->
updateChapterRead.await(manga, index, read = read, onError = { toast(it.message.orEmpty()) })
batchUpdateChapter.await(manga, chapterIds, isRead = read, onError = { toast(it.message.orEmpty()) })
refreshChaptersAsync(manga.id).await()
_selectedIds.value = _selectedIds.value.minus(chapter.id).toImmutableList()
_selectedIds.value = persistentListOf()
}
}
}
fun markRead(index: Int) = setRead(index, true)
fun markUnread(index: Int) = setRead(index, false)
fun markRead(id: Long?) = setRead(listOfNotNull(id).ifEmpty { _selectedIds.value }, true)
fun markUnread(id: Long?) = setRead(listOfNotNull(id).ifEmpty { _selectedIds.value }, false)
private fun setBookmarked(index: Int, bookmark: Boolean) {
val chapter = findChapter(index) ?: return
if (chapter.bookmarked == bookmark) return
private fun setBookmarked(chapterIds: List<Long>, bookmark: Boolean) {
scope.launch {
manga.value?.let { manga ->
updateChapterBookmarked.await(manga, index, bookmarked = bookmark, onError = { toast(it.message.orEmpty()) })
batchUpdateChapter.await(manga, chapterIds, isBookmarked = bookmark, onError = { toast(it.message.orEmpty()) })
refreshChaptersAsync(manga.id).await()
_selectedIds.value = _selectedIds.value.minus(chapter.id).toImmutableList()
_selectedIds.value = persistentListOf()
}
}
}
fun bookmarkChapter(index: Int) = setBookmarked(index, true)
fun unBookmarkChapter(index: Int) = setBookmarked(index, false)
fun bookmarkChapter(id: Long?) = setBookmarked(listOfNotNull(id).ifEmpty { _selectedIds.value }, true)
fun unBookmarkChapter(id: Long?) = setBookmarked(listOfNotNull(id).ifEmpty { _selectedIds.value }, false)
fun markPreviousRead(index: Int) {
scope.launch {
@@ -275,10 +267,20 @@ class MangaScreenViewModel @Inject constructor(
}
}
fun deleteDownload(index: Int) {
fun deleteDownload(id: Long?) {
scope.launch {
chapters.value.find { it.chapter.index == index }
?.deleteDownload(deleteChapterDownload)
if (id == null) {
val manga = _manga.value ?: return@launch
val chapterIds = _selectedIds.value
batchUpdateChapter.await(manga, chapterIds, delete = true, onError = { toast(it.message.orEmpty()) })
chapterIds.forEach { id ->
chapters.value.find { it.chapter.id == id }?.setNotDownloaded()
}
_selectedIds.value = persistentListOf()
} else {
chapters.value.find { it.chapter.id == id }
?.deleteDownload(deleteChapterDownload)
}
}
}

View File

@@ -59,14 +59,14 @@ fun ChapterItem(
chapterDownload: ChapterDownloadItem,
format: (Instant) -> String,
onClick: (Int) -> Unit,
markRead: (Int) -> Unit,
markUnread: (Int) -> Unit,
bookmarkChapter: (Int) -> Unit,
unBookmarkChapter: (Int) -> Unit,
markRead: (Long) -> Unit,
markUnread: (Long) -> Unit,
bookmarkChapter: (Long) -> Unit,
unBookmarkChapter: (Long) -> Unit,
markPreviousAsRead: (Int) -> Unit,
onClickDownload: (Int) -> Unit,
onClickStopDownload: (Int) -> Unit,
onClickDeleteChapter: (Int) -> Unit,
onClickDeleteChapter: (Long) -> Unit,
onSelectChapter: (Int) -> Unit,
onUnselectChapter: (Int) -> Unit
) {
@@ -79,10 +79,10 @@ fun ChapterItem(
.selectedBackground(isSelected)
.chapterItemModifier(
onClick = { onClick(chapter.index) },
markRead = { markRead(chapter.index) }.takeUnless { chapter.read },
markUnread = { markUnread(chapter.index) }.takeIf { chapter.read },
bookmarkChapter = { bookmarkChapter(chapter.index) }.takeUnless { chapter.bookmarked },
unBookmarkChapter = { unBookmarkChapter(chapter.index) }.takeIf { chapter.bookmarked },
markRead = { markRead(chapter.id) }.takeUnless { chapter.read },
markUnread = { markUnread(chapter.id) }.takeIf { chapter.read },
bookmarkChapter = { bookmarkChapter(chapter.id) }.takeUnless { chapter.bookmarked },
unBookmarkChapter = { unBookmarkChapter(chapter.id) }.takeIf { chapter.bookmarked },
markPreviousAsRead = { markPreviousAsRead(chapter.index) },
onSelectChapter = { onSelectChapter(chapter.index) }.takeUnless { chapterDownload.isSelected.value },
onUnselectChapter = { onUnselectChapter(chapter.index) }.takeIf { chapterDownload.isSelected.value }
@@ -157,7 +157,7 @@ fun ChapterItem(
chapterDownload,
{ onClickDownload(it.index) },
{ onClickStopDownload(it.index) },
{ onClickDeleteChapter(it.index) }
{ onClickDeleteChapter(it.id) }
)
}
}

View File

@@ -97,13 +97,13 @@ fun MangaScreenContent(
downloadNext: (Int) -> Unit,
downloadUnread: () -> Unit,
downloadAll: () -> Unit,
markRead: (Int) -> Unit,
markUnread: (Int) -> Unit,
bookmarkChapter: (Int) -> Unit,
unBookmarkChapter: (Int) -> Unit,
markRead: (Long?) -> Unit,
markUnread: (Long?) -> Unit,
bookmarkChapter: (Long?) -> Unit,
unBookmarkChapter: (Long?) -> Unit,
markPreviousRead: (Int) -> Unit,
downloadChapter: (Int) -> Unit,
deleteDownload: (Int) -> Unit,
deleteDownload: (Long?) -> Unit,
stopDownloadingChapter: (Int) -> Unit,
onSelectChapter: (Int) -> Unit,
onUnselectChapter: (Int) -> Unit,
@@ -178,12 +178,12 @@ fun MangaScreenContent(
visible = inActionMode,
items = getBottomActionItems(
selectedItems = selectedItems,
markRead = markRead,
markUnread = markUnread,
bookmarkChapter = bookmarkChapter,
unBookmarkChapter = unBookmarkChapter,
markRead = { markRead(null) },
markUnread = { markUnread(null) },
bookmarkChapter = { bookmarkChapter(null) },
unBookmarkChapter = { unBookmarkChapter(null) },
markPreviousAsRead = markPreviousRead,
deleteChapter = deleteDownload,
deleteChapter = { deleteDownload(null) },
downloadChapters = downloadChapters
)
)
@@ -366,35 +366,35 @@ private fun getActionModeActionItems(
@Stable
private fun getBottomActionItems(
selectedItems: ImmutableList<ChapterDownloadItem>,
markRead: (Int) -> Unit,
markUnread: (Int) -> Unit,
bookmarkChapter: (Int) -> Unit,
unBookmarkChapter: (Int) -> Unit,
markRead: () -> Unit,
markUnread: () -> Unit,
bookmarkChapter: () -> Unit,
unBookmarkChapter: () -> Unit,
markPreviousAsRead: (Int) -> Unit,
deleteChapter: (Int) -> Unit,
deleteChapter: () -> Unit,
downloadChapters: () -> Unit
): ImmutableList<BottomActionItem> {
return listOfNotNull(
BottomActionItem(
name = stringResource(MR.strings.action_bookmark),
icon = Icons.Rounded.BookmarkAdd,
onClick = { bookmarkChapter(selectedItems.first().chapter.index) }
).takeIf { selectedItems.fastAny { !it.chapter.bookmarked } && selectedItems.size == 1 },
onClick = bookmarkChapter
).takeIf { selectedItems.fastAny { !it.chapter.bookmarked } },
BottomActionItem(
name = stringResource(MR.strings.action_remove_bookmark),
icon = Icons.Rounded.BookmarkRemove,
onClick = { unBookmarkChapter(selectedItems.first().chapter.index) }
).takeIf { selectedItems.fastAny { it.chapter.bookmarked } && selectedItems.size == 1 },
onClick = unBookmarkChapter
).takeIf { selectedItems.fastAny { it.chapter.bookmarked } },
BottomActionItem(
name = stringResource(MR.strings.action_mark_as_read),
icon = Icons.Rounded.DoneAll,
onClick = { markRead(selectedItems.first().chapter.index) }
).takeIf { selectedItems.fastAny { !it.chapter.read } && selectedItems.size == 1 },
onClick = markRead
).takeIf { selectedItems.fastAny { !it.chapter.read } },
BottomActionItem(
name = stringResource(MR.strings.action_mark_as_unread),
icon = Icons.Rounded.RemoveDone,
onClick = { markUnread(selectedItems.first().chapter.index) }
).takeIf { selectedItems.fastAny { it.chapter.read } && selectedItems.size == 1 },
onClick = markUnread
).takeIf { selectedItems.fastAny { it.chapter.read } },
BottomActionItem(
name = stringResource(MR.strings.action_mark_previous_read),
icon = JuiAssets.DonePrev,
@@ -408,7 +408,7 @@ private fun getBottomActionItems(
BottomActionItem(
name = stringResource(MR.strings.action_delete),
icon = Icons.Rounded.Delete,
onClick = { deleteChapter(selectedItems.first().chapter.index) }
).takeIf { selectedItems.fastAny { it.downloadState.value == ChapterDownloadState.Downloaded } && selectedItems.size == 1 }
onClick = deleteChapter
).takeIf { selectedItems.fastAny { it.downloadState.value == ChapterDownloadState.Downloaded } }
).toImmutableList()
}