mirror of
https://github.com/tateisu/SubwayTooter
synced 2025-02-04 04:37:40 +01:00
firebase messaging のtoken id の取得方法が非同期になった。文字列リソース中のパーセント表記のエスケープを修正。
This commit is contained in:
parent
9913f89d95
commit
15a845e0e2
1
.idea/dictionaries/tateisu.xml
generated
1
.idea/dictionaries/tateisu.xml
generated
@ -68,6 +68,7 @@
|
||||
<w>ihdr</w>
|
||||
<w>infos</w>
|
||||
<w>iptc</w>
|
||||
<w>jetbrains</w>
|
||||
<w>jfif</w>
|
||||
<w>jwcp</w>
|
||||
<w>kapt</w>
|
||||
|
@ -105,9 +105,10 @@ dependencies {
|
||||
// PreferenceManager
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.1"
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.2"
|
||||
|
||||
// CustomTabs
|
||||
// TODO 1.3.0 に上げたいが、その前に2回開く問題を調査したい
|
||||
implementation "androidx.browser:browser:1.2.0"
|
||||
|
||||
// Recyclerview
|
||||
@ -123,7 +124,8 @@ dependencies {
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$kotlinx_coroutines_version"
|
||||
implementation("ru.gildor.coroutines:kotlin-coroutines-okhttp:1.0")
|
||||
|
||||
// Anko Layouts
|
||||
// sdk15, sdk19, sdk21, sdk23 are also available
|
||||
|
@ -35,6 +35,7 @@ import jp.juggler.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
@ -1580,7 +1581,9 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
|
||||
)
|
||||
|
||||
override fun background(client : TootApiClient) : TootApiResult? {
|
||||
return wps.updateSubscription(client, true)
|
||||
return runBlocking{
|
||||
wps.updateSubscription(client, true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleResult(result : TootApiResult?) {
|
||||
|
@ -538,7 +538,11 @@ class Column(
|
||||
// プロフカラムでのアカウント情報
|
||||
@Volatile
|
||||
internal var who_account : TootAccountRef? = null
|
||||
|
||||
|
||||
// プロフカラムでのfeatured tag 情報(Mastodon3.3.0)
|
||||
@Volatile
|
||||
internal var who_featured_tags : List<TootTag>? = null
|
||||
|
||||
// リストカラムでのリスト情報
|
||||
@Volatile
|
||||
internal var list_info : TootList? = null
|
||||
@ -1733,8 +1737,14 @@ class Column(
|
||||
client.request(String.format(Locale.JAPAN, PATH_ACCOUNT, profile_id))?.also { result1 ->
|
||||
TootAccountRef.mayNull(parser, parser.account(result1.jsonObject))?.also { a ->
|
||||
this.who_account = a
|
||||
|
||||
this.who_featured_tags = null
|
||||
client.request("/api/v1/accounts/${profile_id}/featured_tags")?.also{ result2->
|
||||
|
||||
this.who_featured_tags =TootTag.parseListOrNull(parser,result2.jsonArray)
|
||||
}
|
||||
|
||||
client.publishApiProgress("") // カラムヘッダの再表示
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@ package jp.juggler.subwaytooter
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.ForegroundColorSpan
|
||||
@ -11,19 +12,16 @@ import jp.juggler.emoji.EmojiMap
|
||||
import jp.juggler.subwaytooter.action.Action_Follow
|
||||
import jp.juggler.subwaytooter.action.Action_User
|
||||
import jp.juggler.subwaytooter.api.*
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccountRef
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||
import jp.juggler.subwaytooter.api.entity.*
|
||||
import jp.juggler.subwaytooter.dialog.DlgTextInput
|
||||
import jp.juggler.subwaytooter.span.EmojiImageSpan
|
||||
import jp.juggler.subwaytooter.span.LinkInfo
|
||||
import jp.juggler.subwaytooter.span.MyClickableSpan
|
||||
import jp.juggler.subwaytooter.span.createSpan
|
||||
import jp.juggler.subwaytooter.table.AcctColor
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.subwaytooter.table.UserRelation
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions
|
||||
import jp.juggler.subwaytooter.util.NetworkEmojiInvalidator
|
||||
import jp.juggler.subwaytooter.util.openCustomTab
|
||||
import jp.juggler.subwaytooter.util.startMargin
|
||||
import jp.juggler.subwaytooter.util.*
|
||||
import jp.juggler.subwaytooter.view.MyLinkMovementMethod
|
||||
import jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
import jp.juggler.subwaytooter.view.MyTextView
|
||||
@ -38,6 +36,8 @@ internal class ViewHolderHeaderProfile(
|
||||
private val ivBackground : MyNetworkImageView
|
||||
private val tvCreated : TextView
|
||||
private val tvLastStatusAt : TextView
|
||||
private val tvFeaturedTags : TextView
|
||||
|
||||
private val ivAvatar : MyNetworkImageView
|
||||
private val tvDisplayName : TextView
|
||||
private val tvAcct : TextView
|
||||
@ -79,6 +79,7 @@ internal class ViewHolderHeaderProfile(
|
||||
llProfile = viewRoot.findViewById(R.id.llProfile)
|
||||
tvCreated = viewRoot.findViewById(R.id.tvCreated)
|
||||
tvLastStatusAt = viewRoot.findViewById(R.id.tvLastStatusAt)
|
||||
tvFeaturedTags = viewRoot.findViewById(R.id.tvFeaturedTags)
|
||||
ivAvatar = viewRoot.findViewById(R.id.ivAvatar)
|
||||
tvDisplayName = viewRoot.findViewById(R.id.tvDisplayName)
|
||||
tvAcct = viewRoot.findViewById(R.id.tvAcct)
|
||||
@ -160,6 +161,7 @@ internal class ViewHolderHeaderProfile(
|
||||
tvMovedName.textSize = f
|
||||
tvMoved.textSize = f
|
||||
tvPersonalNotes.textSize = f
|
||||
tvFeaturedTags.textSize = f
|
||||
}
|
||||
|
||||
f = activity.acct_font_size_sp
|
||||
@ -187,7 +189,8 @@ internal class ViewHolderHeaderProfile(
|
||||
btnStatusCount.textColor = contentColor
|
||||
btnFollowing.textColor = contentColor
|
||||
btnFollowers.textColor = contentColor
|
||||
|
||||
tvFeaturedTags.textColor = contentColor
|
||||
|
||||
setIconDrawableId(
|
||||
activity,
|
||||
btnMore,
|
||||
@ -208,6 +211,7 @@ internal class ViewHolderHeaderProfile(
|
||||
tvCreated.textColor = acctColor
|
||||
tvMovedAcct.textColor = acctColor
|
||||
tvLastStatusAt.textColor = acctColor
|
||||
|
||||
|
||||
val whoRef = column.who_account
|
||||
this.whoRef = whoRef
|
||||
@ -231,6 +235,7 @@ internal class ViewHolderHeaderProfile(
|
||||
relation = null
|
||||
tvCreated.text = ""
|
||||
tvLastStatusAt.vg(false)
|
||||
tvFeaturedTags.vg(false)
|
||||
ivBackground.setImageDrawable(null)
|
||||
ivAvatar.setImageDrawable(null)
|
||||
|
||||
@ -259,6 +264,28 @@ internal class ViewHolderHeaderProfile(
|
||||
invalidator = null,
|
||||
fromProfileHeader = true
|
||||
)
|
||||
|
||||
val featuredTagsText = column.who_featured_tags?.notEmpty()?.let{ tagList->
|
||||
SpannableStringBuilder().apply {
|
||||
append(activity.getString(R.string.featured_hashtags))
|
||||
append(":")
|
||||
tagList.forEach { tag ->
|
||||
append(" ")
|
||||
val tagWithSharp = "#" + tag.name
|
||||
val start = length
|
||||
append(tagWithSharp)
|
||||
val end = length
|
||||
tag.url?.notEmpty()?.let{ url->
|
||||
val span = MyClickableSpan(LinkInfo(url = url, tag = tag.name, caption = tagWithSharp))
|
||||
setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tvFeaturedTags.vg( featuredTagsText !=null)?.let{
|
||||
it.text = featuredTagsText!!
|
||||
it.movementMethod = MyLinkMovementMethod
|
||||
}
|
||||
|
||||
ivBackground.setImageUrl(
|
||||
activity.pref,
|
||||
|
@ -24,10 +24,10 @@ class TootParser(
|
||||
val misskeyUserRelationMap = HashMap<EntityId, UserRelation>()
|
||||
// val misskeyAccountDetailMap = HashMap<EntityId, TootAccount>()
|
||||
|
||||
val apiHost : Host?
|
||||
val apiHost : Host
|
||||
get() = linkHelper.apiHost
|
||||
|
||||
val apDomain : Host?
|
||||
val apDomain : Host
|
||||
get() = linkHelper.apDomain
|
||||
|
||||
init {
|
||||
|
@ -127,9 +127,10 @@ open class TootAccount(parser : TootParser, src : JsonObject) : HostAndDomain {
|
||||
init {
|
||||
this.json = src
|
||||
src["_fromStream"] = parser.fromStream
|
||||
|
||||
|
||||
if(parser.serviceType == ServiceType.MISSKEY) {
|
||||
|
||||
|
||||
|
||||
this.custom_emojis =
|
||||
parseMapOrNull(CustomEmoji.decodeMisskey, src.jsonArray("emojis"))
|
||||
this.profile_emojis = null
|
||||
|
@ -7,181 +7,187 @@ import jp.juggler.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
open class TootTag constructor(
|
||||
|
||||
|
||||
// The hashtag, not including the preceding #
|
||||
val name : String,
|
||||
|
||||
val name: String,
|
||||
|
||||
// The URL of the hashtag. may null if generated from TootContext
|
||||
val url : String? = null,
|
||||
|
||||
val url: String? = null,
|
||||
|
||||
// Mastodon /api/v2/search provides history.
|
||||
val history : ArrayList<History>? = null
|
||||
val history: ArrayList<History>? = null
|
||||
|
||||
) : TimelineItem() {
|
||||
|
||||
val countDaily : Int
|
||||
val countWeekly : Int
|
||||
val accountDaily : Int
|
||||
val accountWeekly : Int
|
||||
|
||||
init {
|
||||
countDaily = history?.first()?.uses ?: 0
|
||||
countWeekly = history?.sumBy { it.uses } ?: 0
|
||||
|
||||
accountDaily = history?.first()?.accounts ?: 0
|
||||
accountWeekly = history?.map { it.accounts }?.maxOrNull() ?: accountDaily
|
||||
}
|
||||
|
||||
class History(src : JsonObject) {
|
||||
|
||||
private val day : Long
|
||||
val uses : Int
|
||||
val accounts : Int
|
||||
|
||||
init {
|
||||
day = src.long("day")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing day")
|
||||
uses = src.int("uses")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing uses")
|
||||
accounts = src.int("accounts")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing accounts")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val log = LogCategory("TootTag")
|
||||
|
||||
fun parse(parser : TootParser, src : JsonObject) =
|
||||
if(parser.linkHelper.isMisskey) {
|
||||
val name = src.stringOrThrow("tag")
|
||||
val url = "https://${parser.apiHost}/tags/${Uri.encode(name)}"
|
||||
TootTag(
|
||||
|
||||
val countDaily: Int
|
||||
val countWeekly: Int
|
||||
val accountDaily: Int
|
||||
val accountWeekly: Int
|
||||
|
||||
init {
|
||||
countDaily = history?.first()?.uses ?: 0
|
||||
countWeekly = history?.sumBy { it.uses } ?: 0
|
||||
|
||||
accountDaily = history?.first()?.accounts ?: 0
|
||||
accountWeekly = history?.map { it.accounts }?.maxOrNull() ?: accountDaily
|
||||
}
|
||||
|
||||
class History(src: JsonObject) {
|
||||
|
||||
private val day: Long
|
||||
val uses: Int
|
||||
val accounts: Int
|
||||
|
||||
init {
|
||||
day = src.long("day")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing day")
|
||||
uses = src.int("uses")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing uses")
|
||||
accounts = src.int("accounts")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing accounts")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val log = LogCategory("TootTag")
|
||||
|
||||
private val reHeadSharp = """\A#""".toRegex()
|
||||
|
||||
private val reUserTagUrl = """/@[^/]+/tagged/""".toRegex()
|
||||
|
||||
fun parse(parser: TootParser, src: JsonObject) =
|
||||
if (parser.linkHelper.isMisskey) {
|
||||
val name = src.stringOrThrow("tag").replaceFirst(reHeadSharp, "")
|
||||
TootTag(
|
||||
name = name,
|
||||
url = url,
|
||||
history = null
|
||||
url = "https://${parser.apiHost}/tags/${Uri.encode(name)}"
|
||||
)
|
||||
} else {
|
||||
TootTag(
|
||||
name = src.stringOrThrow("name"),
|
||||
url = src.string("url"),
|
||||
} else {
|
||||
// /api/v1/accounts/$id/featured_tags の場合、
|
||||
// name部分は先頭に#がついているかもしれない。必要なら除去するべき。
|
||||
// url部分はユーザのタグTLになる。 https://nightly.fedibird.com/@noellabo/tagged/fedibird
|
||||
// STはメニューから選べるので、URLは普通のタグURLの方が望ましい https://nightly.fedibird.com/tags/fedibird
|
||||
TootTag(
|
||||
name = src.stringOrThrow("name").replaceFirst(reHeadSharp, ""),
|
||||
url = src.string("url")?.replaceFirst(reUserTagUrl, "/tags/"),
|
||||
history = parseHistories(src.jsonArray("history"))
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseHistories(src : JsonArray?) : ArrayList<History>? {
|
||||
src ?: return null
|
||||
|
||||
val dst = ArrayList<History>()
|
||||
src.objectList().forEach {
|
||||
try {
|
||||
dst.add(History(it))
|
||||
} catch(ex : Throwable) {
|
||||
log.e(ex, "parseHistories failed.")
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
fun parseListOrNull(parser : TootParser, array : JsonArray?) =
|
||||
array?.mapNotNull { src->
|
||||
try {
|
||||
when(src) {
|
||||
}
|
||||
|
||||
private fun parseHistories(src: JsonArray?): ArrayList<History>? {
|
||||
src ?: return null
|
||||
|
||||
val dst = ArrayList<History>()
|
||||
src.objectList().forEach {
|
||||
try {
|
||||
dst.add(History(it))
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex, "parseHistories failed.")
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
fun parseListOrNull(parser: TootParser, array: JsonArray?) =
|
||||
array?.mapNotNull { src ->
|
||||
try {
|
||||
when (src) {
|
||||
null -> null
|
||||
"" -> null
|
||||
is String -> TootTag(name = src)
|
||||
is JsonObject -> parse(parser, src)
|
||||
else->null
|
||||
}
|
||||
}catch(ex:Throwable){
|
||||
log.e(ex,"parseListOrNull failed.")
|
||||
null
|
||||
}
|
||||
}?.notEmpty()
|
||||
|
||||
fun parseList(parser : TootParser, array : JsonArray?) =
|
||||
parseListOrNull(parser,array) ?: emptyList()
|
||||
|
||||
private const val w = TootAccount.reRubyWord
|
||||
private const val a = TootAccount.reRubyAlpha
|
||||
private const val s = "_\\u00B7\\u200c" // separators
|
||||
|
||||
private fun generateMastodonTagPattern() : Pattern {
|
||||
val reMastodonTagName = """([_$w][$s$w]*[$s$a][$s$w]*[_$w])|([_$w]*[$a][_$w]*)"""
|
||||
return """(?:^|[^\w/)])#($reMastodonTagName)""".asciiPattern()
|
||||
}
|
||||
|
||||
private val reMastodonTag = generateMastodonTagPattern()
|
||||
|
||||
// https://medium.com/@alice/some-article#.abcdef123 => タグにならない
|
||||
// https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit => タグにならない
|
||||
// #aesthetic => #aesthetic
|
||||
// #3d => #3d
|
||||
// #l33ts35k => #l33ts35k
|
||||
// #world2016 => #world2016
|
||||
// #_test => #_test
|
||||
// #test_ => #test_
|
||||
// #one·two·three· => 末尾の・はタグに含まれない。#one·two·three までがハッシュタグになる。
|
||||
// #0123456' => 数字だけのハッシュタグはタグとして認識されない。
|
||||
// #000_000 => 認識される。orの前半分が機能してるらしい
|
||||
//
|
||||
|
||||
// タグに使えない文字
|
||||
// 入力補完用なのでやや緩め
|
||||
private val reCharsNotTagMastodon = """[^$s$w$a]""".asciiPattern()
|
||||
private val reCharsNotTagMisskey = """[\s.,!?'${'"'}:/\[\]【】]""".asciiPattern()
|
||||
|
||||
// find hashtags in content text(raw)
|
||||
// returns null if hashtags not found, or ArrayList of String (tag without #)
|
||||
fun findHashtags(src : String, isMisskey : Boolean) : ArrayList<String>? =
|
||||
if(isMisskey) {
|
||||
MisskeyMarkdownDecoder.findHashtags(src)
|
||||
} else {
|
||||
var result : ArrayList<String>? = null
|
||||
val m = reMastodonTag.matcher(src)
|
||||
while(m.find()) {
|
||||
if(result == null) result = ArrayList()
|
||||
result.add(m.groupEx(1) !!)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun isValid(src : String, isMisskey : Boolean) =
|
||||
if(isMisskey) {
|
||||
! reCharsNotTagMisskey.matcher(src).find()
|
||||
} else {
|
||||
! reCharsNotTagMastodon.matcher(src).find()
|
||||
}
|
||||
|
||||
// https://mastodon.juggler.jp/tags/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%B0
|
||||
// あるサービスは /tags/... でなく /tag/... を使う
|
||||
private val reUrlHashTag = """\Ahttps://([^/]+)/tags?/([^?#・\s\-+.,:;/]+)(?:\z|[?#])"""
|
||||
.asciiPattern()
|
||||
|
||||
// https://pixelfed.tokyo/discover/tags/SubwayTooter?src=hash
|
||||
private val reUrlHashTagPixelfed =
|
||||
"""\Ahttps://([^/]+)/discover/tags/([^?#・\s\-+.,:;/]+)(?:\z|[?#])"""
|
||||
.asciiPattern()
|
||||
|
||||
// returns null or pair of ( decoded tag without sharp, host)
|
||||
fun String.findHashtagFromUrl() : Pair<String, String>? {
|
||||
var m = reUrlHashTag.matcher(this)
|
||||
if(m.find()) {
|
||||
val host = m.groupEx(1) !!
|
||||
val tag = m.groupEx(2) !!.decodePercent()
|
||||
return Pair(tag, host)
|
||||
}
|
||||
|
||||
m = reUrlHashTagPixelfed.matcher(this)
|
||||
if(m.find()) {
|
||||
val host = m.groupEx(1) !!
|
||||
val tag = m.groupEx(2) !!.decodePercent()
|
||||
return Pair(tag, host)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex, "parseListOrNull failed.")
|
||||
null
|
||||
}
|
||||
}?.notEmpty()
|
||||
|
||||
fun parseList(parser: TootParser, array: JsonArray?) =
|
||||
parseListOrNull(parser, array) ?: emptyList()
|
||||
|
||||
|
||||
private const val w = TootAccount.reRubyWord
|
||||
private const val a = TootAccount.reRubyAlpha
|
||||
private const val s = "_\\u00B7\\u200c" // separators
|
||||
|
||||
private fun generateMastodonTagPattern(): Pattern {
|
||||
val reMastodonTagName = """([_$w][$s$w]*[$s$a][$s$w]*[_$w])|([_$w]*[$a][_$w]*)"""
|
||||
return """(?:^|[^\w/)])#($reMastodonTagName)""".asciiPattern()
|
||||
}
|
||||
|
||||
private val reMastodonTag = generateMastodonTagPattern()
|
||||
|
||||
// https://medium.com/@alice/some-article#.abcdef123 => タグにならない
|
||||
// https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit => タグにならない
|
||||
// #aesthetic => #aesthetic
|
||||
// #3d => #3d
|
||||
// #l33ts35k => #l33ts35k
|
||||
// #world2016 => #world2016
|
||||
// #_test => #_test
|
||||
// #test_ => #test_
|
||||
// #one·two·three· => 末尾の・はタグに含まれない。#one·two·three までがハッシュタグになる。
|
||||
// #0123456' => 数字だけのハッシュタグはタグとして認識されない。
|
||||
// #000_000 => 認識される。orの前半分が機能してるらしい
|
||||
//
|
||||
|
||||
// タグに使えない文字
|
||||
// 入力補完用なのでやや緩め
|
||||
private val reCharsNotTagMastodon = """[^$s$w$a]""".asciiPattern()
|
||||
private val reCharsNotTagMisskey = """[\s.,!?'${'"'}:/\[\]【】]""".asciiPattern()
|
||||
|
||||
// find hashtags in content text(raw)
|
||||
// returns null if hashtags not found, or ArrayList of String (tag without #)
|
||||
fun findHashtags(src: String, isMisskey: Boolean): ArrayList<String>? =
|
||||
if (isMisskey) {
|
||||
MisskeyMarkdownDecoder.findHashtags(src)
|
||||
} else {
|
||||
var result: ArrayList<String>? = null
|
||||
val m = reMastodonTag.matcher(src)
|
||||
while (m.find()) {
|
||||
if (result == null) result = ArrayList()
|
||||
result.add(m.groupEx(1)!!)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun isValid(src: String, isMisskey: Boolean) =
|
||||
if (isMisskey) {
|
||||
!reCharsNotTagMisskey.matcher(src).find()
|
||||
} else {
|
||||
!reCharsNotTagMastodon.matcher(src).find()
|
||||
}
|
||||
|
||||
// https://mastodon.juggler.jp/tags/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%B0
|
||||
// あるサービスは /tags/... でなく /tag/... を使う
|
||||
private val reUrlHashTag = """\Ahttps://([^/]+)/tags?/([^?#・\s\-+.,:;/]+)(?:\z|[?#])"""
|
||||
.asciiPattern()
|
||||
|
||||
// https://pixelfed.tokyo/discover/tags/SubwayTooter?src=hash
|
||||
private val reUrlHashTagPixelfed =
|
||||
"""\Ahttps://([^/]+)/discover/tags/([^?#・\s\-+.,:;/]+)(?:\z|[?#])"""
|
||||
.asciiPattern()
|
||||
|
||||
// returns null or pair of ( decoded tag without sharp, host)
|
||||
fun String.findHashtagFromUrl(): Pair<String, String>? {
|
||||
var m = reUrlHashTag.matcher(this)
|
||||
if (m.find()) {
|
||||
val host = m.groupEx(1)!!
|
||||
val tag = m.groupEx(2)!!.decodePercent()
|
||||
return Pair(tag, host)
|
||||
}
|
||||
|
||||
m = reUrlHashTagPixelfed.matcher(this)
|
||||
if (m.find()) {
|
||||
val host = m.groupEx(1)!!
|
||||
val tag = m.groupEx(2)!!.decodePercent()
|
||||
return Pair(tag, host)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,11 +150,11 @@ class PushSubscriptionHelper(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSubscriptionMisskey(client: TootApiClient): TootApiResult? {
|
||||
private suspend fun updateSubscriptionMisskey(client: TootApiClient): TootApiResult? {
|
||||
|
||||
// 現在の購読状態を取得できないので、毎回購読の更新を行う
|
||||
// FCMのデバイスIDを取得
|
||||
val device_id = PollingWorker.getDeviceId(context)
|
||||
val device_id = PollingWorker.getFirebaseMessagingToken(context)
|
||||
?: return TootApiResult(error = context.getString(R.string.missing_fcm_device_id))
|
||||
|
||||
// アクセストークン
|
||||
@ -221,7 +221,7 @@ class PushSubscriptionHelper(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSubscriptionMastodon(client: TootApiClient, force: Boolean): TootApiResult? {
|
||||
private suspend fun updateSubscriptionMastodon(client: TootApiClient, force: Boolean): TootApiResult? {
|
||||
|
||||
// 現在の購読状態を取得
|
||||
// https://github.com/tootsuite/mastodon/pull/7471
|
||||
@ -293,7 +293,7 @@ class PushSubscriptionHelper(
|
||||
}
|
||||
|
||||
// FCMのデバイスIDを取得
|
||||
val device_id = PollingWorker.getDeviceId(context)
|
||||
val device_id = PollingWorker.getFirebaseMessagingToken(context)
|
||||
?: return TootApiResult(error = context.getString(R.string.missing_fcm_device_id))
|
||||
|
||||
// アクセストークン
|
||||
@ -508,7 +508,7 @@ class PushSubscriptionHelper(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSubscription(client: TootApiClient, force: Boolean = false): TootApiResult? =
|
||||
suspend fun updateSubscription(client: TootApiClient, force: Boolean = false): TootApiResult? =
|
||||
try {
|
||||
when {
|
||||
isRecentlyChecked() ->
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -15,25 +14,23 @@
|
||||
android:id="@+id/tvMoved"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="center"
|
||||
tools:text="aaa\@bbb さんは引っ越しました"
|
||||
/>
|
||||
tools:text="aaa\@bbb さんは引っ越しました" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llMoved"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
android:orientation="horizontal">
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
android:id="@+id/ivMoved"
|
||||
@ -49,33 +46,29 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMovedName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Follower Name"
|
||||
/>
|
||||
tools:text="Follower Name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMovedAcct"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:textSize="12sp"
|
||||
tools:text="aaaaaaaaaaaaaaaa"
|
||||
/>
|
||||
tools:text="aaaaaaaaaaaaaaaa" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="4dp"
|
||||
>
|
||||
android:layout_marginStart="4dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnMoved"
|
||||
@ -84,8 +77,7 @@
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:contentDescription="@string/follow"
|
||||
android:scaleType="center"
|
||||
tools:src="@drawable/ic_follow_plus"
|
||||
/>
|
||||
tools:src="@drawable/ic_follow_plus" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivMovedBy"
|
||||
@ -93,8 +85,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_followed_by"
|
||||
tools:ignore="ContentDescription"
|
||||
/>
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@ -104,20 +95,17 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textSize="12sp"
|
||||
tools:text="xxxx-xx-xx xx:xx:xx"
|
||||
/>
|
||||
tools:text="xxxx-xx-xx xx:xx:xx" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
android:id="@+id/ivBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llProfile"
|
||||
@ -125,16 +113,14 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
>
|
||||
android:padding="12dp">
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
android:id="@+id/ivAvatar"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
/>
|
||||
android:background="@drawable/btn_bg_transparent_round6dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDisplayName"
|
||||
@ -143,8 +129,7 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:textSize="20sp"
|
||||
tools:text="ディスプレイネームディスプレイネームディスプレイネーム"
|
||||
/>
|
||||
tools:text="ディスプレイネームディスプレイネームディスプレイネーム" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAcct"
|
||||
@ -154,32 +139,28 @@
|
||||
android:gravity="center"
|
||||
|
||||
android:textColor="?attr/colorLink"
|
||||
tools:text="\@fugahogehogera\@jugemujyugemugokounosurikire.jp"
|
||||
/>
|
||||
tools:text="\@fugahogehogera\@jugemujyugemugokounosurikire.jp" />
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyTextView
|
||||
android:id="@+id/tvNote"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
tools:text="説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 "
|
||||
/>
|
||||
tools:text="説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 " />
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyTextView
|
||||
android:id="@+id/tvMisskeyExtra"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
tools:text="説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 "
|
||||
/>
|
||||
tools:text="説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 " />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
>
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnFollow"
|
||||
@ -188,8 +169,7 @@
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:contentDescription="@string/follow"
|
||||
android:scaleType="center"
|
||||
tools:src="@drawable/ic_follow_plus"
|
||||
/>
|
||||
tools:src="@drawable/ic_follow_plus" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivFollowedBy"
|
||||
@ -197,61 +177,64 @@
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_followed_by"
|
||||
tools:ignore="ContentDescription"
|
||||
/>
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llFields"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:id="@+id/llFields"
|
||||
android:orientation="vertical"
|
||||
/>
|
||||
android:orientation="vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFeaturedTags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvLastStatusAt"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
tools:text="xxxx-xx-xx xx:xx:xx"
|
||||
/>
|
||||
tools:text="xxxx-xx-xx xx:xx:xx" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="start"
|
||||
android:text="@string/personal_notes"
|
||||
/>
|
||||
android:text="@string/personal_notes" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start|top"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPersonalNotes"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start"
|
||||
android:padding="12dp"
|
||||
android:text="@string/personal_notes"
|
||||
/>
|
||||
android:text="@string/personal_notes" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnPersonalNotesEdit"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:id="@+id/btnPersonalNotesEdit"
|
||||
android:src="@drawable/ic_edit"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:contentDescription="@string/edit"
|
||||
/>
|
||||
android:src="@drawable/ic_edit" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
@ -262,40 +245,35 @@
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:gravity="center"
|
||||
android:padding="12dp"
|
||||
android:text="@string/remote_profile_warning"
|
||||
/>
|
||||
android:text="@string/remote_profile_warning" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnStatusCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
tools:text="statuses\n124"
|
||||
/>
|
||||
tools:text="statuses\n124" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnFollowing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
tools:text="following\n9999"
|
||||
/>
|
||||
tools:text="following\n9999" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnFollowers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
tools:text="followers\n9999"
|
||||
/>
|
||||
tools:text="followers\n9999" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnMore"
|
||||
@ -304,10 +282,9 @@
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
android:contentDescription="@string/more"
|
||||
android:minWidth="48dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:src="@drawable/ic_more"
|
||||
/>
|
||||
android:paddingEnd="4dp"
|
||||
android:src="@drawable/ic_more" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -634,7 +634,7 @@
|
||||
<string name="always_show_application">Mostra (mitjançant) el nom de l\'aplicació, si és possible</string>
|
||||
<string name="force_gap_when_refresh">Forçar que s\'afegeixi una separació en refrescar la part superior</string>
|
||||
<string name="avatar_icon_size">Mida d\'icona d\'avatar (Unitat:dp. per defecte:48. cal reiniciar aplicació)</string>
|
||||
<string name="avatar_icon_round_ratio">Quocient d\'arrodoniment de la icona d\'avatar (Unitat:%. per defrecte:33. cal reiniciar aplicació)</string>
|
||||
<string name="avatar_icon_round_ratio">Quocient d\'arrodoniment de la icona d\'avatar (Unitat:%%. per defrecte:33. cal reiniciar aplicació)</string>
|
||||
<string name="avatar_icon_dont_round">No arrodonir els angles de la icona d\'avatar (cal reiniciar l\'aplicació)</string>
|
||||
<string name="share_view_pool">Comparteix la visualització entre pissarres</string>
|
||||
<string name="rename">Rebateja…</string>
|
||||
@ -821,7 +821,7 @@
|
||||
<string name="conversation_to">A:</string>
|
||||
<string name="use_quote_toot">Fer ús de \"Nota citada\"</string>
|
||||
<string name="mute_application_confirm">Vols silenciar l\'aplicació \"%1$s\"\?</string>
|
||||
<string name="boost_button_alpha">Augmenta l\'opacitat del botó de difusió (Unitat:%. cal reiniciar aplicació. també afecta al text de contingut alfa.)</string>
|
||||
<string name="boost_button_alpha">Augmenta l\'opacitat del botó de difusió (Unitat:%%. cal reiniciar aplicació. també afecta al text de contingut alfa.)</string>
|
||||
<string name="toot_background_color">Color de fons dels brams</string>
|
||||
<string name="column_color_default">Color per defecte de les pissarres</string>
|
||||
<string name="header_background_color">Color de fons de la capçalera</string>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_name">Subway Tooter</string>
|
||||
<string name="action_settings">Einstellungen</string>
|
||||
<string name="account_add">Konto hinzufügen</string>
|
||||
@ -321,7 +321,7 @@
|
||||
<string name="read_gap_head">Lese Kopfspalt</string>
|
||||
<string name="remote_only">Nur entfernt</string>
|
||||
<string name="featured">Promotet</string>
|
||||
<string name="announcements_period2">Ereignis-Zeitraum: %1$s...%2$s</string>
|
||||
<string name="announcements_period2">Ereignis-Zeitraum: %1$s…%2$s</string>
|
||||
<string name="announcements_period1">Ereignis-Zeitraum: %1$s</string>
|
||||
<string name="boost_with_visibility">Sichtbar boosten</string>
|
||||
<string name="hide_totals">Verberge die Summe bis zum Ablauf</string>
|
||||
@ -424,7 +424,7 @@
|
||||
<string name="notification_type_mention">Nennung</string>
|
||||
<string name="share_view_pool">Teile Anzeigenpool zwischen den Spalten</string>
|
||||
<string name="allow_column_duplication">Erlaube Verdoppelung von Spalten</string>
|
||||
<string name="avatar_icon_round_ratio">Abrundungsfaktor des Avatarbildes (Einheit: %. Standard: 33. App-Neustart erforderlich)</string>
|
||||
<string name="avatar_icon_round_ratio">Abrundungsfaktor des Avatarbildes (Einheit: %%. Standard: 33. App-Neustart erforderlich)</string>
|
||||
<string name="always_show_application">Zeige per App-Name, falls möglich</string>
|
||||
<string name="domain_block_from_local">Kann Domänen auf deinem Server nicht blockieren.</string>
|
||||
<string name="domain_block_from_pseudo">Kann Domäne nicht vom Pseudokonto aus blockieren.</string>
|
||||
@ -569,11 +569,11 @@
|
||||
<string name="endorse_set">In deinem Profil promoten</string>
|
||||
<string name="already_voted">Bereits abgestimmt.</string>
|
||||
<string name="toot_background_color">Hintergrundfarbe des Toots</string>
|
||||
<string name="boost_button_alpha">Deckkraft des Boost-Buttons (Einheit: %. App-Neustart erforderlich; wird auch von der Transparenz des Inhaltstextes beeinflusst)</string>
|
||||
<string name="boost_button_alpha">Deckkraft des Boost-Buttons (Einheit: %%. App-Neustart erforderlich; wird auch von der Transparenz des Inhaltstextes beeinflusst)</string>
|
||||
<string name="mute_application_confirm">App \"%1$s\" stummschalten\?</string>
|
||||
<string name="use_quote_toot">Benutze “Toot zitieren”. (Misskey oder individiualisierter Mastodonserver)</string>
|
||||
<string name="conversation_to">An:</string>
|
||||
<string name="participants_and_more">...und weitere</string>
|
||||
<string name="participants_and_more">…und weitere</string>
|
||||
<string name="participants">Teilnehmer:</string>
|
||||
<string name="show_conversation">Unterhaltung anzeigen</string>
|
||||
<string name="around_toot_limitation_warning">Das Feature \"Timeline um die angegebene Zeit herum\" ist auf Mastodonserver ab Version 2.6.0 beschränkt. Eine etwas neuere Timeline kann nicht abgerufen werden.</string>
|
||||
@ -982,7 +982,7 @@
|
||||
<string name="show_quick_toot_bar">Zeige „Schnell-Toot“-Leiste (App-Neustart erforderlich)</string>
|
||||
<string name="timeline_font_size">Schriftgröße der Timeline
|
||||
\n(Einheit: Skalierbare Pixel / SP. Leer lassen, um Standard zu benutzen. App-Neustart erforderlich)
|
||||
\n...
|
||||
\n…
|
||||
\n…</string>
|
||||
<string name="notification_sound">Benachrichtungston</string>
|
||||
<string name="open_local_timeline_for">Timeline von \"%1$s\" öffnen</string>
|
||||
@ -1007,7 +1007,7 @@
|
||||
<string name="blocked_domains">Blockierte Domains</string>
|
||||
<string name="url_omitted">(URL ausgelassen)</string>
|
||||
<string name="enable_speech">Aktiviert Sprachausgabe</string>
|
||||
<string name="account_change_failed_old_draft_has_no_in_reply_to_url">Konnte Konto nicht wechseln. Alte Entwurfsdaten besitzen kein in_reply_to_url, kann für gewählten Server nicht in in_reply_to_url umgewandelt werden.</string>
|
||||
<string name="account_change_failed_old_draft_has_no_in_reply_to_url" tools:ignore="Typos">Konnte Konto nicht wechseln. Alte Entwurfsdaten besitzen kein in_reply_to_url, kann für gewählten Server nicht in in_reply_to_url umgewandelt werden.</string>
|
||||
<string name="toot_button_default_account">Standardkonto, wenn der „Toot“-Button gedrückt wird</string>
|
||||
<string name="notification_on_off_desc">Es gibt auch eine Konteneinstellung, um Benachrichtigungen ein- und auszuschalten.</string>
|
||||
<string name="behavior">Verhalten</string>
|
||||
|
@ -602,7 +602,7 @@
|
||||
<string name="always_show_application">Afficher (via) le nom de l\'application si possible</string>
|
||||
<string name="force_gap_when_refresh">Forcer l’ajout d\'un espace lors du rafraîchissement du dessus</string>
|
||||
<string name="avatar_icon_size">Taille de l’icône de l’avatar (Unité:dp. par défaut:48. Redémarrage de l’app requis)</string>
|
||||
<string name="avatar_icon_round_ratio">Ratio de l’arrondi de l’icône de l’avatar (Unité:%. défaut:33. redémarrage de l\'application requis)</string>
|
||||
<string name="avatar_icon_round_ratio">Ratio de l’arrondi de l’icône de l’avatar (Unité:%%. défaut:33. redémarrage de l\'application requis)</string>
|
||||
<string name="avatar_icon_dont_round">Ne pas arrondir les coins de l’avatar (redémarrage requis)</string>
|
||||
<string name="share_view_pool">Partager le pool de vues entre les colonnes</string>
|
||||
<string name="rename">Renommer …</string>
|
||||
@ -849,7 +849,7 @@
|
||||
<string name="strip_icon_size">Taille de l’icône de la barre de colonne (Unité : dp. Défaut : 30. Redémarrage de l’application requis)</string>
|
||||
<string name="show_acct_in_system_notification">Afficher le compte (au lieu du nom d’utilisateur) dans les notifications système</string>
|
||||
<string name="account_tl_around">Fil public autour …</string>
|
||||
<string name="boost_button_alpha">Transparence du bouton Boost (Unité:%. redémarrage de l’app nécessaire. Affecte également la transparence du contenu texte.)</string>
|
||||
<string name="boost_button_alpha">Transparence du bouton Boost (Unité:%%. redémarrage de l’app nécessaire. Affecte également la transparence du contenu texte.)</string>
|
||||
<string name="move_notifications_quick_filter_to_column_setting">Afficher le filtre rapide des notifications dans la configuration de la colonne (redémarrage de l’app requis)</string>
|
||||
<string name="official_account">Compte officiel</string>
|
||||
<string name="releases">Sorties</string>
|
||||
|
@ -72,7 +72,7 @@
|
||||
<string name="auto_cw_prefix">(自動CW)</string>
|
||||
<string name="available_mastodon_2_4_later">(マストドン2.4以降で利用可能)</string>
|
||||
<string name="avatar_icon_dont_round">ユーザ画像を角丸にしない(アプリ再起動が必要)</string>
|
||||
<string name="avatar_icon_round_ratio">ユーザ画像の角丸率(単位:%。デフォルト:33。アプリ再起動が必要)</string>
|
||||
<string name="avatar_icon_round_ratio">ユーザ画像の角丸率(単位:%%。デフォルト:33。アプリ再起動が必要)</string>
|
||||
<string name="avatar_icon_size">ユーザ画像の大きさ(単位:dp。デフォルト:48。アプリ再起動が必要)</string>
|
||||
<string name="back_button_action">戻るボタンの動作</string>
|
||||
<string name="back_to_column_list">戻るボタンでカラム一覧を開く</string>
|
||||
@ -809,7 +809,7 @@
|
||||
<string name="conversation_to">送り先:</string>
|
||||
<string name="use_quote_toot">引用トゥートにする(MisskeyまたはカスタマイズされたMastodonサーバ)</string>
|
||||
<string name="mute_application_confirm">アプリ \"%1$s\" はミュートされます。よろしいですか?</string>
|
||||
<string name="boost_button_alpha">ブーストボタンのアルファ不透明度(単位:%。アプリの再起動が必要。本文テキスト色のアルファ値の影響も受けます)</string>
|
||||
<string name="boost_button_alpha">ブーストボタンのアルファ不透明度(単位:%%。アプリの再起動が必要。本文テキスト色のアルファ値の影響も受けます)</string>
|
||||
<string name="toot_background_color">トゥート背景色</string>
|
||||
<string name="unlisted_visibility">\'未収載\' 公開範囲</string>
|
||||
<string name="followers_visibility">\'フォロワーのみ\' 公開範囲</string>
|
||||
|
@ -611,7 +611,7 @@
|
||||
<string name="always_show_application">가능하면 (경유) 앱 이름 보이기</string>
|
||||
<string name="force_gap_when_refresh">위로 새로고침할 때 강제로 띄움 넣기</string>
|
||||
<string name="avatar_icon_size">아바타 아이콘 크기 (단위:dp. 기본값:48. 앱 재시작 필요)</string>
|
||||
<string name="avatar_icon_round_ratio">아바타 아이콘 곡률 (Unit:%. 기본값:33. 앱 재시작 필요)</string>
|
||||
<string name="avatar_icon_round_ratio">아바타 아이콘 곡률 (Unit:%%. 기본값:33. 앱 재시작 필요)</string>
|
||||
<string name="avatar_icon_dont_round">아바타 아이콘의 모서리를 둥글게 하지 않기 (앱 재시작 필요)</string>
|
||||
<string name="share_view_pool">칼럼 사이에 뷰 풀을 공유</string>
|
||||
<string name="rename">이름 변경…</string>
|
||||
@ -796,7 +796,7 @@
|
||||
<string name="conversation_to">받을 이:</string>
|
||||
<string name="use_quote_toot">\"인용 리노트\" 사용</string>
|
||||
<string name="mute_application_confirm">앱 \"%1$s\"를 음소거할까요\?</string>
|
||||
<string name="boost_button_alpha">부스트 버튼 알파 불투명도 (단위:%. 앱 재시작 필요. 본문의 알파에 영향을 미침.)</string>
|
||||
<string name="boost_button_alpha">부스트 버튼 알파 불투명도 (단위:%%. 앱 재시작 필요. 본문의 알파에 영향을 미침.)</string>
|
||||
<string name="toot_background_color">툿 배경색</string>
|
||||
<string name="column_color_default">칼럼 색 기본값</string>
|
||||
<string name="header_background_color">헤더 배경색</string>
|
||||
|
@ -678,7 +678,7 @@
|
||||
<string name="media_attachment_still_uploading">Media har ikke blitt lastet opp enda.</string>
|
||||
<string name="highlight_word">Framhev nøkkelord</string>
|
||||
<string name="avatar_icon_size">Avatarikonstørrelse (enhet:dp. Forvalg:48. Programomstart kreves)</string>
|
||||
<string name="avatar_icon_round_ratio">Avatarikonstørrelseforhold (enhet:%. Forvalg:33. Programomstart kreves)</string>
|
||||
<string name="avatar_icon_round_ratio">Avatarikonstørrelseforhold (enhet:%%. Forvalg:33. Programomstart kreves)</string>
|
||||
<string name="avatar_icon_dont_round">Ikke avrund avatarikonets hjørner (programomstart kreves)</string>
|
||||
<string name="allow_column_duplication">Tillat duplisering av kolonner</string>
|
||||
<string name="system_notification_not_related">Ikke valgt når systemmerknad trykkes</string>
|
||||
|
@ -621,7 +621,7 @@
|
||||
<string name="always_show_application">Show (via) application name if possible</string>
|
||||
<string name="force_gap_when_refresh">Force adding gap when refreshing top</string>
|
||||
<string name="avatar_icon_size">Avatar icon size (Unit:dp. default:48. app restart required)</string>
|
||||
<string name="avatar_icon_round_ratio">Avatar icon round ratio (Unit:%. default:33. app restart required)</string>
|
||||
<string name="avatar_icon_round_ratio">Avatar icon round ratio (Unit:%%. default:33. app restart required)</string>
|
||||
<string name="avatar_icon_dont_round">Don\'t round corner of avatar icon (app restart required)</string>
|
||||
<string name="share_view_pool">Share view pool between columns</string>
|
||||
<string name="rename">Rename…</string>
|
||||
@ -815,7 +815,7 @@
|
||||
<string name="conversation_to">To:</string>
|
||||
<string name="use_quote_toot">Use \"Quote Toot\". (Misskey or some customized Mastodon server)</string>
|
||||
<string name="mute_application_confirm">Mute the app \"%1$s\"?</string>
|
||||
<string name="boost_button_alpha">Boost button alpha opacity (Unit:%. app restart required. also affected of content text alpha.)</string>
|
||||
<string name="boost_button_alpha">Boost button alpha opacity (Unit:%%. app restart required. also affected of content text alpha.)</string>
|
||||
<string name="toot_background_color">Toot background color</string>
|
||||
<string name="column_color_default">Column color default</string>
|
||||
<string name="header_background_color">Header background color</string>
|
||||
|
@ -122,8 +122,8 @@ for my $lang ( sort keys %langs ){
|
||||
|
||||
# 残りの部分に%が登場したらエラー
|
||||
my $sv = $value;
|
||||
$sv =~ s/(%\d+\$[\d\.]*[sdxf])//g;
|
||||
if( $sv =~ /%/ && not $sv=~/:%/ ){
|
||||
$sv =~ s/(%\d+\$[\d\.]*[sdxf])|%%//g;
|
||||
if( $sv =~ /%/ ){
|
||||
$hasError =1;
|
||||
print "!! ($lang)$name : broken param: $sv // $value\n";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user