mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-26 23:18:17 +03:00
parent
c6daaae9e6
commit
24e9e1846d
26 changed files with 86 additions and 308 deletions
|
@ -61,9 +61,9 @@ class DelayedAnimeTrackingUpdateJob(context: Context, workerParams: WorkerParame
|
|||
private const val TAG = "DelayedTrackingUpdate"
|
||||
|
||||
fun setupTask(context: Context) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = NetworkType.CONNECTED,
|
||||
)
|
||||
|
||||
val request = OneTimeWorkRequestBuilder<DelayedAnimeTrackingUpdateJob>()
|
||||
.setConstraints(constraints)
|
||||
|
|
|
@ -61,9 +61,9 @@ class DelayedMangaTrackingUpdateJob(context: Context, workerParams: WorkerParame
|
|||
private const val TAG = "DelayedTrackingUpdate"
|
||||
|
||||
fun setupTask(context: Context) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = NetworkType.CONNECTED,
|
||||
)
|
||||
|
||||
val request = OneTimeWorkRequestBuilder<DelayedMangaTrackingUpdateJob>()
|
||||
.setConstraints(constraints)
|
||||
|
|
|
@ -3,6 +3,7 @@ package eu.kanade.presentation.components
|
|||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import eu.kanade.presentation.entries.DownloadAction
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -19,50 +20,20 @@ fun EntryDownloadDropdownMenu(
|
|||
expanded = expanded,
|
||||
onDismissRequest = onDismissRequest,
|
||||
) {
|
||||
val download1 = if (isManga) R.string.download_1 else R.string.download_1_episode
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(download1)) },
|
||||
onClick = {
|
||||
onDownloadClicked(DownloadAction.NEXT_1_ITEM)
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
val download5 = if (isManga) R.string.download_5 else R.string.download_5_episodes
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(download5)) },
|
||||
onClick = {
|
||||
onDownloadClicked(DownloadAction.NEXT_5_ITEMS)
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
val download10 = if (isManga) R.string.download_10 else R.string.download_10_episodes
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(download10)) },
|
||||
onClick = {
|
||||
onDownloadClicked(DownloadAction.NEXT_10_ITEMS)
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.download_custom)) },
|
||||
onClick = {
|
||||
onDownloadClicked(DownloadAction.CUSTOM)
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
val downloadAmount = if (isManga) R.plurals.download_amount_manga else R.plurals.download_amount_anime
|
||||
val downloadUnviewed = if (isManga) R.string.download_unread else R.string.download_unseen
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(downloadUnviewed)) },
|
||||
onClick = {
|
||||
onDownloadClicked(DownloadAction.UNVIEWED_ITEMS)
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
if (includeDownloadAllOption) {
|
||||
listOfNotNull(
|
||||
DownloadAction.NEXT_1_ITEM to pluralStringResource(downloadAmount, 1, 1),
|
||||
DownloadAction.NEXT_5_ITEMS to pluralStringResource(downloadAmount, 5, 5),
|
||||
DownloadAction.NEXT_10_ITEMS to pluralStringResource(downloadAmount, 10, 10),
|
||||
DownloadAction.NEXT_25_ITEMS to pluralStringResource(downloadAmount, 25, 25),
|
||||
DownloadAction.UNVIEWED_ITEMS to stringResource(downloadUnviewed),
|
||||
(DownloadAction.ALL_ITEMS to stringResource(R.string.download_all)).takeIf { includeDownloadAllOption },
|
||||
).map { (downloadAction, string) ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.download_all)) },
|
||||
text = { Text(text = string) },
|
||||
onClick = {
|
||||
onDownloadClicked(DownloadAction.ALL_ITEMS)
|
||||
onDownloadClicked(downloadAction)
|
||||
onDismissRequest()
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
package eu.kanade.presentation.entries
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ChevronLeft
|
||||
import androidx.compose.material.icons.outlined.ChevronRight
|
||||
import androidx.compose.material.icons.outlined.KeyboardDoubleArrowLeft
|
||||
import androidx.compose.material.icons.outlined.KeyboardDoubleArrowRight
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@Composable
|
||||
fun DownloadCustomAmountDialog(
|
||||
maxAmount: Int,
|
||||
onDismissRequest: () -> Unit,
|
||||
onConfirm: (Int) -> Unit,
|
||||
) {
|
||||
var amount by remember { mutableStateOf(0) }
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
enabled = amount != 0,
|
||||
onClick = {
|
||||
onDismissRequest()
|
||||
onConfirm(amount.coerceIn(0, maxAmount))
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_download))
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(R.string.custom_download))
|
||||
},
|
||||
text = {
|
||||
val setAmount: (Int) -> Unit = { amount = it.coerceIn(0, maxAmount) }
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { setAmount(amount - 10) },
|
||||
enabled = amount > 0,
|
||||
) {
|
||||
Icon(imageVector = Icons.Outlined.KeyboardDoubleArrowLeft, contentDescription = "-10")
|
||||
}
|
||||
IconButton(
|
||||
onClick = { setAmount(amount - 1) },
|
||||
enabled = amount > 0,
|
||||
) {
|
||||
Icon(imageVector = Icons.Outlined.ChevronLeft, contentDescription = "-1")
|
||||
}
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
value = amount.toString(),
|
||||
onValueChange = { setAmount(it.toIntOrNull() ?: 0) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
|
||||
)
|
||||
IconButton(
|
||||
onClick = { setAmount(amount + 1) },
|
||||
enabled = amount < maxAmount,
|
||||
) {
|
||||
Icon(imageVector = Icons.Outlined.ChevronRight, contentDescription = "+1")
|
||||
}
|
||||
IconButton(
|
||||
onClick = { setAmount(amount + 10) },
|
||||
enabled = amount < maxAmount,
|
||||
) {
|
||||
Icon(imageVector = Icons.Outlined.KeyboardDoubleArrowRight, contentDescription = "+10")
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -4,7 +4,7 @@ enum class DownloadAction {
|
|||
NEXT_1_ITEM,
|
||||
NEXT_5_ITEMS,
|
||||
NEXT_10_ITEMS,
|
||||
CUSTOM,
|
||||
NEXT_25_ITEMS,
|
||||
UNVIEWED_ITEMS,
|
||||
ALL_ITEMS,
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import androidx.compose.ui.window.Dialog
|
|||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.core.view.updatePadding
|
||||
import coil.imageLoader
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.Size
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
|
@ -162,6 +163,7 @@ fun AnimeCoverDialog(
|
|||
val request = ImageRequest.Builder(view.context)
|
||||
.data(coverDataProvider())
|
||||
.size(Size.ORIGINAL)
|
||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||
.target { drawable ->
|
||||
// Copy bitmap in case it came from memory cache
|
||||
// Because SSIV needs to thoroughly read the image
|
||||
|
|
|
@ -40,6 +40,7 @@ import androidx.compose.ui.window.Dialog
|
|||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.core.view.updatePadding
|
||||
import coil.imageLoader
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.Size
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
|
@ -162,6 +163,7 @@ fun MangaCoverDialog(
|
|||
val request = ImageRequest.Builder(view.context)
|
||||
.data(coverDataProvider())
|
||||
.size(Size.ORIGINAL)
|
||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||
.target { drawable ->
|
||||
// Copy bitmap in case it came from memory cache
|
||||
// Because SSIV needs to thoroughly read the image
|
||||
|
|
|
@ -550,11 +550,11 @@ class AnimeLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
val interval = prefInterval ?: preferences.libraryUpdateInterval().get()
|
||||
if (interval > 0) {
|
||||
val restrictions = preferences.libraryUpdateDeviceRestriction().get()
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED })
|
||||
.setRequiresCharging(DEVICE_CHARGING in restrictions)
|
||||
.setRequiresBatteryNotLow(DEVICE_BATTERY_NOT_LOW in restrictions)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED },
|
||||
requiresCharging = DEVICE_CHARGING in restrictions,
|
||||
requiresBatteryNotLow = DEVICE_BATTERY_NOT_LOW in restrictions,
|
||||
)
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<AnimeLibraryUpdateJob>(
|
||||
interval.toLong(),
|
||||
|
|
|
@ -549,17 +549,11 @@ class MangaLibraryUpdateJob(private val context: Context, workerParams: WorkerPa
|
|||
val interval = prefInterval ?: preferences.libraryUpdateInterval().get()
|
||||
if (interval > 0) {
|
||||
val restrictions = preferences.libraryUpdateDeviceRestriction().get()
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(
|
||||
if (DEVICE_NETWORK_NOT_METERED in restrictions) {
|
||||
NetworkType.UNMETERED
|
||||
} else {
|
||||
NetworkType.CONNECTED
|
||||
},
|
||||
)
|
||||
.setRequiresCharging(DEVICE_CHARGING in restrictions)
|
||||
.setRequiresBatteryNotLow(DEVICE_BATTERY_NOT_LOW in restrictions)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED },
|
||||
requiresCharging = DEVICE_CHARGING in restrictions,
|
||||
requiresBatteryNotLow = DEVICE_BATTERY_NOT_LOW in restrictions,
|
||||
)
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<MangaLibraryUpdateJob>(
|
||||
interval.toLong(),
|
||||
|
|
|
@ -37,9 +37,9 @@ class AppUpdateJob(private val context: Context, workerParams: WorkerParameters)
|
|||
return
|
||||
}
|
||||
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = NetworkType.CONNECTED,
|
||||
)
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<AppUpdateJob>(
|
||||
7,
|
||||
|
|
|
@ -71,9 +71,9 @@ class AnimeExtensionUpdateJob(private val context: Context, workerParams: Worker
|
|||
val preferences = Injekt.get<BasePreferences>()
|
||||
val autoUpdateJob = forceAutoUpdateJob ?: preferences.automaticExtUpdates().get()
|
||||
if (autoUpdateJob) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = NetworkType.CONNECTED,
|
||||
)
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<AnimeExtensionUpdateJob>(
|
||||
2,
|
||||
|
|
|
@ -71,9 +71,9 @@ class MangaExtensionUpdateJob(private val context: Context, workerParams: Worker
|
|||
val preferences = Injekt.get<BasePreferences>()
|
||||
val autoUpdateJob = forceAutoUpdateJob ?: preferences.automaticExtUpdates().get()
|
||||
if (autoUpdateJob) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
val constraints = Constraints(
|
||||
requiredNetworkType = NetworkType.CONNECTED,
|
||||
)
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<MangaExtensionUpdateJob>(
|
||||
2,
|
||||
|
|
|
@ -39,7 +39,6 @@ import eu.kanade.presentation.components.DuplicateAnimeDialog
|
|||
import eu.kanade.presentation.components.LoadingScreen
|
||||
import eu.kanade.presentation.components.NavigatorAdaptiveSheet
|
||||
import eu.kanade.presentation.entries.DeleteItemsDialog
|
||||
import eu.kanade.presentation.entries.DownloadCustomAmountDialog
|
||||
import eu.kanade.presentation.entries.EditCoverAction
|
||||
import eu.kanade.presentation.entries.anime.AnimeScreen
|
||||
import eu.kanade.presentation.entries.anime.EpisodeSettingsDialog
|
||||
|
@ -189,18 +188,6 @@ class AnimeScreen(
|
|||
isManga = false,
|
||||
)
|
||||
}
|
||||
is AnimeInfoScreenModel.Dialog.DownloadCustomAmount -> {
|
||||
DownloadCustomAmountDialog(
|
||||
maxAmount = dialog.max,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { amount ->
|
||||
val episodesToDownload = screenModel.getUnseenEpisodesSorted().take(amount)
|
||||
if (episodesToDownload.isNotEmpty()) {
|
||||
screenModel.startDownload(episodes = episodesToDownload, startNow = false)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
is AnimeInfoScreenModel.Dialog.DuplicateAnime -> DuplicateAnimeDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { screenModel.toggleFavorite(onRemoved = {}, checkDuplicate = false) },
|
||||
|
|
|
@ -82,7 +82,7 @@ class AnimeInfoScreenModel(
|
|||
private val isFromSource: Boolean,
|
||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
private val uiPreferences: UiPreferences = Injekt.get(),
|
||||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
private val trackPreferences: TrackPreferences = Injekt.get(),
|
||||
internal val playerPreferences: PlayerPreferences = Injekt.get(),
|
||||
private val trackManager: TrackManager = Injekt.get(),
|
||||
|
@ -364,7 +364,7 @@ class AnimeInfoScreenModel(
|
|||
/**
|
||||
* Returns true if the anime has any downloads.
|
||||
*/
|
||||
fun hasDownloads(): Boolean {
|
||||
private fun hasDownloads(): Boolean {
|
||||
val anime = successState?.anime ?: return false
|
||||
return downloadManager.getDownloadCount(anime) > 0
|
||||
}
|
||||
|
@ -542,7 +542,7 @@ class AnimeInfoScreenModel(
|
|||
return successState.episodes.getNextUnseen(successState.anime)
|
||||
}
|
||||
|
||||
fun getUnseenEpisodes(): List<Episode> {
|
||||
private fun getUnseenEpisodes(): List<Episode> {
|
||||
return successState?.processedEpisodes
|
||||
?.filter { (episode, dlStatus) -> !episode.seen && dlStatus == AnimeDownload.State.NOT_DOWNLOADED }
|
||||
?.map { it.episode }
|
||||
|
@ -550,13 +550,13 @@ class AnimeInfoScreenModel(
|
|||
?: emptyList()
|
||||
}
|
||||
|
||||
fun getUnseenEpisodesSorted(): List<Episode> {
|
||||
private fun getUnseenEpisodesSorted(): List<Episode> {
|
||||
val anime = successState?.anime ?: return emptyList()
|
||||
val episodes = getUnseenEpisodes().sortedWith(getEpisodeSort(anime))
|
||||
return if (anime.sortDescending()) episodes.reversed() else episodes
|
||||
}
|
||||
|
||||
fun startDownload(
|
||||
private fun startDownload(
|
||||
episodes: List<Episode>,
|
||||
startNow: Boolean,
|
||||
) {
|
||||
|
@ -616,10 +616,8 @@ class AnimeInfoScreenModel(
|
|||
DownloadAction.NEXT_1_ITEM -> getUnseenEpisodesSorted().take(1)
|
||||
DownloadAction.NEXT_5_ITEMS -> getUnseenEpisodesSorted().take(5)
|
||||
DownloadAction.NEXT_10_ITEMS -> getUnseenEpisodesSorted().take(10)
|
||||
DownloadAction.CUSTOM -> {
|
||||
showDownloadCustomDialog()
|
||||
return
|
||||
}
|
||||
DownloadAction.NEXT_25_ITEMS -> getUnseenEpisodesSorted().take(25)
|
||||
|
||||
DownloadAction.UNVIEWED_ITEMS -> getUnseenEpisodes()
|
||||
DownloadAction.ALL_ITEMS -> successState?.episodes?.map { it.episode }
|
||||
}
|
||||
|
@ -628,7 +626,7 @@ class AnimeInfoScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun cancelDownload(episodeId: Long) {
|
||||
private fun cancelDownload(episodeId: Long) {
|
||||
val activeDownload = downloadManager.getQueuedDownloadOrNull(episodeId) ?: return
|
||||
downloadManager.cancelQueuedDownloads(listOf(activeDownload))
|
||||
updateDownloadState(activeDownload.apply { status = AnimeDownload.State.NOT_DOWNLOADED })
|
||||
|
@ -922,7 +920,6 @@ class AnimeInfoScreenModel(
|
|||
data class ChangeCategory(val anime: Anime, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteEpisodes(val episodes: List<Episode>) : Dialog()
|
||||
data class DuplicateAnime(val anime: Anime, val duplicate: Anime) : Dialog()
|
||||
data class DownloadCustomAmount(val max: Int) : Dialog()
|
||||
object ChangeAnimeSkipIntro : Dialog()
|
||||
object SettingsSheet : Dialog()
|
||||
object TrackSheet : Dialog()
|
||||
|
@ -937,15 +934,6 @@ class AnimeInfoScreenModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
private fun showDownloadCustomDialog() {
|
||||
val max = processedEpisodes?.count() ?: return
|
||||
mutableState.update { state ->
|
||||
when (state) {
|
||||
AnimeScreenState.Loading -> state
|
||||
is AnimeScreenState.Success -> state.copy(dialog = Dialog.DownloadCustomAmount(max))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showDeleteEpisodeDialog(chapters: List<Episode>) {
|
||||
mutableState.update { state ->
|
||||
|
|
|
@ -29,7 +29,6 @@ import eu.kanade.presentation.components.DuplicateMangaDialog
|
|||
import eu.kanade.presentation.components.LoadingScreen
|
||||
import eu.kanade.presentation.components.NavigatorAdaptiveSheet
|
||||
import eu.kanade.presentation.entries.DeleteItemsDialog
|
||||
import eu.kanade.presentation.entries.DownloadCustomAmountDialog
|
||||
import eu.kanade.presentation.entries.EditCoverAction
|
||||
import eu.kanade.presentation.entries.manga.ChapterSettingsDialog
|
||||
import eu.kanade.presentation.entries.manga.MangaScreen
|
||||
|
@ -164,18 +163,6 @@ class MangaScreen(
|
|||
isManga = true,
|
||||
)
|
||||
}
|
||||
is MangaInfoScreenModel.Dialog.DownloadCustomAmount -> {
|
||||
DownloadCustomAmountDialog(
|
||||
maxAmount = dialog.max,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { amount ->
|
||||
val chaptersToDownload = screenModel.getUnreadChaptersSorted().take(amount)
|
||||
if (chaptersToDownload.isNotEmpty()) {
|
||||
screenModel.startDownload(chapters = chaptersToDownload, startNow = false)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
is MangaInfoScreenModel.Dialog.DuplicateManga -> DuplicateMangaDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { screenModel.toggleFavorite(onRemoved = {}, checkDuplicate = false) },
|
||||
|
|
|
@ -84,8 +84,8 @@ class MangaInfoScreenModel(
|
|||
private val isFromSource: Boolean,
|
||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
private val readerPreferences: ReaderPreferences = Injekt.get(),
|
||||
private val uiPreferences: UiPreferences = Injekt.get(),
|
||||
readerPreferences: ReaderPreferences = Injekt.get(),
|
||||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
private val trackPreferences: TrackPreferences = Injekt.get(),
|
||||
private val trackManager: TrackManager = Injekt.get(),
|
||||
private val downloadManager: MangaDownloadManager = Injekt.get(),
|
||||
|
@ -125,8 +125,8 @@ class MangaInfoScreenModel(
|
|||
get() = successState?.processedChapters
|
||||
|
||||
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
|
||||
val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope)
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
||||
val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope)
|
||||
|
||||
private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list
|
||||
private val selectedChapterIds: HashSet<Long> = HashSet()
|
||||
|
@ -372,7 +372,7 @@ class MangaInfoScreenModel(
|
|||
/**
|
||||
* Returns true if the manga has any downloads.
|
||||
*/
|
||||
fun hasDownloads(): Boolean {
|
||||
private fun hasDownloads(): Boolean {
|
||||
val manga = successState?.manga ?: return false
|
||||
return downloadManager.getDownloadCount(manga) > 0
|
||||
}
|
||||
|
@ -545,7 +545,7 @@ class MangaInfoScreenModel(
|
|||
/**
|
||||
* Returns the list of filtered or all chapter items if [skipFiltered] is false.
|
||||
*/
|
||||
fun getChapterItems(): List<ChapterItem> {
|
||||
private fun getChapterItems(): List<ChapterItem> {
|
||||
return if (skipFiltered) filteredChapters.orEmpty().toList() else allChapters.orEmpty()
|
||||
}
|
||||
|
||||
|
@ -557,19 +557,19 @@ class MangaInfoScreenModel(
|
|||
return successState.chapters.getNextUnread(successState.manga)
|
||||
}
|
||||
|
||||
fun getUnreadChapters(): List<Chapter> {
|
||||
private fun getUnreadChapters(): List<Chapter> {
|
||||
return getChapterItems()
|
||||
.filter { (chapter, dlStatus) -> !chapter.read && dlStatus == MangaDownload.State.NOT_DOWNLOADED }
|
||||
.map { it.chapter }
|
||||
}
|
||||
|
||||
fun getUnreadChaptersSorted(): List<Chapter> {
|
||||
private fun getUnreadChaptersSorted(): List<Chapter> {
|
||||
val manga = successState?.manga ?: return emptyList()
|
||||
val chaptersSorted = getUnreadChapters().sortedWith(getChapterSort(manga))
|
||||
return if (manga.sortDescending()) chaptersSorted.reversed() else chaptersSorted
|
||||
}
|
||||
|
||||
fun startDownload(
|
||||
private fun startDownload(
|
||||
chapters: List<Chapter>,
|
||||
startNow: Boolean,
|
||||
) {
|
||||
|
@ -628,19 +628,17 @@ class MangaInfoScreenModel(
|
|||
DownloadAction.NEXT_1_ITEM -> getUnreadChaptersSorted().take(1)
|
||||
DownloadAction.NEXT_5_ITEMS -> getUnreadChaptersSorted().take(5)
|
||||
DownloadAction.NEXT_10_ITEMS -> getUnreadChaptersSorted().take(10)
|
||||
DownloadAction.CUSTOM -> {
|
||||
showDownloadCustomDialog()
|
||||
return
|
||||
}
|
||||
DownloadAction.NEXT_25_ITEMS -> getUnreadChaptersSorted().take(25)
|
||||
|
||||
DownloadAction.UNVIEWED_ITEMS -> getUnreadChapters()
|
||||
DownloadAction.ALL_ITEMS -> getChapterItems().map { it.chapter }
|
||||
}
|
||||
if (!chaptersToDownload.isNullOrEmpty()) {
|
||||
if (!chaptersToDownload.isNotEmpty()) {
|
||||
startDownload(chaptersToDownload, false)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelDownload(chapterId: Long) {
|
||||
private fun cancelDownload(chapterId: Long) {
|
||||
val activeDownload = downloadManager.getQueuedDownloadOrNull(chapterId) ?: return
|
||||
downloadManager.cancelQueuedDownloads(listOf(activeDownload))
|
||||
updateDownloadState(activeDownload.apply { status = MangaDownload.State.NOT_DOWNLOADED })
|
||||
|
@ -930,7 +928,6 @@ class MangaInfoScreenModel(
|
|||
data class ChangeCategory(val manga: Manga, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteChapters(val chapters: List<Chapter>) : Dialog()
|
||||
data class DuplicateManga(val manga: Manga, val duplicate: Manga) : Dialog()
|
||||
data class DownloadCustomAmount(val max: Int) : Dialog()
|
||||
object SettingsSheet : Dialog()
|
||||
object TrackSheet : Dialog()
|
||||
object FullCover : Dialog()
|
||||
|
@ -945,16 +942,6 @@ class MangaInfoScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun showDownloadCustomDialog() {
|
||||
val max = getChapterItems().count()
|
||||
mutableState.update { state ->
|
||||
when (state) {
|
||||
MangaScreenState.Loading -> state
|
||||
is MangaScreenState.Success -> state.copy(dialog = Dialog.DownloadCustomAmount(max))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showDeleteChapterDialog(chapters: List<Chapter>) {
|
||||
mutableState.update { state ->
|
||||
when (state) {
|
||||
|
|
|
@ -457,18 +457,8 @@ class AnimeLibraryScreenModel(
|
|||
DownloadAction.NEXT_1_ITEM -> downloadUnseenEpisodes(animes, 1)
|
||||
DownloadAction.NEXT_5_ITEMS -> downloadUnseenEpisodes(animes, 5)
|
||||
DownloadAction.NEXT_10_ITEMS -> downloadUnseenEpisodes(animes, 10)
|
||||
DownloadAction.NEXT_25_ITEMS -> downloadUnseenEpisodes(animes, 25)
|
||||
DownloadAction.UNVIEWED_ITEMS -> downloadUnseenEpisodes(animes, null)
|
||||
DownloadAction.CUSTOM -> {
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
dialog = Dialog.DownloadCustomAmount(
|
||||
animes,
|
||||
selection.maxOf { it.unseenCount }.toInt(),
|
||||
),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
clearSelection()
|
||||
|
@ -480,7 +470,7 @@ class AnimeLibraryScreenModel(
|
|||
* @param animes the list of anime.
|
||||
* @param amount the amount to queue or null to queue all
|
||||
*/
|
||||
fun downloadUnseenEpisodes(animes: List<Anime>, amount: Int?) {
|
||||
private fun downloadUnseenEpisodes(animes: List<Anime>, amount: Int?) {
|
||||
coroutineScope.launchNonCancellable {
|
||||
animes.forEach { anime ->
|
||||
val episodes = getNextEpisodes.await(anime.id)
|
||||
|
@ -702,7 +692,6 @@ class AnimeLibraryScreenModel(
|
|||
sealed class Dialog {
|
||||
data class ChangeCategory(val anime: List<Anime>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteAnime(val anime: List<Anime>) : Dialog()
|
||||
data class DownloadCustomAmount(val anime: List<Anime>, val max: Int) : Dialog()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
@ -40,7 +40,6 @@ import eu.kanade.presentation.components.EmptyScreenAction
|
|||
import eu.kanade.presentation.components.LibraryBottomActionMenu
|
||||
import eu.kanade.presentation.components.LoadingScreen
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.entries.DownloadCustomAmountDialog
|
||||
import eu.kanade.presentation.library.LibraryToolbar
|
||||
import eu.kanade.presentation.library.anime.AnimeLibraryContent
|
||||
import eu.kanade.presentation.util.Tab
|
||||
|
@ -261,16 +260,6 @@ object AnimeLibraryTab : Tab {
|
|||
isManga = false,
|
||||
)
|
||||
}
|
||||
is AnimeLibraryScreenModel.Dialog.DownloadCustomAmount -> {
|
||||
DownloadCustomAmountDialog(
|
||||
maxAmount = dialog.max,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { amount ->
|
||||
screenModel.downloadUnseenEpisodes(dialog.anime, amount)
|
||||
screenModel.clearSelection()
|
||||
},
|
||||
)
|
||||
}
|
||||
null -> {}
|
||||
}
|
||||
|
||||
|
|
|
@ -457,18 +457,8 @@ class MangaLibraryScreenModel(
|
|||
DownloadAction.NEXT_1_ITEM -> downloadUnreadChapters(mangas, 1)
|
||||
DownloadAction.NEXT_5_ITEMS -> downloadUnreadChapters(mangas, 5)
|
||||
DownloadAction.NEXT_10_ITEMS -> downloadUnreadChapters(mangas, 10)
|
||||
DownloadAction.NEXT_25_ITEMS -> downloadUnreadChapters(mangas, 25)
|
||||
DownloadAction.UNVIEWED_ITEMS -> downloadUnreadChapters(mangas, null)
|
||||
DownloadAction.CUSTOM -> {
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
dialog = Dialog.DownloadCustomAmount(
|
||||
mangas,
|
||||
selection.maxOf { it.unreadCount }.toInt(),
|
||||
),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
clearSelection()
|
||||
|
@ -480,7 +470,7 @@ class MangaLibraryScreenModel(
|
|||
* @param mangas the list of manga.
|
||||
* @param amount the amount to queue or null to queue all
|
||||
*/
|
||||
fun downloadUnreadChapters(mangas: List<Manga>, amount: Int?) {
|
||||
private fun downloadUnreadChapters(mangas: List<Manga>, amount: Int?) {
|
||||
coroutineScope.launchNonCancellable {
|
||||
mangas.forEach { manga ->
|
||||
val chapters = getNextChapters.await(manga.id)
|
||||
|
@ -702,7 +692,6 @@ class MangaLibraryScreenModel(
|
|||
sealed class Dialog {
|
||||
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||
data class DeleteManga(val manga: List<Manga>) : Dialog()
|
||||
data class DownloadCustomAmount(val manga: List<Manga>, val max: Int) : Dialog()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
@ -39,7 +39,6 @@ import eu.kanade.presentation.components.EmptyScreenAction
|
|||
import eu.kanade.presentation.components.LibraryBottomActionMenu
|
||||
import eu.kanade.presentation.components.LoadingScreen
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.entries.DownloadCustomAmountDialog
|
||||
import eu.kanade.presentation.library.LibraryToolbar
|
||||
import eu.kanade.presentation.library.manga.MangaLibraryContent
|
||||
import eu.kanade.presentation.util.Tab
|
||||
|
@ -248,16 +247,6 @@ object MangaLibraryTab : Tab {
|
|||
isManga = true,
|
||||
)
|
||||
}
|
||||
is MangaLibraryScreenModel.Dialog.DownloadCustomAmount -> {
|
||||
DownloadCustomAmountDialog(
|
||||
maxAmount = dialog.max,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { amount ->
|
||||
screenModel.downloadUnreadChapters(dialog.manga, amount)
|
||||
screenModel.clearSelection()
|
||||
},
|
||||
)
|
||||
}
|
||||
null -> {}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[versions]
|
||||
agp_version = "7.4.1"
|
||||
lifecycle_version = "2.5.1"
|
||||
lifecycle_version = "2.6.0-beta01"
|
||||
|
||||
[libraries]
|
||||
gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" }
|
||||
|
||||
annotation = "androidx.annotation:annotation:1.5.0"
|
||||
appcompat = "androidx.appcompat:appcompat:1.6.0"
|
||||
appcompat = "androidx.appcompat:appcompat:1.6.1"
|
||||
biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05"
|
||||
constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||
|
@ -21,11 +21,11 @@ lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref
|
|||
lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycle_version" }
|
||||
lifecycle-runtimektx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle_version" }
|
||||
|
||||
work-runtime = "androidx.work:work-runtime-ktx:2.8.0-rc01"
|
||||
work-runtime = "androidx.work:work-runtime-ktx:2.8.0"
|
||||
guava = "com.google.guava:guava:31.1-android"
|
||||
|
||||
paging-runtime = "androidx.paging:paging-runtime:3.1.1"
|
||||
paging-compose = "androidx.paging:paging-compose:1.0.0-alpha17"
|
||||
paging-compose = "androidx.paging:paging-compose:1.0.0-alpha18"
|
||||
|
||||
benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.1.1"
|
||||
test-ext = "androidx.test.ext:junit-ktx:1.1.5"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[versions]
|
||||
compiler = "1.4.0"
|
||||
compiler = "1.4.2"
|
||||
compose-bom = "2023.01.00"
|
||||
accompanist = "0.28.0"
|
||||
|
||||
|
@ -16,9 +16,9 @@ material3-core = { module = "androidx.compose.material3:material3" }
|
|||
material-icons = { module = "androidx.compose.material:material-icons-extended" }
|
||||
|
||||
# Here until M3's swipeable became public https://issuetracker.google.com/issues/234640556
|
||||
# Using alpha version for PullRefresh fix
|
||||
# Using newer version for PullRefresh fix
|
||||
# TODO: use default version after next Compose BOM is released
|
||||
material-core = { module = "androidx.compose.material:material", version = "1.4.0-alpha05" }
|
||||
material-core = { module = "androidx.compose.material:material", version = "1.4.0-beta01" }
|
||||
|
||||
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
|
||||
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[versions]
|
||||
kotlin_version = "1.8.0"
|
||||
kotlin_version = "1.8.10"
|
||||
# TODO: 1.4.1 introduces an issue with cached serializers; see https://github.com/Kotlin/kotlinx.serialization/issues/2065
|
||||
serialization_version = "1.4.0"
|
||||
xml_serialization_version = "0.84.3"
|
||||
|
||||
|
@ -11,9 +12,8 @@ coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", vers
|
|||
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" }
|
||||
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" }
|
||||
|
||||
# TODO: 1.4.1 introduces an issue with cached serializers; see https://github.com/Kotlin/kotlinx.serialization/issues/2065
|
||||
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.4.0" }
|
||||
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version = "1.4.0" }
|
||||
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_version" }
|
||||
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization_version" }
|
||||
serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" }
|
||||
serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core-android", version.ref = "xml_serialization_version" }
|
||||
serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization-android", version.ref = "xml_serialization_version" }
|
||||
|
|
|
@ -61,7 +61,7 @@ flexible-adapter-ui = "com.github.arkon.FlexibleAdapter:flexible-adapter-ui:c801
|
|||
photoview = "com.github.chrisbanes:PhotoView:2.3.0"
|
||||
directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0"
|
||||
insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
|
||||
cascade = "me.saket.cascade:cascade-compose:2.0.0-beta1"
|
||||
cascade = "me.saket.cascade:cascade-compose:2.0.0-rc01"
|
||||
wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11"
|
||||
materialmotion-core = "io.github.fornewid:material-motion-compose-core:0.10.4"
|
||||
|
||||
|
|
|
@ -171,9 +171,10 @@
|
|||
<string name="download_paused">Paused</string>
|
||||
<string name="show_episode_number">Episode number</string>
|
||||
<string name="sort_by_episode_number">By episode number</string>
|
||||
<string name="download_1_episode">Next episode</string>
|
||||
<string name="download_5_episodes">Next 5 episodes</string>
|
||||
<string name="download_10_episodes">Next 10 episodes</string>
|
||||
<plurals name="download_amount_anime">
|
||||
<item quantity="one">Next episode</item>
|
||||
<item quantity="other">Next %d episode</item>
|
||||
</plurals>
|
||||
<string name="download_unseen">Unseen</string>
|
||||
<string name="confirm_delete_episodes">Are you sure you want to delete the selected episodes?</string>
|
||||
<string name="also_set_chapter_settings_for_library">Also apply to all manga in my library</string>
|
||||
|
|
|
@ -631,11 +631,10 @@
|
|||
<string name="sort_by_number">By chapter number</string>
|
||||
<string name="sort_by_upload_date">By upload date</string>
|
||||
<string name="manga_download">Download</string>
|
||||
<string name="custom_download">Download custom amount</string>
|
||||
<string name="download_1">Next chapter</string>
|
||||
<string name="download_5">Next 5 chapters</string>
|
||||
<string name="download_10">Next 10 chapters</string>
|
||||
<string name="download_custom">Custom</string>
|
||||
<plurals name="download_amount_manga">
|
||||
<item quantity="one">Next chapter</item>
|
||||
<item quantity="other">Next %d chapters</item>
|
||||
</plurals>
|
||||
<string name="download_all">All</string>
|
||||
<string name="download_unread">Unread</string>
|
||||
<string name="custom_cover">Custom cover</string>
|
||||
|
|
Loading…
Reference in a new issue