Restrict line length with ktlint

(cherry picked from commit 1d144e67678a99ec7198e5efcb1410b5da4bc42e)

# Conflicts:
#	.editorconfig
#	app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt
#	source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt
This commit is contained in:
arkon 2023-11-04 23:28:41 -04:00 committed by Jobobby04
parent 0a9f15d74c
commit d9a6a7be50
123 changed files with 1366 additions and 382 deletions

View File

@ -1,15 +1,16 @@
[*.{kt,kts}]
indent_size=4
insert_final_newline=true
ij_kotlin_allow_trailing_comma=true
ij_kotlin_allow_trailing_comma_on_call_site=true
ij_kotlin_name_count_to_use_star_import=2147483647
ij_kotlin_name_count_to_use_star_import_for_members=2147483647
max_line_length = 120
indent_size = 4
insert_final_newline = true
ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ktlint_standard_filename=disabled
ktlint_standard_argument-list-wrapping=disabled
ktlint_standard_function-naming=disabled
ktlint_standard_property-naming=disabled
ktlint_standard_multiline-expression-wrapping=disabled
ktlint_standard_string-template-indent=disabled
ktlint_standard_comment-wrapping=disabled
ktlint_standard_filename = disabled
ktlint_standard_argument-list-wrapping = disabled
ktlint_standard_function-naming = disabled
ktlint_standard_property-naming = disabled
ktlint_standard_multiline-expression-wrapping = disabled
ktlint_standard_string-template-indent = disabled
ktlint_standard_comment-wrapping = disabled

View File

@ -100,7 +100,11 @@ class SyncChaptersWithSource(
}
// Recognize chapter number for the chapter.
val chapterNumber = ChapterRecognition.parseChapterNumber(manga.title, chapter.name, chapter.chapterNumber)
val chapterNumber = ChapterRecognition.parseChapterNumber(
manga.title,
chapter.name,
chapter.chapterNumber,
)
chapter = chapter.copy(chapterNumber = chapterNumber)
val dbChapter = dbChapters.find { it.url == chapter.url }
@ -117,7 +121,12 @@ class SyncChaptersWithSource(
} else {
if (shouldUpdateDbChapter.await(dbChapter, chapter)) {
val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) &&
downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, manga.source)
downloadManager.isChapterDownloaded(
dbChapter.name,
dbChapter.scanlator,
/* SY --> */ manga.ogTitle /* SY <-- */,
manga.source,
)
if (shouldRenameChapter) {
downloadManager.renameChapter(source, manga, dbChapter, chapter)

View File

@ -14,7 +14,11 @@ import tachiyomi.source.local.isLocal
* Applies the view filters to the list of chapters obtained from the database.
* @return an observable of the list of chapters filtered and sorted.
*/
fun List<Chapter>.applyFilters(manga: Manga, downloadManager: DownloadManager/* SY --> */, mergedManga: Map<Long, Manga>/* SY <-- */): List<Chapter> {
fun List<Chapter>.applyFilters(
manga: Manga,
downloadManager: DownloadManager/* SY --> */,
mergedManga: Map<Long, Manga>, /* SY <-- */
): List<Chapter> {
val isLocalManga = manga.isLocal()
val unreadFilter = manga.unreadFilter
val downloadedFilter = manga.downloadedFilter
@ -28,13 +32,21 @@ fun List<Chapter>.applyFilters(manga: Manga, downloadManager: DownloadManager/*
val manga = mergedManga.getOrElse(chapter.mangaId) { manga }
// SY <--
applyFilter(downloadedFilter) {
val downloaded = downloadManager.isChapterDownloaded(chapter.name, chapter.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, manga.source)
val downloaded = downloadManager.isChapterDownloaded(
chapter.name,
chapter.scanlator,
/* SY --> */ manga.ogTitle /* SY <-- */,
manga.source,
)
downloaded || isLocalManga
}
}
// SY -->
.filter { chapter ->
manga.filteredScanlators.isNullOrEmpty() || MdUtil.getScanlators(chapter.scanlator).any { group -> manga.filteredScanlators!!.contains(group) }
manga.filteredScanlators.isNullOrEmpty() ||
MdUtil.getScanlators(chapter.scanlator).any { group ->
manga.filteredScanlators!!.contains(group)
}
}
// SY <--
.sortedWith(getChapterSort(manga))
@ -55,7 +67,10 @@ fun List<ChapterList.Item>.applyFilters(manga: Manga): Sequence<ChapterList.Item
.filter { applyFilter(downloadedFilter) { it.isDownloaded || isLocalManga } }
// SY -->
.filter { chapter ->
manga.filteredScanlators.isNullOrEmpty() || MdUtil.getScanlators(chapter.chapter.scanlator).any { group -> manga.filteredScanlators!!.contains(group) }
manga.filteredScanlators.isNullOrEmpty() ||
MdUtil.getScanlators(chapter.chapter.scanlator).any { group ->
manga.filteredScanlators!!.contains(group)
}
}
// SY <--
.sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) }

View File

