Minor cleanup
This commit is contained in:
parent
c90f344910
commit
f48f212001
@ -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 {
|
||||||
Text(
|
Row(
|
||||||
modifier = Modifier.weight(1f),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
text = stringResource(R.string.pref_update_release_leading_days, "x"),
|
) {
|
||||||
textAlign = TextAlign.Center,
|
Text(
|
||||||
maxLines = 1,
|
modifier = Modifier.weight(1f),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
text = pluralStringResource(R.plurals.pref_update_release_leading_days, leadValue, leadValue),
|
||||||
)
|
textAlign = TextAlign.Center,
|
||||||
Text(
|
maxLines = 1,
|
||||||
modifier = Modifier.weight(1f),
|
style = MaterialTheme.typography.labelMedium,
|
||||||
text = stringResource(R.string.pref_update_release_following_days, "x"),
|
)
|
||||||
textAlign = TextAlign.Center,
|
Text(
|
||||||
maxLines = 1,
|
modifier = Modifier.weight(1f),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
text = pluralStringResource(R.plurals.pref_update_release_following_days, followValue, followValue),
|
||||||
)
|
textAlign = TextAlign.Center,
|
||||||
|
maxLines = 1,
|
||||||
|
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,
|
||||||
|
@ -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
|
||||||
.atStartOfDay()
|
.filter { it.dateUpload > 0L }
|
||||||
}
|
.map {
|
||||||
val uploadDateDistinct = uploadDates.distinctBy { it }
|
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zonedDateTime.zone)
|
||||||
val fetchDates = sortChapters.map {
|
.toLocalDate()
|
||||||
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zonedDateTime.zone).toLocalDate()
|
.atStartOfDay()
|
||||||
.atStartOfDay()
|
}
|
||||||
}
|
.distinct()
|
||||||
val fetchDatesDistinct = fetchDates.distinctBy { it }
|
val fetchDates = sortedChapters
|
||||||
|
.map {
|
||||||
|
ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zonedDateTime.zone)
|
||||||
|
.toLocalDate()
|
||||||
|
.atStartOfDay()
|
||||||
|
}
|
||||||
|
.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
|
||||||
) {
|
) {
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user