Improve Theme cover based (#81)
* Support Pure dark mode * Tag using elevated style (non pure-dark-mode) and more vibrant outline color (pure-dark-mode) * More color for various icons * Color theme for Metadata screen * Always animated color change * Always/Only use dominant color for library/update/upcoming cover's background * Don't always generate color each time cover loaded (library/browse), only update color when new cover changed on detail page * Fix the spinner background in Edit Manga Info * Improve manga's backdrop color Detail: * Change Cover's color & ratio preference key to AppState * using ElevatedSuggestionChip with color * more icon color * color theme for MetadataViewScreen * enable animation by default * Fix: can't turn off theme cover based * Won't check pref for theme enabled everytime, instead always generate cover's color to run faster later * Skip generate cover's vibrant color for browsing mangas if already generated, also won't even trying to read ratio for favorite mangas * Only generate new seed color when cover loaded in detail page * only use dominantColor for cover when cover is unable to load * Don't use elevatedSuggestionChip for darkmode and change border color * EditMangaInfo: Set Spinner's selected item's background color to transparent * update chip color * Colors Palette screen * Support Amoled Dark Mode by upgrading Material-Kolor to 1.7.0 * improve manga's backdrop color * only generate color while browsing if option is enabled, aslo fixed the case won't update dominant color if cover changed * always using theme animation * update translation
This commit is contained in:
parent
95fef0d019
commit
753285275f
65 changed files with 558 additions and 275 deletions
|
|
@ -25,12 +25,10 @@ class UiPreferences(
|
|||
|
||||
fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
|
||||
|
||||
fun detailsPageThemeCoverBased() = preferenceStore.getBoolean("pref_details_page_theme_cover_based_key", true)
|
||||
fun themeCoverBased() = preferenceStore.getBoolean("pref_theme_cover_based_key", true)
|
||||
|
||||
fun themeCoverBasedStyle() = preferenceStore.getEnum("pref_theme_cover_based_style_key", PaletteStyle.Vibrant)
|
||||
|
||||
fun themeCoverBasedAnimate() = preferenceStore.getBoolean("pref_theme_cover_based_animate_key", false)
|
||||
|
||||
fun relativeTime() = preferenceStore.getBoolean("relative_time_v2", true)
|
||||
|
||||
fun dateFormat() = preferenceStore.getString("app_date_format", "")
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
|
|
@ -48,10 +49,15 @@ fun HistoryItem(
|
|||
.padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val mangaCover = history.coverData
|
||||
val bgColor = mangaCover.dominantCoverColors?.first?.let { Color(it) }
|
||||
val onBgColor = mangaCover.dominantCoverColors?.second
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
data = history.coverData,
|
||||
data = mangaCover,
|
||||
onClick = onClickCover,
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -27,18 +27,15 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
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.graphics.toArgb
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.presentation.manga.components.CoverPlaceholderColor
|
||||
import eu.kanade.presentation.manga.components.MangaCover
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.BadgeGroup
|
||||
|
|
@ -74,7 +71,10 @@ fun MangaCompactGridItem(
|
|||
coverAlpha: Float = 1f,
|
||||
coverBadgeStart: @Composable (RowScope.() -> Unit)? = null,
|
||||
coverBadgeEnd: @Composable (RowScope.() -> Unit)? = null,
|
||||
libraryColored: Boolean? = null,
|
||||
) {
|
||||
val bgColor = libraryColored?.let { coverData.dominantCoverColors?.first?.let { Color(it) } }
|
||||
val onBgColor = libraryColored?.let { coverData.dominantCoverColors?.second }
|
||||
GridItemSelectable(
|
||||
isSelected = isSelected,
|
||||
onClick = onClick,
|
||||
|
|
@ -84,15 +84,11 @@ fun MangaCompactGridItem(
|
|||
cover = {
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = DomainMangaCover.coverColorMap[coverData.mangaId]?.first?.let { Color(it) }
|
||||
?: MaterialTheme.colorScheme.surface
|
||||
),
|
||||
.fillMaxWidth(),
|
||||
alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha,
|
||||
data = coverData,
|
||||
tint = DomainMangaCover.coverColorMap[coverData.mangaId]?.second
|
||||
?: MaterialTheme.colorScheme.onSurface.toArgb(),
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
)
|
||||
},
|
||||
badgesStart = coverBadgeStart,
|
||||
|
|
@ -182,7 +178,10 @@ fun MangaComfortableGridItem(
|
|||
coverBadgeStart: (@Composable RowScope.() -> Unit)? = null,
|
||||
coverBadgeEnd: (@Composable RowScope.() -> Unit)? = null,
|
||||
onClickContinueReading: (() -> Unit)? = null,
|
||||
libraryColored: Boolean? = null,
|
||||
) {
|
||||
val bgColor = libraryColored?.let { coverData.dominantCoverColors?.first?.let { Color(it) } }
|
||||
val onBgColor = libraryColored?.let { coverData.dominantCoverColors?.second }
|
||||
GridItemSelectable(
|
||||
isSelected = isSelected,
|
||||
onClick = onClick,
|
||||
|
|
@ -193,15 +192,11 @@ fun MangaComfortableGridItem(
|
|||
cover = {
|
||||
MangaCover.Book(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = DomainMangaCover.coverColorMap[coverData.mangaId]?.first?.let { Color(it) }
|
||||
?: MaterialTheme.colorScheme.surface
|
||||
),
|
||||
.fillMaxWidth(),
|
||||
alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha,
|
||||
data = coverData,
|
||||
tint = DomainMangaCover.coverColorMap[coverData.mangaId]?.second
|
||||
?: MaterialTheme.colorScheme.onSurface.toArgb(),
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
)
|
||||
},
|
||||
badgesStart = coverBadgeStart,
|
||||
|
|
@ -339,7 +334,10 @@ fun MangaListItem(
|
|||
isSelected: Boolean = false,
|
||||
coverAlpha: Float = 1f,
|
||||
onClickContinueReading: (() -> Unit)? = null,
|
||||
libraryColored: Boolean? = null,
|
||||
) {
|
||||
val bgColor = libraryColored?.let { coverData.dominantCoverColors?.first?.let { Color(it) } }
|
||||
val onBgColor = libraryColored?.let { coverData.dominantCoverColors?.second }
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.selectedBackground(isSelected)
|
||||
|
|
@ -353,15 +351,11 @@ fun MangaListItem(
|
|||
) {
|
||||
MangaCover.Square(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.background(
|
||||
color = DomainMangaCover.coverColorMap[coverData.mangaId]?.first?.let { Color(it) }
|
||||
?: MaterialTheme.colorScheme.surface
|
||||
),
|
||||
.fillMaxHeight(),
|
||||
alpha = coverAlpha,
|
||||
data = coverData,
|
||||
tint = DomainMangaCover.coverColorMap[coverData.mangaId]?.second
|
||||
?: MaterialTheme.colorScheme.onSurface.toArgb(),
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ internal fun LibraryComfortableGrid(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
libraryColored = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ internal fun LibraryCompactGrid(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
libraryColored = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ internal fun LibraryList(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
libraryColored = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ import tachiyomi.domain.chapter.model.Chapter
|
|||
import tachiyomi.domain.chapter.service.missingChaptersCount
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaCover
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.kmk.KMR
|
||||
|
|
@ -183,6 +184,8 @@ fun MangaScreen(
|
|||
onRelatedMangaClick: (Manga) -> Unit,
|
||||
onRelatedMangaLongClick: (Manga) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (MangaCover) -> Unit,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -243,6 +246,8 @@ fun MangaScreen(
|
|||
onRelatedMangaClick = onRelatedMangaClick,
|
||||
onRelatedMangaLongClick = onRelatedMangaLongClick,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
onPaletteScreenClick = onPaletteScreenClick,
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
|
|
@ -296,6 +301,8 @@ fun MangaScreen(
|
|||
onRelatedMangaClick = onRelatedMangaClick,
|
||||
onRelatedMangaLongClick = onRelatedMangaLongClick,
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
onPaletteScreenClick = onPaletteScreenClick,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -366,6 +373,8 @@ private fun MangaScreenSmallImpl(
|
|||
onRelatedMangaClick: (Manga) -> Unit,
|
||||
onRelatedMangaLongClick: (Manga) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (MangaCover) -> Unit,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
val chapterListState = rememberLazyListState()
|
||||
|
|
@ -437,6 +446,7 @@ private fun MangaScreenSmallImpl(
|
|||
actionModeCounter = selectedChapterCount,
|
||||
onSelectAll = { onAllChapterSelected(true) },
|
||||
onInvertSelection = { onInvertSelection() },
|
||||
onPaletteScreenClick = onPaletteScreenClick,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
@ -520,6 +530,7 @@ private fun MangaScreenSmallImpl(
|
|||
doSearch = onSearch,
|
||||
// KMK -->
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -747,6 +758,8 @@ private fun MangaScreenLargeImpl(
|
|||
onRelatedMangaClick: (Manga) -> Unit,
|
||||
onRelatedMangaLongClick: (Manga) -> Unit,
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (MangaCover) -> Unit,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
|
|
@ -809,6 +822,7 @@ private fun MangaScreenLargeImpl(
|
|||
actionModeCounter = selectedChapterCount,
|
||||
onSelectAll = { onAllChapterSelected(true) },
|
||||
onInvertSelection = { onInvertSelection() },
|
||||
onPaletteScreenClick = onPaletteScreenClick,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
@ -893,6 +907,7 @@ private fun MangaScreenLargeImpl(
|
|||
doSearch = onSearch,
|
||||
// KMK -->
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
// KMK <--
|
||||
)
|
||||
MangaActionRow(
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ private fun NotDownloadedIndicator(
|
|||
painter = painterResource(R.drawable.ic_download_chapter_24dp),
|
||||
contentDescription = stringResource(MR.strings.manga_download),
|
||||
modifier = Modifier.size(IndicatorSize),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ private fun DownloadingIndicator(
|
|||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val arrowColor: Color
|
||||
val strokeColor = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
val strokeColor = MaterialTheme.colorScheme.primary
|
||||
val downloadProgress = downloadProgressProvider()
|
||||
val indeterminate = downloadState == Download.State.QUEUE ||
|
||||
(downloadState == Download.State.DOWNLOADING && downloadProgress == 0)
|
||||
|
|
@ -208,7 +208,7 @@ private fun DownloadedIndicator(
|
|||
imageVector = Icons.Filled.CheckCircle,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(IndicatorSize),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
|
||||
DropdownMenuItem(
|
||||
|
|
|
|||
|
|
@ -3,11 +3,16 @@ package eu.kanade.presentation.manga.components
|
|||
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.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.FilterList
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -25,7 +30,7 @@ fun ChapterHeader(
|
|||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(
|
||||
|
|
@ -33,19 +38,30 @@ fun ChapterHeader(
|
|||
onClick = onClick,
|
||||
)
|
||||
.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = if (chapterCount == null) {
|
||||
stringResource(MR.strings.chapters)
|
||||
} else {
|
||||
pluralStringResource(MR.plurals.manga_num_chapters, count = chapterCount, chapterCount)
|
||||
},
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
||||
) {
|
||||
Text(
|
||||
text = if (chapterCount == null) {
|
||||
stringResource(MR.strings.chapters)
|
||||
} else {
|
||||
pluralStringResource(MR.plurals.manga_num_chapters, count = chapterCount, chapterCount)
|
||||
},
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
|
||||
MissingChaptersWarning(missingChapterCount)
|
||||
MissingChaptersWarning(missingChapterCount)
|
||||
}
|
||||
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.FilterList,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.annotation.ColorInt
|
|||
import androidx.compose.animation.graphics.res.animatedVectorResource
|
||||
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
|
||||
import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -16,6 +17,7 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.semantics.Role
|
||||
|
|
@ -23,6 +25,9 @@ import coil3.compose.AsyncImage
|
|||
import eu.kanade.presentation.util.rememberResourceBitmapPainter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.coroutines.delay
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.asMangaCover
|
||||
import tachiyomi.domain.manga.model.MangaCover as DomainMangaCover
|
||||
|
||||
enum class MangaCover(val ratio: Float) {
|
||||
Square(1f / 1f),
|
||||
|
|
@ -36,8 +41,10 @@ enum class MangaCover(val ratio: Float) {
|
|||
contentDescription: String = "",
|
||||
shape: Shape = MaterialTheme.shapes.extraSmall,
|
||||
onClick: (() -> Unit)? = null,
|
||||
@ColorInt tint: Int = CoverPlaceholderColor,
|
||||
alpha: Float = 1f,
|
||||
bgColor: Color? = null,
|
||||
@ColorInt tint: Int? = null,
|
||||
onCoverLoaded: ((DomainMangaCover) -> Unit)? = null,
|
||||
) {
|
||||
val animatedImageVector = AnimatedImageVector.animatedVectorResource(R.drawable.anim_waiting)
|
||||
var atEnd by remember { mutableStateOf(false) }
|
||||
|
|
@ -60,12 +67,21 @@ enum class MangaCover(val ratio: Float) {
|
|||
placeholder = rememberAnimatedVectorPainter(animatedImageVector = animatedImageVector, atEnd = atEnd),
|
||||
error = rememberResourceBitmapPainter(id = R.drawable.cover_error, tint),
|
||||
fallback = rememberResourceBitmapPainter(id = R.drawable.cover_error, tint),
|
||||
onSuccess = { succeed = true },
|
||||
onSuccess = {
|
||||
succeed = true
|
||||
if (onCoverLoaded != null) {
|
||||
when (data) {
|
||||
is Manga -> onCoverLoaded(data.asMangaCover())
|
||||
is DomainMangaCover -> onCoverLoaded(data)
|
||||
}
|
||||
}
|
||||
},
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier
|
||||
.aspectRatio(ratio)
|
||||
.clip(shape)
|
||||
.alpha(if (succeed) alpha else 1f)
|
||||
.background(bgColor ?: Color.Transparent)
|
||||
.then(
|
||||
if (onClick != null) {
|
||||
Modifier.clickable(
|
||||
|
|
@ -81,6 +97,4 @@ enum class MangaCover(val ratio: Float) {
|
|||
}
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
internal val CoverPlaceholderColor = 0x7F888888
|
||||
const val LoadingAnimatedDuration = 600L
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import androidx.compose.material.icons.filled.PersonOutline
|
|||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material.icons.outlined.AttachMoney
|
||||
import androidx.compose.material.icons.outlined.Block
|
||||
import androidx.compose.material.icons.outlined.CallMerge
|
||||
import androidx.compose.material.icons.outlined.Close
|
||||
import androidx.compose.material.icons.outlined.Done
|
||||
import androidx.compose.material.icons.outlined.DoneAll
|
||||
|
|
@ -74,7 +73,7 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil3.compose.AsyncImage
|
||||
import com.materialkolor.ktx.blend
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
|
|
@ -88,9 +87,12 @@ import tachiyomi.presentation.core.i18n.pluralStringResource
|
|||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
import kotlin.math.roundToInt
|
||||
import tachiyomi.domain.manga.model.MangaCover as DomainMangaCover
|
||||
|
||||
private val whitespaceLineRegex = Regex("[\\r\\n]{2,}", setOf(RegexOption.MULTILINE))
|
||||
|
||||
|
|
@ -110,6 +112,7 @@ fun MangaInfoBox(
|
|||
modifier: Modifier = Modifier,
|
||||
// KMK -->
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (DomainMangaCover) -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
|
|
@ -127,11 +130,14 @@ fun MangaInfoBox(
|
|||
.drawWithContent {
|
||||
drawContent()
|
||||
drawRect(
|
||||
brush = Brush.verticalGradient(colors = backdropGradientColors),
|
||||
brush = Brush.verticalGradient(
|
||||
colors = backdropGradientColors,
|
||||
startY = size.height / 2,
|
||||
),
|
||||
)
|
||||
}
|
||||
.background(MaterialTheme.colorScheme.inversePrimary.copy(alpha = 0.2f))
|
||||
.blur(4.dp)
|
||||
.background(MaterialTheme.colorScheme.surfaceTint.copy(alpha = 0.4f))
|
||||
.blur(7.dp)
|
||||
.alpha(0.2f),
|
||||
)
|
||||
|
||||
|
|
@ -151,6 +157,7 @@ fun MangaInfoBox(
|
|||
isStubSource = isStubSource,
|
||||
// KMK -->
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
|
|
@ -167,6 +174,7 @@ fun MangaInfoBox(
|
|||
isStubSource = isStubSource,
|
||||
// KMK -->
|
||||
onSourceClick = onSourceClick,
|
||||
onCoverLoaded = onCoverLoaded,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -226,7 +234,11 @@ fun MangaActionRow(
|
|||
)
|
||||
},
|
||||
icon = Icons.Default.HourglassEmpty,
|
||||
color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
|
||||
color = if (isUserIntervalMode || nextUpdateDays?.let { it <= 1 } == true) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
defaultActionButtonColor
|
||||
},
|
||||
onClick = { onEditIntervalClicked?.invoke() },
|
||||
)
|
||||
MangaActionButton(
|
||||
|
|
@ -274,6 +286,8 @@ fun ExpandableMangaDescription(
|
|||
// SY <--
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val uiPreferences = Injekt.get<UiPreferences>()
|
||||
val pureDarkMode = uiPreferences.themeDarkAmoled().get()
|
||||
Column(modifier = modifier) {
|
||||
val (expanded, onExpanded) = rememberSaveable {
|
||||
mutableStateOf(defaultExpandState)
|
||||
|
|
@ -341,6 +355,7 @@ fun ExpandableMangaDescription(
|
|||
tagSelected = it
|
||||
showMenu = true
|
||||
},
|
||||
pureDarkMode = pureDarkMode,
|
||||
)
|
||||
} else {
|
||||
// SY <--
|
||||
|
|
@ -356,6 +371,7 @@ fun ExpandableMangaDescription(
|
|||
tagSelected = it
|
||||
showMenu = true
|
||||
},
|
||||
pureDarkMode = pureDarkMode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -373,6 +389,7 @@ fun ExpandableMangaDescription(
|
|||
tagSelected = it
|
||||
showMenu = true
|
||||
},
|
||||
pureDarkMode = pureDarkMode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -396,6 +413,7 @@ private fun MangaAndSourceTitlesLarge(
|
|||
isStubSource: Boolean,
|
||||
// KMK -->
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (DomainMangaCover) -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
Column(
|
||||
|
|
@ -409,6 +427,7 @@ private fun MangaAndSourceTitlesLarge(
|
|||
data = coverDataProvider(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
onCoverLoaded = { mangaCover -> onCoverLoaded(mangaCover) },
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
MangaContentInfo(
|
||||
|
|
@ -441,6 +460,7 @@ private fun MangaAndSourceTitlesSmall(
|
|||
isStubSource: Boolean,
|
||||
// KMK -->
|
||||
onSourceClick: () -> Unit,
|
||||
onCoverLoaded: (DomainMangaCover) -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -457,6 +477,7 @@ private fun MangaAndSourceTitlesSmall(
|
|||
data = coverDataProvider(),
|
||||
contentDescription = stringResource(MR.strings.manga_cover),
|
||||
onClick = onCoverClick,
|
||||
onCoverLoaded = { mangaCover -> onCoverLoaded(mangaCover) },
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
|
|
@ -674,7 +695,7 @@ private fun MangaSummary(
|
|||
contentDescription = stringResource(
|
||||
if (expanded) MR.strings.manga_info_collapse else MR.strings.manga_info_expand,
|
||||
),
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.icerock.moko.graphics.BuildConfig
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.components.DownloadDropdownMenu
|
||||
|
|
@ -59,6 +60,7 @@ fun MangaToolbar(
|
|||
|
||||
modifier: Modifier = Modifier,
|
||||
backgroundAlphaProvider: () -> Float = titleAlphaProvider,
|
||||
onPaletteScreenClick: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
|
|
@ -191,6 +193,14 @@ fun MangaToolbar(
|
|||
}
|
||||
// SY <--
|
||||
// KMK -->
|
||||
if (BuildConfig.DEBUG) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = "Colors Palette",
|
||||
onClick = onPaletteScreenClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
// add(
|
||||
// AppBar.OverflowAction(
|
||||
// title = stringResource(MR.strings.pref_invalidate_download_cache),
|
||||
|
|
@ -204,7 +214,6 @@ fun MangaToolbar(
|
|||
// ),
|
||||
// )
|
||||
// KMK <--
|
||||
|
||||
}
|
||||
.build(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.FlowRow
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ElevatedSuggestionChip
|
||||
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SuggestionChip
|
||||
|
|
@ -98,6 +99,7 @@ value class SearchMetadataChips(
|
|||
fun NamespaceTags(
|
||||
tags: SearchMetadataChips,
|
||||
onClick: (item: String) -> Unit,
|
||||
pureDarkMode: Boolean = false,
|
||||
) {
|
||||
Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
tags.tags.forEach { (namespace, tags) ->
|
||||
|
|
@ -107,6 +109,7 @@ fun NamespaceTags(
|
|||
modifier = Modifier.padding(top = 4.dp),
|
||||
text = namespace,
|
||||
onClick = null,
|
||||
pureDarkMode = pureDarkMode,
|
||||
)
|
||||
}
|
||||
FlowRow(
|
||||
|
|
@ -120,11 +123,23 @@ fun NamespaceTags(
|
|||
text = text,
|
||||
onClick = { onClick(search) },
|
||||
border = borderDp?.let {
|
||||
SuggestionChipDefaults.suggestionChipBorder(borderWidth = it)
|
||||
} ?: SuggestionChipDefaults.suggestionChipBorder(),
|
||||
SuggestionChipDefaults.suggestionChipBorder(
|
||||
borderWidth = it,
|
||||
borderColor = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
} ?: SuggestionChipDefaults.suggestionChipBorder(
|
||||
borderColor = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
borderM3 = borderDp?.let {
|
||||
SuggestionChipDefaultsM3.suggestionChipBorder(enabled = true, borderWidth = it)
|
||||
} ?: SuggestionChipDefaultsM3.suggestionChipBorder(enabled = true),
|
||||
SuggestionChipDefaultsM3.suggestionChipBorder(
|
||||
enabled = true,
|
||||
borderWidth = it,
|
||||
borderColor = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
} ?: SuggestionChipDefaultsM3.suggestionChipBorder(
|
||||
enabled = true,
|
||||
borderColor = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -139,23 +154,45 @@ fun TagsChip(
|
|||
onClick: (() -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
border: ChipBorder? = SuggestionChipDefaults.suggestionChipBorder(),
|
||||
borderM3: BorderStroke? = SuggestionChipDefaultsM3.suggestionChipBorder(enabled = true),
|
||||
borderM3: BorderStroke? = null,
|
||||
pureDarkMode: Boolean = false,
|
||||
) {
|
||||
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
|
||||
if (onClick != null) {
|
||||
SuggestionChip(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
label = {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
},
|
||||
border = borderM3,
|
||||
)
|
||||
if (borderM3 != null || pureDarkMode) {
|
||||
SuggestionChip(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
label = {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
},
|
||||
border = borderM3 ?: SuggestionChipDefaultsM3.suggestionChipBorder(
|
||||
enabled = true,
|
||||
borderColor = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
ElevatedSuggestionChip(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
label = {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
},
|
||||
colors = SuggestionChipDefaultsM3.elevatedSuggestionChipColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
SuggestionChip(
|
||||
modifier = modifier,
|
||||
|
|
|
|||
|
|
@ -112,14 +112,14 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||
): Preference.PreferenceGroup {
|
||||
val scope = rememberCoroutineScope()
|
||||
val detailsPageThemeCoverBased by remember {
|
||||
Injekt.get<UiPreferences>().detailsPageThemeCoverBased().asState(scope)
|
||||
Injekt.get<UiPreferences>().themeCoverBased().asState(scope)
|
||||
}
|
||||
return Preference.PreferenceGroup(
|
||||
title = stringResource(KMR.strings.pref_details_page_theme),
|
||||
preferenceItems = persistentListOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = uiPreferences.detailsPageThemeCoverBased(),
|
||||
title = stringResource(KMR.strings.pref_details_page_theme_cover_based),
|
||||
pref = uiPreferences.themeCoverBased(),
|
||||
title = stringResource(KMR.strings.pref_theme_cover_based),
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = uiPreferences.themeCoverBasedStyle(),
|
||||
|
|
@ -129,11 +129,6 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||
.associateWith { it.name }
|
||||
.toImmutableMap(),
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = uiPreferences.themeCoverBasedAnimate(),
|
||||
title = stringResource(KMR.strings.pref_theme_cover_based_animate),
|
||||
enabled = detailsPageThemeCoverBased,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
|
|
@ -168,12 +169,17 @@ private fun UpdatesUiItem(
|
|||
.padding(horizontal = MaterialTheme.padding.medium),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val mangaCover = update.coverData
|
||||
val bgColor = mangaCover.dominantCoverColors?.first?.let { Color(it) }
|
||||
val onBgColor = mangaCover.dominantCoverColors?.second
|
||||
MangaCover.Square(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 6.dp)
|
||||
.fillMaxHeight(),
|
||||
data = update.coverData,
|
||||
data = mangaCover,
|
||||
onClick = onClickCover,
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
)
|
||||
|
||||
Column(
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
|||
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverMetadata
|
||||
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
||||
import eu.kanade.tachiyomi.data.coil.PagePreviewFetcher
|
||||
import eu.kanade.tachiyomi.data.coil.PagePreviewKeyer
|
||||
|
|
@ -54,7 +55,6 @@ import eu.kanade.tachiyomi.di.SYPreferenceModule
|
|||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverMetadata
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ class MangaCoverFetcher(
|
|||
private val imageLoader: ImageLoader,
|
||||
) : Fetcher {
|
||||
|
||||
private val uiPreferences: UiPreferences = Injekt.get()
|
||||
private val fileScope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
private val fileScope by lazy { CoroutineScope(Job() + Dispatchers.IO) }
|
||||
private val uiPreferences = Injekt.get<UiPreferences>()
|
||||
|
||||
private val diskCacheKey: String
|
||||
get() = diskCacheKeyLazy.value
|
||||
|
|
@ -325,18 +325,17 @@ class MangaCoverFetcher(
|
|||
* @param bufferedSource if not null then it will load bitmap from [BufferedSource], regardless of [ogFile]
|
||||
* @param ogFile if not null then it will load bitmap from [File]. If it's null then it will try to load bitmap
|
||||
* from [CoverCache] using either [CoverCache.customCoverCacheDir] or [CoverCache.cacheDir]
|
||||
* @param force if true (default) then it will always re-calculate ratio & color for favorite mangas.
|
||||
* This is useful when a favorite manga updates/changes its cover. If false then it will only update ratio.
|
||||
* @param force if true then it will always re-calculate ratio & color for favorite mangas.
|
||||
*/
|
||||
private fun setRatioAndColorsInScope(
|
||||
mangaCover: MangaCover,
|
||||
bufferedSource: BufferedSource? = null,
|
||||
ogFile: File? = null,
|
||||
force: Boolean = true
|
||||
onlyFavorite: Boolean = !uiPreferences.themeCoverBased().get(),
|
||||
force: Boolean = false,
|
||||
) {
|
||||
if (!uiPreferences.detailsPageThemeCoverBased().get()) return
|
||||
fileScope.launch {
|
||||
MangaCoverMetadata.setRatioAndColors(mangaCover, bufferedSource, ogFile, force)
|
||||
MangaCoverMetadata.setRatioAndColors(mangaCover, bufferedSource, ogFile, onlyFavorite, force)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.coil
|
|||
import android.graphics.BitmapFactory
|
||||
import androidx.palette.graphics.Palette
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenModel
|
||||
import okio.BufferedSource
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.manga.model.MangaCover
|
||||
|
|
@ -65,37 +66,57 @@ object MangaCoverMetadata {
|
|||
* @param bufferedSource if not null then it will load bitmap from [BufferedSource], regardless of [ogFile]
|
||||
* @param ogFile if not null then it will load bitmap from [File]. If it's null then it will try to load bitmap
|
||||
* from [CoverCache] using either [CoverCache.customCoverCacheDir] or [CoverCache.cacheDir]
|
||||
* @param force if true (default) then it will always re-calculate ratio & color for favorite mangas.
|
||||
* This is useful when a favorite manga updates/changes its cover. If false then it will only update ratio.
|
||||
* @param force if true then it will always re-calculate ratio & color for favorite mangas.
|
||||
*
|
||||
* @author Jays2Kings
|
||||
* This is only for loading color first time it appears on Library/Browse. Any new colors caused by loading new
|
||||
* cover when open a manga detail or change cover will be updated separately on [MangaScreenModel.setPaletteColor].
|
||||
*/
|
||||
fun setRatioAndColors(
|
||||
mangaCover: MangaCover,
|
||||
bufferedSource: BufferedSource? = null,
|
||||
ogFile: File? = null,
|
||||
force: Boolean = true,
|
||||
onlyDominantColor: Boolean = true,
|
||||
force: Boolean = false,
|
||||
) {
|
||||
if (!mangaCover.isMangaFavorite) {
|
||||
mangaCover.remove()
|
||||
if (mangaCover.vibrantCoverColor != null) return
|
||||
}
|
||||
|
||||
if (mangaCover.isMangaFavorite && onlyDominantColor && mangaCover.dominantCoverColors != null) return
|
||||
|
||||
val options = BitmapFactory.Options()
|
||||
|
||||
val updateColors = mangaCover.isMangaFavorite && mangaCover.dominantCoverColors == null ||
|
||||
!onlyDominantColor && mangaCover.vibrantCoverColor == null || force
|
||||
|
||||
if (updateColors) {
|
||||
/**
|
||||
* + Manga is Favorite & doesn't have dominant color
|
||||
* For non-favorite, it doesn't care if dominant is there or not, if it has vibrant color then it will
|
||||
* already be returned from beginning.
|
||||
* + [onlyDominantColor] = false
|
||||
* - Manga doesn't have vibrant color
|
||||
*/
|
||||
options.inSampleSize = 4
|
||||
} else {
|
||||
/**
|
||||
* + [onlyDominantColor] = true
|
||||
* - Manga is Favorite & already have dominant color
|
||||
* + [onlyDominantColor] = false
|
||||
* - Manga is Favorite & already have dominant color & vibrant color
|
||||
* - Manga is not Favorite & already have vibrant color (already skip at beginning)
|
||||
*/
|
||||
// Just trying to update ratio without actual reading bitmap (bitmap will be null)
|
||||
options.inJustDecodeBounds = true
|
||||
// Don't even need to update ratio because we don't use it yet.
|
||||
return
|
||||
}
|
||||
|
||||
val file = ogFile
|
||||
?: coverCache.getCustomCoverFile(mangaCover.mangaId).takeIf { it.exists() }
|
||||
?: coverCache.getCoverFile(mangaCover.url)
|
||||
|
||||
val options = BitmapFactory.Options()
|
||||
val hasVibrantColor = if (mangaCover.isMangaFavorite) mangaCover.vibrantCoverColor != null else true
|
||||
// If dominantCoverColors is not null, it means that color is restored from Prefs
|
||||
// and also has vibrantCoverColor (e.g. new color caused by updated cover)
|
||||
val updateRatioOnly = mangaCover.dominantCoverColors != null && hasVibrantColor && !force
|
||||
if (updateRatioOnly) {
|
||||
// Just trying to update ratio without actual reading bitmap (bitmap will be null)
|
||||
// This is often when open a favorite manga
|
||||
options.inJustDecodeBounds = true
|
||||
} else {
|
||||
options.inSampleSize = 4
|
||||
}
|
||||
|
||||
val bitmap = when {
|
||||
bufferedSource != null -> BitmapFactory.decodeStream(bufferedSource.inputStream(), null, options)
|
||||
// if the file exists and the there was still an error then the file is corrupted
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import android.os.Build
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorInt
|
||||
|
|
@ -82,7 +83,6 @@ fun EditMangaDialog(
|
|||
textHighlightColor = MaterialTheme.colorScheme.outline.toArgb(),
|
||||
iconColor = MaterialTheme.colorScheme.primary.toArgb(),
|
||||
tagColor = MaterialTheme.colorScheme.outlineVariant.toArgb(),
|
||||
tagFocusColor = MaterialTheme.colorScheme.outline.toArgb(),
|
||||
tagTextColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb(),
|
||||
btnTextColor = MaterialTheme.colorScheme.onPrimary.toArgb(),
|
||||
btnBgColor = MaterialTheme.colorScheme.surfaceTint.toArgb(),
|
||||
|
|
@ -159,7 +159,6 @@ class EditMangaDialogColors(
|
|||
@ColorInt val textHighlightColor: Int,
|
||||
@ColorInt val iconColor: Int,
|
||||
@ColorInt val tagColor: Int,
|
||||
@ColorInt val tagFocusColor: Int,
|
||||
@ColorInt val tagTextColor: Int,
|
||||
@ColorInt val btnTextColor: Int,
|
||||
@ColorInt val btnBgColor: Int,
|
||||
|
|
@ -207,6 +206,14 @@ private fun onViewCreated(
|
|||
)
|
||||
}
|
||||
|
||||
// Set Spinner's selected item's background color to transparent
|
||||
binding.status.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
|
||||
if (view != null) (view as TextView).setBackgroundColor(0x00000000)
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
|
||||
}
|
||||
|
||||
// Set Spinner's dropdown caret color
|
||||
binding.status.backgroundTintList = ColorStateList.valueOf(colors.iconColor)
|
||||
|
||||
|
|
@ -346,18 +353,7 @@ private fun ChipGroup.setChips(
|
|||
) {
|
||||
removeAllViews()
|
||||
|
||||
val colorStateList = ColorStateList(
|
||||
arrayOf(
|
||||
intArrayOf(android.R.attr.state_focused),
|
||||
intArrayOf(android.R.attr.state_pressed),
|
||||
intArrayOf(-android.R.attr.state_active),
|
||||
),
|
||||
intArrayOf(
|
||||
colors.tagFocusColor,
|
||||
colors.tagFocusColor,
|
||||
colors.tagColor,
|
||||
),
|
||||
)
|
||||
val colorStateList = ColorStateList.valueOf(colors.tagColor)
|
||||
|
||||
items.asSequence().map { item ->
|
||||
Chip(context).apply {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import cafe.adriel.voyager.navigator.Navigator
|
|||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.materialkolor.DynamicMaterialTheme
|
||||
import com.materialkolor.rememberDynamicColorScheme
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
|
|
@ -140,24 +139,17 @@ class MangaScreen(
|
|||
val seedColorState = rememberUpdatedState(newValue = successState.seedColor)
|
||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
||||
|
||||
if (uiPreferences.themeCoverBasedAnimate().get()) {
|
||||
if (uiPreferences.themeCoverBased().get()) {
|
||||
DynamicMaterialTheme(
|
||||
seedColor = seedColorState.value ?: MaterialTheme.colorScheme.primary,
|
||||
useDarkTheme = isSystemInDarkTheme(),
|
||||
withAmoled = uiPreferences.themeDarkAmoled().get(),
|
||||
style = uiPreferences.themeCoverBasedStyle().get(),
|
||||
animate = uiPreferences.themeCoverBasedAnimate().get(),
|
||||
animate = true,
|
||||
content = { MaterialThemeContent(context, screenModel, successState) },
|
||||
)
|
||||
} else {
|
||||
val colorScheme = rememberDynamicColorScheme(
|
||||
seedColor = seedColorState.value ?: MaterialTheme.colorScheme.primary,
|
||||
isDark = isSystemInDarkTheme(),
|
||||
style = uiPreferences.themeCoverBasedStyle().get(),
|
||||
)
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
content = { MaterialThemeContent(context, screenModel, successState) },
|
||||
)
|
||||
MaterialThemeContent(context, screenModel, successState)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +254,7 @@ class MangaScreen(
|
|||
previewsRowCount = successState.previewsRowCount,
|
||||
// SY -->
|
||||
onMigrateClicked = { migrateManga(navigator, screenModel.manga!!) }.takeIf { successState.manga.favorite },
|
||||
onMetadataViewerClicked = { openMetadataViewer(navigator, successState.manga) },
|
||||
onMetadataViewerClicked = { openMetadataViewer(navigator, successState.manga, successState.seedColor) },
|
||||
onEditInfoClicked = screenModel::showEditMangaInfoDialog,
|
||||
onRecommendClicked = { openRecommends(context, navigator, screenModel.source?.getMainSource(), successState.manga) },
|
||||
onMergedSettingsClicked = screenModel::showEditMergedSettingsDialog,
|
||||
|
|
@ -313,6 +305,8 @@ class MangaScreen(
|
|||
navigator.push(ExtensionsScreen(searchSource = successState.source.name))
|
||||
}
|
||||
},
|
||||
onCoverLoaded = screenModel::setPaletteColor,
|
||||
onPaletteScreenClick = { navigator.push(PaletteScreen(successState.seedColor)) }
|
||||
// KMK <--
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import androidx.palette.graphics.Palette
|
|||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import coil3.Image
|
||||
import coil3.executeBlocking
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.allowHardware
|
||||
|
|
@ -45,6 +44,7 @@ import eu.kanade.domain.ui.UiPreferences
|
|||
import eu.kanade.presentation.manga.DownloadAction
|
||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
||||
import eu.kanade.presentation.util.formattedMessage
|
||||
import eu.kanade.tachiyomi.data.coil.getBestColor
|
||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
|
|
@ -64,7 +64,6 @@ import eu.kanade.tachiyomi.ui.manga.RelatedManga.Companion.sorted
|
|||
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.chapter.getNextUnread
|
||||
import eu.kanade.tachiyomi.data.coil.getBestColor
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||
import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
||||
|
|
@ -481,7 +480,7 @@ class MangaScreenModel(
|
|||
/**
|
||||
* Get the color of the manga cover by loading cover with ImageRequest directly from network.
|
||||
*/
|
||||
private suspend fun setPaletteColor(model: Any, method: ImageRequestType = ImageRequestType.Enqueue) {
|
||||
fun setPaletteColor(model: Any) {
|
||||
if (model is ImageRequest && model.defined.sizeResolver != null) return
|
||||
|
||||
val imageRequestBuilder = if (model is ImageRequest) {
|
||||
|
|
@ -494,58 +493,41 @@ class MangaScreenModel(
|
|||
val generatePalette: (Image) -> Unit = { image ->
|
||||
val bitmap = image.asDrawable(context.resources).getBitmapOrNull()
|
||||
if (bitmap != null) {
|
||||
Palette.from(bitmap).generate { palette ->
|
||||
Palette.from(bitmap).generate {
|
||||
screenModelScope.launchUI {
|
||||
palette?.getBestColor()?.let { vibrantColor ->
|
||||
when (model) {
|
||||
is Manga -> model.asMangaCover().vibrantCoverColor = vibrantColor
|
||||
is MangaCover -> model.vibrantCoverColor = vibrantColor
|
||||
if (it == null) return@launchUI
|
||||
val mangaCover = when (model) {
|
||||
is Manga -> model.asMangaCover()
|
||||
is MangaCover -> model
|
||||
else -> return@launchUI
|
||||
}
|
||||
if (mangaCover.isMangaFavorite) {
|
||||
it.dominantSwatch?.let { swatch ->
|
||||
mangaCover.dominantCoverColors = swatch.rgb to swatch.titleTextColor
|
||||
}
|
||||
}
|
||||
val vibrantColor = it.getBestColor() ?: return@launchUI
|
||||
mangaCover.vibrantCoverColor = vibrantColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (method) {
|
||||
ImageRequestType.Enqueue -> {
|
||||
context.imageLoader.enqueue(
|
||||
imageRequestBuilder
|
||||
.target(
|
||||
onSuccess = generatePalette,
|
||||
onError = {
|
||||
// TODO: handle error
|
||||
// val file = coverCache.getCoverFile(manga!!)
|
||||
// if (file.exists()) {
|
||||
// file.delete()
|
||||
// setPaletteColor()
|
||||
// }
|
||||
},
|
||||
)
|
||||
.build()
|
||||
context.imageLoader.enqueue(
|
||||
imageRequestBuilder
|
||||
.target(
|
||||
onSuccess = generatePalette,
|
||||
onError = {
|
||||
// TODO: handle error
|
||||
// val file = coverCache.getCoverFile(manga!!)
|
||||
// if (file.exists()) {
|
||||
// file.delete()
|
||||
// setPaletteColor()
|
||||
// }
|
||||
},
|
||||
)
|
||||
}
|
||||
ImageRequestType.Execute -> {
|
||||
context.imageLoader.execute(imageRequestBuilder.build())
|
||||
.image?.let { image ->
|
||||
generatePalette(image)
|
||||
}
|
||||
}
|
||||
ImageRequestType.ExecuteBlocking -> {
|
||||
context.imageLoader.executeBlocking(imageRequestBuilder.build())
|
||||
.image?.let { image ->
|
||||
generatePalette(image)
|
||||
}
|
||||
}
|
||||
ImageRequestType.IOContext -> {
|
||||
withIOContext {
|
||||
context.imageLoader.execute(imageRequestBuilder.build())
|
||||
.image?.let { image ->
|
||||
generatePalette(image)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
|
|
@ -2079,10 +2061,3 @@ sealed interface RelatedManga {
|
|||
}
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
enum class ImageRequestType {
|
||||
IOContext,
|
||||
Enqueue,
|
||||
Execute,
|
||||
ExecuteBlocking,
|
||||
}
|
||||
|
|
|
|||
197
app/src/main/java/eu/kanade/tachiyomi/ui/manga/PaletteScreen.kt
Normal file
197
app/src/main/java/eu/kanade/tachiyomi/ui/manga/PaletteScreen.kt
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
package eu.kanade.tachiyomi.ui.manga
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
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.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.materialkolor.DynamicMaterialTheme
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import tachiyomi.presentation.core.components.material.Button
|
||||
import tachiyomi.presentation.core.components.material.ButtonDefaults
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* A screen that displays a colors palette of current theme.
|
||||
*/
|
||||
class PaletteScreen(
|
||||
private val seedColor: Color?,
|
||||
) : Screen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
||||
|
||||
if (uiPreferences.themeCoverBased().get()) {
|
||||
DynamicMaterialTheme(
|
||||
seedColor = seedColor ?: MaterialTheme.colorScheme.primary,
|
||||
useDarkTheme = isSystemInDarkTheme(),
|
||||
withAmoled = uiPreferences.themeDarkAmoled().get(),
|
||||
style = uiPreferences.themeCoverBasedStyle().get(),
|
||||
animate = true,
|
||||
content = { MaterialThemeContent() },
|
||||
)
|
||||
} else {
|
||||
MaterialThemeContent()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MaterialThemeContent() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
AppBar(
|
||||
title = "Colors Palette",
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
) { contentPadding ->
|
||||
Column(
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
) {
|
||||
ButtonsColor(
|
||||
"accent & onPrimary",
|
||||
seedColor ?: MaterialTheme.colorScheme.primary,
|
||||
"accent & contentColor",
|
||||
seedColor ?: MaterialTheme.colorScheme.primary,
|
||||
MaterialTheme.colorScheme.onPrimary,
|
||||
)
|
||||
|
||||
ButtonsColor(
|
||||
"primary",
|
||||
MaterialTheme.colorScheme.primary,
|
||||
"primaryContainer",
|
||||
MaterialTheme.colorScheme.primaryContainer
|
||||
)
|
||||
ButtonsColor(
|
||||
"secondary",
|
||||
MaterialTheme.colorScheme.secondary,
|
||||
"secondaryContainer",
|
||||
MaterialTheme.colorScheme.secondaryContainer
|
||||
)
|
||||
ButtonsColor(
|
||||
"tertiary",
|
||||
MaterialTheme.colorScheme.tertiary,
|
||||
"tertiaryContainer",
|
||||
MaterialTheme.colorScheme.tertiaryContainer
|
||||
)
|
||||
ButtonsColor(
|
||||
"surface",
|
||||
MaterialTheme.colorScheme.surface,
|
||||
"surfaceVariant",
|
||||
MaterialTheme.colorScheme.surfaceVariant
|
||||
)
|
||||
ButtonsColor(
|
||||
"inverseSurface",
|
||||
MaterialTheme.colorScheme.inverseSurface,
|
||||
"surfaceTint",
|
||||
MaterialTheme.colorScheme.surfaceTint
|
||||
)
|
||||
ButtonsColor(
|
||||
"inversePrimary",
|
||||
MaterialTheme.colorScheme.inversePrimary,
|
||||
"background",
|
||||
MaterialTheme.colorScheme.background
|
||||
)
|
||||
ButtonsColor(
|
||||
"error",
|
||||
MaterialTheme.colorScheme.error,
|
||||
"errorContainer",
|
||||
MaterialTheme.colorScheme.errorContainer
|
||||
)
|
||||
ButtonsColor(
|
||||
"outline",
|
||||
MaterialTheme.colorScheme.outline,
|
||||
"outlineVariant",
|
||||
MaterialTheme.colorScheme.outlineVariant
|
||||
)
|
||||
ButtonsColor(
|
||||
"scrim",
|
||||
MaterialTheme.colorScheme.scrim,
|
||||
"surfaceBright",
|
||||
MaterialTheme.colorScheme.surfaceBright
|
||||
)
|
||||
ButtonsColor(
|
||||
"surfaceDim",
|
||||
MaterialTheme.colorScheme.surfaceDim,
|
||||
"surfaceContainer",
|
||||
MaterialTheme.colorScheme.surfaceContainer
|
||||
)
|
||||
ButtonsColor(
|
||||
"surfaceContainerHigh",
|
||||
MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
"surfaceContainerHighest",
|
||||
MaterialTheme.colorScheme.surfaceContainerHighest
|
||||
)
|
||||
ButtonsColor(
|
||||
"surfaceContainerLow",
|
||||
MaterialTheme.colorScheme.surfaceContainerLow,
|
||||
"surfaceContainerLowest",
|
||||
MaterialTheme.colorScheme.surfaceContainerLowest
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ButtonsColor(
|
||||
name1: String,
|
||||
color1: Color,
|
||||
name2: String,
|
||||
color2: Color,
|
||||
contentColor1: Color = contentColorFor(backgroundColor = color1),
|
||||
contentColor2: Color = contentColorFor(backgroundColor = color2),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Button(
|
||||
onClick = { },
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = color1,
|
||||
contentColor = contentColor1,
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = name1,
|
||||
)
|
||||
}
|
||||
Button(
|
||||
onClick = { },
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = color2,
|
||||
contentColor = contentColor2,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = name2
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
|
|||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.materialkolor.DynamicMaterialTheme
|
||||
import com.materialkolor.PaletteStyle
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
|
|
@ -36,6 +36,8 @@ import tachiyomi.presentation.core.screens.EmptyScreen
|
|||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
import tachiyomi.presentation.core.util.plus
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MetadataViewScreen(
|
||||
private val mangaId: Long,
|
||||
|
|
@ -107,12 +109,19 @@ class MetadataViewScreen(
|
|||
}
|
||||
}
|
||||
|
||||
DynamicMaterialTheme(
|
||||
seedColor = seedColor ?: MaterialTheme.colorScheme.primary,
|
||||
useDarkTheme = isSystemInDarkTheme(),
|
||||
style = PaletteStyle.Vibrant,
|
||||
animate = true,
|
||||
content = { content() }
|
||||
)
|
||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
||||
|
||||
if (uiPreferences.themeCoverBased().get()) {
|
||||
DynamicMaterialTheme(
|
||||
seedColor = seedColor ?: MaterialTheme.colorScheme.primary,
|
||||
useDarkTheme = isSystemInDarkTheme(),
|
||||
withAmoled = uiPreferences.themeDarkAmoled().get(),
|
||||
style = uiPreferences.themeCoverBasedStyle().get(),
|
||||
animate = true,
|
||||
content = { content() },
|
||||
)
|
||||
} else {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ fun EHentaiDescription(
|
|||
search: (String) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
val ratingBarSecondaryColor = MaterialTheme.colorScheme.outlineVariant.toArgb()
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import tachiyomi.i18n.MR
|
|||
@Composable
|
||||
fun EightMusesDescription(state: State.Success, openMetadataViewer: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import tachiyomi.i18n.sy.SYMR
|
|||
@Composable
|
||||
fun HBrowseDescription(state: State.Success, openMetadataViewer: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import kotlin.math.round
|
|||
@Composable
|
||||
fun MangaDexDescription(state: State.Success, openMetadataViewer: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
val ratingBarSecondaryColor = MaterialTheme.colorScheme.outlineVariant.toArgb()
|
||||
AndroidView(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import java.time.ZonedDateTime
|
|||
@Composable
|
||||
fun NHentaiDescription(state: State.Success, openMetadataViewer: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import kotlin.math.round
|
|||
@Composable
|
||||
fun PururinDescription(state: State.Success, openMetadataViewer: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
val ratingBarSecondaryColor = MaterialTheme.colorScheme.outlineVariant.toArgb()
|
||||
AndroidView(
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import kotlin.math.round
|
|||
@Composable
|
||||
fun TsuminoDescription(state: State.Success, openMetadataViewer: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.secondary.toArgb()
|
||||
val iconColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
val ratingBarSecondaryColor = MaterialTheme.colorScheme.outlineVariant.toArgb()
|
||||
AndroidView(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -38,9 +39,14 @@ fun UpcomingItem(
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.large),
|
||||
) {
|
||||
val mangaCover = upcoming.asMangaCover()
|
||||
val bgColor = mangaCover.dominantCoverColors?.first?.let { Color(it) }
|
||||
val onBgColor = mangaCover.dominantCoverColors?.second
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
data = upcoming.asMangaCover(),
|
||||
data = mangaCover,
|
||||
bgColor = bgColor,
|
||||
tint = onBgColor,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
|
|
|
|||
|
|
@ -35,9 +35,15 @@ class LibraryPreferences(
|
|||
fun lastUpdatedTimestamp() = preferenceStore.getLong(Preference.appStateKey("library_update_last_timestamp"), 0L)
|
||||
fun autoUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0)
|
||||
|
||||
fun coverRatios() = preferenceStore.getStringSet("pref_library_cover_ratios_key", emptySet())
|
||||
fun coverRatios() = preferenceStore.getStringSet(
|
||||
Preference.appStateKey("pref_library_cover_ratios_key"),
|
||||
emptySet(),
|
||||
)
|
||||
|
||||
fun coverColors() = preferenceStore.getStringSet("pref_library_cover_colors_key", emptySet())
|
||||
fun coverColors() = preferenceStore.getStringSet(
|
||||
Preference.appStateKey("pref_library_cover_colors_key"),
|
||||
emptySet(),
|
||||
)
|
||||
|
||||
fun autoUpdateDeviceRestrictions() = preferenceStore.getStringSet(
|
||||
"library_update_restriction",
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ sqlite = "2.4.0"
|
|||
voyager = "1.0.0"
|
||||
detekt = "1.23.6"
|
||||
detektCompose = "0.3.12"
|
||||
paletteKtxVersion = "1.0.0"
|
||||
materialKolorVersion = "1.6.1"
|
||||
|
||||
[libraries]
|
||||
desugar = "com.android.tools:desugar_jdk_libs:2.0.4"
|
||||
|
|
@ -70,8 +68,8 @@ insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
|
|||
compose-materialmotion = "io.github.fornewid:material-motion-compose-core:2.0.0"
|
||||
compose-webview = "io.github.kevinnzou:compose-webview:0.33.6"
|
||||
compose-grid = "io.woong.compose.grid:grid:1.2.2"
|
||||
palette-ktx = { group = "androidx.palette", name = "palette-ktx", version.ref = "paletteKtxVersion" }
|
||||
material-kolor = { module = "com.materialkolor:material-kolor", version.ref = "materialKolorVersion" }
|
||||
palette-ktx = "androidx.palette:palette-ktx:1.0.0"
|
||||
material-kolor = "com.materialkolor:material-kolor:1.7.0"
|
||||
|
||||
swipe = "me.saket.swipe:swipe:1.3.0"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">وضع التحديد بالجملة</string>
|
||||
<string name="action_faq_and_guides">الأسئلة الشائعة والأدلة</string>
|
||||
<string name="pref_details_page_theme">صفحة التفاصيل</string>
|
||||
<string name="pref_details_page_theme_cover_based">تفاصيل سمة الصفحة استنادًا إلى الغلاف</string>
|
||||
<string name="pref_theme_cover_based">السمة المبنية على الغلاف</string>
|
||||
<string name="pref_theme_cover_based_style">نمط السمة</string>
|
||||
<string name="pref_theme_cover_based_animate">الرسوم المتحركة للسمة</string>
|
||||
<string name="ext_unofficial">غير رسمي</string>
|
||||
<string name="unofficial_extension_message">وهذا التمديد ليس من المستودع الرسمي.</string>
|
||||
<string name="download_cache_renew_interval">الفاصل الزمني لتجديد التحميل</string>
|
||||
|
|
|
|||
|
|
@ -9,9 +9,8 @@
|
|||
<!-- Preferences -->
|
||||
<!-- General section -->
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="pref_expand_related_titles">Expand Related titles</string>
|
||||
<string name="pref_expand_related_titles_summary">If turned off, related titles won\'t automatically load & show expanded</string>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Režim hromadného výběru</string>
|
||||
<string name="action_faq_and_guides">FAQ a návody</string>
|
||||
<string name="pref_details_page_theme">Stránka s podrobnostmi</string>
|
||||
<string name="pref_details_page_theme_cover_based">Šablona stránky s podrobnostmi na základě obalu</string>
|
||||
<string name="pref_theme_cover_based">Šablona založená na obálce</string>
|
||||
<string name="pref_theme_cover_based_style">Styl motivu</string>
|
||||
<string name="pref_theme_cover_based_animate">Animace motivu</string>
|
||||
<string name="ext_unofficial">Neoficiální</string>
|
||||
<string name="unofficial_extension_message">Toto rozšíření není z oficiálního repozitáře.</string>
|
||||
<string name="download_cache_renew_interval">Interval obnovení mezipaměti</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Masse valg tilstand</string>
|
||||
<string name="action_faq_and_guides">Ofte stillede spørgsmål og vejledninger</string>
|
||||
<string name="pref_details_page_theme">Detaljer side</string>
|
||||
<string name="pref_details_page_theme_cover_based">Detaljer sidetema baseret på omslag</string>
|
||||
<string name="pref_theme_cover_based">Tema baseret på omslag</string>
|
||||
<string name="pref_theme_cover_based_style">Tema stil</string>
|
||||
<string name="pref_theme_cover_based_animate">Tema animere</string>
|
||||
<string name="ext_unofficial">Uofficiel</string>
|
||||
<string name="unofficial_extension_message">Denne udvidelse er ikke fra den officielle repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache forny interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Massenauswahlmodus</string>
|
||||
<string name="action_faq_and_guides">FAQ und Anleitungen</string>
|
||||
<string name="pref_details_page_theme">Detailseite</string>
|
||||
<string name="pref_details_page_theme_cover_based">Detailseitenthema basierend auf Cover</string>
|
||||
<string name="pref_theme_cover_based">Theme basierend auf Cover</string>
|
||||
<string name="pref_theme_cover_based_style">Design-Stil</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animieren</string>
|
||||
<string name="ext_unofficial">Ungültig</string>
|
||||
<string name="unofficial_extension_message">Diese Erweiterung ist nicht vom offiziellen Repo.</string>
|
||||
<string name="download_cache_renew_interval">Download-Cache Erneuerungsintervall</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Λειτουργία μαζικής επιλογής</string>
|
||||
<string name="action_faq_and_guides">Συχνές ερωτήσεις και οδηγοί</string>
|
||||
<string name="pref_details_page_theme">Σελίδα λεπτομερειών</string>
|
||||
<string name="pref_details_page_theme_cover_based">Θέμα λεπτομερειών σελίδας με βάση το εξώφυλλο</string>
|
||||
<string name="pref_theme_cover_based">Θέμα βασισμένο στο εξώφυλλο</string>
|
||||
<string name="pref_theme_cover_based_style">Στυλ θέματος</string>
|
||||
<string name="pref_theme_cover_based_animate">Εφέ κίνησης θέματος</string>
|
||||
<string name="ext_unofficial">Ανεπίσημη</string>
|
||||
<string name="unofficial_extension_message">Η επέκταση αυτή δεν προέρχεται από την επίσημη αποχώρηση.</string>
|
||||
<string name="download_cache_renew_interval">Χρονικό διάστημα ανανέωσης προσωρινής μνήμης</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Modo de selección masiva</string>
|
||||
<string name="action_faq_and_guides">Preguntas frecuentes y guías</string>
|
||||
<string name="pref_details_page_theme">Página de detalles</string>
|
||||
<string name="pref_details_page_theme_cover_based">Tema de página de detalles basado en portada</string>
|
||||
<string name="pref_theme_cover_based">Tema basado en portada</string>
|
||||
<string name="pref_theme_cover_based_style">Estilo del tema</string>
|
||||
<string name="pref_theme_cover_based_animate">Animar tema</string>
|
||||
<string name="ext_unofficial">No oficial</string>
|
||||
<string name="unofficial_extension_message">Esta extensión no es del repositorio oficial.</string>
|
||||
<string name="download_cache_renew_interval">Descargar el intervalo de renovación de caché</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk valintatila</string>
|
||||
<string name="action_faq_and_guides">UKK ja oppaat</string>
|
||||
<string name="pref_details_page_theme">Yksityiskohdat sivu</string>
|
||||
<string name="pref_details_page_theme_cover_based">Yksityiskohtaiset tiedot sivun teema kannen perusteella</string>
|
||||
<string name="pref_theme_cover_based">Teema perustuu kanteen</string>
|
||||
<string name="pref_theme_cover_based_style">Teeman tyyli</string>
|
||||
<string name="pref_theme_cover_based_animate">Teema animoitu</string>
|
||||
<string name="ext_unofficial">Epävirallinen</string>
|
||||
<string name="unofficial_extension_message">Tämä laajennus ei ole virallisesta reposta.</string>
|
||||
<string name="download_cache_renew_interval">Lataa välimuistin uusimisväli</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Mode de sélection en bloc</string>
|
||||
<string name="action_faq_and_guides">FAQ et tutoriels</string>
|
||||
<string name="pref_details_page_theme">Page de détails</string>
|
||||
<string name="pref_details_page_theme_cover_based">Thème de la page de détails basé sur la couverture</string>
|
||||
<string name="pref_theme_cover_based">Thème basé sur la couverture</string>
|
||||
<string name="pref_theme_cover_based_style">Style du thème</string>
|
||||
<string name="pref_theme_cover_based_animate">Animation du thème</string>
|
||||
<string name="ext_unofficial">Non officiel</string>
|
||||
<string name="unofficial_extension_message">Cette extension ne provient pas du dépôt officiel.</string>
|
||||
<string name="download_cache_renew_interval">Intervalle de renouvellement du cache de téléchargement</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Modalità selezione Bulk</string>
|
||||
<string name="action_faq_and_guides">FAQ e guide</string>
|
||||
<string name="pref_details_page_theme">Pagina dettagli</string>
|
||||
<string name="pref_details_page_theme_cover_based">Dettagli tema pagina basato sulla copertina</string>
|
||||
<string name="pref_theme_cover_based">Tema basato sulla copertina</string>
|
||||
<string name="pref_theme_cover_based_style">Stile tema</string>
|
||||
<string name="pref_theme_cover_based_animate">Animazione tema</string>
|
||||
<string name="ext_unofficial">Non Ufficiale</string>
|
||||
<string name="unofficial_extension_message">Questa estensione non proviene dal repo ufficiale.</string>
|
||||
<string name="download_cache_renew_interval">Intervallo di rinnovo download cache</string>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@
|
|||
<string name="action_bulk_select">一括選択モード</string>
|
||||
<string name="action_faq_and_guides">FAQ とガイド</string>
|
||||
<string name="pref_details_page_theme">詳細ページ</string>
|
||||
<string name="pref_details_page_theme_cover_based">カバーに基づく詳細ページのテーマ</string>
|
||||
<string name="pref_theme_cover_based">カバーに基づくテーマ</string>
|
||||
<string name="pref_theme_cover_based_style">テーマのスタイル</string>
|
||||
<string name="pref_theme_cover_based_animate">テーマのアニメーション</string>
|
||||
<string name="ext_unofficial"><unk></string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">この拡張機能は公式リポジトリからのものではありません。</string>
|
||||
<string name="download_cache_renew_interval">キャッシュの更新間隔をダウンロード</string>
|
||||
<string name="download_cache_renew_interval_manual">マニュアル</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selectiemodus</string>
|
||||
<string name="action_faq_and_guides">FAQ en handleidingen</string>
|
||||
<string name="pref_details_page_theme">Details pagina</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details pagina thema gebaseerd op cover</string>
|
||||
<string name="pref_theme_cover_based">Thema gebaseerd op cover</string>
|
||||
<string name="pref_theme_cover_based_style">Thema stijl</string>
|
||||
<string name="pref_theme_cover_based_animate">Thema animeren</string>
|
||||
<string name="ext_unofficial">Onofficiële</string>
|
||||
<string name="unofficial_extension_message">Deze uitbreiding komt niet uit de officiële repo.</string>
|
||||
<string name="download_cache_renew_interval">Download de cache vernieuwingsinterval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Tryb masowego zaznaczenia</string>
|
||||
<string name="action_faq_and_guides">FAQ i przewodniki</string>
|
||||
<string name="pref_details_page_theme">Strona szczegółów</string>
|
||||
<string name="pref_details_page_theme_cover_based">Szczegółowy motyw strony oparty na okładce</string>
|
||||
<string name="pref_theme_cover_based">Motyw oparty na okładce</string>
|
||||
<string name="pref_theme_cover_based_style">Styl motywu</string>
|
||||
<string name="pref_theme_cover_based_animate">Animacja motywu</string>
|
||||
<string name="ext_unofficial">Nieoficjalne</string>
|
||||
<string name="unofficial_extension_message">To rozszerzenie nie pochodzi z oficjalnego repozytorium.</string>
|
||||
<string name="download_cache_renew_interval">Częstotliwość odnawiania pamięci podręcznej pobierania</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Modo de seleção em massa</string>
|
||||
<string name="action_faq_and_guides">FAQ e Guias</string>
|
||||
<string name="pref_details_page_theme">Página de detalhes</string>
|
||||
<string name="pref_details_page_theme_cover_based">Detalhe o tema da página baseado na capa</string>
|
||||
<string name="pref_theme_cover_based">Tema baseado na capa</string>
|
||||
<string name="pref_theme_cover_based_style">Estilo do tema</string>
|
||||
<string name="pref_theme_cover_based_animate">Animação do tema</string>
|
||||
<string name="ext_unofficial">Não-oficial</string>
|
||||
<string name="unofficial_extension_message">Essa extensão não é do repositório oficial.</string>
|
||||
<string name="download_cache_renew_interval">Baixar intervalo de renovação do cache</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Modo de seleção em massa</string>
|
||||
<string name="action_faq_and_guides">FAQ e Guias</string>
|
||||
<string name="pref_details_page_theme">Página de detalhes</string>
|
||||
<string name="pref_details_page_theme_cover_based">Detalhe o tema da página baseado na capa</string>
|
||||
<string name="pref_theme_cover_based">Tema baseado na capa</string>
|
||||
<string name="pref_theme_cover_based_style">Estilo do tema</string>
|
||||
<string name="pref_theme_cover_based_animate">Animação do tema</string>
|
||||
<string name="ext_unofficial">Não-oficial</string>
|
||||
<string name="unofficial_extension_message">Essa extensão não é do repositório oficial.</string>
|
||||
<string name="download_cache_renew_interval">Baixar intervalo de renovação do cache</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Mod selecţie în masă</string>
|
||||
<string name="action_faq_and_guides">Întrebări frecvente și ghiduri</string>
|
||||
<string name="pref_details_page_theme">Pagina de detalii</string>
|
||||
<string name="pref_details_page_theme_cover_based">Tema paginii cu detalii bazate pe copertă</string>
|
||||
<string name="pref_theme_cover_based">Temă bazată pe copertă</string>
|
||||
<string name="pref_theme_cover_based_style">Stil temă</string>
|
||||
<string name="pref_theme_cover_based_animate">Animare temă</string>
|
||||
<string name="ext_unofficial">Neoficial.</string>
|
||||
<string name="unofficial_extension_message">Această extensie nu este din repo-ul oficial.</string>
|
||||
<string name="download_cache_renew_interval">Interval reînnoire descărcare geocutie</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Режим массового выбора</string>
|
||||
<string name="action_faq_and_guides">FAQ и руководства</string>
|
||||
<string name="pref_details_page_theme">Детали</string>
|
||||
<string name="pref_details_page_theme_cover_based">Детали темы на основе обложки</string>
|
||||
<string name="pref_theme_cover_based">Тема на основе обложки</string>
|
||||
<string name="pref_theme_cover_based_style">Стиль темы</string>
|
||||
<string name="pref_theme_cover_based_animate">Тема анимации</string>
|
||||
<string name="ext_unofficial">Неофициальный</string>
|
||||
<string name="unofficial_extension_message">Это расширение не из официального репозитория.</string>
|
||||
<string name="download_cache_renew_interval">Загрузить интервал обновления кэша</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk markeringsläge</string>
|
||||
<string name="action_faq_and_guides">Vanliga frågor och guider</string>
|
||||
<string name="pref_details_page_theme">Detaljer sida</string>
|
||||
<string name="pref_details_page_theme_cover_based">Detaljer sida tema baserat på omslag</string>
|
||||
<string name="pref_theme_cover_based">Tema baserat på omslag</string>
|
||||
<string name="pref_theme_cover_based_style">Tema stil</string>
|
||||
<string name="pref_theme_cover_based_animate">Tema animerat</string>
|
||||
<string name="ext_unofficial">Inofficiellt</string>
|
||||
<string name="unofficial_extension_message">Denna förlängning kommer inte från den officiella rapo.</string>
|
||||
<string name="download_cache_renew_interval">Hämta cache förnyelseintervall</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Масовий режим вибору</string>
|
||||
<string name="action_faq_and_guides">ЧаПи та керівництва</string>
|
||||
<string name="pref_details_page_theme">Сторінка подробиць</string>
|
||||
<string name="pref_details_page_theme_cover_based">Тема сторінки подробиць на основі обкладинки</string>
|
||||
<string name="pref_theme_cover_based">Тему на основі обкладинки</string>
|
||||
<string name="pref_theme_cover_based_style">Стиль теми</string>
|
||||
<string name="pref_theme_cover_based_animate">Анімація теми</string>
|
||||
<string name="ext_unofficial">Неофіційна</string>
|
||||
<string name="unofficial_extension_message">Це розширення не з офіційного репозиторію.</string>
|
||||
<string name="download_cache_renew_interval">Завантажити інтервал оновлення кешу</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">Bulk selection mode</string>
|
||||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="pref_details_page_theme">Details page</string>
|
||||
<string name="pref_details_page_theme_cover_based">Details page theme based on cover</string>
|
||||
<string name="pref_theme_cover_based">Theme based on cover</string>
|
||||
<string name="pref_theme_cover_based_style">Theme style</string>
|
||||
<string name="pref_theme_cover_based_animate">Theme animate</string>
|
||||
<string name="ext_unofficial">Unofficial</string>
|
||||
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||
<string name="download_cache_renew_interval">Download cache renew interval</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">批量选择模式</string>
|
||||
<string name="action_faq_and_guides">常见问题和指南</string>
|
||||
<string name="pref_details_page_theme">详细信息页面</string>
|
||||
<string name="pref_details_page_theme_cover_based">基于封面的详细页面主题</string>
|
||||
<string name="pref_theme_cover_based">基于封面的主题</string>
|
||||
<string name="pref_theme_cover_based_style">主题样式</string>
|
||||
<string name="pref_theme_cover_based_animate">主题动画</string>
|
||||
<string name="ext_unofficial">非官方的</string>
|
||||
<string name="unofficial_extension_message">这个扩展不是官方仓库的扩展。</string>
|
||||
<string name="download_cache_renew_interval">下载缓存续间隔</string>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
<string name="action_bulk_select">批量選擇模式</string>
|
||||
<string name="action_faq_and_guides">常見問題和指南</string>
|
||||
<string name="pref_details_page_theme">詳情頁面</string>
|
||||
<string name="pref_details_page_theme_cover_based">基於封面的詳細資訊頁面主題</string>
|
||||
<string name="pref_theme_cover_based">基於封面的主題</string>
|
||||
<string name="pref_theme_cover_based_style">主題風格</string>
|
||||
<string name="pref_theme_cover_based_animate">主題動畫</string>
|
||||
<string name="ext_unofficial">非官方版本</string>
|
||||
<string name="unofficial_extension_message">此擴充功能不是來自官方儲存庫</string>
|
||||
<string name="download_cache_renew_interval">下載快取更新間隔</string>
|
||||
|
|
|
|||
Loading…
Reference in a new issue