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}] [*.{kt,kts}]
max_line_length = 120
indent_size = 4 indent_size = 4
insert_final_newline = true insert_final_newline = true
ij_kotlin_allow_trailing_comma = 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(bookmarkedFilter) { chapter.bookmark } }
.filter { chapter -> .filter { chapter ->
applyFilter(downloadedFilter) { 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 downloaded || isLocalManga
} }
} }

View file

@ -11,7 +11,12 @@ class SourcePreferences(
private val preferenceStore: PreferenceStore, 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()) 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 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) fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)

View file

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

View file

@ -43,7 +43,9 @@ class DelayedTrackingUpdateJob(private val context: Context, workerParams: Worke
track?.copy(lastChapterRead = it.lastChapterRead.toDouble()) track?.copy(lastChapterRead = it.lastChapterRead.toDouble())
} }
.forEach { track -> .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) trackChapter.await(context, track.mangaId, track.lastChapterRead)
} }
} }

View file

@ -102,14 +102,26 @@ private fun MigrateSourceList(
IconButton(onClick = onToggleSortingMode) { IconButton(onClick = onToggleSortingMode) {
when (sortingMode) { when (sortingMode) {
SetMigrateSorting.Mode.ALPHABETICAL -> Icon(Icons.Outlined.SortByAlpha, contentDescription = stringResource(R.string.action_sort_alpha)) SetMigrateSorting.Mode.ALPHABETICAL -> Icon(
SetMigrateSorting.Mode.TOTAL -> Icon(Icons.Outlined.Numbers, contentDescription = stringResource(R.string.action_sort_count)) 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) { IconButton(onClick = onToggleSortingDirection) {
when (sortingDirection) { when (sortingDirection) {
SetMigrateSorting.Direction.ASCENDING -> Icon(Icons.Outlined.ArrowUpward, contentDescription = stringResource(R.string.action_asc)) SetMigrateSorting.Direction.ASCENDING -> Icon(
SetMigrateSorting.Direction.DESCENDING -> Icon(Icons.Outlined.ArrowDownward, contentDescription = stringResource(R.string.action_desc)) 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, onClick: () -> Unit,
) { ) {
val icon = if (isPinned) Icons.Filled.PushPin else Icons.Outlined.PushPin 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 val description = if (isPinned) R.string.action_unpin else R.string.action_pin
IconButton(onClick = onClick) { IconButton(onClick = onClick) {
Icon( Icon(

View file

@ -25,7 +25,9 @@ fun BaseSourceItem(
action: @Composable RowScope.(Source) -> Unit = {}, action: @Composable RowScope.(Source) -> Unit = {},
content: @Composable RowScope.(Source, String?) -> Unit = defaultContent, 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( BaseBrowseItem(
modifier = modifier, modifier = modifier,
onClickItem = onClickItem, onClickItem = onClickItem,

View file

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

View file

@ -614,7 +614,9 @@ fun MangaScreenLargeImpl(
val isReading = remember(state.chapters) { val isReading = remember(state.chapters) {
state.chapters.fastAny { it.chapter.read } 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) }, icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
onClick = onContinueReading, onClick = onContinueReading,

View file

@ -189,7 +189,11 @@ fun MangaActionRow(
) )
if (onEditIntervalClicked != null && fetchInterval != null) { if (onEditIntervalClicked != null && fetchInterval != null) {
MangaActionButton( 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, icon = Icons.Default.HourglassEmpty,
color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor, color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
onClick = onEditIntervalClicked, onClick = onEditIntervalClicked,
@ -587,7 +591,9 @@ private fun MangaSummary(
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down) val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down)
Icon( Icon(
painter = rememberAnimatedVectorPainter(image, !expanded), 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, tint = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())), modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())),
) )

View file

@ -62,7 +62,9 @@ fun MoreScreen(
WarningBanner( WarningBanner(
textRes = R.string.fdroid_warning, textRes = R.string.fdroid_warning,
modifier = Modifier.clickable { 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 { val includedItemsText = when {
// Some selected, but not all // 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 // All explicitly selected
includedCategories.size == allCategories.size -> stringResource(R.string.all) includedCategories.size == allCategories.size -> stringResource(R.string.all)
allExcluded -> stringResource(R.string.none) allExcluded -> stringResource(R.string.none)

View file

@ -120,7 +120,9 @@ object SettingsAppearanceScreen : SearchableSettings {
uiPreferences: UiPreferences, uiPreferences: UiPreferences,
): Preference.PreferenceGroup { ): Preference.PreferenceGroup {
val langs = remember { getLangs(context) } 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 now = remember { Date().time }
val dateFormat by uiPreferences.dateFormat().collectAsState() val dateFormat by uiPreferences.dateFormat().collectAsState()

View file

@ -115,7 +115,9 @@ class WorkerInfoScreen : Screen() {
private val workManager = context.workManager private val workManager = context.workManager
val finished = 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() .asFlow()
.map(::constructString) .map(::constructString)
.stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "") .stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "")

View file

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

View file

@ -77,7 +77,9 @@ fun ChapterNavigator(
) { ) {
Icon( Icon(
imageVector = Icons.Outlined.SkipPrevious, 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( Icon(
imageVector = Icons.Outlined.SkipNext, 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( AppBarActions(
listOfNotNull( listOfNotNull(
AppBar.Action( 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, icon = if (bookmarked) Icons.Outlined.Bookmark else Icons.Outlined.BookmarkBorder,
onClick = onToggleBookmarked, onClick = onToggleBookmarked,
), ),

View file

@ -173,7 +173,9 @@ fun WebViewScreenContent(
modifier = Modifier modifier = Modifier
.clip(MaterialTheme.shapes.small) .clip(MaterialTheme.shapes.small)
.clickable { .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() { fun register() {
if (!registered) { 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 registered = true
} }
} }

View file

@ -121,13 +121,22 @@ object Migrations {
} }
} }
prefs.edit { 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") 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") 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") remove("pref_filter_completed_key")
} }
} }
@ -242,7 +251,10 @@ object Migrations {
if (oldSecureScreen) { if (oldSecureScreen) {
securityPreferences.secureScreen().set(SecurityPreferences.SecureScreenMode.ALWAYS) 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) basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.LEGACY)
} }
} }
@ -259,7 +271,12 @@ object Migrations {
if (oldVersion < 81) { if (oldVersion < 81) {
// Handle renamed enum values // Handle renamed enum values
prefs.edit { 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" "LAST_CHECKED" -> "LAST_MANGA_UPDATE"
"UNREAD" -> "UNREAD_COUNT" "UNREAD" -> "UNREAD_COUNT"
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE" "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 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)) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
setSmallIcon(R.drawable.ic_tachi) setSmallIcon(R.drawable.ic_tachi)
setAutoCancel(false) setAutoCancel(false)
@ -28,7 +30,9 @@ class BackupNotifier(private val context: Context) {
setOnlyAlertOnce(true) 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)) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
setSmallIcon(R.drawable.ic_tachi) setSmallIcon(R.drawable.ic_tachi)
setAutoCancel(false) setAutoCancel(false)
@ -72,14 +76,25 @@ class BackupNotifier(private val context: Context) {
addAction( addAction(
R.drawable.ic_share_24dp, R.drawable.ic_share_24dp,
context.getString(R.string.action_share), 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) 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) { val builder = with(progressNotificationBuilder) {
setContentTitle(contentTitle) 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) context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
val timeString = context.getString( val timeString = context.getString(
@ -127,7 +150,14 @@ class BackupNotifier(private val context: Context) {
with(completeNotificationBuilder) { with(completeNotificationBuilder) {
setContentTitle(contentTitle) 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() clearActions()
if (errorCount > 0 && !path.isNullOrEmpty() && !file.isNullOrEmpty()) { if (errorCount > 0 && !path.isNullOrEmpty() && !file.isNullOrEmpty()) {

View file

@ -88,7 +88,13 @@ class BackupRestorer(
val logFile = writeErrorLog() val logFile = writeErrorLog()
if (sync) { 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 { } else {
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name) notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
} }
@ -183,7 +189,12 @@ class BackupRestorer(
) )
restoreProgress += 1 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) { private suspend fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>, sync: Boolean) {
@ -214,9 +225,19 @@ class BackupRestorer(
restoreProgress += 1 restoreProgress += 1
if (sync) { 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 { } 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) BackupCreateJob.setupTask(context)
restoreProgress += 1 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>) { private fun restoreSourcePreferences(preferences: List<BackupSourcePreferences>) {
@ -613,7 +639,12 @@ class BackupRestorer(
} }
restoreProgress += 1 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( private fun restorePreferences(

View file

@ -148,7 +148,10 @@ class DownloadCache(
if (sourceDir != null) { if (sourceDir != null) {
val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(mangaTitle)] val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(mangaTitle)]
if (mangaDir != null) { 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 return false

View file

@ -95,7 +95,10 @@ internal class DownloadNotifier(private val context: Context) {
} else { } else {
val title = download.manga.title.chop(15) val title = download.manga.title.chop(15)
val quotedTitle = Pattern.quote(title) 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)) setContentTitle("$title - $chapter".chop(30))
setContentText(downloadingProgressText) setContentText(downloadingProgressText)
} }

View file

@ -324,7 +324,11 @@ class Downloader(
val availSpace = DiskUtil.getAvailableStorageSpace(mangaDir) val availSpace = DiskUtil.getAvailableStorageSpace(mangaDir)
if (availSpace != -1L && availSpace < MIN_DISK_SPACE) { if (availSpace != -1L && availSpace < MIN_DISK_SPACE) {
download.status = Download.State.ERROR 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 return
} }
@ -432,13 +436,17 @@ class Downloader(
tmpFile?.delete() tmpFile?.delete()
// Try to find the image file // 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 { try {
// If the image is already downloaded, do nothing. Otherwise download from network // If the image is already downloaded, do nothing. Otherwise download from network
val file = when { val file = when {
imageFile != null -> imageFile 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) 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) { val errorMessage = when (e) {
is NoChaptersException -> context.getString(R.string.no_chapters_error) is NoChaptersException -> context.getString(R.string.no_chapters_error)
// failedUpdates will already have the source, don't need to copy it into the message // 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 else -> e.message
} }
failedUpdates.add(manga to errorMessage) failedUpdates.add(manga to errorMessage)
@ -500,7 +502,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
if (interval > 0) { if (interval > 0) {
val restrictions = preferences.autoUpdateDeviceRestrictions().get() val restrictions = preferences.autoUpdateDeviceRestrictions().get()
val constraints = Constraints( 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, requiresCharging = DEVICE_CHARGING in restrictions,
requiresBatteryNotLow = true, requiresBatteryNotLow = true,
) )
@ -517,7 +521,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
.setBackoffCriteria(BackoffPolicy.LINEAR, 10, TimeUnit.MINUTES) .setBackoffCriteria(BackoffPolicy.LINEAR, 10, TimeUnit.MINUTES)
.build() .build()
context.workManager.enqueueUniquePeriodicWork(WORK_NAME_AUTO, ExistingPeriodicWorkPolicy.UPDATE, request) context.workManager.enqueueUniquePeriodicWork(
WORK_NAME_AUTO,
ExistingPeriodicWorkPolicy.UPDATE,
request,
)
} else { } else {
context.workManager.cancelUniqueWork(WORK_NAME_AUTO) context.workManager.cancelUniqueWork(WORK_NAME_AUTO)
} }

View file

@ -82,7 +82,12 @@ class LibraryUpdateNotifier(private val context: Context) {
} else { } else {
val updatingText = manga.joinToString("\n") { it.title.chop(40) } val updatingText = manga.joinToString("\n") { it.title.chop(40) }
progressNotificationBuilder 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)) .setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
} }
@ -166,7 +171,13 @@ class LibraryUpdateNotifier(private val context: Context) {
if (updates.size == 1 && !preferences.hideNotificationContent().get()) { if (updates.size == 1 && !preferences.hideNotificationContent().get()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN)) setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else { } 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()) { if (!preferences.hideNotificationContent().get()) {
setStyle( setStyle(
@ -196,7 +207,10 @@ class LibraryUpdateNotifier(private val context: Context) {
launchUI { launchUI {
context.notify( context.notify(
updates.map { (manga, chapters) -> 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) // No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
0 -> { 0 -> {
// "1 new chapter" or "5 new chapters" // "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 // Only 1 chapter has a parsed chapter number
1 -> { 1 -> {
val remaining = chapters.size - displayableChapterNumbers.size val remaining = chapters.size - displayableChapterNumbers.size
if (remaining == 0) { if (remaining == 0) {
// "Chapter 2.5" // "Chapter 2.5"
context.resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first()) context.resources.getString(
R.string.notification_chapters_single,
displayableChapterNumbers.first(),
)
} else { } else {
// "Chapter 2.5 and 10 more" // "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) // 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" // "Chapters 1, 2.5, 3, 4, 5 and 10 more"
val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS
val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ") 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 { } else {
// "Chapters 1, 2.5, 3" // "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 flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = Constants.SHORTCUT_UPDATES 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 { companion object {

View file

@ -23,7 +23,12 @@ object NotificationHandler {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = Constants.SHORTCUT_DOWNLOADS 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/*") setDataAndType(uri, "image/*")
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION 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 { val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_RESUME_DOWNLOADS 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 { val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_PAUSE_DOWNLOADS 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 { val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CLEAR_DOWNLOADS 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 action = ACTION_DISMISS_NOTIFICATION
putExtra(EXTRA_NOTIFICATION_ID, notificationId) 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_FILE_LOCATION, path)
putExtra(EXTRA_NOTIFICATION_ID, notificationId) 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_FILE_LOCATION, path)
putExtra(EXTRA_NOTIFICATION_ID, notificationId) 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 { internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter: Chapter): PendingIntent {
val newIntent = ReaderActivity.newIntent(context, manga.id, chapter.id) 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(Constants.MANGA_EXTRA, manga.id)
.putExtra("notificationId", manga.id.hashCode()) .putExtra("notificationId", manga.id.hashCode())
.putExtra("groupId", groupId) .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_NOTIFICATION_ID, manga.id.hashCode())
putExtra(EXTRA_GROUP_ID, groupId) 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_NOTIFICATION_ID, manga.id.hashCode())
putExtra(EXTRA_GROUP_ID, groupId) 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 { val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CANCEL_LIBRARY_UPDATE 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 * @param context context of application
* @return [PendingIntent] * @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 { return Intent(context, NotificationReceiver::class.java).run {
action = ACTION_START_APP_UPDATE action = ACTION_START_APP_UPDATE
putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL, url) putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL, url)
title?.let { putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_TITLE, it) } 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 { val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD 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 action = Constants.SHORTCUT_EXTENSIONS
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 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_URI, uri)
putExtra(EXTRA_NOTIFICATION_ID, notificationId) 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 action = ACTION_CANCEL_RESTORE
putExtra(EXTRA_NOTIFICATION_ID, notificationId) 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) { when (it.code) {
200 -> return it.parseAs<AuthenticationDto>().token 200 -> return it.parseAs<AuthenticationDto>().token
401 -> { 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") throw IOException("Unauthorized / api key not valid")
} }
500 -> { 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") throw IOException("Error fetching JWT token")
} }
else -> {} else -> {}
@ -62,12 +66,12 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
// Not sure which one to catch // Not sure which one to catch
} catch (e: SocketTimeoutException) { } catch (e: SocketTimeoutException) {
logcat(LogPriority.WARN) { 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 return null
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR) { logcat(LogPriority.ERROR) {
"Unhandled exception fetching JWT token for url: '$apiUrl'" "Unhandled exception fetching JWT token for URL: '$apiUrl'"
} }
throw IOException(e) throw IOException(e)
} }
@ -129,7 +133,10 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
} }
} }
} catch (e: Exception) { } 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 throw e
} }
return 0F return 0F
@ -164,8 +171,14 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
} }
suspend fun updateProgress(track: Track): Track { 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}" val requestUrl = "${getApiFromUrl(
authClient.newCall(POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()))) 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() .awaitSuccess()
return getTrackSearch(track.tracking_url) return getTrackSearch(track.tracking_url)
} }

View file

@ -101,7 +101,10 @@ class MyAnimeListApi(
return withIOContext { return withIOContext {
val url = "$baseApiUrl/manga".toUri().buildUpon() val url = "$baseApiUrl/manga".toUri().buildUpon()
.appendPath(id.toString()) .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() .build()
with(json) { with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))

View file

@ -91,7 +91,9 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
null 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? = override fun migrateTrack(track: DomainTrack, manga: DomainManga, newSource: Source): DomainTrack? =
if (accept(newSource)) { if (accept(newSource)) {

View file

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

View file

@ -42,7 +42,12 @@ internal class AppUpdateNotifier(private val context: Context) {
val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run { val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP 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) { with(notificationBuilder) {
@ -143,7 +148,12 @@ internal class AppUpdateNotifier(private val context: Context) {
setContentTitle(context.getString(R.string.update_check_notification_update_available)) setContentTitle(context.getString(R.string.update_check_notification_update_available))
setContentText(context.getString(R.string.update_check_fdroid_migration_info)) setContentText(context.getString(R.string.update_check_fdroid_migration_info))
setSmallIcon(R.drawable.ic_tachi) 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) notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT)
} }

View file

@ -101,7 +101,12 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic
} }
init { 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" } logcat(LogPriority.WARN) { "Package name not found" }
return LoadResult.Error 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>() 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 { init {
scope.launch { scope.launch {

View file

@ -264,7 +264,9 @@ class BrowseSourceScreenModel(
// Choose a category // Choose a category
else -> { else -> {
val preselectedIds = getCategories.await(manga.id).map { it.id } 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) { sealed class Listing(open val query: String?, open val filters: FilterList) {
data object Popular : Listing(query = GetRemoteManga.QUERY_POPULAR, filters = FilterList()) data object Popular : Listing(query = GetRemoteManga.QUERY_POPULAR, filters = FilterList())
data object Latest : Listing(query = GetRemoteManga.QUERY_LATEST, 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 { companion object {
fun valueOf(query: String?): Listing { fun valueOf(query: String?): Listing {

View file

@ -543,7 +543,8 @@ class LibraryScreenModel(
} }
fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState<Int> { 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? { suspend fun getRandomLibraryItemForCurrentCategory(): LibraryItem? {

View file

@ -178,7 +178,9 @@ object LibraryTab : Tab {
scope.launchIO { scope.launchIO {
val chapter = screenModel.getNextUnreadChapter(it.manga) val chapter = screenModel.getNextUnreadChapter(it.manga)
if (chapter != null) { if (chapter != null) {
context.startActivity(ReaderActivity.newIntent(context, chapter.mangaId, chapter.id)) context.startActivity(
ReaderActivity.newIntent(context, chapter.mangaId, chapter.id),
)
} else { } else {
snackbarHostState.showSnackbar(context.getString(R.string.no_next_chapter)) 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 { private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean {
val notificationId = intent.getIntExtra("notificationId", -1) val notificationId = intent.getIntExtra("notificationId", -1)
if (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) { val tabToOpen = when (intent.action) {

View file

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

View file

@ -160,8 +160,18 @@ class ReaderViewModel @JvmOverloads constructor(
readerPreferences.skipFiltered().get() -> { readerPreferences.skipFiltered().get() -> {
(manga.unreadFilterRaw == Manga.CHAPTER_SHOW_READ && !it.read) || (manga.unreadFilterRaw == Manga.CHAPTER_SHOW_READ && !it.read) ||
(manga.unreadFilterRaw == Manga.CHAPTER_SHOW_UNREAD && 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_BOOKMARKED && !it.bookmark) ||
(manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_NOT_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) val filename = generateFilename(manga, page)
// Pictures directory. // 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. // Copy file in background.
viewModelScope.launchNonCancellable { viewModelScope.launchNonCancellable {

View file

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

View file

@ -5,14 +5,54 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
enum class OrientationType(val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) { enum class OrientationType(
DEFAULT(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000), val flag: Int,
FREE(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008), @StringRes val stringRes: Int,
PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010), @DrawableRes val iconRes: Int,
LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018), val flagValue: Int,
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), DEFAULT(
REVERSE_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030), 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 { companion object {

View file

@ -30,9 +30,15 @@ class ReaderPreferences(
fun keepScreenOn() = preferenceStore.getBoolean("pref_keep_screen_on_key", true) 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) 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.pager.VerticalPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer 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), 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), 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), 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) { LaunchedEffect(Unit) {
screenModel.events.collectLatest { event -> screenModel.events.collectLatest { event ->
when (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 -> { is Event.LibraryUpdateTriggered -> {
val msg = if (event.started) { val msg = if (event.started) {
R.string.updating_library R.string.updating_library

View file

@ -36,9 +36,17 @@ fun File.copyAndSetReadOnlyTo(target: File, overwrite: Boolean = false, bufferSi
if (target.exists()) { if (target.exists()) {
if (!overwrite) { 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()) { } 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. * @param permission the permission to check.
* @return true if it has permissions. * @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 val Context.powerManager: PowerManager
get() = getSystemService()!! get() = getSystemService()!!
@ -105,7 +107,10 @@ fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) {
private fun Context.defaultBrowserPackageName(): String? { private fun Context.defaultBrowserPackageName(): String? {
val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri()) val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri())
val resolveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { 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 { } else {
packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY) 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. * @param block the function that will execute inside the builder.
* @return a notification to be displayed or updated. * @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) val builder = NotificationCompat.Builder(this, channelId)
.setColor(getColor(R.color.accent_blue)) .setColor(getColor(R.color.accent_blue))
if (block != null) { if (block != null) {

View file

@ -91,6 +91,7 @@ fun View?.isVisibleOnScreen(): Boolean {
} }
val actualPosition = Rect() val actualPosition = Rect()
this.getGlobalVisibleRect(actualPosition) 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) 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 { private fun isRequestHeaderSafe(_name: String, _value: String): Boolean {
val name = _name.lowercase(Locale.ENGLISH) val name = _name.lowercase(Locale.ENGLISH)
val value = _value.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 if (name == "connection" && value == "upgrade") return false
return true 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 private val BitmapFactory.Options.splitData
get(): List<SplitData> { get(): List<SplitData> {
@ -356,10 +358,12 @@ object ImageUtil {
val botLeftIsDark = botLeftPixel.isDark() val botLeftIsDark = botLeftPixel.isDark()
val botRightIsDark = botRightPixel.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)) (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 isNotWhiteAndCloseTo = topAndBotPixels.mapIndexed { index, color ->
val other = topAndBotPixels[(index + 1) % topAndBotPixels.size] val other = topAndBotPixels[(index + 1) % topAndBotPixels.size]
!color.isWhite() && color.isCloseTo(other) !color.isWhite() && color.isCloseTo(other)
@ -504,10 +508,16 @@ object ImageUtil {
darkBG -> { darkBG -> {
return ColorDrawable(blackColor) return ColorDrawable(blackColor)
} }
topIsBlackStreak || (topCornersIsDark && topOffsetCornersIsDark && (topMidIsDark || overallBlackPixels > 9)) -> { topIsBlackStreak || (
topCornersIsDark && topOffsetCornersIsDark &&
(topMidIsDark || overallBlackPixels > 9)
) -> {
intArrayOf(blackColor, blackColor, whiteColor, whiteColor) intArrayOf(blackColor, blackColor, whiteColor, whiteColor)
} }
bottomIsBlackStreak || (botCornersIsDark && botOffsetCornersIsDark && (bottomCenterPixel.isDark() || overallBlackPixels > 9)) -> { bottomIsBlackStreak || (
botCornersIsDark && botOffsetCornersIsDark &&
(bottomCenterPixel.isDark() || overallBlackPixels > 9)
) -> {
intArrayOf(whiteColor, whiteColor, blackColor, blackColor) intArrayOf(whiteColor, whiteColor, blackColor, blackColor)
} }
else -> { else -> {

View file

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

View file

@ -16,5 +16,18 @@ data class ChapterUpdate(
) )
fun Chapter.toChapterUpdate(): 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 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 thumbHeightPx = with(LocalDensity.current) { ThumbLength.toPx() }
val trackHeightPx = heightPx - thumbHeightPx val trackHeightPx = heightPx - thumbHeightPx
@ -261,7 +264,10 @@ fun VerticalGridFastScroller(
} }
val thumbBottomPadding = with(LocalDensity.current) { bottomContentPadding.toPx() } 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 thumbHeightPx = with(LocalDensity.current) { ThumbLength.toPx() }
val trackHeightPx = heightPx - thumbHeightPx val trackHeightPx = heightPx - thumbHeightPx

View file

@ -121,7 +121,11 @@ private fun Modifier.drawScrollbar(
items items
.fastFirstOrNull { (it.key as? String)?.startsWith(STICKY_HEADER_KEY_PREFIX)?.not() ?: true }!! .fastFirstOrNull { (it.key as? String)?.startsWith(STICKY_HEADER_KEY_PREFIX)?.not() ?: true }!!
.run { .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) startPadding + ((estimatedItemSize * index - offset) / totalSize * viewportSize)
} }
} }

View file

@ -70,7 +70,10 @@ fun UpdatesWidget(
.padding(horizontal = 3.dp), .padding(horizontal = 3.dp),
contentAlignment = Alignment.Center, 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 action = Constants.SHORTCUT_MANGA
putExtra(Constants.MANGA_EXTRA, mangaId) putExtra(Constants.MANGA_EXTRA, mangaId)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 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 { override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
val baseDirsFiles = fileSystem.getFilesInBaseDirectories() 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 var mangaDirs = baseDirsFiles
// Filter out files that are hidden and is not a folder // Filter out files that are hidden and is not a folder
.filter { it.isDirectory && !it.name.startsWith('.') } .filter { it.isDirectory && !it.name.startsWith('.') }