Minor cleanup

This commit is contained in:
arkon 2023-05-27 23:27:02 -04:00
parent c90f344910
commit f48f212001
3 changed files with 105 additions and 87 deletions

View File

@ -1,7 +1,9 @@
package eu.kanade.presentation.more.settings.screen package eu.kanade.presentation.more.settings.screen
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
@ -12,6 +14,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -52,7 +55,7 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_HAS_U
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD
import tachiyomi.presentation.core.components.WheelPickerDefaults import tachiyomi.domain.manga.interactor.MAX_GRACE_PERIOD
import tachiyomi.presentation.core.components.WheelTextPicker import tachiyomi.presentation.core.components.WheelTextPicker
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -144,6 +147,7 @@ object SettingsLibraryScreen : SearchableSettings {
val libraryUpdateCategoriesExcludePref = libraryPreferences.libraryUpdateCategoriesExclude() val libraryUpdateCategoriesExcludePref = libraryPreferences.libraryUpdateCategoriesExclude()
val libraryUpdateInterval by libraryUpdateIntervalPref.collectAsState() val libraryUpdateInterval by libraryUpdateIntervalPref.collectAsState()
val libraryUpdateMangaRestriction by libraryUpdateMangaRestrictionPref.collectAsState()
val included by libraryUpdateCategoriesPref.collectAsState() val included by libraryUpdateCategoriesPref.collectAsState()
val excluded by libraryUpdateCategoriesExcludePref.collectAsState() val excluded by libraryUpdateCategoriesExcludePref.collectAsState()
@ -182,7 +186,7 @@ object SettingsLibraryScreen : SearchableSettings {
} }
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_library_update), title = stringResource(R.string.pref_category_library_update),
preferenceItems = listOf( preferenceItems = listOfNotNull(
Preference.PreferenceItem.ListPreference( Preference.PreferenceItem.ListPreference(
pref = libraryUpdateIntervalPref, pref = libraryUpdateIntervalPref,
title = stringResource(R.string.pref_library_update_interval), title = stringResource(R.string.pref_library_update_interval),
@ -216,34 +220,6 @@ object SettingsLibraryScreen : SearchableSettings {
true true
}, },
), ),
Preference.PreferenceItem.MultiSelectListPreference(
pref = libraryUpdateMangaRestrictionPref,
title = stringResource(R.string.pref_library_update_manga_restriction),
entries = mapOf(
MANGA_HAS_UNREAD to stringResource(R.string.pref_update_only_completely_read),
MANGA_NON_READ to stringResource(R.string.pref_update_only_started),
MANGA_NON_COMPLETED to stringResource(R.string.pref_update_only_non_completed),
MANGA_OUTSIDE_RELEASE_PERIOD to stringResource(R.string.pref_update_only_in_release_period),
),
),
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_library_update_manga_restriction),
subtitle = setOf(
stringResource(R.string.pref_update_release_leading_days, leadRange),
stringResource(R.string.pref_update_release_following_days, followRange),
)
.joinToString(";"),
onClick = { showFetchRangesDialog = true },
),
Preference.PreferenceItem.InfoPreference(
title = stringResource(R.string.pref_update_release_grace_period_info1),
),
Preference.PreferenceItem.InfoPreference(
title = stringResource(R.string.pref_update_release_grace_period_info2),
),
Preference.PreferenceItem.InfoPreference(
title = stringResource(R.string.pref_update_release_grace_period_info3),
),
Preference.PreferenceItem.TextPreference( Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.categories), title = stringResource(R.string.categories),
subtitle = getCategoriesLabel( subtitle = getCategoriesLabel(
@ -264,6 +240,27 @@ object SettingsLibraryScreen : SearchableSettings {
title = stringResource(R.string.pref_library_update_refresh_trackers), title = stringResource(R.string.pref_library_update_refresh_trackers),
subtitle = stringResource(R.string.pref_library_update_refresh_trackers_summary), subtitle = stringResource(R.string.pref_library_update_refresh_trackers_summary),
), ),
Preference.PreferenceItem.MultiSelectListPreference(
pref = libraryUpdateMangaRestrictionPref,
title = stringResource(R.string.pref_library_update_manga_restriction),
entries = mapOf(
MANGA_HAS_UNREAD to stringResource(R.string.pref_update_only_completely_read),
MANGA_NON_READ to stringResource(R.string.pref_update_only_started),
MANGA_NON_COMPLETED to stringResource(R.string.pref_update_only_non_completed),
MANGA_OUTSIDE_RELEASE_PERIOD to stringResource(R.string.pref_update_only_in_release_period),
),
),
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_update_release_grace_period),
subtitle = listOf(
pluralStringResource(R.plurals.pref_update_release_leading_days, leadRange, leadRange),
pluralStringResource(R.plurals.pref_update_release_following_days, followRange, followRange),
).joinToString(),
onClick = { showFetchRangesDialog = true },
).takeIf { MANGA_OUTSIDE_RELEASE_PERIOD in libraryUpdateMangaRestriction },
Preference.PreferenceItem.InfoPreference(
title = stringResource(R.string.pref_update_release_grace_period_info),
).takeIf { MANGA_OUTSIDE_RELEASE_PERIOD in libraryUpdateMangaRestriction },
), ),
) )
} }
@ -306,45 +303,48 @@ object SettingsLibraryScreen : SearchableSettings {
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,
onValueChanged: (portrait: Int, landscape: Int) -> Unit, onValueChanged: (portrait: Int, landscape: Int) -> Unit,
) { ) {
val context = LocalContext.current var leadValue by rememberSaveable { mutableIntStateOf(initialLead) }
var leadValue by rememberSaveable { mutableStateOf(initialLead) } var followValue by rememberSaveable { mutableIntStateOf(initialFollow) }
var followValue by rememberSaveable { mutableStateOf(initialFollow) }
AlertDialog( AlertDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
title = { Text(text = stringResource(R.string.pref_update_release_grace_period)) }, title = { Text(text = stringResource(R.string.pref_update_release_grace_period)) },
text = { text = {
Row { Column {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
Text( Text(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
text = stringResource(R.string.pref_update_release_leading_days, "x"), text = pluralStringResource(R.plurals.pref_update_release_leading_days, leadValue, leadValue),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
maxLines = 1, maxLines = 1,
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
) )
Text( Text(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
text = stringResource(R.string.pref_update_release_following_days, "x"), text = pluralStringResource(R.plurals.pref_update_release_following_days, followValue, followValue),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
maxLines = 1, maxLines = 1,
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
) )
} }
}
BoxWithConstraints( BoxWithConstraints(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
WheelPickerDefaults.Background(size = DpSize(maxWidth, maxHeight))
val size = DpSize(width = maxWidth / 2, height = 128.dp) val size = DpSize(width = maxWidth / 2, height = 128.dp)
val items = (0..28).map { val items = (0..MAX_GRACE_PERIOD).map {
if (it == 0) { if (it == 0) {
stringResource(R.string.label_default) stringResource(R.string.label_default)
} else { } else {
it.toString() it.toString()
} }
} }
Row { Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
WheelTextPicker( WheelTextPicker(
size = size, size = size,
items = items, items = items,

View File

@ -11,6 +11,8 @@ import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
const val MAX_GRACE_PERIOD = 28
fun updateIntervalMeta( fun updateIntervalMeta(
manga: Manga, manga: Manga,
chapters: List<Chapter>, chapters: List<Chapter>,
@ -29,41 +31,54 @@ fun updateIntervalMeta(
null null
} else { MangaUpdate(id = manga.id, nextUpdate = nextUpdate, calculateInterval = interval) } } else { MangaUpdate(id = manga.id, nextUpdate = nextUpdate, calculateInterval = interval) }
} }
fun calculateInterval(chapters: List<Chapter>, zonedDateTime: ZonedDateTime): Int { fun calculateInterval(chapters: List<Chapter>, zonedDateTime: ZonedDateTime): Int {
val sortChapters = val sortedChapters = chapters
chapters.sortedWith(compareBy<Chapter> { it.dateUpload }.thenBy { it.dateFetch }) .sortedWith(compareByDescending<Chapter> { it.dateUpload }.thenByDescending { it.dateFetch })
.reversed().take(50) .take(50)
val uploadDates = sortChapters.filter { it.dateUpload != 0L }.map {
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zonedDateTime.zone).toLocalDate() val uploadDates = sortedChapters
.filter { it.dateUpload > 0L }
.map {
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zonedDateTime.zone)
.toLocalDate()
.atStartOfDay() .atStartOfDay()
} }
val uploadDateDistinct = uploadDates.distinctBy { it } .distinct()
val fetchDates = sortChapters.map { val fetchDates = sortedChapters
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zonedDateTime.zone).toLocalDate() .map {
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zonedDateTime.zone)
.toLocalDate()
.atStartOfDay() .atStartOfDay()
} }
val fetchDatesDistinct = fetchDates.distinctBy { it } .distinct()
val newInterval = when { val newInterval = when {
// enough upload date from source // Enough upload date from source
(uploadDateDistinct.size >= 3) -> { uploadDates.size >= 3 -> {
val uploadDelta = uploadDateDistinct.last().until(uploadDateDistinct.first(), ChronoUnit.DAYS) val uploadDelta = uploadDates.last().until(uploadDates.first(), ChronoUnit.DAYS)
val uploadPeriod = uploadDates.indexOf(uploadDateDistinct.last()) val uploadPeriod = uploadDates.indexOf(uploadDates.last())
(uploadDelta).floorDiv(uploadPeriod).toInt() uploadDelta.floorDiv(uploadPeriod).toInt()
} }
// enough fetch date from client // Enough fetch date from client
(fetchDatesDistinct.size >= 3) -> { fetchDates.size >= 3 -> {
val fetchDelta = fetchDatesDistinct.last().until(fetchDatesDistinct.first(), ChronoUnit.DAYS) val fetchDelta = fetchDates.last().until(fetchDates.first(), ChronoUnit.DAYS)
val uploadPeriod = fetchDates.indexOf(fetchDatesDistinct.last()) val uploadPeriod = fetchDates.indexOf(fetchDates.last())
(fetchDelta).floorDiv(uploadPeriod).toInt() fetchDelta.floorDiv(uploadPeriod).toInt()
} }
// default 7 days // Default to 7 days
else -> 7 else -> 7
} }
// min 1, max 28 days // Min 1, max 28 days
return newInterval.coerceIn(1, 28) return newInterval.coerceIn(1, MAX_GRACE_PERIOD)
} }
private fun calculateNextUpdate(manga: Manga, interval: Int, zonedDateTime: ZonedDateTime, currentFetchRange: Pair<Long, Long>): Long { private fun calculateNextUpdate(
manga: Manga,
interval: Int,
zonedDateTime: ZonedDateTime,
currentFetchRange: Pair<Long, Long>,
): Long {
return if (manga.nextUpdate !in currentFetchRange.first.rangeTo(currentFetchRange.second + 1) || return if (manga.nextUpdate !in currentFetchRange.first.rangeTo(currentFetchRange.second + 1) ||
manga.calculateInterval == 0 manga.calculateInterval == 0
) { ) {

View File

@ -262,15 +262,18 @@
<string name="pref_update_only_non_completed">With \"Completed\" status</string> <string name="pref_update_only_non_completed">With \"Completed\" status</string>
<string name="pref_update_only_started">That haven\'t been started</string> <string name="pref_update_only_started">That haven\'t been started</string>
<string name="pref_library_update_show_tab_badge">Show unread count on Updates icon</string> <string name="pref_library_update_show_tab_badge">Show unread count on Updates icon</string>
<string name="pref_update_only_in_release_period">Outside release period</string> <string name="pref_update_only_in_release_period">Outside expected release period</string>
<string name="pref_update_release_grace_period">Grace release period:</string>
<string name="pref_update_release_leading_days">Check %s day(s) before</string>
<string name="pref_update_release_following_days">Check %s day(s) after</string>
<string name="pref_update_release_grace_period_info1">It is recommended to keep small grace period to minimize stress on servers.</string>
<string name="pref_update_release_grace_period_info2">The more checks comic missed, the longer extend check interval (max at 28 day).</string>
<string name="pref_update_release_grace_period_info3">It is recommend to remove or migrate source if comic in Dropped status filter.</string>
<string name="pref_update_release_grace_period">Expected release grace period</string>
<plurals name="pref_update_release_leading_days">
<item quantity="one">%d day before</item>
<item quantity="other">%d days before</item>
</plurals>
<plurals name="pref_update_release_following_days">
<item quantity="one">%d day after</item>
<item quantity="other">%d days after</item>
</plurals>
<string name="pref_update_release_grace_period_info">A low grace period is recommended to minimize stress on sources. The more checks for an entry that are missed, the longer the interval in between checks will be with a maximum of 28 days.</string>
<string name="pref_library_update_refresh_metadata">Automatically refresh metadata</string> <string name="pref_library_update_refresh_metadata">Automatically refresh metadata</string>
<string name="pref_library_update_refresh_metadata_summary">Check for new cover and details when updating library</string> <string name="pref_library_update_refresh_metadata_summary">Check for new cover and details when updating library</string>