mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-27 16:26:29 +03:00
parent
d7aee03688
commit
375a252a69
71 changed files with 961 additions and 327 deletions
|
@ -20,7 +20,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId = "xyz.jmir.tachiyomi.mi"
|
||||
|
||||
versionCode = 108
|
||||
versionCode = 109
|
||||
versionName = "0.14.7"
|
||||
|
||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||
|
|
|
@ -4,6 +4,8 @@ import eu.kanade.domain.download.anime.interactor.DeleteEpisodeDownload
|
|||
import eu.kanade.domain.download.manga.interactor.DeleteChapterDownload
|
||||
import eu.kanade.domain.entries.anime.interactor.SetAnimeViewerFlags
|
||||
import eu.kanade.domain.entries.anime.interactor.UpdateAnime
|
||||
import eu.kanade.domain.entries.manga.interactor.GetExcludedScanlators
|
||||
import eu.kanade.domain.entries.manga.interactor.SetExcludedScanlators
|
||||
import eu.kanade.domain.entries.manga.interactor.SetMangaViewerFlags
|
||||
import eu.kanade.domain.entries.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.extension.anime.interactor.GetAnimeExtensionLanguages
|
||||
|
@ -12,6 +14,7 @@ import eu.kanade.domain.extension.anime.interactor.GetAnimeExtensionsByType
|
|||
import eu.kanade.domain.extension.manga.interactor.GetExtensionSources
|
||||
import eu.kanade.domain.extension.manga.interactor.GetMangaExtensionLanguages
|
||||
import eu.kanade.domain.extension.manga.interactor.GetMangaExtensionsByType
|
||||
import eu.kanade.domain.items.chapter.interactor.GetAvailableScanlators
|
||||
import eu.kanade.domain.items.chapter.interactor.SetReadStatus
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.items.episode.interactor.SetSeenStatus
|
||||
|
@ -224,6 +227,8 @@ class DomainModule : InjektModule {
|
|||
addFactory { NetworkToLocalManga(get()) }
|
||||
addFactory { UpdateManga(get(), get()) }
|
||||
addFactory { SetMangaCategories(get()) }
|
||||
addFactory { GetExcludedScanlators(get()) }
|
||||
addFactory { SetExcludedScanlators(get()) }
|
||||
|
||||
addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
|
||||
addFactory { GetApplicationRelease(get(), get()) }
|
||||
|
@ -264,7 +269,8 @@ class DomainModule : InjektModule {
|
|||
addFactory { UpdateChapter(get()) }
|
||||
addFactory { SetReadStatus(get(), get(), get(), get()) }
|
||||
addFactory { ShouldUpdateDbChapter() }
|
||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) }
|
||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get(), get()) }
|
||||
addFactory { GetAvailableScanlators(get()) }
|
||||
|
||||
addSingletonFactory<AnimeHistoryRepository> { AnimeHistoryRepositoryImpl(get()) }
|
||||
addFactory { GetAnimeHistory(get()) }
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package eu.kanade.domain.entries.manga.interactor
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import tachiyomi.data.handlers.manga.MangaDatabaseHandler
|
||||
|
||||
class GetExcludedScanlators(
|
||||
private val handler: MangaDatabaseHandler,
|
||||
) {
|
||||
|
||||
suspend fun await(mangaId: Long): Set<String> {
|
||||
return handler.awaitList {
|
||||
excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId)
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
|
||||
fun subscribe(mangaId: Long): Flow<Set<String>> {
|
||||
return handler.subscribeToList {
|
||||
excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId)
|
||||
}
|
||||
.map { it.toSet() }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package eu.kanade.domain.entries.manga.interactor
|
||||
|
||||
import tachiyomi.data.handlers.manga.MangaDatabaseHandler
|
||||
|
||||
class SetExcludedScanlators(
|
||||
private val handler: MangaDatabaseHandler,
|
||||
) {
|
||||
|
||||
suspend fun await(mangaId: Long, excludedScanlators: Set<String>) {
|
||||
handler.await(inTransaction = true) {
|
||||
val currentExcluded = handler.awaitList {
|
||||
excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId)
|
||||
}.toSet()
|
||||
val toAdd = excludedScanlators.minus(currentExcluded)
|
||||
for (scanlator in toAdd) {
|
||||
excluded_scanlatorsQueries.insert(mangaId, scanlator)
|
||||
}
|
||||
val toRemove = currentExcluded.minus(excludedScanlators)
|
||||
excluded_scanlatorsQueries.remove(mangaId, toRemove)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.domain.entries.manga.interactor
|
||||
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import tachiyomi.domain.entries.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.entries.manga.repository.MangaRepository
|
||||
|
||||
|
@ -14,7 +14,7 @@ class SetMangaViewerFlags(
|
|||
mangaRepository.updateManga(
|
||||
MangaUpdate(
|
||||
id = id,
|
||||
viewerFlags = manga.viewerFlags.setFlag(flag, ReadingModeType.MASK.toLong()),
|
||||
viewerFlags = manga.viewerFlags.setFlag(flag, ReadingMode.MASK.toLong()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class SetMangaViewerFlags(
|
|||
mangaRepository.updateManga(
|
||||
MangaUpdate(
|
||||
id = id,
|
||||
viewerFlags = manga.viewerFlags.setFlag(flag, OrientationType.MASK.toLong()),
|
||||
viewerFlags = manga.viewerFlags.setFlag(flag, ReaderOrientation.MASK.toLong()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package eu.kanade.domain.entries.manga.model
|
|||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.data.cache.MangaCoverCache
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import tachiyomi.core.metadata.comicinfo.ComicInfo
|
||||
import tachiyomi.core.metadata.comicinfo.ComicInfoPublishingStatus
|
||||
import tachiyomi.core.preference.TriState
|
||||
|
@ -14,11 +14,11 @@ import uy.kohesive.injekt.Injekt
|
|||
import uy.kohesive.injekt.api.get
|
||||
|
||||
// TODO: move these into the domain model
|
||||
val Manga.readingModeType: Long
|
||||
get() = viewerFlags and ReadingModeType.MASK.toLong()
|
||||
val Manga.readingMode: Long
|
||||
get() = viewerFlags and ReadingMode.MASK.toLong()
|
||||
|
||||
val Manga.orientationType: Long
|
||||
get() = viewerFlags and OrientationType.MASK.toLong()
|
||||
val Manga.readerOrientation: Long
|
||||
get() = viewerFlags and ReaderOrientation.MASK.toLong()
|
||||
|
||||
val Manga.downloadedFilter: TriState
|
||||
get() {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package eu.kanade.domain.items.chapter.interactor
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import tachiyomi.domain.items.chapter.repository.ChapterRepository
|
||||
|
||||
class GetAvailableScanlators(
|
||||
private val repository: ChapterRepository,
|
||||
) {
|
||||
|
||||
private fun List<String>.cleanupAvailableScanlators(): Set<String> {
|
||||
return mapNotNull { it.ifBlank { null } }.toSet()
|
||||
}
|
||||
|
||||
suspend fun await(mangaId: Long): Set<String> {
|
||||
return repository.getScanlatorsByMangaId(mangaId)
|
||||
.cleanupAvailableScanlators()
|
||||
}
|
||||
|
||||
fun subscribe(mangaId: Long): Flow<Set<String>> {
|
||||
return repository.getScanlatorsByMangaIdAsFlow(mangaId)
|
||||
.map { it.cleanupAvailableScanlators() }
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.domain.items.chapter.interactor
|
||||
|
||||
import eu.kanade.domain.entries.manga.interactor.GetExcludedScanlators
|
||||
import eu.kanade.domain.entries.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.entries.manga.model.toSManga
|
||||
import eu.kanade.domain.items.chapter.model.copyFromSChapter
|
||||
|
@ -33,6 +34,7 @@ class SyncChaptersWithSource(
|
|||
private val updateManga: UpdateManga,
|
||||
private val updateChapter: UpdateChapter,
|
||||
private val getChaptersByMangaId: GetChaptersByMangaId,
|
||||
private val getExcludedScanlators: GetExcludedScanlators,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -218,6 +220,10 @@ class SyncChaptersWithSource(
|
|||
|
||||
val reAddedUrls = reAdded.map { it.url }.toHashSet()
|
||||
|
||||
return updatedToAdd.filterNot { it.url in reAddedUrls }
|
||||
val excludedScanlators = getExcludedScanlators.await(manga.id).toHashSet()
|
||||
|
||||
return updatedToAdd.filterNot {
|
||||
it.url in reAddedUrls || it.scanlator in excludedScanlators
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ fun Chapter.copyFromSChapter(sChapter: SChapter): Chapter {
|
|||
url = sChapter.url,
|
||||
dateUpload = sChapter.date_upload,
|
||||
chapterNumber = sChapter.chapter_number.toDouble(),
|
||||
scanlator = sChapter.scanlator?.ifBlank { null },
|
||||
scanlator = sChapter.scanlator?.ifBlank { null }?.trim(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ import androidx.compose.material.icons.outlined.HelpOutline
|
|||
import androidx.compose.material.icons.outlined.Refresh
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun NoActionPreview() {
|
||||
TachiyomiTheme {
|
||||
|
@ -23,7 +23,7 @@ private fun NoActionPreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun WithActionPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -14,13 +14,13 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.screens.InfoScreen
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
@Composable
|
||||
fun CrashScreen(
|
||||
|
@ -63,7 +63,7 @@ fun CrashScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun CrashScreenPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -5,11 +5,9 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
|
@ -29,9 +27,7 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -51,7 +47,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.util.fastAll
|
||||
import androidx.compose.ui.util.fastAny
|
||||
|
@ -69,6 +64,7 @@ import eu.kanade.presentation.entries.anime.components.AnimeEpisodeListItem
|
|||
import eu.kanade.presentation.entries.anime.components.AnimeInfoBox
|
||||
import eu.kanade.presentation.entries.anime.components.EpisodeDownloadAction
|
||||
import eu.kanade.presentation.entries.anime.components.ExpandableAnimeDescription
|
||||
import eu.kanade.presentation.entries.anime.components.MissingEpisodeCountListItem
|
||||
import eu.kanade.presentation.entries.anime.components.NextEpisodeAiringListItem
|
||||
import eu.kanade.presentation.util.formatEpisodeNumber
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -95,7 +91,6 @@ import tachiyomi.presentation.core.components.material.Scaffold
|
|||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrollingUp
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -915,25 +910,7 @@ private fun LazyListScope.sharedEpisodeItems(
|
|||
|
||||
when (item) {
|
||||
is EpisodeList.MissingCount -> {
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = MaterialTheme.padding.medium,
|
||||
vertical = MaterialTheme.padding.small,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
|
||||
) {
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = pluralStringResource(
|
||||
id = R.plurals.missing_items,
|
||||
count = item.count,
|
||||
item.count,
|
||||
),
|
||||
modifier = Modifier.secondaryItemAlpha(),
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
}
|
||||
MissingEpisodeCountListItem(count = item.count)
|
||||
}
|
||||
is EpisodeList.Item -> {
|
||||
AnimeEpisodeListItem(
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package eu.kanade.presentation.entries.anime.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
fun MissingEpisodeCountListItem(
|
||||
count: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(
|
||||
horizontal = MaterialTheme.padding.medium,
|
||||
vertical = MaterialTheme.padding.small,
|
||||
)
|
||||
.secondaryItemAlpha(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
|
||||
) {
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = pluralStringResource(id = R.plurals.missing_items, count = count, count),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
MissingEpisodeCountListItem(count = 42)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,20 @@
|
|||
package eu.kanade.presentation.entries.manga
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.PeopleAlt
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -14,6 +22,7 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
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.unit.dp
|
||||
|
@ -28,6 +37,7 @@ import tachiyomi.presentation.core.components.LabeledCheckbox
|
|||
import tachiyomi.presentation.core.components.RadioItem
|
||||
import tachiyomi.presentation.core.components.SortItem
|
||||
import tachiyomi.presentation.core.components.TriStateItem
|
||||
import tachiyomi.presentation.core.theme.active
|
||||
|
||||
@Composable
|
||||
fun ChapterSettingsDialog(
|
||||
|
@ -36,6 +46,8 @@ fun ChapterSettingsDialog(
|
|||
onDownloadFilterChanged: (TriState) -> Unit,
|
||||
onUnreadFilterChanged: (TriState) -> Unit,
|
||||
onBookmarkedFilterChanged: (TriState) -> Unit,
|
||||
scanlatorFilterActive: Boolean,
|
||||
onScanlatorFilterClicked: (() -> Unit),
|
||||
onSortModeChanged: (Long) -> Unit,
|
||||
onDisplayModeChanged: (Long) -> Unit,
|
||||
onSetAsDefault: (applyToExistingManga: Boolean) -> Unit,
|
||||
|
@ -88,6 +100,8 @@ fun ChapterSettingsDialog(
|
|||
onUnreadFilterChanged = onUnreadFilterChanged,
|
||||
bookmarkedFilter = manga?.bookmarkedFilter ?: TriState.DISABLED,
|
||||
onBookmarkedFilterChanged = onBookmarkedFilterChanged,
|
||||
scanlatorFilterActive = scanlatorFilterActive,
|
||||
onScanlatorFilterClicked = onScanlatorFilterClicked,
|
||||
)
|
||||
}
|
||||
1 -> {
|
||||
|
@ -116,6 +130,8 @@ private fun FilterPage(
|
|||
onUnreadFilterChanged: (TriState) -> Unit,
|
||||
bookmarkedFilter: TriState,
|
||||
onBookmarkedFilterChanged: (TriState) -> Unit,
|
||||
scanlatorFilterActive: Boolean,
|
||||
onScanlatorFilterClicked: (() -> Unit),
|
||||
) {
|
||||
TriStateItem(
|
||||
label = stringResource(R.string.label_downloaded),
|
||||
|
@ -132,6 +148,39 @@ private fun FilterPage(
|
|||
state = bookmarkedFilter,
|
||||
onClick = onBookmarkedFilterChanged,
|
||||
)
|
||||
ScanlatorFilterItem(
|
||||
active = scanlatorFilterActive,
|
||||
onClick = onScanlatorFilterClicked,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ScanlatorFilterItem(
|
||||
active: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TabbedDialogPaddings.Horizontal, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(24.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.PeopleAlt,
|
||||
contentDescription = null,
|
||||
tint = if (active) {
|
||||
MaterialTheme.colorScheme.active
|
||||
} else {
|
||||
LocalContentColor.current
|
||||
},
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.scanlator),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -5,11 +5,9 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
|
@ -28,9 +26,7 @@ import androidx.compose.foundation.rememberScrollState
|
|||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -48,14 +44,12 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.util.fastAll
|
||||
import androidx.compose.ui.util.fastAny
|
||||
import androidx.compose.ui.util.fastMap
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.domain.entries.manga.model.chaptersFiltered
|
||||
import eu.kanade.presentation.entries.DownloadAction
|
||||
import eu.kanade.presentation.entries.EntryBottomActionMenu
|
||||
import eu.kanade.presentation.entries.EntryScreenItem
|
||||
|
@ -66,6 +60,7 @@ import eu.kanade.presentation.entries.manga.components.ExpandableMangaDescriptio
|
|||
import eu.kanade.presentation.entries.manga.components.MangaActionRow
|
||||
import eu.kanade.presentation.entries.manga.components.MangaChapterListItem
|
||||
import eu.kanade.presentation.entries.manga.components.MangaInfoBox
|
||||
import eu.kanade.presentation.entries.manga.components.MissingChapterCountListItem
|
||||
import eu.kanade.presentation.util.formatChapterNumber
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.manga.model.MangaDownload
|
||||
|
@ -89,7 +84,6 @@ import tachiyomi.presentation.core.components.material.Scaffold
|
|||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrollingUp
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
|
||||
|
@ -328,7 +322,7 @@ private fun MangaScreenSmallImpl(
|
|||
title = state.manga.title,
|
||||
titleAlphaProvider = { animatedTitleAlpha },
|
||||
backgroundAlphaProvider = { animatedBgAlpha },
|
||||
hasFilters = state.manga.chaptersFiltered(),
|
||||
hasFilters = state.filterActive,
|
||||
onBackClicked = internalOnBackPressed,
|
||||
onClickFilter = onFilterClicked,
|
||||
onClickShare = onShareClicked,
|
||||
|
@ -586,7 +580,7 @@ fun MangaScreenLargeImpl(
|
|||
title = state.manga.title,
|
||||
titleAlphaProvider = { if (isAnySelected) 1f else 0f },
|
||||
backgroundAlphaProvider = { 1f },
|
||||
hasFilters = state.manga.chaptersFiltered(),
|
||||
hasFilters = state.filterActive,
|
||||
onBackClicked = internalOnBackPressed,
|
||||
onClickFilter = onFilterButtonClicked,
|
||||
onClickShare = onShareClicked,
|
||||
|
@ -818,25 +812,7 @@ private fun LazyListScope.sharedChapterItems(
|
|||
|
||||
when (item) {
|
||||
is ChapterList.MissingCount -> {
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = MaterialTheme.padding.medium,
|
||||
vertical = MaterialTheme.padding.small,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
|
||||
) {
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = pluralStringResource(
|
||||
id = R.plurals.missing_items,
|
||||
count = item.count,
|
||||
item.count,
|
||||
),
|
||||
modifier = Modifier.secondaryItemAlpha(),
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
}
|
||||
MissingChapterCountListItem(count = item.count)
|
||||
}
|
||||
is ChapterList.Item -> {
|
||||
MangaChapterListItem(
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package eu.kanade.presentation.entries.manga.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
fun MissingChapterCountListItem(
|
||||
count: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(
|
||||
horizontal = MaterialTheme.padding.medium,
|
||||
vertical = MaterialTheme.padding.small,
|
||||
)
|
||||
.secondaryItemAlpha(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
|
||||
) {
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = pluralStringResource(id = R.plurals.missing_items, count = count, count),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
MissingChapterCountListItem(count = 42)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package eu.kanade.presentation.entries.manga.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank
|
||||
import androidx.compose.material.icons.rounded.DisabledByDefault
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.minimumInteractiveComponentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
|
||||
@Composable
|
||||
fun ScanlatorFilterDialog(
|
||||
availableScanlators: Set<String>,
|
||||
excludedScanlators: Set<String>,
|
||||
onDismissRequest: () -> Unit,
|
||||
onConfirm: (Set<String>) -> Unit,
|
||||
) {
|
||||
val sortedAvailableScanlators = remember(availableScanlators) {
|
||||
availableScanlators.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it })
|
||||
}
|
||||
val mutableExcludedScanlators = remember(excludedScanlators) { excludedScanlators.toMutableStateList() }
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = { Text(text = stringResource(R.string.exclude_scanlators)) },
|
||||
text = textFunc@{
|
||||
if (sortedAvailableScanlators.isEmpty()) {
|
||||
Text(text = stringResource(R.string.no_scanlators_found))
|
||||
return@textFunc
|
||||
}
|
||||
Box {
|
||||
val state = rememberLazyListState()
|
||||
LazyColumn(state = state) {
|
||||
sortedAvailableScanlators.forEach { scanlator ->
|
||||
item {
|
||||
val isExcluded = mutableExcludedScanlators.contains(scanlator)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
if (isExcluded) {
|
||||
mutableExcludedScanlators.remove(scanlator)
|
||||
} else {
|
||||
mutableExcludedScanlators.add(scanlator)
|
||||
}
|
||||
}
|
||||
.minimumInteractiveComponentSize()
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = MaterialTheme.padding.small),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isExcluded) {
|
||||
Icons.Rounded.DisabledByDefault
|
||||
} else {
|
||||
Icons.Rounded.CheckBoxOutlineBlank
|
||||
},
|
||||
tint = if (isExcluded) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
LocalContentColor.current
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = scanlator,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.padding(start = 24.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
},
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = true,
|
||||
),
|
||||
confirmButton = {
|
||||
if (sortedAvailableScanlators.isEmpty()) {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
} else {
|
||||
FlowRow {
|
||||
TextButton(onClick = mutableExcludedScanlators::clear) {
|
||||
Text(text = stringResource(R.string.action_reset))
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
onConfirm(mutableExcludedScanlators.toSet())
|
||||
onDismissRequest()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -11,11 +11,11 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import kotlin.random.Random
|
||||
|
||||
@Composable
|
||||
|
@ -94,7 +94,7 @@ fun HistoryDeleteAllDialog(
|
|||
)
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun HistoryDeleteDialogPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -11,6 +11,7 @@ import androidx.compose.material.icons.outlined.Delete
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -19,6 +20,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.entries.ItemCover
|
||||
|
@ -28,7 +30,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.util.lang.toTimestampString
|
||||
import tachiyomi.domain.history.anime.model.AnimeHistoryWithRelations
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
private val HistoryItemHeight = 96.dp
|
||||
|
||||
|
@ -94,13 +95,14 @@ fun AnimeHistoryItem(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun HistoryItemPreviews(
|
||||
@PreviewParameter(AnimeHistoryWithRelationsProvider::class)
|
||||
historyWithRelations: AnimeHistoryWithRelations,
|
||||
) {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
AnimeHistoryItem(
|
||||
history = historyWithRelations,
|
||||
onClickCover = {},
|
||||
|
@ -109,3 +111,4 @@ private fun HistoryItemPreviews(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.compose.material3.SnackbarHost
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
|
@ -17,7 +18,6 @@ import tachiyomi.presentation.core.components.material.Scaffold
|
|||
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
|
@ -70,7 +70,7 @@ sealed interface AnimeHistoryUiModel {
|
|||
data class Item(val item: AnimeHistoryWithRelations) : AnimeHistoryUiModel
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
internal fun HistoryScreenPreviews(
|
||||
@PreviewParameter(AnimeHistoryScreenModelStateProvider::class)
|
||||
|
|
|
@ -11,6 +11,7 @@ import androidx.compose.material.icons.outlined.Delete
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -19,6 +20,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.entries.ItemCover
|
||||
|
@ -28,7 +30,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.util.lang.toTimestampString
|
||||
import tachiyomi.domain.history.manga.model.MangaHistoryWithRelations
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
private val HISTORY_ITEM_HEIGHT = 96.dp
|
||||
|
||||
|
@ -94,13 +95,14 @@ fun MangaHistoryItem(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
internal fun HistoryItemPreviews(
|
||||
@PreviewParameter(MangaHistoryWithRelationsProvider::class)
|
||||
historyWithRelations: MangaHistoryWithRelations,
|
||||
) {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
MangaHistoryItem(
|
||||
history = historyWithRelations,
|
||||
onClickCover = {},
|
||||
|
@ -109,3 +111,4 @@ internal fun HistoryItemPreviews(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.compose.material3.SnackbarHost
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
|
@ -17,7 +18,6 @@ import tachiyomi.presentation.core.components.material.Scaffold
|
|||
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Date
|
||||
|
||||
|
@ -71,7 +71,7 @@ sealed interface MangaHistoryUiModel {
|
|||
data class Item(val item: MangaHistoryWithRelations) : MangaHistoryUiModel
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
internal fun HistoryScreenPreviews(
|
||||
@PreviewParameter(MangaHistoryScreenModelStateProvider::class)
|
||||
|
|
|
@ -5,9 +5,9 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.outlined.Folder
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import tachiyomi.presentation.core.components.Badge
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
@Composable
|
||||
fun DownloadsBadge(count: Long) {
|
||||
|
@ -47,7 +47,7 @@ fun LanguageBadge(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun BadgePreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import com.halilibo.richtext.markdown.Markdown
|
||||
import com.halilibo.richtext.ui.RichTextStyle
|
||||
import com.halilibo.richtext.ui.material3.Material3RichText
|
||||
|
@ -24,7 +25,6 @@ import eu.kanade.presentation.theme.TachiyomiTheme
|
|||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.screens.InfoScreen
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
@Composable
|
||||
fun NewUpdateScreen(
|
||||
|
@ -67,7 +67,7 @@ fun NewUpdateScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun NewUpdateScreenPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -10,9 +10,9 @@ import androidx.compose.ui.platform.LocalView
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
@ -32,7 +32,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||
Preference.PreferenceItem.ListPreference(
|
||||
pref = readerPref.defaultReadingMode(),
|
||||
title = stringResource(R.string.pref_viewer_type),
|
||||
entries = ReadingModeType.entries.drop(1)
|
||||
entries = ReadingMode.entries.drop(1)
|
||||
.associate { it.flagValue to stringResource(it.stringRes) },
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
|
@ -88,7 +88,7 @@ object SettingsReaderScreen : SearchableSettings {
|
|||
Preference.PreferenceItem.ListPreference(
|
||||
pref = readerPreferences.defaultOrientationType(),
|
||||
title = stringResource(R.string.pref_rotation_type),
|
||||
entries = OrientationType.entries.drop(1)
|
||||
entries = ReaderOrientation.entries.drop(1)
|
||||
.associate { it.flagValue to stringResource(it.stringRes) },
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
|
|
|
@ -38,6 +38,7 @@ import androidx.compose.ui.draw.alpha
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.domain.ui.model.AppTheme
|
||||
import eu.kanade.presentation.entries.ItemCover
|
||||
|
@ -46,7 +47,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
|
@ -249,11 +249,12 @@ fun AppThemePreviewItem(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun AppThemesListPreview() {
|
||||
var appTheme by remember { mutableStateOf(AppTheme.DEFAULT) }
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
AppThemesList(
|
||||
currentTheme = appTheme,
|
||||
amoled = false,
|
||||
|
@ -261,3 +262,4 @@ private fun AppThemesListPreview() {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
|
@ -40,7 +40,7 @@ internal fun InfoWidget(text: String) {
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun InfoWidgetPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -9,8 +9,8 @@ import androidx.compose.material3.Switch
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
@Composable
|
||||
fun SwitchPreferenceWidget(
|
||||
|
@ -37,7 +37,7 @@ fun SwitchPreferenceWidget(
|
|||
)
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun SwitchPreferenceWidgetPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -12,8 +12,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
|
@ -59,7 +59,7 @@ fun TextPreferenceWidget(
|
|||
)
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TextPreferenceWidgetPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -34,6 +34,7 @@ import androidx.compose.ui.text.Placeholder
|
|||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.google.common.io.Files.append
|
||||
|
@ -45,7 +46,6 @@ import eu.kanade.tachiyomi.data.database.models.manga.toDomainChapter
|
|||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import tachiyomi.domain.items.service.calculateChapterGap
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
|
@ -317,7 +317,7 @@ private val FakeChapterLongTitle = previewChapter(
|
|||
chapterNumber = 1f,
|
||||
)
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TransitionTextPreview() {
|
||||
TachiyomiTheme {
|
||||
|
@ -334,7 +334,7 @@ private fun TransitionTextPreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TransitionTextLongTitlePreview() {
|
||||
TachiyomiTheme {
|
||||
|
@ -351,7 +351,7 @@ private fun TransitionTextLongTitlePreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TransitionTextWithGapPreview() {
|
||||
TachiyomiTheme {
|
||||
|
@ -368,7 +368,7 @@ private fun TransitionTextWithGapPreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TransitionTextNoNextPreview() {
|
||||
TachiyomiTheme {
|
||||
|
@ -382,7 +382,7 @@ private fun TransitionTextNoNextPreview() {
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TransitionTextNoPreviousPreview() {
|
||||
TachiyomiTheme {
|
||||
|
|
|
@ -1,46 +1,48 @@
|
|||
package eu.kanade.presentation.reader
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.domain.entries.manga.model.orientationType
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.domain.entries.manga.model.readerOrientation
|
||||
import eu.kanade.presentation.components.AdaptiveSheet
|
||||
import eu.kanade.presentation.reader.components.ModeSelectionDialog
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||
import tachiyomi.presentation.core.components.SettingsIconGrid
|
||||
import tachiyomi.presentation.core.components.material.IconToggleButton
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
private val orientationTypeOptions = OrientationType.entries.map { it.stringRes to it }
|
||||
private val ReaderOrientationsWithoutDefault = ReaderOrientation.entries - ReaderOrientation.DEFAULT
|
||||
|
||||
@Composable
|
||||
fun OrientationModeSelectDialog(
|
||||
fun OrientationSelectDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
screenModel: ReaderSettingsScreenModel,
|
||||
onChange: (Int) -> Unit,
|
||||
) {
|
||||
val manga by screenModel.mangaFlow.collectAsState()
|
||||
val orientationType = remember(manga) {
|
||||
OrientationType.fromPreference(
|
||||
manga?.orientationType?.toInt(),
|
||||
val orientation = remember(manga) {
|
||||
ReaderOrientation.fromPreference(
|
||||
manga?.readerOrientation?.toInt(),
|
||||
)
|
||||
}
|
||||
|
||||
AdaptiveSheet(onDismissRequest = onDismissRequest) {
|
||||
DialogContent(
|
||||
orientationType = orientationType,
|
||||
orientation = orientation,
|
||||
onChangeOrientation = {
|
||||
screenModel.onChangeOrientation(it)
|
||||
onChange(it.stringRes)
|
||||
|
@ -52,16 +54,25 @@ fun OrientationModeSelectDialog(
|
|||
|
||||
@Composable
|
||||
private fun DialogContent(
|
||||
orientationType: OrientationType,
|
||||
onChangeOrientation: (OrientationType) -> Unit,
|
||||
orientation: ReaderOrientation,
|
||||
onChangeOrientation: (ReaderOrientation) -> Unit,
|
||||
) {
|
||||
var selected by remember { mutableStateOf(orientation) }
|
||||
|
||||
ModeSelectionDialog(
|
||||
onUseDefault = {
|
||||
onChangeOrientation(
|
||||
ReaderOrientation.DEFAULT,
|
||||
)
|
||||
}.takeIf { orientation != ReaderOrientation.DEFAULT },
|
||||
onApply = { onChangeOrientation(selected) },
|
||||
) {
|
||||
Box(modifier = Modifier.padding(vertical = 16.dp)) {
|
||||
SettingsIconGrid(R.string.rotation_type) {
|
||||
items(OrientationType.entries) { mode ->
|
||||
items(ReaderOrientationsWithoutDefault) { mode ->
|
||||
IconToggleButton(
|
||||
checked = mode == orientationType,
|
||||
checked = mode == selected,
|
||||
onCheckedChange = {
|
||||
onChangeOrientation(mode)
|
||||
selected = (mode)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
imageVector = ImageVector.vectorResource(mode.iconRes),
|
||||
|
@ -72,13 +83,22 @@ private fun DialogContent(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun DialogContentPreview() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
Column {
|
||||
DialogContent(
|
||||
orientationType = OrientationType.DEFAULT,
|
||||
orientation = ReaderOrientation.DEFAULT,
|
||||
onChangeOrientation = {},
|
||||
)
|
||||
|
||||
DialogContent(
|
||||
orientation = ReaderOrientation.FREE,
|
||||
onChangeOrientation = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package eu.kanade.presentation.reader
|
|||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -9,9 +10,9 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
@Composable
|
||||
fun PageIndicatorText(
|
||||
|
@ -48,10 +49,12 @@ fun PageIndicatorText(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun PageIndicatorTextPreview() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
PageIndicatorText(currentPage = 10, totalPages = 69)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
package eu.kanade.presentation.reader
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import eu.kanade.domain.entries.manga.model.readingModeType
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.domain.entries.manga.model.readingMode
|
||||
import eu.kanade.presentation.components.AdaptiveSheet
|
||||
import eu.kanade.presentation.reader.components.ModeSelectionDialog
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import tachiyomi.presentation.core.components.SettingsIconGrid
|
||||
import tachiyomi.presentation.core.components.material.IconToggleButton
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
|
||||
private val readingModeOptions = ReadingModeType.entries.map { it.stringRes to it }
|
||||
private val ReadingModesWithoutDefault = ReadingMode.entries - ReadingMode.DEFAULT
|
||||
|
||||
@Composable
|
||||
fun ReadingModeSelectDialog(
|
||||
|
@ -34,8 +35,8 @@ fun ReadingModeSelectDialog(
|
|||
) {
|
||||
val manga by screenModel.mangaFlow.collectAsState()
|
||||
val readingMode = remember(manga) {
|
||||
ReadingModeType.fromPreference(
|
||||
manga?.readingModeType?.toInt(),
|
||||
ReadingMode.fromPreference(
|
||||
manga?.readingMode?.toInt(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -53,16 +54,21 @@ fun ReadingModeSelectDialog(
|
|||
|
||||
@Composable
|
||||
private fun DialogContent(
|
||||
readingMode: ReadingModeType,
|
||||
onChangeReadingMode: (ReadingModeType) -> Unit,
|
||||
readingMode: ReadingMode,
|
||||
onChangeReadingMode: (ReadingMode) -> Unit,
|
||||
) {
|
||||
var selected by remember { mutableStateOf(readingMode) }
|
||||
|
||||
ModeSelectionDialog(
|
||||
onUseDefault = { onChangeReadingMode(ReadingMode.DEFAULT) }.takeIf { readingMode != ReadingMode.DEFAULT },
|
||||
onApply = { onChangeReadingMode(selected) },
|
||||
) {
|
||||
Box(modifier = Modifier.padding(vertical = MaterialTheme.padding.medium)) {
|
||||
SettingsIconGrid(R.string.pref_category_reading_mode) {
|
||||
items(ReadingModeType.entries) { mode ->
|
||||
items(ReadingModesWithoutDefault) { mode ->
|
||||
IconToggleButton(
|
||||
checked = mode == readingMode,
|
||||
checked = mode == selected,
|
||||
onCheckedChange = {
|
||||
onChangeReadingMode(mode)
|
||||
selected = (mode)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
imageVector = ImageVector.vectorResource(mode.iconRes),
|
||||
|
@ -73,13 +79,22 @@ private fun DialogContent(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun DialogContentPreview() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
Column {
|
||||
DialogContent(
|
||||
readingMode = ReadingModeType.DEFAULT,
|
||||
readingMode = ReadingMode.DEFAULT,
|
||||
onChangeReadingMode = {},
|
||||
)
|
||||
|
||||
DialogContent(
|
||||
readingMode = ReadingMode.LEFT_TO_RIGHT,
|
||||
onChangeReadingMode = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,16 +17,16 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
|
||||
@Composable
|
||||
fun BottomReaderBar(
|
||||
backgroundColor: Color,
|
||||
readingMode: ReadingModeType,
|
||||
readingMode: ReadingMode,
|
||||
onClickReadingMode: () -> Unit,
|
||||
orientationMode: OrientationType,
|
||||
onClickOrientationMode: () -> Unit,
|
||||
orientation: ReaderOrientation,
|
||||
onClickOrientation: () -> Unit,
|
||||
cropEnabled: Boolean,
|
||||
onClickCropBorder: () -> Unit,
|
||||
onClickSettings: () -> Unit,
|
||||
|
@ -46,19 +46,17 @@ fun BottomReaderBar(
|
|||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = onClickCropBorder) {
|
||||
IconButton(onClick = onClickOrientation) {
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
if (cropEnabled) R.drawable.ic_crop_24dp else R.drawable.ic_crop_off_24dp,
|
||||
),
|
||||
contentDescription = stringResource(R.string.pref_crop_borders),
|
||||
painter = painterResource(orientation.iconRes),
|
||||
contentDescription = stringResource(R.string.rotation_type),
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = onClickOrientationMode) {
|
||||
IconButton(onClick = onClickCropBorder) {
|
||||
Icon(
|
||||
painter = painterResource(orientationMode.iconRes),
|
||||
contentDescription = stringResource(R.string.pref_rotation_type),
|
||||
painter = painterResource(if (cropEnabled) R.drawable.ic_crop_24dp else R.drawable.ic_crop_off_24dp),
|
||||
contentDescription = stringResource(R.string.pref_crop_borders),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,10 @@ import androidx.compose.ui.unit.IntOffset
|
|||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.reader.components.ChapterNavigator
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
|
||||
|
@ -54,10 +55,10 @@ fun ReaderAppBars(
|
|||
totalPages: Int,
|
||||
onSliderValueChange: (Int) -> Unit,
|
||||
|
||||
readingMode: ReadingModeType,
|
||||
readingMode: ReadingMode,
|
||||
onClickReadingMode: () -> Unit,
|
||||
orientationMode: OrientationType,
|
||||
onClickOrientationMode: () -> Unit,
|
||||
orientation: ReaderOrientation,
|
||||
onClickOrientation: () -> Unit,
|
||||
cropEnabled: Boolean,
|
||||
onClickCropBorder: () -> Unit,
|
||||
onClickSettings: () -> Unit,
|
||||
|
@ -155,8 +156,8 @@ fun ReaderAppBars(
|
|||
backgroundColor = backgroundColor,
|
||||
readingMode = readingMode,
|
||||
onClickReadingMode = onClickReadingMode,
|
||||
orientationMode = orientationMode,
|
||||
onClickOrientationMode = onClickOrientationMode,
|
||||
orientation = orientation,
|
||||
onClickOrientation = onClickOrientation,
|
||||
cropEnabled = cropEnabled,
|
||||
onClickCropBorder = onClickCropBorder,
|
||||
onClickSettings = onClickSettings,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.presentation.reader.appbars
|
||||
package eu.kanade.presentation.reader.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
@ -0,0 +1,89 @@
|
|||
package eu.kanade.presentation.reader.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Check
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.presentation.core.components.SettingsItemsPaddings
|
||||
|
||||
@Composable
|
||||
fun ModeSelectionDialog(
|
||||
onApply: () -> Unit,
|
||||
onUseDefault: (() -> Unit)? = null,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Box(modifier = Modifier.padding(vertical = 16.dp)) {
|
||||
Column {
|
||||
content()
|
||||
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = SettingsItemsPaddings.Horizontal,
|
||||
),
|
||||
) {
|
||||
onUseDefault?.let {
|
||||
OutlinedButton(onClick = it) {
|
||||
Text(text = stringResource(R.string.action_revert_to_default))
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
FilledTonalButton(
|
||||
onClick = onApply,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Check,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(text = stringResource(R.string.action_apply))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
Column {
|
||||
ModeSelectionDialog(
|
||||
onApply = {},
|
||||
onUseDefault = {},
|
||||
) {
|
||||
Text("Dummy content")
|
||||
}
|
||||
|
||||
ModeSelectionDialog(
|
||||
onApply = {},
|
||||
) {
|
||||
Text("Dummy content without default")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,13 +8,13 @@ import androidx.compose.runtime.collectAsState
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import eu.kanade.domain.entries.manga.model.orientationType
|
||||
import eu.kanade.domain.entries.manga.model.readingModeType
|
||||
import eu.kanade.domain.entries.manga.model.readerOrientation
|
||||
import eu.kanade.domain.entries.manga.model.readingMode
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||
import tachiyomi.presentation.core.components.CheckboxItem
|
||||
import tachiyomi.presentation.core.components.HeadingItem
|
||||
|
@ -23,41 +23,37 @@ import tachiyomi.presentation.core.components.SliderItem
|
|||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import java.text.NumberFormat
|
||||
|
||||
private val readingModeOptions = ReadingModeType.entries.map { it.stringRes to it }
|
||||
private val orientationTypeOptions = OrientationType.entries.map { it.stringRes to it }
|
||||
private val tappingInvertModeOptions = ReaderPreferences.TappingInvertMode.entries.map { it.titleResId to it }
|
||||
|
||||
@Composable
|
||||
internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) {
|
||||
HeadingItem(R.string.pref_category_for_this_series)
|
||||
val manga by screenModel.mangaFlow.collectAsState()
|
||||
|
||||
val readingMode = remember(manga) {
|
||||
ReadingModeType.fromPreference(
|
||||
manga?.readingModeType?.toInt(),
|
||||
ReadingMode.fromPreference(
|
||||
manga?.readingMode?.toInt(),
|
||||
)
|
||||
}
|
||||
SettingsChipRow(R.string.pref_category_reading_mode) {
|
||||
readingModeOptions.map { (stringRes, it) ->
|
||||
ReadingMode.entries.map {
|
||||
FilterChip(
|
||||
selected = it == readingMode,
|
||||
onClick = { screenModel.onChangeReadingMode(it) },
|
||||
label = { Text(stringResource(stringRes)) },
|
||||
label = { Text(stringResource(it.stringRes)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val orientationType = remember(manga) {
|
||||
OrientationType.fromPreference(
|
||||
manga?.orientationType?.toInt(),
|
||||
val orientation = remember(manga) {
|
||||
ReaderOrientation.fromPreference(
|
||||
manga?.readerOrientation?.toInt(),
|
||||
)
|
||||
}
|
||||
SettingsChipRow(R.string.rotation_type) {
|
||||
orientationTypeOptions.map { (stringRes, it) ->
|
||||
ReaderOrientation.entries.map {
|
||||
FilterChip(
|
||||
selected = it == orientationType,
|
||||
selected = it == orientation,
|
||||
onClick = { screenModel.onChangeOrientation(it) },
|
||||
label = { Text(stringResource(stringRes)) },
|
||||
label = { Text(stringResource(it.stringRes)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -217,11 +213,11 @@ private fun ColumnScope.TapZonesItems(
|
|||
|
||||
if (selected != 5) {
|
||||
SettingsChipRow(R.string.pref_read_with_tapping_inverted) {
|
||||
tappingInvertModeOptions.map { (stringRes, mode) ->
|
||||
ReaderPreferences.TappingInvertMode.entries.map {
|
||||
FilterChip(
|
||||
selected = mode == invertMode,
|
||||
onClick = { onSelectInvertMode(mode) },
|
||||
label = { Text(stringResource(stringRes)) },
|
||||
selected = it == invertMode,
|
||||
onClick = { onSelectInvertMode(it) },
|
||||
label = { Text(stringResource(it.titleResId)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import androidx.compose.material3.HorizontalDivider
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.SelectableDates
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.rememberDatePickerState
|
||||
|
@ -31,6 +32,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -39,7 +41,6 @@ import tachiyomi.presentation.core.components.WheelNumberPicker
|
|||
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
|
||||
|
@ -238,10 +239,11 @@ fun BaseSelector(
|
|||
)
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TrackStatusSelectorPreviews() {
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
TrackStatusSelector(
|
||||
selection = 1,
|
||||
onSelectionChange = {},
|
||||
|
@ -261,3 +263,4 @@ private fun TrackStatusSelectorPreviews() {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.domain.track.anime.model.toDbTrack
|
||||
|
@ -43,7 +44,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.track.AnimeTrackItem
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import java.text.DateFormat
|
||||
|
||||
private const val UnsetStatusTextAlpha = 0.5F
|
||||
|
@ -250,7 +250,7 @@ private fun TrackInfoItemEmpty(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TrackInfoDialogHomePreviews(
|
||||
@PreviewParameter(AnimeTrackInfoDialogHomePreviewProvider::class)
|
||||
|
|
|
@ -42,6 +42,7 @@ import androidx.compose.ui.text.input.ImeAction
|
|||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.text.toLowerCase
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
|
@ -52,7 +53,6 @@ import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
|||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.plus
|
||||
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
|
||||
|
||||
|
@ -201,7 +201,7 @@ fun AnimeTrackerSearch(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TrackerSearchPreviews(
|
||||
@PreviewParameter(AnimeTrackerSearchPreviewProvider::class)
|
||||
|
|
|
@ -11,11 +11,11 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
|
||||
@Composable
|
||||
|
@ -43,7 +43,7 @@ fun TrackLogoIcon(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TrackLogoIconPreviews(
|
||||
@PreviewParameter(TrackLogoIconPreviewProvider::class)
|
||||
|
|
|
@ -44,6 +44,7 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.domain.track.manga.model.toDbTrack
|
||||
|
@ -54,7 +55,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.track.MangaTrackItem
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import java.text.DateFormat
|
||||
|
||||
private const val UnsetStatusTextAlpha = 0.5F
|
||||
|
@ -322,7 +322,7 @@ fun TrackInfoItemMenu(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TrackInfoDialogHomePreviews(
|
||||
@PreviewParameter(MangaTrackInfoDialogHomePreviewProvider::class)
|
||||
|
|
|
@ -38,6 +38,7 @@ import androidx.compose.material3.HorizontalDivider
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -57,6 +58,7 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.toLowerCase
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.entries.ItemCover
|
||||
|
@ -68,7 +70,6 @@ import tachiyomi.presentation.core.components.material.Scaffold
|
|||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.plus
|
||||
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
@ -326,11 +327,15 @@ fun SearchResultItemDetails(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun TrackerSearchPreviews(
|
||||
@PreviewParameter(MangaTrackerSearchPreviewProvider::class)
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
TachiyomiTheme { content() }
|
||||
TachiyomiTheme {
|
||||
Surface {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import eu.kanade.tachiyomi.data.track.TrackerManager
|
|||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
|
@ -190,12 +190,12 @@ object Migrations {
|
|||
if (oldVersion < 60) {
|
||||
// Migrate Rotation and Viewer values to default values for viewer_flags
|
||||
val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) {
|
||||
1 -> OrientationType.FREE.flagValue
|
||||
2 -> OrientationType.PORTRAIT.flagValue
|
||||
3 -> OrientationType.LANDSCAPE.flagValue
|
||||
4 -> OrientationType.LOCKED_PORTRAIT.flagValue
|
||||
5 -> OrientationType.LOCKED_LANDSCAPE.flagValue
|
||||
else -> OrientationType.FREE.flagValue
|
||||
1 -> ReaderOrientation.FREE.flagValue
|
||||
2 -> ReaderOrientation.PORTRAIT.flagValue
|
||||
3 -> ReaderOrientation.LANDSCAPE.flagValue
|
||||
4 -> ReaderOrientation.LOCKED_PORTRAIT.flagValue
|
||||
5 -> ReaderOrientation.LOCKED_LANDSCAPE.flagValue
|
||||
else -> ReaderOrientation.FREE.flagValue
|
||||
}
|
||||
|
||||
// Reading mode flag and prefValue is the same value
|
||||
|
|
|
@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.data.backup.models.BackupAnime
|
|||
import eu.kanade.tachiyomi.data.backup.models.BackupAnimeHistory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupAnimeSource
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtension
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionPreferences
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
||||
|
@ -240,15 +241,15 @@ class BackupCreator(
|
|||
// Check if user wants chapter information in backup
|
||||
if (options and BackupConst.BACKUP_CHAPTER_MASK == BackupConst.BACKUP_CHAPTER) {
|
||||
// Backup all the chapters
|
||||
val chapters = mangaHandler.awaitList {
|
||||
mangaHandler.awaitList {
|
||||
chaptersQueries.getChaptersByMangaId(
|
||||
manga.id,
|
||||
backupChapterMapper,
|
||||
mangaId = manga.id,
|
||||
applyScanlatorFilter = 0, // false
|
||||
mapper = backupChapterMapper,
|
||||
)
|
||||
}
|
||||
if (chapters.isNotEmpty()) {
|
||||
mangaObject.chapters = chapters
|
||||
}
|
||||
.takeUnless(List<BackupChapter>::isEmpty)
|
||||
?.let { mangaObject.chapters = it }
|
||||
}
|
||||
|
||||
// Check if user wants category information in backup
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.tachiyomi.data.backup.models
|
||||
|
||||
import eu.kanade.tachiyomi.model.UpdateStrategy
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
|
@ -89,7 +89,7 @@ data class BackupManga(
|
|||
favorite = manga.favorite,
|
||||
source = manga.source,
|
||||
dateAdded = manga.dateAdded,
|
||||
viewer = (manga.viewerFlags.toInt() and ReadingModeType.MASK),
|
||||
viewer = (manga.viewerFlags.toInt() and ReadingMode.MASK),
|
||||
viewer_flags = manga.viewerFlags.toInt(),
|
||||
chapterFlags = manga.chapterFlags.toInt(),
|
||||
updateStrategy = manga.updateStrategy,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
|
@ -13,10 +12,10 @@ class AppUpdateChecker {
|
|||
private val getApplicationRelease: GetApplicationRelease by injectLazy()
|
||||
|
||||
suspend fun checkForUpdate(context: Context, forceCheck: Boolean = false): GetApplicationRelease.Result {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
return GetApplicationRelease.Result.OsTooOld
|
||||
}
|
||||
// Disabling app update checks for older Android versions that we're going to drop support for
|
||||
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
// return GetApplicationRelease.Result.OsTooOld
|
||||
// }
|
||||
|
||||
return withIOContext {
|
||||
val result = getApplicationRelease.await(
|
||||
|
|
|
@ -9,8 +9,10 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
@ -31,6 +33,7 @@ import eu.kanade.presentation.entries.manga.ChapterSettingsDialog
|
|||
import eu.kanade.presentation.entries.manga.DuplicateMangaDialog
|
||||
import eu.kanade.presentation.entries.manga.MangaScreen
|
||||
import eu.kanade.presentation.entries.manga.components.MangaCoverDialog
|
||||
import eu.kanade.presentation.entries.manga.components.ScanlatorFilterDialog
|
||||
import eu.kanade.presentation.util.AssistContentScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.presentation.util.isTabletUi
|
||||
|
@ -153,6 +156,8 @@ class MangaScreen(
|
|||
onInvertSelection = screenModel::invertSelection,
|
||||
)
|
||||
|
||||
var showScanlatorsDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val onDismissRequest = {
|
||||
screenModel.dismissDialog()
|
||||
if (screenModel.autoOpenTrack && screenModel.isFromChangeCategory) {
|
||||
|
@ -197,6 +202,8 @@ class MangaScreen(
|
|||
onDisplayModeChanged = screenModel::setDisplayMode,
|
||||
onSetAsDefault = screenModel::setCurrentSettingsAsDefault,
|
||||
onResetToDefault = screenModel::resetToDefaultSettings,
|
||||
scanlatorFilterActive = successState.scanlatorFilterActive,
|
||||
onScanlatorFilterClicked = { showScanlatorsDialog = true },
|
||||
)
|
||||
MangaScreenModel.Dialog.TrackSheet -> {
|
||||
NavigatorAdaptiveSheet(
|
||||
|
@ -245,6 +252,15 @@ class MangaScreen(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (showScanlatorsDialog) {
|
||||
ScanlatorFilterDialog(
|
||||
availableScanlators = successState.availableScanlators,
|
||||
excludedScanlators = successState.excludedScanlators,
|
||||
onDismissRequest = { showScanlatorsDialog = false },
|
||||
onConfirm = screenModel::setExcludedScanlators,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun continueReading(context: Context, unreadChapter: Chapter?) {
|
||||
|
|
|
@ -11,9 +11,13 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
|||
import eu.kanade.core.preference.asState
|
||||
import eu.kanade.core.util.addOrRemove
|
||||
import eu.kanade.core.util.insertSeparators
|
||||
import eu.kanade.domain.entries.manga.interactor.GetExcludedScanlators
|
||||
import eu.kanade.domain.entries.manga.interactor.SetExcludedScanlators
|
||||
import eu.kanade.domain.entries.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.entries.manga.model.chaptersFiltered
|
||||
import eu.kanade.domain.entries.manga.model.downloadedFilter
|
||||
import eu.kanade.domain.entries.manga.model.toSManga
|
||||
import eu.kanade.domain.items.chapter.interactor.GetAvailableScanlators
|
||||
import eu.kanade.domain.items.chapter.interactor.SetReadStatus
|
||||
import eu.kanade.domain.items.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.track.manga.interactor.AddMangaTracks
|
||||
|
@ -95,6 +99,9 @@ class MangaScreenModel(
|
|||
private val downloadCache: MangaDownloadCache = Injekt.get(),
|
||||
private val getMangaAndChapters: GetMangaWithChapters = Injekt.get(),
|
||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||
private val getAvailableScanlators: GetAvailableScanlators = Injekt.get(),
|
||||
private val getExcludedScanlators: GetExcludedScanlators = Injekt.get(),
|
||||
private val setExcludedScanlators: SetExcludedScanlators = Injekt.get(),
|
||||
private val setMangaChapterFlags: SetMangaChapterFlags = Injekt.get(),
|
||||
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
|
||||
private val setReadStatus: SetReadStatus = Injekt.get(),
|
||||
|
@ -162,7 +169,7 @@ class MangaScreenModel(
|
|||
init {
|
||||
screenModelScope.launchIO {
|
||||
combine(
|
||||
getMangaAndChapters.subscribe(mangaId).distinctUntilChanged(),
|
||||
getMangaAndChapters.subscribe(mangaId, applyScanlatorFilter = true).distinctUntilChanged(),
|
||||
downloadCache.changes,
|
||||
downloadManager.queueState,
|
||||
) { mangaAndChapters, _, _ -> mangaAndChapters }
|
||||
|
@ -176,11 +183,31 @@ class MangaScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
screenModelScope.launchIO {
|
||||
getExcludedScanlators.subscribe(mangaId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { excludedScanlators ->
|
||||
updateSuccessState {
|
||||
it.copy(excludedScanlators = excludedScanlators)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
screenModelScope.launchIO {
|
||||
getAvailableScanlators.subscribe(mangaId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { availableScanlators ->
|
||||
updateSuccessState {
|
||||
it.copy(availableScanlators = availableScanlators)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observeDownloads()
|
||||
|
||||
screenModelScope.launchIO {
|
||||
val manga = getMangaAndChapters.awaitManga(mangaId)
|
||||
val chapters = getMangaAndChapters.awaitChapters(mangaId)
|
||||
val chapters = getMangaAndChapters.awaitChapters(mangaId, applyScanlatorFilter = true)
|
||||
.toChapterListItems(manga)
|
||||
|
||||
if (!manga.favorite) {
|
||||
|
@ -197,6 +224,8 @@ class MangaScreenModel(
|
|||
source = Injekt.get<MangaSourceManager>().getOrStub(manga.source),
|
||||
isFromSource = isFromSource,
|
||||
chapters = chapters,
|
||||
availableScanlators = getAvailableScanlators.await(mangaId),
|
||||
excludedScanlators = getExcludedScanlators.await(mangaId),
|
||||
isRefreshingData = needRefreshInfo || needRefreshChapter,
|
||||
dialog = null,
|
||||
)
|
||||
|
@ -1028,6 +1057,12 @@ class MangaScreenModel(
|
|||
updateSuccessState { it.copy(dialog = Dialog.FullCover) }
|
||||
}
|
||||
|
||||
fun setExcludedScanlators(excludedScanlators: Set<String>) {
|
||||
screenModelScope.launchIO {
|
||||
setExcludedScanlators.await(mangaId, excludedScanlators)
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface State {
|
||||
@Immutable
|
||||
data object Loading : State
|
||||
|
@ -1038,12 +1073,13 @@ class MangaScreenModel(
|
|||
val source: MangaSource,
|
||||
val isFromSource: Boolean,
|
||||
val chapters: List<ChapterList.Item>,
|
||||
val availableScanlators: Set<String>,
|
||||
val excludedScanlators: Set<String>,
|
||||
val trackItems: List<MangaTrackItem> = emptyList(),
|
||||
val isRefreshingData: Boolean = false,
|
||||
val dialog: Dialog? = null,
|
||||
val hasPromptedToAddBefore: Boolean = false,
|
||||
) : State {
|
||||
|
||||
val processedChapters by lazy {
|
||||
chapters.applyFilters(manga).toList()
|
||||
}
|
||||
|
@ -1075,6 +1111,12 @@ class MangaScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
val scanlatorFilterActive: Boolean
|
||||
get() = excludedScanlators.intersect(availableScanlators).isNotEmpty()
|
||||
|
||||
val filterActive: Boolean
|
||||
get() = scanlatorFilterActive || manga.chaptersFiltered()
|
||||
|
||||
val trackingAvailable: Boolean
|
||||
get() = trackItems.isNotEmpty()
|
||||
|
||||
|
|
|
@ -416,7 +416,7 @@ class MangaLibraryScreenModel(
|
|||
}
|
||||
|
||||
suspend fun getNextUnreadChapter(manga: Manga): Chapter? {
|
||||
return getChaptersByMangaId.await(manga.id).getNextUnread(manga, downloadManager)
|
||||
return getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true).getNextUnread(manga, downloadManager)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -43,7 +43,7 @@ import dev.chrisbanes.insetter.applyInsetter
|
|||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.presentation.reader.BrightnessOverlay
|
||||
import eu.kanade.presentation.reader.DisplayRefreshHost
|
||||
import eu.kanade.presentation.reader.OrientationModeSelectDialog
|
||||
import eu.kanade.presentation.reader.OrientationSelectDialog
|
||||
import eu.kanade.presentation.reader.PageIndicatorText
|
||||
import eu.kanade.presentation.reader.ReaderPageActionsDialog
|
||||
import eu.kanade.presentation.reader.ReadingModeSelectDialog
|
||||
|
@ -63,10 +63,10 @@ import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.Success
|
|||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||
|
@ -338,7 +338,7 @@ class ReaderActivity : BaseActivity() {
|
|||
|
||||
val cropBorderPaged by readerPreferences.cropBorders().collectAsState()
|
||||
val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState()
|
||||
val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode())
|
||||
val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode())
|
||||
val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon
|
||||
|
||||
ReaderAppBars(
|
||||
|
@ -367,14 +367,14 @@ class ReaderActivity : BaseActivity() {
|
|||
moveToPageIndex(it)
|
||||
},
|
||||
|
||||
readingMode = ReadingModeType.fromPreference(
|
||||
readingMode = ReadingMode.fromPreference(
|
||||
viewModel.getMangaReadingMode(resolveDefault = false),
|
||||
),
|
||||
onClickReadingMode = viewModel::openReadingModeSelectDialog,
|
||||
orientationMode = OrientationType.fromPreference(
|
||||
viewModel.getMangaOrientationType(resolveDefault = false),
|
||||
orientation = ReaderOrientation.fromPreference(
|
||||
viewModel.getMangaOrientation(resolveDefault = false),
|
||||
),
|
||||
onClickOrientationMode = viewModel::openOrientationModeSelectDialog,
|
||||
onClickOrientation = viewModel::openOrientationModeSelectDialog,
|
||||
cropEnabled = cropEnabled,
|
||||
onClickCropBorder = {
|
||||
val enabled = viewModel.toggleCropBorders()
|
||||
|
@ -432,7 +432,7 @@ class ReaderActivity : BaseActivity() {
|
|||
)
|
||||
}
|
||||
is ReaderViewModel.Dialog.OrientationModeSelect -> {
|
||||
OrientationModeSelectDialog(
|
||||
OrientationSelectDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
screenModel = settingsScreenModel,
|
||||
onChange = { stringRes ->
|
||||
|
@ -489,15 +489,15 @@ class ReaderActivity : BaseActivity() {
|
|||
*/
|
||||
private fun setManga(manga: Manga) {
|
||||
val prevViewer = viewModel.state.value.viewer
|
||||
val newViewer = ReadingModeType.toViewer(viewModel.getMangaReadingMode(), this)
|
||||
val newViewer = ReadingMode.toViewer(viewModel.getMangaReadingMode(), this)
|
||||
|
||||
if (window.sharedElementEnterTransition is MaterialContainerTransform) {
|
||||
// Wait until transition is complete to avoid crash on API 26
|
||||
window.sharedElementEnterTransition.doOnEnd {
|
||||
setOrientation(viewModel.getMangaOrientationType())
|
||||
setOrientation(viewModel.getMangaOrientation())
|
||||
}
|
||||
} else {
|
||||
setOrientation(viewModel.getMangaOrientationType())
|
||||
setOrientation(viewModel.getMangaOrientation())
|
||||
}
|
||||
|
||||
// Destroy previous viewer if there was one
|
||||
|
@ -550,7 +550,7 @@ class ReaderActivity : BaseActivity() {
|
|||
private fun showReadingModeToast(mode: Int) {
|
||||
try {
|
||||
readingModeToast?.cancel()
|
||||
readingModeToast = toast(ReadingModeType.fromPreference(mode).stringRes)
|
||||
readingModeToast = toast(ReadingMode.fromPreference(mode).stringRes)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
logcat(LogPriority.ERROR) { "Unknown reading mode: $mode" }
|
||||
}
|
||||
|
@ -728,7 +728,7 @@ class ReaderActivity : BaseActivity() {
|
|||
* Forces the user preferred [orientation] on the activity.
|
||||
*/
|
||||
private fun setOrientation(orientation: Int) {
|
||||
val newOrientation = OrientationType.fromPreference(orientation)
|
||||
val newOrientation = ReaderOrientation.fromPreference(orientation)
|
||||
if (newOrientation.flag != requestedOrientation) {
|
||||
requestedOrientation = newOrientation.flag
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.entries.manga.interactor.SetMangaViewerFlags
|
||||
import eu.kanade.domain.entries.manga.model.orientationType
|
||||
import eu.kanade.domain.entries.manga.model.readingModeType
|
||||
import eu.kanade.domain.entries.manga.model.readerOrientation
|
||||
import eu.kanade.domain.entries.manga.model.readingMode
|
||||
import eu.kanade.domain.items.chapter.model.toDbChapter
|
||||
import eu.kanade.domain.track.manga.interactor.TrackChapter
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
|
@ -29,9 +29,9 @@ import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
|||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
|
||||
import eu.kanade.tachiyomi.util.chapter.filterDownloadedChapters
|
||||
import eu.kanade.tachiyomi.util.chapter.removeDuplicates
|
||||
|
@ -147,7 +147,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
*/
|
||||
private val chapterList by lazy {
|
||||
val manga = manga!!
|
||||
val chapters = runBlocking { getChaptersByMangaId.await(manga.id) }
|
||||
val chapters = runBlocking { getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true) }
|
||||
|
||||
val selectedChapter = chapters.find { it.id == chapterId }
|
||||
?: error("Requested chapter of id $chapterId not found in chapter list")
|
||||
|
@ -642,22 +642,22 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
*/
|
||||
fun getMangaReadingMode(resolveDefault: Boolean = true): Int {
|
||||
val default = readerPreferences.defaultReadingMode().get()
|
||||
val readingMode = ReadingModeType.fromPreference(manga?.readingModeType?.toInt())
|
||||
val readingMode = ReadingMode.fromPreference(manga?.readingMode?.toInt())
|
||||
return when {
|
||||
resolveDefault && readingMode == ReadingModeType.DEFAULT -> default
|
||||
else -> manga?.readingModeType?.toInt() ?: default
|
||||
resolveDefault && readingMode == ReadingMode.DEFAULT -> default
|
||||
else -> manga?.readingMode?.toInt() ?: default
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the viewer position for the open manga.
|
||||
*/
|
||||
fun setMangaReadingMode(readingModeType: ReadingModeType) {
|
||||
fun setMangaReadingMode(readingMode: ReadingMode) {
|
||||
val manga = manga ?: return
|
||||
runBlocking(Dispatchers.IO) {
|
||||
setMangaViewerFlags.awaitSetReadingMode(
|
||||
manga.id,
|
||||
readingModeType.flagValue.toLong(),
|
||||
readingMode.flagValue.toLong(),
|
||||
)
|
||||
val currChapters = state.value.viewerChapters
|
||||
if (currChapters != null) {
|
||||
|
@ -679,22 +679,22 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
/**
|
||||
* Returns the orientation type used by this manga or the default one.
|
||||
*/
|
||||
fun getMangaOrientationType(resolveDefault: Boolean = true): Int {
|
||||
fun getMangaOrientation(resolveDefault: Boolean = true): Int {
|
||||
val default = readerPreferences.defaultOrientationType().get()
|
||||
val orientation = OrientationType.fromPreference(manga?.orientationType?.toInt())
|
||||
val orientation = ReaderOrientation.fromPreference(manga?.readerOrientation?.toInt())
|
||||
return when {
|
||||
resolveDefault && orientation == OrientationType.DEFAULT -> default
|
||||
else -> manga?.orientationType?.toInt() ?: default
|
||||
resolveDefault && orientation == ReaderOrientation.DEFAULT -> default
|
||||
else -> manga?.readerOrientation?.toInt() ?: default
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the orientation type for the open manga.
|
||||
*/
|
||||
fun setMangaOrientationType(rotationType: OrientationType) {
|
||||
fun setMangaOrientationType(orientation: ReaderOrientation) {
|
||||
val manga = manga ?: return
|
||||
viewModelScope.launchIO {
|
||||
setMangaViewerFlags.awaitSetOrientation(manga.id, rotationType.flagValue.toLong())
|
||||
setMangaViewerFlags.awaitSetOrientation(manga.id, orientation.flagValue.toLong())
|
||||
val currChapters = state.value.viewerChapters
|
||||
if (currChapters != null) {
|
||||
// Save current page
|
||||
|
@ -707,14 +707,14 @@ class ReaderViewModel @JvmOverloads constructor(
|
|||
viewerChapters = currChapters,
|
||||
)
|
||||
}
|
||||
eventChannel.send(Event.SetOrientation(getMangaOrientationType()))
|
||||
eventChannel.send(Event.SetOrientation(getMangaOrientation()))
|
||||
eventChannel.send(Event.ReloadViewerChapters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleCropBorders(): Boolean {
|
||||
val isPagerType = ReadingModeType.isPagerType(getMangaReadingMode())
|
||||
val isPagerType = ReadingMode.isPagerType(getMangaReadingMode())
|
||||
return if (isPagerType) {
|
||||
readerPreferences.cropBorders().toggle()
|
||||
} else {
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.annotation.DrawableRes
|
|||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
enum class OrientationType(
|
||||
enum class ReaderOrientation(
|
||||
val flag: Int,
|
||||
@StringRes val stringRes: Int,
|
||||
@DrawableRes val iconRes: Int,
|
||||
|
@ -58,6 +58,6 @@ enum class OrientationType(
|
|||
companion object {
|
||||
const val MASK = 0x00000038
|
||||
|
||||
fun fromPreference(preference: Int?): OrientationType = entries.find { it.flagValue == preference } ?: DEFAULT
|
||||
fun fromPreference(preference: Int?): ReaderOrientation = entries.find { it.flagValue == preference } ?: DEFAULT
|
||||
}
|
||||
}
|
|
@ -32,12 +32,12 @@ class ReaderPreferences(
|
|||
|
||||
fun defaultReadingMode() = preferenceStore.getInt(
|
||||
"pref_default_reading_mode_key",
|
||||
ReadingModeType.RIGHT_TO_LEFT.flagValue,
|
||||
ReadingMode.RIGHT_TO_LEFT.flagValue,
|
||||
)
|
||||
|
||||
fun defaultOrientationType() = preferenceStore.getInt(
|
||||
"pref_default_orientation_type_key",
|
||||
OrientationType.FREE.flagValue,
|
||||
ReaderOrientation.FREE.flagValue,
|
||||
)
|
||||
|
||||
fun webtoonDoubleTapZoomEnabled() = preferenceStore.getBoolean(
|
||||
|
|
|
@ -14,8 +14,8 @@ import uy.kohesive.injekt.api.get
|
|||
class ReaderSettingsScreenModel(
|
||||
readerState: StateFlow<ReaderViewModel.State>,
|
||||
val hasDisplayCutout: Boolean,
|
||||
val onChangeReadingMode: (ReadingModeType) -> Unit,
|
||||
val onChangeOrientation: (OrientationType) -> Unit,
|
||||
val onChangeReadingMode: (ReadingMode) -> Unit,
|
||||
val onChangeOrientation: (ReaderOrientation) -> Unit,
|
||||
val preferences: ReaderPreferences = Injekt.get(),
|
||||
) : ScreenModel {
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
|||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||
|
||||
enum class ReadingModeType(
|
||||
enum class ReadingMode(
|
||||
@StringRes val stringRes: Int,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val flagValue: Int,
|
||||
val direction: Direction? = null,
|
||||
val type: ViewerType? = null,
|
||||
) {
|
||||
DEFAULT(R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000),
|
||||
LEFT_TO_RIGHT(R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001),
|
||||
|
@ -30,11 +32,11 @@ enum class ReadingModeType(
|
|||
companion object {
|
||||
const val MASK = 0x00000007
|
||||
|
||||
fun fromPreference(preference: Int?): ReadingModeType = entries.find { it.flagValue == preference } ?: DEFAULT
|
||||
fun fromPreference(preference: Int?): ReadingMode = entries.find { it.flagValue == preference } ?: DEFAULT
|
||||
|
||||
fun isPagerType(preference: Int): Boolean {
|
||||
val mode = fromPreference(preference)
|
||||
return mode == LEFT_TO_RIGHT || mode == RIGHT_TO_LEFT || mode == VERTICAL
|
||||
return mode.type is ViewerType.Pager
|
||||
}
|
||||
|
||||
fun toViewer(preference: Int?, activity: ReaderActivity): Viewer {
|
||||
|
@ -50,4 +52,14 @@ enum class ReadingModeType(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface Direction {
|
||||
data object Horizontal : Direction
|
||||
data object Vertical : Direction
|
||||
}
|
||||
|
||||
sealed interface ViewerType {
|
||||
data object Pager : ViewerType
|
||||
data object Webtoon : ViewerType
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package tachiyomi.data.items.chapter
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.toLong
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.data.handlers.manga.MangaDatabaseHandler
|
||||
import tachiyomi.domain.items.chapter.model.Chapter
|
||||
|
@ -76,8 +77,22 @@ class ChapterRepositoryImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getChapterByMangaId(mangaId: Long): List<Chapter> {
|
||||
return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, ::mapChapter) }
|
||||
override suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean): List<Chapter> {
|
||||
return handler.awaitList {
|
||||
chaptersQueries.getChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ::mapChapter)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getScanlatorsByMangaId(mangaId: Long): List<String> {
|
||||
return handler.awaitList {
|
||||
chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScanlatorsByMangaIdAsFlow(mangaId: Long): Flow<List<String>> {
|
||||
return handler.subscribeToList {
|
||||
chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List<Chapter> {
|
||||
|
@ -93,12 +108,9 @@ class ChapterRepositoryImpl(
|
|||
return handler.awaitOneOrNull { chaptersQueries.getChapterById(id, ::mapChapter) }
|
||||
}
|
||||
|
||||
override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow<List<Chapter>> {
|
||||
override suspend fun getChapterByMangaIdAsFlow(mangaId: Long, applyScanlatorFilter: Boolean): Flow<List<Chapter>> {
|
||||
return handler.subscribeToList {
|
||||
chaptersQueries.getChaptersByMangaId(
|
||||
mangaId,
|
||||
::mapChapter,
|
||||
)
|
||||
chaptersQueries.getChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ::mapChapter)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,19 @@ FROM chapters
|
|||
WHERE _id = :id;
|
||||
|
||||
getChaptersByMangaId:
|
||||
SELECT *
|
||||
SELECT C.*
|
||||
FROM chapters C
|
||||
LEFT JOIN excluded_scanlators ES
|
||||
ON C.manga_id = ES.manga_id
|
||||
AND C.scanlator = ES.scanlator
|
||||
WHERE C.manga_id = :mangaId
|
||||
AND (
|
||||
:applyScanlatorFilter = 0
|
||||
OR ES.scanlator IS NULL
|
||||
);
|
||||
|
||||
getScanlatorsByMangaId:
|
||||
SELECT scanlator
|
||||
FROM chapters
|
||||
WHERE manga_id = :mangaId;
|
||||
|
||||
|
|
22
data/src/main/sqldelight/data/excluded_scanlators.sq
Normal file
22
data/src/main/sqldelight/data/excluded_scanlators.sq
Normal file
|
@ -0,0 +1,22 @@
|
|||
CREATE TABLE excluded_scanlators(
|
||||
manga_id INTEGER NOT NULL,
|
||||
scanlator TEXT NOT NULL,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id);
|
||||
|
||||
insert:
|
||||
INSERT INTO excluded_scanlators(manga_id, scanlator)
|
||||
VALUES (:mangaId, :scanlator);
|
||||
|
||||
remove:
|
||||
DELETE FROM excluded_scanlators
|
||||
WHERE manga_id = :mangaId
|
||||
AND scanlator IN :scanlators;
|
||||
|
||||
getExcludedScanlatorsByMangaId:
|
||||
SELECT scanlator
|
||||
FROM excluded_scanlators
|
||||
WHERE manga_id = :mangaId;
|
44
data/src/main/sqldelight/migrations/27.sqm
Normal file
44
data/src/main/sqldelight/migrations/27.sqm
Normal file
|
@ -0,0 +1,44 @@
|
|||
CREATE TABLE excluded_scanlators(
|
||||
manga_id INTEGER NOT NULL,
|
||||
scanlator TEXT NOT NULL,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id);
|
||||
|
||||
DROP VIEW IF EXISTS libraryView;
|
||||
|
||||
CREATE VIEW libraryView AS
|
||||
SELECT
|
||||
M.*,
|
||||
coalesce(C.total, 0) AS totalCount,
|
||||
coalesce(C.readCount, 0) AS readCount,
|
||||
coalesce(C.latestUpload, 0) AS latestUpload,
|
||||
coalesce(C.fetchedAt, 0) AS chapterFetchedAt,
|
||||
coalesce(C.lastRead, 0) AS lastRead,
|
||||
coalesce(C.bookmarkCount, 0) AS bookmarkCount,
|
||||
coalesce(MC.category_id, 0) AS category
|
||||
FROM mangas M
|
||||
LEFT JOIN(
|
||||
SELECT
|
||||
chapters.manga_id,
|
||||
count(*) AS total,
|
||||
sum(read) AS readCount,
|
||||
coalesce(max(chapters.date_upload), 0) AS latestUpload,
|
||||
coalesce(max(history.last_read), 0) AS lastRead,
|
||||
coalesce(max(chapters.date_fetch), 0) AS fetchedAt,
|
||||
sum(chapters.bookmark) AS bookmarkCount
|
||||
FROM chapters
|
||||
LEFT JOIN excluded_scanlators
|
||||
ON chapters.manga_id = excluded_scanlators.manga_id
|
||||
AND chapters.scanlator = excluded_scanlators.scanlator
|
||||
LEFT JOIN history
|
||||
ON chapters._id = history.chapter_id
|
||||
WHERE excluded_scanlators.scanlator IS NULL
|
||||
GROUP BY chapters.manga_id
|
||||
) AS C
|
||||
ON M._id = C.manga_id
|
||||
LEFT JOIN mangas_categories AS MC
|
||||
ON MC.manga_id = M._id
|
||||
WHERE M.favorite = 1;
|
3
data/src/main/sqldelight/migrations/28.sqm
Normal file
3
data/src/main/sqldelight/migrations/28.sqm
Normal file
|
@ -0,0 +1,3 @@
|
|||
UPDATE chapters
|
||||
SET scanlator = trim(scanlator)
|
||||
WHERE scanlator IS NOT NULL;
|
|
@ -19,8 +19,12 @@ LEFT JOIN(
|
|||
coalesce(max(chapters.date_fetch), 0) AS fetchedAt,
|
||||
sum(chapters.bookmark) AS bookmarkCount
|
||||
FROM chapters
|
||||
LEFT JOIN excluded_scanlators
|
||||
ON chapters.manga_id = excluded_scanlators.manga_id
|
||||
AND chapters.scanlator = excluded_scanlators.scanlator
|
||||
LEFT JOIN history
|
||||
ON chapters._id = history.chapter_id
|
||||
WHERE excluded_scanlators.scanlator IS NULL
|
||||
GROUP BY chapters.manga_id
|
||||
) AS C
|
||||
ON M._id = C.manga_id
|
||||
|
|
|
@ -12,10 +12,10 @@ class GetMangaWithChapters(
|
|||
private val chapterRepository: ChapterRepository,
|
||||
) {
|
||||
|
||||
suspend fun subscribe(id: Long): Flow<Pair<Manga, List<Chapter>>> {
|
||||
suspend fun subscribe(id: Long, applyScanlatorFilter: Boolean = false): Flow<Pair<Manga, List<Chapter>>> {
|
||||
return combine(
|
||||
mangaRepository.getMangaByIdAsFlow(id),
|
||||
chapterRepository.getChapterByMangaIdAsFlow(id),
|
||||
chapterRepository.getChapterByMangaIdAsFlow(id, applyScanlatorFilter),
|
||||
) { manga, chapters ->
|
||||
Pair(manga, chapters)
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class GetMangaWithChapters(
|
|||
return mangaRepository.getMangaById(id)
|
||||
}
|
||||
|
||||
suspend fun awaitChapters(id: Long): List<Chapter> {
|
||||
return chapterRepository.getChapterByMangaId(id)
|
||||
suspend fun awaitChapters(id: Long, applyScanlatorFilter: Boolean = false): List<Chapter> {
|
||||
return chapterRepository.getChapterByMangaId(id, applyScanlatorFilter)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class MangaFetchInterval(
|
|||
} else {
|
||||
window
|
||||
}
|
||||
val chapters = getChaptersByMangaId.await(manga.id)
|
||||
val chapters = getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true)
|
||||
val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval(
|
||||
chapters,
|
||||
dateTime.zone,
|
||||
|
|
|
@ -20,7 +20,7 @@ class GetNextChapters(
|
|||
|
||||
suspend fun await(mangaId: Long, onlyUnread: Boolean = true): List<Chapter> {
|
||||
val manga = getManga.await(mangaId) ?: return emptyList()
|
||||
val chapters = getChaptersByMangaId.await(mangaId)
|
||||
val chapters = getChaptersByMangaId.await(mangaId, applyScanlatorFilter = true)
|
||||
.sortedWith(getChapterSort(manga, sortDescending = false))
|
||||
|
||||
return if (onlyUnread) {
|
||||
|
|
|
@ -9,9 +9,9 @@ class GetChaptersByMangaId(
|
|||
private val chapterRepository: ChapterRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(mangaId: Long): List<Chapter> {
|
||||
suspend fun await(mangaId: Long, applyScanlatorFilter: Boolean = false): List<Chapter> {
|
||||
return try {
|
||||
chapterRepository.getChapterByMangaId(mangaId)
|
||||
chapterRepository.getChapterByMangaId(mangaId, applyScanlatorFilter)
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
emptyList()
|
||||
|
|
|
@ -14,13 +14,17 @@ interface ChapterRepository {
|
|||
|
||||
suspend fun removeChaptersWithIds(chapterIds: List<Long>)
|
||||
|
||||
suspend fun getChapterByMangaId(mangaId: Long): List<Chapter>
|
||||
suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean = false): List<Chapter>
|
||||
|
||||
suspend fun getScanlatorsByMangaId(mangaId: Long): List<String>
|
||||
|
||||
fun getScanlatorsByMangaIdAsFlow(mangaId: Long): Flow<List<String>>
|
||||
|
||||
suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List<Chapter>
|
||||
|
||||
suspend fun getChapterById(id: Long): Chapter?
|
||||
|
||||
suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow<List<Chapter>>
|
||||
suspend fun getChapterByMangaIdAsFlow(mangaId: Long, applyScanlatorFilter: Boolean = false): Flow<List<Chapter>>
|
||||
|
||||
suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long): Chapter?
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ shizuku_version = "12.2.0"
|
|||
sqlite = "2.4.0"
|
||||
sqldelight = "2.0.0"
|
||||
leakcanary = "2.12"
|
||||
voyager = "1.0.0-rc08"
|
||||
voyager = "1.0.0-rc09"
|
||||
richtext = "0.17.0"
|
||||
|
||||
[libraries]
|
||||
|
@ -81,7 +81,7 @@ sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-ext
|
|||
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
|
||||
sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" }
|
||||
|
||||
junit = "org.junit.jupiter:junit-jupiter:5.10.0"
|
||||
junit = "org.junit.jupiter:junit-jupiter:5.10.1"
|
||||
kotest-assertions = "io.kotest:kotest-assertions-core:5.8.0"
|
||||
mockk = "io.mockk:mockk:1.13.8"
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<string name="track">Tracking</string>
|
||||
<string name="delete_downloaded">Delete downloaded</string>
|
||||
<string name="history">History</string>
|
||||
<string name="scanlator">Scanlator</string>
|
||||
|
||||
<!-- Screen titles -->
|
||||
<string name="label_more">More</string>
|
||||
|
@ -126,6 +127,7 @@
|
|||
<string name="action_disable">Disable</string>
|
||||
<string name="action_pin">Pin</string>
|
||||
<string name="action_unpin">Unpin</string>
|
||||
<string name="action_apply">Apply</string>
|
||||
<string name="action_cancel">Cancel</string>
|
||||
<string name="action_ok">OK</string>
|
||||
<string name="action_cancel_all">Cancel all</string>
|
||||
|
@ -146,6 +148,7 @@
|
|||
<string name="action_share">Share</string>
|
||||
<string name="action_save">Save</string>
|
||||
<string name="action_reset">Reset</string>
|
||||
<string name="action_revert_to_default">Revert to default</string>
|
||||
<!-- missing undo feature after Compose rewrite #7454 -->
|
||||
<string name="action_undo">Undo</string>
|
||||
<string name="action_close">Close</string>
|
||||
|
@ -686,6 +689,8 @@
|
|||
<string name="set_chapter_settings_as_default">Set as default</string>
|
||||
<string name="no_chapters_error">No chapters found</string>
|
||||
<string name="are_you_sure">Are you sure?</string>
|
||||
<string name="exclude_scanlators">Exclude scanlators</string>
|
||||
<string name="no_scanlators_found">No scanlators found</string>
|
||||
|
||||
<!-- Tracking Screen -->
|
||||
<string name="manga_tracking_tab">Tracking</string>
|
||||
|
|
|
@ -23,12 +23,12 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.ThemePreviews
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
|
||||
@Composable
|
||||
|
@ -121,7 +121,7 @@ fun InfoScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@ThemePreviews
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun InfoScaffoldPreview() {
|
||||
InfoScreen(
|
||||
|
|
Loading…
Reference in a new issue