Convert ReadableTime and TextUrl to kotlin

This commit is contained in:
FooIbar authored and tarsin committed 2023-06-22 10:01:41 +08:00
1 parent 0c9a8624bc
commit 0adc43b243
2 files changed
+107 -122

No files matched your search

@@ -13,123 +13,116 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.util
package com.hippo.ehviewer.util;
import android.content.Context
import android.content.res.Resources
import com.hippo.ehviewer.R
import java.time.Instant
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Locale
import android.content.Context;
import android.content.res.Resources;
import com.hippo.ehviewer.R;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public final class ReadableTime {
public static final long SECOND_MILLIS = 1000;
public static final long MINUTE_MILLIS = 60 * SECOND_MILLIS;
public static final long HOUR_MILLIS = 60 * MINUTE_MILLIS;
public static final long DAY_MILLIS = 24 * HOUR_MILLIS;
public static final long WEEK_MILLIS = 7 * DAY_MILLIS;
public static final long YEAR_MILLIS = 365 * DAY_MILLIS;
public static final long[] MULTIPLES = {
YEAR_MILLIS,
DAY_MILLIS,
HOUR_MILLIS,
MINUTE_MILLIS,
SECOND_MILLIS
};
public static final int SIZE = 5;
public static final int[] UNITS = {
R.plurals.year,
R.plurals.day,
R.plurals.hour,
R.plurals.minute,
R.plurals.second
};
private static final Object sCalendarLock = new Object();
private static final DateTimeFormatter DATE_FORMAT_WITHOUT_YEAR = DateTimeFormatter.ofPattern("MMM d");
private static final DateTimeFormatter DATE_FORMAT_WITH_YEAR = DateTimeFormatter.ofPattern("MMM d, yyyy");
private static final DateTimeFormatter DATE_FORMAT_WITHOUT_YEAR_ZH = DateTimeFormatter.ofPattern("M月d日");
private static final DateTimeFormatter DATE_FORMAT_WITH_YEAR_ZH = DateTimeFormatter.ofPattern("yyyy年M月d日");
private static final DateTimeFormatter FILENAMABLE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss-SSS");
private static final Object sDateFormatLock = new Object();
private static Resources sResources;
public static void initialize(Context context) {
sResources = context.getApplicationContext().getResources();
object ReadableTime {
private const val SECOND_MILLIS: Long = 1000
private const val MINUTE_MILLIS = 60 * SECOND_MILLIS
private const val HOUR_MILLIS = 60 * MINUTE_MILLIS
private const val DAY_MILLIS = 24 * HOUR_MILLIS
private const val WEEK_MILLIS = 7 * DAY_MILLIS
private const val YEAR_MILLIS = 365 * DAY_MILLIS
private val MULTIPLES = longArrayOf(
YEAR_MILLIS,
DAY_MILLIS,
HOUR_MILLIS,
MINUTE_MILLIS,
SECOND_MILLIS,
)
private const val SIZE = 5
private val UNITS = intArrayOf(
R.plurals.year,
R.plurals.day,
R.plurals.hour,
R.plurals.minute,
R.plurals.second,
)
private val sCalendarLock = Any()
private val DATE_FORMAT_WITHOUT_YEAR = DateTimeFormatter.ofPattern("MMM d")
private val DATE_FORMAT_WITH_YEAR = DateTimeFormatter.ofPattern("MMM d, yyyy")
private val DATE_FORMAT_WITHOUT_YEAR_ZH = DateTimeFormatter.ofPattern("M月d日")
private val DATE_FORMAT_WITH_YEAR_ZH = DateTimeFormatter.ofPattern("yyyy年M月d日")
private val FILENAMABLE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss-SSS")
private val sDateFormatLock = Any()
private var sResources: Resources? = null
fun initialize(context: Context) {
sResources = context.applicationContext.resources
}
public static String getTimeAgo(long time) {
Resources resources = sResources;
long now = System.currentTimeMillis();
if (time > now + (2 * MINUTE_MILLIS) || time <= 0) {
return resources.getString(R.string.from_the_future);
fun getTimeAgo(time: Long): String {
val resources = sResources
val now = System.currentTimeMillis()
if (time > now + 2 * MINUTE_MILLIS || time <= 0) {
return resources!!.getString(R.string.from_the_future)
}
final long diff = now - time;
val diff = now - time
if (diff < MINUTE_MILLIS) {
return resources.getString(R.string.just_now);
return resources!!.getString(R.string.just_now)
} else if (diff < 2 * MINUTE_MILLIS) {
return resources.getQuantityString(R.plurals.some_minutes_ago, 1, 1);
return resources!!.getQuantityString(R.plurals.some_minutes_ago, 1, 1)
} else if (diff < 50 * MINUTE_MILLIS) {
int minutes = (int) (diff / MINUTE_MILLIS);
return resources.getQuantityString(R.plurals.some_minutes_ago, minutes, minutes);
val minutes = (diff / MINUTE_MILLIS).toInt()
return resources!!.getQuantityString(R.plurals.some_minutes_ago, minutes, minutes)
} else if (diff < 90 * MINUTE_MILLIS) {
return resources.getQuantityString(R.plurals.some_hours_ago, 1, 1);
return resources!!.getQuantityString(R.plurals.some_hours_ago, 1, 1)
} else if (diff < 24 * HOUR_MILLIS) {
int hours = (int) (diff / HOUR_MILLIS);
return resources.getQuantityString(R.plurals.some_hours_ago, hours, hours);
val hours = (diff / HOUR_MILLIS).toInt()
return resources!!.getQuantityString(R.plurals.some_hours_ago, hours, hours)
} else if (diff < 48 * HOUR_MILLIS) {
return resources.getString(R.string.yesterday);
return resources!!.getString(R.string.yesterday)
} else if (diff < WEEK_MILLIS) {
int days = (int) (diff / DAY_MILLIS);
return resources.getString(R.string.some_days_ago, days);
val days = (diff / DAY_MILLIS).toInt()
return resources!!.getString(R.string.some_days_ago, days)
} else {
synchronized (sCalendarLock) {
OffsetDateTime nowDate = Instant.ofEpochMilli(now).atOffset(ZoneOffset.UTC);
OffsetDateTime timeDate = Instant.ofEpochMilli(time).atOffset(ZoneOffset.UTC);
int nowYear = nowDate.getYear();
int timeYear = timeDate.getYear();
boolean isZh = Locale.getDefault().getLanguage().equals("zh");
if (nowYear == timeYear) {
return (isZh ? DATE_FORMAT_WITHOUT_YEAR_ZH : DATE_FORMAT_WITHOUT_YEAR)
.format(timeDate.toInstant().atOffset(ZoneOffset.UTC));
synchronized(sCalendarLock) {
val nowDate = Instant.ofEpochMilli(now).atOffset(ZoneOffset.UTC)
val timeDate = Instant.ofEpochMilli(time).atOffset(ZoneOffset.UTC)
val nowYear = nowDate.year
val timeYear = timeDate.year
val isZh = Locale.getDefault().language == "zh"
return if (nowYear == timeYear) {
(if (isZh) DATE_FORMAT_WITHOUT_YEAR_ZH else DATE_FORMAT_WITHOUT_YEAR)
.format(timeDate.toInstant().atOffset(ZoneOffset.UTC))
} else {
return (isZh ? DATE_FORMAT_WITH_YEAR_ZH : DATE_FORMAT_WITH_YEAR)
.format(timeDate.toInstant().atOffset(ZoneOffset.UTC));
(if (isZh) DATE_FORMAT_WITH_YEAR_ZH else DATE_FORMAT_WITH_YEAR)
.format(timeDate.toInstant().atOffset(ZoneOffset.UTC))
}
}
}
}
public static String getShortTimeInterval(long time) {
StringBuilder sb = new StringBuilder();
Resources resources = sResources;
for (int i = 0; i < SIZE; i++) {
long multiple = MULTIPLES[i];
long quotient = time / multiple;
fun getShortTimeInterval(time: Long): String {
val sb = StringBuilder()
val resources = sResources
for (i in 0 until SIZE) {
val multiple = MULTIPLES[i]
val quotient = time / multiple
if (time > multiple * 1.5 || i == SIZE - 1) {
sb.append(quotient)
.append(" ")
.append(resources.getQuantityString(UNITS[i], (int) quotient));
break;
.append(" ")
.append(resources!!.getQuantityString(UNITS[i], quotient.toInt()))
break
}
}
return sb.toString();
return sb.toString()
}
public static String getFilenamableTime(long time) {
synchronized (sDateFormatLock) {
return FILENAMABLE_DATE_FORMAT.format(Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault()));
fun getFilenamableTime(time: Long): String {
synchronized(sDateFormatLock) {
return FILENAMABLE_DATE_FORMAT.format(
Instant.ofEpochMilli(time).atZone(
ZoneId.systemDefault(),
),
)
}
}
}
@@ -13,47 +13,39 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.util
package com.hippo.ehviewer.util;
import android.text.Spannable
import android.text.SpannableString
import android.text.style.URLSpan
import java.util.regex.Pattern
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.URLSpan;
object TextUrl {
private val URL_PATTERN =
Pattern.compile("(http|https)://[a-z0-9A-Z%-]+(\\.[a-z0-9A-Z%-]+)+(:\\d{1,5})?(/[a-zA-Z0-9-_~:#@!&',;=%/*.?+$\\[\\]()]+)?/?")
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class TextUrl {
private static final Pattern URL_PATTERN = Pattern.compile("(http|https)://[a-z0-9A-Z%-]+(\\.[a-z0-9A-Z%-]+)+(:\\d{1,5})?(/[a-zA-Z0-9-_~:#@!&',;=%/*.?+$\\[\\]()]+)?/?");
public static CharSequence handleTextUrl(CharSequence content) {
Matcher m = URL_PATTERN.matcher(content);
Spannable spannable = null;
fun handleTextUrl(content: CharSequence): CharSequence {
val m = URL_PATTERN.matcher(content)
var spannable: Spannable? = null
while (m.find()) {
// Ensure spannable
if (spannable == null) {
if (content instanceof Spannable) {
spannable = (Spannable) content;
spannable = if (content is Spannable) {
content
} else {
spannable = new SpannableString(content);
SpannableString(content)
}
}
int start = m.start();
int end = m.end();
URLSpan[] links = spannable.getSpans(start, end, URLSpan.class);
if (links.length > 0) {
val start = m.start()
val end = m.end()
val links = spannable.getSpans(start, end, URLSpan::class.java)
if (links.isNotEmpty()) {
// There has been URLSpan already, leave it alone
continue;
continue
}
URLSpan urlSpan = new URLSpan(m.group(0));
spannable.setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
val urlSpan = URLSpan(m.group(0))
spannable.setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
return spannable == null ? content : spannable;
return spannable ?: content
}
}