From 856fbd647070341eecd8eef83e25501fadee35f7 Mon Sep 17 00:00:00 2001 From: tateisu Date: Thu, 27 Dec 2018 02:08:01 +0900 Subject: [PATCH] More flexible Relative time format string --- .../subwaytooter/api/entity/TootStatus.kt | 123 +++++++++--------- app/src/main/res/values-ar/strings.xml | 13 +- app/src/main/res/values-cy/strings.xml | 22 ++-- app/src/main/res/values-fr/strings.xml | 22 ++-- app/src/main/res/values-ja/strings.xml | 21 +-- app/src/main/res/values-nb-rNO/strings.xml | 21 +-- app/src/main/res/values/strings.xml | 28 ++-- 7 files changed, 130 insertions(+), 120 deletions(-) diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt index 5ccfca32..a600de1d 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt @@ -2,6 +2,7 @@ package jp.juggler.subwaytooter.api.entity import android.annotation.SuppressLint import android.content.Context +import android.support.annotation.StringRes import android.text.Spannable import android.text.SpannableString import jp.juggler.subwaytooter.App1 @@ -21,6 +22,7 @@ import java.text.SimpleDateFormat import java.util.* import java.util.regex.Pattern import kotlin.collections.ArrayList +import kotlin.math.abs @Suppress("MemberVisibilityCanPrivate") class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { @@ -89,7 +91,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { // Pleromaは「空文字列:CWなし」「空じゃない文字列:CWあり」の2種類 // Misskeyは「CWなし」「空欄CW」「CWあり」の3通り。空欄CWはパース時に書き換えてしまう // Misskeyで投稿が削除された時に変更されるため、val変数にできない - var spoiler_text : String ="" + var spoiler_text : String = "" var decoded_spoiler_text : Spannable // Body of the status; this will contain HTML (remote HTML already sanitized) @@ -281,7 +283,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { if(options.highlight_sound != null && this.highlight_sound == null) { this.highlight_sound = options.highlight_sound } - + // Markdownのデコード結果からmentionsを読むのだった this.mentions = (decoded_content as? MisskeyMarkdownDecoder.SpannableStringBuilderEx)?.mentions @@ -292,12 +294,12 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { ) ?: EMPTY_SPANNABLE val sv = src.parseString("cw")?.cleanCW() - this.spoiler_text = when{ + this.spoiler_text = when { sv == null -> "" // CWなし sv.isBlank() -> parser.context.getString(R.string.blank_cw) - else-> sv + else -> sv } - + options = DecodeOptions( parser.context, parser.linkHelper, @@ -368,7 +370,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { ServiceType.MASTODON -> { this.host_access = parser.linkHelper.host - this.id = EntityId.mayDefault(src.parseLong("id") ) + this.id = EntityId.mayDefault(src.parseLong("id")) this.uri = src.parseString("uri") ?: error("missing uri") this.reblogged = src.optBoolean("reblogged") @@ -394,7 +396,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { // 投稿元タンスでのIDを調べる。失敗するかもしれない this.uri = src.parseString("uri") ?: error("missing uri") this.id = findStatusIdFromUri(uri, url) ?: EntityId.defaultLong - + this.time_created_at = TootStatus.parseTime(this.created_at) this.media_attachments = parseListOrNull( @@ -412,10 +414,11 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { this.host_access = null // MSPのデータはLTLから呼んだものなので、常に投稿元タンスでのidが得られる - this.id = EntityId.mayDefault(src.parseLong("id") ) + this.id = EntityId.mayDefault(src.parseLong("id")) // MSPだとuriは提供されない。LTL限定なのでURL的なものを作れるはず - this.uri = "https://${parser.linkHelper.host}/users/${who.username}/statuses/$id" - + this.uri = + "https://${parser.linkHelper.host}/users/${who.username}/statuses/$id" + this.time_created_at = parseTimeMSP(created_at) this.media_attachments = TootAttachmentMSP.parseList(src.optJSONArray("media_attachments")) @@ -463,13 +466,13 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { this.highlight_sound = options.highlight_sound } - val sv = (src.parseString("spoiler_text")?:"").cleanCW() - this.spoiler_text = when{ - sv.isEmpty() ->"" // CWなし - sv.isBlank() ->parser.context.getString(R.string.blank_cw) - else->sv + val sv = (src.parseString("spoiler_text") ?: "").cleanCW() + this.spoiler_text = when { + sv.isEmpty() -> "" // CWなし + sv.isBlank() -> parser.context.getString(R.string.blank_cw) + else -> sv } - + options = DecodeOptions( parser.context, emojiMapCustom = custom_emojis, @@ -499,7 +502,6 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { } } - /////////////////////////////////////////////////// // ユーティリティ @@ -600,7 +602,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { || enquete != null -> true else -> false } - + // return true if updated fun increaseReaction(reaction : String?, byMe : Boolean, caller : String) : Boolean { reaction ?: return false @@ -682,9 +684,11 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { // 公開ステータスページのURL Misskey @Suppress("HasPlatformType") - val reStatusPageMisskey = Pattern.compile("""\Ahttps://([^/]+)/notes/([0-9a-f]{24})\b""", Pattern.CASE_INSENSITIVE) + val reStatusPageMisskey = Pattern.compile( + """\Ahttps://([^/]+)/notes/([0-9a-f]{24})\b""", + Pattern.CASE_INSENSITIVE + ) - fun parseListTootsearch( parser : TootParser, root : JSONObject @@ -780,48 +784,52 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { if(bAllowRelative && Pref.bpRelativeTimestamp(App1.pref)) { val now = System.currentTimeMillis() var delta = now - t - val sign = context.getString(if(delta > 0) R.string.ago else R.string.later) - delta = if(delta >= 0) delta else - delta + + @StringRes val phraseId = if(delta >= 0) + R.string.relative_time_phrase_past + else + R.string.relative_time_phrase_future + + delta = abs(delta) + + fun f(v : Long, unit1 : Int, units : Int) : String { + val vi = v.toInt() + return context.getString( + phraseId, + vi, + context.getString(if(vi <= 1) unit1 else units) + ) + } + when { delta < 1000L -> return context.getString(R.string.time_within_second) - delta < 60000L -> { - val v = (delta / 1000L).toInt() - return context.getString( - if(v > 1) R.string.relative_time_second_2 else R.string.relative_time_second_1, - v, - sign - ) - } + delta < 60000L -> return f( + delta / 1000L, + R.string.relative_time_unit_second1, + R.string.relative_time_unit_seconds + ) - delta < 3600000L -> { - val v = (delta / 60000L).toInt() - return context.getString( - if(v > 1) R.string.relative_time_minute_2 else R.string.relative_time_minute_1, - v, - sign - ) - } + delta < 3600000L -> return f( + delta / 60000L, + R.string.relative_time_unit_minute1, + R.string.relative_time_unit_minutes + ) - delta < 86400000L -> { - val v = (delta / 3600000L).toInt() - return context.getString( - if(v > 1) R.string.relative_time_hour_2 else R.string.relative_time_hour_1, - v, - sign - ) - } + delta < 86400000L -> return f( + delta / 3600000L, + R.string.relative_time_unit_hour1, + R.string.relative_time_unit_hours + ) - delta < 40 * 86400000L -> { - val v = (delta / 86400000L).toInt() - return context.getString( - if(v > 1) R.string.relative_time_day_2 else R.string.relative_time_day_1, - v, - sign - ) - } + delta < 40 * 86400000L -> return f( + delta / 86400000L, + R.string.relative_time_unit_day1, + R.string.relative_time_unit_days + ) else -> { + // fall back to absolute time } } } @@ -874,11 +882,10 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { return if(host != null && host.isNotEmpty() && host != "?") host else null } - private fun readMisskeyNoteId(url : String) : EntityId? { // https://misskey.xyz/notes/5b802367744b650030a13640 val m = reStatusPageMisskey.matcher(url) - return if(!m.find()) null else EntityIdString(m.group(2)) + return if(! m.find()) null else EntityIdString(m.group(2)) } fun validStatusId(src : EntityId?) : EntityId? { @@ -889,12 +896,10 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { } } - - private fun String.cleanCW() = CharacterGroup.reWhitespace.matcher(this).replaceAll(" ").sanitizeBDI() /* 空欄かどうかがCW判定条件に影響するので、trimしてはいけない */ - + // 投稿元タンスでのステータスIDを調べる fun findStatusIdFromUri( uri : String?, diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index e4da210f..20c7e25f 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -244,17 +244,8 @@ تحديد رمز النفاذ (للمستخدمين المتقدمين) العنوان معلومات عن مثيل الخادوم - لاحقًا - الآن - %1$d ثانية %2$s - %1$d ثواني %2$s - %1$d دقيقة %2$s - %1$d دقائق %2$s - %1$d ساعة %2$s - %1$d ساعات %2$s - %1$d يوم %2$s - %1$d أيام %2$s + الآن إنشاء استطلاع للرأي تدبيس على الملف الشخصي إلغاء التدبيس مِن الملف الشخصي @@ -396,7 +387,7 @@ سمة واجهة المستخدم (مطلوب أعادة تشغيل التطبيق) قائمة بسيطة (مطلوب أعادة تشغيل التطبيق) تم حذفه من المفضلة - "حجم هذا الملف أكبر من الحد الأقصى المسموح به %1$dMB." + حجم هذا الملف أكبر من الحد الأقصى المسموح به %1$dMB. الرئيسية (محلي) للمتابِعين فقط (محلي) غير مدرج (محلي) diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml index 785b1b84..27dc11a7 100644 --- a/app/src/main/res/values-cy/strings.xml +++ b/app/src/main/res/values-cy/strings.xml @@ -303,7 +303,6 @@ Fersiwn Gwybodaeth achos \"%1$s\" Gwybodaeth achos - wedyn Wedi pleidleisio! Pleidlais wedi methu. %1$s dewis 1 @@ -418,15 +417,18 @@ (sampl)enwdefnyddiwr@achos Newid delwedd pennawd Ap E-bost ar goll. - yn ôl - %1$d eiliad %2$s - %1$d eiliadau %2$s - %1$d munud %2$s - %1$d munudau %2$s - %1$d awr %2$s - %1$d oriau %2$s - %1$d dydd %2$s - %1$d dyddiau %2$s + + eiliad + eiliadau + munud + munudau + awr + oriau + dydd + dyddiau + %1$d %2$s yn ôl + %1$d %2$s wedyn + lliw croen golau lliw croen cymhedrol o olau lliw croen cymhedrol diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 461f0aea..83825fc7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -447,17 +447,19 @@ Informations sur l\'instance App de courriel manquante. Afficher les horodatages relatifs - ago - plus tard à l\'instant - %1$d seconde %2$s - %1$d secondes %2$s - %1$d minute %2$s - %1$d minutes %2$s - %1$d heure %2$s - %1$d heures %2$s - %1$d day %2$s - %1$d jours %2$s + + seconde + secondes + minute + minutes + heure + heures + day + jours + %1$d %2$s ago + %1$d %2$s plus tard + Son de notification (avant Android 8.0) Style de notification (Android 8.0 ou version ultérieure) Notification for %1$s diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index dbb4cef7..6c840138 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -34,7 +34,6 @@ 通知へのアクション トゥートへのアクション ユーザへのアクション - カラムの重複を許容する 絵文字コードの手前に空白以外の文字があっても変換する (投稿と表示の両方に影響します。表示の反映にはアプリ再起動とカラムのリロードが必要です。投稿時に変換された絵文字を元のコードに戻すことはできません。) 既にブースト済みです @@ -370,7 +369,6 @@ ja 言語 最後に選択した - ランチャーアイコンはフタバさんがデザインしました LED \"%1$s\"が長すぎます(%2$d/%3$d文字).\n標準的なタンスではエラーとなりますが、一部のタンスでは通るかも。\nよろしいですか? @@ -562,14 +560,17 @@ 正規表現フィルタ(上級者向け) 正規表現フィルタは空文字列にマッチしてしまいます %1$sにこのアプリを登録しています… - %1$d日%2$s - %1$d日%2$s - %1$d時間%2$s - %1$d時間%2$s - %1$d分%2$s - %1$d分%2$s - %1$d秒%2$s - %1$d秒%2$s + + + + + + 時間 + 時間 + + + %1$d %2$s前 + %1$d %2$s後 相対時刻を表示 再読み込み リモートユーザのプロフィールは情報が不十分な可能性があります。より正確な情報をWebページで確認することができます。 diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 27f3401d..cf7134a0 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -367,18 +367,19 @@ Instansinfo Manglende e-postprogram. Vis relative tidsstempel - siden - senere akkurat nå - %1$d sekund %2$s - %1$d sekunder %2$s - %1$d minutt %2$s - %1$d minutter %2$s - %1$d time %2$s - %1$d timer %2$s - %1$d dag %2$s - %1$d dager %2$s + sekund + sekunder + minutt + minutter + time + timer + dag + dager + %1$d %2$s siden + %1$d %2$s senere + Disse innstillingen brukes for merknad for %1$s Merknadslyd (før Android 8.0) Merknadsstil (Android 8.0 eller senere) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 924344bf..2ed90adc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -455,18 +455,26 @@ Instance information Missing e-mail app. Show relative timestamps - ago - later just now + second + seconds + minute + minutes + hour + hours + day + days + %1$d %2$s + %1$d %2$s future - %1$d second %2$s - %1$d seconds %2$s - %1$d minute %2$s - %1$d minutes %2$s - %1$d hour %2$s - %1$d hours %2$s - %1$d day %2$s - %1$d days %2$s + + + + + + + + This setting is used to adjust notification for %1$s Notification sound (pre Android 8.0) Notification style (Android 8.0+)