Bring back simplified relative timestamp setting

Except now it's just an on/off toggle for relative up to a week.

(cherry picked from commit 56d2464870cbd59f1e67dab7cf2a359bddfa0f41)

# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt
#	app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt
This commit is contained in:
arkon 2023-09-24 17:01:26 -04:00 committed by Jobobby04
parent 35eb6c7ebe
commit b5b947400b
16 changed files with 118 additions and 10 deletions

View File

@ -26,7 +26,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.kanade.tachiyomi.sy" applicationId = "eu.kanade.tachiyomi.sy"
versionCode = 56 versionCode = 57
versionName = "1.9.3" versionName = "1.9.3"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")

View File

@ -28,6 +28,8 @@ class UiPreferences(
fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false) 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 dateFormat() = preferenceStore.getString("app_date_format", "")
fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC) fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)

View File

@ -3,6 +3,8 @@ package eu.kanade.presentation.components
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier 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 tachiyomi.presentation.core.components.ListGroupHeader
import java.text.DateFormat import java.text.DateFormat
import java.util.Date import java.util.Date
@ -11,12 +13,18 @@ import java.util.Date
fun RelativeDateHeader( fun RelativeDateHeader(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
date: Date, date: Date,
relativeTime: Boolean,
dateFormat: DateFormat, dateFormat: DateFormat,
) { ) {
val context = LocalContext.current
ListGroupHeader( ListGroupHeader(
modifier = modifier, modifier = modifier,
text = remember { text = remember {
dateFormat.format(date) date.toRelativeString(
context,
relativeTime,
dateFormat,
)
}, },
) )
} }

View File

