From 0201e0027f2ee22d2cf0f2872ccac25a0d548785 Mon Sep 17 00:00:00 2001 From: tateisu Date: Sat, 1 Feb 2020 20:38:38 +0900 Subject: [PATCH] =?UTF-8?q?=E3=82=A2=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E6=99=82=E3=81=AE=E3=82=B5=E3=83=BC=E3=83=90?= =?UTF-8?q?=E5=90=8D=E5=85=A5=E5=8A=9B=E3=81=A7IDN=E3=83=89=E3=83=A1?= =?UTF-8?q?=E3=82=A4=E3=83=B3=E3=82=92=E5=85=A5=E5=8A=9B=E8=A3=9C=E5=AE=8C?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=80=82=E3=82=AB=E3=83=A9=E3=83=A0=E3=83=98?= =?UTF-8?q?=E3=83=83=E3=83=80=E3=81=ABprettyAcct=E3=82=92=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=99=E3=82=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../juggler/subwaytooter/ColumnViewHolder.kt | 2 +- .../juggler/subwaytooter/dialog/LoginForm.kt | 58 ++++++++++--------- .../subwaytooter/table/SavedAccount.kt | 6 ++ app/src/main/res/raw/server_list.txt | 1 + .../java/jp/juggler/subwaytooter/TestIDN.kt | 28 +++++++++ 5 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 app/src/test/java/jp/juggler/subwaytooter/TestIDN.kt 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