2022-11-06 21:05:36 +05:30
|
|
|
package com.github.libretube.util
|
|
|
|
|
2023-03-03 19:33:30 +05:30
|
|
|
import android.content.Context
|
2023-02-20 14:46:58 +05:30
|
|
|
import android.icu.text.RelativeDateTimeFormatter
|
|
|
|
import android.os.Build
|
|
|
|
import android.text.format.DateUtils
|
2023-03-03 19:33:30 +05:30
|
|
|
import com.github.libretube.R
|
2023-02-20 14:46:58 +05:30
|
|
|
import java.time.Instant
|
2023-04-24 18:48:29 +05:30
|
|
|
import java.time.LocalDate
|
2023-02-20 21:43:40 +05:30
|
|
|
import java.time.LocalDateTime
|
|
|
|
import java.time.ZoneId
|
2023-01-09 20:51:14 +05:30
|
|
|
import java.time.format.DateTimeFormatter
|
|
|
|
import java.time.format.FormatStyle
|
2023-02-20 21:43:40 +05:30
|
|
|
import java.time.temporal.ChronoUnit
|
2023-01-23 00:15:25 +05:30
|
|
|
import kotlin.time.Duration
|
2023-04-24 18:48:29 +05:30
|
|
|
import kotlinx.datetime.LocalDate as KotlinLocalDate
|
2023-01-18 07:01:06 +05:30
|
|
|
import kotlinx.datetime.toJavaLocalDate
|
2023-01-29 07:41:13 +05:30
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
2022-12-26 21:12:47 +05:30
|
|
|
|
2022-11-06 21:05:36 +05:30
|
|
|
object TextUtils {
|
|
|
|
/**
|
|
|
|
* Separator used for descriptions
|
|
|
|
*/
|
|
|
|
const val SEPARATOR = " • "
|
2022-11-09 22:31:59 +05:30
|
|
|
|
2022-12-25 13:17:17 +05:30
|
|
|
/**
|
|
|
|
* Reserved characters by unix which can not be used for file name.
|
|
|
|
*/
|
|
|
|
const val RESERVED_CHARS = "?:\"*|/\\<>\u0000"
|
|
|
|
|
2023-01-09 20:51:14 +05:30
|
|
|
/**
|
2023-03-01 19:49:27 +05:30
|
|
|
* Date time formatter which uses the [FormatStyle.MEDIUM] format style.
|
|
|
|
*/
|
|
|
|
private val MEDIUM_DATE_FORMATTER = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Localize the date from a date string, using the medium format.
|
2023-01-09 20:51:14 +05:30
|
|
|
* @param date The date to parse
|
2023-03-01 19:49:27 +05:30
|
|
|
* @return localized date string
|
2023-01-09 20:51:14 +05:30
|
|
|
*/
|
2023-04-24 18:48:29 +05:30
|
|
|
fun localizeDate(date: KotlinLocalDate): String {
|
2023-03-01 19:49:27 +05:30
|
|
|
return date.toJavaLocalDate().format(MEDIUM_DATE_FORMATTER)
|
2023-01-09 20:51:14 +05:30
|
|
|
}
|
2023-01-19 21:38:57 +05:30
|
|
|
|
|
|
|
/**
|
2023-03-25 06:23:52 +05:30
|
|
|
* Get time in seconds from a YouTube video link.
|
2023-01-23 00:15:25 +05:30
|
|
|
* @return Time in seconds
|
2023-01-19 21:38:57 +05:30
|
|
|
*/
|
2023-03-25 06:23:52 +05:30
|
|
|
fun String.toTimeInSeconds(): Long? {
|
|
|
|
return toLongOrNull() ?: Duration.parseOrNull(this)?.inWholeSeconds
|
2023-01-19 21:38:57 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get video id if the link is a valid youtube video link
|
|
|
|
*/
|
|
|
|
fun getVideoIdFromUri(link: String): String? {
|
2023-01-29 07:41:13 +05:30
|
|
|
return link.toHttpUrlOrNull()?.let {
|
|
|
|
when (it.host) {
|
|
|
|
"www.youtube.com" -> it.queryParameter("v")
|
|
|
|
"youtu.be" -> it.pathSegments.lastOrNull()
|
|
|
|
else -> null
|
2023-01-19 21:38:57 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-20 14:46:58 +05:30
|
|
|
|
2023-03-03 19:33:30 +05:30
|
|
|
fun formatRelativeDate(context: Context, unixTime: Long): CharSequence {
|
2023-03-20 08:47:14 +05:30
|
|
|
// TODO: Use LocalDate.ofInstant() when it is available in SDK 34.
|
2023-02-20 21:43:40 +05:30
|
|
|
val date = LocalDateTime.ofInstant(Instant.ofEpochMilli(unixTime), ZoneId.systemDefault())
|
2023-03-20 08:47:14 +05:30
|
|
|
.toLocalDate()
|
2023-04-24 18:48:29 +05:30
|
|
|
val now = LocalDate.now()
|
|
|
|
val months = date.until(now, ChronoUnit.MONTHS)
|
2023-02-20 21:43:40 +05:30
|
|
|
|
2023-04-24 18:48:29 +05:30
|
|
|
return if (months > 0) {
|
2023-03-03 19:33:30 +05:30
|
|
|
val years = months / 12
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
2023-04-24 18:48:29 +05:30
|
|
|
val (timeFormat, time) = if (years > 0) {
|
|
|
|
RelativeDateTimeFormatter.RelativeUnit.YEARS to years
|
|
|
|
} else {
|
|
|
|
RelativeDateTimeFormatter.RelativeUnit.MONTHS to months
|
2023-03-03 19:33:30 +05:30
|
|
|
}
|
|
|
|
RelativeDateTimeFormatter.getInstance()
|
|
|
|
.format(time.toDouble(), RelativeDateTimeFormatter.Direction.LAST, timeFormat)
|
|
|
|
} else {
|
2023-04-24 18:48:29 +05:30
|
|
|
val (timeAgoRes, time) = if (years > 0) {
|
|
|
|
R.plurals.years_ago to years
|
|
|
|
} else {
|
|
|
|
R.plurals.months_ago to months
|
2023-03-03 19:33:30 +05:30
|
|
|
}
|
|
|
|
context.resources.getQuantityString(timeAgoRes, time.toInt(), time)
|
2023-02-20 14:46:58 +05:30
|
|
|
}
|
|
|
|
} else {
|
2023-04-24 18:48:29 +05:30
|
|
|
val weeks = date.until(now, ChronoUnit.WEEKS)
|
|
|
|
val minResolution = if (weeks > 0) DateUtils.WEEK_IN_MILLIS else 0L
|
|
|
|
DateUtils.getRelativeTimeSpanString(unixTime, System.currentTimeMillis(), minResolution)
|
2023-02-20 14:46:58 +05:30
|
|
|
}
|
|
|
|
}
|
2023-02-22 15:45:43 +05:30
|
|
|
|
|
|
|
fun formatBitrate(bitrate: Int?): String {
|
|
|
|
bitrate ?: return ""
|
|
|
|
return "${bitrate / 1024}kbps"
|
|
|
|
}
|
2022-11-06 21:05:36 +05:30
|
|
|
}
|