Address spotless lint errors (#1138)

* Add spotless (with ktlint)

* Run spotlessApply

* screaming case screaming case screaming case

* Update PagerViewerAdapter.kt

* Update ReaderTransitionView.kt
This commit is contained in:
AntsyLich 2024-08-19 18:11:39 +06:00 committed by GitHub
parent 5ae8095ef1
commit d6252ab770
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
230 changed files with 580 additions and 467 deletions

View file

@ -17,7 +17,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"
@ -35,7 +35,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"
@ -45,7 +45,7 @@ android {
abi { abi {
isEnable = true isEnable = true
reset() reset()
include(*SUPPORTED_ABIS.toTypedArray()) include(*supportedAbis.toTypedArray())
isUniversalApk = true isUniversalApk = true
} }
} }
@ -158,7 +158,7 @@ dependencies {
implementation(compose.ui.tooling.preview) implementation(compose.ui.tooling.preview)
implementation(compose.ui.util) implementation(compose.ui.util)
implementation(compose.accompanist.systemuicontroller) implementation(compose.accompanist.systemuicontroller)
implementation(androidx.interpolator) implementation(androidx.interpolator)
implementation(androidx.paging.runtime) implementation(androidx.paging.runtime)
@ -236,7 +236,6 @@ dependencies {
implementation(libs.compose.webview) implementation(libs.compose.webview)
implementation(libs.compose.grid) implementation(libs.compose.grid)
// Logging // Logging
implementation(libs.logcat) implementation(libs.logcat)

View file

@ -110,7 +110,10 @@ class SyncChaptersWithSource(
if (shouldUpdateDbChapter.await(dbChapter, chapter)) { if (shouldUpdateDbChapter.await(dbChapter, chapter)) {
val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) && val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) &&
downloadManager.isChapterDownloaded( downloadManager.isChapterDownloaded(
dbChapter.name, dbChapter.scanlator, manga.title, manga.source, dbChapter.name,
dbChapter.scanlator,
manga.title,
manga.source,
) )
if (shouldRenameChapter) { if (shouldRenameChapter) {

View file

@ -19,7 +19,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

@ -232,7 +232,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) {
@ -242,8 +242,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

@ -219,7 +219,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,
@ -241,7 +243,9 @@ private fun ExtensionContent(
onOpenExtension(it) onOpenExtension(it)
} }
} }
is Extension.Untrusted -> { trustState = it } is Extension.Untrusted -> {
trustState = it
}
} }
}, },
) )

View file

@ -28,7 +28,7 @@ import tachiyomi.domain.source.model.Pin
import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.model.Source
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.ScrollbarLazyColumn
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.components.material.topSmallPaddingValues import tachiyomi.presentation.core.components.material.topSmallPaddingValues
import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.i18n.stringResource
@ -148,7 +148,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

@ -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

@ -62,7 +62,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
private const val GridSelectedCoverAlpha = 0.76f private 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.
@ -90,7 +90,7 @@ fun MangaCompactGridItem(
MangaCover.Book( MangaCover.Book(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha), .alpha(if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha),
data = coverData, data = coverData,
) )
}, },
@ -197,7 +197,7 @@ fun MangaComfortableGridItem(
MangaCover.Book( MangaCover.Book(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.alpha(if (isSelected) GridSelectedCoverAlpha else coverAlpha), .alpha(if (isSelected) GRID_SELECTED_COVER_ALPHA else coverAlpha),
data = coverData, data = coverData,
) )
}, },
@ -371,7 +371,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),
) )
} }
} }
@ -392,7 +392,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

@ -12,7 +12,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
@ -60,6 +60,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
@ -132,7 +132,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),
) )
} }
@ -140,7 +140,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) {
@ -156,7 +156,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) DotSeparatorText() if (scanlator != null) DotSeparatorText()
} }

View file

