커뮤니티 게시글 상대 시간 표기 다국어 지원
This commit is contained in:
@@ -49,6 +49,7 @@ import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
|
||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.relativeTimeText
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAdapter
|
||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
|
||||
@@ -965,7 +966,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
layout.tvCreatorNickname.text = item.creatorNickname
|
||||
layout.tvDate.text = item.date
|
||||
layout.tvDate.text = item.relativeTimeText(this)
|
||||
|
||||
layout.tvContent.text = item.content
|
||||
layout.ivPostImage.loadUrl(item.imageUrl) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.relativeTimeText
|
||||
|
||||
class CreatorCommunityAdapter(
|
||||
private val width: Int,
|
||||
@@ -31,7 +32,7 @@ class CreatorCommunityAdapter(
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
binding.tvCreatorNickname.text = item.creatorNickname
|
||||
binding.tvDate.text = item.date
|
||||
binding.tvDate.text = item.relativeTimeText(context)
|
||||
|
||||
binding.tvContent.text = item.content
|
||||
binding.ivPostImage.loadUrl(item.imageUrl) {
|
||||
|
||||
@@ -2,6 +2,14 @@ package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import android.content.Context
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
@Keep
|
||||
data class GetCommunityPostListResponse(
|
||||
@@ -14,6 +22,7 @@ data class GetCommunityPostListResponse(
|
||||
@SerializedName("content") val content: String,
|
||||
@SerializedName("price") val price: Int,
|
||||
@SerializedName("date") val date: String,
|
||||
@SerializedName("dateUtc") val dateUtc: String,
|
||||
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
|
||||
@SerializedName("isAdult") val isAdult: Boolean,
|
||||
@SerializedName("isLike") var isLike: Boolean,
|
||||
@@ -23,3 +32,100 @@ data class GetCommunityPostListResponse(
|
||||
@SerializedName("firstComment") val firstComment: GetCommunityPostCommentListItem?,
|
||||
@SerializedName("isExpand") var isExpand: Boolean = false
|
||||
)
|
||||
|
||||
/**
|
||||
* dateUtc 를 디바이스 로컬 타임존 기준의 상대 시간 문자열로 변환한다.
|
||||
* 규칙:
|
||||
* - 1분 미만: 방금 전
|
||||
* - 1시간 미만: OO분 전
|
||||
* - 1일 미만: OO시간 전
|
||||
* - 1개월 미만: OO일 전
|
||||
* - 1년 미만: OO개월 전
|
||||
* - 그 외: OO년 전
|
||||
* 기존 다국어 문자열 리소스(character_comment_time_*)를 사용한다.
|
||||
*/
|
||||
fun GetCommunityPostListResponse.relativeTimeText(context: Context): String {
|
||||
val pastMillis = parseServerUtcToMillis(dateUtc)
|
||||
?: return context.getString(R.string.character_comment_time_just_now)
|
||||
|
||||
val nowMillis = System.currentTimeMillis()
|
||||
var diff = nowMillis - pastMillis
|
||||
if (diff < 0) diff = 0 // 미래 보호
|
||||
|
||||
val minute = 60_000L
|
||||
val hour = 60 * minute
|
||||
val day = 24 * hour
|
||||
|
||||
if (diff < minute) {
|
||||
return context.getString(R.string.character_comment_time_just_now)
|
||||
}
|
||||
|
||||
if (diff < hour) {
|
||||
val minutes = (diff / minute).toInt()
|
||||
return context.getString(R.string.character_comment_time_minutes, minutes)
|
||||
}
|
||||
|
||||
if (diff < day) {
|
||||
val hours = (diff / hour).toInt()
|
||||
return context.getString(R.string.character_comment_time_hours, hours)
|
||||
}
|
||||
|
||||
if (diff < 30 * day) {
|
||||
val days = (diff / day).toInt()
|
||||
return context.getString(R.string.character_comment_time_days, days)
|
||||
}
|
||||
|
||||
// 개월/년 계산은 캘린더를 사용해 더 정확히 계산
|
||||
val tz = TimeZone.getDefault()
|
||||
val calNow = Calendar.getInstance(tz, Locale.getDefault())
|
||||
val calPast = Calendar.getInstance(tz, Locale.getDefault())
|
||||
calPast.timeInMillis = pastMillis
|
||||
|
||||
// 연도 계산 (아직 기념일 전이면 1년 빼기)
|
||||
var years = calNow.get(Calendar.YEAR) - calPast.get(Calendar.YEAR)
|
||||
val nowMonth = calNow.get(Calendar.MONTH)
|
||||
val pastMonth = calPast.get(Calendar.MONTH)
|
||||
val nowDay = calNow.get(Calendar.DAY_OF_MONTH)
|
||||
val pastDay = calPast.get(Calendar.DAY_OF_MONTH)
|
||||
if (nowMonth < pastMonth || (nowMonth == pastMonth && nowDay < pastDay)) {
|
||||
years -= 1
|
||||
}
|
||||
|
||||
if (years < 1) {
|
||||
var months = (calNow.get(Calendar.YEAR) - calPast.get(Calendar.YEAR)) * 12 + (nowMonth - pastMonth)
|
||||
if (nowDay < pastDay) months -= 1
|
||||
if (months < 1) months = 1 // 최소 1개월
|
||||
return context.getString(R.string.character_comment_time_months, months)
|
||||
}
|
||||
|
||||
return context.getString(R.string.character_comment_time_years, years)
|
||||
}
|
||||
|
||||
// 서버에서 내려오는 dateUtc 문자열을 UTC 기준 millis 로 파싱한다.
|
||||
private fun parseServerUtcToMillis(dateUtc: String?): Long? {
|
||||
if (dateUtc.isNullOrBlank()) return null
|
||||
|
||||
val s = dateUtc.trim()
|
||||
// epoch millis 가능성
|
||||
if (s.all { it.isDigit() }) {
|
||||
return try { s.toLong() } catch (_: NumberFormatException) { null }
|
||||
}
|
||||
|
||||
// 자주 쓰이는 포맷들 (UTC 가정)
|
||||
val patterns = listOf(
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
|
||||
"yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
"yyyy/MM/dd HH:mm:ss"
|
||||
)
|
||||
for (p in patterns) {
|
||||
try {
|
||||
val sdf = SimpleDateFormat(p, Locale.US)
|
||||
sdf.timeZone = TimeZone.getTimeZone("UTC")
|
||||
val date: Date? = sdf.parse(s)
|
||||
if (date != null) return date.time
|
||||
} catch (_: ParseException) { }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityAllBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.player.CreatorCommunityContentItem
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.relativeTimeText
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
import java.util.regex.Pattern
|
||||
@@ -53,7 +54,7 @@ class CreatorCommunityAllAdapter(
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@SuppressLint("NotifyDataSetChanged", "SetTextI18n")
|
||||
fun bind(item: GetCommunityPostListResponse, index: Int) {
|
||||
binding.tvDate.text = item.date
|
||||
binding.tvDate.text = item.relativeTimeText(context)
|
||||
binding.tvNickname.text = item.creatorNickname
|
||||
binding.ivCreatorProfile.loadUrl(item.creatorProfileUrl) {
|
||||
crossfade(true)
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
<string name="character_comment_time_minutes">%1$d min ago</string>
|
||||
<string name="character_comment_time_hours">%1$d hr ago</string>
|
||||
<string name="character_comment_time_days">%1$d day ago</string>
|
||||
<string name="character_comment_time_months">%1$d mo ago</string>
|
||||
<string name="character_comment_time_years">%1$d yr ago</string>
|
||||
<string name="character_comment_error_empty">Please enter a message.</string>
|
||||
<string name="character_comment_error_report_reason">Please enter a report reason.</string>
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
<string name="character_comment_time_minutes">%1$d分前</string>
|
||||
<string name="character_comment_time_hours">%1$d時間前</string>
|
||||
<string name="character_comment_time_days">%1$d日前</string>
|
||||
<string name="character_comment_time_months">%1$dか月前</string>
|
||||
<string name="character_comment_time_years">%1$d年前</string>
|
||||
<string name="character_comment_error_empty">内容を入力してください。</string>
|
||||
<string name="character_comment_error_report_reason">通報理由を入力してください。</string>
|
||||
|
||||
@@ -266,6 +266,7 @@
|
||||
<string name="character_comment_time_minutes">%1$d분전</string>
|
||||
<string name="character_comment_time_hours">%1$d시간전</string>
|
||||
<string name="character_comment_time_days">%1$d일전</string>
|
||||
<string name="character_comment_time_months">%1$d개월전</string>
|
||||
<string name="character_comment_time_years">%1$d년전</string>
|
||||
<string name="character_comment_error_empty">내용을 입력하세요</string>
|
||||
<string name="character_comment_error_report_reason">신고 사유를 입력하세요</string>
|
||||
|
||||
Reference in New Issue
Block a user