Convert ReadableTime and TextUrl to kotlin
This commit is contained in:
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
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user