@ -81,6 +81,7 @@ import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.copyToClipboard
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
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
@ -177,7 +178,7 @@ fun MangaActionRow(
onEditCategory: (() -> Unit)?, onEditCategory: (() -> Unit)?,
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

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

View file

@ -340,7 +340,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

@ -44,7 +44,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
@ -146,7 +146,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
@ -220,7 +220,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

@ -1,6 +1,5 @@
package eu.kanade.presentation.util package eu.kanade.presentation.util
import android.annotation.SuppressLint
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform import androidx.compose.animation.ContentTransform

View file

@ -167,7 +167,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

@ -9,7 +9,7 @@ data class RestoreOptions(
val categories: Boolean = true, val categories: Boolean = true,
val appSettings: Boolean = true, val appSettings: Boolean = true,
val extensionRepoSettings: Boolean = true, val extensionRepoSettings: Boolean = true,
val sourceSettings: Boolean = true val sourceSettings: Boolean = true,
) { ) {
fun asBooleanArray() = booleanArrayOf( fun asBooleanArray() = booleanArrayOf(
@ -17,7 +17,7 @@ data class RestoreOptions(
categories, categories,
appSettings, appSettings,
extensionRepoSettings, extensionRepoSettings,
sourceSettings sourceSettings,
) )
fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings

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

@ -85,7 +85,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

@ -180,7 +180,7 @@ class Downloader(
fun clearQueue() { fun clearQueue() {
cancelDownloaderJob() cancelDownloaderJob()
_clearQueue() internalClearQueue()
notifier.dismissProgress() notifier.dismissProgress()
} }
@ -194,9 +194,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)
@ -616,7 +619,7 @@ class Downloader(
chapter, chapter,
urls, urls,
categories, categories,
source.name source.name,
) )
// Remove the old file // Remove the old file
@ -676,7 +679,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) {
@ -698,7 +701,7 @@ class Downloader(
} }
pause() pause()
_clearQueue() internalClearQueue()
addAllToQueue(downloads) addAllToQueue(downloads)
if (wasRunning) { if (wasRunning) {

View file

@ -437,7 +437,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),
), ),
) )
@ -364,17 +364,17 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
} }
companion object { companion object {
private const val clientId = "16329" private const val CLIENT_ID = "16329"
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 = "bgm291665acbd06a4c28" private const val CLIENT_ID = "bgm291665acbd06a4c28"
private const val clientSecret = "43e5ce36b207de16e5d3cfd3e79118db" private const val CLIENT_SECRET = "43e5ce36b207de16e5d3cfd3e79118db"
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 = "mihon://bangumi-auth" private const val REDIRECT_URL = "mihon://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()
@ -73,14 +73,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")
@ -103,10 +103,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 ?: ""
@ -122,13 +122,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) {
@ -137,7 +137,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")
@ -161,7 +161,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 {
@ -181,39 +181,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 = "PB9dq8DzI405s7wdtwTdirYqHiyVMh--djnP7lBUqSA" private const val CLIENT_ID = "PB9dq8DzI405s7wdtwTdirYqHiyVMh--djnP7lBUqSA"
private const val clientSecret = "NajpZcOBKB9sJtgNcejf8OB9jBN1OYYoo-k4h2WWZus" private const val CLIENT_SECRET = "NajpZcOBKB9sJtgNcejf8OB9jBN1OYYoo-k4h2WWZus"
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 = "mihon://shikimori-auth" private const val REDIRECT_URL = "mihon://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

@ -62,14 +62,14 @@ 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>())
val availableExtensionsFlow = _availableExtensionsMapFlow.mapExtensions(scope) val availableExtensionsFlow = availableExtensionMapFlow.mapExtensions(scope)
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()
@ -79,7 +79,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 }
} }
@ -109,11 +109,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 }
@ -121,7 +121,7 @@ class ExtensionManager(
} }
/** /**
* 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 {
@ -134,7 +134,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)
} }
@ -180,7 +180,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 }
@ -204,7 +204,7 @@ class ExtensionManager(
} }
} }
if (changed) { if (changed) {
_installedExtensionsMapFlow.value = installedExtensionsMap installedExtensionMapFlow.value = installedExtensionsMap
} }
updatePendingUpdatesCount() updatePendingUpdatesCount()
} }
@ -228,7 +228,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)
} }
@ -265,11 +265,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 }
@ -282,7 +282,7 @@ class ExtensionManager(
* @param extension The extension to be registered. * @param extension The extension to be registered.
*/ */
private fun registerNewExtension(extension: Extension.Installed) { private fun registerNewExtension(extension: Extension.Installed) {
_installedExtensionsMapFlow.value += extension installedExtensionMapFlow.value += extension
} }
/** /**
@ -292,7 +292,7 @@ class ExtensionManager(
* @param extension The extension to be registered. * @param extension The extension to be registered.
*/ */
private fun registerUpdatedExtension(extension: Extension.Installed) { private fun registerUpdatedExtension(extension: Extension.Installed) {
_installedExtensionsMapFlow.value += extension installedExtensionMapFlow.value += extension
} }
/** /**
@ -302,8 +302,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
} }
/** /**
@ -322,8 +322,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()
} }
@ -347,14 +347,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

@ -97,7 +97,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)
} }
@ -80,7 +86,7 @@ class ExtensionsScreenModel(
screenModelScope.launchIO { screenModelScope.launchIO {
combine( combine(
state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS), state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS),
_currentDownloads, currentDownloads,
getExtensions.subscribe(), getExtensions.subscribe(),
) { query, downloads, (_updates, _installed, _available, _untrusted) -> ) { query, downloads, (_updates, _installed, _available, _untrusted) ->
val searchQuery = query ?: "" val searchQuery = query ?: ""
@ -166,11 +172,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

@ -66,8 +66,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,
@ -82,7 +82,7 @@ object HomeScreen : Screen() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
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) {
@ -124,8 +124,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",
) { ) {

View file

@ -258,7 +258,7 @@ class LibraryScreenModel(
private fun LibraryMap.applySort( private fun LibraryMap.applySort(
// Map<MangaId, List<Track>> // Map<MangaId, List<Track>>
trackMap: Map<Long, List<Track>>, trackMap: Map<Long, List<Track>>,
loggedInTrackerIds: Set<Long> loggedInTrackerIds: Set<Long>,
): LibraryMap { ): LibraryMap {
val sortAlphabetically: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> val sortAlphabetically: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
i1.libraryManga.manga.title.lowercase().compareToWithCollator(i2.libraryManga.manga.title.lowercase()) i1.libraryManga.manga.title.lowercase().compareToWithCollator(i2.libraryManga.manga.title.lowercase())

View file

@ -32,7 +32,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(),
) )
fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriState>) { fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriState>) {

View file

@ -87,8 +87,8 @@ private class MoreScreenModel(
var downloadedOnly by preferences.downloadedOnly().asState(screenModelScope) var downloadedOnly by preferences.downloadedOnly().asState(screenModelScope)
var incognitoMode by preferences.incognitoMode().asState(screenModelScope) var incognitoMode by preferences.incognitoMode().asState(screenModelScope)
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
@ -99,7 +99,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

@ -165,13 +165,19 @@ class ReaderViewModel @JvmOverloads constructor(
( (
manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED && manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED &&
!downloadManager.isChapterDownloaded( !downloadManager.isChapterDownloaded(
it.name, it.scanlator, manga.title, manga.source, it.name,
it.scanlator,
manga.title,
manga.source,
) )
) || ) ||
( (
manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED && manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED &&
downloadManager.isChapterDownloaded( downloadManager.isChapterDownloaded(
it.name, it.scanlator, manga.title, manga.source, it.name,
it.scanlator,
manga.title,
manga.source,
) )
) || ) ||
(manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark) || (manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark) ||

View file

@ -142,7 +142,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

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

View file

@ -32,15 +32,16 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At
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 = manga.title, chapterScanlator = goingToChapter.scanlator,
sourceId = manga.source, mangaTitle = manga.title,
skipCache = true, sourceId = manga.source,
) skipCache = true,
} ?: false, )
} ?: false,
) )
} else { } else {
null null

View file

@ -92,7 +92,9 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
// 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

@ -82,7 +82,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

@ -79,7 +79,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
.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
@ -362,4 +362,4 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
} }
// 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 @@
<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

@ -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

@ -445,7 +445,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

@ -127,8 +127,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

@ -500,16 +500,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

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

View file

@ -12,4 +12,4 @@
<item quantity="one">ከ %2$s ስህተት ጋር በ %1$s ውስጥ ተከናውኗል</item> <item quantity="one">ከ %2$s ስህተት ጋር በ %1$s ውስጥ ተከናውኗል</item>
<item quantity="other">ከ %2$s ስህተት ጋር በ %1$s ውስጥ ተከናውኗል</item> <item quantity="other">ከ %2$s ስህተት ጋር በ %1$s ውስጥ ተከናውኗል</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -275,4 +275,4 @@
<string name="backup_restore_missing_trackers">መከታተያዎች አልገቡም:</string> <string name="backup_restore_missing_trackers">መከታተያዎች አልገቡም:</string>
<string name="backup_restore_missing_sources">የጠፋ ምንጮች:</string> <string name="backup_restore_missing_sources">የጠፋ ምንጮች:</string>
<string name="invalid_backup_file_missing_manga">ምትኬ ማንኛውንም ማንጋ አልያዘም ፡፡</string> <string name="invalid_backup_file_missing_manga">ምትኬ ማንኛውንም ማንጋ አልያዘም ፡፡</string>
</resources> </resources>

View file

@ -152,4 +152,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

@ -817,4 +817,4 @@
\n إذا كان هذا متوقعًا، فسيتم استبدال %2$s، وإلا فاتصل بمشرف الرابطالخاص بك.</string> \n إذا كان هذا متوقعًا، فسيتم استبدال %2$s، وإلا فاتصل بمشرف الرابطالخاص بك.</string>
<string name="action_migrate_duplicate">نقل مَدْخَل موجود</string> <string name="action_migrate_duplicate">نقل مَدْخَل موجود</string>
<string name="pref_display_profile">ملف تعريف عرض خاص</string> <string name="pref_display_profile">ملف تعريف عرض خاص</string>
</resources> </resources>

View file

@ -24,4 +24,4 @@
<item quantity="many">Наступныя %d непрачытаных глав</item> <item quantity="many">Наступныя %d непрачытаных глав</item>
<item quantity="other">Наступныя %d непрачытаных глав</item> <item quantity="other">Наступныя %d непрачытаных глав</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -352,4 +352,4 @@
<string name="label_upcoming">Наступнае</string> <string name="label_upcoming">Наступнае</string>
<string name="scanlator">Перакладчык</string> <string name="scanlator">Перакладчык</string>
<string name="label_downloaded">Загружана</string> <string name="label_downloaded">Загружана</string>
</resources> </resources>

View file

@ -68,4 +68,4 @@
<item quantity="one">%d хранилище</item> <item quantity="one">%d хранилище</item>
<item quantity="other">%d хранилища</item> <item quantity="other">%d хранилища</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -642,4 +642,4 @@
<string name="publishing_finished">Приключено издаване</string> <string name="publishing_finished">Приключено издаване</string>
<string name="update_check_fdroid_migration_info">Достъпна е нова версия от официалните източници. Научете как да мигрирате от неофициалните версии на F-Droid.</string> <string name="update_check_fdroid_migration_info">Достъпна е нова версия от официалните източници. Научете как да мигрирате от неофициалните версии на F-Droid.</string>
<string name="download_notifier_split_page_not_found">Страница %d не беше намерена при разделяне</string> <string name="download_notifier_split_page_not_found">Страница %d не беше намерена при разделяне</string>
</resources> </resources>

View file

@ -64,4 +64,4 @@
<item quantity="one">%d দিন</item> <item quantity="one">%d দিন</item>
<item quantity="other">%d দিন</item> <item quantity="other">%d দিন</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -637,4 +637,4 @@
<string name="sort_category_confirmation">আপনি কি বর্ণানুক্রমিকভাবে ফিল্টার করতে চান</string> <string name="sort_category_confirmation">আপনি কি বর্ণানুক্রমিকভাবে ফিল্টার করতে চান</string>
<string name="action_ok">ঠিক আছে</string> <string name="action_ok">ঠিক আছে</string>
<string name="action_sort_next_updated">পরবর্তী আপডেটের সম্ভাব্য সময়</string> <string name="action_sort_next_updated">পরবর্তী আপডেটের সম্ভাব্য সময়</string>
</resources> </resources>

View file

@ -95,4 +95,4 @@
<item quantity="many">%1$s pàgines</item> <item quantity="many">%1$s pàgines</item>
<item quantity="other">%1$s pàgines</item> <item quantity="other">%1$s pàgines</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -820,4 +820,4 @@
<string name="invalid_backup_file_json">Còpia de seguretat en JSON no suportada</string> <string name="invalid_backup_file_json">Còpia de seguretat en JSON no suportada</string>
<string name="invalid_backup_file_unknown">El fitxer de còpia de seguretat és corrupte</string> <string name="invalid_backup_file_unknown">El fitxer de còpia de seguretat és corrupte</string>
<string name="extensionRepo_settings">Repositoris dextensions</string> <string name="extensionRepo_settings">Repositoris dextensions</string>
</resources> </resources>

View file

@ -20,4 +20,4 @@
<item quantity="one">%1$s ang nahibilin</item> <item quantity="one">%1$s ang nahibilin</item>
<item quantity="other">%1$s ang nahibilin</item> <item quantity="other">%1$s ang nahibilin</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -443,4 +443,4 @@
<string name="action_not_now">Dili karon</string> <string name="action_not_now">Dili karon</string>
<string name="information_webview_required">Gikinahanlan ang WebView alang sa Mihon</string> <string name="information_webview_required">Gikinahanlan ang WebView alang sa Mihon</string>
<string name="information_required_plain">*gikinahanlan</string> <string name="information_required_plain">*gikinahanlan</string>
</resources> </resources>

View file

@ -95,4 +95,4 @@
<item quantity="few">%1$s stránky</item> <item quantity="few">%1$s stránky</item>
<item quantity="other">%1$s stránek</item> <item quantity="other">%1$s stránek</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -814,4 +814,4 @@
<string name="pref_display_profile">Vlastní profil zobrazení</string> <string name="pref_display_profile">Vlastní profil zobrazení</string>
<string name="action_view_upcoming">Zobrazit nadcházející aktualizace</string> <string name="action_view_upcoming">Zobrazit nadcházející aktualizace</string>
<string name="file_picker_uri_permission_unsupported">Nepodařilo se získat trvalý přístup ke složce. Aplikace se může chovat zvláštně.</string> <string name="file_picker_uri_permission_unsupported">Nepodařilo se získat trvalý přístup ke složce. Aplikace se může chovat zvláštně.</string>
</resources> </resources>

View file

@ -68,4 +68,4 @@
<item quantity="one">%d усрав</item> <item quantity="one">%d усрав</item>
<item quantity="other">%d усрав</item> <item quantity="other">%d усрав</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -599,4 +599,4 @@
<string name="onboarding_storage_help_info">Кивӗ верссирен ҫӗнӗлетӗн те мӗн суламаллине пӗлместӗн? Нумайрах пӗлме усрав пӗлкӗчне кӗрсе пӑх.</string> <string name="onboarding_storage_help_info">Кивӗ верссирен ҫӗнӗлетӗн те мӗн суламаллине пӗлместӗн? Нумайрах пӗлме усрав пӗлкӗчне кӗрсе пӑх.</string>
<string name="onboarding_guides_returning_user">%s ҫӗнӗрен лартатӑн?</string> <string name="onboarding_guides_returning_user">%s ҫӗнӗрен лартатӑн?</string>
<string name="pref_relative_format_summary">«%1$s» вырӑнне «%2$s»</string> <string name="pref_relative_format_summary">«%1$s» вырӑнне «%2$s»</string>
</resources> </resources>

View file

@ -16,4 +16,4 @@
<item quantity="one">Næste ulæste kapitel</item> <item quantity="one">Næste ulæste kapitel</item>
<item quantity="other">Næste %d ulæste kapitler</item> <item quantity="other">Næste %d ulæste kapitler</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -316,4 +316,4 @@
<string name="creating_backup">Opretter sikkerhedskopi</string> <string name="creating_backup">Opretter sikkerhedskopi</string>
<string name="exception_unknown_host">Kunne ikke nå %s</string> <string name="exception_unknown_host">Kunne ikke nå %s</string>
<string name="channel_new_chapters">Kapitelopdateringer</string> <string name="channel_new_chapters">Kapitelopdateringer</string>
</resources> </resources>

View file

@ -76,4 +76,4 @@
<item quantity="one">1 Seite</item> <item quantity="one">1 Seite</item>
<item quantity="other">%1$s Seiten</item> <item quantity="other">%1$s Seiten</item>
</plurals> </plurals>
</resources> </resources>

View file

@ -817,4 +817,4 @@
<string name="pref_flash_style_white_black">Weiß und Schwarz</string> <string name="pref_flash_style_white_black">Weiß und Schwarz</string>
<string name="pref_flash_duration">Dauer des Leuchtens</string> <string name="pref_flash_duration">Dauer des Leuchtens</string>
<string name="pref_flash_duration_summary">%1$s ms</string> <string name="pref_flash_duration_summary">%1$s ms</string>
</resources> </resources>

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