@ -24,8 +24,9 @@ class GetExtensionsByType(
val (updates, installed) = _installed
.filter { (showNsfwSources || it.isNsfw.not()) }
.sortedWith(
compareBy<Extension.Installed> { it.isObsolete.not() /* SY --> */ && it.isRedundant.not() /* SY <-- */ }
.thenBy(String.CASE_INSENSITIVE_ORDER) { it.name },
compareBy<Extension.Installed> {
it.isObsolete.not() /* SY --> */ && it.isRedundant.not() /* SY <-- */
}.thenBy(String.CASE_INSENSITIVE_ORDER) { it.name },
)
.partition { it.hasUpdate }

View File

@ -11,7 +11,12 @@ class SourcePreferences(
private val preferenceStore: PreferenceStore,
) {
fun sourceDisplayMode() = preferenceStore.getObject("pref_display_mode_catalogue", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize)
fun sourceDisplayMode() = preferenceStore.getObject(
"pref_display_mode_catalogue",
LibraryDisplayMode.default,
LibraryDisplayMode.Serializer::serialize,
LibraryDisplayMode.Serializer::deserialize,
)
fun enabledLanguages() = preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
@ -28,7 +33,10 @@ class SourcePreferences(
fun migrationSortingMode() = preferenceStore.getEnum("pref_migration_sorting", SetMigrateSorting.Mode.ALPHABETICAL)
fun migrationSortingDirection() = preferenceStore.getEnum("pref_migration_direction", SetMigrateSorting.Direction.ASCENDING)
fun migrationSortingDirection() = preferenceStore.getEnum(
"pref_migration_direction",
SetMigrateSorting.Direction.ASCENDING,
)
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)

View File

@ -61,7 +61,10 @@ class AddTracks(
?.readAt
firstReadChapterDate?.let {
val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC)
val startDate = firstReadChapterDate.time.convertEpochMillisZone(
ZoneOffset.systemDefault(),
ZoneOffset.UTC,
)
track = track.copy(
startDate = startDate,
)

View File

@ -43,7 +43,9 @@ class DelayedTrackingUpdateJob(private val context: Context, workerParams: Worke
track?.copy(lastChapterRead = it.lastChapterRead.toDouble())
}
.forEach { track ->
logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.mangaId}, last chapter read: ${track.lastChapterRead}" }
logcat(LogPriority.DEBUG) {
"Updating delayed track item: ${track.mangaId}, last chapter read: ${track.lastChapterRead}"
}
trackChapter.await(context, track.mangaId, track.lastChapterRead)
}
}

View File

@ -113,14 +113,26 @@ private fun MigrateSourceList(
IconButton(onClick = onToggleSortingMode) {
when (sortingMode) {
SetMigrateSorting.Mode.ALPHABETICAL -> Icon(Icons.Outlined.SortByAlpha, contentDescription = stringResource(R.string.action_sort_alpha))
SetMigrateSorting.Mode.TOTAL -> Icon(Icons.Outlined.Numbers, contentDescription = stringResource(R.string.action_sort_count))
SetMigrateSorting.Mode.ALPHABETICAL -> Icon(
Icons.Outlined.SortByAlpha,
contentDescription = stringResource(R.string.action_sort_alpha),
)
SetMigrateSorting.Mode.TOTAL -> Icon(
Icons.Outlined.Numbers,
contentDescription = stringResource(R.string.action_sort_count),
)
}
}
IconButton(onClick = onToggleSortingDirection) {
when (sortingDirection) {
SetMigrateSorting.Direction.ASCENDING -> Icon(Icons.Outlined.ArrowUpward, contentDescription = stringResource(R.string.action_asc))
SetMigrateSorting.Direction.DESCENDING -> Icon(Icons.Outlined.ArrowDownward, contentDescription = stringResource(R.string.action_desc))
SetMigrateSorting.Direction.ASCENDING -> Icon(
Icons.Outlined.ArrowUpward,
contentDescription = stringResource(R.string.action_asc),
)
SetMigrateSorting.Direction.DESCENDING -> Icon(
Icons.Outlined.ArrowDownward,
contentDescription = stringResource(R.string.action_desc),
)
}
}
}

View File

@ -173,7 +173,13 @@ private fun SourcePinButton(
onClick: () -> Unit,
) {
val icon = if (isPinned) Icons.Filled.PushPin else Icons.Outlined.PushPin
val tint = if (isPinned) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground.copy(alpha = SecondaryItemAlpha)
val tint = if (isPinned) {
MaterialTheme.colorScheme.primary
} else {
MaterialTheme.colorScheme.onBackground.copy(
alpha = SecondaryItemAlpha,
)
}
val description = if (isPinned) R.string.action_unpin else R.string.action_pin
IconButton(onClick = onClick) {
Icon(

View File

@ -25,7 +25,9 @@ fun BaseSourceItem(
action: @Composable RowScope.(Source) -> Unit = {},
content: @Composable RowScope.(Source, String?) -> Unit = defaultContent,
) {
val sourceLangString = LocaleHelper.getSourceDisplayName(source.lang, LocalContext.current).takeIf { showLanguageInContent }
val sourceLangString = LocaleHelper.getSourceDisplayName(source.lang, LocalContext.current).takeIf {
showLanguageInContent
}
BaseBrowseItem(
modifier = modifier,
onClickItem = onClickItem,

View File

@ -71,7 +71,10 @@ fun CategoryListItem(
}
Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = onRename) {
Icon(imageVector = Icons.Outlined.Edit, contentDescription = stringResource(R.string.action_rename_category))
Icon(
imageVector = Icons.Outlined.Edit,
contentDescription = stringResource(R.string.action_rename_category),
)
}
IconButton(onClick = onDelete) {
Icon(imageVector = Icons.Outlined.Delete, contentDescription = stringResource(R.string.action_delete))

View File

@ -764,7 +764,9 @@ fun MangaScreenLargeImpl(
val isReading = remember(state.chapters) {
state.chapters.fastAny { it.chapter.read }
}
Text(text = stringResource(if (isReading) R.string.action_resume else R.string.action_start))
Text(
text = stringResource(if (isReading) R.string.action_resume else R.string.action_start),
)
},
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
onClick = onContinueReading,
@ -1030,7 +1032,9 @@ private fun LazyListScope.sharedChapterItems(
it + 1,
)
},
scanlator = item.chapter.scanlator.takeIf { !it.isNullOrBlank() /* SY --> */ && item.showScanlator /* SY <-- */ },
scanlator = item.chapter.scanlator.takeIf {
!it.isNullOrBlank() /* SY --> */ && item.showScanlator /* SY <-- */
},
// SY -->
sourceName = item.sourceName,
// SY <--
@ -1082,7 +1086,11 @@ private fun onChapterItemClick(
}
// SY -->
typealias MetadataDescriptionComposable = @Composable (state: MangaScreenModel.State.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) -> Unit
typealias MetadataDescriptionComposable = @Composable (
state: MangaScreenModel.State.Success,
openMetadataViewer: () -> Unit,
search: (String) -> Unit,
) -> Unit
@Composable
fun metadataDescription(source: Source): MetadataDescriptionComposable? {

View File

@ -248,7 +248,8 @@ fun LibraryBottomActionMenu(
tonalElevation = 3.dp,
) {
val haptic = LocalHapticFeedback.current
val confirm = remember { mutableStateListOf(false, false, false, false, false /* SY --> */, false /* SY <-- */) }
val confirm =
remember { mutableStateListOf(false, false, false, false, false /* SY --> */, false /* SY <-- */) }
var resetJob: Job? = remember { null }
val onLongClickItem: (Int) -> Unit = { toConfirmIndex ->
haptic.performHapticFeedback(HapticFeedbackType.LongPress)

View File

@ -42,7 +42,6 @@ import androidx.compose.material.icons.outlined.Sync
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
@ -192,7 +191,11 @@ fun MangaActionRow(
)
if (onEditIntervalClicked != null && fetchInterval != null) {
MangaActionButton(
title = pluralStringResource(id = R.plurals.day, count = fetchInterval.absoluteValue, fetchInterval.absoluteValue),
title = pluralStringResource(
id = R.plurals.day,
count = fetchInterval.absoluteValue,
fetchInterval.absoluteValue,
),
icon = Icons.Default.HourglassEmpty,
color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
onClick = onEditIntervalClicked,
@ -625,7 +628,9 @@ private fun MangaSummary(
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down)
Icon(
painter = rememberAnimatedVectorPainter(image, !expanded),
contentDescription = stringResource(if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand),
contentDescription = stringResource(
if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand,
),
tint = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())),
)

View File

@ -72,7 +72,9 @@ fun MoreScreen(
WarningBanner(
textRes = R.string.fdroid_warning,
modifier = Modifier.clickable {
uriHandler.openUri("https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds")
uriHandler.openUri(
"https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds",
)
},
)
}

View File

@ -31,7 +31,8 @@ fun getCategoriesLabel(
val includedItemsText = when {
// Some selected, but not all
includedCategories.isNotEmpty() && includedCategories.size != allCategories.size -> includedCategories.joinToString { it.visualName(context) }
includedCategories.isNotEmpty() && includedCategories.size != allCategories.size ->
includedCategories.joinToString { it.visualName(context) }
// All explicitly selected
includedCategories.size == allCategories.size -> stringResource(R.string.all)
allExcluded -> stringResource(R.string.none)

View File

@ -124,7 +124,9 @@ object SettingsAppearanceScreen : SearchableSettings {
uiPreferences: UiPreferences,
): Preference.PreferenceGroup {
val langs = remember { getLangs(context) }
var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") }
var currentLanguage by remember {
mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "")
}
val now = remember { Date().time }
val dateFormat by uiPreferences.dateFormat().collectAsState()

View File

@ -181,7 +181,8 @@ object SettingsEhScreen : SearchableSettings {
unsortedPreferences: UnsortedPreferences,
openWarnConfigureDialogController: () -> Unit,
): Preference.PreferenceItem.SwitchPreference {
val activityResultContract = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val activityResultContract =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
// Upload settings
openWarnConfigureDialogController()
@ -932,7 +933,9 @@ object SettingsEhScreen : SearchableSettings {
}
@Composable
fun updateCheckerFrequency(unsortedPreferences: UnsortedPreferences): Preference.PreferenceItem.ListPreference<Int> {
fun updateCheckerFrequency(
unsortedPreferences: UnsortedPreferences,
): Preference.PreferenceItem.ListPreference<Int> {
val value by unsortedPreferences.exhAutoUpdateFrequency().collectAsState()
val context = LocalContext.current
return Preference.PreferenceItem.ListPreference(
@ -941,7 +944,12 @@ object SettingsEhScreen : SearchableSettings {
subtitle = if (value == 0) {
stringResource(R.string.time_between_batches_summary_1, stringResource(R.string.app_name))
} else {
stringResource(R.string.time_between_batches_summary_2, stringResource(R.string.app_name), value, EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION)
stringResource(
R.string.time_between_batches_summary_2,
stringResource(R.string.app_name),
value,
EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION,
)
},
entries = mapOf(
0 to stringResource(R.string.time_between_batches_never),
@ -961,7 +969,9 @@ object SettingsEhScreen : SearchableSettings {
}
@Composable
fun autoUpdateRequirements(unsortedPreferences: UnsortedPreferences): Preference.PreferenceItem.MultiSelectListPreference {
fun autoUpdateRequirements(
unsortedPreferences: UnsortedPreferences,
): Preference.PreferenceItem.MultiSelectListPreference {
val value by unsortedPreferences.exhAutoUpdateRequirements().collectAsState()
val context = LocalContext.current
return Preference.PreferenceItem.MultiSelectListPreference(
@ -1100,12 +1110,18 @@ object SettingsEhScreen : SearchableSettings {
private fun getRelativeTimeString(relativeTime: RelativeTime, context: Context): String {
return relativeTime.years?.let { context.resources.getQuantityString(R.plurals.humanize_year, it.toInt(), it) }
?: relativeTime.months?.let { context.resources.getQuantityString(R.plurals.humanize_month, it.toInt(), it) }
?: relativeTime.months?.let {
context.resources.getQuantityString(R.plurals.humanize_month, it.toInt(), it)
}
?: relativeTime.weeks?.let { context.resources.getQuantityString(R.plurals.humanize_week, it.toInt(), it) }
?: relativeTime.days?.let { context.resources.getQuantityString(R.plurals.humanize_day, it.toInt(), it) }
?: relativeTime.hours?.let { context.resources.getQuantityString(R.plurals.humanize_hour, it.toInt(), it) }
?: relativeTime.minutes?.let { context.resources.getQuantityString(R.plurals.humanize_minute, it.toInt(), it) }
?: relativeTime.seconds?.let { context.resources.getQuantityString(R.plurals.humanize_second, it.toInt(), it) }
?: relativeTime.minutes?.let {
context.resources.getQuantityString(R.plurals.humanize_minute, it.toInt(), it)
}
?: relativeTime.seconds?.let {
context.resources.getQuantityString(R.plurals.humanize_second, it.toInt(), it)
}
?: context.getString(R.string.humanize_fallback)
}
@ -1138,7 +1154,12 @@ object SettingsEhScreen : SearchableSettings {
}
val statsText = if (stats != null) {
context.getString(R.string.gallery_updater_stats_text, getRelativeTimeString(getRelativeTimeFromNow(stats.startTime.milliseconds), context), stats.updateCount, stats.possibleUpdates)
context.getString(
R.string.gallery_updater_stats_text,
getRelativeTimeString(getRelativeTimeFromNow(stats.startTime.milliseconds), context),
stats.updateCount,
stats.possibleUpdates,
)
} else {
context.getString(R.string.gallery_updater_not_ran_yet)
}

View File

@ -100,7 +100,10 @@ object SettingsMangadexScreen : SearchableSettings {
}
@Composable
fun loginPreference(mdex: MangaDex, trackPreferences: TrackPreferences): Preference.PreferenceItem.CustomPreference {
fun loginPreference(
mdex: MangaDex,
trackPreferences: TrackPreferences,
): Preference.PreferenceItem.CustomPreference {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val loggedIn by remember { trackPreferences.trackToken(mdex.mdList) }.collectAsState()

View File

@ -115,7 +115,9 @@ class WorkerInfoScreen : Screen() {
private val workManager = context.workManager
val finished = workManager
.getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
.getWorkInfosLiveData(
WorkQuery.fromStates(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED),
)
.asFlow()
.map(::constructString)
.stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "")

View File

@ -115,8 +115,16 @@ fun <T> TriStateListDialog(
}
}
if (!listState.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
if (!listState.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
if (!listState.isScrolledToStart()) {
HorizontalDivider(
modifier = Modifier.align(Alignment.TopCenter),
)
}
if (!listState.isScrolledToEnd()) {
HorizontalDivider(
modifier = Modifier.align(Alignment.BottomCenter),
)
}
}
}
},

View File

@ -53,6 +53,6 @@ fun PageIndicatorText(
@Composable
private fun PageIndicatorTextPreview() {
TachiyomiTheme {
PageIndicatorText(currentPage = 10, totalPages = 69)
PageIndicatorText(currentPage = "10", totalPages = 69)
}
}

View File

@ -103,7 +103,9 @@ fun ChapterNavigator(
) {
Icon(
imageVector = Icons.Outlined.SkipPrevious,
contentDescription = stringResource(if (isRtl) R.string.action_next_chapter else R.string.action_previous_chapter),
contentDescription = stringResource(
if (isRtl) R.string.action_next_chapter else R.string.action_previous_chapter,
),
)
}
@ -155,7 +157,9 @@ fun ChapterNavigator(
) {
Icon(
imageVector = Icons.Outlined.SkipNext,
contentDescription = stringResource(if (isRtl) R.string.action_previous_chapter else R.string.action_next_chapter),
contentDescription = stringResource(
if (isRtl) R.string.action_previous_chapter else R.string.action_next_chapter,
),
)
}
}

View File

@ -61,7 +61,7 @@ fun ExhUtils(
Column(
modifier
.fillMaxWidth()
.background(backgroundColor)
.background(backgroundColor),
) {
AnimatedVisibility(visible = isVisible) {
Column {
@ -83,12 +83,12 @@ fun ExhUtils(
fontSize = 13.sp,
fontFamily = FontFamily.SansSerif,
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(start = 24.dp)
modifier = Modifier.padding(start = 24.dp),
)
Switch(
checked = isAutoScroll,
onCheckedChange = null,
enabled = isAutoScrollEnabled
enabled = isAutoScrollEnabled,
)
}
Row(
@ -112,18 +112,18 @@ fun ExhUtils(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
focusedTextColor = MaterialTheme.colorScheme.onSurface,
unfocusedTextColor = MaterialTheme.colorScheme.onSurface
unfocusedTextColor = MaterialTheme.colorScheme.onSurface,
),
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Decimal
keyboardType = KeyboardType.Decimal,
),
)
AnimatedVisibility(!isAutoScrollEnabled) {
Text(
text = stringResource(R.string.eh_autoscroll_freq_invalid),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.labelSmall
style = MaterialTheme.typography.labelSmall,
)
}
}
@ -147,7 +147,7 @@ fun ExhUtils(
Row(
Modifier.fillMaxWidth(0.5f),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
verticalAlignment = Alignment.CenterVertically,
) {
TextButton(
onClick = onClickRetryAll,
@ -157,7 +157,7 @@ fun ExhUtils(
text = stringResource(R.string.eh_retry_all),
color = MaterialTheme.colorScheme.onSurface,
fontSize = 13.sp,
fontFamily = FontFamily.SansSerif
fontFamily = FontFamily.SansSerif,
)
}
TextButton(
@ -175,7 +175,7 @@ fun ExhUtils(
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
verticalAlignment = Alignment.CenterVertically,
) {
TextButton(
onClick = onClickBoostPage,
@ -185,7 +185,7 @@ fun ExhUtils(
text = stringResource(R.string.eh_boost_page),
color = MaterialTheme.colorScheme.onSurface,
fontSize = 13.sp,
fontFamily = FontFamily.SansSerif
fontFamily = FontFamily.SansSerif,
)
}
TextButton(
@ -206,7 +206,7 @@ fun ExhUtils(
IconButton(
onClick = { onSetExhUtilsVisibility(!isVisible) },
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth(),
) {
Icon(
imageVector = if (isVisible) {
@ -237,7 +237,7 @@ private fun ExhUtilsPreview() {
onClickBoostPage = {},
onClickBoostPageHelp = {},
onClickRetryAll = {},
onClickRetryAllHelp = {}
onClickRetryAllHelp = {},
)
}
}

View File

@ -46,11 +46,11 @@ enum class NavBarType {
fun BoxIgnoreLayoutDirection(modifier: Modifier, content: @Composable BoxScope.() -> Unit) {
val layoutDirection = LocalLayoutDirection.current
CompositionLocalProvider(
LocalLayoutDirection provides LayoutDirection.Ltr
LocalLayoutDirection provides LayoutDirection.Ltr,
) {
Box(modifier) {
CompositionLocalProvider(
LocalLayoutDirection provides layoutDirection
LocalLayoutDirection provides layoutDirection,
) {
content()
}
@ -125,7 +125,7 @@ fun ReaderAppBars(
// SY -->
BoxIgnoreLayoutDirection(
Modifier.fillMaxWidth()
Modifier.fillMaxWidth(),
) {
AnimatedVisibility(
visible = visible && navBarType == NavBarType.VerticalLeft,
@ -139,7 +139,7 @@ fun ReaderAppBars(
),
modifier = modifierWithInsetsPadding
.padding(bottom = 48.dp, top = 120.dp)
.align(Alignment.TopStart)
.align(Alignment.TopStart),
) {
ChapterNavigator(
isRtl = isRtl,
@ -167,7 +167,7 @@ fun ReaderAppBars(
),
modifier = modifierWithInsetsPadding
.padding(bottom = 48.dp, top = 120.dp)
.align(Alignment.TopEnd)
.align(Alignment.TopEnd),
) {
ChapterNavigator(
isRtl = isRtl,
@ -246,13 +246,12 @@ fun ReaderAppBars(
onClickRetryAll = onClickRetryAll,
onClickRetryAllHelp = onClickRetryAllHelp,
onClickBoostPage = onClickBoostPage,
onClickBoostPageHelp = onClickBoostPageHelp
onClickBoostPageHelp = onClickBoostPageHelp,
)
// SY <--
}
}
Spacer(modifier = Modifier.weight(1f))
AnimatedVisibility(
@ -304,7 +303,7 @@ fun ReaderAppBars(
onClickWebView = onOpenInWebView,
onClickShare = onShare,
onClickPageLayout = onClickPageLayout,
onClickShiftPage = onClickShiftPage
onClickShiftPage = onClickShiftPage,
)
}
}

View File

@ -104,7 +104,11 @@ internal fun LazyListScope.updatesUiItems(
update = updatesItem.update,
selected = updatesItem.selected,
readProgress = updatesItem.update.lastPageRead
.takeIf { /* SY --> */(!updatesItem.update.read || (preserveReadingPosition && updatesItem.isEhBasedUpdate()))/* SY <-- */ && it > 0L }
.takeIf {
/* SY --> */(
!updatesItem.update.read || (preserveReadingPosition && updatesItem.isEhBasedUpdate())
)/* SY <-- */ && it > 0L
}
?.let {
stringResource(
R.string.chapter_progress,

View File

@ -173,7 +173,9 @@ fun WebViewScreenContent(
modifier = Modifier
.clip(MaterialTheme.shapes.small)
.clickable {
uriHandler.openUri("https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare")
uriHandler.openUri(
"https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare",
)
},
)
}

View File

@ -304,7 +304,12 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
fun register() {
if (!registered) {
ContextCompat.registerReceiver(this@App, this, IntentFilter(ACTION_DISABLE_INCOGNITO_MODE), ContextCompat.RECEIVER_NOT_EXPORTED)
ContextCompat.registerReceiver(
this@App,
this,
IntentFilter(ACTION_DISABLE_INCOGNITO_MODE),
ContextCompat.RECEIVER_NOT_EXPORTED,
)
registered = true
}
}

View File

@ -123,13 +123,22 @@ object Migrations {
}
}
prefs.edit {
putInt(libraryPreferences.filterDownloaded().key(), convertBooleanPrefToTriState("pref_filter_downloaded_key"))
putInt(
libraryPreferences.filterDownloaded().key(),
convertBooleanPrefToTriState("pref_filter_downloaded_key"),
)
remove("pref_filter_downloaded_key")
putInt(libraryPreferences.filterUnread().key(), convertBooleanPrefToTriState("pref_filter_unread_key"))
putInt(
libraryPreferences.filterUnread().key(),
convertBooleanPrefToTriState("pref_filter_unread_key"),
)
remove("pref_filter_unread_key")
putInt(libraryPreferences.filterCompleted().key(), convertBooleanPrefToTriState("pref_filter_completed_key"))
putInt(
libraryPreferences.filterCompleted().key(),
convertBooleanPrefToTriState("pref_filter_completed_key"),
)
remove("pref_filter_completed_key")
}
}
@ -245,7 +254,10 @@ object Migrations {
if (oldSecureScreen) {
securityPreferences.secureScreen().set(SecurityPreferences.SecureScreenMode.ALWAYS)
}
if (DeviceUtil.isMiui && basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER) {
if (
DeviceUtil.isMiui &&
basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER
) {
basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.LEGACY)
}
}
@ -262,7 +274,12 @@ object Migrations {
if (oldVersion < 81) {
// Handle renamed enum values
prefs.edit {
val newSortingMode = when (val oldSortingMode = prefs.getString(libraryPreferences.sortingMode().key(), "ALPHABETICAL")) {
val newSortingMode = when (
val oldSortingMode = prefs.getString(
libraryPreferences.sortingMode().key(),
"ALPHABETICAL",
)
) {
"LAST_CHECKED" -> "LAST_MANGA_UPDATE"
"UNREAD" -> "UNREAD_COUNT"
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE"

View File

@ -104,7 +104,8 @@ class BackupCreator(
throw IllegalStateException(context.getString(R.string.missing_storage_permission))
}
val databaseManga = getFavorites.await() /* SY --> */ + if (flags and BACKUP_READ_MANGA_MASK == BACKUP_READ_MANGA) {
val databaseManga = getFavorites.await() /* SY --> */ +
if (flags and BACKUP_READ_MANGA_MASK == BACKUP_READ_MANGA) {
handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) }
} else {
emptyList()
@ -226,12 +227,18 @@ class BackupCreator(
val mangaObject = BackupManga.copyFrom(
manga,
// SY -->
if (options and BACKUP_CUSTOM_INFO_MASK == BACKUP_CUSTOM_INFO) getCustomMangaInfo.get(manga.id) else null, /* SY <-- */
if (options and BACKUP_CUSTOM_INFO_MASK == BACKUP_CUSTOM_INFO) {
getCustomMangaInfo.get(manga.id)
} else {
null
}, /* SY <-- */
)
// SY -->
if (manga.source == MERGED_SOURCE_ID) {
mangaObject.mergedMangaReferences = handler.awaitList { mergedQueries.selectByMergeId(manga.id, backupMergedMangaReferenceMapper) }
mangaObject.mergedMangaReferences = handler.awaitList {
mergedQueries.selectByMergeId(manga.id, backupMergedMangaReferenceMapper)
}
}
val source = sourceManager.get(manga.source)?.getMainSource<MetadataSource<*, *>>()

View File

@ -20,7 +20,9 @@ class BackupNotifier(private val context: Context) {
private val preferences: SecurityPreferences by injectLazy()
private val progressNotificationBuilder = context.notificationBuilder(Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS) {
private val progressNotificationBuilder = context.notificationBuilder(
Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS,
) {
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
setSmallIcon(R.drawable.ic_tachi)
setAutoCancel(false)
@ -28,7 +30,9 @@ class BackupNotifier(private val context: Context) {
setOnlyAlertOnce(true)
}
private val completeNotificationBuilder = context.notificationBuilder(Notifications.CHANNEL_BACKUP_RESTORE_COMPLETE) {
private val completeNotificationBuilder = context.notificationBuilder(
Notifications.CHANNEL_BACKUP_RESTORE_COMPLETE,
) {
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
setSmallIcon(R.drawable.ic_tachi)
setAutoCancel(false)
@ -72,14 +76,25 @@ class BackupNotifier(private val context: Context) {
addAction(
R.drawable.ic_share_24dp,
context.getString(R.string.action_share),
NotificationReceiver.shareBackupPendingBroadcast(context, unifile.uri, Notifications.ID_BACKUP_COMPLETE),
NotificationReceiver.shareBackupPendingBroadcast(
context,
unifile.uri,
Notifications.ID_BACKUP_COMPLETE,
),
)
show(Notifications.ID_BACKUP_COMPLETE)
}
}
fun showRestoreProgress(content: String = "", contentTitle: String = context.getString(R.string.restoring_backup), progress: Int = 0, maxAmount: Int = 100): NotificationCompat.Builder {
fun showRestoreProgress(
content: String = "",
contentTitle: String = context.getString(
R.string.restoring_backup,
),
progress: Int = 0,
maxAmount: Int = 100,
): NotificationCompat.Builder {
val builder = with(progressNotificationBuilder) {
setContentTitle(contentTitle)
@ -114,7 +129,15 @@ class BackupNotifier(private val context: Context) {
}
}
fun showRestoreComplete(time: Long, errorCount: Int, path: String?, file: String?, contentTitle: String = context.getString(R.string.restore_completed)) {
fun showRestoreComplete(
time: Long,
errorCount: Int,
path: String?,
file: String?,
contentTitle: String = context.getString(
R.string.restore_completed,
),
) {
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
val timeString = context.getString(
@ -127,7 +150,14 @@ class BackupNotifier(private val context: Context) {
with(completeNotificationBuilder) {
setContentTitle(contentTitle)
setContentText(context.resources.getQuantityString(R.plurals.restore_completed_message, errorCount, timeString, errorCount))
setContentText(
context.resources.getQuantityString(
R.plurals.restore_completed_message,
errorCount,
timeString,
errorCount,
),
)
clearActions()
if (errorCount > 0 && !path.isNullOrEmpty() && !file.isNullOrEmpty()) {

View File

@ -108,7 +108,13 @@ class BackupRestorer(
val logFile = writeErrorLog()
if (sync) {
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name, contentTitle = context.getString(R.string.library_sync_complete))
notifier.showRestoreComplete(
time,
errors.size,
logFile.parent,
logFile.name,
contentTitle = context.getString(R.string.library_sync_complete),
)
} else {
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
}
@ -210,7 +216,12 @@ class BackupRestorer(
)
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories), context.getString(R.string.restoring_backup))
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.categories),
context.getString(R.string.restoring_backup),
)
}
// SY -->
@ -234,7 +245,12 @@ class BackupRestorer(
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.saved_searches), context.getString(R.string.restoring_backup))
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.saved_searches),
context.getString(R.string.restoring_backup),
)
}
// SY <--
@ -259,13 +275,33 @@ class BackupRestorer(
val dbManga = getMangaFromDatabase(manga.url, manga.source)
val restoredManga = if (dbManga == null) {
// Manga not in database
restoreExistingManga(manga, chapters, categories, history, tracks, backupCategories/* SY --> */, mergedMangaReferences, flatMetadata, customManga/* SY <-- */)
restoreExistingManga(
manga = manga,
chapters = chapters,
categories = categories,
history = history,
tracks = tracks,
backupCategories = backupCategories/* SY --> */,
mergedMangaReferences = mergedMangaReferences,
flatMetadata = flatMetadata,
customManga = customManga, /* SY <-- */
)
} else {
// Manga in database
// Copy information from manga already in database
val updatedManga = restoreExistingManga(manga, dbManga)
// Fetch rest of manga information
restoreNewManga(updatedManga, chapters, categories, history, tracks, backupCategories/* SY --> */, mergedMangaReferences, flatMetadata, customManga/* SY <-- */)
restoreNewManga(
backupManga = updatedManga,
chapters = chapters,
categories = categories,
history = history,
tracks = tracks,
backupCategories = backupCategories/* SY --> */,
mergedMangaReferences = mergedMangaReferences,
flatMetadata = flatMetadata,
customManga = customManga, /* SY <-- */
)
}
updateManga.awaitUpdateFetchInterval(restoredManga, now, currentFetchWindow)
} catch (e: Exception) {
@ -275,9 +311,19 @@ class BackupRestorer(
restoreProgress += 1
if (sync) {
showRestoreProgress(restoreProgress, restoreAmount, manga.title, context.getString(R.string.syncing_library))
showRestoreProgress(
restoreProgress,
restoreAmount,
manga.title,
context.getString(R.string.syncing_library),
)
} else {
showRestoreProgress(restoreProgress, restoreAmount, manga.title, context.getString(R.string.restoring_backup))
showRestoreProgress(
restoreProgress,
restoreAmount,
manga.title,
context.getString(R.string.restoring_backup),
)
}
}
@ -350,7 +396,16 @@ class BackupRestorer(
): Manga {
val fetchedManga = restoreNewManga(manga)
restoreChapters(fetchedManga, chapters)
restoreExtras(fetchedManga, categories, history, tracks, backupCategories/* SY --> */, mergedMangaReferences, flatMetadata, customManga/* SY <-- */)
restoreExtras(
manga = fetchedManga,
categories = categories,
history = history,
tracks = tracks,
backupCategories = backupCategories/* SY --> */,
mergedMangaReferences = mergedMangaReferences,
flatMetadata = flatMetadata,
customManga = customManga, /* SY <-- */
)
return fetchedManga
}
@ -498,7 +553,16 @@ class BackupRestorer(
// SY <--
): Manga {
restoreChapters(backupManga, chapters)
restoreExtras(backupManga, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, customManga)
restoreExtras(
manga = backupManga,
categories = categories,
history = history,
tracks = tracks,
backupCategories = backupCategories,
mergedMangaReferences = mergedMangaReferences,
flatMetadata = flatMetadata,
customManga = customManga,
)
return backupManga
}
@ -696,17 +760,33 @@ class BackupRestorer(
* @param manga the merge manga for the references
* @param backupMergedMangaReferences the list of backup manga references for the merged manga
*/
internal suspend fun restoreMergedMangaReferencesForManga(mergeMangaId: Long, backupMergedMangaReferences: List<BackupMergedMangaReference>) {
internal suspend fun restoreMergedMangaReferencesForManga(
mergeMangaId: Long,
backupMergedMangaReferences: List<BackupMergedMangaReference>,
) {
// Get merged manga references from file and from db
val dbMergedMangaReferences = handler.awaitList { mergedQueries.selectAll(MergedMangaMapper::map) }
val dbMergedMangaReferences = handler.awaitList {
mergedQueries.selectAll(MergedMangaMapper::map)
}
// Iterate over them
backupMergedMangaReferences.forEach { backupMergedMangaReference ->
// If the backupMergedMangaReference isn't in the db, remove the id and insert a new backupMergedMangaReference
// If the backupMergedMangaReference isn't in the db,
// remove the id and insert a new backupMergedMangaReference
// Store the inserted id in the backupMergedMangaReference
if (dbMergedMangaReferences.none { backupMergedMangaReference.mergeUrl == it.mergeUrl && backupMergedMangaReference.mangaUrl == it.mangaUrl }) {
if (dbMergedMangaReferences.none {
backupMergedMangaReference.mergeUrl == it.mergeUrl &&
backupMergedMangaReference.mangaUrl == it.mangaUrl
}
) {
// Let the db assign the id
val mergedManga = handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(backupMergedMangaReference.mangaUrl, backupMergedMangaReference.mangaSourceId, MangaMapper::mapManga) } ?: return@forEach
val mergedManga = handler.awaitOneOrNull {
mangasQueries.getMangaByUrlAndSource(
backupMergedMangaReference.mangaUrl,
backupMergedMangaReference.mangaSourceId,
MangaMapper::mapManga,
)
} ?: return@forEach
backupMergedMangaReference.getMergedMangaReference().run {
handler.await {
mergedQueries.insert(
@ -746,7 +826,12 @@ class BackupRestorer(
BackupCreateJob.setupTask(context)
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.app_settings), context.getString(R.string.restoring_backup))
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.app_settings),
context.getString(R.string.restoring_backup),
)
}
private fun restoreSourcePreferences(preferences: List<BackupSourcePreferences>) {
@ -756,7 +841,12 @@ class BackupRestorer(
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.source_settings), context.getString(R.string.restoring_backup))
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.source_settings),
context.getString(R.string.restoring_backup),
)
}
private fun restorePreferences(

View File

@ -29,7 +29,9 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti
if (resources.sourceOrNull()?.peek()?.use { CbzCrypto.detectCoverImageArchive(it.inputStream()) } == true) {
if (resources.source().peek().use { ImageUtil.findImageType(it.inputStream()) == null }) {
zip4j = ZipFile(resources.file().toFile().absolutePath)
entry = zip4j.fileHeaders.firstOrNull { it.fileName.equals(CbzCrypto.DEFAULT_COVER_NAME, ignoreCase = true) }
entry = zip4j.fileHeaders.firstOrNull {
it.fileName.equals(CbzCrypto.DEFAULT_COVER_NAME, ignoreCase = true)
}
if (zip4j.isEncrypted) zip4j.setPassword(CbzCrypto.getDecryptedPasswordCbz())
}

View File

@ -148,7 +148,10 @@ class DownloadCache(
if (sourceDir != null) {
val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(mangaTitle)]
if (mangaDir != null) {
return provider.getValidChapterDirNames(chapterName, chapterScanlator).any { it in mangaDir.chapterDirs }
return provider.getValidChapterDirNames(
chapterName,
chapterScanlator,
).any { it in mangaDir.chapterDirs }
}
}
return false

View File

@ -156,7 +156,12 @@ class DownloadManager(
* @return the list of pages from the chapter.
*/
fun buildPageList(source: Source, manga: Manga, chapter: Chapter): List<Page> {
val chapterDir = provider.findChapterDir(chapter.name, chapter.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, source)
val chapterDir = provider.findChapterDir(
chapter.name,
chapter.scanlator,
/* SY --> */ manga.ogTitle /* SY <-- */,
source,
)
val files = chapterDir?.listFiles().orEmpty()
.filter { "image" in it.type.orEmpty() }
@ -292,7 +297,13 @@ class DownloadManager(
* @param manga the manga of the chapters.
* @param source the source of the chapters.
*/
suspend fun cleanupChapters(allChapters: List<Chapter>, manga: Manga, source: Source, removeRead: Boolean, removeNonFavorite: Boolean): Int {
suspend fun cleanupChapters(
allChapters: List<Chapter>,
manga: Manga,
source: Source,
removeRead: Boolean,
removeNonFavorite: Boolean,
): Int {
var cleaned = 0
if (removeNonFavorite && !manga.favorite) {

View File

@ -95,7 +95,10 @@ internal class DownloadNotifier(private val context: Context) {
} else {
val title = download.manga.title.chop(15)
val quotedTitle = Pattern.quote(title)
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
val chapter = download.chapter.name.replaceFirst(
"$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE),
"",
)
setContentTitle("$title - $chapter".chop(30))
setContentText(downloadingProgressText)
}

View File

@ -286,7 +286,9 @@ class Downloader(
val wasEmpty = queueState.value.isEmpty()
val chaptersWithoutDir = chapters
// Filter out those already downloaded.
.filter { provider.findChapterDir(it.name, it.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, source) == null }
.filter {
provider.findChapterDir(it.name, it.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, source) == null
}
// Add chapters to queue from the start.
.sortedByDescending { it.sourceOrder }
@ -335,7 +337,11 @@ class Downloader(
val availSpace = DiskUtil.getAvailableStorageSpace(mangaDir)
if (availSpace != -1L && availSpace < MIN_DISK_SPACE) {
download.status = Download.State.ERROR
notifier.onError(context.getString(R.string.download_insufficient_space), download.chapter.name, download.manga.title)
notifier.onError(
context.getString(R.string.download_insufficient_space),
download.chapter.name,
download.manga.title,
)
return
}
@ -449,13 +455,16 @@ class Downloader(
tmpFile?.delete()
// Try to find the image file
val imageFile = tmpDir.listFiles()?.firstOrNull { it.name!!.startsWith("$filename.") || it.name!!.startsWith("${filename}__001") }
val imageFile = tmpDir.listFiles()?.firstOrNull {
it.name!!.startsWith("$filename.") || it.name!!.startsWith("${filename}__001")
}
try {
// If the image is already downloaded, do nothing. Otherwise download from network
val file = when {
imageFile != null -> imageFile
chapterCache.isImageInCache(page.imageUrl!!) -> copyImageFromCache(chapterCache.getImageFile(page.imageUrl!!), tmpDir, filename)
chapterCache.isImageInCache(page.imageUrl!!) ->
copyImageFromCache(chapterCache.getImageFile(page.imageUrl!!), tmpDir, filename)
else -> downloadImage(page, download.source, tmpDir, filename, dataSaver)
}
@ -482,7 +491,13 @@ class Downloader(
* @param tmpDir the temporary directory of the download.
* @param filename the filename of the image.
*/
private suspend fun downloadImage(page: Page, source: HttpSource, tmpDir: UniFile, filename: String, dataSaver: DataSaver): UniFile {
private suspend fun downloadImage(
page: Page,
source: HttpSource,
tmpDir: UniFile,
filename: String,
dataSaver: DataSaver,
): UniFile {
page.status = Page.State.DOWNLOAD_IMAGE
page.progress = 0
return flow {

View File

@ -402,7 +402,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
val errorMessage = when (e) {
is NoChaptersException -> context.getString(R.string.no_chapters_error)
// failedUpdates will already have the source, don't need to copy it into the message
is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error)
is SourceNotInstalledException -> context.getString(
R.string.loader_not_implemented_error,
)
else -> e.message
}
failedUpdates.add(manga to errorMessage)
@ -722,7 +724,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
if (interval > 0) {
val restrictions = preferences.autoUpdateDeviceRestrictions().get()
val constraints = Constraints(
requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED },
requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) {
NetworkType.UNMETERED
} else { NetworkType.CONNECTED },
requiresCharging = DEVICE_CHARGING in restrictions,
requiresBatteryNotLow = true,
)
@ -739,7 +743,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
.setBackoffCriteria(BackoffPolicy.LINEAR, 10, TimeUnit.MINUTES)
.build()
context.workManager.enqueueUniquePeriodicWork(WORK_NAME_AUTO, ExistingPeriodicWorkPolicy.UPDATE, request)
context.workManager.enqueueUniquePeriodicWork(
WORK_NAME_AUTO,
ExistingPeriodicWorkPolicy.UPDATE,
request,
)
} else {
context.workManager.cancelUniqueWork(WORK_NAME_AUTO)
}

View File

@ -82,7 +82,12 @@ class LibraryUpdateNotifier(private val context: Context) {
} else {
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
progressNotificationBuilder
.setContentTitle(context.getString(R.string.notification_updating_progress, percentFormatter.format(current.toFloat() / total)))
.setContentTitle(
context.getString(
R.string.notification_updating_progress,
percentFormatter.format(current.toFloat() / total),
),
)
.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
}
@ -166,7 +171,13 @@ class LibraryUpdateNotifier(private val context: Context) {
if (updates.size == 1 && !preferences.hideNotificationContent().get()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else {
setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
setContentText(
context.resources.getQuantityString(
R.plurals.notification_new_chapters_summary,
updates.size,
updates.size,
),
)
if (!preferences.hideNotificationContent().get()) {
setStyle(
@ -196,7 +207,10 @@ class LibraryUpdateNotifier(private val context: Context) {
launchUI {
context.notify(
updates.map { (manga, chapters) ->
NotificationManagerCompat.NotificationWithIdAndTag(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
NotificationManagerCompat.NotificationWithIdAndTag(
manga.id.hashCode(),
createNewChaptersNotification(manga, chapters),
)
},
)
}
@ -292,17 +306,28 @@ class LibraryUpdateNotifier(private val context: Context) {
// No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
0 -> {
// "1 new chapter" or "5 new chapters"
context.resources.getQuantityString(R.plurals.notification_chapters_generic, chapters.size, chapters.size)
context.resources.getQuantityString(
R.plurals.notification_chapters_generic,
chapters.size,
chapters.size,
)
}
// Only 1 chapter has a parsed chapter number
1 -> {
val remaining = chapters.size - displayableChapterNumbers.size
if (remaining == 0) {
// "Chapter 2.5"
context.resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first())
context.resources.getString(
R.string.notification_chapters_single,
displayableChapterNumbers.first(),
)
} else {
// "Chapter 2.5 and 10 more"
context.resources.getString(R.string.notification_chapters_single_and_more, displayableChapterNumbers.first(), remaining)
context.resources.getString(
R.string.notification_chapters_single_and_more,
displayableChapterNumbers.first(),
remaining,
)
}
}
// Everything else (i.e. multiple parsed chapter numbers)
@ -312,10 +337,18 @@ class LibraryUpdateNotifier(private val context: Context) {
// "Chapters 1, 2.5, 3, 4, 5 and 10 more"
val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS
val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ")
context.resources.getQuantityString(R.plurals.notification_chapters_multiple_and_more, remaining, joinedChapterNumbers, remaining)
context.resources.getQuantityString(
R.plurals.notification_chapters_multiple_and_more,
remaining,
joinedChapterNumbers,
remaining,
)
} else {
// "Chapters 1, 2.5, 3"
context.resources.getString(R.string.notification_chapters_multiple, displayableChapterNumbers.joinToString(", "))
context.resources.getString(
R.string.notification_chapters_multiple,
displayableChapterNumbers.joinToString(", "),
)
}
}
}
@ -329,7 +362,12 @@ class LibraryUpdateNotifier(private val context: Context) {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = Constants.SHORTCUT_UPDATES
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
companion object {

View File

@ -23,7 +23,12 @@ object NotificationHandler {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = Constants.SHORTCUT_DOWNLOADS
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -37,7 +42,12 @@ object NotificationHandler {
setDataAndType(uri, "image/*")
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**

View File

@ -306,7 +306,12 @@ class NotificationReceiver : BroadcastReceiver() {
val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_RESUME_DOWNLOADS
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -319,7 +324,12 @@ class NotificationReceiver : BroadcastReceiver() {
val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_PAUSE_DOWNLOADS
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -332,7 +342,12 @@ class NotificationReceiver : BroadcastReceiver() {
val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CLEAR_DOWNLOADS
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -347,7 +362,12 @@ class NotificationReceiver : BroadcastReceiver() {
action = ACTION_DISMISS_NOTIFICATION
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -402,7 +422,12 @@ class NotificationReceiver : BroadcastReceiver() {
putExtra(EXTRA_FILE_LOCATION, path)
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -419,7 +444,12 @@ class NotificationReceiver : BroadcastReceiver() {
putExtra(EXTRA_FILE_LOCATION, path)
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -431,7 +461,12 @@ class NotificationReceiver : BroadcastReceiver() {
*/
internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter: Chapter): PendingIntent {
val newIntent = ReaderActivity.newIntent(context, manga.id, chapter.id)
return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getActivity(
context,
manga.id.hashCode(),
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -447,7 +482,12 @@ class NotificationReceiver : BroadcastReceiver() {
.putExtra(Constants.MANGA_EXTRA, manga.id)
.putExtra("notificationId", manga.id.hashCode())
.putExtra("groupId", groupId)
return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getActivity(
context,
manga.id.hashCode(),
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -469,7 +509,12 @@ class NotificationReceiver : BroadcastReceiver() {
putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode())
putExtra(EXTRA_GROUP_ID, groupId)
}
return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
manga.id.hashCode(),
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -491,7 +536,12 @@ class NotificationReceiver : BroadcastReceiver() {
putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode())
putExtra(EXTRA_GROUP_ID, groupId)
}
return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
manga.id.hashCode(),
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -504,7 +554,12 @@ class NotificationReceiver : BroadcastReceiver() {
val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CANCEL_LIBRARY_UPDATE
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -513,12 +568,21 @@ class NotificationReceiver : BroadcastReceiver() {
* @param context context of application
* @return [PendingIntent]
*/
internal fun downloadAppUpdatePendingBroadcast(context: Context, url: String, title: String? = null): PendingIntent {
internal fun downloadAppUpdatePendingBroadcast(
context: Context,
url: String,
title: String? = null,
): PendingIntent {
return Intent(context, NotificationReceiver::class.java).run {
action = ACTION_START_APP_UPDATE
putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL, url)
title?.let { putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_TITLE, it) }
PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
PendingIntent.getBroadcast(
context,
0,
this,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
}
@ -529,7 +593,12 @@ class NotificationReceiver : BroadcastReceiver() {
val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -543,7 +612,12 @@ class NotificationReceiver : BroadcastReceiver() {
action = Constants.SHORTCUT_EXTENSIONS
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -560,7 +634,12 @@ class NotificationReceiver : BroadcastReceiver() {
putExtra(EXTRA_URI, uri)
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
/**
@ -591,7 +670,12 @@ class NotificationReceiver : BroadcastReceiver() {
action = ACTION_CANCEL_RESTORE
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
}
}

View File

@ -35,7 +35,8 @@ class TrackerManager {
val kavita = Kavita(KAVITA)
val suwayomi = Suwayomi(9L)
val trackers = listOf(mdList, myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi)
val trackers =
listOf(mdList, myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi)
fun loggedInTrackers() = trackers.filter { it.isLoggedIn }

View File

@ -48,11 +48,15 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
when (it.code) {
200 -> return it.parseAs<AuthenticationDto>().token
401 -> {
logcat(LogPriority.WARN) { "Unauthorized / api key not valid: Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" }
logcat(LogPriority.WARN) {
"Unauthorized / API key not valid: API URL: $apiUrl, empty API key: ${apiKey.isEmpty()}"
}
throw IOException("Unauthorized / api key not valid")
}
500 -> {
logcat(LogPriority.WARN) { "Error fetching JWT token. Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" }
logcat(
LogPriority.WARN,
) { "Error fetching JWT token. API URL: $apiUrl, empty API key: ${apiKey.isEmpty()}" }
throw IOException("Error fetching JWT token")
}
else -> {}
@ -62,12 +66,12 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
// Not sure which one to catch
} catch (e: SocketTimeoutException) {
logcat(LogPriority.WARN) {
"Could not fetch JWT token. Probably due to connectivity issue or the url '$apiUrl' is not available, skipping"
"Could not fetch JWT token. Probably due to connectivity issue or URL '$apiUrl' not available, skipping"
}
return null
} catch (e: Exception) {
logcat(LogPriority.ERROR) {
"Unhandled exception fetching JWT token for url: '$apiUrl'"
"Unhandled exception fetching JWT token for URL: '$apiUrl'"
}
throw IOException(e)
}
@ -129,7 +133,10 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
}
}
} catch (e: Exception) {
logcat(LogPriority.WARN, e) { "Exception getting latest chapter read. Could not get itemRequest: $requestUrl" }
logcat(
LogPriority.WARN,
e,
) { "Exception getting latest chapter read. Could not get itemRequest: $requestUrl" }
throw e
}
return 0F
@ -164,8 +171,14 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
}
suspend fun updateProgress(track: Track): Track {
val requestUrl = "${getApiFromUrl(track.tracking_url)}/Tachiyomi/mark-chapter-until-as-read?seriesId=${getIdFromUrl(track.tracking_url)}&chapterNumber=${track.last_chapter_read}"
authClient.newCall(POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())))
val requestUrl = "${getApiFromUrl(
track.tracking_url,
)}/Tachiyomi/mark-chapter-until-as-read?seriesId=${getIdFromUrl(
track.tracking_url,
)}&chapterNumber=${track.last_chapter_read}"
authClient.newCall(
POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())),
)
.awaitSuccess()
return getTrackSearch(track.tracking_url)
}

View File

@ -101,7 +101,10 @@ class MyAnimeListApi(
return withIOContext {
val url = "$baseApiUrl/manga".toUri().buildUpon()
.appendPath(id.toString())
.appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date")
.appendQueryParameter(
"fields",
"id,title,synopsis,num_chapters,main_picture,status,media_type,start_date",
)
.build()
with(json) {
authClient.newCall(GET(url.toString()))

View File

@ -91,7 +91,9 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
null
}
override fun isTrackFrom(track: DomainTrack, manga: DomainManga, source: Source?): Boolean = source?.let { accept(it) } == true
override fun isTrackFrom(track: DomainTrack, manga: DomainManga, source: Source?): Boolean = source?.let {
accept(it)
} == true
override fun migrateTrack(track: DomainTrack, manga: DomainManga, newSource: Source): DomainTrack? =
if (accept(newSource)) {

View File

@ -38,7 +38,9 @@ class AppUpdateChecker {
when (result) {
is GetApplicationRelease.Result.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release)
is GetApplicationRelease.Result.ThirdPartyInstallation -> AppUpdateNotifier(context).promptFdroidUpdate()
is GetApplicationRelease.Result.ThirdPartyInstallation -> AppUpdateNotifier(
context,
).promptFdroidUpdate()
else -> {}
}

View File

@ -42,7 +42,12 @@ internal class AppUpdateNotifier(private val context: Context) {
val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
PendingIntent.getActivity(context, release.hashCode(), this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
PendingIntent.getActivity(
context,
release.hashCode(),
this,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
with(notificationBuilder) {
@ -143,7 +148,12 @@ internal class AppUpdateNotifier(private val context: Context) {
setContentTitle(context.getString(R.string.update_check_notification_update_available))
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
setSmallIcon(R.drawable.ic_tachi)
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds"))
setContentIntent(
NotificationHandler.openUrl(
context,
"https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds",
),
)
}
notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT)
}

View File

@ -101,7 +101,12 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic
}
init {
ContextCompat.registerReceiver(service, packageActionReceiver, IntentFilter(INSTALL_ACTION), ContextCompat.RECEIVER_EXPORTED)
ContextCompat.registerReceiver(
service,
packageActionReceiver,
IntentFilter(INSTALL_ACTION),
ContextCompat.RECEIVER_EXPORTED,
)
}
}

View File

@ -108,7 +108,9 @@ internal class ExtensionInstallReceiver(private val listener: Listener) :
logcat(LogPriority.WARN) { "Package name not found" }
return LoadResult.Error
}
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) { ExtensionLoader.loadExtensionFromPkgName(context, pkgName) }.await()
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {
ExtensionLoader.loadExtensionFromPkgName(context, pkgName)
}.await()
}
/**

View File

@ -59,7 +59,9 @@ class AndroidSourceManager(
private val stubSourcesMap = ConcurrentHashMap<Long, StubSource>()
override val catalogueSources: Flow<List<CatalogueSource>> = sourcesMapFlow.map { it.values.filterIsInstance<CatalogueSource>() }
override val catalogueSources: Flow<List<CatalogueSource>> = sourcesMapFlow.map {
it.values.filterIsInstance<CatalogueSource>()
}
// SY -->
private val preferences: UnsortedPreferences by injectLazy()
@ -118,7 +120,9 @@ class AndroidSourceManager(
private fun Source.toInternalSource(): Source? {
// EXH -->
val sourceQName = this::class.qualifiedName
val factories = DELEGATED_SOURCES.entries.filter { it.value.factory }.map { it.value.originalSourceQualifiedClassName }
val factories = DELEGATED_SOURCES.entries
.filter { it.value.factory }
.map { it.value.originalSourceQualifiedClassName }
val delegate = if (sourceQName != null) {
val matched = factories.find { sourceQName.startsWith(it) }
if (matched != null) {
@ -149,7 +153,12 @@ class AndroidSourceManager(
}
return if (id in BlacklistedSources.BLACKLISTED_EXT_SOURCES) {
xLogD("Removing blacklisted source: (id: %s, name: %s, lang: %s)!", id, name, (this as? CatalogueSource)?.lang)
xLogD(
"Removing blacklisted source: (id: %s, name: %s, lang: %s)!",
id,
name,
(this as? CatalogueSource)?.lang,
)
null
} else {
newSource
@ -177,15 +186,21 @@ class AndroidSourceManager(
}
// SY -->
override fun getVisibleOnlineSources() = sourcesMapFlow.value.values.filterIsInstance<HttpSource>().filter {
override fun getVisibleOnlineSources() = sourcesMapFlow.value.values
.filterIsInstance<HttpSource>()
.filter {
it.id !in BlacklistedSources.HIDDEN_SOURCES
}
override fun getVisibleCatalogueSources() = sourcesMapFlow.value.values.filterIsInstance<CatalogueSource>().filter {
override fun getVisibleCatalogueSources() = sourcesMapFlow.value.values
.filterIsInstance<CatalogueSource>()
.filter {
it.id !in BlacklistedSources.HIDDEN_SOURCES
}
fun getDelegatedCatalogueSources() = sourcesMapFlow.value.values.filterIsInstance<EnhancedHttpSource>().mapNotNull { enhancedHttpSource ->
fun getDelegatedCatalogueSources() = sourcesMapFlow.value.values
.filterIsInstance<EnhancedHttpSource>()
.mapNotNull { enhancedHttpSource ->
enhancedHttpSource.enhancedSource as? DelegatedHttpSource
}
// SY <--
@ -256,7 +271,8 @@ class AndroidSourceManager(
),
).associateBy { it.originalSourceQualifiedClassName }
val currentDelegatedSources: MutableMap<Long, DelegatedSource> = ListenMutableMap(mutableMapOf(), ::handleSourceLibrary)
val currentDelegatedSources: MutableMap<Long, DelegatedSource> =
ListenMutableMap(mutableMapOf(), ::handleSourceLibrary)
data class DelegatedSource(
val sourceName: String,

View File

@ -281,7 +281,9 @@ class EHentai(
private fun getRating(element: Element?): Double? {
val ratingStyle = element?.attr("style")?.nullIfBlank()
return if (ratingStyle != null) {
val matches = RATING_REGEX.findAll(ratingStyle).mapNotNull { it.groupValues.getOrNull(1)?.toIntOrNull() }.toList()
val matches = RATING_REGEX.findAll(ratingStyle)
.mapNotNull { it.groupValues.getOrNull(1)?.toIntOrNull() }
.toList()
if (matches.size == 2) {
var rate = 5 - matches[0] / 16
if (matches[1] == 21) {
@ -314,7 +316,9 @@ class EHentai(
/**
* Parse a list of galleries
*/
private fun genericMangaParse(response: Response) = extendedGenericMangaParse(response.asJsoup()).let { (parsedManga, nextPage) ->
private fun genericMangaParse(
response: Response,
) = extendedGenericMangaParse(response.asJsoup()).let { (parsedManga, nextPage) ->
MetadataMangasPage(
parsedManga.map { it.manga },
nextPage != null,
@ -409,7 +413,9 @@ class EHentai(
}
@Deprecated("Use the 1.x API instead", replaceWith = ReplaceWith("getPageList"))
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> = fetchChapterPage(chapter, baseUrl + chapter.url)
override fun fetchPageList(
chapter: SChapter,
): Observable<List<Page>> = fetchChapterPage(chapter, baseUrl + chapter.url)
.map {
it.mapIndexed { i, s ->
Page(i, s)
@ -461,7 +467,9 @@ class EHentai(
private fun <T : MangasPage> T.checkValid(): MangasPage =
if (exh && mangas.isEmpty() && preferences.igneousVal().get().equals("mystery", true)) {
throw Exception("Invalid igneous cookie, try re-logging or finding a correct one to input in the login menu")
throw Exception(
"Invalid igneous cookie, try re-logging or finding a correct one to input in the login menu",
)
} else {
this
}
@ -521,7 +529,11 @@ class EHentai(
if (jumpSeekValue != null && page == 1) {
if (
MATCH_SEEK_REGEX.matches(jumpSeekValue) ||
(MATCH_YEAR_REGEX.matches(jumpSeekValue) && jumpSeekValue.toIntOrNull()?.let { it in 2007..2099 } == true)
(
MATCH_YEAR_REGEX.matches(jumpSeekValue) && jumpSeekValue.toIntOrNull()?.let {
it in 2007..2099
} == true
)
) {
uri.appendQueryParameter("seek", jumpSeekValue)
} else if (MATCH_JUMP_REGEX.matches(jumpSeekValue)) {
@ -590,7 +602,9 @@ class EHentai(
// Pull to most recent
val doc = response.asJsoup()
val newerGallery = doc.select("#gnd a").lastOrNull()
val pre = if (newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled) {
val pre = if (
newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled
) {
manga.url = EHentaiSearchMetadata.normalizeUrl(newerGallery.attr("href"))
client.newCall(mangaDetailsRequest(manga))
.asObservableSuccess().map { it.asJsoup() }
@ -627,7 +641,9 @@ class EHentai(
// Pull to most recent
val doc = response.asJsoup()
val newerGallery = doc.select("#gnd a").lastOrNull()
val pre = if (newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled) {
val pre = if (
newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled
) {
val sManga = manga.copy(
url = EHentaiSearchMetadata.normalizeUrl(newerGallery.attr("href")),
)
@ -756,16 +772,24 @@ class EHentai(
tags += RaisedTag(EH_UPLOADER_NAMESPACE, it, TAG_TYPE_VIRTUAL)
}
visible?.let {
tags += RaisedTag(EH_VISIBILITY_NAMESPACE, it.substringAfter('(').substringBeforeLast(')'), TAG_TYPE_VIRTUAL)
tags += RaisedTag(
EH_VISIBILITY_NAMESPACE,
it.substringAfter('(').substringBeforeLast(')'),
TAG_TYPE_VIRTUAL,
)
}
}
}
}
override fun chapterListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
override fun chapterPageParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
override fun chapterListParse(response: Response) =
throw UnsupportedOperationException("Unused method was called somehow!")
override fun chapterPageParse(
response: Response,
) = throw UnsupportedOperationException("Unused method was called somehow!")
override fun pageListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
override fun pageListParse(response: Response) =
throw UnsupportedOperationException("Unused method was called somehow!")
override fun fetchImageUrl(page: Page): Observable<String> {
return client.newCall(imageUrlRequest(page))
@ -959,7 +983,11 @@ class EHentai(
}
}
class AdvancedOption(name: String, val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter {
class AdvancedOption(
name: String,
val param: String,
defValue: Boolean = false,
) : Filter.CheckBox(name, defValue), UriFilter {
override fun addToUri(builder: Uri.Builder) {
if (state) {
builder.appendQueryParameter(param, "on")
@ -1140,7 +1168,9 @@ class EHentai(
)
val obj = outJson["tokenlist"]!!.jsonArray.first().jsonObject
return "${uri.scheme}://${uri.host}/g/${obj["gid"]!!.jsonPrimitive.int}/${obj["token"]!!.jsonPrimitive.content}/"
return "${uri.scheme}://${uri.host}/g/${obj["gid"]!!.jsonPrimitive.int}/${
obj["token"]!!.jsonPrimitive.content
}/"
}
override suspend fun getPagePreviewList(
@ -1190,7 +1220,8 @@ class EHentai(
}
override suspend fun fetchPreviewImage(page: PagePreviewInfo, cacheControl: CacheControl?): Response {
return client.newCachelessCallWithProgress(exGet(page.imageUrl, cacheControl = cacheControl), page).awaitSuccess()
return client.newCachelessCallWithProgress(exGet(page.imageUrl, cacheControl = cacheControl), page)
.awaitSuccess()
}
/**

View File

@ -49,7 +49,11 @@ class MergedSource : HttpSource() {
override fun popularMangaRequest(page: Int) = throw UnsupportedOperationException()
override fun popularMangaParse(response: Response) = throw UnsupportedOperationException()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException()
override fun searchMangaRequest(
page: Int,
query: String,
filters: FilterList,
) = throw UnsupportedOperationException()
override fun searchMangaParse(response: Response) = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException()
@ -63,6 +67,7 @@ class MergedSource : HttpSource() {
override fun fetchChapterList(manga: SManga) = throw UnsupportedOperationException()
override suspend fun getChapterList(manga: SManga) = throw UnsupportedOperationException()
override suspend fun getImage(page: Page): Response = throw UnsupportedOperationException()
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getImageUrl"))
override fun fetchImageUrl(page: Page) = throw UnsupportedOperationException()
override suspend fun getImageUrl(page: Page) = throw UnsupportedOperationException()
@ -70,9 +75,11 @@ class MergedSource : HttpSource() {
@Deprecated("Use the 1.x API instead", replaceWith = ReplaceWith("getPageList"))
override fun fetchPageList(chapter: SChapter) = throw UnsupportedOperationException()
override suspend fun getPageList(chapter: SChapter) = throw UnsupportedOperationException()
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getLatestUpdates"))
override fun fetchLatestUpdates(page: Int) = throw UnsupportedOperationException()
override suspend fun getLatestUpdates(page: Int) = throw UnsupportedOperationException()
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPopularManga"))
override fun fetchPopularManga(page: Int) = throw UnsupportedOperationException()
override suspend fun getPopularManga(page: Int) = throw UnsupportedOperationException()
@ -99,7 +106,12 @@ class MergedSource : HttpSource() {
}
}
suspend fun fetchChaptersForMergedManga(manga: Manga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true) {
suspend fun fetchChaptersForMergedManga(
manga: Manga,
downloadChapters: Boolean = true,
editScanlators: Boolean = false,
dedupe: Boolean = true,
) {
fetchChaptersAndSync(manga, downloadChapters)
}
@ -109,7 +121,12 @@ class MergedSource : HttpSource() {
"Manga references are empty, chapters unavailable, merge is likely corrupted"
}
val ifDownloadNewChapters = downloadChapters && manga.shouldDownloadNewChapters(getCategories.await(manga.id).map { it.id }, downloadPreferences)
val ifDownloadNewChapters = downloadChapters && manga.shouldDownloadNewChapters(
getCategories.await(manga.id).map {
it.id
},
downloadPreferences,
)
val semaphore = Semaphore(5)
var exception: Exception? = null
return supervisorScope {

View File

@ -58,7 +58,7 @@ class NHentai(delegate: HttpSource, val context: Context) :
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
return urlImportFetchSearchMangaSuspend(context, query) {
super<DelegatedHttpSource>.getSearchManga(page, query, filters,)
super<DelegatedHttpSource>.getSearchManga(page, query, filters)
}
}
@ -195,7 +195,8 @@ class NHentai(delegate: HttpSource, val context: Context) :
)
}
private fun thumbnailUrlFromType(mediaId: String, page: Int, t: String) = NHentaiSearchMetadata.typeToExtension(t)?.let {
private fun thumbnailUrlFromType(mediaId: String, page: Int, t: String) =
NHentaiSearchMetadata.typeToExtension(t)?.let {
"https://t3.nhentai.net/galleries/$mediaId/${page}t.$it"
}

View File

@ -38,7 +38,7 @@ class EightMuses(delegate: HttpSource, val context: Context) :
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
return urlImportFetchSearchMangaSuspend(context, query) {
super<DelegatedHttpSource>.getSearchManga(page, query, filters,)
super<DelegatedHttpSource>.getSearchManga(page, query, filters)
}
}

View File

@ -37,7 +37,7 @@ class HBrowse(delegate: HttpSource, val context: Context) :
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
return urlImportFetchSearchMangaSuspend(context, query) {
super<DelegatedHttpSource>.getSearchManga(page, query, filters,)
super<DelegatedHttpSource>.getSearchManga(page, query, filters)
}
}

View File

@ -62,7 +62,7 @@ class Pururin(delegate: HttpSource, val context: Context) :
query
}
return urlImportFetchSearchMangaSuspend(context, newQuery) {
super<DelegatedHttpSource>.getSearchManga(page, query, filters,)
super<DelegatedHttpSource>.getSearchManga(page, query, filters)
}
}
@ -111,7 +111,11 @@ class Pururin(delegate: HttpSource, val context: Context) :
tags += RaisedTag(
namespace,
searchUrl.lastPathSegment!!.substringBefore("."),
if (namespace != PururinSearchMetadata.TAG_NAMESPACE_CATEGORY) PururinSearchMetadata.TAG_TYPE_DEFAULT else RaisedSearchMetadata.TAG_TYPE_VIRTUAL,
if (namespace != PururinSearchMetadata.TAG_NAMESPACE_CATEGORY) {
PururinSearchMetadata.TAG_TYPE_DEFAULT
} else {
RaisedSearchMetadata.TAG_TYPE_VIRTUAL
},
)
}
}

View File

@ -43,7 +43,7 @@ class Tsumino(delegate: HttpSource, val context: Context) :
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
return urlImportFetchSearchMangaSuspend(context, query) {
super<DelegatedHttpSource>.getSearchManga(page, query, filters,)
super<DelegatedHttpSource>.getSearchManga(page, query, filters)
}
}

View File

@ -16,7 +16,8 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel { MigrateSearchScreenModel(mangaId = mangaId, validSources = validSources) }
val screenModel =
rememberScreenModel { MigrateSearchScreenModel(mangaId = mangaId, validSources = validSources) }
val state by screenModel.state.collectAsState()
val dialogScreenModel = rememberScreenModel { MigrateSearchScreenDialogScreenModel(mangaId = mangaId) }

View File

@ -19,7 +19,6 @@ import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.domain.source.interactor.GetExhSavedSearch
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.model.toDomainTrack
import eu.kanade.domain.track.interactor.AddTracks
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.util.ioCoroutineScope
@ -52,13 +51,11 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import logcat.LogPriority
import tachiyomi.core.preference.CheckboxState
import tachiyomi.core.preference.mapAsCheckboxState
import tachiyomi.core.util.lang.launchIO
import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.interactor.SetMangaCategories
@ -370,7 +367,9 @@ open class BrowseSourceScreenModel(
// Choose a category
else -> {
val preselectedIds = getCategories.await(manga.id).map { it.id }
setDialog(Dialog.ChangeMangaCategory(manga, categories.mapAsCheckboxState { it.id in preselectedIds }))
setDialog(
Dialog.ChangeMangaCategory(manga, categories.mapAsCheckboxState { it.id in preselectedIds }),
)
}
}
}
@ -426,7 +425,10 @@ open class BrowseSourceScreenModel(
sealed class Listing(open val query: String?, open val filters: FilterList) {
data object Popular : Listing(query = GetRemoteManga.QUERY_POPULAR, filters = FilterList())
data object Latest : Listing(query = GetRemoteManga.QUERY_LATEST, filters = FilterList())
data class Search(override val query: String?, override val filters: FilterList) : Listing(query = query, filters = filters)
data class Search(
override val query: String?,
override val filters: FilterList,
) : Listing(query = query, filters = filters)
companion object {
fun valueOf(query: String?): Listing {
@ -530,7 +532,9 @@ open class BrowseSourceScreenModel(
source = source.id,
name = name.trim(),
query = query,
filtersJson = runCatching { filterSerializer.serialize(filterList).ifEmpty { null }?.let { Json.encodeToString(it) } }.getOrNull(),
filtersJson = runCatching {
filterSerializer.serialize(filterList).ifEmpty { null }?.let { Json.encodeToString(it) }
}.getOrNull(),
),
)
}

View File

@ -29,10 +29,8 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import tachiyomi.core.util.lang.awaitSingle
import tachiyomi.core.util.lang.launchIO
import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withIOContext
@ -175,7 +173,9 @@ open class SourceFeedScreenModel(
mutableState.update { state ->
state.copy(
items = state.items.map { item -> if (item.id == sourceFeed.id) sourceFeed.withResults(titles) else item },
items = state.items.map { item ->
if (item.id == sourceFeed.id) sourceFeed.withResults(titles) else item
},
)
}
}

View File

@ -188,7 +188,10 @@ object HomeScreen : Screen() {
}
@Composable
private fun RowScope.NavigationBarItem(tab: eu.kanade.presentation.util.Tab/* SY --> */, alwaysShowLabel: Boolean/* SY <-- */) {
private fun RowScope.NavigationBarItem(
tab: eu.kanade.presentation.util.Tab/* SY --> */,
alwaysShowLabel: Boolean, /* SY <-- */
) {
val tabNavigator = LocalTabNavigator.current
val navigator = LocalNavigator.currentOrThrow
val scope = rememberCoroutineScope()

View File

@ -352,7 +352,8 @@ class LibraryScreenModel(
private fun LibraryMap.applySort(
// Map<MangaId, List<Track>>
trackMap: Map<Long, List<Track>>,
/* SY --> */ groupSort: LibrarySort? = null, /* SY <-- */
/* SY --> */
groupSort: LibrarySort? = null, /* SY <-- */
): LibraryMap {
// SY -->
val listOfTags by lazy {
@ -813,7 +814,8 @@ class LibraryScreenModel(
}
fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState<Int> {
return (if (isLandscape) libraryPreferences.landscapeColumns() else libraryPreferences.portraitColumns()).asState(screenModelScope)
return (if (isLandscape) libraryPreferences.landscapeColumns() else libraryPreferences.portraitColumns())
.asState(screenModelScope)
}
suspend fun getRandomLibraryItemForCurrentCategory(): LibraryItem? {
@ -1163,7 +1165,9 @@ class LibraryScreenModel(
.find { it.int == id }
.let { it ?: TrackStatus.OTHER }
.let { context.getString(it.res) },
order = TrackStatus.values().indexOfFirst { it.int == id }.takeUnless { it == -1 }?.toLong() ?: TrackStatus.OTHER.ordinal.toLong(),
order = TrackStatus.values().indexOfFirst {
it.int == id
}.takeUnless { it == -1 }?.toLong() ?: TrackStatus.OTHER.ordinal.toLong(),
flags = 0,
)
}

View File

@ -141,7 +141,9 @@ object LibraryTab : Tab {
onClickSelectAll = { screenModel.selectAll(screenModel.activeCategoryIndex) },
onClickInvertSelection = { screenModel.invertSelection(screenModel.activeCategoryIndex) },
onClickFilter = screenModel::showSettingsDialog,
onClickRefresh = { onClickRefresh(state.categories[screenModel.activeCategoryIndex.coerceAtMost(state.categories.lastIndex)]) },
onClickRefresh = {
onClickRefresh(state.categories[screenModel.activeCategoryIndex.coerceAtMost(state.categories.lastIndex)])
},
onClickGlobalUpdate = { onClickRefresh(null) },
onClickOpenRandomManga = {
scope.launch {
@ -224,7 +226,9 @@ object LibraryTab : Tab {
scope.launchIO {
val chapter = screenModel.getNextUnreadChapter(it.manga)
if (chapter != null) {
context.startActivity(ReaderActivity.newIntent(context, chapter.mangaId, chapter.id))
context.startActivity(
ReaderActivity.newIntent(context, chapter.mangaId, chapter.id),
)
} else {
snackbarHostState.showSnackbar(context.getString(R.string.no_next_chapter))
}

View File

@ -453,7 +453,11 @@ class MainActivity : BaseActivity() {
private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean {
val notificationId = intent.getIntExtra("notificationId", -1)
if (notificationId > -1) {
NotificationReceiver.dismissNotification(applicationContext, notificationId, intent.getIntExtra("groupId", 0))
NotificationReceiver.dismissNotification(
applicationContext,
notificationId,
intent.getIntExtra("groupId", 0),
)
}
val tabToOpen = when (intent.action) {

View File

@ -99,7 +99,8 @@ class MangaScreen(
val context = LocalContext.current
val haptic = LocalHapticFeedback.current
val scope = rememberCoroutineScope()
val screenModel = rememberScreenModel { MangaScreenModel(context, mangaId, fromSource, smartSearchConfig != null) }
val screenModel =
rememberScreenModel { MangaScreenModel(context, mangaId, fromSource, smartSearchConfig != null) }
val state by screenModel.state.collectAsState()
@ -172,7 +173,9 @@ class MangaScreen(
onShareClicked = { shareManga(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource },
onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() },
onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.manga.favorite },
onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf { screenModel.isUpdateIntervalEnabled && successState.manga.favorite },
onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf {
screenModel.isUpdateIntervalEnabled && successState.manga.favorite
},
// SY -->
onMigrateClicked = { migrateManga(navigator, screenModel.manga!!) }.takeIf { successState.manga.favorite },
onMetadataViewerClicked = { openMetadataViewer(navigator, successState.manga) },
@ -181,7 +184,9 @@ class MangaScreen(
onMergedSettingsClicked = screenModel::showEditMergedSettingsDialog,
onMergeClicked = { openSmartSearch(navigator, successState.manga) },
onMergeWithAnotherClicked = { mergeWithAnother(navigator, context, successState.manga, screenModel::smartSearchMerge) },
onOpenPagePreview = { openPagePreview(context, successState.chapters.minByOrNull { it.chapter.sourceOrder }?.chapter, it) },
onOpenPagePreview = {
openPagePreview(context, successState.chapters.minByOrNull { it.chapter.sourceOrder }?.chapter, it)
},
onMorePreviewsClicked = { openMorePagePreviews(navigator, successState.manga) },
// SY <--
onMultiBookmarkClicked = screenModel::bookmarkChapters,

View File

@ -869,7 +869,9 @@ class MangaScreenModel(
// SY <--
screenModelScope.launchIO {
downloadManager.statusFlow()
.filter { /* SY --> */ if (isMergedSource) it.manga.id in mergedIds else /* SY <-- */ it.manga.id == successState?.manga?.id }
.filter {
/* SY --> */ if (isMergedSource) it.manga.id in mergedIds else /* SY <-- */ it.manga.id == successState?.manga?.id
}
.catch { error -> logcat(LogPriority.ERROR, error) }
.collect {
withUIContext {
@ -880,7 +882,9 @@ class MangaScreenModel(
screenModelScope.launchIO {
downloadManager.progressFlow()
.filter { /* SY --> */ if (isMergedSource) it.manga.id in mergedIds else /* SY <-- */ it.manga.id == successState?.manga?.id }
.filter {
/* SY --> */ if (isMergedSource) it.manga.id in mergedIds else /* SY <-- */ it.manga.id == successState?.manga?.id
}
.catch { error -> logcat(LogPriority.ERROR, error) }
.collect {
withUIContext {
@ -1454,7 +1458,10 @@ class MangaScreenModel(
}
// SY -->
.map { trackItems ->
if (manga.source in mangaDexSourceIds || state.mergedData?.manga?.values.orEmpty().any { it.source in mangaDexSourceIds }) {
if (manga.source in mangaDexSourceIds || state.mergedData?.manga?.values.orEmpty().any {
it.source in mangaDexSourceIds
}
) {
val mdTrack = trackItems.firstOrNull { it.tracker is MdList }
when {
mdTrack == null -> {
@ -1614,7 +1621,9 @@ class MangaScreenModel(
get() = trackItems.isNotEmpty()
val trackingCount: Int
get() = trackItems.count { it.track != null && ((it.tracker is MdList && it.track.status != FollowStatus.UNFOLLOWED.int.toLong()) || it.tracker !is MdList ) }
get() = trackItems.count {
it.track != null && ((it.tracker is MdList && it.track.status != FollowStatus.UNFOLLOWED.int.toLong()) || it.tracker !is MdList)
}
/**
* Applies the view filters to the list of chapters obtained from the database.

View File

@ -53,7 +53,9 @@ class EditMergedSettingsState(
context.toast(R.string.merged_references_invalid)
onDismissRequest()
}
mergedMangas += mergedReferences.filter { it.mangaSourceId != MERGED_SOURCE_ID }.map { reference -> mergedManga.firstOrNull { it.id == reference.mangaId } to reference }
mergedMangas += mergedReferences.filter {
it.mangaSourceId != MERGED_SOURCE_ID
}.map { reference -> mergedManga.firstOrNull { it.id == reference.mangaId } to reference }
mergeReference = mergedReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }
val isPriorityOrder = mergeReference?.let { it.chapterSortMode == MergedMangaReference.CHAPTER_SORT_PRIORITY } ?: false
@ -66,7 +68,11 @@ class EditMergedSettingsState(
mergedMangaAdapter?.isHandleDragEnabled = isPriorityOrder
mergedMangaAdapter?.updateDataSet(mergedMangas.map { it.toModel() }.sortedBy { it.mergedMangaReference.chapterPriority })
mergedMangaAdapter?.updateDataSet(
mergedMangas.map {
it.toModel()
}.sortedBy { it.mergedMangaReference.chapterPriority },
)
}
override fun onItemReleased(position: Int) {
@ -113,7 +119,9 @@ class EditMergedSettingsState(
val (manga, reference) = pair
if (reference.id != adapterReference.id) return@map pair
mergedMangaAdapter?.allBoundViewHolders?.firstOrNull { it is EditMergedMangaHolder && it.reference.id == reference.id }?.let {
mergedMangaAdapter?.allBoundViewHolders?.firstOrNull {
it is EditMergedMangaHolder && it.reference.id == reference.id
}?.let {
if (it is EditMergedMangaHolder) {
it.updateChapterUpdatesIcon(!reference.getChapterUpdates)
}
@ -141,7 +149,9 @@ class EditMergedSettingsState(
val (manga, reference) = pair
if (reference.id != adapterReference.id) return@map pair
mergedMangaAdapter?.allBoundViewHolders?.firstOrNull { it is EditMergedMangaHolder && it.reference.id == reference.id }?.let {
mergedMangaAdapter?.allBoundViewHolders?.firstOrNull {
it is EditMergedMangaHolder && it.reference.id == reference.id
}?.let {
if (it is EditMergedMangaHolder) {
it.updateDownloadChaptersIcon(!reference.downloadChapters)
}

View File

@ -133,7 +133,9 @@ class EditMergedSettingsHeaderAdapter(private val state: EditMergedSettingsState
}
}
binding.dedupeSwitch.isChecked = state.mergeReference?.let { it.chapterSortMode != MergedMangaReference.CHAPTER_SORT_NONE } ?: false
binding.dedupeSwitch.isChecked = state.mergeReference?.let {
it.chapterSortMode != MergedMangaReference.CHAPTER_SORT_NONE
} ?: false
binding.dedupeSwitch.setOnCheckedChangeListener { _, isChecked ->
binding.dedupeModeSpinner.isEnabled = isChecked
binding.dedupeModeSpinner.alpha = when (isChecked) {

View File

@ -117,7 +117,6 @@ import tachiyomi.domain.source.service.SourceManager
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.math.abs
import kotlin.time.Duration.Companion.seconds
class ReaderActivity : BaseActivity() {
@ -402,7 +401,6 @@ class ReaderActivity : BaseActivity() {
!showVerticalSeekbar -> NavBarType.Bottom
leftHandedVerticalSeekbar -> NavBarType.VerticalLeft
else -> NavBarType.VerticalRight
}
// SY <--
@ -569,7 +567,7 @@ class ReaderActivity : BaseActivity() {
}
}
},
state.dateRelativeTime
state.dateRelativeTime,
)
}
// SY -->
@ -605,7 +603,6 @@ class ReaderActivity : BaseActivity() {
)
// SY <--
null -> {}
}
}
@ -883,7 +880,9 @@ class ReaderActivity : BaseActivity() {
// SY -->
val state = viewModel.state.value
if (state.indexChapterToShift != null && state.indexPageToShift != null) {
viewerChapters.currChapter.pages?.find { it.index == state.indexPageToShift && it.chapter.chapter.id == state.indexChapterToShift }?.let {
viewerChapters.currChapter.pages?.find {
it.index == state.indexPageToShift && it.chapter.chapter.id == state.indexChapterToShift
}?.let {
(viewModel.state.value.viewer as? PagerViewer)?.updateShifting(it)
}
viewModel.setIndexChapterToShift(null)

View File

@ -210,13 +210,22 @@ class ReaderViewModel @JvmOverloads constructor(
(manga.unreadFilterRaw == Manga.CHAPTER_SHOW_READ && !it.read) ||
(manga.unreadFilterRaw == Manga.CHAPTER_SHOW_UNREAD && it.read) ||
// SY -->
(manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED && !isChapterDownloaded(it)) ||
(manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED && isChapterDownloaded(it)) ||
(
manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED &&
!isChapterDownloaded(it)
) ||
(
manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED &&
isChapterDownloaded(it)
) ||
// SY <--
(manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark) ||
(manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_NOT_BOOKMARKED && it.bookmark) ||
// SY -->
(manga.filteredScanlators != null && MdUtil.getScanlators(it.scanlator).none { group -> manga.filteredScanlators!!.contains(group) })
(
manga.filteredScanlators != null && MdUtil.getScanlators(it.scanlator)
.none { group -> manga.filteredScanlators!!.contains(group) }
)
// SY <--
}
else -> false
@ -336,8 +345,20 @@ class ReaderViewModel @JvmOverloads constructor(
} else {
null
}
val mergedReferences = if (source is MergedSource) runBlocking { getMergedReferencesById.await(manga.id) } else emptyList()
val mergedManga = if (source is MergedSource) runBlocking { getMergedMangaById.await(manga.id) }.associateBy { it.id } else emptyMap()
val mergedReferences = if (source is MergedSource) {
runBlocking {
getMergedReferencesById.await(manga.id)
}
} else {
emptyList()
}
val mergedManga = if (source is MergedSource) {
runBlocking {
getMergedMangaById.await(manga.id)
}.associateBy { it.id }
} else {
emptyMap()
}
val relativeTime = uiPreferences.relativeTime().get()
val autoScrollFreq = readerPreferences.autoscrollInterval().get()
// SY <--
@ -353,7 +374,7 @@ class ReaderViewModel @JvmOverloads constructor(
} else {
autoScrollFreq.toString()
},
isAutoScrollEnabled = autoScrollFreq != -1f
isAutoScrollEnabled = autoScrollFreq != -1f,
/* SY <-- */
)
}
@ -361,9 +382,23 @@ class ReaderViewModel @JvmOverloads constructor(
val context = Injekt.get<Application>()
// val source = sourceManager.getOrStub(manga.source)
loader = ChapterLoader(context, downloadManager, downloadProvider, manga, source, /* SY --> */sourceManager, readerPreferences, mergedReferences, mergedManga/* SY <-- */)
loader = ChapterLoader(
context = context,
downloadManager = downloadManager,
downloadProvider = downloadProvider,
manga = manga,
source = source, /* SY --> */
sourceManager = sourceManager,
readerPrefs = readerPreferences,
mergedReferences = mergedReferences,
mergedManga = mergedManga, /* SY <-- */
)
loadChapter(loader!!, chapterList.first { chapterId == it.chapter.id } /* SY --> */, page/* SY <-- */)
loadChapter(
loader!!,
chapterList.first { chapterId == it.chapter.id },
/* SY --> */page, /* SY <-- */
)
Result.success(true)
} else {
// Unlikely but okay
@ -634,7 +669,11 @@ class ReaderViewModel @JvmOverloads constructor(
* Saves the chapter progress (last read page and whether it's read)
* if incognito mode isn't on.
*/
private suspend fun updateChapterProgress(readerChapter: ReaderChapter, page: Page/* SY --> */, hasExtraPage: Boolean/* SY <-- */) {
private suspend fun updateChapterProgress(
readerChapter: ReaderChapter,
page: Page/* SY --> */,
hasExtraPage: Boolean, /* SY <-- */
) {
val pageIndex = page.index
mutableState.update {
@ -989,7 +1028,11 @@ class ReaderViewModel @JvmOverloads constructor(
val filename = generateFilename(manga, page)
// Pictures directory.
val relativePath = if (readerPreferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else ""
val relativePath = if (readerPreferences.folderPerManga().get()) {
DiskUtil.buildValidFilename(manga.title)
} else {
""
}
// Copy file in background.
viewModelScope.launchNonCancellable {
@ -1036,7 +1079,7 @@ class ReaderViewModel @JvmOverloads constructor(
page2 = secondPage,
isLTR = isLTR,
bg = bg,
location = Location.Pictures(DiskUtil.buildValidFilename(manga.title)),
location = Location.Pictures.create(DiskUtil.buildValidFilename(manga.title)),
manga = manga,
)
eventChannel.send(Event.SavedImage(SaveImageResult.Success(uri)))
@ -1288,7 +1331,10 @@ class ReaderViewModel @JvmOverloads constructor(
data object ChapterList : Dialog
// SY <--
data class PageActions(val page: ReaderPage/* SY --> */, val extraPage: ReaderPage? = null /* SY <-- */) : Dialog
data class PageActions(
val page: ReaderPage/* SY --> */,
val extraPage: ReaderPage? = null, /* SY <-- */
) : Dialog
// SY -->
data object AutoScrollHelp : Dialog
@ -1304,6 +1350,10 @@ class ReaderViewModel @JvmOverloads constructor(
data class SetCoverResult(val result: SetAsCoverResult) : Event
data class SavedImage(val result: SaveImageResult) : Event
data class ShareImage(val uri: Uri, val page: ReaderPage/* SY --> */, val secondPage: ReaderPage? = null /* SY <-- */) : Event
data class ShareImage(
val uri: Uri,
val page: ReaderPage/* SY --> */,
val secondPage: ReaderPage? = null, /* SY <-- */
) : Event
}
}

View File

@ -88,16 +88,37 @@ class ChapterLoader(
*/
private fun getPageLoader(chapter: ReaderChapter): PageLoader {
val dbChapter = chapter.chapter
val isDownloaded = downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, manga.source, skipCache = true)
val isDownloaded = downloadManager.isChapterDownloaded(
chapterName = dbChapter.name,
chapterScanlator = dbChapter.scanlator, /* SY --> */
mangaTitle = manga.ogTitle /* SY <-- */,
sourceId = manga.source,
skipCache = true,
)
return when {
// SY -->
source is MergedSource -> {
val mangaReference = mergedReferences.firstOrNull { it.mangaId == chapter.chapter.manga_id } ?: error("Merge reference null")
val source = sourceManager.get(mangaReference.mangaSourceId) ?: error("Source ${mangaReference.mangaSourceId} was null")
val mangaReference = mergedReferences.firstOrNull {
it.mangaId == chapter.chapter.manga_id
} ?: error("Merge reference null")
val source = sourceManager.get(mangaReference.mangaSourceId)
?: error("Source ${mangaReference.mangaSourceId} was null")
val manga = mergedManga[chapter.chapter.manga_id] ?: error("Manga for merged chapter was null")
val isMergedMangaDownloaded = downloadManager.isChapterDownloaded(chapter.chapter.name, chapter.chapter.scanlator, manga.ogTitle, manga.source, true)
val isMergedMangaDownloaded = downloadManager.isChapterDownloaded(
chapterName = chapter.chapter.name,
chapterScanlator = chapter.chapter.scanlator,
mangaTitle = manga.ogTitle,
sourceId = manga.source,
skipCache = true,
)
when {
isMergedMangaDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider)
isMergedMangaDownloaded -> DownloadPageLoader(
chapter = chapter,
manga = manga,
source = source,
downloadManager = downloadManager,
downloadProvider = downloadProvider,
)
source is HttpSource -> HttpPageLoader(chapter, source)
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
when (format) {

View File

@ -5,14 +5,54 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import eu.kanade.tachiyomi.R
enum class OrientationType(val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
DEFAULT(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000),
FREE(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008),
PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010),
LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018),
LOCKED_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020),
LOCKED_LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028),
REVERSE_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030),
enum class OrientationType(
val flag: Int,
@StringRes val stringRes: Int,
@DrawableRes val iconRes: Int,
val flagValue: Int,
) {
DEFAULT(
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
R.string.label_default,
R.drawable.ic_screen_rotation_24dp,
0x00000000,
),
FREE(
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
R.string.rotation_free,
R.drawable.ic_screen_rotation_24dp,
0x00000008,
),
PORTRAIT(
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT,
R.string.rotation_portrait,
R.drawable.ic_stay_current_portrait_24dp,
0x00000010,
),
LANDSCAPE(
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
R.string.rotation_landscape,
R.drawable.ic_stay_current_landscape_24dp,
0x00000018,
),
LOCKED_PORTRAIT(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
R.string.rotation_force_portrait,
R.drawable.ic_screen_lock_portrait_24dp,
0x00000020,
),
LOCKED_LANDSCAPE(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
R.string.rotation_force_landscape,
R.drawable.ic_screen_lock_landscape_24dp,
0x00000028,
),
REVERSE_PORTRAIT(
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
R.string.rotation_reverse_portrait,
R.drawable.ic_stay_current_portrait_24dp,
0x00000030,
),
;
companion object {

View File

@ -35,9 +35,15 @@ class ReaderPreferences(
fun keepScreenOn() = preferenceStore.getBoolean("pref_keep_screen_on_key", true)
fun defaultReadingMode() = preferenceStore.getInt("pref_default_reading_mode_key", ReadingModeType.RIGHT_TO_LEFT.flagValue)
fun defaultReadingMode() = preferenceStore.getInt(
"pref_default_reading_mode_key",
ReadingModeType.RIGHT_TO_LEFT.flagValue,
)
fun defaultOrientationType() = preferenceStore.getInt("pref_default_orientation_type_key", OrientationType.FREE.flagValue)
fun defaultOrientationType() = preferenceStore.getInt(
"pref_default_orientation_type_key",
OrientationType.FREE.flagValue,
)
fun webtoonDoubleTapZoomEnabled() = preferenceStore.getBoolean("pref_enable_double_tap_zoom_webtoon", true)

View File

@ -10,7 +10,11 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
enum class ReadingModeType(@StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
enum class ReadingModeType(
@StringRes val stringRes: Int,
@DrawableRes val iconRes: Int,
val flagValue: Int,
) {
DEFAULT(R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000),
LEFT_TO_RIGHT(R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001),
RIGHT_TO_LEFT(R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp, 0x00000002),

View File

@ -350,7 +350,9 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
val newPage =
when {
(oldCurrent?.first as? ReaderPage)?.chapter != currentChapter &&
(oldCurrent?.first as? ChapterTransition)?.from != currentChapter -> subItems.find { (it as? ReaderPage)?.chapter == currentChapter }
(oldCurrent?.first as? ChapterTransition)?.from != currentChapter -> subItems.find {
(it as? ReaderPage)?.chapter == currentChapter
}
useSecondPage -> (oldCurrent?.second ?: oldCurrent?.first)
else -> oldCurrent?.first ?: return
}

View File

@ -33,7 +33,11 @@ import kotlin.time.Duration
/**
* Implementation of a [Viewer] to display pages with a [RecyclerView].
*/
class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true, private val tapByPage: Boolean = false) : Viewer {
class WebtoonViewer(
val activity: ReaderActivity,
val isContinuous: Boolean = true,
private val tapByPage: Boolean = false,
) : Viewer {
val downloadManager: DownloadManager by injectLazy()
@ -291,7 +295,12 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
* Scrolls one screen over a period of time
*/
fun linearScroll(duration: Duration) {
recycler.smoothScrollBy(0, activity.resources.displayMetrics.heightPixels, LinearInterpolator(), duration.inWholeMilliseconds.toInt())
recycler.smoothScrollBy(
0,
activity.resources.displayMetrics.heightPixels,
LinearInterpolator(),
duration.inWholeMilliseconds.toInt(),
)
}
/**

View File

@ -106,7 +106,9 @@ object UpdatesTab : Tab {
LaunchedEffect(Unit) {
screenModel.events.collectLatest { event ->
when (event) {
Event.InternalError -> screenModel.snackbarHostState.showSnackbar(context.getString(R.string.internal_error))
Event.InternalError -> screenModel.snackbarHostState.showSnackbar(
context.getString(R.string.internal_error),
)
is Event.LibraryUpdateTriggered -> {
val msg = if (event.started) {
R.string.updating_library

View File

@ -10,7 +10,11 @@ import tachiyomi.domain.manga.model.Manga
/**
* Gets next unread chapter with filters and sorting applied
*/
fun List<Chapter>.getNextUnread(manga: Manga, downloadManager: DownloadManager /* SY --> */, mergedManga: Map<Long, Manga>/* SY <-- */): Chapter? {
fun List<Chapter>.getNextUnread(
manga: Manga,
downloadManager: DownloadManager /* SY --> */,
mergedManga: Map<Long, Manga>, /* SY <-- */
): Chapter? {
return applyFilters(manga, downloadManager/* SY --> */, mergedManga/* SY <-- */).let { chapters ->
// SY -->
if (manga.isEhBasedManga()) {

View File

@ -36,9 +36,17 @@ fun File.copyAndSetReadOnlyTo(target: File, overwrite: Boolean = false, bufferSi
if (target.exists()) {
if (!overwrite) {
throw FileAlreadyExistsException(file = this, other = target, reason = "The destination file already exists.")
throw FileAlreadyExistsException(
file = this,
other = target,
reason = "The destination file already exists.",
)
} else if (!target.delete()) {
throw FileAlreadyExistsException(file = this, other = target, reason = "Tried to overwrite the destination, but failed to delete it.")
throw FileAlreadyExistsException(
file = this,
other = target,
reason = "Tried to overwrite the destination, but failed to delete it.",
)
}
}

View File

@ -59,7 +59,9 @@ fun Context.copyToClipboard(label: String, content: String) {
* @param permission the permission to check.
* @return true if it has permissions.
*/
fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED
fun Context.hasPermission(
permission: String,
) = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED
val Context.powerManager: PowerManager
get() = getSystemService()!!
@ -105,7 +107,10 @@ fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) {
private fun Context.defaultBrowserPackageName(): String? {
val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri())
val resolveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.resolveActivity(browserIntent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong()))
packageManager.resolveActivity(
browserIntent,
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong()),
)
} else {
packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
}

View File

@ -49,7 +49,10 @@ fun Context.cancelNotification(id: Int) {
* @param block the function that will execute inside the builder.
* @return a notification to be displayed or updated.
*/
fun Context.notificationBuilder(channelId: String, block: (NotificationCompat.Builder.() -> Unit)? = null): NotificationCompat.Builder {
fun Context.notificationBuilder(
channelId: String,
block: (NotificationCompat.Builder.() -> Unit)? = null,
): NotificationCompat.Builder {
val builder = NotificationCompat.Builder(this, channelId)
.setColor(getColor(R.color.accent_blue))
if (block != null) {

View File

@ -91,6 +91,7 @@ fun View?.isVisibleOnScreen(): Boolean {
}
val actualPosition = Rect()
this.getGlobalVisibleRect(actualPosition)
val screen = Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels)
val screen =
Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels)
return actualPosition.intersect(screen)
}

View File

@ -138,7 +138,9 @@ object EXHMigrations {
val mergedMangas = runBlocking { getMangaBySource.await(MERGED_SOURCE_ID) }
if (mergedMangas.isNotEmpty()) {
val mangaConfigs = mergedMangas.mapNotNull { mergedManga -> readMangaConfig(mergedManga)?.let { mergedManga to it } }
val mangaConfigs = mergedMangas.mapNotNull { mergedManga ->
readMangaConfig(mergedManga)?.let { mergedManga to it }
}
if (mangaConfigs.isNotEmpty()) {
val mangaToUpdate = mutableListOf<MangaUpdate>()
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
@ -183,15 +185,45 @@ object EXHMigrations {
insertMergedReference.awaitAll(mergedMangaReferences)
}
val loadedMangaList = mangaConfigs.map { it.second.children }.flatten().mapNotNull { it.load() }.distinct()
val chapters = runBlocking { handler.awaitList { ehQueries.getChaptersByMangaIds(mergedMangas.map { it.id }, ChapterMapper::mapChapter) } }
val mergedMangaChapters = runBlocking { handler.awaitList { ehQueries.getChaptersByMangaIds(loadedMangaList.map { it.manga.id }, ChapterMapper::mapChapter) } }
val loadedMangaList = mangaConfigs
.map { it.second.children }
.flatten()
.mapNotNull { it.load() }
.distinct()
val chapters =
runBlocking {
handler.awaitList {
ehQueries.getChaptersByMangaIds(
mergedMangas.map { it.id },
ChapterMapper::mapChapter,
)
}
}
val mergedMangaChapters =
runBlocking {
handler.awaitList {
ehQueries.getChaptersByMangaIds(
loadedMangaList.map { it.manga.id },
ChapterMapper::mapChapter,
)
}
}
val mergedMangaChaptersMatched = mergedMangaChapters.mapNotNull { chapter -> loadedMangaList.firstOrNull { it.manga.id == chapter.id }?.let { it to chapter } }
val parsedChapters = chapters.filter { it.read || it.lastPageRead != 0L }.mapNotNull { chapter -> readUrlConfig(chapter.url)?.let { chapter to it } }
val mergedMangaChaptersMatched = mergedMangaChapters.mapNotNull { chapter ->
loadedMangaList.firstOrNull {
it.manga.id == chapter.id
}?.let { it to chapter }
}
val parsedChapters = chapters.filter {
it.read || it.lastPageRead != 0L
}.mapNotNull { chapter -> readUrlConfig(chapter.url)?.let { chapter to it } }
val chaptersToUpdate = mutableListOf<ChapterUpdate>()
parsedChapters.forEach { parsedChapter ->
mergedMangaChaptersMatched.firstOrNull { it.second.url == parsedChapter.second.url && it.first.source.id == parsedChapter.second.source && it.first.manga.url == parsedChapter.second.mangaUrl }?.let {
mergedMangaChaptersMatched.firstOrNull {
it.second.url == parsedChapter.second.url &&
it.first.source.id == parsedChapter.second.source &&
it.first.manga.url == parsedChapter.second.mangaUrl
}?.let {
chaptersToUpdate += ChapterUpdate(
it.second.id,
read = parsedChapter.first.read,
@ -353,7 +385,11 @@ object EXHMigrations {
if (oldSecureScreen) {
securityPreferences.secureScreen().set(SecurityPreferences.SecureScreenMode.ALWAYS)
}
if (DeviceUtil.isMiui && basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER) {
if (
DeviceUtil.isMiui &&
basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller
.PACKAGEINSTALLER
) {
basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.LEGACY)
}
}
@ -418,7 +454,9 @@ object EXHMigrations {
}
if (oldVersion under 38) {
// Handle renamed enum values
val newSortingMode = when (val oldSortingMode = prefs.getString(libraryPreferences.sortingMode().key(), "ALPHABETICAL")) {
val newSortingMode = when (
val oldSortingMode = prefs.getString(libraryPreferences.sortingMode().key(), "ALPHABETICAL")
) {
"LAST_CHECKED" -> "LAST_MANGA_UPDATE"
"UNREAD" -> "UNREAD_COUNT"
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE"
@ -618,7 +656,7 @@ object EXHMigrations {
"eh_exhSettingsProfile",
"eh_settingsKey",
"eh_sessionCookie",
"eh_hathPerksCookie"
"eh_hathPerksCookie",
)
replacePreferences(
@ -750,7 +788,6 @@ object EXHMigrations {
}
}
@Suppress("UNCHECKED_CAST")
private fun replacePreferences(
preferenceStore: PreferenceStore,

View File

@ -113,7 +113,9 @@ object DebugFunctions {
}
private val throttleManager = EHentaiThrottleManager()
fun getDelegatedSourceList(): String = AndroidSourceManager.currentDelegatedSources.map { it.value.sourceName + " : " + it.value.sourceId + " : " + it.value.factory }.joinToString(separator = "\n")
fun getDelegatedSourceList(): String = AndroidSourceManager.currentDelegatedSources.map {
it.value.sourceName + " : " + it.value.sourceId + " : " + it.value.factory
}.joinToString(separator = "\n")
fun resetEHGalleriesForUpdater() {
throttleManager.resetThrottle()

View File

@ -51,7 +51,10 @@ class EHentaiUpdateHelper(context: Context) {
*
* @return Triple<Accepted, Discarded, HasNew>
*/
suspend fun findAcceptedRootAndDiscardOthers(sourceId: Long, chapters: List<Chapter>): Triple<ChapterChain, List<ChapterChain>, Boolean> {
suspend fun findAcceptedRootAndDiscardOthers(
sourceId: Long,
chapters: List<Chapter>,
): Triple<ChapterChain, List<ChapterChain>, Boolean> {
// Find other chains
val chains = chapters
.flatMap { chapter ->
@ -115,7 +118,11 @@ class EHentaiUpdateHelper(context: Context) {
chapterRepository.updateAll(chapterUpdates)
chapterRepository.addAll(newChapters)
val (newHistory, deleteHistory) = getHistory(getChaptersByMangaId.await(accepted.manga.id), chainsAsChapters, chainsAsHistory)
val (newHistory, deleteHistory) = getHistory(
getChaptersByMangaId.await(accepted.manga.id),
chainsAsChapters,
chainsAsHistory,
)
// Delete the duplicate history first
deleteHistory.forEach {

View File

@ -102,7 +102,8 @@ class FavoritesSyncHelper(val context: Context) {
if (manga.id in seenManga) {
val inCategories = getCategories.await(manga.id)
status.value = FavoritesSyncStatus.BadLibraryState.MangaInMultipleCategories(manga, inCategories, context)
status.value = FavoritesSyncStatus.BadLibraryState
.MangaInMultipleCategories(manga, inCategories, context)
logger.w(context.getString(R.string.favorites_sync_gallery_multiple_categories_error, manga.id))
return
@ -143,17 +144,23 @@ class FavoritesSyncHelper(val context: Context) {
// Do not update galleries while syncing favorites
EHentaiUpdateWorker.cancelBackground(context)
status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_calculating_remote_changes))
status.value = FavoritesSyncStatus.Processing(
context.getString(R.string.favorites_sync_calculating_remote_changes),
)
val remoteChanges = storage.getChangedRemoteEntries(favorites.first)
val localChanges = if (prefs.exhReadOnlySync().get()) {
null // Do not build local changes if they are not going to be applied
} else {
status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_calculating_local_changes))
status.value = FavoritesSyncStatus.Processing(
context.getString(R.string.favorites_sync_calculating_local_changes),
)
storage.getChangedDbEntries()
}
// Apply remote categories
status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_syncing_category_names))
status.value = FavoritesSyncStatus.Processing(
context.getString(R.string.favorites_sync_syncing_category_names),
)
applyRemoteCategories(favorites.second)
// Apply change sets
@ -173,7 +180,9 @@ class FavoritesSyncHelper(val context: Context) {
logger.w(context.getString(R.string.favorites_sync_ignoring_exception), e)
return
} catch (e: Exception) {
status.value = FavoritesSyncStatus.Error(context.getString(R.string.favorites_sync_unknown_error, e.message))
status.value = FavoritesSyncStatus.Error(
context.getString(R.string.favorites_sync_unknown_error, e.message),
)
logger.e(context.getString(R.string.favorites_sync_sync_error), e)
return
} finally {
@ -273,7 +282,9 @@ class FavoritesSyncHelper(val context: Context) {
private suspend fun applyChangeSetToRemote(errorList: MutableList<String>, changeSet: ChangeSet) {
// Apply removals
if (changeSet.removed.isNotEmpty()) {
status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_removing_galleries, changeSet.removed.size))
status.value = FavoritesSyncStatus.Processing(
context.getString(R.string.favorites_sync_removing_galleries, changeSet.removed.size),
)
val formBody = FormBody.Builder()
.add("ddact", "delete")
@ -322,7 +333,10 @@ class FavoritesSyncHelper(val context: Context) {
// Apply removals
changeSet.removed.forEachIndexed { index, it ->
status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_remove_from_local, index + 1, changeSet.removed.size), title = it.title)
status.value = FavoritesSyncStatus.Processing(
context.getString(R.string.favorites_sync_remove_from_local, index + 1, changeSet.removed.size),
title = it.title,
)
val url = it.getUrl()
// Consider both EX and EH sources
@ -377,10 +391,17 @@ class FavoritesSyncHelper(val context: Context) {
return@forEachIndexed
}
val errorString = context.getString(R.string.favorites_sync_failed_to_add_to_local) + when (result) {
is GalleryAddEvent.Fail.Error -> context.getString(R.string.favorites_sync_failed_to_add_to_local_error, it.title, result.logMessage)
is GalleryAddEvent.Fail.UnknownType -> context.getString(R.string.favorites_sync_failed_to_add_to_local_unknown_type, it.title, result.galleryUrl)
is GalleryAddEvent.Fail.UnknownSource -> context.getString(R.string.favorites_sync_failed_to_add_to_local_unknown_type, it.title, result.galleryUrl)
val errorString = context.getString(R.string.favorites_sync_failed_to_add_to_local) +
when (result) {
is GalleryAddEvent.Fail.Error -> context.getString(
R.string.favorites_sync_failed_to_add_to_local_error, it.title, result.logMessage,
)
is GalleryAddEvent.Fail.UnknownType -> context.getString(
R.string.favorites_sync_failed_to_add_to_local_unknown_type, it.title, result.galleryUrl,
)
is GalleryAddEvent.Fail.UnknownSource -> context.getString(
R.string.favorites_sync_failed_to_add_to_local_unknown_type, it.title, result.galleryUrl,
)
}
if (prefs.exhLenientSync().get()) {
@ -427,7 +448,12 @@ sealed class FavoritesSyncStatus() {
this(
manga = manga,
categories = categories,
message = context.getString(R.string.favorites_sync_gallery_in_multiple_categories, manga.title, categories.joinToString { it.name }),
message = context.getString(
R.string.favorites_sync_gallery_in_multiple_categories, manga.title,
categories.joinToString {
it.name
},
),
)
}
}

View File

@ -23,7 +23,7 @@ import okhttp3.Response
import rx.Observable
import tachiyomi.core.util.lang.runAsObservable
import uy.kohesive.injekt.injectLazy
import java.util.concurrent.TimeUnit
import kotlin.time.Duration.Companion.seconds
class BilibiliHandler(currentClient: OkHttpClient) {
val baseUrl = "https://www.bilibilicomics.com"
@ -34,7 +34,7 @@ class BilibiliHandler(currentClient: OkHttpClient) {
.build()
val client: OkHttpClient = currentClient.newBuilder()
.rateLimit(1, 1, TimeUnit.SECONDS)
.rateLimit(1, 1.seconds)
.build()
val json by injectLazy<Json>()

View File

@ -28,7 +28,10 @@ class MangaHandler(
val mangaId = MdUtil.getMangaId(manga.url)
val response = async(Dispatchers.IO) { service.viewManga(mangaId) }
val simpleChapters = async(Dispatchers.IO) { getSimpleChapters(manga) }
val statistics = async(Dispatchers.IO) { kotlin.runCatching { service.mangasRating(mangaId) }.getOrNull()?.statistics?.get(mangaId) }
val statistics =
async(Dispatchers.IO) {
kotlin.runCatching { service.mangasRating(mangaId) }.getOrNull()?.statistics?.get(mangaId)
}
apiMangaParser.parseToManga(
manga,
sourceId,
@ -45,7 +48,11 @@ class MangaHandler(
}
}
fun fetchChapterListObservable(manga: SManga, blockedGroups: String, blockedUploaders: String): Observable<List<SChapter>> = runAsObservable {
fun fetchChapterListObservable(
manga: SManga,
blockedGroups: String,
blockedUploaders: String,
): Observable<List<SChapter>> = runAsObservable {
getChapterList(manga, blockedGroups, blockedUploaders)
}

View File

@ -21,7 +21,13 @@ class MangaHotHandler(currentClient: OkHttpClient, userAgent: String) {
val client: OkHttpClient = currentClient
suspend fun fetchPageList(externalUrl: String): List<Page> {
val request = GET(externalUrl.substringBefore("?").replace(baseUrl, apiUrl).replace("viewer", "v1/works/storyDetail"), headers)
val request =
GET(
externalUrl.substringBefore("?")
.replace(baseUrl, apiUrl)
.replace("viewer", "v1/works/storyDetail"),
headers,
)
return pageListParse(client.newCall(request).awaitSuccess())
}

View File

@ -33,7 +33,12 @@ class SimilarHandler(
MdUtil.createMangaEntry(it, lang)
}
return MetadataMangasPage(mangaList, false, List(mangaList.size) { MangaDexSearchMetadata().also { it.relation = MangaDexRelation.SIMILAR } })
return MetadataMangasPage(
mangaList, false,
List(mangaList.size) {
MangaDexSearchMetadata().also { it.relation = MangaDexRelation.SIMILAR }
},
)
}
suspend fun getRelated(manga: SManga): MetadataMangasPage {
@ -57,7 +62,8 @@ class SimilarHandler(
hasNextPage = false,
mangasMetadata = mangaList.map { manga ->
MangaDexSearchMetadata().also {
it.relation = relatedListDto.data.firstOrNull { it.relationships.any { it.id == MdUtil.getMangaId(manga.url) } }
it.relation = relatedListDto.data
.firstOrNull { it.relationships.any { it.id == MdUtil.getMangaId(manga.url) } }
?.attributes?.relation?.let(MangaDexRelation::fromDex)
}
},

View File

@ -15,7 +15,9 @@ enum class FollowStatus(val int: Int) {
fun toDex(): String = this.name.lowercase(Locale.US)
companion object {
fun fromDex(value: String?): FollowStatus = values().firstOrNull { it.name.lowercase(Locale.US) == value } ?: UNFOLLOWED
fun fromDex(
value: String?,
): FollowStatus = values().firstOrNull { it.name.lowercase(Locale.US) == value } ?: UNFOLLOWED
fun fromInt(value: Int): FollowStatus = values().firstOrNull { it.int == value } ?: UNFOLLOWED
}
}

View File

@ -66,7 +66,11 @@ class EhUConfigBuilder {
configItems += Entry.LanguageSystem().getLanguages(preferences.exhSettingsLanguages().get().split("\n"))
configItems += Entry.Categories().categoryConfigs(preferences.exhEnabledCategories().get().split(",").map { it.toBoolean() })
configItems += Entry.Categories().categoryConfigs(
preferences.exhEnabledCategories().get().split(",").map {
it.toBoolean()
},
)
// Actually build form body
val formBody = FormBody.Builder()

View File

@ -18,7 +18,10 @@ import exh.util.SourceTagsUtil
import kotlin.math.roundToInt
object MetadataUIUtil {
fun getRatingString(context: Context, @FloatRange(from = 0.0, to = 10.0) rating: Float? = null) = when (rating?.roundToInt()) {
fun getRatingString(
context: Context,
@FloatRange(from = 0.0, to = 10.0) rating: Float? = null,
) = when (rating?.roundToInt()) {
0 -> R.string.rating0
1 -> R.string.rating1
2 -> R.string.rating2
@ -36,7 +39,8 @@ object MetadataUIUtil {
fun getGenreAndColour(context: Context, genre: String) = when (genre) {
"doujinshi", "Doujinshi" -> SourceTagsUtil.GenreColor.DOUJINSHI_COLOR to R.string.doujinshi
"manga", "Japanese Manga", "Manga" -> SourceTagsUtil.GenreColor.MANGA_COLOR to R.string.entry_type_manga
"artistcg", "artist CG", "artist-cg", "Artist CG" -> SourceTagsUtil.GenreColor.ARTIST_CG_COLOR to R.string.artist_cg
"artistcg", "artist CG", "artist-cg", "Artist CG" ->
SourceTagsUtil.GenreColor.ARTIST_CG_COLOR to R.string.artist_cg
"gamecg", "game CG", "game-cg", "Game CG" -> SourceTagsUtil.GenreColor.GAME_CG_COLOR to R.string.game_cg
"western" -> SourceTagsUtil.GenreColor.WESTERN_COLOR to R.string.western
"non-h", "non-H" -> SourceTagsUtil.GenreColor.NON_H_COLOR to R.string.non_h

View File

@ -29,7 +29,9 @@ fun NHentaiDescription(state: State.Success, openMetadataViewer: () -> Unit) {
if (meta == null || meta !is NHentaiSearchMetadata) return@AndroidView
val binding = DescriptionAdapterNhBinding.bind(it)
binding.genre.text = meta.tags.filter { it.namespace == NHentaiSearchMetadata.NHENTAI_CATEGORIES_NAMESPACE }.let { tags ->
binding.genre.text = meta.tags.filter {
it.namespace == NHentaiSearchMetadata.NHENTAI_CATEGORIES_NAMESPACE
}.let { tags ->
if (tags.isNotEmpty()) tags.joinToString(transform = { it.name }) else null
}.let { categoriesString ->
categoriesString?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
@ -46,7 +48,11 @@ fun NHentaiDescription(state: State.Success, openMetadataViewer: () -> Unit) {
binding.whenPosted.text = MetadataUtil.EX_DATE_FORMAT.format(Date((meta.uploadDate ?: 0) * 1000))
binding.pages.text = context.resources.getQuantityString(R.plurals.num_pages, meta.pageImageTypes.size, meta.pageImageTypes.size)
binding.pages.text = context.resources.getQuantityString(
R.plurals.num_pages,
meta.pageImageTypes.size,
meta.pageImageTypes.size,
)
binding.pages.bindDrawable(context, R.drawable.ic_baseline_menu_book_24)
@SuppressLint("SetTextI18n")

View File

@ -16,7 +16,11 @@ private val galleryAdder by lazy {
/**
* A version of fetchSearchManga that supports URL importing
*/
fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> =
fun UrlImportableSource.urlImportFetchSearchManga(
context: Context,
query: String,
fail: () -> Observable<MangasPage>,
): Observable<MangasPage> =
when {
query.startsWith("http://") || query.startsWith("https://") -> {
runAsObservable {
@ -36,18 +40,21 @@ fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: Strin
else -> fail()
}
/**
* A version of fetchSearchManga that supports URL importing
*/
suspend fun UrlImportableSource.urlImportFetchSearchMangaSuspend(context: Context, query: String, fail: suspend () -> MangasPage): MangasPage =
suspend fun UrlImportableSource.urlImportFetchSearchMangaSuspend(
context: Context,
query: String,
fail: suspend () -> MangasPage,
): MangasPage =
when {
query.startsWith("http://") || query.startsWith("https://") -> {
val res = galleryAdder.addGallery(
context = context,
url = query,
fav = false,
forceSource = this
forceSource = this,
)
MangasPage(

View File

@ -26,7 +26,10 @@ class SecurityPreferences(
fun sqlPassword() = this.preferenceStore.getString(Preference.privateKey("sql_password"), "")
fun passwordProtectDownloads() = preferenceStore.getBoolean(Preference.privateKey("password_protect_downloads"), false)
fun passwordProtectDownloads() = preferenceStore.getBoolean(
Preference.privateKey("password_protect_downloads"),
false,
)
fun encryptionType() = this.preferenceStore.getEnum("encryption_type", EncryptionType.AES_256)

View File

@ -89,7 +89,8 @@ abstract class WebViewInterceptor(
}
}
// Based on [IsRequestHeaderSafe] in https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc
// Based on [IsRequestHeaderSafe] in
// https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc
private fun isRequestHeaderSafe(_name: String, _value: String): Boolean {
val name = _name.lowercase(Locale.ENGLISH)
val value = _value.lowercase(Locale.ENGLISH)
@ -97,4 +98,6 @@ private fun isRequestHeaderSafe(_name: String, _value: String): Boolean {
if (name == "connection" && value == "upgrade") return false
return true
}
private val unsafeHeaderNames = listOf("content-length", "host", "trailer", "te", "upgrade", "cookie2", "keep-alive", "transfer-encoding", "set-cookie")
private val unsafeHeaderNames = listOf(
"content-length", "host", "trailer", "te", "upgrade", "cookie2", "keep-alive", "transfer-encoding", "set-cookie",
)

View File

@ -159,7 +159,9 @@ object CbzCrypto {
}
return true
} catch (e: Exception) {
logcat(LogPriority.WARN) { "Wrong CBZ archive password for: ${zip4j.file.name} in: ${zip4j.file.parentFile?.name}" }
logcat(LogPriority.WARN) {
"Wrong CBZ archive password for: ${zip4j.file.name} in: ${zip4j.file.parentFile?.name}"
}
}
return false
}

View File

@ -27,7 +27,10 @@ fun Any.xLogE(log: Any?) = xLog().let { if (log == null) it.e("null") else it.e(
fun Any.xLogW(log: Any?) = xLog().let { if (log == null) it.w("null") else it.w(log) }
fun Any.xLogD(log: Any?) = xLog().let { if (log == null) it.d("null") else it.d(log) }
fun Any.xLogI(log: Any?) = xLog().let { if (log == null) it.i("null") else it.i(log) }
fun Any.xLog(logLevel: LogLevel, log: Any?) = xLog().let { if (log == null) it.log(logLevel.int, "null") else it.log(logLevel.int, log) }
fun Any.xLog(
logLevel: LogLevel,
log: Any?,
) = xLog().let { if (log == null) it.log(logLevel.int, "null") else it.log(logLevel.int, log) }
/*fun Any.xLogE(vararg logs: Any) = xLog().e(logs)
fun Any.xLogW(vararg logs: Any) = xLog().w(logs)

View File

@ -364,7 +364,9 @@ object ImageUtil {
}
}
private fun splitImageName(filenamePrefix: String, index: Int) = "${filenamePrefix}__${"%03d".format(index + 1)}.jpg"
private fun splitImageName(filenamePrefix: String, index: Int) = "${filenamePrefix}__${"%03d".format(
index + 1,
)}.jpg"
private val BitmapFactory.Options.splitData
get(): List<SplitData> {
@ -449,10 +451,12 @@ object ImageUtil {
val botLeftIsDark = botLeftPixel.isDark()
val botRightIsDark = botRightPixel.isDark()
var darkBG = (topLeftIsDark && (botLeftIsDark || botRightIsDark || topRightIsDark || midLeftIsDark || topMidIsDark)) ||
var darkBG =
(topLeftIsDark && (botLeftIsDark || botRightIsDark || topRightIsDark || midLeftIsDark || topMidIsDark)) ||
(topRightIsDark && (botRightIsDark || botLeftIsDark || midRightIsDark || topMidIsDark))
val topAndBotPixels = listOf(topLeftPixel, topCenterPixel, topRightPixel, botRightPixel, bottomCenterPixel, botLeftPixel)
val topAndBotPixels =
listOf(topLeftPixel, topCenterPixel, topRightPixel, botRightPixel, bottomCenterPixel, botLeftPixel)
val isNotWhiteAndCloseTo = topAndBotPixels.mapIndexed { index, color ->
val other = topAndBotPixels[(index + 1) % topAndBotPixels.size]
!color.isWhite() && color.isCloseTo(other)
@ -597,10 +601,16 @@ object ImageUtil {
darkBG -> {
return ColorDrawable(blackColor)
}
topIsBlackStreak || (topCornersIsDark && topOffsetCornersIsDark && (topMidIsDark || overallBlackPixels > 9)) -> {
topIsBlackStreak || (
topCornersIsDark && topOffsetCornersIsDark &&
(topMidIsDark || overallBlackPixels > 9)
) -> {
intArrayOf(blackColor, blackColor, whiteColor, whiteColor)
}
bottomIsBlackStreak || (botCornersIsDark && botOffsetCornersIsDark && (bottomCenterPixel.isDark() || overallBlackPixels > 9)) -> {
bottomIsBlackStreak || (
botCornersIsDark && botOffsetCornersIsDark &&
(bottomCenterPixel.isDark() || overallBlackPixels > 9)
) -> {
intArrayOf(whiteColor, whiteColor, blackColor, blackColor)
}
else -> {

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