Address spotless lint errors (mihonapp/mihon#1138)

* Add spotless (with ktlint)

* Run spotlessApply

* screaming case screaming case screaming case

* Update PagerViewerAdapter.kt

* Update ReaderTransitionView.kt

(cherry picked from commit d6252ab7703d52ecf9f43de3ee36fd63e665a31f)
This commit is contained in:
AntsyLich 2024-08-19 18:11:39 +06:00 committed by Cuong-Tran
parent 62507fc3cd
commit e7ca892f65
No known key found for this signature in database
GPG key ID: 733AA7624B9315C2
267 changed files with 605 additions and 505 deletions

View file

@ -23,7 +23,7 @@ if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
// shortcutHelper.setFilePath("./shortcuts.xml") // shortcutHelper.setFilePath("./shortcuts.xml")
val SUPPORTED_ABIS = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") val supportedAbis = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
android { android {
namespace = "eu.kanade.tachiyomi" namespace = "eu.kanade.tachiyomi"
@ -41,7 +41,7 @@ android {
buildConfigField("boolean", "PREVIEW", "false") buildConfigField("boolean", "PREVIEW", "false")
ndk { ndk {
abiFilters += SUPPORTED_ABIS abiFilters += supportedAbis
} }
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@ -50,7 +50,7 @@ android {
abi { abi {
isEnable = true isEnable = true
reset() reset()
include(*SUPPORTED_ABIS.toTypedArray()) include(*supportedAbis.toTypedArray())
isUniversalApk = true isUniversalApk = true
} }
} }

View file

@ -117,7 +117,10 @@ class SyncChaptersWithSource(
downloadManager.isChapterDownloaded( downloadManager.isChapterDownloaded(
dbChapter.name, dbChapter.name,
dbChapter.scanlator, dbChapter.scanlator,
/* SY --> */ manga.ogTitle /* SY <-- */, // SY -->
// manga.title,
manga.ogTitle,
// SY <--
manga.source, manga.source,
) )

View file

@ -20,7 +20,11 @@ class UiPreferences(
fun appTheme() = preferenceStore.getEnum( fun appTheme() = preferenceStore.getEnum(
"pref_app_theme", "pref_app_theme",
if (DeviceUtil.isDynamicColorAvailable) { AppTheme.MONET } else { AppTheme.DEFAULT }, if (DeviceUtil.isDynamicColorAvailable) {
AppTheme.MONET
} else {
AppTheme.DEFAULT
},
) )
fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false) fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)

View file

@ -266,7 +266,7 @@ private fun DetailsHeader(
Extension name: ${extension.name} (lang: ${extension.lang}; package: ${extension.pkgName}) Extension name: ${extension.name} (lang: ${extension.lang}; package: ${extension.pkgName})
Extension version: ${extension.versionName} (lib: ${extension.libVersion}; version code: ${extension.versionCode}) Extension version: ${extension.versionName} (lib: ${extension.libVersion}; version code: ${extension.versionCode})
NSFW: ${extension.isNsfw} NSFW: ${extension.isNsfw}
""".trimIndent() """.trimIndent(),
) )
if (extension is Extension.Installed) { if (extension is Extension.Installed) {
@ -276,8 +276,8 @@ private fun DetailsHeader(
Update available: ${extension.hasUpdate} Update available: ${extension.hasUpdate}
Obsolete: ${extension.isObsolete} Obsolete: ${extension.isObsolete}
Shared: ${extension.isShared} Shared: ${extension.isShared}
Repository: ${extension.repoUrl} Repository: ${extension.repoUrl}
""".trimIndent() """.trimIndent(),
) )
} }
} }

View file

@ -231,7 +231,9 @@ private fun ExtensionContent(
when (it) { when (it) {
is Extension.Available -> onInstallExtension(it) is Extension.Available -> onInstallExtension(it)
is Extension.Installed -> onOpenExtension(it) is Extension.Installed -> onOpenExtension(it)
is Extension.Untrusted -> { trustState = it } is Extension.Untrusted -> {
trustState = it
}
} }
}, },
onLongClickItem = onLongClickItem, onLongClickItem = onLongClickItem,
@ -253,7 +255,9 @@ private fun ExtensionContent(
onOpenExtension(it) onOpenExtension(it)
} }
} }
is Extension.Untrusted -> { trustState = it } is Extension.Untrusted -> {
trustState = it
}
} }
}, },
) )

View file

@ -69,7 +69,7 @@ import tachiyomi.i18n.kmk.KMR
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.FastScrollLazyColumn import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.EmptyScreen
@ -399,7 +399,7 @@ private fun SourcePinButton(
MaterialTheme.colorScheme.primary MaterialTheme.colorScheme.primary
} else { } else {
MaterialTheme.colorScheme.onBackground.copy( MaterialTheme.colorScheme.onBackground.copy(
alpha = SecondaryItemAlpha, alpha = SECONDARY_ALPHA,
) )
} }
val description = if (isPinned) MR.strings.action_unpin else MR.strings.action_pin val description = if (isPinned) MR.strings.action_unpin else MR.strings.action_pin

View file

@ -34,7 +34,7 @@ import com.gowtham.ratingbar.RatingBar
import com.gowtham.ratingbar.RatingBarStyle import com.gowtham.ratingbar.RatingBarStyle
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import eu.kanade.presentation.library.components.CommonMangaItemDefaults import eu.kanade.presentation.library.components.CommonMangaItemDefaults
import eu.kanade.presentation.library.components.GridSelectedCoverAlpha import eu.kanade.presentation.library.components.GRID_SELECTED_COVER_ALPHA
import eu.kanade.presentation.manga.components.MangaCover import eu.kanade.presentation.manga.components.MangaCover
import eu.kanade.presentation.manga.components.MangaCoverHide import eu.kanade.presentation.manga.components.MangaCoverHide
import exh.debug.DebugToggles import exh.debug.DebugToggles
@ -205,7 +205,7 @@ fun BrowseSourceEHentaiListItem(
modifier = Modifier modifier = Modifier
.fillMaxHeight(), .fillMaxHeight(),
// KMK --> // KMK -->
alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha, alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }), bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
tint = onBgColor, tint = onBgColor,
// KMK <-- // KMK <--

View file

@ -79,7 +79,7 @@ fun TabbedDialog(
modifier = Modifier.animateContentSize(), modifier = Modifier.animateContentSize(),
state = pagerState, state = pagerState,
verticalAlignment = Alignment.Top, verticalAlignment = Alignment.Top,
pageContent = { page -> content(page) } pageContent = { page -> content(page) },
) )
} }
} }

View file

@ -63,7 +63,7 @@ private val ContinueReadingButtonIconSizeLarge = 20.dp
private val ContinueReadingButtonGridPadding = 6.dp private val ContinueReadingButtonGridPadding = 6.dp
private val ContinueReadingButtonListSpacing = 8.dp private val ContinueReadingButtonListSpacing = 8.dp
internal const val GridSelectedCoverAlpha = 0.76f internal const val GRID_SELECTED_COVER_ALPHA = 0.76f
/** /**
* Layout of grid list item with title overlaying the cover. * Layout of grid list item with title overlaying the cover.
@ -113,7 +113,7 @@ fun MangaCompactGridItem(
.fillMaxWidth(), .fillMaxWidth(),
data = coverData, data = coverData,
// KMK --> // KMK -->
alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha, alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }), bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
tint = onBgColor, tint = onBgColor,
// KMK <-- // KMK <--
@ -245,7 +245,7 @@ fun MangaComfortableGridItem(
.fillMaxWidth(), .fillMaxWidth(),
data = coverData, data = coverData,
// KMK --> // KMK -->
alpha = if (isSelected) GridSelectedCoverAlpha else coverAlpha, alpha = if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha,
bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }), bgColor = bgColor ?: (MaterialTheme.colorScheme.surface.takeIf { isSelected }),
tint = onBgColor, tint = onBgColor,
// KMK <-- // KMK <--
@ -448,7 +448,7 @@ fun MangaListItem(
size = ContinueReadingButtonSizeSmall, size = ContinueReadingButtonSizeSmall,
iconSize = ContinueReadingButtonIconSizeSmall, iconSize = ContinueReadingButtonIconSizeSmall,
onClick = onClickContinueReading, onClick = onClickContinueReading,
modifier = Modifier.padding(start = ContinueReadingButtonListSpacing) modifier = Modifier.padding(start = ContinueReadingButtonListSpacing),
) )
} }
} }
@ -469,7 +469,7 @@ private fun ContinueReadingButton(
containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f), containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f),
contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer), contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer),
), ),
modifier = Modifier.size(size) modifier = Modifier.size(size),
) { ) {
Icon( Icon(
imageVector = Icons.Filled.PlayArrow, imageVector = Icons.Filled.PlayArrow,

View file

@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.pluralStringResource
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
@ -70,6 +70,6 @@ private fun MissingChaptersWarning(count: Int) {
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error.copy(alpha = SecondaryItemAlpha), color = MaterialTheme.colorScheme.error.copy(alpha = SECONDARY_ALPHA),
) )
} }

View file

@ -40,8 +40,8 @@ import eu.kanade.tachiyomi.data.download.model.Download
import me.saket.swipe.SwipeableActionsBox import me.saket.swipe.SwipeableActionsBox
import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.ReadItemAlpha import tachiyomi.presentation.core.components.material.DISABLED_ALPHA
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.selectedBackground import tachiyomi.presentation.core.util.selectedBackground
@ -135,7 +135,7 @@ fun MangaChapterListItem(
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
onTextLayout = { textHeight = it.size.height }, onTextLayout = { textHeight = it.size.height },
color = LocalContentColor.current.copy(alpha = if (read) ReadItemAlpha else 1f), color = LocalContentColor.current.copy(alpha = if (read) DISABLED_ALPHA else 1f),
) )
} }
@ -143,7 +143,7 @@ fun MangaChapterListItem(
val subtitleStyle = MaterialTheme.typography.bodySmall val subtitleStyle = MaterialTheme.typography.bodySmall
.merge( .merge(
color = LocalContentColor.current color = LocalContentColor.current
.copy(alpha = if (read) ReadItemAlpha else SecondaryItemAlpha) .copy(alpha = if (read) DISABLED_ALPHA else SECONDARY_ALPHA),
) )
ProvideTextStyle(value = subtitleStyle) { ProvideTextStyle(value = subtitleStyle) {
if (date != null) { if (date != null) {
@ -159,7 +159,7 @@ fun MangaChapterListItem(
text = readProgress, text = readProgress,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
color = LocalContentColor.current.copy(alpha = ReadItemAlpha), color = LocalContentColor.current.copy(alpha = DISABLED_ALPHA),
) )
if (scanlator != null/* SY --> */ || sourceName != null/* SY <-- */) DotSeparatorText() if (scanlator != null/* SY --> */ || sourceName != null/* SY <-- */) DotSeparatorText()
} }

View file

@ -83,6 +83,7 @@ import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.i18n.kmk.KMR import tachiyomi.i18n.kmk.KMR
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.material.DISABLED_ALPHA
import tachiyomi.presentation.core.components.material.TextButton import tachiyomi.presentation.core.components.material.TextButton
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.pluralStringResource import tachiyomi.presentation.core.i18n.pluralStringResource
@ -209,7 +210,7 @@ fun MangaActionRow(
// SY <-- // SY <--
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f) val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = DISABLED_ALPHA)
// TODO: show something better when using custom interval // TODO: show something better when using custom interval
val nextUpdateDays = remember(nextUpdate) { val nextUpdateDays = remember(nextUpdate) {

View file

@ -76,7 +76,7 @@ private fun NewUpdateScreenPreview() {
changelogInfo = """ changelogInfo = """
## Yay ## Yay
Foobar Foobar
### More info ### More info
- Hello - Hello
- World - World

View file

@ -397,7 +397,7 @@ object SettingsAdvancedScreen : SearchableSettings {
chooseColorProfile.launch(arrayOf("*/*")) chooseColorProfile.launch(arrayOf("*/*"))
}, },
), ),
) ),
) )
} }

View file

@ -37,7 +37,7 @@ class OpenSourceLicensesScreen : Screen() {
name = it.name, name = it.name,
website = it.website, website = it.website,
license = it.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(), license = it.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(),
) ),
) )
}, },
) )

View file

