diff --git a/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.kt b/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.kt index d5a4d6ca..794b77b2 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.kt @@ -1178,7 +1178,7 @@ class ColumnViewHolder( tvColumnContext.text = if(nickname != null && nickname.isNotEmpty()) nickname else - acct + column.access_info.prettyAcct tvColumnContext.setTextColor( diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/LoginForm.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/LoginForm.kt index 812b2d8b..5a45986b 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/dialog/LoginForm.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/LoginForm.kt @@ -14,6 +14,7 @@ import jp.juggler.util.LogCategory import jp.juggler.util.showToast import java.io.BufferedReader import java.io.InputStreamReader +import java.net.IDN import java.util.* object LoginForm { @@ -111,31 +112,35 @@ object LoginForm { showToast(activity, true, R.string.instance_not_need_slash) else -> { + val instanceAscii = IDN.toASCII(instance,IDN.ALLOW_UNASSIGNED) val actionPos = spAction.selectedItemPosition when(val action = Action.values().find { it.pos == actionPos }) { null -> { } // will no happened - else -> onClickOk(dialog, instance, action) + else -> onClickOk(dialog, instanceAscii, action) } } } } view.findViewById(R.id.btnCancel).setOnClickListener { dialog.cancel() } - val instance_list = ArrayList() - try { - activity.resources.openRawResource(R.raw.server_list).use { inStream -> - val br = BufferedReader(InputStreamReader(inStream, "UTF-8")) - while(true) { - val s : String = - br.readLine()?.trim { it <= ' ' }?.toLowerCase(Locale.JAPAN) ?: break - if(s.isNotEmpty()) instance_list.add(s) + val instance_list = HashSet().apply{ + try { + activity.resources.openRawResource(R.raw.server_list).use { inStream -> + val br = BufferedReader(InputStreamReader(inStream, "UTF-8")) + while(true) { + val s : String = + br.readLine()?.trim { it <= ' ' }?.toLowerCase(Locale.JAPAN) ?: break + if(s.isEmpty()) continue + add(s) + add(IDN.toASCII(s,IDN.ALLOW_UNASSIGNED)) + add(IDN.toUnicode(s,IDN.ALLOW_UNASSIGNED)) + } } + } catch(ex : Throwable) { + log.trace(ex) } - instance_list.sort() - } catch(ex : Throwable) { - log.trace(ex) - } + }.toList().sorted() val adapter = object : ArrayAdapter( activity, R.layout.lv_spinner_dropdown, ArrayList() @@ -146,23 +151,22 @@ object LoginForm { return value as String } - override fun performFiltering(constraint : CharSequence?) : FilterResults { - val result = FilterResults() - if(constraint?.isNotEmpty() == true) { - val key = constraint.toString().toLowerCase(Locale.JAPAN) - // suggestions リストは毎回生成する必要がある。publishResultsと同時にアクセスされる場合がある - val suggestions = StringArray() - for(s in instance_list) { - if(s.contains(key)) { - suggestions.add(s) - if(suggestions.size >= 20) break + override fun performFiltering(constraint : CharSequence?) : FilterResults = + FilterResults().also { result -> + if(constraint?.isNotEmpty() == true) { + val key = constraint.toString().toLowerCase(Locale.JAPAN) + // suggestions リストは毎回生成する必要がある。publishResultsと同時にアクセスされる場合がある + val suggestions = StringArray() + for(s in instance_list) { + if(s.contains(key)) { + suggestions.add(s) + if(suggestions.size >= 20) break + } } + result.values = suggestions + result.count = suggestions.size } - result.values = suggestions - result.count = suggestions.size } - return result - } override fun publishResults( constraint : CharSequence?, diff --git a/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt b/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt index 4229f70b..40332422 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt @@ -16,6 +16,7 @@ import jp.juggler.subwaytooter.api.entity.TootNotification import jp.juggler.subwaytooter.api.entity.TootVisibility import jp.juggler.subwaytooter.util.LinkHelper import jp.juggler.util.* +import java.net.IDN import java.util.* import java.util.regex.Pattern @@ -69,13 +70,18 @@ class SavedAccount( var last_subscription_error : String? = null var last_push_endpoint : String? = null + val prettyAcct :String + init { val pos = acct.indexOf('@') if(pos == - 1) { this.username = acct + prettyAcct = acct } else { this.username = acct.substring(0, pos) + prettyAcct = username+"@"+IDN.toUnicode(acct.substring(pos+1),IDN.ALLOW_UNASSIGNED) } + if(username.isEmpty()) throw RuntimeException("missing username in acct") this.host = if(hostArg != null && hostArg.isNotEmpty()) { diff --git a/app/src/main/res/raw/server_list.txt b/app/src/main/res/raw/server_list.txt index 7fada83d..0ec61847 100644 --- a/app/src/main/res/raw/server_list.txt +++ b/app/src/main/res/raw/server_list.txt @@ -10073,3 +10073,4 @@ zuyadon.tk zwitscher.l-uni.co zxc.st zzz.cat +xn--3-pfuzbe6htf.juggler.jp diff --git a/app/src/test/java/jp/juggler/subwaytooter/TestIDN.kt b/app/src/test/java/jp/juggler/subwaytooter/TestIDN.kt new file mode 100644 index 00000000..25556c62 --- /dev/null +++ b/app/src/test/java/jp/juggler/subwaytooter/TestIDN.kt @@ -0,0 +1,28 @@ +package jp.juggler.subwaytooter + +import org.junit.Test +import java.net.IDN +import kotlin.test.assertEquals + +class TestIDN { + + @Test + @Throws(Exception::class) + fun testIDN() { + // normal conversion + assertEquals("xn--3-pfuzbe6htf.juggler.jp", IDN.toASCII("マストドン3.juggler.jp",IDN.ALLOW_UNASSIGNED)) + assertEquals("マストドン3.juggler.jp", IDN.toUnicode("xn--3-pfuzbe6htf.juggler.jp",IDN.ALLOW_UNASSIGNED)) + + // not IDN domain + assertEquals("mastodon.juggler.jp", IDN.toASCII("mastodon.juggler.jp",IDN.ALLOW_UNASSIGNED)) + assertEquals("mastodon.juggler.jp", IDN.toUnicode("mastodon.juggler.jp",IDN.ALLOW_UNASSIGNED)) + + // 既に変換済みの引数 + assertEquals("xn--3-pfuzbe6htf.juggler.jp", IDN.toASCII("xn--3-pfuzbe6htf.juggler.jp",IDN.ALLOW_UNASSIGNED)) + assertEquals("マストドン3.juggler.jp", IDN.toUnicode("マストドン3.juggler.jp",IDN.ALLOW_UNASSIGNED)) + + // 複数のpunycode + assertEquals("թութ.հայ", IDN.toUnicode("xn--69aa8bzb.xn--y9a3aq",IDN.ALLOW_UNASSIGNED)) + + } +} \ No newline at end of file