mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Bring back simplified relative timestamp setting
Except now it's just an on/off toggle for relative up to a week.
This commit is contained in:
		@@ -28,6 +28,8 @@ class UiPreferences(
 | 
			
		||||
 | 
			
		||||
    fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
 | 
			
		||||
 | 
			
		||||
    fun relativeTime() = preferenceStore.getBoolean("relative_time_v2", true)
 | 
			
		||||
 | 
			
		||||
    fun dateFormat() = preferenceStore.getString("app_date_format", "")
 | 
			
		||||
 | 
			
		||||
    fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@ package eu.kanade.presentation.components
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
 | 
			
		||||
import tachiyomi.presentation.core.components.ListGroupHeader
 | 
			
		||||
import java.text.DateFormat
 | 
			
		||||
import java.util.Date
 | 
			
		||||
@@ -11,12 +13,18 @@ import java.util.Date
 | 
			
		||||
fun RelativeDateHeader(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    date: Date,
 | 
			
		||||
    relativeTime: Boolean,
 | 
			
		||||
    dateFormat: DateFormat,
 | 
			
		||||
) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    ListGroupHeader(
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
        text = remember {
 | 
			
		||||
            dateFormat.format(date)
 | 
			
		||||
            date.toRelativeString(
 | 
			
		||||
                context,
 | 
			
		||||
                relativeTime,
 | 
			
		||||
                dateFormat,
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -98,7 +98,8 @@ private fun HistoryScreenContent(
 | 
			
		||||
    onClickDelete: (HistoryWithRelations) -> Unit,
 | 
			
		||||
    preferences: UiPreferences = Injekt.get(),
 | 
			
		||||
) {
 | 
			
		||||
    val dateFormat: DateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
 | 
			
		||||
    val relativeTime = remember { preferences.relativeTime().get() }
 | 
			
		||||
    val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
 | 
			
		||||
 | 
			
		||||
    FastScrollLazyColumn(
 | 
			
		||||
        contentPadding = contentPadding,
 | 
			
		||||
@@ -118,6 +119,7 @@ private fun HistoryScreenContent(
 | 
			
		||||
                    RelativeDateHeader(
 | 
			
		||||
                        modifier = Modifier.animateItemPlacement(),
 | 
			
		||||
                        date = item.date,
 | 
			
		||||
                        relativeTime = relativeTime,
 | 
			
		||||
                        dateFormat = dateFormat,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -63,6 +63,7 @@ import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.source.getNameForMangaInfo
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.ChapterItem
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenModel
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
 | 
			
		||||
import tachiyomi.domain.chapter.model.Chapter
 | 
			
		||||
import tachiyomi.domain.chapter.service.missingChaptersCount
 | 
			
		||||
@@ -84,6 +85,7 @@ fun MangaScreen(
 | 
			
		||||
    state: MangaScreenModel.State.Success,
 | 
			
		||||
    snackbarHostState: SnackbarHostState,
 | 
			
		||||
    fetchInterval: Int?,
 | 
			
		||||
    dateRelativeTime: Boolean,
 | 
			
		||||
    dateFormat: DateFormat,
 | 
			
		||||
    isTabletUi: Boolean,
 | 
			
		||||
    chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
 | 
			
		||||
@@ -139,6 +141,7 @@ fun MangaScreen(
 | 
			
		||||
        MangaScreenSmallImpl(
 | 
			
		||||
            state = state,
 | 
			
		||||
            snackbarHostState = snackbarHostState,
 | 
			
		||||
            dateRelativeTime = dateRelativeTime,
 | 
			
		||||
            dateFormat = dateFormat,
 | 
			
		||||
            fetchInterval = fetchInterval,
 | 
			
		||||
            chapterSwipeStartAction = chapterSwipeStartAction,
 | 
			
		||||
@@ -175,6 +178,7 @@ fun MangaScreen(
 | 
			
		||||
        MangaScreenLargeImpl(
 | 
			
		||||
            state = state,
 | 
			
		||||
            snackbarHostState = snackbarHostState,
 | 
			
		||||
            dateRelativeTime = dateRelativeTime,
 | 
			
		||||
            chapterSwipeStartAction = chapterSwipeStartAction,
 | 
			
		||||
            chapterSwipeEndAction = chapterSwipeEndAction,
 | 
			
		||||
            dateFormat = dateFormat,
 | 
			
		||||
@@ -214,6 +218,7 @@ fun MangaScreen(
 | 
			
		||||
private fun MangaScreenSmallImpl(
 | 
			
		||||
    state: MangaScreenModel.State.Success,
 | 
			
		||||
    snackbarHostState: SnackbarHostState,
 | 
			
		||||
    dateRelativeTime: Boolean,
 | 
			
		||||
    dateFormat: DateFormat,
 | 
			
		||||
    fetchInterval: Int?,
 | 
			
		||||
    chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
 | 
			
		||||
@@ -282,11 +287,9 @@ private fun MangaScreenSmallImpl(
 | 
			
		||||
            }
 | 
			
		||||
            val animatedTitleAlpha by animateFloatAsState(
 | 
			
		||||
                if (firstVisibleItemIndex > 0) 1f else 0f,
 | 
			
		||||
                label = "titleAlpha",
 | 
			
		||||
            )
 | 
			
		||||
            val animatedBgAlpha by animateFloatAsState(
 | 
			
		||||
                if (firstVisibleItemIndex > 0 || firstVisibleItemScrollOffset > 0) 1f else 0f,
 | 
			
		||||
                label = "bgAlpha",
 | 
			
		||||
            )
 | 
			
		||||
            MangaToolbar(
 | 
			
		||||
                title = state.manga.title,
 | 
			
		||||
@@ -427,6 +430,7 @@ private fun MangaScreenSmallImpl(
 | 
			
		||||
                    sharedChapterItems(
 | 
			
		||||
                        manga = state.manga,
 | 
			
		||||
                        chapters = chapters,
 | 
			
		||||
                        dateRelativeTime = dateRelativeTime,
 | 
			
		||||
                        dateFormat = dateFormat,
 | 
			
		||||
                        chapterSwipeStartAction = chapterSwipeStartAction,
 | 
			
		||||
                        chapterSwipeEndAction = chapterSwipeEndAction,
 | 
			
		||||
@@ -445,6 +449,7 @@ private fun MangaScreenSmallImpl(
 | 
			
		||||
fun MangaScreenLargeImpl(
 | 
			
		||||
    state: MangaScreenModel.State.Success,
 | 
			
		||||
    snackbarHostState: SnackbarHostState,
 | 
			
		||||
    dateRelativeTime: Boolean,
 | 
			
		||||
    dateFormat: DateFormat,
 | 
			
		||||
    fetchInterval: Int?,
 | 
			
		||||
    chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
 | 
			
		||||
@@ -650,6 +655,7 @@ fun MangaScreenLargeImpl(
 | 
			
		||||
                            sharedChapterItems(
 | 
			
		||||
                                manga = state.manga,
 | 
			
		||||
                                chapters = chapters,
 | 
			
		||||
                                dateRelativeTime = dateRelativeTime,
 | 
			
		||||
                                dateFormat = dateFormat,
 | 
			
		||||
                                chapterSwipeStartAction = chapterSwipeStartAction,
 | 
			
		||||
                                chapterSwipeEndAction = chapterSwipeEndAction,
 | 
			
		||||
@@ -711,6 +717,7 @@ private fun SharedMangaBottomActionMenu(
 | 
			
		||||
private fun LazyListScope.sharedChapterItems(
 | 
			
		||||
    manga: Manga,
 | 
			
		||||
    chapters: List<ChapterItem>,
 | 
			
		||||
    dateRelativeTime: Boolean,
 | 
			
		||||
    dateFormat: DateFormat,
 | 
			
		||||
    chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
 | 
			
		||||
    chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
 | 
			
		||||
@@ -739,7 +746,11 @@ private fun LazyListScope.sharedChapterItems(
 | 
			
		||||
            date = chapterItem.chapter.dateUpload
 | 
			
		||||
                .takeIf { it > 0L }
 | 
			
		||||
                ?.let {
 | 
			
		||||
                    dateFormat.format(Date(it))
 | 
			
		||||
                    Date(it).toRelativeString(
 | 
			
		||||
                        context,
 | 
			
		||||
                        dateRelativeTime,
 | 
			
		||||
                        dateFormat,
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
            readProgress = chapterItem.chapter.lastPageRead
 | 
			
		||||
                .takeIf { !chapterItem.chapter.read && it > 0L }
 | 
			
		||||
 
 | 
			
		||||
@@ -123,6 +123,11 @@ object SettingsAppearanceScreen : SearchableSettings {
 | 
			
		||||
        var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") }
 | 
			
		||||
        val now = remember { Date().time }
 | 
			
		||||
 | 
			
		||||
        val dateFormat by uiPreferences.dateFormat().collectAsState()
 | 
			
		||||
        val formattedNow = remember(dateFormat) {
 | 
			
		||||
            UiPreferences.dateFormat(dateFormat).format(now)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        LaunchedEffect(currentLanguage) {
 | 
			
		||||
            val locale = if (currentLanguage.isEmpty()) {
 | 
			
		||||
                LocaleListCompat.getEmptyLocaleList()
 | 
			
		||||
@@ -162,6 +167,15 @@ object SettingsAppearanceScreen : SearchableSettings {
 | 
			
		||||
                            "${it.ifEmpty { stringResource(R.string.label_default) }} ($formattedDate)"
 | 
			
		||||
                        },
 | 
			
		||||
                ),
 | 
			
		||||
                Preference.PreferenceItem.SwitchPreference(
 | 
			
		||||
                    pref = uiPreferences.relativeTime(),
 | 
			
		||||
                    title = stringResource(R.string.pref_relative_format),
 | 
			
		||||
                    subtitle = stringResource(
 | 
			
		||||
                        R.string.pref_relative_format_summary,
 | 
			
		||||
                        stringResource(R.string.relative_time_today),
 | 
			
		||||
                        formattedNow,
 | 
			
		||||
                    ),
 | 
			
		||||
                ),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@ fun UpdateScreen(
 | 
			
		||||
    state: UpdatesScreenModel.State,
 | 
			
		||||
    snackbarHostState: SnackbarHostState,
 | 
			
		||||
    lastUpdated: Long,
 | 
			
		||||
    relativeTime: Boolean,
 | 
			
		||||
    onClickCover: (UpdatesItem) -> Unit,
 | 
			
		||||
    onSelectAll: (Boolean) -> Unit,
 | 
			
		||||
    onInvertSelection: () -> Unit,
 | 
			
		||||
@@ -113,7 +114,7 @@ fun UpdateScreen(
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        updatesUiItems(
 | 
			
		||||
                            uiModels = state.getUiModel(context),
 | 
			
		||||
                            uiModels = state.getUiModel(context, relativeTime),
 | 
			
		||||
                            selectionMode = state.selectionMode,
 | 
			
		||||
                            onUpdateSelected = onUpdateSelected,
 | 
			
		||||
                            onClickCover = onClickCover,
 | 
			
		||||
 
 | 
			
		||||
@@ -375,6 +375,12 @@ object Migrations {
 | 
			
		||||
                    pref.getAndSet { it - "battery_not_low" }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (oldVersion < 106) {
 | 
			
		||||
                val pref = preferenceStore.getInt("relative_time", 7)
 | 
			
		||||
                if (pref.get() == 0) {
 | 
			
		||||
                    uiPreferences.relativeTime().set(false)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,7 @@ class MangaScreen(
 | 
			
		||||
        MangaScreen(
 | 
			
		||||
            state = successState,
 | 
			
		||||
            snackbarHostState = screenModel.snackbarHostState,
 | 
			
		||||
            dateRelativeTime = screenModel.relativeTime,
 | 
			
		||||
            dateFormat = screenModel.dateFormat,
 | 
			
		||||
            fetchInterval = successState.manga.fetchInterval,
 | 
			
		||||
            isTabletUi = isTabletUi(),
 | 
			
		||||
 
 | 
			
		||||
@@ -125,6 +125,7 @@ class MangaScreenModel(
 | 
			
		||||
    val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get()
 | 
			
		||||
    val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get()
 | 
			
		||||
 | 
			
		||||
    val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
 | 
			
		||||
    val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
 | 
			
		||||
    private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.toDateKey
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
 | 
			
		||||
import kotlinx.coroutines.channels.Channel
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import kotlinx.coroutines.flow.catch
 | 
			
		||||
@@ -58,12 +59,14 @@ class UpdatesScreenModel(
 | 
			
		||||
    private val getChapter: GetChapter = Injekt.get(),
 | 
			
		||||
    private val libraryPreferences: LibraryPreferences = Injekt.get(),
 | 
			
		||||
    val snackbarHostState: SnackbarHostState = SnackbarHostState(),
 | 
			
		||||
    uiPreferences: UiPreferences = Injekt.get(),
 | 
			
		||||
) : StateScreenModel<UpdatesScreenModel.State>(State()) {
 | 
			
		||||
 | 
			
		||||
    private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
 | 
			
		||||
    val events: Flow<Event> = _events.receiveAsFlow()
 | 
			
		||||
 | 
			
		||||
    val lastUpdated by libraryPreferences.lastUpdatedTimestamp().asState(coroutineScope)
 | 
			
		||||
    val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    // First and last selected index in list
 | 
			
		||||
    private val selectedPositions: Array<Int> = arrayOf(-1, -1)
 | 
			
		||||
@@ -373,7 +376,7 @@ class UpdatesScreenModel(
 | 
			
		||||
        val selected = items.filter { it.selected }
 | 
			
		||||
        val selectionMode = selected.isNotEmpty()
 | 
			
		||||
 | 
			
		||||
        fun getUiModel(context: Context): List<UpdatesUiModel> {
 | 
			
		||||
        fun getUiModel(context: Context, relativeTime: Boolean): List<UpdatesUiModel> {
 | 
			
		||||
            val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
 | 
			
		||||
 | 
			
		||||
            return items
 | 
			
		||||
@@ -383,7 +386,11 @@ class UpdatesScreenModel(
 | 
			
		||||
                    val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
 | 
			
		||||
                    when {
 | 
			
		||||
                        beforeDate.time != afterDate.time && afterDate.time != 0L -> {
 | 
			
		||||
                            val text = dateFormat.format(afterDate)
 | 
			
		||||
                            val text = afterDate.toRelativeString(
 | 
			
		||||
                                context = context,
 | 
			
		||||
                                relative = relativeTime,
 | 
			
		||||
                                dateFormat = dateFormat,
 | 
			
		||||
                            )
 | 
			
		||||
                            UpdatesUiModel.Header(text)
 | 
			
		||||
                        }
 | 
			
		||||
                        // Return null to avoid adding a separator between two items.
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ object UpdatesTab : Tab {
 | 
			
		||||
            state = state,
 | 
			
		||||
            snackbarHostState = screenModel.snackbarHostState,
 | 
			
		||||
            lastUpdated = screenModel.lastUpdated,
 | 
			
		||||
            relativeTime = screenModel.relativeTime,
 | 
			
		||||
            onClickCover = { item -> navigator.push(MangaScreen(item.update.mangaId)) },
 | 
			
		||||
            onSelectAll = screenModel::toggleAllSelection,
 | 
			
		||||
            onInvertSelection = screenModel::invertSelection,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package eu.kanade.tachiyomi.util.lang
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import java.text.DateFormat
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.time.LocalDateTime
 | 
			
		||||
@@ -42,3 +44,41 @@ fun Long.toDateKey(): Date {
 | 
			
		||||
    cal[Calendar.MILLISECOND] = 0
 | 
			
		||||
    return cal.time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private const val MILLISECONDS_IN_DAY = 86_400_000L
 | 
			
		||||
 | 
			
		||||
fun Date.toRelativeString(
 | 
			
		||||
    context: Context,
 | 
			
		||||
    relative: Boolean = true,
 | 
			
		||||
    dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT),
 | 
			
		||||
): String {
 | 
			
		||||
    if (!relative) {
 | 
			
		||||
        return dateFormat.format(this)
 | 
			
		||||
    }
 | 
			
		||||
    val now = Date()
 | 
			
		||||
    val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY)
 | 
			
		||||
    val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt()
 | 
			
		||||
    return when {
 | 
			
		||||
        difference < 0 -> dateFormat.format(this)
 | 
			
		||||
        difference < MILLISECONDS_IN_DAY -> context.getString(R.string.relative_time_today)
 | 
			
		||||
        difference < MILLISECONDS_IN_DAY.times(7) -> context.resources.getQuantityString(
 | 
			
		||||
            R.plurals.relative_time,
 | 
			
		||||
            days,
 | 
			
		||||
            days,
 | 
			
		||||
        )
 | 
			
		||||
        else -> dateFormat.format(this)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private val Date.timeWithOffset: Long
 | 
			
		||||
    get() {
 | 
			
		||||
        return Calendar.getInstance().run {
 | 
			
		||||
            time = this@timeWithOffset
 | 
			
		||||
            val dstOffset = get(Calendar.DST_OFFSET)
 | 
			
		||||
            this@timeWithOffset.time + timeZone.rawOffset + dstOffset
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
fun Long.floorNearest(to: Long): Long {
 | 
			
		||||
    return this.floorDiv(to) * to
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user