@ -28,7 +28,7 @@ import tachiyomi.presentation.core.i18n.stringResource
class BackupSchemaScreen : Screen() { class BackupSchemaScreen : Screen() {
companion object { companion object {
const val title = "Backup file schema" const val TITLE = "Backup file schema"
} }
@Composable @Composable
@ -41,7 +41,7 @@ class BackupSchemaScreen : Screen() {
Scaffold( Scaffold(
topBar = { topBar = {
AppBar( AppBar(
title = title, title = TITLE,
navigateUp = navigator::pop, navigateUp = navigator::pop,
actions = { actions = {
AppBarActions( AppBarActions(
@ -50,7 +50,7 @@ class BackupSchemaScreen : Screen() {
title = stringResource(MR.strings.action_copy_to_clipboard), title = stringResource(MR.strings.action_copy_to_clipboard),
icon = Icons.Default.ContentCopy, icon = Icons.Default.ContentCopy,
onClick = { onClick = {
context.copyToClipboard(title, schema) context.copyToClipboard(TITLE, schema)
}, },
), ),
), ),

View file

@ -31,11 +31,11 @@ class DebugInfoScreen : Screen() {
itemsProvider = { itemsProvider = {
listOf( listOf(
Preference.PreferenceItem.TextPreference( Preference.PreferenceItem.TextPreference(
title = WorkerInfoScreen.title, title = WorkerInfoScreen.TITLE,
onClick = { navigator.push(WorkerInfoScreen()) }, onClick = { navigator.push(WorkerInfoScreen()) },
), ),
Preference.PreferenceItem.TextPreference( Preference.PreferenceItem.TextPreference(
title = BackupSchemaScreen.title, title = BackupSchemaScreen.TITLE,
onClick = { navigator.push(BackupSchemaScreen()) }, onClick = { navigator.push(BackupSchemaScreen()) },
), ),
getAppInfoGroup(), getAppInfoGroup(),

View file

@ -49,7 +49,7 @@ import java.time.ZoneId
class WorkerInfoScreen : Screen() { class WorkerInfoScreen : Screen() {
companion object { companion object {
const val title = "Worker info" const val TITLE = "Worker info"
} }
@Composable @Composable
@ -65,7 +65,7 @@ class WorkerInfoScreen : Screen() {
Scaffold( Scaffold(
topBar = { topBar = {
AppBar( AppBar(
title = title, title = TITLE,
navigateUp = navigator::pop, navigateUp = navigator::pop,
actions = { actions = {
AppBarActions( AppBarActions(
@ -74,7 +74,7 @@ class WorkerInfoScreen : Screen() {
title = stringResource(MR.strings.action_copy_to_clipboard), title = stringResource(MR.strings.action_copy_to_clipboard),
icon = Icons.Default.ContentCopy, icon = Icons.Default.ContentCopy,
onClick = { onClick = {
context.copyToClipboard(title, enqueued + finished + running) context.copyToClipboard(TITLE, enqueued + finished + running)
}, },
), ),
), ),
@ -159,7 +159,7 @@ class WorkerInfoScreen : Screen() {
Injekt.get<UiPreferences>().dateFormat().get(), Injekt.get<UiPreferences>().dateFormat().get(),
), ),
) )
appendLine("Next scheduled run: $timestamp",) appendLine("Next scheduled run: $timestamp")
appendLine("Attempt #${workInfo.runAttemptCount + 1}") appendLine("Attempt #${workInfo.runAttemptCount + 1}")
} }
appendLine() appendLine()

View file

@ -32,7 +32,9 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
private enum class State { private enum class State {
CHECKED, INVERSED, UNCHECKED CHECKED,
INVERSED,
UNCHECKED,
} }
@Composable @Composable

View file

@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha import tachiyomi.presentation.core.components.material.SECONDARY_ALPHA
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
@Composable @Composable
@ -73,7 +73,7 @@ private fun RowScope.BaseStatsItem(
style = subtitleStyle style = subtitleStyle
.copy( .copy(
color = MaterialTheme.colorScheme.onSurface color = MaterialTheme.colorScheme.onSurface
.copy(alpha = SecondaryItemAlpha), .copy(alpha = SECONDARY_ALPHA),
), ),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
) )

View file

@ -226,7 +226,7 @@ private fun ChapterText(
Text( Text(
text = buildAnnotatedString { text = buildAnnotatedString {
if (downloaded) { if (downloaded) {
appendInlineContent(DownloadedIconContentId) appendInlineContent(DOWNLOADED_ICON_ID)
append(' ') append(' ')
} }
append(name) append(name)
@ -236,7 +236,7 @@ private fun ChapterText(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleLarge,
inlineContent = persistentMapOf( inlineContent = persistentMapOf(
DownloadedIconContentId to InlineTextContent( DOWNLOADED_ICON_ID to InlineTextContent(
Placeholder( Placeholder(
width = 22.sp, width = 22.sp,
height = 22.sp, height = 22.sp,
@ -273,7 +273,7 @@ private val CardColor: CardColors
) )
private val VerticalSpacerSize = 24.dp private val VerticalSpacerSize = 24.dp
private const val DownloadedIconContentId = "downloaded" private const val DOWNLOADED_ICON_ID = "downloaded"
private fun previewChapter(name: String, scanlator: String, chapterNumber: Double) = Chapter.create().copy( private fun previewChapter(name: String, scanlator: String, chapterNumber: Double) = Chapter.create().copy(
id = 0L, id = 0L,

View file

@ -38,7 +38,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@ -58,8 +57,6 @@ import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
private const val UnsetStatusTextAlpha = 0.5F
@Composable @Composable
fun TrackInfoDialogHome( fun TrackInfoDialogHome(
trackItems: List<TrackItem>, trackItems: List<TrackItem>,
@ -211,10 +208,9 @@ private fun TrackInfoItem(
if (onScoreClick != null) { if (onScoreClick != null) {
VerticalDivider() VerticalDivider()
TrackDetailsItem( TrackDetailsItem(
modifier = Modifier modifier = Modifier.weight(1f),
.weight(1f) text = score,
.alpha(if (score == null) UnsetStatusTextAlpha else 1f), placeholder = stringResource(MR.strings.score),
text = score ?: stringResource(MR.strings.score),
onClick = onScoreClick, onClick = onScoreClick,
) )
} }
@ -243,6 +239,8 @@ private fun TrackInfoItem(
} }
} }
private const val UNSET_TEXT_ALPHA = 0.5F
@Composable @Composable
private fun TrackDetailsItem( private fun TrackDetailsItem(
text: String?, text: String?,
@ -263,7 +261,7 @@ private fun TrackDetailsItem(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = if (text == null) UnsetStatusTextAlpha else 1f), color = MaterialTheme.colorScheme.onSurface.copy(alpha = if (text == null) UNSET_TEXT_ALPHA else 1f),
) )
} }
} }

View file

@ -45,7 +45,7 @@ import eu.kanade.tachiyomi.ui.updates.UpdatesItem
import tachiyomi.domain.updates.model.UpdatesWithRelations import tachiyomi.domain.updates.model.UpdatesWithRelations
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.ListGroupHeader import tachiyomi.presentation.core.components.ListGroupHeader
import tachiyomi.presentation.core.components.material.ReadItemAlpha import tachiyomi.presentation.core.components.material.DISABLED_ALPHA
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.selectedBackground import tachiyomi.presentation.core.util.selectedBackground
@ -154,7 +154,7 @@ private fun UpdatesUiItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val haptic = LocalHapticFeedback.current val haptic = LocalHapticFeedback.current
val textAlpha = if (update.read) ReadItemAlpha else 1f val textAlpha = if (update.read) DISABLED_ALPHA else 1f
Row( Row(
modifier = modifier modifier = modifier
@ -238,7 +238,7 @@ private fun UpdatesUiItem(
Text( Text(
text = readProgress, text = readProgress,
maxLines = 1, maxLines = 1,
color = LocalContentColor.current.copy(alpha = ReadItemAlpha), color = LocalContentColor.current.copy(alpha = DISABLED_ALPHA),
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
} }

View file

@ -218,7 +218,7 @@ class BackupRestorer(
} }
private fun CoroutineScope.restoreExtensionRepos( private fun CoroutineScope.restoreExtensionRepos(
backupExtensionRepo: List<BackupExtensionRepos> backupExtensionRepo: List<BackupExtensionRepos>,
) = launch { ) = launch {
backupExtensionRepo backupExtensionRepo
.forEach { .forEach {

View file

@ -8,7 +8,7 @@ import uy.kohesive.injekt.api.get
class ExtensionRepoRestorer( class ExtensionRepoRestorer(
private val handler: DatabaseHandler = Injekt.get(), private val handler: DatabaseHandler = Injekt.get(),
private val getExtensionRepos: GetExtensionRepo = Injekt.get() private val getExtensionRepos: GetExtensionRepo = Injekt.get(),
) { ) {
suspend operator fun invoke( suspend operator fun invoke(
@ -32,7 +32,7 @@ class ExtensionRepoRestorer(
backupRepo.name, backupRepo.name,
backupRepo.shortName, backupRepo.shortName,
backupRepo.website, backupRepo.website,
backupRepo.signingKeyFingerprint backupRepo.signingKeyFingerprint,
) )
} }
} }

View file

@ -110,7 +110,7 @@ class MangaCoverFetcher(
source = ImageSource( source = ImageSource(
file = file.toOkioPath(), file = file.toOkioPath(),
fileSystem = FileSystem.SYSTEM, fileSystem = FileSystem.SYSTEM,
diskCacheKey = diskCacheKey diskCacheKey = diskCacheKey,
), ),
mimeType = "image/*", mimeType = "image/*",
dataSource = DataSource.DISK, dataSource = DataSource.DISK,

View file

@ -1,3 +1,5 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter

View file

@ -1,3 +1,5 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
class ChapterImpl : Chapter { class ChapterImpl : Chapter {

View file

@ -1,3 +1,5 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
import java.io.Serializable import java.io.Serializable

View file

@ -1,3 +1,5 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
class TrackImpl : Track { class TrackImpl : Track {

View file

@ -190,7 +190,7 @@ class Downloader(
fun clearQueue() { fun clearQueue() {
cancelDownloaderJob() cancelDownloaderJob()
_clearQueue() internalClearQueue()
notifier.dismissProgress() notifier.dismissProgress()
} }
@ -204,9 +204,12 @@ class Downloader(
val activeDownloadsFlow = queueState.transformLatest { queue -> val activeDownloadsFlow = queueState.transformLatest { queue ->
while (true) { while (true) {
val activeDownloads = queue.asSequence() val activeDownloads = queue.asSequence()
.filter { it.status.value <= Download.State.DOWNLOADING.value } // Ignore completed downloads, leave them in the queue // Ignore completed downloads, leave them in the queue
.filter { it.status.value <= Download.State.DOWNLOADING.value }
.groupBy { it.source } .groupBy { it.source }
.toList().take(5) // Concurrently download from 5 different sources .toList()
// Concurrently download from 5 different sources
.take(5)
.map { (_, downloads) -> downloads.first() } .map { (_, downloads) -> downloads.first() }
emit(activeDownloads) emit(activeDownloads)
@ -650,7 +653,7 @@ class Downloader(
chapter, chapter,
urls, urls,
categories, categories,
source.name source.name,
) )
// Remove the old file // Remove the old file
@ -710,7 +713,7 @@ class Downloader(
removeFromQueueIf { it.manga.id == manga.id } removeFromQueueIf { it.manga.id == manga.id }
} }
private fun _clearQueue() { private fun internalClearQueue() {
_queueState.update { _queueState.update {
it.forEach { download -> it.forEach { download ->
if (download.status == Download.State.DOWNLOADING || download.status == Download.State.QUEUE) { if (download.status == Download.State.DOWNLOADING || download.status == Download.State.QUEUE) {
@ -732,7 +735,7 @@ class Downloader(
} }
pause() pause()
_clearQueue() internalClearQueue()
addAllToQueue(downloads) addAllToQueue(downloads)
if (wasRunning) { if (wasRunning) {

View file

@ -778,7 +778,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
val constraints = Constraints( val constraints = Constraints(
requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) {
NetworkType.UNMETERED NetworkType.UNMETERED
} else { NetworkType.CONNECTED }, } else {
NetworkType.CONNECTED
},
requiresCharging = DEVICE_CHARGING in restrictions, requiresCharging = DEVICE_CHARGING in restrictions,
requiresBatteryNotLow = true, requiresBatteryNotLow = true,
) )

View file

@ -47,10 +47,10 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
return withIOContext { return withIOContext {
val query = """ val query = """
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
| id | id
| status | status
|} |}
|} |}
| |
""".trimMargin() """.trimMargin()
@ -65,7 +65,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
with(json) { with(json) {
authClient.newCall( authClient.newCall(
POST( POST(
apiUrl, API_URL,
body = payload.toString().toRequestBody(jsonMime), body = payload.toString().toRequestBody(jsonMime),
), ),
) )
@ -109,7 +109,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("completedAt", createDate(track.finished_reading_date)) put("completedAt", createDate(track.finished_reading_date))
} }
} }
authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
.awaitSuccess() .awaitSuccess()
track track
} }
@ -119,9 +119,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
withIOContext { withIOContext {
val query = """ val query = """
|mutation DeleteManga(${'$'}listId: Int) { |mutation DeleteManga(${'$'}listId: Int) {
|DeleteMediaListEntry(id: ${'$'}listId) { |DeleteMediaListEntry(id: ${'$'}listId) {
|deleted |deleted
|} |}
|} |}
| |
""".trimMargin() """.trimMargin()
@ -131,7 +131,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("listId", track.libraryId) put("listId", track.libraryId)
} }
} }
authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
.awaitSuccess() .awaitSuccess()
} }
} }
@ -172,7 +172,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
with(json) { with(json) {
authClient.newCall( authClient.newCall(
POST( POST(
apiUrl, API_URL,
body = payload.toString().toRequestBody(jsonMime), body = payload.toString().toRequestBody(jsonMime),
), ),
) )
@ -242,7 +242,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
with(json) { with(json) {
authClient.newCall( authClient.newCall(
POST( POST(
apiUrl, API_URL,
body = payload.toString().toRequestBody(jsonMime), body = payload.toString().toRequestBody(jsonMime),
), ),
) )
@ -286,7 +286,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
with(json) { with(json) {
authClient.newCall( authClient.newCall(
POST( POST(
apiUrl, API_URL,
body = payload.toString().toRequestBody(jsonMime), body = payload.toString().toRequestBody(jsonMime),
), ),
) )
@ -365,17 +365,17 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
companion object { companion object {
// Registered under KMK's MAL account // Registered under KMK's MAL account
private const val clientId = "16801" private const val CLIENT_ID = "16801"
private const val apiUrl = "https://graphql.anilist.co/" private const val API_URL = "https://graphql.anilist.co/"
private const val baseUrl = "https://anilist.co/api/v2/" private const val BASE_URL = "https://anilist.co/api/v2/"
private const val baseMangaUrl = "https://anilist.co/manga/" private const val BASE_MANGA_URL = "https://anilist.co/manga/"
fun mangaUrl(mediaId: Long): String { fun mangaUrl(mediaId: Long): String {
return baseMangaUrl + mediaId return BASE_MANGA_URL + mediaId
} }
fun authUrl(): Uri = "${baseUrl}oauth/authorize".toUri().buildUpon() fun authUrl(): Uri = "${BASE_URL}oauth/authorize".toUri().buildUpon()
.appendQueryParameter("client_id", clientId) .appendQueryParameter("client_id", CLIENT_ID)
.appendQueryParameter("response_type", "token") .appendQueryParameter("response_type", "token")
.build() .build()
} }

View file

@ -42,7 +42,7 @@ class BangumiApi(
.add("rating", track.score.toInt().toString()) .add("rating", track.score.toInt().toString())
.add("status", track.toBangumiStatus()) .add("status", track.toBangumiStatus())
.build() .build()
authClient.newCall(POST("$apiUrl/collection/${track.remote_id}/update", body = body)) authClient.newCall(POST("$API_URL/collection/${track.remote_id}/update", body = body))
.awaitSuccess() .awaitSuccess()
track track
} }
@ -55,7 +55,7 @@ class BangumiApi(
.add("rating", track.score.toInt().toString()) .add("rating", track.score.toInt().toString())
.add("status", track.toBangumiStatus()) .add("status", track.toBangumiStatus())
.build() .build()
authClient.newCall(POST("$apiUrl/collection/${track.remote_id}/update", body = sbody)) authClient.newCall(POST("$API_URL/collection/${track.remote_id}/update", body = sbody))
.awaitSuccess() .awaitSuccess()
// chapter update // chapter update
@ -64,7 +64,7 @@ class BangumiApi(
.build() .build()
authClient.newCall( authClient.newCall(
POST( POST(
"$apiUrl/subject/${track.remote_id}/update/watched_eps", "$API_URL/subject/${track.remote_id}/update/watched_eps",
body = body, body = body,
), ),
).awaitSuccess() ).awaitSuccess()
@ -75,7 +75,7 @@ class BangumiApi(
suspend fun search(search: String): List<TrackSearch> { suspend fun search(search: String): List<TrackSearch> {
return withIOContext { return withIOContext {
val url = "$apiUrl/search/subject/${URLEncoder.encode(search, StandardCharsets.UTF_8.name())}" val url = "$API_URL/search/subject/${URLEncoder.encode(search, StandardCharsets.UTF_8.name())}"
.toUri() .toUri()
.buildUpon() .buildUpon()
.appendQueryParameter("max_results", "20") .appendQueryParameter("max_results", "20")
@ -124,7 +124,7 @@ class BangumiApi(
suspend fun findLibManga(track: Track): Track? { suspend fun findLibManga(track: Track): Track? {
return withIOContext { return withIOContext {
with(json) { with(json) {
authClient.newCall(GET("$apiUrl/subject/${track.remote_id}")) authClient.newCall(GET("$API_URL/subject/${track.remote_id}"))
.awaitSuccess() .awaitSuccess()
.parseAs<JsonObject>() .parseAs<JsonObject>()
.let { jsonToSearch(it) } .let { jsonToSearch(it) }
@ -134,7 +134,7 @@ class BangumiApi(
suspend fun statusLibManga(track: Track): Track? { suspend fun statusLibManga(track: Track): Track? {
return withIOContext { return withIOContext {
val urlUserRead = "$apiUrl/collection/${track.remote_id}" val urlUserRead = "$API_URL/collection/${track.remote_id}"
val requestUserRead = Request.Builder() val requestUserRead = Request.Builder()
.url(urlUserRead) .url(urlUserRead)
.cacheControl(CacheControl.FORCE_NETWORK) .cacheControl(CacheControl.FORCE_NETWORK)
@ -171,41 +171,41 @@ class BangumiApi(
} }
private fun accessTokenRequest(code: String) = POST( private fun accessTokenRequest(code: String) = POST(
oauthUrl, OAUTH_URL,
body = FormBody.Builder() body = FormBody.Builder()
.add("grant_type", "authorization_code") .add("grant_type", "authorization_code")
.add("client_id", clientId) .add("client_id", CLIENT_ID)
.add("client_secret", clientSecret) .add("client_secret", CLIENT_SECRET)
.add("code", code) .add("code", code)
.add("redirect_uri", redirectUrl) .add("redirect_uri", REDIRECT_URL)
.build(), .build(),
) )
companion object { companion object {
private const val clientId = "bgm31586666817a5d03b" private const val CLIENT_ID = "bgm31586666817a5d03b"
private const val clientSecret = "3dad27cf8edcac6f55361d7971d219e1" private const val CLIENT_SECRET = "3dad27cf8edcac6f55361d7971d219e1"
private const val apiUrl = "https://api.bgm.tv" private const val API_URL = "https://api.bgm.tv"
private const val oauthUrl = "https://bgm.tv/oauth/access_token" private const val OAUTH_URL = "https://bgm.tv/oauth/access_token"
private const val loginUrl = "https://bgm.tv/oauth/authorize" private const val LOGIN_URL = "https://bgm.tv/oauth/authorize"
private const val redirectUrl = "komikku://bangumi-auth" private const val REDIRECT_URL = "komikku://bangumi-auth"
fun authUrl(): Uri = fun authUrl(): Uri =
loginUrl.toUri().buildUpon() LOGIN_URL.toUri().buildUpon()
.appendQueryParameter("client_id", clientId) .appendQueryParameter("client_id", CLIENT_ID)
.appendQueryParameter("response_type", "code") .appendQueryParameter("response_type", "code")
.appendQueryParameter("redirect_uri", redirectUrl) .appendQueryParameter("redirect_uri", REDIRECT_URL)
.build() .build()
fun refreshTokenRequest(token: String) = POST( fun refreshTokenRequest(token: String) = POST(
oauthUrl, OAUTH_URL,
body = FormBody.Builder() body = FormBody.Builder()
.add("grant_type", "refresh_token") .add("grant_type", "refresh_token")
.add("client_id", clientId) .add("client_id", CLIENT_ID)
.add("client_secret", clientSecret) .add("client_secret", CLIENT_SECRET)
.add("refresh_token", token) .add("refresh_token", token)
.add("redirect_uri", redirectUrl) .add("redirect_uri", REDIRECT_URL)
.build(), .build(),
) )
} }

View file

@ -66,7 +66,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
with(json) { with(json) {
authClient.newCall( authClient.newCall(
POST( POST(
"${baseUrl}library-entries", "${BASE_URL}library-entries",
headers = headersOf( headers = headersOf(
"Content-Type", "Content-Type",
"application/vnd.api+json", "application/vnd.api+json",
@ -104,7 +104,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
with(json) { with(json) {
authClient.newCall( authClient.newCall(
Request.Builder() Request.Builder()
.url("${baseUrl}library-entries/${track.remote_id}") .url("${BASE_URL}library-entries/${track.remote_id}")
.headers( .headers(
headersOf( headersOf(
"Content-Type", "Content-Type",
@ -130,7 +130,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
authClient authClient
.newCall( .newCall(
DELETE( DELETE(
"${baseUrl}library-entries/${track.remoteId}", "${BASE_URL}library-entries/${track.remoteId}",
headers = headersOf( headers = headersOf(
"Content-Type", "Content-Type",
"application/vnd.api+json", "application/vnd.api+json",
@ -143,7 +143,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
suspend fun search(query: String): List<TrackSearch> { suspend fun search(query: String): List<TrackSearch> {
return withIOContext { return withIOContext {
with(json) { with(json) {
authClient.newCall(GET(algoliaKeyUrl)) authClient.newCall(GET(ALGOLIA_KEY_URL))
.awaitSuccess() .awaitSuccess()
.parseAs<JsonObject>() .parseAs<JsonObject>()
.let { .let {
@ -157,16 +157,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
private suspend fun algoliaSearch(key: String, query: String): List<TrackSearch> { private suspend fun algoliaSearch(key: String, query: String): List<TrackSearch> {
return withIOContext { return withIOContext {
val jsonObject = buildJsonObject { val jsonObject = buildJsonObject {
put("params", "query=${URLEncoder.encode(query, StandardCharsets.UTF_8.name())}$algoliaFilter") put("params", "query=${URLEncoder.encode(query, StandardCharsets.UTF_8.name())}$ALGOLIA_FILTER")
} }
with(json) { with(json) {
client.newCall( client.newCall(
POST( POST(
algoliaUrl, ALGOLIA_URL,
headers = headersOf( headers = headersOf(
"X-Algolia-Application-Id", "X-Algolia-Application-Id",
algoliaAppId, ALGOLIA_APP_ID,
"X-Algolia-API-Key", "X-Algolia-API-Key",
key, key,
), ),
@ -187,7 +187,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
suspend fun findLibManga(track: Track, userId: String): Track? { suspend fun findLibManga(track: Track, userId: String): Track? {
return withIOContext { return withIOContext {
val url = "${baseUrl}library-entries".toUri().buildUpon() val url = "${BASE_URL}library-entries".toUri().buildUpon()
.encodedQuery("filter[manga_id]=${track.remote_id}&filter[user_id]=$userId") .encodedQuery("filter[manga_id]=${track.remote_id}&filter[user_id]=$userId")
.appendQueryParameter("include", "manga") .appendQueryParameter("include", "manga")
.build() .build()
@ -210,7 +210,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
suspend fun getLibManga(track: Track): Track { suspend fun getLibManga(track: Track): Track {
return withIOContext { return withIOContext {
val url = "${baseUrl}library-entries".toUri().buildUpon() val url = "${BASE_URL}library-entries".toUri().buildUpon()
.encodedQuery("filter[id]=${track.remote_id}") .encodedQuery("filter[id]=${track.remote_id}")
.appendQueryParameter("include", "manga") .appendQueryParameter("include", "manga")
.build() .build()
@ -237,11 +237,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
.add("username", username) .add("username", username)
.add("password", password) .add("password", password)
.add("grant_type", "password") .add("grant_type", "password")
.add("client_id", clientId) .add("client_id", CLIENT_ID)
.add("client_secret", clientSecret) .add("client_secret", CLIENT_SECRET)
.build() .build()
with(json) { with(json) {
client.newCall(POST(loginUrl, body = formBody)) client.newCall(POST(LOGIN_URL, body = formBody))
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
} }
@ -250,7 +250,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
suspend fun getCurrentUser(): String { suspend fun getCurrentUser(): String {
return withIOContext { return withIOContext {
val url = "${baseUrl}users".toUri().buildUpon() val url = "${BASE_URL}users".toUri().buildUpon()
.encodedQuery("filter[self]=true") .encodedQuery("filter[self]=true")
.build() .build()
with(json) { with(json) {
@ -265,35 +265,31 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
} }
companion object { companion object {
private const val clientId = private const val CLIENT_ID = "dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd"
"dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd" private const val CLIENT_SECRET = "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151"
private const val clientSecret =
"54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151"
private const val baseUrl = "https://kitsu.app/api/edge/" private const val BASE_URL = "https://kitsu.app/api/edge/"
private const val loginUrl = "https://kitsu.app/api/oauth/token" private const val LOGIN_URL = "https://kitsu.app/api/oauth/token"
private const val baseMangaUrl = "https://kitsu.app/manga/" private const val BASE_MANGA_URL = "https://kitsu.app/manga/"
private const val algoliaKeyUrl = "https://kitsu.app/api/edge/algolia-keys/media/" private const val ALGOLIA_KEY_URL = "https://kitsu.app/api/edge/algolia-keys/media/"
private const val algoliaUrl = private const val ALGOLIA_APP_ID = "AWQO5J657S"
"https://AWQO5J657S-dsn.algolia.net/1/indexes/production_media/query/" private const val ALGOLIA_URL = "https://$ALGOLIA_APP_ID-dsn.algolia.net/1/indexes/production_media/query/"
private const val algoliaAppId = "AWQO5J657S" private const val ALGOLIA_FILTER = "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=" +
private const val algoliaFilter = "%5B%22synopsis%22%2C%22averageRating%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22" +
"&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=" + "posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D"
"%5B%22synopsis%22%2C%22averageRating%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22" +
"posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D"
fun mangaUrl(remoteId: Long): String { fun mangaUrl(remoteId: Long): String {
return baseMangaUrl + remoteId return BASE_MANGA_URL + remoteId
} }
fun refreshTokenRequest(token: String) = POST( fun refreshTokenRequest(token: String) = POST(
loginUrl, LOGIN_URL,
body = FormBody.Builder() body = FormBody.Builder()
.add("grant_type", "refresh_token") .add("grant_type", "refresh_token")
.add("refresh_token", token) .add("refresh_token", token)
.add("client_id", clientId) .add("client_id", CLIENT_ID)
.add("client_secret", clientSecret) .add("client_secret", CLIENT_SECRET)
.build(), .build(),
) )
} }

View file

@ -6,8 +6,8 @@ import java.util.Locale
object KitsuDateHelper { object KitsuDateHelper {
private const val pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" private const val PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
private val formatter = SimpleDateFormat(pattern, Locale.ENGLISH) private val formatter = SimpleDateFormat(PATTERN, Locale.ENGLISH)
fun convert(dateValue: Long): String? { fun convert(dateValue: Long): String? {
if (dateValue == 0L) return null if (dateValue == 0L) return null

View file

@ -1,3 +1,5 @@
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
package eu.kanade.tachiyomi.data.track.model package eu.kanade.tachiyomi.data.track.model
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track

View file

@ -54,7 +54,7 @@ class ShikimoriApi(
} }
authClient.newCall( authClient.newCall(
POST( POST(
"$apiUrl/v2/user_rates", "$API_URL/v2/user_rates",
body = payload.toString().toRequestBody(jsonMime), body = payload.toString().toRequestBody(jsonMime),
), ),
).awaitSuccess() ).awaitSuccess()
@ -72,14 +72,14 @@ class ShikimoriApi(
suspend fun deleteLibManga(track: DomainTrack) { suspend fun deleteLibManga(track: DomainTrack) {
withIOContext { withIOContext {
authClient authClient
.newCall(DELETE("$apiUrl/v2/user_rates/${track.libraryId}")) .newCall(DELETE("$API_URL/v2/user_rates/${track.libraryId}"))
.awaitSuccess() .awaitSuccess()
} }
} }
suspend fun search(search: String): List<TrackSearch> { suspend fun search(search: String): List<TrackSearch> {
return withIOContext { return withIOContext {
val url = "$apiUrl/mangas".toUri().buildUpon() val url = "$API_URL/mangas".toUri().buildUpon()
.appendQueryParameter("order", "popularity") .appendQueryParameter("order", "popularity")
.appendQueryParameter("search", search) .appendQueryParameter("search", search)
.appendQueryParameter("limit", "20") .appendQueryParameter("limit", "20")
@ -102,10 +102,10 @@ class ShikimoriApi(
remote_id = obj["id"]!!.jsonPrimitive.long remote_id = obj["id"]!!.jsonPrimitive.long
title = obj["name"]!!.jsonPrimitive.content title = obj["name"]!!.jsonPrimitive.content
total_chapters = obj["chapters"]!!.jsonPrimitive.long total_chapters = obj["chapters"]!!.jsonPrimitive.long
cover_url = baseUrl + obj["image"]!!.jsonObject["preview"]!!.jsonPrimitive.content cover_url = BASE_URL + obj["image"]!!.jsonObject["preview"]!!.jsonPrimitive.content
summary = "" summary = ""
score = obj["score"]!!.jsonPrimitive.double score = obj["score"]!!.jsonPrimitive.double
tracking_url = baseUrl + obj["url"]!!.jsonPrimitive.content tracking_url = BASE_URL + obj["url"]!!.jsonPrimitive.content
publishing_status = obj["status"]!!.jsonPrimitive.content publishing_status = obj["status"]!!.jsonPrimitive.content
publishing_type = obj["kind"]!!.jsonPrimitive.content publishing_type = obj["kind"]!!.jsonPrimitive.content
start_date = obj["aired_on"]!!.jsonPrimitive.contentOrNull ?: "" start_date = obj["aired_on"]!!.jsonPrimitive.contentOrNull ?: ""
@ -121,13 +121,13 @@ class ShikimoriApi(
last_chapter_read = obj["chapters"]!!.jsonPrimitive.double last_chapter_read = obj["chapters"]!!.jsonPrimitive.double
score = obj["score"]!!.jsonPrimitive.int.toDouble() score = obj["score"]!!.jsonPrimitive.int.toDouble()
status = toTrackStatus(obj["status"]!!.jsonPrimitive.content) status = toTrackStatus(obj["status"]!!.jsonPrimitive.content)
tracking_url = baseUrl + mangas["url"]!!.jsonPrimitive.content tracking_url = BASE_URL + mangas["url"]!!.jsonPrimitive.content
} }
} }
suspend fun findLibManga(track: Track, userId: String): Track? { suspend fun findLibManga(track: Track, userId: String): Track? {
return withIOContext { return withIOContext {
val urlMangas = "$apiUrl/mangas".toUri().buildUpon() val urlMangas = "$API_URL/mangas".toUri().buildUpon()
.appendPath(track.remote_id.toString()) .appendPath(track.remote_id.toString())
.build() .build()
val mangas = with(json) { val mangas = with(json) {
@ -136,7 +136,7 @@ class ShikimoriApi(
.parseAs<JsonObject>() .parseAs<JsonObject>()
} }
val url = "$apiUrl/v2/user_rates".toUri().buildUpon() val url = "$API_URL/v2/user_rates".toUri().buildUpon()
.appendQueryParameter("user_id", userId) .appendQueryParameter("user_id", userId)
.appendQueryParameter("target_id", track.remote_id.toString()) .appendQueryParameter("target_id", track.remote_id.toString())
.appendQueryParameter("target_type", "Manga") .appendQueryParameter("target_type", "Manga")
@ -160,7 +160,7 @@ class ShikimoriApi(
suspend fun getCurrentUser(): Int { suspend fun getCurrentUser(): Int {
return with(json) { return with(json) {
authClient.newCall(GET("$apiUrl/users/whoami")) authClient.newCall(GET("$API_URL/users/whoami"))
.awaitSuccess() .awaitSuccess()
.parseAs<JsonObject>() .parseAs<JsonObject>()
.let { .let {
@ -180,39 +180,39 @@ class ShikimoriApi(
} }
private fun accessTokenRequest(code: String) = POST( private fun accessTokenRequest(code: String) = POST(
oauthUrl, OAUTH_URL,
body = FormBody.Builder() body = FormBody.Builder()
.add("grant_type", "authorization_code") .add("grant_type", "authorization_code")
.add("client_id", clientId) .add("client_id", CLIENT_ID)
.add("client_secret", clientSecret) .add("client_secret", CLIENT_SECRET)
.add("code", code) .add("code", code)
.add("redirect_uri", redirectUrl) .add("redirect_uri", REDIRECT_URL)
.build(), .build(),
) )
companion object { companion object {
private const val clientId = "hst3O_VlZ0HrrXcnZAd6m-SCIc1_mv5cQV-3nQCdJ0E" private const val CLIENT_ID = "hst3O_VlZ0HrrXcnZAd6m-SCIc1_mv5cQV-3nQCdJ0E"
private const val clientSecret = "n1Pn9AIKvUhDzjehfPt_5nk7xbr4wSnas6djggw_AjE" private const val CLIENT_SECRET = "n1Pn9AIKvUhDzjehfPt_5nk7xbr4wSnas6djggw_AjE"
private const val baseUrl = "https://shikimori.one" private const val BASE_URL = "https://shikimori.one"
private const val apiUrl = "$baseUrl/api" private const val API_URL = "$BASE_URL/api"
private const val oauthUrl = "$baseUrl/oauth/token" private const val OAUTH_URL = "$BASE_URL/oauth/token"
private const val loginUrl = "$baseUrl/oauth/authorize" private const val LOGIN_URL = "$BASE_URL/oauth/authorize"
private const val redirectUrl = "komikku://shikimori-auth" private const val REDIRECT_URL = "komikku://shikimori-auth"
fun authUrl(): Uri = loginUrl.toUri().buildUpon() fun authUrl(): Uri = LOGIN_URL.toUri().buildUpon()
.appendQueryParameter("client_id", clientId) .appendQueryParameter("client_id", CLIENT_ID)
.appendQueryParameter("redirect_uri", redirectUrl) .appendQueryParameter("redirect_uri", REDIRECT_URL)
.appendQueryParameter("response_type", "code") .appendQueryParameter("response_type", "code")
.build() .build()
fun refreshTokenRequest(token: String) = POST( fun refreshTokenRequest(token: String) = POST(
oauthUrl, OAUTH_URL,
body = FormBody.Builder() body = FormBody.Builder()
.add("grant_type", "refresh_token") .add("grant_type", "refresh_token")
.add("client_id", clientId) .add("client_id", CLIENT_ID)
.add("client_secret", clientSecret) .add("client_secret", CLIENT_SECRET)
.add("refresh_token", token) .add("refresh_token", token)
.build(), .build(),
) )

View file

@ -69,17 +69,17 @@ class ExtensionManager(
private val iconMap = mutableMapOf<String, Drawable>() private val iconMap = mutableMapOf<String, Drawable>()
private val _installedExtensionsMapFlow = MutableStateFlow(emptyMap<String, Extension.Installed>()) private val installedExtensionMapFlow = MutableStateFlow(emptyMap<String, Extension.Installed>())
val installedExtensionsFlow = _installedExtensionsMapFlow.mapExtensions(scope) val installedExtensionsFlow = installedExtensionMapFlow.mapExtensions(scope)
private val _availableExtensionsMapFlow = MutableStateFlow(emptyMap<String, Extension.Available>()) private val availableExtensionMapFlow = MutableStateFlow(emptyMap<String, Extension.Available>())
// SY --> // SY -->
val availableExtensionsFlow = _availableExtensionsMapFlow.map { it.filterNotBlacklisted().values.toList() } val availableExtensionsFlow = availableExtensionMapFlow.map { it.filterNotBlacklisted().values.toList() }
.stateIn(scope, SharingStarted.Lazily, _availableExtensionsMapFlow.value.values.toList()) .stateIn(scope, SharingStarted.Lazily, availableExtensionMapFlow.value.values.toList())
// SY <-- // SY <--
private val _untrustedExtensionsMapFlow = MutableStateFlow(emptyMap<String, Extension.Untrusted>()) private val untrustedExtensionMapFlow = MutableStateFlow(emptyMap<String, Extension.Untrusted>())
val untrustedExtensionsFlow = _untrustedExtensionsMapFlow.mapExtensions(scope) val untrustedExtensionsFlow = untrustedExtensionMapFlow.mapExtensions(scope)
init { init {
initExtensions() initExtensions()
@ -89,7 +89,7 @@ class ExtensionManager(
private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet() private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet()
fun getAppIconForSource(sourceId: Long): Drawable? { fun getAppIconForSource(sourceId: Long): Drawable? {
val pkgName = _installedExtensionsMapFlow.value.values val pkgName = installedExtensionMapFlow.value.values
.find { ext -> .find { ext ->
ext.sources.any { it.id == sourceId } ext.sources.any { it.id == sourceId }
} }
@ -128,11 +128,11 @@ class ExtensionManager(
private fun initExtensions() { private fun initExtensions() {
val extensions = ExtensionLoader.loadExtensions(context) val extensions = ExtensionLoader.loadExtensions(context)
_installedExtensionsMapFlow.value = extensions installedExtensionMapFlow.value = extensions
.filterIsInstance<LoadResult.Success>() .filterIsInstance<LoadResult.Success>()
.associate { it.extension.pkgName to it.extension } .associate { it.extension.pkgName to it.extension }
_untrustedExtensionsMapFlow.value = extensions untrustedExtensionMapFlow.value = extensions
.filterIsInstance<LoadResult.Untrusted>() .filterIsInstance<LoadResult.Untrusted>()
.associate { it.extension.pkgName to it.extension } .associate { it.extension.pkgName to it.extension }
// SY --> // SY -->
@ -159,7 +159,7 @@ class ExtensionManager(
// EXH <-- // EXH <--
/** /**
* Finds the available extensions in the [api] and updates [_availableExtensionsMapFlow]. * Finds the available extensions in the [api] and updates [availableExtensionMapFlow].
*/ */
suspend fun findAvailableExtensions() { suspend fun findAvailableExtensions() {
val extensions: List<Extension.Available> = try { val extensions: List<Extension.Available> = try {
@ -172,7 +172,7 @@ class ExtensionManager(
enableAdditionalSubLanguages(extensions) enableAdditionalSubLanguages(extensions)
_availableExtensionsMapFlow.value = extensions.associateBy { it.pkgName } availableExtensionMapFlow.value = extensions.associateBy { it.pkgName }
updatedInstalledExtensionsStatuses(extensions) updatedInstalledExtensionsStatuses(extensions)
setupAvailableExtensionsSourcesDataMap(extensions) setupAvailableExtensionsSourcesDataMap(extensions)
} }
@ -218,7 +218,7 @@ class ExtensionManager(
return return
} }
val installedExtensionsMap = _installedExtensionsMapFlow.value.toMutableMap() val installedExtensionsMap = installedExtensionMapFlow.value.toMutableMap()
var changed = false var changed = false
for ((pkgName, extension) in installedExtensionsMap) { for ((pkgName, extension) in installedExtensionsMap) {
val availableExt = availableExtensions.find { it.pkgName == pkgName } val availableExt = availableExtensions.find { it.pkgName == pkgName }
@ -247,7 +247,7 @@ class ExtensionManager(
} }
} }
if (changed) { if (changed) {
_installedExtensionsMapFlow.value = installedExtensionsMap installedExtensionMapFlow.value = installedExtensionsMap
} }
updatePendingUpdatesCount() updatePendingUpdatesCount()
} }
@ -271,7 +271,7 @@ class ExtensionManager(
* @param extension The extension to be updated. * @param extension The extension to be updated.
*/ */
fun updateExtension(extension: Extension.Installed): Flow<InstallStep> { fun updateExtension(extension: Extension.Installed): Flow<InstallStep> {
val availableExt = _availableExtensionsMapFlow.value[extension.pkgName] ?: return emptyFlow() val availableExt = availableExtensionMapFlow.value[extension.pkgName] ?: return emptyFlow()
return installExtension(availableExt) return installExtension(availableExt)
} }
@ -308,11 +308,11 @@ class ExtensionManager(
* @param extension the extension to trust * @param extension the extension to trust
*/ */
suspend fun trust(extension: Extension.Untrusted) { suspend fun trust(extension: Extension.Untrusted) {
_untrustedExtensionsMapFlow.value[extension.pkgName] ?: return untrustedExtensionMapFlow.value[extension.pkgName] ?: return
trustExtension.trust(extension.pkgName, extension.versionCode, extension.signatureHash) trustExtension.trust(extension.pkgName, extension.versionCode, extension.signatureHash)
_untrustedExtensionsMapFlow.value -= extension.pkgName untrustedExtensionMapFlow.value -= extension.pkgName
ExtensionLoader.loadExtensionFromPkgName(context, extension.pkgName) ExtensionLoader.loadExtensionFromPkgName(context, extension.pkgName)
.let { it as? LoadResult.Success } .let { it as? LoadResult.Success }
@ -332,7 +332,7 @@ class ExtensionManager(
} }
// SY <-- // SY <--
_installedExtensionsMapFlow.value += extension installedExtensionMapFlow.value += extension
} }
/** /**
@ -349,7 +349,7 @@ class ExtensionManager(
} }
// SY <-- // SY <--
_installedExtensionsMapFlow.value += extension installedExtensionMapFlow.value += extension
} }
/** /**
@ -359,8 +359,8 @@ class ExtensionManager(
* @param pkgName The package name of the uninstalled application. * @param pkgName The package name of the uninstalled application.
*/ */
private fun unregisterExtension(pkgName: String) { private fun unregisterExtension(pkgName: String) {
_installedExtensionsMapFlow.value -= pkgName installedExtensionMapFlow.value -= pkgName
_untrustedExtensionsMapFlow.value -= pkgName untrustedExtensionMapFlow.value -= pkgName
} }
/** /**
@ -379,8 +379,8 @@ class ExtensionManager(
} }
override fun onExtensionUntrusted(extension: Extension.Untrusted) { override fun onExtensionUntrusted(extension: Extension.Untrusted) {
_installedExtensionsMapFlow.value -= extension.pkgName installedExtensionMapFlow.value -= extension.pkgName
_untrustedExtensionsMapFlow.value += extension untrustedExtensionMapFlow.value += extension
updatePendingUpdatesCount() updatePendingUpdatesCount()
} }
@ -404,14 +404,14 @@ class ExtensionManager(
private fun Extension.Installed.updateExists(availableExtension: Extension.Available? = null): Boolean { private fun Extension.Installed.updateExists(availableExtension: Extension.Available? = null): Boolean {
val availableExt = availableExtension val availableExt = availableExtension
?: _availableExtensionsMapFlow.value[pkgName] ?: availableExtensionMapFlow.value[pkgName]
?: return false ?: return false
return (availableExt.versionCode > versionCode || availableExt.libVersion > libVersion) return (availableExt.versionCode > versionCode || availableExt.libVersion > libVersion)
} }
private fun updatePendingUpdatesCount() { private fun updatePendingUpdatesCount() {
val pendingUpdateCount = _installedExtensionsMapFlow.value.values.count { it.hasUpdate } val pendingUpdateCount = installedExtensionMapFlow.value.values.count { it.hasUpdate }
preferences.extensionUpdatesCount().set(pendingUpdateCount) preferences.extensionUpdatesCount().set(pendingUpdateCount)
if (pendingUpdateCount == 0) { if (pendingUpdateCount == 0) {
ExtensionUpdateNotifier(context).dismiss() ExtensionUpdateNotifier(context).dismiss()

View file

@ -1,7 +1,13 @@
package eu.kanade.tachiyomi.extension.model package eu.kanade.tachiyomi.extension.model
enum class InstallStep { enum class InstallStep {
Idle, Pending, Downloading, Installing, Installed, Error; Idle,
Pending,
Downloading,
Installing,
Installed,
Error,
;
fun isCompleted(): Boolean { fun isCompleted(): Boolean {
return this == Installed || this == Error || this == Idle return this == Installed || this == Error || this == Idle

View file

@ -140,7 +140,7 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser
val incognitoModeFlow = preferences.incognitoMode().changes() val incognitoModeFlow = preferences.incognitoMode().changes()
combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode -> combine(secureScreenFlow, incognitoModeFlow) { secureScreen, incognitoMode ->
secureScreen == SecurityPreferences.SecureScreenMode.ALWAYS || secureScreen == SecurityPreferences.SecureScreenMode.ALWAYS ||
secureScreen == SecurityPreferences.SecureScreenMode.INCOGNITO && incognitoMode (secureScreen == SecurityPreferences.SecureScreenMode.INCOGNITO && incognitoMode)
} }
.onEach(activity.window::setSecureScreen) .onEach(activity.window::setSecureScreen)
.launchIn(activity.lifecycleScope) .launchIn(activity.lifecycleScope)

View file

@ -41,7 +41,7 @@ class ExtensionsScreenModel(
private val getExtensions: GetExtensionsByType = Injekt.get(), private val getExtensions: GetExtensionsByType = Injekt.get(),
) : StateScreenModel<ExtensionsScreenModel.State>(State()) { ) : StateScreenModel<ExtensionsScreenModel.State>(State()) {
private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf()) private val currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf())
init { init {
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
@ -62,14 +62,20 @@ class ExtensionsScreenModel(
it.name.contains(input, ignoreCase = true) || it.name.contains(input, ignoreCase = true) ||
it.baseUrl.contains(input, ignoreCase = true) || it.baseUrl.contains(input, ignoreCase = true) ||
it.id == input.toLongOrNull() it.id == input.toLongOrNull()
} || extension.name.contains(input, ignoreCase = true) } ||
extension.name.contains(input, ignoreCase = true)
} }
is Extension.Installed -> { is Extension.Installed -> {
extension.sources.any { extension.sources.any {
it.name.contains(input, ignoreCase = true) || it.name.contains(input, ignoreCase = true) ||
it.id == input.toLongOrNull() || it.id == input.toLongOrNull() ||
if (it is HttpSource) { it.baseUrl.contains(input, ignoreCase = true) } else false if (it is HttpSource) {
} || extension.name.contains(input, ignoreCase = true) it.baseUrl.contains(input, ignoreCase = true)
} else {
false
}
} ||
extension.name.contains(input, ignoreCase = true)
} }
is Extension.Untrusted -> extension.name.contains(input, ignoreCase = true) is Extension.Untrusted -> extension.name.contains(input, ignoreCase = true)
} }
@ -83,7 +89,7 @@ class ExtensionsScreenModel(
// KMK --> // KMK -->
state.map { it.nsfwOnly }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS), state.map { it.nsfwOnly }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS),
// KMK <-- // KMK <--
_currentDownloads, currentDownloads,
getExtensions.subscribe(), getExtensions.subscribe(),
) { query, nsfwOnly, downloads, (_updates, _installed, _available, _untrusted) -> ) { query, nsfwOnly, downloads, (_updates, _installed, _available, _untrusted) ->
val searchQuery = query ?: "" val searchQuery = query ?: ""
@ -181,11 +187,11 @@ class ExtensionsScreenModel(
} }
private fun addDownloadState(extension: Extension, installStep: InstallStep) { private fun addDownloadState(extension: Extension, installStep: InstallStep) {
_currentDownloads.update { it + Pair(extension.pkgName, installStep) } currentDownloads.update { it + Pair(extension.pkgName, installStep) }
} }
private fun removeDownloadState(extension: Extension) { private fun removeDownloadState(extension: Extension) {
_currentDownloads.update { it - extension.pkgName } currentDownloads.update { it - extension.pkgName }
} }
private suspend fun Flow<InstallStep>.collectToInstallUpdate(extension: Extension) = private suspend fun Flow<InstallStep>.collectToInstallUpdate(extension: Extension) =

View file

@ -71,8 +71,8 @@ object HomeScreen : Screen() {
private val openTabEvent = Channel<Tab>() private val openTabEvent = Channel<Tab>()
private val showBottomNavEvent = Channel<Boolean>() private val showBottomNavEvent = Channel<Boolean>()
private const val TabFadeDuration = 200 private const val TAB_FADE_DURATION = 200
private const val TabNavigatorKey = "HomeTabs" private const val TAB_NAVIGATOR_KEY = "HomeTabs"
private val tabs = listOf( private val tabs = listOf(
LibraryTab, LibraryTab,
@ -95,7 +95,7 @@ object HomeScreen : Screen() {
TabNavigator( TabNavigator(
tab = LibraryTab, tab = LibraryTab,
key = TabNavigatorKey, key = TAB_NAVIGATOR_KEY,
) { tabNavigator -> ) { tabNavigator ->
// Provide usable navigator to content screen // Provide usable navigator to content screen
CompositionLocalProvider(LocalNavigator provides navigator) { CompositionLocalProvider(LocalNavigator provides navigator) {
@ -145,8 +145,11 @@ object HomeScreen : Screen() {
AnimatedContent( AnimatedContent(
targetState = tabNavigator.current, targetState = tabNavigator.current,
transitionSpec = { transitionSpec = {
materialFadeThroughIn(initialScale = 1f, durationMillis = TabFadeDuration) togetherWith materialFadeThroughIn(
materialFadeThroughOut(durationMillis = TabFadeDuration) initialScale = 1f,
durationMillis = TAB_FADE_DURATION,
) togetherWith
materialFadeThroughOut(durationMillis = TAB_FADE_DURATION)
}, },
label = "tabContent", label = "tabContent",
contentKey = { it.key } contentKey = { it.key }

View file

@ -384,8 +384,9 @@ class LibraryScreenModel(
// Map<MangaId, List<Track>> // Map<MangaId, List<Track>>
trackMap: Map<Long, List<Track>>, trackMap: Map<Long, List<Track>>,
loggedInTrackerIds: Set<Long>, loggedInTrackerIds: Set<Long>,
/* SY --> */ // SY -->
groupSort: LibrarySort? = null, /* SY <-- */ groupSort: LibrarySort? = null,
// SY <--
): LibraryMap { ): LibraryMap {
// SY --> // SY -->
val listOfTags by lazy { val listOfTags by lazy {

View file

@ -34,7 +34,7 @@ class LibrarySettingsScreenModel(
.stateIn( .stateIn(
scope = screenModelScope, scope = screenModelScope,
started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds), started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds),
initialValue = trackerManager.loggedInTrackers() initialValue = trackerManager.loggedInTrackers(),
) )
// SY --> // SY -->

View file

@ -109,8 +109,8 @@ private class MoreScreenModel(
val showNavHistory by uiPreferences.showNavHistory().asState(screenModelScope) val showNavHistory by uiPreferences.showNavHistory().asState(screenModelScope)
// SY <-- // SY <--
private var _state: MutableStateFlow<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped) private var _downloadQueueState: MutableStateFlow<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped)
val downloadQueueState: StateFlow<DownloadQueueState> = _state.asStateFlow() val downloadQueueState: StateFlow<DownloadQueueState> = _downloadQueueState.asStateFlow()
init { init {
// Handle running/paused status change and queue progress updating // Handle running/paused status change and queue progress updating
@ -121,7 +121,7 @@ private class MoreScreenModel(
) { isRunning, downloadQueue -> Pair(isRunning, downloadQueue.size) } ) { isRunning, downloadQueue -> Pair(isRunning, downloadQueue.size) }
.collectLatest { (isDownloading, downloadQueueSize) -> .collectLatest { (isDownloading, downloadQueueSize) ->
val pendingDownloadExists = downloadQueueSize != 0 val pendingDownloadExists = downloadQueueSize != 0
_state.value = when { _downloadQueueState.value = when {
!pendingDownloadExists -> DownloadQueueState.Stopped !pendingDownloadExists -> DownloadQueueState.Stopped
!isDownloading -> DownloadQueueState.Paused(downloadQueueSize) !isDownloading -> DownloadQueueState.Paused(downloadQueueSize)
else -> DownloadQueueState.Downloading(downloadQueueSize) else -> DownloadQueueState.Downloading(downloadQueueSize)

View file

@ -191,7 +191,7 @@ class ReaderPreferences(
enum class FlashColor { enum class FlashColor {
BLACK, BLACK,
WHITE, WHITE,
WHITE_BLACK WHITE_BLACK,
} }
enum class TappingInvertMode( enum class TappingInvertMode(

View file

@ -398,7 +398,9 @@ open class ReaderPageImageView @JvmOverloads constructor(
) )
enum class ZoomStartPosition { enum class ZoomStartPosition {
LEFT, CENTER, RIGHT LEFT,
CENTER,
RIGHT,
} }
} }

View file

@ -43,15 +43,16 @@ class ReaderTransitionView @JvmOverloads constructor(
Data( Data(
transition = transition, transition = transition,
currChapterDownloaded = transition.from.pageLoader?.isLocal == true, currChapterDownloaded = transition.from.pageLoader?.isLocal == true,
goingToChapterDownloaded = manga.isLocal() || transition.to?.chapter?.let { goingToChapter -> goingToChapterDownloaded = manga.isLocal() ||
downloadManager.isChapterDownloaded( transition.to?.chapter?.let { goingToChapter ->
chapterName = goingToChapter.name, downloadManager.isChapterDownloaded(
chapterScanlator = goingToChapter.scanlator, chapterName = goingToChapter.name,
mangaTitle = /* SY --> */ manga.ogTitle, /* SY <-- */ chapterScanlator = goingToChapter.scanlator,
sourceId = manga.source, mangaTitle = /* SY --> */ manga.ogTitle, /* SY <-- */
skipCache = true, sourceId = manga.source,
) skipCache = true,
} ?: false, )
} ?: false,
) )
} else { } else {
null null

View file

@ -115,7 +115,9 @@ class PagerViewerAdapter(
// Add next chapter transition and pages. // Add next chapter transition and pages.
nextTransition = ChapterTransition.Next(chapters.currChapter, chapters.nextChapter) nextTransition = ChapterTransition.Next(chapters.currChapter, chapters.nextChapter)
.also { .also {
if (nextHasMissingChapters || forceTransition || if (
nextHasMissingChapters ||
forceTransition ||
chapters.nextChapter?.state !is ReaderChapter.State.Loaded chapters.nextChapter?.state !is ReaderChapter.State.Loaded
) { ) {
newItems.add(it) newItems.add(it)

View file

@ -89,7 +89,7 @@ class WebtoonConfig(
readerPreferences.webtoonDisableZoomOut() readerPreferences.webtoonDisableZoomOut()
.register( .register(
{ zoomOutDisabled = it }, { zoomOutDisabled = it },
{ zoomPropertyChangedListener?.invoke(it) } { zoomPropertyChangedListener?.invoke(it) },
) )
readerPreferences.webtoonDoubleTapZoomEnabled() readerPreferences.webtoonDoubleTapZoomEnabled()

View file

@ -182,7 +182,11 @@ class WebtoonRecyclerView @JvmOverloads constructor(
setScaleRate(currentScale) setScaleRate(currentScale)
layoutParams.height = if (currentScale < 1) { (originalHeight / currentScale).toInt() } else { originalHeight } layoutParams.height = if (currentScale < 1) {
(originalHeight / currentScale).toInt()
} else {
originalHeight
}
halfHeight = layoutParams.height / 2 halfHeight = layoutParams.height / 2
if (currentScale != DEFAULT_RATE) { if (currentScale != DEFAULT_RATE) {

View file

@ -95,7 +95,7 @@ class WebtoonViewer(
.threshold .threshold
init { init {
recycler.setItemViewCacheSize(RecyclerViewCacheSize) recycler.setItemViewCacheSize(RECYCLER_VIEW_CACHE_SIZE)
recycler.isVisible = false // Don't let the recycler layout yet recycler.isVisible = false // Don't let the recycler layout yet
recycler.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) recycler.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
recycler.isFocusable = false recycler.isFocusable = false
@ -412,4 +412,4 @@ class WebtoonViewer(
} }
// Double the cache size to reduce rebinds/recycles incurred by the extra layout space on scroll direction changes // Double the cache size to reduce rebinds/recycles incurred by the extra layout space on scroll direction changes
private const val RecyclerViewCacheSize = 4 private const val RECYCLER_VIEW_CACHE_SIZE = 4

View file

@ -15,7 +15,7 @@ import java.util.Enumeration
class ChildFirstPathClassLoader( class ChildFirstPathClassLoader(
dexPath: String, dexPath: String,
librarySearchPath: String?, librarySearchPath: String?,
parent: ClassLoader parent: ClassLoader,
) : PathClassLoader(dexPath, librarySearchPath, parent) { ) : PathClassLoader(dexPath, librarySearchPath, parent) {
private val systemClassLoader: ClassLoader? = getSystemClassLoader() private val systemClassLoader: ClassLoader? = getSystemClassLoader()

View file

@ -9,20 +9,24 @@ import tachiyomi.core.common.util.system.logcat
class MigrationJobFactory( class MigrationJobFactory(
private val migrationContext: MigrationContext, private val migrationContext: MigrationContext,
private val scope: CoroutineScope private val scope: CoroutineScope,
) { ) {
fun create(migrations: List<Migration>): Deferred<Boolean> = with(scope) { fun create(migrations: List<Migration>): Deferred<Boolean> = with(scope) {
return migrations.sortedBy { it.version } return migrations.sortedBy { it.version }
.fold(CompletableDeferred(true)) { acc: Deferred<Boolean>, migration: Migration -> .fold(CompletableDeferred(true)) { acc: Deferred<Boolean>, migration: Migration ->
if (!migrationContext.dryrun) { if (!migrationContext.dryrun) {
logcat { "Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" } logcat {
"Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }"
}
async(start = CoroutineStart.UNDISPATCHED) { async(start = CoroutineStart.UNDISPATCHED) {
val prev = acc.await() val prev = acc.await()
migration(migrationContext) || prev migration(migrationContext) || prev
} }
} else { } else {
logcat { "(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" } logcat {
"(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }"
}
CompletableDeferred(true) CompletableDeferred(true)
} }
} }

View file

@ -12,7 +12,7 @@ interface MigrationStrategy {
class DefaultMigrationStrategy( class DefaultMigrationStrategy(
private val migrationJobFactory: MigrationJobFactory, private val migrationJobFactory: MigrationJobFactory,
private val migrationCompletedListener: MigrationCompletedListener, private val migrationCompletedListener: MigrationCompletedListener,
private val scope: CoroutineScope private val scope: CoroutineScope,
) : MigrationStrategy { ) : MigrationStrategy {
override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> = with(scope) { override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> = with(scope) {
@ -46,7 +46,7 @@ class NoopMigrationStrategy(val state: Boolean) : MigrationStrategy {
class VersionRangeMigrationStrategy( class VersionRangeMigrationStrategy(
private val versions: IntRange, private val versions: IntRange,
private val strategy: DefaultMigrationStrategy private val strategy: DefaultMigrationStrategy,
) : MigrationStrategy { ) : MigrationStrategy {
override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> { override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> {

View file

@ -17,7 +17,7 @@ object Migrator {
new: Int, new: Int,
migrations: List<Migration>, migrations: List<Migration>,
dryrun: Boolean = false, dryrun: Boolean = false,
onMigrationComplete: () -> Unit onMigrationComplete: () -> Unit,
) { ) {
val migrationContext = MigrationContext(dryrun) val migrationContext = MigrationContext(dryrun)
val migrationJobFactory = MigrationJobFactory(migrationContext, scope) val migrationJobFactory = MigrationJobFactory(migrationContext, scope)

View file

@ -32,7 +32,7 @@ import java.time.temporal.WeekFields
import java.util.Locale import java.util.Locale
private val FontSize = 16.sp private val FontSize = 16.sp
private const val DaysOfWeek = 7 private const val DAYS_OF_WEEK = 7
@Composable @Composable
fun Calendar( fun Calendar(
@ -54,7 +54,7 @@ fun Calendar(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = MaterialTheme.padding.small) .padding(vertical = MaterialTheme.padding.small)
.padding(start = MaterialTheme.padding.medium) .padding(start = MaterialTheme.padding.medium),
) )
CalendarGrid( CalendarGrid(
selectedYearMonth = selectedYearMonth, selectedYearMonth = selectedYearMonth,
@ -72,8 +72,8 @@ private fun CalendarGrid(
) { ) {
val localeFirstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value val localeFirstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value
val weekDays = remember { val weekDays = remember {
(0 until DaysOfWeek) (0 until DAYS_OF_WEEK)
.map { DayOfWeek.of((localeFirstDayOfWeek - 1 + it) % DaysOfWeek + 1) } .map { DayOfWeek.of((localeFirstDayOfWeek - 1 + it) % DAYS_OF_WEEK + 1) }
.toImmutableList() .toImmutableList()
} }
@ -81,12 +81,12 @@ private fun CalendarGrid(
val daysInMonth = selectedYearMonth.lengthOfMonth() val daysInMonth = selectedYearMonth.lengthOfMonth()
VerticalGrid( VerticalGrid(
columns = SimpleGridCells.Fixed(DaysOfWeek), columns = SimpleGridCells.Fixed(DAYS_OF_WEEK),
modifier = if (isMediumWidthWindow() && !isExpandedWidthWindow()) { modifier = if (isMediumWidthWindow() && !isExpandedWidthWindow()) {
Modifier.widthIn(max = 360.dp) Modifier.widthIn(max = 360.dp)
} else { } else {
Modifier Modifier
} },
) { ) {
weekDays.fastForEach { item -> weekDays.fastForEach { item ->
Text( Text(

View file

@ -19,9 +19,10 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import tachiyomi.presentation.core.components.material.DISABLED_ALPHA
import java.time.LocalDate import java.time.LocalDate
private const val MaxEvents = 3 private const val MAX_EVENTS = 3
@Composable @Composable
fun CalendarDay( fun CalendarDay(
@ -39,7 +40,7 @@ fun CalendarDay(
Modifier.border( Modifier.border(
border = BorderStroke( border = BorderStroke(
width = 1.dp, width = 1.dp,
color = MaterialTheme.colorScheme.onBackground color = MaterialTheme.colorScheme.onBackground,
), ),
shape = CircleShape, shape = CircleShape,
) )
@ -57,14 +58,14 @@ fun CalendarDay(
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontSize = 16.sp, fontSize = 16.sp,
color = if (date.isBefore(today)) { color = if (date.isBefore(today)) {
MaterialTheme.colorScheme.onBackground.copy(alpha = 0.38f) MaterialTheme.colorScheme.onBackground.copy(alpha = DISABLED_ALPHA)
} else { } else {
MaterialTheme.colorScheme.onBackground MaterialTheme.colorScheme.onBackground
}, },
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
) )
Row(Modifier.offset(y = 12.dp)) { Row(Modifier.offset(y = 12.dp)) {
val size = events.coerceAtMost(MaxEvents) val size = events.coerceAtMost(MAX_EVENTS)
for (index in 0 until size) { for (index in 0 until size) {
CalendarIndicator( CalendarIndicator(
index = index, index = index,

View file

@ -63,20 +63,20 @@ fun CalenderHeader(
} }
} }
private const val MonthYearChangeAnimationDuration = 200 private const val MONTH_YEAR_CHANGE_ANIMATION_DURATION = 200
private fun AnimatedContentTransitionScope<YearMonth>.getAnimation(): ContentTransform { private fun AnimatedContentTransitionScope<YearMonth>.getAnimation(): ContentTransform {
val movingForward = targetState > initialState val movingForward = targetState > initialState
val enterTransition = slideInVertically( val enterTransition = slideInVertically(
animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION),
) { height -> if (movingForward) height else -height } + fadeIn( ) { height -> if (movingForward) height else -height } + fadeIn(
animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION),
) )
val exitTransition = slideOutVertically( val exitTransition = slideOutVertically(
animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION),
) { height -> if (movingForward) -height else height } + fadeOut( ) { height -> if (movingForward) -height else height } + fadeOut(
animationSpec = tween(durationMillis = MonthYearChangeAnimationDuration), animationSpec = tween(durationMillis = MONTH_YEAR_CHANGE_ANIMATION_DURATION),
) )
return (enterTransition togetherWith exitTransition) return (enterTransition togetherWith exitTransition)
.using(SizeTransform(clip = false)) .using(SizeTransform(clip = false))

View file

@ -12,8 +12,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
private const val IndicatorScale = 12 private const val INDICATOR_SCALE = 12
private const val IndicatorAlphaMultiplier = 0.3f private const val INDICATOR_ALPHA_MULTIPLIER = 0.3f
@Composable @Composable
fun CalendarIndicator( fun CalendarIndicator(
@ -26,7 +26,7 @@ fun CalendarIndicator(
modifier = modifier modifier = modifier
.padding(horizontal = 1.dp) .padding(horizontal = 1.dp)
.clip(shape = CircleShape) .clip(shape = CircleShape)
.background(color = color.copy(alpha = (index + 1) * IndicatorAlphaMultiplier)) .background(color = color.copy(alpha = (index + 1) * INDICATOR_ALPHA_MULTIPLIER))
.size(size = size.div(IndicatorScale)), .size(size = size.div(INDICATOR_SCALE)),
) )
} }

View file

@ -6,4 +6,4 @@
android:viewportHeight="24" android:viewportHeight="24"
android:tint="@android:color/black"> android:tint="@android:color/black">
<path android:fillColor="#000" android:pathData="M17.5 14.33C18.29 14.33 19.13 14.41 20 14.57V16.07C19.38 15.91 18.54 15.83 17.5 15.83C15.6 15.83 14.11 16.16 13 16.82V15.13C14.17 14.6 15.67 14.33 17.5 14.33M13 12.46C14.29 11.93 15.79 11.67 17.5 11.67C18.29 11.67 19.13 11.74 20 11.9V13.4C19.38 13.24 18.54 13.16 17.5 13.16C15.6 13.16 14.11 13.5 13 14.15M17.5 10.5C15.6 10.5 14.11 10.82 13 11.5V9.84C14.23 9.28 15.73 9 17.5 9C18.29 9 19.13 9.08 20 9.23V10.78C19.26 10.59 18.41 10.5 17.5 10.5M21 18.5V7C19.96 6.67 18.79 6.5 17.5 6.5C15.45 6.5 13.62 7 12 8V19.5C13.62 18.5 15.45 18 17.5 18C18.69 18 19.86 18.16 21 18.5M17.5 4.5C19.85 4.5 21.69 5 23 6V20.56C23 20.68 22.95 20.8 22.84 20.91C22.73 21 22.61 21.08 22.5 21.08C22.39 21.08 22.31 21.06 22.25 21.03C20.97 20.34 19.38 20 17.5 20C15.45 20 13.62 20.5 12 21.5C10.66 20.5 8.83 20 6.5 20C4.84 20 3.25 20.36 1.75 21.07C1.72 21.08 1.68 21.08 1.63 21.1C1.59 21.11 1.55 21.12 1.5 21.12C1.39 21.12 1.27 21.08 1.16 21C1.05 20.89 1 20.78 1 20.65V6C2.34 5 4.18 4.5 6.5 4.5C8.83 4.5 10.66 5 12 6C13.34 5 15.17 4.5 17.5 4.5Z" /> <path android:fillColor="#000" android:pathData="M17.5 14.33C18.29 14.33 19.13 14.41 20 14.57V16.07C19.38 15.91 18.54 15.83 17.5 15.83C15.6 15.83 14.11 16.16 13 16.82V15.13C14.17 14.6 15.67 14.33 17.5 14.33M13 12.46C14.29 11.93 15.79 11.67 17.5 11.67C18.29 11.67 19.13 11.74 20 11.9V13.4C19.38 13.24 18.54 13.16 17.5 13.16C15.6 13.16 14.11 13.5 13 14.15M17.5 10.5C15.6 10.5 14.11 10.82 13 11.5V9.84C14.23 9.28 15.73 9 17.5 9C18.29 9 19.13 9.08 20 9.23V10.78C19.26 10.59 18.41 10.5 17.5 10.5M21 18.5V7C19.96 6.67 18.79 6.5 17.5 6.5C15.45 6.5 13.62 7 12 8V19.5C13.62 18.5 15.45 18 17.5 18C18.69 18 19.86 18.16 21 18.5M17.5 4.5C19.85 4.5 21.69 5 23 6V20.56C23 20.68 22.95 20.8 22.84 20.91C22.73 21 22.61 21.08 22.5 21.08C22.39 21.08 22.31 21.06 22.25 21.03C20.97 20.34 19.38 20 17.5 20C15.45 20 13.62 20.5 12 21.5C10.66 20.5 8.83 20 6.5 20C4.84 20 3.25 20.36 1.75 21.07C1.72 21.08 1.68 21.08 1.63 21.1C1.59 21.11 1.55 21.12 1.5 21.12C1.39 21.12 1.27 21.08 1.16 21C1.05 20.89 1 20.78 1 20.65V6C2.34 5 4.18 4.5 6.5 4.5C8.83 4.5 10.66 5 12 6C13.34 5 15.17 4.5 17.5 4.5Z" />
</vector> </vector>

View file

@ -6,4 +6,4 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M22,3H5A2,2 0 0,0 3,5V9H5V5H22V19H5V15H3V19A2,2 0 0,0 5,21H22A2,2 0 0,0 24,19V5A2,2 0 0,0 22,3M7,15V13H0V11H7V9L11,12L7,15M20,13H13V11H20V13M20,9H13V7H20V9M17,17H13V15H17V17Z" /> <path android:fillColor="#000" android:pathData="M22,3H5A2,2 0 0,0 3,5V9H5V5H22V19H5V15H3V19A2,2 0 0,0 5,21H22A2,2 0 0,0 24,19V5A2,2 0 0,0 22,3M7,15V13H0V11H7V9L11,12L7,15M20,13H13V11H20V13M20,9H13V7H20V9M17,17H13V15H17V17Z" />
</vector> </vector>

View file

@ -7,4 +7,4 @@ android:viewportHeight="24">
<path <path
android:fillColor="@color/cover_placeholder" android:fillColor="@color/cover_placeholder"
android:pathData="M21,5v6.59l-2.29,-2.3c-0.39,-0.39 -1.03,-0.39 -1.42,0L14,12.59 10.71,9.3c-0.39,-0.39 -1.02,-0.39 -1.41,0L6,12.59 3,9.58L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.3 3.29,3.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.28z"/> android:pathData="M21,5v6.59l-2.29,-2.3c-0.39,-0.39 -1.03,-0.39 -1.42,0L14,12.59 10.71,9.3c-0.39,-0.39 -1.02,-0.39 -1.41,0L6,12.59 3,9.58L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.3 3.29,3.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.28z"/>
</vector> </vector>

View file

@ -6,4 +6,4 @@
<path <path
android:fillColor="#FFF" android:fillColor="#FFF"
android:pathData="M3,10C2.76,10 2.55,10.09 2.41,10.25C2.27,10.4 2.21,10.62 2.24,10.86L2.74,13.85C2.82,14.5 3.4,15 4,15H7C7.64,15 8.36,14.44 8.5,13.82L9.56,10.63C9.6,10.5 9.57,10.31 9.5,10.19C9.39,10.07 9.22,10 9,10H3M7,17H4C2.38,17 0.96,15.74 0.76,14.14L0.26,11.15C0.15,10.3 0.39,9.5 0.91,8.92C1.43,8.34 2.19,8 3,8H9C9.83,8 10.58,8.35 11.06,8.96C11.17,9.11 11.27,9.27 11.35,9.45C11.78,9.36 12.22,9.36 12.64,9.45C12.72,9.27 12.82,9.11 12.94,8.96C13.41,8.35 14.16,8 15,8H21C21.81,8 22.57,8.34 23.09,8.92C23.6,9.5 23.84,10.3 23.74,11.11L23.23,14.18C23.04,15.74 21.61,17 20,17H17C15.44,17 13.92,15.81 13.54,14.3L12.64,11.59C12.26,11.31 11.73,11.31 11.35,11.59L10.43,14.37C10.07,15.82 8.56,17 7,17M15,10C14.78,10 14.61,10.07 14.5,10.19C14.42,10.31 14.4,10.5 14.45,10.7L15.46,13.75C15.64,14.44 16.36,15 17,15H20C20.59,15 21.18,14.5 21.25,13.89L21.76,10.82C21.79,10.62 21.73,10.4 21.59,10.25C21.45,10.09 21.24,10 21,10H15Z" /> android:pathData="M3,10C2.76,10 2.55,10.09 2.41,10.25C2.27,10.4 2.21,10.62 2.24,10.86L2.74,13.85C2.82,14.5 3.4,15 4,15H7C7.64,15 8.36,14.44 8.5,13.82L9.56,10.63C9.6,10.5 9.57,10.31 9.5,10.19C9.39,10.07 9.22,10 9,10H3M7,17H4C2.38,17 0.96,15.74 0.76,14.14L0.26,11.15C0.15,10.3 0.39,9.5 0.91,8.92C1.43,8.34 2.19,8 3,8H9C9.83,8 10.58,8.35 11.06,8.96C11.17,9.11 11.27,9.27 11.35,9.45C11.78,9.36 12.22,9.36 12.64,9.45C12.72,9.27 12.82,9.11 12.94,8.96C13.41,8.35 14.16,8 15,8H21C21.81,8 22.57,8.34 23.09,8.92C23.6,9.5 23.84,10.3 23.74,11.11L23.23,14.18C23.04,15.74 21.61,17 20,17H17C15.44,17 13.92,15.81 13.54,14.3L12.64,11.59C12.26,11.31 11.73,11.31 11.35,11.59L10.43,14.37C10.07,15.82 8.56,17 7,17M15,10C14.78,10 14.61,10.07 14.5,10.19C14.42,10.31 14.4,10.5 14.45,10.7L15.46,13.75C15.64,14.44 16.36,15 17,15H20C20.59,15 21.18,14.5 21.25,13.89L21.76,10.82C21.79,10.62 21.73,10.4 21.59,10.25C21.45,10.09 21.24,10 21,10H15Z" />
</vector> </vector>

View file

@ -7,4 +7,4 @@
<path <path
android:fillColor="#000" android:fillColor="#000"
android:pathData="M13,2.03V2.05L13,4.05C17.39,4.59 20.5,8.58 19.96,12.97C19.5,16.61 16.64,19.5 13,19.93V21.93C18.5,21.38 22.5,16.5 21.95,11C21.5,6.25 17.73,2.5 13,2.03M11,2.06C9.05,2.25 7.19,3 5.67,4.26L7.1,5.74C8.22,4.84 9.57,4.26 11,4.06V2.06M4.26,5.67C3,7.19 2.25,9.04 2.05,11H4.05C4.24,9.58 4.8,8.23 5.69,7.1L4.26,5.67M2.06,13C2.26,14.96 3.03,16.81 4.27,18.33L5.69,16.9C4.81,15.77 4.24,14.42 4.06,13H2.06M7.1,18.37L5.67,19.74C7.18,21 9.04,21.79 11,22V20C9.58,19.82 8.23,19.25 7.1,18.37M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z" /> android:pathData="M13,2.03V2.05L13,4.05C17.39,4.59 20.5,8.58 19.96,12.97C19.5,16.61 16.64,19.5 13,19.93V21.93C18.5,21.38 22.5,16.5 21.95,11C21.5,6.25 17.73,2.5 13,2.03M11,2.06C9.05,2.25 7.19,3 5.67,4.26L7.1,5.74C8.22,4.84 9.57,4.26 11,4.06V2.06M4.26,5.67C3,7.19 2.25,9.04 2.05,11H4.05C4.24,9.58 4.8,8.23 5.69,7.1L4.26,5.67M2.06,13C2.26,14.96 3.03,16.81 4.27,18.33L5.69,16.9C4.81,15.77 4.24,14.42 4.06,13H2.06M7.1,18.37L5.67,19.74C7.18,21 9.04,21.79 11,22V20C9.58,19.82 8.23,19.25 7.1,18.37M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z" />
</vector> </vector>

View file

@ -5,4 +5,4 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M2,2H6V3H13V2H17V6H16V9H18V8H22V12H21V18H22V22H18V21H12V22H8V18H9V16H6V17H2V13H3V6H2V2M18,12V11H16V13H17V17H13V16H11V18H12V19H18V18H19V12H18M13,6V5H6V6H5V13H6V14H9V12H8V8H12V9H14V6H13M12,12H11V14H13V13H14V11H12V12Z" /> <path android:fillColor="#000" android:pathData="M2,2H6V3H13V2H17V6H16V9H18V8H22V12H21V18H22V22H18V21H12V22H8V18H9V16H6V17H2V13H3V6H2V2M18,12V11H16V13H17V17H13V16H11V18H12V19H18V18H19V12H18M13,6V5H6V6H5V13H6V14H9V12H8V8H12V9H14V6H13M12,12H11V14H13V13H14V11H12V12Z" />
</vector> </vector>

View file

@ -12,4 +12,4 @@
<corners android:radius="@dimen/m3_alert_dialog_corner_size" /> <corners android:radius="@dimen/m3_alert_dialog_corner_size" />
</shape> </shape>
</item> </item>
</layer-list> </layer-list>

View file

@ -36,4 +36,4 @@
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout> </LinearLayout>

View file

@ -157,4 +157,4 @@
</LinearLayout> </LinearLayout>

View file

@ -27,4 +27,4 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -45,4 +45,4 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -95,4 +95,4 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout> </LinearLayout>

View file

@ -115,4 +115,4 @@
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout> </LinearLayout>

View file

@ -124,4 +124,4 @@
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout> </LinearLayout>

View file

@ -14,4 +14,4 @@
android:layout_height="1dp" android:layout_height="1dp"
android:background="?android:attr/divider"/> android:background="?android:attr/divider"/>
</LinearLayout> </LinearLayout>

View file

@ -4,4 +4,4 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
tools:listitem="@layout/migration_source_item" /> tools:listitem="@layout/migration_source_item" />

View file

@ -17,4 +17,4 @@
<item name="android:clickable">true</item> <item name="android:clickable">true</item>
<item name="android:focusable">true</item> <item name="android:focusable">true</item>
</style> </style>
</resources> </resources>

View file

@ -660,7 +660,7 @@
<item name="colorSurfaceContainerLow">@color/nord_surfaceContainerLow</item> <item name="colorSurfaceContainerLow">@color/nord_surfaceContainerLow</item>
<item name="colorSurfaceContainerLowest">@color/nord_surfaceContainerLowest</item> <item name="colorSurfaceContainerLowest">@color/nord_surfaceContainerLowest</item>
</style> </style>
<!--== AMOLED Mode Overlay ==--> <!--== AMOLED Mode Overlay ==-->
<style name="ThemeOverlay.Tachiyomi.Amoled" parent="" /> <style name="ThemeOverlay.Tachiyomi.Amoled" parent="" />

View file

@ -57,4 +57,4 @@
name="gesture" name="gesture"
value="swipe_left" /> value="swipe_left" />
</action> </action>
</remote-actions> </remote-actions>

View file

@ -133,8 +133,8 @@ class MigratorTest {
listOf( listOf(
Migration.of(Migration.ALWAYS) { true }, Migration.of(Migration.ALWAYS) { true },
Migration.of(2f) { true }, Migration.of(2f) { true },
Migration.of(3f) { false } Migration.of(3f) { false },
) ),
) )
execute.await() execute.await()

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest /> <manifest />

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest /> <manifest />

View file

@ -1,3 +1,5 @@
@file:Suppress("FunctionName", "ktlint:standard:function-naming")
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
import okhttp3.CacheControl import okhttp3.CacheControl

View file

@ -546,16 +546,20 @@ object ImageUtil {
darkBG -> { darkBG -> {
return ColorDrawable(blackColor) return ColorDrawable(blackColor)
} }
topIsBlackStreak || ( topIsBlackStreak ||
topCornersIsDark && topOffsetCornersIsDark && (
(topMidIsDark || overallBlackPixels > 9) topCornersIsDark &&
) -> { topOffsetCornersIsDark &&
(topMidIsDark || overallBlackPixels > 9)
) -> {
intArrayOf(blackColor, blackColor, whiteColor, whiteColor) intArrayOf(blackColor, blackColor, whiteColor, whiteColor)
} }
bottomIsBlackStreak || ( bottomIsBlackStreak ||
botCornersIsDark && botOffsetCornersIsDark && (
(bottomCenterPixel.isDark() || overallBlackPixels > 9) botCornersIsDark &&
) -> { botOffsetCornersIsDark &&
(bottomCenterPixel.isDark() || overallBlackPixels > 9)
) -> {
intArrayOf(whiteColor, whiteColor, blackColor, blackColor) intArrayOf(whiteColor, whiteColor, blackColor, blackColor)
} }
else -> { else -> {

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest /> <manifest />

View file

@ -42,8 +42,8 @@ class QueryPagingSource<RowType : Any>(
} }
val (prevKey, nextKey) = when (params) { val (prevKey, nextKey) = when (params) {
is LoadParams.Append -> { offset - loadSize to offset + loadSize } is LoadParams.Append -> (offset - loadSize to offset + loadSize)
else -> { offset to offset + loadSize } else -> (offset to offset + loadSize)
} }
return LoadResult.Page( return LoadResult.Page(

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest /> <manifest />

View file

@ -5,7 +5,8 @@ import tachiyomi.domain.chapter.model.Chapter
class ShouldUpdateDbChapter { class ShouldUpdateDbChapter {
fun await(dbChapter: Chapter, sourceChapter: Chapter): Boolean { fun await(dbChapter: Chapter, sourceChapter: Chapter): Boolean {
return dbChapter.scanlator != sourceChapter.scanlator || dbChapter.name != sourceChapter.name || return dbChapter.scanlator != sourceChapter.scanlator ||
dbChapter.name != sourceChapter.name ||
dbChapter.dateUpload != sourceChapter.dateUpload || dbChapter.dateUpload != sourceChapter.dateUpload ||
dbChapter.chapterNumber != sourceChapter.chapterNumber || dbChapter.chapterNumber != sourceChapter.chapterNumber ||
dbChapter.sourceOrder != sourceChapter.sourceOrder dbChapter.sourceOrder != sourceChapter.sourceOrder

View file

@ -20,10 +20,8 @@ class GetApplicationRelease(
val now = Instant.now() val now = Instant.now()
// Limit checks to once every 3 days at most // Limit checks to once every 3 days at most
if (!arguments.forceCheck && now.isBefore( val nextCheckTime = Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS)
Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS), if (!arguments.forceCheck && now.isBefore(nextCheckTime)) {
)
) {
return Result.NoNewUpdate return Result.NoNewUpdate
} }

View file

@ -293,7 +293,7 @@ object FlagKit {
"yt", "yt",
"za", "za",
"zm", "zm",
"zw" "zw",
) )
} }
} }

View file

@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
</resources> </resources>

View file

@ -80,4 +80,4 @@
<item quantity="many">منذُ %1$d دقيقة</item> <item quantity="many">منذُ %1$d دقيقة</item>
<item quantity="other">منذُ %1$d دقيقة</item> <item quantity="other">منذُ %1$d دقيقة</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -451,4 +451,4 @@
<string name="action_copy_combined_page">نسخ الصفحة المجمعة</string> <string name="action_copy_combined_page">نسخ الصفحة المجمعة</string>
<string name="only_show_updated_entries">إظهار الإدخالات التي تحتوي على فصول جديدة فقط</string> <string name="only_show_updated_entries">إظهار الإدخالات التي تحتوي على فصول جديدة فقط</string>
<string name="pref_crop_borders_pager">قص اطراف الصفحات</string> <string name="pref_crop_borders_pager">قص اطراف الصفحات</string>
</resources> </resources>

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources></resources> <resources></resources>

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources></resources> <resources></resources>

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources></resources> <resources></resources>

View file

@ -533,4 +533,4 @@
<string name="group">Grupo</string> <string name="group">Grupo</string>
<string name="uploader_capital">Naka-capitalize ang Uploader</string> <string name="uploader_capital">Naka-capitalize ang Uploader</string>
<string name="deduplication_entry_info">Impo ng entry:</string> <string name="deduplication_entry_info">Impo ng entry:</string>
</resources> </resources>

View file

@ -67,4 +67,4 @@
<item quantity="one">%1$d seconde auparavant</item> <item quantity="one">%1$d seconde auparavant</item>
<item quantity="other">%1$d seconde auparavant</item> <item quantity="other">%1$d seconde auparavant</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -72,4 +72,4 @@
<item quantity="one">%1$d detik yang lalu</item> <item quantity="one">%1$d detik yang lalu</item>
<item quantity="other">%1$d detik yang lalu</item> <item quantity="other">%1$d detik yang lalu</item>
</plurals> </plurals>
</resources> </resources>

Some files were not shown because too many files have changed in this diff Show more