メンションの入力補完でIDNドメインを選択するとpunycodeを入力する。MMFパーサはデコード結果にIDNドメインを使う。
This commit is contained in:
parent
36b86e4471
commit
6ae0ef4df9
|
@ -744,7 +744,8 @@ class ActPost : AppCompatActivity(),
|
||||||
sv = intent.getStringExtra(KEY_REPLY_STATUS)
|
sv = intent.getStringExtra(KEY_REPLY_STATUS)
|
||||||
if(sv != null && account != null) {
|
if(sv != null && account != null) {
|
||||||
try {
|
try {
|
||||||
val reply_status = TootParser(this@ActPost, account).status(sv.decodeJsonObject())
|
val reply_status =
|
||||||
|
TootParser(this@ActPost, account).status(sv.decodeJsonObject())
|
||||||
|
|
||||||
val isQuoterRenote = intent.getBooleanExtra(KEY_QUOTED_RENOTE, false)
|
val isQuoterRenote = intent.getBooleanExtra(KEY_QUOTED_RENOTE, false)
|
||||||
|
|
||||||
|
@ -764,35 +765,28 @@ class ActPost : AppCompatActivity(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新しいメンションリスト
|
// 新しいメンションリスト
|
||||||
val mention_list = ArrayList<String>()
|
val mention_list = ArrayList<Acct>()
|
||||||
|
|
||||||
// 自己レス以外なら元レスへのメンションを追加
|
// 自己レス以外なら元レスへのメンションを追加
|
||||||
// 最初に追加する https://github.com/tateisu/SubwayTooter/issues/94
|
// 最初に追加する https://github.com/tateisu/SubwayTooter/issues/94
|
||||||
if(! account.isMe(reply_status.account)) {
|
if(! account.isMe(reply_status.account)) {
|
||||||
mention_list.add("@${account.getFullAcct(reply_status.account).pretty}")
|
mention_list.add(account.getFullAcct(reply_status.account))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 元レスに含まれていたメンションを複製
|
// 元レスに含まれていたメンションを複製
|
||||||
reply_status.mentions?.forEach { mention ->
|
reply_status.mentions?.forEach { mention ->
|
||||||
|
|
||||||
val who_acct = mention.acct
|
val who_acct = mention.acct
|
||||||
|
|
||||||
// 空データなら追加しない
|
// 空データなら追加しない
|
||||||
if( ! who_acct.isValid ) return@forEach
|
if(! who_acct.isValid) return@forEach
|
||||||
|
|
||||||
// 自分なら追加しない
|
// 自分なら追加しない
|
||||||
if(account.isMe(who_acct)) return@forEach
|
if(account.isMe(who_acct)) return@forEach
|
||||||
|
|
||||||
// 既出なら追加しない
|
|
||||||
val strMention = "@${account.getFullAcct(who_acct).pretty}"
|
|
||||||
if(mention_list.contains(strMention)) return@forEach
|
|
||||||
mention_list.add(strMention)
|
|
||||||
|
|
||||||
/*
|
|
||||||
FIXME インスタンスのバージョンが3.1.0 以降ならメンションのホスト部分にIDNドメインを使いたいが、
|
|
||||||
投稿画面でのアカウント切り替え時にタンスのバージョンが異なると破綻する可能性が高い。
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// 既出でないなら追加する
|
||||||
|
val acct = account.getFullAcct(who_acct)
|
||||||
|
if(! mention_list.contains(acct)) mention_list.add(acct)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mention_list.isNotEmpty()) {
|
if(mention_list.isNotEmpty()) {
|
||||||
|
@ -800,7 +794,7 @@ class ActPost : AppCompatActivity(),
|
||||||
StringBuilder().apply {
|
StringBuilder().apply {
|
||||||
for(acct in mention_list) {
|
for(acct in mention_list) {
|
||||||
if(isNotEmpty()) append(' ')
|
if(isNotEmpty()) append(' ')
|
||||||
append(acct)
|
append("@${acct.ascii}")
|
||||||
}
|
}
|
||||||
append(' ')
|
append(' ')
|
||||||
}.toString()
|
}.toString()
|
||||||
|
@ -852,7 +846,8 @@ class ActPost : AppCompatActivity(),
|
||||||
sv = intent.getStringExtra(KEY_REDRAFT_STATUS)
|
sv = intent.getStringExtra(KEY_REDRAFT_STATUS)
|
||||||
if(sv != null && account != null) {
|
if(sv != null && account != null) {
|
||||||
try {
|
try {
|
||||||
val base_status = TootParser(this@ActPost, account).status(sv.decodeJsonObject())
|
val base_status =
|
||||||
|
TootParser(this@ActPost, account).status(sv.decodeJsonObject())
|
||||||
if(base_status != null) {
|
if(base_status != null) {
|
||||||
|
|
||||||
redraft_status_id = base_status.id
|
redraft_status_id = base_status.id
|
||||||
|
@ -1060,12 +1055,12 @@ class ActPost : AppCompatActivity(),
|
||||||
|
|
||||||
val array = attachment_list
|
val array = attachment_list
|
||||||
// アップロード完了したものだけ保持する
|
// アップロード完了したものだけ保持する
|
||||||
.filter{it.status == PostAttachment.STATUS_UPLOADED }
|
.filter { it.status == PostAttachment.STATUS_UPLOADED }
|
||||||
.mapNotNull { it.attachment?.encodeJson() }
|
.mapNotNull { it.attachment?.encodeJson() }
|
||||||
.toJsonArray()
|
.toJsonArray()
|
||||||
.notEmpty()
|
.notEmpty()
|
||||||
|
|
||||||
if(array != null ) outState.putString(KEY_ATTACHMENT_LIST, array.toString())
|
if(array != null) outState.putString(KEY_ATTACHMENT_LIST, array.toString())
|
||||||
|
|
||||||
in_reply_to_id?.putTo(outState, KEY_IN_REPLY_TO_ID)
|
in_reply_to_id?.putTo(outState, KEY_IN_REPLY_TO_ID)
|
||||||
outState.putString(KEY_IN_REPLY_TO_TEXT, in_reply_to_text)
|
outState.putString(KEY_IN_REPLY_TO_TEXT, in_reply_to_text)
|
||||||
|
@ -1511,7 +1506,7 @@ class ActPost : AppCompatActivity(),
|
||||||
) { ai ->
|
) { ai ->
|
||||||
|
|
||||||
// 別タンスのアカウントに変更したならならin_reply_toの変換が必要
|
// 別タンスのアカウントに変更したならならin_reply_toの変換が必要
|
||||||
if(in_reply_to_id != null && ! ai.matchHost(account?.host) ) {
|
if(in_reply_to_id != null && ! ai.matchHost(account?.host)) {
|
||||||
startReplyConversion(ai)
|
startReplyConversion(ai)
|
||||||
} else {
|
} else {
|
||||||
setAccountWithVisibilityConversion(ai)
|
setAccountWithVisibilityConversion(ai)
|
||||||
|
@ -2672,7 +2667,7 @@ class ActPost : AppCompatActivity(),
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val tmp_attachment_list = attachment_list
|
val tmp_attachment_list = attachment_list
|
||||||
.mapNotNull{it.attachment?.encodeJson()}
|
.mapNotNull { it.attachment?.encodeJson() }
|
||||||
.toJsonArray()
|
.toJsonArray()
|
||||||
|
|
||||||
val json = JsonObject()
|
val json = JsonObject()
|
||||||
|
|
|
@ -632,7 +632,9 @@ object Action_User {
|
||||||
|
|
||||||
// メンションを含むトゥートを作る
|
// メンションを含むトゥートを作る
|
||||||
private fun mention(
|
private fun mention(
|
||||||
activity : ActMain, account : SavedAccount, initial_text : String
|
activity : ActMain,
|
||||||
|
account : SavedAccount,
|
||||||
|
initial_text : String
|
||||||
) {
|
) {
|
||||||
ActPost.open(
|
ActPost.open(
|
||||||
activity,
|
activity,
|
||||||
|
@ -646,7 +648,7 @@ object Action_User {
|
||||||
fun mention(
|
fun mention(
|
||||||
activity : ActMain, account : SavedAccount, who : TootAccount
|
activity : ActMain, account : SavedAccount, who : TootAccount
|
||||||
) {
|
) {
|
||||||
mention(activity, account, "@${account.getFullAcct(who).pretty} ")
|
mention(activity, account, "@${account.getFullAcct(who).ascii} ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// メンションを含むトゥートを作る
|
// メンションを含むトゥートを作る
|
||||||
|
@ -656,7 +658,7 @@ object Action_User {
|
||||||
if(who == null) return
|
if(who == null) return
|
||||||
val who_host = who.host
|
val who_host = who.host
|
||||||
|
|
||||||
val initial_text = "@${access_info.getFullAcct(who).pretty} "
|
val initial_text = "@${access_info.getFullAcct(who).ascii} "
|
||||||
AccountPicker.pick(
|
AccountPicker.pick(
|
||||||
activity,
|
activity,
|
||||||
bAllowPseudo = false,
|
bAllowPseudo = false,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.util.concurrent.ConcurrentHashMap
|
||||||
class Host private constructor(
|
class Host private constructor(
|
||||||
val ascii : String,
|
val ascii : String,
|
||||||
val pretty : String = ascii
|
val pretty : String = ascii
|
||||||
) :Comparable<Host>{
|
) : Comparable<Host> {
|
||||||
|
|
||||||
override fun toString() : String = ascii
|
override fun toString() : String = ascii
|
||||||
|
|
||||||
|
@ -16,28 +16,28 @@ class Host private constructor(
|
||||||
ascii.hashCode()
|
ascii.hashCode()
|
||||||
|
|
||||||
override fun equals(other : Any?) : Boolean =
|
override fun equals(other : Any?) : Boolean =
|
||||||
if( other is Host) ascii==other.ascii else false
|
if(other is Host) ascii == other.ascii else false
|
||||||
|
|
||||||
// ソートはprettyのコード順
|
// ソートはprettyのコード順
|
||||||
override fun compareTo(other : Host) : Int =
|
override fun compareTo(other : Host) : Int =
|
||||||
pretty.compareTo(other.pretty).notZero() ?: ascii.compareTo(other.ascii)
|
pretty.compareTo(other.pretty).notZero() ?: ascii.compareTo(other.ascii)
|
||||||
|
|
||||||
fun match(src : String?) : Boolean =
|
fun match(src : String?) : Boolean =
|
||||||
ascii==src || pretty ==src
|
ascii == src || pretty == src
|
||||||
|
|
||||||
val isValid :Boolean
|
val isValid : Boolean
|
||||||
get() = ascii.isNotEmpty() && ascii != "?"
|
get() = ascii.isNotEmpty() && ascii != "?"
|
||||||
|
|
||||||
fun valid() : Host? = if(isValid ) this else null
|
fun valid() : Host? = if(isValid) this else null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// declare this first!
|
// declare this first!
|
||||||
private val hostSet = ConcurrentHashMap<String, Host>()
|
private val hostSet = ConcurrentHashMap<String, Host>()
|
||||||
|
|
||||||
val EMPTY = Host("")
|
val EMPTY = Host("")
|
||||||
val UNKNOWN = Host("?")
|
val UNKNOWN = Host("?")
|
||||||
val FRIENDS_NICO = Host("friends.nico")
|
val FRIENDS_NICO = Host("friends.nico")
|
||||||
|
|
||||||
fun parse(src : String) : Host {
|
fun parse(src : String) : Host {
|
||||||
val cached = hostSet[src]
|
val cached = hostSet[src]
|
||||||
if(cached != null) return cached
|
if(cached != null) return cached
|
||||||
|
@ -53,17 +53,17 @@ class Host private constructor(
|
||||||
class Acct private constructor(
|
class Acct private constructor(
|
||||||
val username : String,
|
val username : String,
|
||||||
val host : Host?
|
val host : Host?
|
||||||
) :Comparable<Acct>{
|
) : Comparable<Acct> {
|
||||||
|
|
||||||
val ascii:String = if(host==null) username else "$username@${host.ascii}"
|
val ascii : String = if(host == null) username else "$username@${host.ascii}"
|
||||||
val pretty:String = if(host==null) username else "$username@${host.pretty}"
|
val pretty : String = if(host == null) username else "$username@${host.pretty}"
|
||||||
|
|
||||||
override fun toString() : String = ascii
|
override fun toString() : String = ascii
|
||||||
|
|
||||||
override fun hashCode() : Int = ascii.hashCode()
|
override fun hashCode() : Int = ascii.hashCode()
|
||||||
|
|
||||||
override fun equals(other : Any?) : Boolean =
|
override fun equals(other : Any?) : Boolean =
|
||||||
if( other is Acct) ascii == other.ascii else false
|
if(other is Acct) ascii == other.ascii else false
|
||||||
|
|
||||||
// ソートはprettyのコード順
|
// ソートはprettyのコード順
|
||||||
override fun compareTo(other : Acct) : Int {
|
override fun compareTo(other : Acct) : Int {
|
||||||
|
@ -71,45 +71,45 @@ class Acct private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun followHost(accessHost : Host?) : Acct {
|
fun followHost(accessHost : Host?) : Acct {
|
||||||
return if( this.host != null) this else Acct(username,accessHost)
|
return if(this.host != null) this else Acct(username, accessHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isValid : Boolean
|
val isValid : Boolean
|
||||||
get() = username.isNotEmpty() && username != "?" && (host?.isValid != false)
|
get() = username.isNotEmpty() && username != "?" && (host?.isValid != false)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
private fun valid():Acct? = if(isValid) this else null
|
private fun valid() : Acct? = if(isValid) this else null
|
||||||
|
|
||||||
private val isValidFull : Boolean
|
private val isValidFull : Boolean
|
||||||
get() = username.isNotEmpty() && username != "?" && (host?.isValid == true)
|
get() = username.isNotEmpty() && username != "?" && (host?.isValid == true)
|
||||||
|
|
||||||
fun validFull():Acct ? = if(isValidFull) this else null
|
fun validFull() : Acct? = if(isValidFull) this else null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// declare this first!
|
// declare this first!
|
||||||
private val acctSet = ConcurrentHashMap<String, Acct>()
|
private val acctSet = ConcurrentHashMap<String, Acct>()
|
||||||
|
|
||||||
val UNKNOWN = Acct("?",Host.UNKNOWN)
|
val UNKNOWN = Acct("?", Host.UNKNOWN)
|
||||||
|
|
||||||
fun parse(src : String) : Acct {
|
fun parse(src : String) : Acct {
|
||||||
val cached = acctSet[src]
|
val cached = acctSet[src]
|
||||||
if(cached != null) return cached
|
if(cached != null) return cached
|
||||||
|
|
||||||
if( src.isEmpty()) return UNKNOWN
|
if(src.isEmpty()) return UNKNOWN
|
||||||
|
|
||||||
val pos = src.indexOf('@')
|
val pos = src.indexOf('@')
|
||||||
val acct = if(pos != - 1)
|
val acct = if(pos != - 1)
|
||||||
Acct(src.substring(0, pos), Host.parse(src.substring(pos + 1)))
|
Acct(src.substring(0, pos), Host.parse(src.substring(pos + 1)))
|
||||||
else
|
else
|
||||||
Acct(src, null)
|
Acct(src, null)
|
||||||
|
|
||||||
acctSet[src] = acct
|
acctSet[src] = acct
|
||||||
return acct
|
return acct
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parse(user : String,host:String?) =
|
fun parse(user : String, host : String?) =
|
||||||
if(host != null) parse("$user@$host") else parse(user)
|
if(host != null) parse("$user@$host") else parse(user)
|
||||||
|
|
||||||
fun parse(user : String,host:Host?) =Acct(user,host)
|
fun parse(user : String, host : Host?) = Acct(user, host)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,9 +12,12 @@ import android.text.style.StrikethroughSpan
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.util.SparseBooleanArray
|
import android.util.SparseBooleanArray
|
||||||
import jp.juggler.subwaytooter.ActMain
|
import jp.juggler.subwaytooter.ActMain
|
||||||
|
import jp.juggler.subwaytooter.Pref
|
||||||
import jp.juggler.subwaytooter.R
|
import jp.juggler.subwaytooter.R
|
||||||
import jp.juggler.subwaytooter.api.entity.TootAccount
|
import jp.juggler.subwaytooter.api.entity.TootAccount
|
||||||
import jp.juggler.subwaytooter.api.entity.TootMention
|
import jp.juggler.subwaytooter.api.entity.TootMention
|
||||||
|
import jp.juggler.subwaytooter.api.entity.Acct
|
||||||
|
import jp.juggler.subwaytooter.api.entity.Host
|
||||||
import jp.juggler.subwaytooter.span.*
|
import jp.juggler.subwaytooter.span.*
|
||||||
import jp.juggler.subwaytooter.table.AcctColor
|
import jp.juggler.subwaytooter.table.AcctColor
|
||||||
import jp.juggler.subwaytooter.table.HighlightWord
|
import jp.juggler.subwaytooter.table.HighlightWord
|
||||||
|
@ -844,38 +847,25 @@ object MisskeyMarkdownDecoder {
|
||||||
|
|
||||||
MENTION({
|
MENTION({
|
||||||
val username = it.args[0]
|
val username = it.args[0]
|
||||||
val host = it.args[1]
|
val strHost = it.args[1].notEmpty()
|
||||||
|
val rawAcct = Acct.parse(username, strHost?.let{ Host.parse(it)})
|
||||||
val linkHelper = linkHelper
|
val linkHelper = linkHelper
|
||||||
if(linkHelper == null) {
|
if(linkHelper == null) {
|
||||||
appendText(
|
appendText("@${rawAcct.pretty}")
|
||||||
when {
|
|
||||||
host.isEmpty() -> "@$username"
|
|
||||||
else -> "@$username@$host"
|
|
||||||
}
|
|
||||||
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
|
when( strHost ){
|
||||||
when(
|
|
||||||
val userHost = (host.notEmpty()
|
|
||||||
?: linkHelper.host?.ascii
|
|
||||||
?: "?"
|
|
||||||
).toLowerCase(Locale.JAPAN)
|
|
||||||
) {
|
|
||||||
|
|
||||||
// https://github.com/syuilo/misskey/pull/3603
|
// https://github.com/syuilo/misskey/pull/3603
|
||||||
|
|
||||||
"github.com", "twitter.com" -> {
|
"github.com", "twitter.com" -> {
|
||||||
appendLink(
|
appendLink(
|
||||||
"@$username@$userHost",
|
"@${rawAcct.pretty}",
|
||||||
"https://$userHost/$username" // no @
|
"https://$strHost/$username" // no @
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"gmail.com" -> {
|
"gmail.com" -> {
|
||||||
appendLink(
|
appendLink(
|
||||||
"@$username@$userHost",
|
"@${rawAcct.pretty}",
|
||||||
"mailto:$username@$userHost"
|
"mailto:$username@$strHost"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,23 +873,25 @@ object MisskeyMarkdownDecoder {
|
||||||
// MFMはメンションからユーザのURIを調べる正式な方法がない
|
// MFMはメンションからユーザのURIを調べる正式な方法がない
|
||||||
// たとえば @group_dev_jp@gup.pe の正式なURLは https://gup.pe/u/group_dev_jp
|
// たとえば @group_dev_jp@gup.pe の正式なURLは https://gup.pe/u/group_dev_jp
|
||||||
// だが、 misskey.io ではメンションのリンク先は https://misskey.io/@group_dev_jp@gup.pe になる
|
// だが、 misskey.io ではメンションのリンク先は https://misskey.io/@group_dev_jp@gup.pe になる
|
||||||
val userUrl = "https://$userHost/@$username"
|
|
||||||
|
val fullAcct = rawAcct.followHost(linkHelper.host)
|
||||||
val shortAcct = when {
|
|
||||||
|
val shortAcct = if(fullAcct.host != linkHelper.host) {
|
||||||
host.isEmpty() || linkHelper.host?.match(host) == true -> username
|
fullAcct
|
||||||
|
} else {
|
||||||
else -> "$username@$host"
|
Acct.parse(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val userUrl = "https://${fullAcct.ascii}/@${username.encodePercent()}"
|
||||||
|
|
||||||
val mentions = prepareMentions()
|
val mentions = prepareMentions()
|
||||||
|
|
||||||
if(null == mentions.find { m -> m.acct.ascii == shortAcct || m.acct.pretty == shortAcct }) {
|
if(null == mentions.find { m -> m.acct == shortAcct }) {
|
||||||
mentions.add(
|
mentions.add(
|
||||||
TootMention(
|
TootMention(
|
||||||
jp.juggler.subwaytooter.api.entity.EntityId.DEFAULT
|
jp.juggler.subwaytooter.api.entity.EntityId.DEFAULT
|
||||||
, userUrl
|
, userUrl
|
||||||
, shortAcct
|
, shortAcct.ascii
|
||||||
, username
|
, username
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -907,9 +899,11 @@ object MisskeyMarkdownDecoder {
|
||||||
|
|
||||||
appendLink(
|
appendLink(
|
||||||
when {
|
when {
|
||||||
jp.juggler.subwaytooter.Pref.bpMentionFullAcct(jp.juggler.subwaytooter.App1.pref) ->
|
Pref.bpMentionFullAcct(jp.juggler.subwaytooter.App1.pref) ->
|
||||||
"@$username@$userHost"
|
"@${fullAcct.pretty}"
|
||||||
else -> "@$shortAcct"
|
else -> {
|
||||||
|
"@${rawAcct.pretty}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
, userUrl
|
, userUrl
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,12 +15,14 @@ import android.widget.LinearLayout
|
||||||
import android.widget.PopupWindow
|
import android.widget.PopupWindow
|
||||||
import jp.juggler.subwaytooter.Pref
|
import jp.juggler.subwaytooter.Pref
|
||||||
import jp.juggler.subwaytooter.R
|
import jp.juggler.subwaytooter.R
|
||||||
|
import jp.juggler.subwaytooter.api.entity.Acct
|
||||||
import jp.juggler.subwaytooter.view.MyEditText
|
import jp.juggler.subwaytooter.view.MyEditText
|
||||||
import jp.juggler.util.LogCategory
|
import jp.juggler.util.LogCategory
|
||||||
import jp.juggler.util.getAttributeColor
|
import jp.juggler.util.getAttributeColor
|
||||||
import jp.juggler.util.groupEx
|
import jp.juggler.util.groupEx
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
internal class PopupAutoCompleteAcct(
|
internal class PopupAutoCompleteAcct(
|
||||||
|
@ -135,8 +137,8 @@ internal class PopupAutoCompleteAcct(
|
||||||
val sb = SpannableStringBuilder()
|
val sb = SpannableStringBuilder()
|
||||||
|
|
||||||
val src_length = editable.length
|
val src_length = editable.length
|
||||||
start = Math.min(src_length, sel_start)
|
start = min(src_length, sel_start)
|
||||||
val end = Math.min(src_length, sel_end)
|
val end = min(src_length, sel_end)
|
||||||
sb.append(editable.subSequence(0, start))
|
sb.append(editable.subSequence(0, start))
|
||||||
val remain = editable.subSequence(end, src_length)
|
val remain = editable.subSequence(end, src_length)
|
||||||
|
|
||||||
|
@ -147,8 +149,13 @@ internal class PopupAutoCompleteAcct(
|
||||||
sb.append(findShortCode(acct.toString()))
|
sb.append(findShortCode(acct.toString()))
|
||||||
// セパレータにZWSPを使う設定なら、補完した次の位置にもZWSPを追加する。連続して入力補完できるようになる。
|
// セパレータにZWSPを使う設定なら、補完した次の位置にもZWSPを追加する。連続して入力補完できるようになる。
|
||||||
if( separator != ' ') sb.append(separator)
|
if( separator != ' ') sb.append(separator)
|
||||||
} else {
|
} else if(acct[0] == '@' && null != acct.find{ it >= 0x80.toChar() } ) {
|
||||||
// @user@host, #hashtag
|
// @user@host IDNドメインを含む
|
||||||
|
// 直後に空白を付与する
|
||||||
|
sb.append("@" + Acct.parse(acct.toString().substring(1)).ascii).append(" ")
|
||||||
|
}else{
|
||||||
|
// @user@host
|
||||||
|
// #hashtag
|
||||||
// 直後に空白を付与する
|
// 直後に空白を付与する
|
||||||
sb.append(acct).append(" ")
|
sb.append(acct).append(" ")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue