diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/i18n/Copywriter.kt b/composeApp/src/commonMain/kotlin/com/clipevery/i18n/Copywriter.kt index 47dc052c8..9d2ae5a84 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/i18n/Copywriter.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/i18n/Copywriter.kt @@ -1,8 +1,13 @@ package com.clipevery.i18n +import java.time.LocalDateTime + interface Copywriter { + fun getText(id: String): String + fun getDate(date: LocalDateTime): String + fun getAbridge(): String } @@ -31,6 +36,10 @@ class PreviewGlobalCopywriter: GlobalCopywriter { return id } + override fun getDate(date: LocalDateTime): String { + return date.toString() + } + override fun getAbridge(): String { return "en" } diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewItemView.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewItemView.kt index 57fc4a791..abc0c9b13 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewItemView.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewItemView.kt @@ -1,26 +1,42 @@ package com.clipevery.ui.clip import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.clipevery.LocalKoinApplication import com.clipevery.dao.clip.ClipAppearItem import com.clipevery.dao.clip.ClipContent import com.clipevery.dao.clip.ClipData import com.clipevery.dao.clip.ClipType +import com.clipevery.i18n.Copywriter +import com.clipevery.i18n.GlobalCopywriter +import com.clipevery.utils.DateUtils +import io.realm.kotlin.types.RealmInstant import kotlin.reflect.KClass import kotlin.reflect.cast @@ -43,6 +59,8 @@ fun ClipData.getClipItem(): ClipAppearItem? { fun ClipPreviewItemView(clipData: ClipData, clipContent: @Composable ClipAppearItem.() -> Unit) { clipData.getClipItem()?.let { + val current = LocalKoinApplication.current + val copywriter = current.koin.get() if (it.getClipType() == ClipType.TEXT) { @@ -85,8 +103,26 @@ fun ClipPreviewItemView(clipData: ClipData, clipContent: @Composable ClipAppearI modifier = Modifier.fillMaxWidth() .background(color = MaterialTheme.colors.surface) .height(30.dp) + .padding(end = 16.dp) + , + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically ) { - + Row(modifier = Modifier.wrapContentSize() + .clip(RoundedCornerShape(3.dp)) + .background(color = MaterialTheme.colors.background) + .padding(horizontal = 8.dp, vertical = 4.dp) + ) { + Text( + text = getDateText(clipData.createTime, copywriter), + fontFamily = FontFamily.SansSerif, + style = TextStyle( + fontWeight = FontWeight.Light, + color = MaterialTheme.colors.onBackground, + fontSize = 10.sp + ) + ) + } } } } @@ -94,6 +130,15 @@ fun ClipPreviewItemView(clipData: ClipData, clipContent: @Composable ClipAppearI } } +fun getDateText(createTime: RealmInstant, copywriter: Copywriter): String { + val date = DateUtils.convertRealmInstantToLocalDateTime(createTime) + DateUtils.getDateText(date)?.let { + return copywriter.getText(it) + } ?: run { + return copywriter.getDate(date) + } +} + @Composable fun ClipSpecificPreviewItemView(clipData: ClipData) { if (clipData.preCreate) { diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/utils/DateUtils.kt b/composeApp/src/commonMain/kotlin/com/clipevery/utils/DateUtils.kt index a75e267b3..3ccbd8d74 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/utils/DateUtils.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/utils/DateUtils.kt @@ -1,6 +1,10 @@ package com.clipevery.utils import io.realm.kotlin.types.RealmInstant +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import java.time.temporal.ChronoUnit import java.util.Calendar object DateUtils { @@ -13,4 +17,38 @@ object DateUtils { // The nanosecondAdjustment parameter is 0 as we're not adjusting nanoseconds here return RealmInstant.from(epochSeconds, 0) } + + fun getDateText(date: LocalDateTime): String? { + val now = LocalDateTime.now() + + if (date.toLocalDate().isEqual(now.toLocalDate())) { + val hour = ChronoUnit.HOURS.between(date, now) + val minutes = ChronoUnit.MINUTES.between(date, now) + val seconds = ChronoUnit.SECONDS.between(date, now) + + if (hour < 1 && minutes < 1 && seconds < 60) { + return "Just now" + } + return "Today" + } + + val yesterday = now.minusDays(1) + if (date.toLocalDate().isEqual(yesterday.toLocalDate())) { + return "Yesterday" + } + + return null + } + + fun convertRealmInstantToLocalDateTime(realmInstant: RealmInstant): LocalDateTime { + // 1. 从 RealmInstant 获取秒和纳秒 + val epochSeconds = realmInstant.epochSeconds + val nanosecondsOfSecond = realmInstant.nanosecondsOfSecond + + // 2. 使用 Instant.ofEpochSecond 创建 Instant + val instant = Instant.ofEpochSecond(epochSeconds, nanosecondsOfSecond.toLong()) + + // 3. 使用系统默认的时区将 Instant 转换为 LocalDateTime + return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()) + } } \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/i18n/I18n.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/i18n/I18n.kt index df8cbedf2..e90879288 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/i18n/I18n.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/i18n/I18n.kt @@ -8,6 +8,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging import java.io.FileNotFoundException import java.io.InputStreamReader import java.nio.charset.StandardCharsets +import java.time.LocalDateTime import java.util.Properties import java.util.concurrent.ConcurrentHashMap @@ -49,6 +50,10 @@ open class GlobalCopywriterImpl(private val configManager: ConfigManager): Globa return copywriter.getText(id) } + override fun getDate(date: LocalDateTime): String { + return copywriter.getDate(date) + } + override fun getAbridge(): String { return copywriter.getAbridge() } @@ -95,6 +100,10 @@ class CopywriterImpl(private val language: String) : Copywriter { } } + override fun getDate(date: LocalDateTime): String { + return date.toString() + } + override fun getAbridge(): String { return language } diff --git a/composeApp/src/desktopMain/resources/i18n/en.properties b/composeApp/src/desktopMain/resources/i18n/en.properties index d94525725..9514cced3 100644 --- a/composeApp/src/desktopMain/resources/i18n/en.properties +++ b/composeApp/src/desktopMain/resources/i18n/en.properties @@ -39,4 +39,7 @@ Base_Info=Base Info Allow_Send_to_this_device=Allow Send to this device Allow_Receive_from_this_device=Allow Receive from this device Remove_Device=Remove Device -Text=Text \ No newline at end of file +Text=Text +Just_now=Just now +Today=Today +Yesterday=Yesterday \ No newline at end of file diff --git a/composeApp/src/desktopMain/resources/i18n/es.properties b/composeApp/src/desktopMain/resources/i18n/es.properties index 6162163dc..981f5fe01 100644 --- a/composeApp/src/desktopMain/resources/i18n/es.properties +++ b/composeApp/src/desktopMain/resources/i18n/es.properties @@ -39,4 +39,7 @@ Base_Info=Información básica Allow_Send_to_this_device=Permitir enviar a este dispositivo Allow_Receive_from_this_device=Permitir recibir de este dispositivo Remove_Device=Eliminar dispositivo -Text=Texto \ No newline at end of file +Text=Texto +Just_now=Justo ahora +Today=Hoy +Yesterday=Ayer \ No newline at end of file diff --git a/composeApp/src/desktopMain/resources/i18n/jp.properties b/composeApp/src/desktopMain/resources/i18n/jp.properties index f3470f0b3..55755b48b 100644 --- a/composeApp/src/desktopMain/resources/i18n/jp.properties +++ b/composeApp/src/desktopMain/resources/i18n/jp.properties @@ -39,4 +39,7 @@ Base_Info=基本情報 Allow_Send_to_this_device=このデバイスに送信を許可する Allow_Receive_from_this_device=このデバイスからの受信を許可する Remove_Device=デバイスを削除 -Text=テキスト \ No newline at end of file +Text=テキスト +Just_now=たった今 +Today=今日 +Yesterday=昨日 \ No newline at end of file diff --git a/composeApp/src/desktopMain/resources/i18n/zh.properties b/composeApp/src/desktopMain/resources/i18n/zh.properties index d4ab09d9c..c4c9f1162 100644 --- a/composeApp/src/desktopMain/resources/i18n/zh.properties +++ b/composeApp/src/desktopMain/resources/i18n/zh.properties @@ -39,4 +39,7 @@ Base_Info=基础信息 Allow_Send_to_this_device=允许发送到此设备 Allow_Receive_from_this_device=允许从此设备接收 Remove_Device=移除设备 -Text=文本 \ No newline at end of file +Text=文本 +Just_now=刚刚 +Today=今天 +Yesterday=昨天 \ No newline at end of file