feat(ui): Panorama cover
* support panorama cover * bigger panorama cover size in GlobalSearchCardRow * setting to enable/disable * panorama cover for History items * Keep panorama cover position in Library View centered for better visual * fix: update ratio in Detail page if cover doesn't reload anew * adjust ratio to switch to panorma * panorama cover for Migration items * center panorama cover & add dominant background color * panorama cover for EditMangaInfo * Fix size on GlobalSearchCardRow * display mode for manual panorama cover * Fix LibraryFlagsTest
This commit is contained in:
parent
8d592c2541
commit
147a36a709
26 changed files with 571 additions and 103 deletions
|
|
@ -64,6 +64,8 @@ class UiPreferences(
|
|||
fun showHomeOnRelatedMangas() = preferenceStore.getBoolean("show_home_on_related_mangas", true)
|
||||
|
||||
fun readButtonPosition() = preferenceStore.getString("reading_button_position", FabPosition.End.toString())
|
||||
|
||||
fun usePanoramaCover() = preferenceStore.getBoolean("use_panorama_cover", false)
|
||||
// KMK <--
|
||||
|
||||
fun recommendsInOverflow() = preferenceStore.getBoolean("recommends_in_overflow", false)
|
||||
|
|
|
|||
|
|
@ -182,6 +182,21 @@ fun BrowseSourceContent(
|
|||
// KMK <--
|
||||
)
|
||||
}
|
||||
// KMK -->
|
||||
LibraryDisplayMode.ComfortableGridPanorama -> {
|
||||
BrowseSourceComfortableGrid(
|
||||
mangaList = mangaList,
|
||||
columns = columns,
|
||||
contentPadding = contentPadding,
|
||||
onMangaClick = onMangaClick,
|
||||
onMangaLongClick = onMangaLongClick,
|
||||
// KMK -->
|
||||
selection = selection,
|
||||
usePanoramaCover = true,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
LibraryDisplayMode.List -> {
|
||||
BrowseSourceList(
|
||||
mangaList = mangaList,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,20 @@ fun RelatedMangasContent(
|
|||
selection = selection,
|
||||
)
|
||||
}
|
||||
LibraryDisplayMode.ComfortableGridPanorama -> {
|
||||
RelatedMangasComfortableGrid(
|
||||
relatedMangas = relatedMangas,
|
||||
getManga = getMangaState,
|
||||
columns = columns,
|
||||
contentPadding = contentPadding,
|
||||
onMangaClick = onMangaClick,
|
||||
onMangaLongClick = onMangaLongClick,
|
||||
onKeywordClick = onKeywordClick,
|
||||
onKeywordLongClick = onKeywordLongClick,
|
||||
selection = selection,
|
||||
usePanoramaCover = true,
|
||||
)
|
||||
}
|
||||
LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> {
|
||||
RelatedMangasCompactGrid(
|
||||
relatedMangas = relatedMangas,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ fun BrowseSourceComfortableGrid(
|
|||
onMangaLongClick: (Manga) -> Unit,
|
||||
// KMK -->
|
||||
selection: List<Manga>,
|
||||
usePanoramaCover: Boolean? = null,
|
||||
// KMK <--
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
|
|
@ -66,6 +67,7 @@ fun BrowseSourceComfortableGrid(
|
|||
onLongClick = { onMangaLongClick(manga) },
|
||||
// KMK -->
|
||||
isSelected = selection.fastAny { selected -> selected.id == manga.id },
|
||||
usePanoramaCover = usePanoramaCover,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -88,6 +90,7 @@ internal fun BrowseSourceComfortableGridItem(
|
|||
onLongClick: () -> Unit = onClick,
|
||||
// KMK -->
|
||||
isSelected: Boolean = false,
|
||||
usePanoramaCover: Boolean?,
|
||||
// KMK <--
|
||||
) {
|
||||
MangaComfortableGridItem(
|
||||
|
|
@ -101,6 +104,8 @@ internal fun BrowseSourceComfortableGridItem(
|
|||
),
|
||||
// KMK -->
|
||||
isSelected = isSelected,
|
||||
panoramaCover = usePanoramaCover,
|
||||
fitToPanoramaCover = true,
|
||||
// KMK <--
|
||||
coverAlpha = if (manga.favorite) CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else 1f,
|
||||
coverBadgeStart = {
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ internal fun BrowseSourceCompactGridItem(
|
|||
),
|
||||
// KMK -->
|
||||
isSelected = isSelected,
|
||||
fitToPanoramaCover = true,
|
||||
// KMK <--
|
||||
coverAlpha = if (manga.favorite) CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else 1f,
|
||||
coverBadgeStart = {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
|
|
@ -18,7 +19,11 @@ import eu.kanade.tachiyomi.ui.browse.bulkSelectionButton
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.kmk.KMR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@Composable
|
||||
fun BrowseSourceSimpleToolbar(
|
||||
|
|
@ -67,6 +72,16 @@ fun BrowseSourceSimpleToolbar(
|
|||
selectingDisplayMode = false
|
||||
onDisplayModeChange(LibraryDisplayMode.ComfortableGrid)
|
||||
}
|
||||
val usePanoramaCover by lazy { Injekt.get<UiPreferences>().usePanoramaCover() }
|
||||
if (!usePanoramaCover.collectAsState().value) {
|
||||
RadioMenuItem(
|
||||
text = { Text(text = stringResource(KMR.strings.action_display_comfortable_grid_panorama)) },
|
||||
isChecked = displayMode == LibraryDisplayMode.ComfortableGridPanorama,
|
||||
) {
|
||||
selectingDisplayMode = false
|
||||
onDisplayModeChange(LibraryDisplayMode.ComfortableGridPanorama)
|
||||
}
|
||||
}
|
||||
RadioMenuItem(
|
||||
text = { Text(text = stringResource(MR.strings.action_display_grid)) },
|
||||
isChecked = displayMode == LibraryDisplayMode.CompactGrid,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.components.AppBarTitle
|
||||
|
|
@ -25,8 +26,12 @@ import exh.source.anyIs
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.kmk.KMR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.source.local.LocalSource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@Composable
|
||||
fun BrowseSourceToolbar(
|
||||
|
|
@ -138,6 +143,18 @@ fun BrowseSourceToolbar(
|
|||
selectingDisplayMode = false
|
||||
onDisplayModeChange(LibraryDisplayMode.ComfortableGrid)
|
||||
}
|
||||
// KMK -->
|
||||
val usePanoramaCover by lazy { Injekt.get<UiPreferences>().usePanoramaCover() }
|
||||
if (!usePanoramaCover.collectAsState().value) {
|
||||
RadioMenuItem(
|
||||
text = { Text(text = stringResource(KMR.strings.action_display_comfortable_grid_panorama)) },
|
||||
isChecked = displayMode == LibraryDisplayMode.ComfortableGridPanorama,
|
||||
) {
|
||||
selectingDisplayMode = false
|
||||
onDisplayModeChange(LibraryDisplayMode.ComfortableGridPanorama)
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
RadioMenuItem(
|
||||
text = { Text(text = stringResource(MR.strings.action_display_grid)) },
|
||||
isChecked = displayMode == LibraryDisplayMode.CompactGrid,
|
||||
|
|
|
|||
|
|
@ -12,17 +12,24 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastAny
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.library.components.CommonMangaItemDefaults
|
||||
import eu.kanade.presentation.library.components.MangaComfortableGridItem
|
||||
import eu.kanade.presentation.manga.components.RatioSwitchToPanorama
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaCover
|
||||
import tachiyomi.domain.manga.model.asMangaCover
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@Composable
|
||||
fun GlobalSearchCardRow(
|
||||
|
|
@ -68,9 +75,20 @@ internal fun MangaItem(
|
|||
onLongClick: () -> Unit,
|
||||
// KMK -->
|
||||
isSelected: Boolean = false,
|
||||
panoramaCover: Boolean? = null,
|
||||
// KMK <--
|
||||
) {
|
||||
Box(modifier = Modifier.width(96.dp)) {
|
||||
// KMK -->
|
||||
val usePanoramaCover = panoramaCover ?: Injekt.get<UiPreferences>().usePanoramaCover().collectAsState().value
|
||||
val coverRatio = remember { mutableFloatStateOf(1f) }
|
||||
// KMK <--
|
||||
Box(
|
||||
modifier = Modifier.width(
|
||||
// KMK -->
|
||||
if (usePanoramaCover && coverRatio.floatValue <= RatioSwitchToPanorama) 205.dp else 96.dp,
|
||||
// KMK <--
|
||||
),
|
||||
) {
|
||||
MangaComfortableGridItem(
|
||||
title = title,
|
||||
titleMaxLines = 3,
|
||||
|
|
@ -80,6 +98,9 @@ internal fun MangaItem(
|
|||
},
|
||||
// KMK -->
|
||||
isSelected = isSelected,
|
||||
coverRatio = coverRatio,
|
||||
panoramaCover = usePanoramaCover,
|
||||
fitToPanoramaCover = true,
|
||||
// KMK <--
|
||||
coverAlpha = if (isFavorite) CommonMangaItemDefaults.BrowseFavoriteCoverAlpha else 1f,
|
||||
onClick = onClick,
|
||||
|
|
|
|||
|
|
@ -13,8 +13,11 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -25,14 +28,21 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.manga.components.CoverPlaceholderColor
|
||||
import eu.kanade.presentation.manga.components.MangaCover
|
||||
import eu.kanade.presentation.manga.components.RatioSwitchToPanorama
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigratingManga
|
||||
import tachiyomi.core.common.util.lang.withIOContext
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.asMangaCover
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.Badge
|
||||
import tachiyomi.presentation.core.components.BadgeGroup
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@Composable
|
||||
fun MigrationItem(
|
||||
|
|
@ -41,7 +51,15 @@ fun MigrationItem(
|
|||
sourcesString: String,
|
||||
chapterInfo: MigratingManga.ChapterInfo,
|
||||
onClick: () -> Unit,
|
||||
// KMK -->
|
||||
coverRatio: MutableFloatState = remember { mutableFloatStateOf(1f) },
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val usePanoramaCover by Injekt.get<UiPreferences>().usePanoramaCover().collectAsState()
|
||||
val coverIsWide = coverRatio.floatValue <= RatioSwitchToPanorama
|
||||
val bgColor = manga.asMangaCover().dominantCoverColors?.first?.let { Color(it) }
|
||||
// KMK <--
|
||||
Column(
|
||||
modifier
|
||||
.widthIn(max = 150.dp)
|
||||
|
|
@ -53,13 +71,41 @@ fun MigrationItem(
|
|||
val context = LocalContext.current
|
||||
Box(
|
||||
Modifier.fillMaxWidth()
|
||||
// KMK -->
|
||||
.background(bgColor ?: CoverPlaceholderColor)
|
||||
// KMK <--
|
||||
.aspectRatio(MangaCover.Book.ratio),
|
||||
) {
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
data = manga,
|
||||
)
|
||||
// KMK -->
|
||||
if (usePanoramaCover && coverIsWide) {
|
||||
MangaCover.Panorama(
|
||||
modifier = Modifier
|
||||
// KMK -->
|
||||
.align(Alignment.Center)
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = manga,
|
||||
// KMK -->
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
data = manga,
|
||||
// KMK -->
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(bottomStart = 4.dp, bottomEnd = 4.dp))
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ fun RelatedMangasComfortableGrid(
|
|||
onKeywordClick: (String) -> Unit,
|
||||
onKeywordLongClick: (String) -> Unit,
|
||||
selection: List<Manga>,
|
||||
usePanoramaCover: Boolean? = null,
|
||||
) {
|
||||
FastScrollLazyVerticalGrid(
|
||||
columns = columns,
|
||||
|
|
@ -89,6 +90,7 @@ fun RelatedMangasComfortableGrid(
|
|||
onLongClick = { onMangaLongClick(manga) },
|
||||
isSelected = selection.fastAny { selected -> selected.id == manga.id },
|
||||
metadata = null,
|
||||
usePanoramaCover = usePanoramaCover,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -23,7 +26,9 @@ 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.ui.UiPreferences
|
||||
import eu.kanade.presentation.manga.components.MangaCover
|
||||
import eu.kanade.presentation.manga.components.RatioSwitchToPanorama
|
||||
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
|
||||
import eu.kanade.presentation.util.formatChapterNumber
|
||||
import eu.kanade.tachiyomi.util.lang.toTimestampString
|
||||
|
|
@ -31,6 +36,9 @@ import tachiyomi.domain.history.model.HistoryWithRelations
|
|||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
private val HistoryItemHeight = 96.dp
|
||||
|
||||
|
|
@ -41,6 +49,9 @@ fun HistoryItem(
|
|||
onClickResume: () -> Unit,
|
||||
onClickDelete: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
// KMK -->
|
||||
coverRatio: MutableFloatState = remember { mutableFloatStateOf(1f) },
|
||||
// KMK <--
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
|
|
@ -51,19 +62,42 @@ fun HistoryItem(
|
|||
) {
|
||||
// KMK -->
|
||||
val mangaCover = history.coverData
|
||||
val usePanoramaCover by Injekt.get<UiPreferences>().usePanoramaCover().collectAsState()
|
||||
val coverIsWide = coverRatio.floatValue <= RatioSwitchToPanorama
|
||||
val bgColor = mangaCover.dominantCoverColors?.first?.let { Color(it) }
|
||||
val onBgColor = mangaCover.dominantCoverColors?.second
|
||||
// KMK <--
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
data = mangaCover,
|
||||
onClick = onClickCover,
|
||||
// KMK -->
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
size = MangaCover.Size.Medium,
|
||||
if (usePanoramaCover && coverIsWide) {
|
||||
MangaCover.Panorama(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
data = mangaCover,
|
||||
onClick = onClickCover,
|
||||
// KMK -->
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
size = MangaCover.Size.Medium,
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
)
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
data = mangaCover,
|
||||
onClick = onClickCover,
|
||||
// KMK -->
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
size = MangaCover.Size.Medium,
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.compose.ui.platform.LocalConfiguration
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.TabbedDialog
|
||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
|
@ -45,6 +46,8 @@ import tachiyomi.presentation.core.components.SortItem
|
|||
import tachiyomi.presentation.core.components.TriStateItem
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@Composable
|
||||
fun LibrarySettingsDialog(
|
||||
|
|
@ -255,8 +258,11 @@ private fun ColumnScope.SortPage(
|
|||
private val displayModes = listOf(
|
||||
MR.strings.action_display_grid to LibraryDisplayMode.CompactGrid,
|
||||
MR.strings.action_display_comfortable_grid to LibraryDisplayMode.ComfortableGrid,
|
||||
MR.strings.action_display_cover_only_grid to LibraryDisplayMode.CoverOnlyGrid,
|
||||
MR.strings.action_display_list to LibraryDisplayMode.List,
|
||||
MR.strings.action_display_cover_only_grid to LibraryDisplayMode.CoverOnlyGrid,
|
||||
// KMK -->
|
||||
KMR.strings.action_display_comfortable_grid_panorama to LibraryDisplayMode.ComfortableGridPanorama,
|
||||
// KMK <--
|
||||
)
|
||||
|
||||
@Suppress("UnusedReceiverParameter")
|
||||
|
|
@ -265,14 +271,22 @@ private fun ColumnScope.DisplayPage(
|
|||
screenModel: LibrarySettingsScreenModel,
|
||||
) {
|
||||
val displayMode by screenModel.libraryPreferences.displayMode().collectAsState()
|
||||
// KMK -->
|
||||
val usePanoramaCover by lazy { Injekt.get<UiPreferences>().usePanoramaCover() }
|
||||
// KMK <--
|
||||
SettingsChipRow(MR.strings.action_display_mode) {
|
||||
displayModes.map { (titleRes, mode) ->
|
||||
FilterChip(
|
||||
selected = displayMode == mode,
|
||||
onClick = { screenModel.setDisplayMode(mode) },
|
||||
label = { Text(stringResource(titleRes)) },
|
||||
)
|
||||
}
|
||||
displayModes
|
||||
.filterNot {
|
||||
it.second == LibraryDisplayMode.ComfortableGridPanorama &&
|
||||
usePanoramaCover.collectAsState().value
|
||||
}
|
||||
.map { (titleRes, mode) ->
|
||||
FilterChip(
|
||||
selected = displayMode == mode,
|
||||
onClick = { screenModel.setDisplayMode(mode) },
|
||||
label = { Text(stringResource(titleRes)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (displayMode != LibraryDisplayMode.List) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -32,18 +36,24 @@ import androidx.compose.ui.draw.drawBehind
|
|||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shadow
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.manga.components.MangaCover
|
||||
import eu.kanade.presentation.manga.components.MangaCoverHide
|
||||
import eu.kanade.presentation.manga.components.RatioSwitchToPanorama
|
||||
import exh.debug.DebugToggles
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.BadgeGroup
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.selectedBackground
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import tachiyomi.domain.manga.model.MangaCover as MangaCoverModel
|
||||
|
||||
object CommonMangaItemDefaults {
|
||||
|
|
@ -82,9 +92,13 @@ fun MangaCompactGridItem(
|
|||
coverBadgeEnd: @Composable (RowScope.() -> Unit)? = null,
|
||||
// KMK -->
|
||||
libraryColored: Boolean = true,
|
||||
coverRatio: MutableFloatState = remember { mutableFloatStateOf(1f) },
|
||||
fitToPanoramaCover: Boolean = false,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val usePanoramaCover by Injekt.get<UiPreferences>().usePanoramaCover().collectAsState()
|
||||
val coverIsWide = coverRatio.floatValue <= RatioSwitchToPanorama
|
||||
val bgColor = coverData.dominantCoverColors?.first?.let { Color(it) }.takeIf { libraryColored }
|
||||
val onBgColor = coverData.dominantCoverColors?.second.takeIf { libraryColored }
|
||||
// KMK <--
|
||||
|
|
@ -104,22 +118,58 @@ fun MangaCompactGridItem(
|
|||
tint = onBgColor,
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
if (fitToPanoramaCover && usePanoramaCover && coverIsWide) {
|
||||
MangaCover.Panorama(
|
||||
modifier = Modifier
|
||||
// KMK -->
|
||||
// .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha)
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = coverData,
|
||||
// KMK -->
|
||||
// .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha)
|
||||
alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
|
||||
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
|
||||
tint = onBgColor,
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = coverData,
|
||||
// KMK -->
|
||||
alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
|
||||
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
|
||||
tint = onBgColor,
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
)
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
// KMK -->
|
||||
// .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha)
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = coverData,
|
||||
// KMK -->
|
||||
alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
|
||||
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
|
||||
tint = onBgColor,
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
scale = if (usePanoramaCover && coverIsWide) {
|
||||
ContentScale.Fit
|
||||
} else {
|
||||
ContentScale.Crop
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
// KMK -->
|
||||
ratio = if (fitToPanoramaCover && usePanoramaCover && coverIsWide) {
|
||||
MangaCover.Panorama.ratio
|
||||
} else {
|
||||
MangaCover.Book.ratio
|
||||
},
|
||||
// KMK <--
|
||||
badgesStart = coverBadgeStart,
|
||||
badgesEnd = coverBadgeEnd,
|
||||
content = {
|
||||
|
|
@ -208,14 +258,19 @@ fun MangaComfortableGridItem(
|
|||
isSelected: Boolean = false,
|
||||
titleMaxLines: Int = 2,
|
||||
coverAlpha: Float = 1f,
|
||||
coverBadgeStart: (@Composable RowScope.() -> Unit)? = null,
|
||||
coverBadgeEnd: (@Composable RowScope.() -> Unit)? = null,
|
||||
coverBadgeStart: @Composable (RowScope.() -> Unit)? = null,
|
||||
coverBadgeEnd: @Composable (RowScope.() -> Unit)? = null,
|
||||
onClickContinueReading: (() -> Unit)? = null,
|
||||
// KMK -->
|
||||
libraryColored: Boolean = true,
|
||||
coverRatio: MutableFloatState = remember { mutableFloatStateOf(1f) },
|
||||
panoramaCover: Boolean?,
|
||||
fitToPanoramaCover: Boolean = false,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val usePanoramaCover = panoramaCover ?: Injekt.get<UiPreferences>().usePanoramaCover().collectAsState().value
|
||||
val coverIsWide = coverRatio.floatValue <= RatioSwitchToPanorama
|
||||
val bgColor = coverData.dominantCoverColors?.first?.let { Color(it) }.takeIf { libraryColored }
|
||||
val onBgColor = coverData.dominantCoverColors?.second.takeIf { libraryColored }
|
||||
// KMK <--
|
||||
|
|
@ -236,22 +291,58 @@ fun MangaComfortableGridItem(
|
|||
tint = onBgColor,
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
if (fitToPanoramaCover && usePanoramaCover && coverIsWide) {
|
||||
MangaCover.Panorama(
|
||||
modifier = Modifier
|
||||
// KMK -->
|
||||
// .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha)
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = coverData,
|
||||
// KMK -->
|
||||
// .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha)
|
||||
alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
|
||||
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
|
||||
tint = onBgColor,
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = coverData,
|
||||
// KMK -->
|
||||
alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
|
||||
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
|
||||
tint = onBgColor,
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
)
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
// KMK -->
|
||||
// .alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha)
|
||||
// KMK <--
|
||||
.fillMaxWidth(),
|
||||
data = coverData,
|
||||
// KMK -->
|
||||
alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
|
||||
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
|
||||
tint = onBgColor,
|
||||
onCoverLoaded = { _, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
scale = if (usePanoramaCover && coverIsWide) {
|
||||
ContentScale.Fit
|
||||
} else {
|
||||
ContentScale.Crop
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
// KMK -->
|
||||
ratio = if (fitToPanoramaCover && usePanoramaCover && coverIsWide) {
|
||||
MangaCover.Panorama.ratio
|
||||
} else {
|
||||
MangaCover.Book.ratio
|
||||
},
|
||||
// KMK <--
|
||||
badgesStart = coverBadgeStart,
|
||||
badgesEnd = coverBadgeEnd,
|
||||
content = {
|
||||
|
|
@ -285,6 +376,9 @@ fun MangaComfortableGridItem(
|
|||
private fun MangaGridCover(
|
||||
modifier: Modifier = Modifier,
|
||||
cover: @Composable BoxScope.() -> Unit = {},
|
||||
// KMK -->
|
||||
ratio: Float = MangaCover.Book.ratio,
|
||||
// KMK <--
|
||||
badgesStart: (@Composable RowScope.() -> Unit)? = null,
|
||||
badgesEnd: (@Composable RowScope.() -> Unit)? = null,
|
||||
content: @Composable (BoxScope.() -> Unit)? = null,
|
||||
|
|
@ -292,7 +386,7 @@ private fun MangaGridCover(
|
|||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(MangaCover.Book.ratio),
|
||||
.aspectRatio(ratio),
|
||||
) {
|
||||
cover()
|
||||
content?.invoke(this)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ internal fun LibraryComfortableGrid(
|
|||
onClickContinueReading: ((LibraryManga) -> Unit)?,
|
||||
searchQuery: String?,
|
||||
onGlobalSearchClicked: () -> Unit,
|
||||
// KMK -->
|
||||
usePanoramaCover: Boolean? = null,
|
||||
// KMK <--
|
||||
) {
|
||||
LazyLibraryGrid(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
@ -67,6 +70,9 @@ internal fun LibraryComfortableGrid(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
// KMK -->
|
||||
panoramaCover = usePanoramaCover,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,22 @@ fun LibraryPager(
|
|||
onGlobalSearchClicked = onGlobalSearchClicked,
|
||||
)
|
||||
}
|
||||
// KMK -->
|
||||
LibraryDisplayMode.ComfortableGridPanorama -> {
|
||||
LibraryComfortableGrid(
|
||||
items = library,
|
||||
columns = columns,
|
||||
contentPadding = contentPadding,
|
||||
selection = selectedManga,
|
||||
onClick = onClickManga,
|
||||
onLongClick = onLongClickManga,
|
||||
onClickContinueReading = onClickContinueReading,
|
||||
searchQuery = searchQuery,
|
||||
onGlobalSearchClicked = onGlobalSearchClicked,
|
||||
usePanoramaCover = true,
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import androidx.compose.material3.SnackbarHost
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -207,6 +208,7 @@ fun MangaScreen(
|
|||
librarySearch: (query: String) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (MangaCover) -> Unit,
|
||||
coverRatio: MutableFloatState,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
hazeState: HazeState,
|
||||
// KMK <--
|
||||
|
|
@ -271,6 +273,7 @@ fun MangaScreen(
|
|||
librarySearch = librarySearch,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
coverRatio = coverRatio,
|
||||
onPaletteScreenClick = onPaletteScreenClick,
|
||||
hazeState = hazeState,
|
||||
// KMK <--
|
||||
|
|
@ -328,6 +331,7 @@ fun MangaScreen(
|
|||
librarySearch = librarySearch,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
coverRatio = coverRatio,
|
||||
onPaletteScreenClick = onPaletteScreenClick,
|
||||
hazeState = hazeState,
|
||||
// KMK <--
|
||||
|
|
@ -402,6 +406,7 @@ private fun MangaScreenSmallImpl(
|
|||
librarySearch: (query: String) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (MangaCover) -> Unit,
|
||||
coverRatio: MutableFloatState,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
hazeState: HazeState,
|
||||
// KMK <--
|
||||
|
|
@ -620,6 +625,7 @@ private fun MangaScreenSmallImpl(
|
|||
librarySearch = librarySearch,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
coverRatio = coverRatio,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -860,6 +866,7 @@ private fun MangaScreenLargeImpl(
|
|||
librarySearch: (query: String) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (MangaCover) -> Unit,
|
||||
coverRatio: MutableFloatState,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
hazeState: HazeState,
|
||||
// KMK <--
|
||||
|
|
@ -1070,6 +1077,7 @@ private fun MangaScreenLargeImpl(
|
|||
librarySearch = librarySearch,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
coverRatio = coverRatio,
|
||||
// KMK <--
|
||||
)
|
||||
MangaActionRow(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import androidx.compose.ui.layout.ContentScale
|
|||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.AsyncImagePainter
|
||||
import coil3.compose.SubcomposeAsyncImage
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
|
|
@ -35,6 +36,10 @@ import tachiyomi.domain.manga.model.MangaCover as DomainMangaCover
|
|||
enum class MangaCover(val ratio: Float) {
|
||||
Square(1f / 1f),
|
||||
Book(2f / 3f),
|
||||
|
||||
// KMK -->
|
||||
Panorama(3f / 2f),
|
||||
// KMK <--
|
||||
;
|
||||
|
||||
enum class Size {
|
||||
|
|
@ -54,9 +59,10 @@ enum class MangaCover(val ratio: Float) {
|
|||
alpha: Float = 1f,
|
||||
bgColor: Color? = null,
|
||||
@ColorInt tint: Int? = null,
|
||||
/** Perform action when cover loaded, specifically generating color map */
|
||||
onCoverLoaded: ((DomainMangaCover) -> Unit)? = null,
|
||||
/** Perform action when cover loaded, specifically generating color map. If the cover doesn't update, it won't be called */
|
||||
onCoverLoaded: ((DomainMangaCover, result: AsyncImagePainter.State.Success) -> Unit)? = null,
|
||||
size: Size = Size.Normal,
|
||||
scale: ContentScale = ContentScale.Crop,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
|
|
@ -128,19 +134,19 @@ enum class MangaCover(val ratio: Float) {
|
|||
)
|
||||
}
|
||||
},
|
||||
onSuccess = {
|
||||
onSuccess = { result ->
|
||||
succeed = true
|
||||
if (onCoverLoaded != null) {
|
||||
when (data) {
|
||||
is Manga -> onCoverLoaded(data.asMangaCover())
|
||||
is DomainMangaCover -> onCoverLoaded(data)
|
||||
is Manga -> onCoverLoaded(data.asMangaCover(), result)
|
||||
is DomainMangaCover -> onCoverLoaded(data, result)
|
||||
}
|
||||
}
|
||||
},
|
||||
// KMK <--
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifierColored,
|
||||
contentScale = ContentScale.Crop,
|
||||
contentScale = scale,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -194,5 +200,7 @@ enum class MangaCoverHide(private val ratio: Float) {
|
|||
}
|
||||
}
|
||||
|
||||
internal val RatioSwitchToPanorama = 0.75f
|
||||
|
||||
internal val CoverPlaceholderColor = Color(0x1F888888)
|
||||
internal val CoverPlaceholderOnBgColor = Color(0x8F888888)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import androidx.compose.material3.ProvideTextStyle
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -96,6 +97,7 @@ import tachiyomi.presentation.core.components.material.padding
|
|||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
|
@ -120,8 +122,12 @@ fun MangaInfoBox(
|
|||
librarySearch: (query: String) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (DomainMangaCover) -> Unit,
|
||||
coverRatio: MutableFloatState,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val usePanoramaCover by Injekt.get<UiPreferences>().usePanoramaCover().collectAsState()
|
||||
// KMK <--
|
||||
Box(modifier = modifier) {
|
||||
// Backdrop
|
||||
val backdropGradientColors = listOf(
|
||||
|
|
@ -135,6 +141,12 @@ fun MangaInfoBox(
|
|||
.build(),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
// KMK -->
|
||||
onSuccess = { result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
},
|
||||
// KMK <--
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.drawWithContent {
|
||||
|
|
@ -170,6 +182,8 @@ fun MangaInfoBox(
|
|||
librarySearch = librarySearch,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
coverRatio = coverRatio,
|
||||
usePanoramaCover = usePanoramaCover,
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
|
|
@ -184,6 +198,8 @@ fun MangaInfoBox(
|
|||
librarySearch = librarySearch,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
coverRatio = coverRatio,
|
||||
usePanoramaCover = usePanoramaCover,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -458,6 +474,8 @@ private fun MangaAndSourceTitlesLarge(
|
|||
librarySearch: (query: String) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (DomainMangaCover) -> Unit,
|
||||
coverRatio: MutableFloatState,
|
||||
usePanoramaCover: Boolean = false,
|
||||
// KMK <--
|
||||
) {
|
||||
Column(
|
||||
|
|
@ -466,18 +484,43 @@ private fun MangaAndSourceTitlesLarge(
|
|||
.padding(start = 16.dp, top = appBarPadding + 16.dp, end = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxWidth(0.65f),
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
// KMK -->
|
||||
onCoverLoaded = { mangaCover -> onCoverLoaded(mangaCover) },
|
||||
// KMK -->
|
||||
if (usePanoramaCover && coverRatio.floatValue <= RatioSwitchToPanorama) {
|
||||
MangaCover.Panorama(
|
||||
modifier = Modifier.fillMaxWidth(0.65f),
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
// KMK -->
|
||||
onCoverLoaded = { mangaCover, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
onCoverLoaded(mangaCover)
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
)
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxWidth(0.65f),
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
// KMK -->
|
||||
onCoverLoaded = { mangaCover, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
onCoverLoaded(mangaCover)
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
MangaContentInfo(
|
||||
title = manga.title,
|
||||
|
|
@ -508,6 +551,8 @@ private fun MangaAndSourceTitlesSmall(
|
|||
librarySearch: (query: String) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (DomainMangaCover) -> Unit,
|
||||
coverRatio: MutableFloatState,
|
||||
usePanoramaCover: Boolean = false,
|
||||
// KMK <--
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -517,20 +562,51 @@ private fun MangaAndSourceTitlesSmall(
|
|||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
.sizeIn(maxWidth = 100.dp)
|
||||
.align(Alignment.Top),
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
// KMK -->
|
||||
onCoverLoaded = { mangaCover -> onCoverLoaded(mangaCover) },
|
||||
// KMK -->
|
||||
if (usePanoramaCover && coverRatio.floatValue <= RatioSwitchToPanorama) {
|
||||
MangaCover.Panorama(
|
||||
modifier = Modifier
|
||||
.sizeIn(maxHeight = 100.dp)
|
||||
// KMK -->
|
||||
.align(Alignment.CenterVertically),
|
||||
// KMK <--
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
// KMK -->
|
||||
onCoverLoaded = { mangaCover, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
onCoverLoaded(mangaCover)
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
// KMK <--
|
||||
)
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
.sizeIn(maxWidth = 100.dp)
|
||||
// KMK -->
|
||||
.align(Alignment.CenterVertically),
|
||||
// KMK <--
|
||||
data = ImageRequest.Builder(LocalContext.current)
|
||||
.data(manga)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
// KMK -->
|
||||
onCoverLoaded = { mangaCover, result ->
|
||||
val image = result.result.image
|
||||
coverRatio.floatValue = image.height.toFloat() / image.width
|
||||
onCoverLoaded(mangaCover)
|
||||
},
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -272,6 +272,13 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||
return Preference.PreferenceGroup(
|
||||
stringResource(SYMR.strings.pref_category_fork),
|
||||
preferenceItems = persistentListOf(
|
||||
// KMK -->
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = uiPreferences.usePanoramaCover(),
|
||||
title = stringResource(KMR.strings.pref_use_panorama_cover),
|
||||
subtitle = stringResource(KMR.strings.pref_use_panorama_cover_summary),
|
||||
),
|
||||
// KMK <--
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = uiPreferences.expandFilters(),
|
||||
title = stringResource(SYMR.strings.toggle_expand_search_filters),
|
||||
|
|
|
|||
|
|
@ -160,5 +160,5 @@ object MangaCoverMetadata {
|
|||
preferences.coverColors().set(mapColorCopy.map { "${it.key}|${it.value.first}|${it.value.second}" }.toSet())
|
||||
}
|
||||
|
||||
const val SUB_SAMPLE = 4
|
||||
private const val SUB_SAMPLE = 4
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -37,6 +38,7 @@ import coil3.transform.RoundedCornersTransformation
|
|||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.presentation.manga.components.RatioSwitchToPanorama
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
|
|
@ -62,6 +64,9 @@ import tachiyomi.source.local.isLocal
|
|||
@Composable
|
||||
fun EditMangaDialog(
|
||||
manga: Manga,
|
||||
// KMK -->
|
||||
coverRatio: MutableFloatState,
|
||||
// KMK <--
|
||||
onDismissRequest: () -> Unit,
|
||||
onPositiveClick: (
|
||||
title: String?,
|
||||
|
|
@ -145,6 +150,7 @@ fun EditMangaDialog(
|
|||
scope,
|
||||
// KMK -->
|
||||
colors,
|
||||
coverRatio = coverRatio,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -178,9 +184,16 @@ private fun onViewCreated(
|
|||
scope: CoroutineScope,
|
||||
// KMK -->
|
||||
colors: EditMangaDialogColors,
|
||||
coverRatio: MutableFloatState,
|
||||
// KMK <--
|
||||
) {
|
||||
loadCover(manga, binding)
|
||||
loadCover(
|
||||
manga,
|
||||
binding,
|
||||
// KMK -->
|
||||
coverRatio,
|
||||
// KMK <--
|
||||
)
|
||||
|
||||
// KMK -->
|
||||
// val statusAdapter: ArrayAdapter<String> = ArrayAdapter(
|
||||
|
|
@ -344,9 +357,25 @@ private fun resetTags(
|
|||
}
|
||||
}
|
||||
|
||||
private fun loadCover(manga: Manga, binding: EditMangaDialogBinding) {
|
||||
binding.mangaCover.load(manga) {
|
||||
transformations(RoundedCornersTransformation(4.dpToPx.toFloat()))
|
||||
private fun loadCover(
|
||||
manga: Manga,
|
||||
binding: EditMangaDialogBinding,
|
||||
// KMK -->
|
||||
coverRatio: MutableFloatState,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
if (coverRatio.floatValue <= RatioSwitchToPanorama) {
|
||||
binding.mangaCover.visibility = View.GONE
|
||||
binding.mangaCoverPanorama.visibility = View.VISIBLE
|
||||
binding.mangaCoverPanorama.load(manga) {
|
||||
transformations(RoundedCornersTransformation(4.dpToPx.toFloat()))
|
||||
}
|
||||
} else {
|
||||
// KMK <--
|
||||
binding.mangaCover.load(manga) {
|
||||
transformations(RoundedCornersTransformation(4.dpToPx.toFloat()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
|
@ -262,6 +263,7 @@ class MangaScreen(
|
|||
// SY <--
|
||||
|
||||
// KMK -->
|
||||
val coverRatio = remember { mutableFloatStateOf(1f) }
|
||||
val hazeState = remember { HazeState() }
|
||||
// KMK <--
|
||||
|
||||
|
|
@ -402,6 +404,7 @@ class MangaScreen(
|
|||
onCoverLoaded = {
|
||||
if (screenModel.themeCoverBased || successState.manga.favorite) screenModel.setPaletteColor(it)
|
||||
},
|
||||
coverRatio = coverRatio,
|
||||
onPaletteScreenClick = { navigator.push(PaletteScreen(successState.seedColor?.toArgb())) },
|
||||
hazeState = hazeState,
|
||||
// KMK <--
|
||||
|
|
@ -537,6 +540,9 @@ class MangaScreen(
|
|||
is MangaScreenModel.Dialog.EditMangaInfo -> {
|
||||
EditMangaDialog(
|
||||
manga = dialog.manga,
|
||||
// KMK -->
|
||||
coverRatio = coverRatio,
|
||||
// KMK <--
|
||||
onDismissRequest = screenModel::dismissDialog,
|
||||
onPositiveClick = screenModel::updateMangaInfo,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,17 @@
|
|||
android:background="@drawable/rounded_rectangle"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
<!-- KMK -> -->
|
||||
<ImageView
|
||||
android:id="@+id/manga_cover_panorama"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="100dp"
|
||||
android:visibility="gone"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
<!-- KMK <- -->
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
|
@ -134,25 +145,32 @@
|
|||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/reset_tags"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/reset_tags"
|
||||
android:textAllCaps="false" />
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/reset_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/reset_info"
|
||||
android:textAllCaps="false" />
|
||||
<Button
|
||||
android:id="@+id/reset_tags"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/reset_tags"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/reset_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/reset_info"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ sealed interface LibraryDisplayMode {
|
|||
|
||||
data object CompactGrid : LibraryDisplayMode
|
||||
data object ComfortableGrid : LibraryDisplayMode
|
||||
|
||||
// KMK -->
|
||||
data object ComfortableGridPanorama : LibraryDisplayMode
|
||||
|
||||
// KMK <--
|
||||
data object List : LibraryDisplayMode
|
||||
data object CoverOnlyGrid : LibraryDisplayMode
|
||||
|
||||
|
|
@ -18,12 +23,15 @@ sealed interface LibraryDisplayMode {
|
|||
}
|
||||
|
||||
companion object {
|
||||
val values by lazy { setOf(CompactGrid, ComfortableGrid, List, CoverOnlyGrid) }
|
||||
val values by lazy { setOf(CompactGrid, ComfortableGrid, ComfortableGridPanorama, List, CoverOnlyGrid) }
|
||||
val default = CompactGrid
|
||||
|
||||
fun deserialize(serialized: String): LibraryDisplayMode {
|
||||
return when (serialized) {
|
||||
"COMFORTABLE_GRID" -> ComfortableGrid
|
||||
// KMK -->
|
||||
"COMFORTABLE_GRID_PANORAMA" -> ComfortableGridPanorama
|
||||
// KMK <--
|
||||
"COMPACT_GRID" -> CompactGrid
|
||||
"COVER_ONLY_GRID" -> CoverOnlyGrid
|
||||
"LIST" -> List
|
||||
|
|
@ -35,6 +43,9 @@ sealed interface LibraryDisplayMode {
|
|||
fun serialize(): String {
|
||||
return when (this) {
|
||||
ComfortableGrid -> "COMFORTABLE_GRID"
|
||||
// KMK -->
|
||||
ComfortableGridPanorama -> "COMFORTABLE_GRID_PANORAMA"
|
||||
// KMK <--
|
||||
CompactGrid -> "COMPACT_GRID"
|
||||
CoverOnlyGrid -> "COVER_ONLY_GRID"
|
||||
List -> "LIST"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class LibraryFlagsTest {
|
|||
|
||||
@Test
|
||||
fun `Check the amount of flags`() {
|
||||
LibraryDisplayMode.values.size shouldBe 4
|
||||
LibraryDisplayMode.values.size shouldBe 5
|
||||
LibrarySort.types.size shouldBe 10
|
||||
LibrarySort.directions.size shouldBe 2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
<string name="pref_theme_cover_based_style_monochrome">Monochrome</string>
|
||||
<string name="pref_theme_cover_based_style_fidelity">Fidelity</string>
|
||||
<string name="pref_theme_cover_based_style_content">Content</string>
|
||||
<string name="pref_use_panorama_cover">Panorama Cover</string>
|
||||
<string name="pref_use_panorama_cover_summary">Show cover in landscape mode if it\'s a wide image</string>
|
||||
<string name="action_display_comfortable_grid_panorama">Panorama comfortable grid</string>
|
||||
<string name="pref_expand_related_mangas">Expand Suggestions</string>
|
||||
<string name="pref_expand_related_mangas_summary">If turned off, Suggestions won\'t automatically load & show expanded</string>
|
||||
<string name="put_related_mangas_in_overflow">Suggestions in overflow</string>
|
||||
|
|
|
|||
Loading…
Reference in a new issue