Explorar o código

Change fetch interval action to show days until next expected update

arkon hai 1 ano
pai
achega
32bed9b041

+ 8 - 7
app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt

@@ -78,12 +78,13 @@ import tachiyomi.presentation.core.i18n.stringResource
 import tachiyomi.presentation.core.util.isScrolledToEnd
 import tachiyomi.presentation.core.util.isScrollingUp
 import tachiyomi.source.local.isLocal
+import java.time.Instant
 
 @Composable
 fun MangaScreen(
     state: MangaScreenModel.State.Success,
     snackbarHostState: SnackbarHostState,
-    fetchInterval: Int?,
+    nextUpdate: Instant?,
     isTabletUi: Boolean,
     chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
     chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
@@ -138,7 +139,7 @@ fun MangaScreen(
         MangaScreenSmallImpl(
             state = state,
             snackbarHostState = snackbarHostState,
-            fetchInterval = fetchInterval,
+            nextUpdate = nextUpdate,
             chapterSwipeStartAction = chapterSwipeStartAction,
             chapterSwipeEndAction = chapterSwipeEndAction,
             onBackClicked = onBackClicked,
@@ -175,7 +176,7 @@ fun MangaScreen(
             snackbarHostState = snackbarHostState,
             chapterSwipeStartAction = chapterSwipeStartAction,
             chapterSwipeEndAction = chapterSwipeEndAction,
-            fetchInterval = fetchInterval,
+            nextUpdate = nextUpdate,
             onBackClicked = onBackClicked,
             onChapterClicked = onChapterClicked,
             onDownloadChapter = onDownloadChapter,
@@ -211,7 +212,7 @@ fun MangaScreen(
 private fun MangaScreenSmallImpl(
     state: MangaScreenModel.State.Success,
     snackbarHostState: SnackbarHostState,
-    fetchInterval: Int?,
+    nextUpdate: Instant?,
     chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
     chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
     onBackClicked: () -> Unit,
@@ -402,7 +403,7 @@ private fun MangaScreenSmallImpl(
                         MangaActionRow(
                             favorite = state.manga.favorite,
                             trackingCount = state.trackingCount,
-                            fetchInterval = fetchInterval,
+                            nextUpdate = nextUpdate,
                             isUserIntervalMode = state.manga.fetchInterval < 0,
                             onAddToLibraryClicked = onAddToLibraryClicked,
                             onWebViewClicked = onWebViewClicked,
@@ -462,7 +463,7 @@ private fun MangaScreenSmallImpl(
 fun MangaScreenLargeImpl(
     state: MangaScreenModel.State.Success,
     snackbarHostState: SnackbarHostState,
-    fetchInterval: Int?,
+    nextUpdate: Instant?,
     chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
     chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
     onBackClicked: () -> Unit,
@@ -641,7 +642,7 @@ fun MangaScreenLargeImpl(
                         MangaActionRow(
                             favorite = state.manga.favorite,
                             trackingCount = state.trackingCount,
-                            fetchInterval = fetchInterval,
+                            nextUpdate = nextUpdate,
                             isUserIntervalMode = state.manga.fetchInterval < 0,
                             onAddToLibraryClicked = onAddToLibraryClicked,
                             onWebViewClicked = onWebViewClicked,

+ 47 - 29
app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt

@@ -2,8 +2,11 @@ package eu.kanade.presentation.manga.components
 
 import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
 import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
@@ -20,6 +23,7 @@ import kotlinx.collections.immutable.toImmutableList
 import tachiyomi.domain.manga.interactor.FetchInterval
 import tachiyomi.i18n.MR
 import tachiyomi.presentation.core.components.WheelTextPicker
+import tachiyomi.presentation.core.components.material.padding
 import tachiyomi.presentation.core.i18n.pluralStringResource
 import tachiyomi.presentation.core.i18n.stringResource
 import java.time.Instant
@@ -59,57 +63,71 @@ fun DeleteChaptersDialog(
 @Composable
 fun SetIntervalDialog(
     interval: Int,
-    nextUpdate: Long,
+    nextUpdate: Instant?,
     onDismissRequest: () -> Unit,
-    onValueChanged: (Int) -> Unit,
+    onValueChanged: ((Int) -> Unit)? = null,
 ) {
     var selectedInterval by rememberSaveable { mutableIntStateOf(if (interval < 0) -interval else 0) }
 
     val nextUpdateDays = remember(nextUpdate) {
-        val now = Instant.now()
-        val nextUpdateInstant = Instant.ofEpochMilli(nextUpdate)
-
-        now.until(nextUpdateInstant, ChronoUnit.DAYS)
+        return@remember if (nextUpdate != null) {
+            val now = Instant.now()
+            now.until(nextUpdate, ChronoUnit.DAYS).toInt()
+        } else {
+            null
+        }
     }
 
+    // TODO: selecting "1" then doesn't allow for future changes unless defaulting first?
     AlertDialog(
         onDismissRequest = onDismissRequest,
-        title = { Text(stringResource(MR.strings.manga_modify_calculated_interval_title)) },
+        title = { Text(stringResource(MR.strings.pref_library_update_smart_update)) },
         text = {
             Column {
-                if (nextUpdateDays >= 0) {
+                if (nextUpdateDays != null && nextUpdateDays >= 0) {
                     Text(
                         stringResource(
                             MR.strings.manga_interval_expected_update,
                             pluralStringResource(
                                 MR.plurals.day,
-                                count = nextUpdateDays.toInt(),
+                                count = nextUpdateDays,
                                 nextUpdateDays,
                             ),
+                            pluralStringResource(
+                                MR.plurals.day,
+                                count = interval,
+                                interval,
+                            ),
                         ),
                     )
+
+                    Spacer(Modifier.height(MaterialTheme.padding.small))
                 }
 
-                BoxWithConstraints(
-                    modifier = Modifier.fillMaxWidth(),
-                    contentAlignment = Alignment.Center,
-                ) {
-                    val size = DpSize(width = maxWidth / 2, height = 128.dp)
-                    val items = (0..FetchInterval.MAX_INTERVAL)
-                        .map {
-                            if (it == 0) {
-                                stringResource(MR.strings.label_default)
-                            } else {
-                                it.toString()
+                if (onValueChanged != null) {
+                    Text(stringResource(MR.strings.manga_interval_custom_amount))
+
+                    BoxWithConstraints(
+                        modifier = Modifier.fillMaxWidth(),
+                        contentAlignment = Alignment.Center,
+                    ) {
+                        val size = DpSize(width = maxWidth / 2, height = 128.dp)
+                        val items = (0..FetchInterval.MAX_INTERVAL)
+                            .map {
+                                if (it == 0) {
+                                    stringResource(MR.strings.label_default)
+                                } else {
+                                    it.toString()
+                                }
                             }
-                        }
-                        .toImmutableList()
-                    WheelTextPicker(
-                        items = items,
-                        size = size,
-                        startIndex = selectedInterval,
-                        onSelectionChanged = { selectedInterval = it },
-                    )
+                            .toImmutableList()
+                        WheelTextPicker(
+                            items = items,
+                            size = size,
+                            startIndex = selectedInterval,
+                            onSelectionChanged = { selectedInterval = it },
+                        )
+                    }
                 }
             }
         },
@@ -120,7 +138,7 @@ fun SetIntervalDialog(
         },
         confirmButton = {
             TextButton(onClick = {
-                onValueChanged(selectedInterval)
+                onValueChanged?.invoke(selectedInterval)
                 onDismissRequest()
             }) {
                 Text(text = stringResource(MR.strings.action_ok))

+ 26 - 13
app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt

@@ -86,7 +86,8 @@ import tachiyomi.presentation.core.i18n.pluralStringResource
 import tachiyomi.presentation.core.i18n.stringResource
 import tachiyomi.presentation.core.util.clickableNoIndication
 import tachiyomi.presentation.core.util.secondaryItemAlpha
-import kotlin.math.absoluteValue
+import java.time.Instant
+import java.time.temporal.ChronoUnit
 import kotlin.math.roundToInt
 
 private val whitespaceLineRegex = Regex("[\\r\\n]{2,}", setOf(RegexOption.MULTILINE))
@@ -165,7 +166,7 @@ fun MangaInfoBox(
 fun MangaActionRow(
     favorite: Boolean,
     trackingCount: Int,
-    fetchInterval: Int?,
+    nextUpdate: Instant?,
     isUserIntervalMode: Boolean,
     onAddToLibraryClicked: () -> Unit,
     onWebViewClicked: (() -> Unit)?,
@@ -177,6 +178,16 @@ fun MangaActionRow(
 ) {
     val defaultActionButtonColor = MaterialTheme.colorScheme.onSurface.copy(alpha = .38f)
 
+    // TODO: show something better when using custom interval
+    val nextUpdateDays = remember(nextUpdate) {
+        return@remember if (nextUpdate != null) {
+            val now = Instant.now()
+            now.until(nextUpdate, ChronoUnit.DAYS).toInt()
+        } else {
+            null
+        }
+    }
+
     Row(modifier = modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp)) {
         MangaActionButton(
             title = if (favorite) {
@@ -189,18 +200,20 @@ fun MangaActionRow(
             onClick = onAddToLibraryClicked,
             onLongClick = onEditCategory,
         )
-        if (onEditIntervalClicked != null && fetchInterval != null) {
-            MangaActionButton(
-                title = pluralStringResource(
+        MangaActionButton(
+            title = if (nextUpdateDays != null) {
+                pluralStringResource(
                     MR.plurals.day,
-                    count = fetchInterval.absoluteValue,
-                    fetchInterval.absoluteValue,
-                ),
-                icon = Icons.Default.HourglassEmpty,
-                color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
-                onClick = onEditIntervalClicked,
-            )
-        }
+                    count = nextUpdateDays,
+                    nextUpdateDays,
+                )
+            } else {
+                stringResource(MR.strings.not_applicable)
+            },
+            icon = Icons.Default.HourglassEmpty,
+            color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
+            onClick = { onEditIntervalClicked?.invoke() },
+        )
         MangaActionButton(
             title = if (trackingCount == 0) {
                 stringResource(MR.strings.manga_tracking_tab)

+ 1 - 1
app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt

@@ -198,7 +198,7 @@ object SettingsLibraryScreen : SearchableSettings {
                 ),
                 Preference.PreferenceItem.MultiSelectListPreference(
                     pref = libraryPreferences.autoUpdateMangaRestrictions(),
-                    title = stringResource(MR.strings.pref_library_update_manga_restriction),
+                    title = stringResource(MR.strings.pref_library_update_smart_update),
                     entries = persistentMapOf(
                         MANGA_HAS_UNREAD to stringResource(MR.strings.pref_update_only_completely_read),
                         MANGA_NON_READ to stringResource(MR.strings.pref_update_only_started),

+ 5 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt

@@ -104,7 +104,7 @@ class MangaScreen(
         MangaScreen(
             state = successState,
             snackbarHostState = screenModel.snackbarHostState,
-            fetchInterval = successState.manga.fetchInterval,
+            nextUpdate = successState.manga.expectedNextUpdate,
             isTabletUi = isTabletUi(),
             chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
             chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
@@ -146,7 +146,7 @@ class MangaScreen(
             onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() },
             onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.manga.favorite },
             onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf {
-                screenModel.isUpdateIntervalEnabled && successState.manga.favorite
+                successState.manga.favorite
             },
             onMigrateClicked = {
                 navigator.push(MigrateSearchScreen(successState.manga.id))
@@ -243,9 +243,10 @@ class MangaScreen(
             is MangaScreenModel.Dialog.SetFetchInterval -> {
                 SetIntervalDialog(
                     interval = dialog.manga.fetchInterval,
-                    nextUpdate = dialog.manga.nextUpdate,
+                    nextUpdate = dialog.manga.expectedNextUpdate,
                     onDismissRequest = onDismissRequest,
-                    onValueChanged = { screenModel.setFetchInterval(dialog.manga, it) },
+                    onValueChanged = { interval: Int -> screenModel.setFetchInterval(dialog.manga, interval) }
+                        .takeIf { screenModel.isUpdateIntervalEnabled },
                 )
             }
         }

+ 7 - 0
domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt

@@ -1,8 +1,10 @@
 package tachiyomi.domain.manga.model
 
+import eu.kanade.tachiyomi.source.model.SManga
 import eu.kanade.tachiyomi.source.model.UpdateStrategy
 import tachiyomi.core.preference.TriState
 import java.io.Serializable
+import java.time.Instant
 
 data class Manga(
     val id: Long,
@@ -29,6 +31,11 @@ data class Manga(
     val favoriteModifiedAt: Long?,
 ) : Serializable {
 
+    val expectedNextUpdate: Instant?
+        get() = nextUpdate
+            .takeIf { status != SManga.COMPLETED.toLong() }
+            ?.let { Instant.ofEpochMilli(it) }
+
     val sorting: Long
         get() = chapterFlags and CHAPTER_SORTING_MASK
 

+ 8 - 7
i18n/src/commonMain/resources/MR/base/strings.xml

@@ -275,12 +275,12 @@
     <string name="charging">When charging</string>
     <string name="restrictions">Restrictions: %s</string>
 
-    <string name="pref_library_update_manga_restriction">Skip updating entries</string>
-    <string name="pref_update_only_completely_read">With unread chapter(s)</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_library_update_smart_update">Smart update</string>
+    <string name="pref_update_only_completely_read">Skip entries with unread chapter(s)</string>
+    <string name="pref_update_only_non_completed">Skip entries with \"Completed\" status</string>
+    <string name="pref_update_only_started">Skip unstarted entries</string>
+    <string name="pref_update_only_in_release_period">Predict next release time</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 expected release period</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>
@@ -668,9 +668,10 @@
     <string name="display_mode_chapter">Chapter %1$s</string>
     <string name="manga_display_interval_title">Estimate every</string>
     <string name="manga_display_modified_interval_title">Set to update every</string>
+    <string name="manga_interval_header">Next update</string>
     <!-- "... around 2 days" -->
-    <string name="manga_interval_expected_update">Next update expected in around %s</string>
-    <string name="manga_modify_calculated_interval_title">Customize interval</string>
+    <string name="manga_interval_expected_update">Next update expected in around %1$s, checking around every %2$s</string>
+    <string name="manga_interval_custom_amount">Custom update frequency:</string>
     <string name="chapter_downloading_progress">Downloading (%1$d/%2$d)</string>
     <string name="chapter_error">Error</string>
     <string name="chapter_paused">Paused</string>