メンションの入力補完でIDNドメインを選択するとpunycodeを入力する。MMFパーサはデコード結果にIDNドメインを使う。

This commit is contained in:
tateisu 2020-02-04 06:14:40 +09:00
parent 36b86e4471
commit 6ae0ef4df9
5 changed files with 87 additions and 89 deletions

View File

@ -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,12 +765,12 @@ 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))
} }
// 元レスに含まれていたメンションを複製 // 元レスに含まれていたメンションを複製
@ -783,16 +784,9 @@ class ActPost : AppCompatActivity(),
// 自分なら追加しない // 自分なら追加しない
if(account.isMe(who_acct)) return@forEach if(account.isMe(who_acct)) return@forEach
// 既出なら追加しない // 既出でないなら追加する
val strMention = "@${account.getFullAcct(who_acct).pretty}" val acct = account.getFullAcct(who_acct)
if(mention_list.contains(strMention)) return@forEach if(! mention_list.contains(acct)) mention_list.add(acct)
mention_list.add(strMention)
/*
FIXME インスタンスのバージョンが3.1.0 以降ならメンションのホスト部分にIDNドメインを使いたいが
投稿画面でのアカウント切り替え時にタンスのバージョンが異なると破綻する可能性が高い
*/
} }
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

View File

@ -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,

View File

@ -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 shortAcct = when { val fullAcct = rawAcct.followHost(linkHelper.host)
host.isEmpty() || linkHelper.host?.match(host) == true -> username val shortAcct = if(fullAcct.host != linkHelper.host) {
fullAcct
else -> "$username@$host" } else {
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
) )

View File

@ -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 if(acct[0] == '@' && null != acct.find{ it >= 0x80.toChar() } ) {
// @user@host IDNドメインを含む
// 直後に空白を付与する
sb.append("@" + Acct.parse(acct.toString().substring(1)).ascii).append(" ")
}else{ }else{
// @user@host, #hashtag // @user@host
// #hashtag
// 直後に空白を付与する // 直後に空白を付与する
sb.append(acct).append(" ") sb.append(acct).append(" ")
} }