Restrict line length with ktlint

This commit is contained in:
arkon 2023-11-04 23:28:41 -04:00
parent 056dbaefda
commit 1d144e6767
61 changed files with 660 additions and 148 deletions

View file

@ -1,4 +1,5 @@
[*.{kt,kts}]
max_line_length = 120
indent_size = 4
insert_final_newline = true
ij_kotlin_allow_trailing_comma = true

View file

@ -23,7 +23,12 @@ fun List<Chapter>.applyFilters(manga: Manga, downloadManager: DownloadManager):
.filter { chapter -> applyFilter(bookmarkedFilter) { chapter.bookmark } }
.filter { chapter ->
applyFilter(downloadedFilter) {
val downloaded = downloadManager.isChapterDownloaded(chapter.name, chapter.scanlator, manga.title, manga.source)
val downloaded = downloadManager.isChapterDownloaded(
chapter.name,
chapter.scanlator,
manga.title,
manga.source,
)
downloaded || isLocalManga
}
}

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

@ -102,14 +102,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

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

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

View file

@ -189,7 +189,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,
@ -587,7 +591,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

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

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

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

@ -77,7 +77,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,
),
)
}
@ -127,7 +129,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

@ -99,7 +99,9 @@ fun ReaderAppBars(
AppBarActions(
listOfNotNull(
AppBar.Action(
title = stringResource(if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark),
title = stringResource(
if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark,
),
icon = if (bookmarked) Icons.Outlined.Bookmark else Icons.Outlined.BookmarkBorder,
onClick = onToggleBookmarked,
),

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

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

@ -121,13 +121,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")
}
}
@ -242,7 +251,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)
}
}
@ -259,7 +271,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

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

@ -88,7 +88,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)
}
@ -183,7 +189,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),
)
}
private suspend fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>, sync: Boolean) {
@ -214,9 +225,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),
)
}
}
@ -603,7 +624,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>) {
@ -613,7 +639,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

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

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

@ -324,7 +324,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
}
@ -432,13 +436,17 @@ 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)
}

View file

@ -296,7 +296,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)
@ -500,7 +502,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,
)
@ -517,7 +521,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

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

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

@ -36,7 +36,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>()
}
init {
scope.launch {

View file

@ -264,7 +264,9 @@ 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 }),
)
}
}
}
@ -314,7 +316,10 @@ 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 {

View file

@ -543,7 +543,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? {

View file

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

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

@ -112,8 +112,20 @@ class MangaScreen(
screenModel.toggleFavorite()
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
onWebViewClicked = { openMangaInWebView(navigator, screenModel.manga, screenModel.source) }.takeIf { isHttpSource },
onWebViewLongClicked = { copyMangaUrl(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource },
onWebViewClicked = {
openMangaInWebView(
navigator,
screenModel.manga,
screenModel.source,
)
}.takeIf { isHttpSource },
onWebViewLongClicked = {
copyMangaUrl(
context,
screenModel.manga,
screenModel.source,
)
}.takeIf { isHttpSource },
onTrackingClicked = screenModel::showTrackDialog.takeIf { successState.trackingAvailable },
onTagSearch = { scope.launch { performGenreSearch(navigator, it, screenModel.source!!) } },
onFilterButtonClicked = screenModel::showSettingsDialog,
@ -124,8 +136,12 @@ 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 },
onMigrateClicked = { navigator.push(MigrateSearchScreen(successState.manga.id)) }.takeIf { successState.manga.favorite },
onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf {
screenModel.isUpdateIntervalEnabled && successState.manga.favorite
},
onMigrateClicked = {
navigator.push(MigrateSearchScreen(successState.manga.id))
}.takeIf { successState.manga.favorite },
onMultiBookmarkClicked = screenModel::bookmarkChapters,
onMultiMarkAsReadClicked = screenModel::markChaptersRead,
onMarkPreviousAsReadClicked = screenModel::markPreviousChapterRead,

View file

@ -160,8 +160,18 @@ class ReaderViewModel @JvmOverloads constructor(
readerPreferences.skipFiltered().get() -> {
(manga.unreadFilterRaw == Manga.CHAPTER_SHOW_READ && !it.read) ||
(manga.unreadFilterRaw == Manga.CHAPTER_SHOW_UNREAD && it.read) ||
(manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED && !downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) ||
(manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED && downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) ||
(
manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED &&
!downloadManager.isChapterDownloaded(
it.name, it.scanlator, manga.title, manga.source,
)
) ||
(
manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED &&
downloadManager.isChapterDownloaded(
it.name, it.scanlator, manga.title, manga.source,
)
) ||
(manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark) ||
(manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_NOT_BOOKMARKED && it.bookmark)
}
@ -759,7 +769,13 @@ 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 {

View file

@ -75,7 +75,13 @@ class ChapterLoader(
*/
private fun getPageLoader(chapter: ReaderChapter): PageLoader {
val dbChapter = chapter.chapter
val isDownloaded = downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, manga.title, manga.source, skipCache = true)
val isDownloaded = downloadManager.isChapterDownloaded(
dbChapter.name,
dbChapter.scanlator,
manga.title,
manga.source,
skipCache = true,
)
return when {
isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider)
source is LocalSource -> source.getFormat(chapter.chapter).let { 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

@ -30,9 +30,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

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

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

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

@ -271,7 +271,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> {
@ -356,10 +358,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)
@ -504,10 +508,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 -> {

View file

@ -8,9 +8,8 @@ import eu.kanade.tachiyomi.source.model.SManga
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.domain.source.repository.SourcePagingSourceType
class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource(
source,
) {
class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) :
SourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source.getSearchManga(currentPage, query, filters)
}

View file

@ -16,5 +16,18 @@ data class ChapterUpdate(
)
fun Chapter.toChapterUpdate(): ChapterUpdate {
return ChapterUpdate(id, mangaId, read, bookmark, lastPageRead, dateFetch, sourceOrder, url, name, dateUpload, chapterNumber, scanlator)
return ChapterUpdate(
id,
mangaId,
read,
bookmark,
lastPageRead,
dateFetch,
sourceOrder,
url,
name,
dateUpload,
chapterNumber,
scanlator,
)
}

View file

@ -95,7 +95,10 @@ fun VerticalFastScroller(
}
val thumbBottomPadding = with(LocalDensity.current) { bottomContentPadding.toPx() }
val heightPx = contentHeight.toFloat() - thumbTopPadding - thumbBottomPadding - listState.layoutInfo.afterContentPadding
val heightPx = contentHeight.toFloat() -
thumbTopPadding -
thumbBottomPadding -
listState.layoutInfo.afterContentPadding
val thumbHeightPx = with(LocalDensity.current) { ThumbLength.toPx() }
val trackHeightPx = heightPx - thumbHeightPx
@ -261,7 +264,10 @@ fun VerticalGridFastScroller(
}
val thumbBottomPadding = with(LocalDensity.current) { bottomContentPadding.toPx() }
val heightPx = contentHeight.toFloat() - thumbTopPadding - thumbBottomPadding - state.layoutInfo.afterContentPadding
val heightPx = contentHeight.toFloat() -
thumbTopPadding -
thumbBottomPadding -
state.layoutInfo.afterContentPadding
val thumbHeightPx = with(LocalDensity.current) { ThumbLength.toPx() }
val trackHeightPx = heightPx - thumbHeightPx

View file

@ -121,7 +121,11 @@ private fun Modifier.drawScrollbar(
items
.fastFirstOrNull { (it.key as? String)?.startsWith(STICKY_HEADER_KEY_PREFIX)?.not() ?: true }!!
.run {
val startPadding = if (reverseDirection) layoutInfo.afterContentPadding else layoutInfo.beforeContentPadding
val startPadding = if (reverseDirection) {
layoutInfo.afterContentPadding
} else {
layoutInfo.beforeContentPadding
}
startPadding + ((estimatedItemSize * index - offset) / totalSize * viewportSize)
}
}

View file

@ -70,7 +70,10 @@ fun UpdatesWidget(
.padding(horizontal = 3.dp),
contentAlignment = Alignment.Center,
) {
val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply {
val intent = Intent(
LocalContext.current,
Class.forName(Constants.MAIN_ACTIVITY),
).apply {
action = Constants.SHORTCUT_MANGA
putExtra(Constants.MANGA_EXTRA, mangaId)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

View file

@ -72,7 +72,13 @@ actual class LocalSource(
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
val baseDirsFiles = fileSystem.getFilesInBaseDirectories()
val lastModifiedLimit by lazy { if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L }
val lastModifiedLimit by lazy {
if (filters === LATEST_FILTERS) {
System.currentTimeMillis() - LATEST_THRESHOLD
} else {
0L
}
}
var mangaDirs = baseDirsFiles
// Filter out files that are hidden and is not a folder
.filter { it.isDirectory && !it.name.startsWith('.') }