@ -98,7 +98,8 @@ private fun HistoryScreenContent(
onClickDelete: (HistoryWithRelations) -> Unit, onClickDelete: (HistoryWithRelations) -> Unit,
preferences: UiPreferences = Injekt.get(), 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( FastScrollLazyColumn(
contentPadding = contentPadding, contentPadding = contentPadding,
@ -118,6 +119,7 @@ private fun HistoryScreenContent(
RelativeDateHeader( RelativeDateHeader(
modifier = Modifier.animateItemPlacement(), modifier = Modifier.animateItemPlacement(),
date = item.date, date = item.date,
relativeTime = relativeTime,
dateFormat = dateFormat, dateFormat = dateFormat,
) )
} }

View File

@ -76,6 +76,7 @@ import eu.kanade.tachiyomi.source.online.english.Tsumino
import eu.kanade.tachiyomi.ui.manga.ChapterItem import eu.kanade.tachiyomi.ui.manga.ChapterItem
import eu.kanade.tachiyomi.ui.manga.MangaScreenModel import eu.kanade.tachiyomi.ui.manga.MangaScreenModel
import eu.kanade.tachiyomi.ui.manga.PagePreviewState import eu.kanade.tachiyomi.ui.manga.PagePreviewState
import eu.kanade.tachiyomi.util.lang.toRelativeString
import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.copyToClipboard
import exh.metadata.MetadataUtil import exh.metadata.MetadataUtil
import exh.source.MERGED_SOURCE_ID import exh.source.MERGED_SOURCE_ID
@ -108,6 +109,7 @@ fun MangaScreen(
state: MangaScreenModel.State.Success, state: MangaScreenModel.State.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
fetchInterval: Int?, fetchInterval: Int?,
dateRelativeTime: Boolean,
dateFormat: DateFormat, dateFormat: DateFormat,
isTabletUi: Boolean, isTabletUi: Boolean,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
@ -173,6 +175,7 @@ fun MangaScreen(
MangaScreenSmallImpl( MangaScreenSmallImpl(
state = state, state = state,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
dateRelativeTime = dateRelativeTime,
dateFormat = dateFormat, dateFormat = dateFormat,
fetchInterval = fetchInterval, fetchInterval = fetchInterval,
chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeStartAction = chapterSwipeStartAction,
@ -219,6 +222,7 @@ fun MangaScreen(
MangaScreenLargeImpl( MangaScreenLargeImpl(
state = state, state = state,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
dateRelativeTime = dateRelativeTime,
chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction, chapterSwipeEndAction = chapterSwipeEndAction,
dateFormat = dateFormat, dateFormat = dateFormat,
@ -268,6 +272,7 @@ fun MangaScreen(
private fun MangaScreenSmallImpl( private fun MangaScreenSmallImpl(
state: MangaScreenModel.State.Success, state: MangaScreenModel.State.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
dateRelativeTime: Boolean,
dateFormat: DateFormat, dateFormat: DateFormat,
fetchInterval: Int?, fetchInterval: Int?,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
@ -349,11 +354,9 @@ private fun MangaScreenSmallImpl(
} }
val animatedTitleAlpha by animateFloatAsState( val animatedTitleAlpha by animateFloatAsState(
if (firstVisibleItemIndex > 0) 1f else 0f, if (firstVisibleItemIndex > 0) 1f else 0f,
label = "titleAlpha",
) )
val animatedBgAlpha by animateFloatAsState( val animatedBgAlpha by animateFloatAsState(
if (firstVisibleItemIndex > 0 || firstVisibleItemScrollOffset > 0) 1f else 0f, if (firstVisibleItemIndex > 0 || firstVisibleItemScrollOffset > 0) 1f else 0f,
label = "bgAlpha",
) )
MangaToolbar( MangaToolbar(
title = state.manga.title, title = state.manga.title,
@ -554,6 +557,7 @@ private fun MangaScreenSmallImpl(
sharedChapterItems( sharedChapterItems(
manga = state.manga, manga = state.manga,
chapters = chapters, chapters = chapters,
dateRelativeTime = dateRelativeTime,
dateFormat = dateFormat, dateFormat = dateFormat,
chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction, chapterSwipeEndAction = chapterSwipeEndAction,
@ -575,6 +579,7 @@ private fun MangaScreenSmallImpl(
fun MangaScreenLargeImpl( fun MangaScreenLargeImpl(
state: MangaScreenModel.State.Success, state: MangaScreenModel.State.Success,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
dateRelativeTime: Boolean,
dateFormat: DateFormat, dateFormat: DateFormat,
fetchInterval: Int?, fetchInterval: Int?,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
@ -834,6 +839,7 @@ fun MangaScreenLargeImpl(
sharedChapterItems( sharedChapterItems(
manga = state.manga, manga = state.manga,
chapters = chapters, chapters = chapters,
dateRelativeTime = dateRelativeTime,
dateFormat = dateFormat, dateFormat = dateFormat,
chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction, chapterSwipeEndAction = chapterSwipeEndAction,
@ -898,6 +904,7 @@ private fun SharedMangaBottomActionMenu(
private fun LazyListScope.sharedChapterItems( private fun LazyListScope.sharedChapterItems(
manga: Manga, manga: Manga,
chapters: List<ChapterItem>, chapters: List<ChapterItem>,
dateRelativeTime: Boolean,
dateFormat: DateFormat, dateFormat: DateFormat,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
@ -933,7 +940,11 @@ private fun LazyListScope.sharedChapterItems(
if (manga.isEhBasedManga()) { if (manga.isEhBasedManga()) {
MetadataUtil.EX_DATE_FORMAT.format(Date(it)) MetadataUtil.EX_DATE_FORMAT.format(Date(it))
} else { } else {
dateFormat.format(Date(it)) Date(it).toRelativeString(
context,
dateRelativeTime,
dateFormat,
)
} }
// SY <-- // SY <--
}, },

View File

@ -127,6 +127,11 @@ object SettingsAppearanceScreen : SearchableSettings {
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 formattedNow = remember(dateFormat) {
UiPreferences.dateFormat(dateFormat).format(now)
}
LaunchedEffect(currentLanguage) { LaunchedEffect(currentLanguage) {
val locale = if (currentLanguage.isEmpty()) { val locale = if (currentLanguage.isEmpty()) {
LocaleListCompat.getEmptyLocaleList() LocaleListCompat.getEmptyLocaleList()
@ -166,6 +171,15 @@ object SettingsAppearanceScreen : SearchableSettings {
"${it.ifEmpty { stringResource(R.string.label_default) }} ($formattedDate)" "${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,
),
),
), ),
) )
} }

View File

@ -43,6 +43,7 @@ fun UpdateScreen(
state: UpdatesScreenModel.State, state: UpdatesScreenModel.State,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
lastUpdated: Long, lastUpdated: Long,
relativeTime: Boolean,
// SY --> // SY -->
preserveReadingPosition: Boolean, preserveReadingPosition: Boolean,
// SY <-- // SY <--
@ -116,7 +117,7 @@ fun UpdateScreen(
} }
updatesUiItems( updatesUiItems(
uiModels = state.getUiModel(context), uiModels = state.getUiModel(context, relativeTime),
selectionMode = state.selectionMode, selectionMode = state.selectionMode,
// SY --> // SY -->
preserveReadingPosition = preserveReadingPosition, preserveReadingPosition = preserveReadingPosition,

View File

@ -378,6 +378,12 @@ object Migrations {
pref.getAndSet { it - "battery_not_low" } 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 return true
} }

View File

@ -138,6 +138,7 @@ class MangaScreen(
MangaScreen( MangaScreen(
state = successState, state = successState,
snackbarHostState = screenModel.snackbarHostState, snackbarHostState = screenModel.snackbarHostState,
dateRelativeTime = screenModel.relativeTime,
dateFormat = screenModel.dateFormat, dateFormat = screenModel.dateFormat,
fetchInterval = successState.manga.fetchInterval, fetchInterval = successState.manga.fetchInterval,
isTabletUi = isTabletUi(), isTabletUi = isTabletUi(),

View File

@ -189,6 +189,7 @@ class MangaScreenModel(
val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get() val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get()
val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get() val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get()
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get())) val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope) private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope)

View File

@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.lang.toDateKey import eu.kanade.tachiyomi.util.lang.toDateKey
import eu.kanade.tachiyomi.util.lang.toRelativeString
import exh.source.EH_SOURCE_ID import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID import exh.source.EXH_SOURCE_ID
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
@ -61,6 +62,7 @@ class UpdatesScreenModel(
private val getChapter: GetChapter = Injekt.get(), private val getChapter: GetChapter = Injekt.get(),
private val libraryPreferences: LibraryPreferences = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(),
val snackbarHostState: SnackbarHostState = SnackbarHostState(), val snackbarHostState: SnackbarHostState = SnackbarHostState(),
uiPreferences: UiPreferences = Injekt.get(),
// SY --> // SY -->
readerPreferences: ReaderPreferences = Injekt.get(), readerPreferences: ReaderPreferences = Injekt.get(),
// SY <-- // SY <--
@ -70,6 +72,7 @@ class UpdatesScreenModel(
val events: Flow<Event> = _events.receiveAsFlow() val events: Flow<Event> = _events.receiveAsFlow()
val lastUpdated by libraryPreferences.lastUpdatedTimestamp().asState(coroutineScope) val lastUpdated by libraryPreferences.lastUpdatedTimestamp().asState(coroutineScope)
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
// SY --> // SY -->
val preserveReadingPosition by readerPreferences.preserveReadingPosition().asState(coroutineScope) val preserveReadingPosition by readerPreferences.preserveReadingPosition().asState(coroutineScope)
@ -385,7 +388,7 @@ class UpdatesScreenModel(
val selected = items.filter { it.selected } val selected = items.filter { it.selected }
val selectionMode = selected.isNotEmpty() 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())) val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()))
return items return items
@ -395,7 +398,11 @@ class UpdatesScreenModel(
val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0) val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
when { when {
beforeDate.time != afterDate.time && afterDate.time != 0L -> { 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) UpdatesUiModel.Header(text)
} }
// Return null to avoid adding a separator between two items. // Return null to avoid adding a separator between two items.

View File

@ -73,6 +73,7 @@ object UpdatesTab : Tab {
state = state, state = state,
snackbarHostState = screenModel.snackbarHostState, snackbarHostState = screenModel.snackbarHostState,
lastUpdated = screenModel.lastUpdated, lastUpdated = screenModel.lastUpdated,
relativeTime = screenModel.relativeTime,
// SY --> // SY -->
preserveReadingPosition = screenModel.preserveReadingPosition, preserveReadingPosition = screenModel.preserveReadingPosition,
// SY <-- // SY <--

View File

@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.util.lang package eu.kanade.tachiyomi.util.lang
import android.content.Context
import eu.kanade.tachiyomi.R
import java.text.DateFormat import java.text.DateFormat
import java.time.Instant import java.time.Instant
import java.time.LocalDateTime import java.time.LocalDateTime
@ -42,3 +44,41 @@ fun Long.toDateKey(): Date {
cal[Calendar.MILLISECOND] = 0 cal[Calendar.MILLISECOND] = 0
return cal.time 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
}

View File

@ -553,6 +553,12 @@ object EXHMigrations {
pref.getAndSet { it - "battery_not_low" } pref.getAndSet { it - "battery_not_low" }
} }
} }
if (oldVersion under 57) {
val pref = preferenceStore.getInt("relative_time", 7)
if (pref.get() == 0) {
uiPreferences.relativeTime().set(false)
}
}
// if (oldVersion under 1) { } (1 is current release version) // if (oldVersion under 1) { } (1 is current release version)
// do stuff here when releasing changed crap // do stuff here when releasing changed crap

View File

@ -201,6 +201,9 @@
<string name="theme_yotsuba">Yotsuba</string> <string name="theme_yotsuba">Yotsuba</string>
<string name="theme_tidalwave">Tidal Wave</string> <string name="theme_tidalwave">Tidal Wave</string>
<string name="pref_dark_theme_pure_black">Pure black dark mode</string> <string name="pref_dark_theme_pure_black">Pure black dark mode</string>
<string name="pref_relative_format">Relative timestamps</string>
<!-- "Today" instead of "2023-12-31" -->
<string name="pref_relative_format_summary">\"%1$s\" instead of \"%2$s\"</string>
<string name="pref_date_format">Date format</string> <string name="pref_date_format">Date format</string>
<string name="pref_manage_notifications">Manage notifications</string> <string name="pref_manage_notifications">Manage notifications</string>
@ -223,6 +226,12 @@
<string name="pref_show_nsfw_source">Show in sources and extensions lists</string> <string name="pref_show_nsfw_source">Show in sources and extensions lists</string>
<string name="parental_controls_info">This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app.</string> <string name="parental_controls_info">This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app.</string>
<string name="relative_time_today">Today</string>
<plurals name="relative_time">
<item quantity="one">Yesterday</item>
<item quantity="other">%1$d days ago</item>
</plurals>
<!-- Library section --> <!-- Library section -->
<string name="pref_category_display">Display</string> <string name="pref_category_display">Display</string>
<string name="pref_library_columns">Grid size</string> <string name="pref_library_columns">Grid size</string>

View File

@ -70,7 +70,6 @@ fun AdaptiveSheet(
val alpha by animateFloatAsState( val alpha by animateFloatAsState(
targetValue = targetAlpha, targetValue = targetAlpha,
animationSpec = sheetAnimationSpec, animationSpec = sheetAnimationSpec,
label = "alpha",
) )
val internalOnDismissRequest: () -> Unit = { val internalOnDismissRequest: () -> Unit = {
scope.launch { scope.launch {