improve IDN domain support
This commit is contained in:
parent
9b696c60f1
commit
23fb9cec43
|
@ -119,7 +119,6 @@ class ActAccountSetting
|
||||||
|
|
||||||
private lateinit var tvUserCustom : TextView
|
private lateinit var tvUserCustom : TextView
|
||||||
private lateinit var btnUserCustom : View
|
private lateinit var btnUserCustom : View
|
||||||
private lateinit var full_acct : String
|
|
||||||
|
|
||||||
private lateinit var btnNotificationSoundEdit : Button
|
private lateinit var btnNotificationSoundEdit : Button
|
||||||
private lateinit var btnNotificationSoundReset : Button
|
private lateinit var btnNotificationSoundReset : Button
|
||||||
|
@ -173,13 +172,13 @@ class ActAccountSetting
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.account = a
|
|
||||||
|
|
||||||
loadUIFromData(account)
|
|
||||||
|
loadUIFromData(a)
|
||||||
|
|
||||||
initializeProfile()
|
initializeProfile()
|
||||||
|
|
||||||
btnOpenBrowser.text = getString(R.string.open_instance_website, account.host)
|
btnOpenBrowser.text = getString(R.string.open_instance_website, account.hostAscii)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
@ -443,11 +442,10 @@ class ActAccountSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadUIFromData(a : SavedAccount) {
|
private fun loadUIFromData(a : SavedAccount) {
|
||||||
|
this.account = a
|
||||||
|
|
||||||
this.full_acct = a.acct
|
tvInstance.text = a.hostPretty
|
||||||
|
tvUser.text = a.acctPretty
|
||||||
tvInstance.text = a.host
|
|
||||||
tvUser.text = a.acct
|
|
||||||
|
|
||||||
this.visibility = a.visibility
|
this.visibility = a.visibility
|
||||||
|
|
||||||
|
@ -518,9 +516,10 @@ class ActAccountSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAcctColor() {
|
private fun showAcctColor() {
|
||||||
val ac = AcctColor.load(full_acct)
|
val sa = this.account
|
||||||
|
val ac = AcctColor.load(sa.acctAscii)
|
||||||
tvUserCustom.backgroundColor = ac.color_bg
|
tvUserCustom.backgroundColor = ac.color_bg
|
||||||
tvUserCustom.text = ac.nickname?.notEmpty() ?: full_acct
|
tvUserCustom.text = ac.nickname?.notEmpty() ?: sa.acctPretty
|
||||||
tvUserCustom.textColor = ac.color_fg.notZero()
|
tvUserCustom.textColor = ac.color_fg.notZero()
|
||||||
?: getAttributeColor(this, R.attr.colorTimeSmall)
|
?: getAttributeColor(this, R.attr.colorTimeSmall)
|
||||||
}
|
}
|
||||||
|
@ -584,13 +583,14 @@ class ActAccountSetting
|
||||||
R.id.btnVisibility -> performVisibility()
|
R.id.btnVisibility -> performVisibility()
|
||||||
R.id.btnOpenBrowser -> App1.openBrowser(
|
R.id.btnOpenBrowser -> App1.openBrowser(
|
||||||
this@ActAccountSetting,
|
this@ActAccountSetting,
|
||||||
"https://" + account.host + "/"
|
"https://" + account.hostAscii + "/"
|
||||||
)
|
)
|
||||||
R.id.btnPushSubscription -> startTest()
|
R.id.btnPushSubscription -> startTest()
|
||||||
|
|
||||||
R.id.btnUserCustom -> ActNickname.open(
|
R.id.btnUserCustom -> ActNickname.open(
|
||||||
this,
|
this,
|
||||||
full_acct,
|
account.acctAscii,
|
||||||
|
account.acctPretty,
|
||||||
false,
|
false,
|
||||||
REQUEST_CODE_ACCT_CUSTOMIZE
|
REQUEST_CODE_ACCT_CUSTOMIZE
|
||||||
)
|
)
|
||||||
|
@ -764,7 +764,7 @@ class ActAccountSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
val call = App1.ok_http_client.newCall(
|
val call = App1.ok_http_client.newCall(
|
||||||
("instance_url=" + ("https://" + account.host).encodePercent()
|
("instance_url=" + ("https://" + account.hostAscii).encodePercent()
|
||||||
+ "&app_id=" + packageName.encodePercent()
|
+ "&app_id=" + packageName.encodePercent()
|
||||||
+ "&tag=" + tag
|
+ "&tag=" + tag
|
||||||
)
|
)
|
||||||
|
|
|
@ -913,14 +913,14 @@ class ActAppSetting : AppCompatActivity(), ColorPickerDialogListener, View.OnCli
|
||||||
|
|
||||||
fun formatFontSize(fv : Float) : String =
|
fun formatFontSize(fv : Float) : String =
|
||||||
when {
|
when {
|
||||||
fv.isFinite() -> String.format(Locale.getDefault(), "%.1f", fv)
|
fv.isFinite() -> String.format(defaultLocale(this), "%.1f", fv)
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseFontSize(src : String) : Float {
|
fun parseFontSize(src : String) : Float {
|
||||||
try {
|
try {
|
||||||
if(src.isNotEmpty()) {
|
if(src.isNotEmpty()) {
|
||||||
val f = NumberFormat.getInstance(Locale.getDefault()).parse(src)?.toFloat()
|
val f = NumberFormat.getInstance(defaultLocale(this)).parse(src)?.toFloat()
|
||||||
return when {
|
return when {
|
||||||
f == null -> Float.NaN
|
f == null -> Float.NaN
|
||||||
f.isNaN() -> Float.NaN
|
f.isNaN() -> Float.NaN
|
||||||
|
|
|
@ -351,7 +351,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
|
||||||
ivColumnBackground.alpha = column.column_bg_image_alpha
|
ivColumnBackground.alpha = column.column_bg_image_alpha
|
||||||
etAlpha.setText(
|
etAlpha.setText(
|
||||||
String.format(
|
String.format(
|
||||||
Locale.getDefault(),
|
defaultLocale(this@ActColumnCustomize),
|
||||||
"%.4f",
|
"%.4f",
|
||||||
column.column_bg_image_alpha
|
column.column_bg_image_alpha
|
||||||
)
|
)
|
||||||
|
@ -379,7 +379,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
|
||||||
if(loading_busy) return
|
if(loading_busy) return
|
||||||
try {
|
try {
|
||||||
|
|
||||||
var f = NumberFormat.getInstance(Locale.getDefault())
|
var f = NumberFormat.getInstance(defaultLocale(this@ActColumnCustomize))
|
||||||
.parse(etAlpha.text.toString())?.toFloat()
|
.parse(etAlpha.text.toString())?.toFloat()
|
||||||
|
|
||||||
if(f != null && ! f.isNaN()) {
|
if(f != null && ! f.isNaN()) {
|
||||||
|
@ -426,7 +426,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
|
||||||
|
|
||||||
etAlpha.setText(
|
etAlpha.setText(
|
||||||
String.format(
|
String.format(
|
||||||
Locale.getDefault(),
|
defaultLocale(this@ActColumnCustomize),
|
||||||
"%.4f",
|
"%.4f",
|
||||||
column.column_bg_image_alpha
|
column.column_bg_image_alpha
|
||||||
)
|
)
|
||||||
|
|
|
@ -221,7 +221,7 @@ class ActKeywordFilter
|
||||||
private fun save() {
|
private fun save() {
|
||||||
if(loading) return
|
if(loading) return
|
||||||
|
|
||||||
val params = jsonObject{
|
val params = jsonObject {
|
||||||
|
|
||||||
put("phrase", etPhrase.text.toString())
|
put("phrase", etPhrase.text.toString())
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ class ActKeywordFilter
|
||||||
filter_expire <= 0L -> {
|
filter_expire <= 0L -> {
|
||||||
}
|
}
|
||||||
// FIXME: currently there is no way to remove expires from existing filter.
|
// FIXME: currently there is no way to remove expires from existing filter.
|
||||||
else -> put("expires_in", Int.MAX_VALUE)
|
else -> put("expires_in", Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// set seconds
|
// set seconds
|
||||||
|
@ -285,9 +285,7 @@ class ActKeywordFilter
|
||||||
} else {
|
} else {
|
||||||
val app_state = App1.prepare(applicationContext)
|
val app_state = App1.prepare(applicationContext)
|
||||||
for(column in app_state.column_list) {
|
for(column in app_state.column_list) {
|
||||||
if(column.access_info.acct == account.acct
|
if(column.type == ColumnType.KEYWORD_FILTER && column.access_info == account) {
|
||||||
&& column.type == ColumnType.KEYWORD_FILTER
|
|
||||||
) {
|
|
||||||
column.filter_reload_required = true
|
column.filter_reload_required = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ class ActMain : AppCompatActivity()
|
||||||
|
|
||||||
// onActivityResultで設定されてonResumeで消化される
|
// onActivityResultで設定されてonResumeで消化される
|
||||||
// 状態保存の必要なし
|
// 状態保存の必要なし
|
||||||
private var posted_acct : String? = null
|
private var posted_acct : String? = null // acctAscii
|
||||||
private var posted_status_id : EntityId? = null
|
private var posted_status_id : EntityId? = null
|
||||||
private var posted_reply_id : EntityId? = null
|
private var posted_reply_id : EntityId? = null
|
||||||
private var posted_redraft_id : EntityId? = null
|
private var posted_redraft_id : EntityId? = null
|
||||||
|
@ -401,7 +401,7 @@ class ActMain : AppCompatActivity()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// 既出でなければ追加する
|
// 既出でなければ追加する
|
||||||
if(null == accounts.find { it.acct == a.acct }) accounts.add(a)
|
if(null == accounts.find { it.acctAscii == a.acctAscii }) accounts.add(a)
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -795,7 +795,7 @@ class ActMain : AppCompatActivity()
|
||||||
when {
|
when {
|
||||||
column.access_info.isNA -> post_helper.setInstance(null, false)
|
column.access_info.isNA -> post_helper.setInstance(null, false)
|
||||||
else -> post_helper.setInstance(
|
else -> post_helper.setInstance(
|
||||||
column.access_info.host,
|
column.access_info.hostAscii,
|
||||||
column.access_info.isMisskey
|
column.access_info.isMisskey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -865,7 +865,7 @@ class ActMain : AppCompatActivity()
|
||||||
// 予約投稿なら予約投稿リストをリロードする
|
// 予約投稿なら予約投稿リストをリロードする
|
||||||
for(column in app_state.column_list) {
|
for(column in app_state.column_list) {
|
||||||
if(column.type == ColumnType.SCHEDULED_STATUS
|
if(column.type == ColumnType.SCHEDULED_STATUS
|
||||||
&& column.access_info.acct == posted_acct
|
&& column.access_info.acctAscii == posted_acct
|
||||||
) {
|
) {
|
||||||
column.startLoading()
|
column.startLoading()
|
||||||
}
|
}
|
||||||
|
@ -888,7 +888,7 @@ class ActMain : AppCompatActivity()
|
||||||
val refresh_after_toot = Pref.ipRefreshAfterToot(pref)
|
val refresh_after_toot = Pref.ipRefreshAfterToot(pref)
|
||||||
if(refresh_after_toot != Pref.RAT_DONT_REFRESH) {
|
if(refresh_after_toot != Pref.RAT_DONT_REFRESH) {
|
||||||
for(column in app_state.column_list) {
|
for(column in app_state.column_list) {
|
||||||
if(column.access_info.acct != posted_acct) continue
|
if(column.access_info.acctAscii != posted_acct) continue
|
||||||
column.startRefreshForPost(
|
column.startRefreshForPost(
|
||||||
refresh_after_toot,
|
refresh_after_toot,
|
||||||
posted_status_id,
|
posted_status_id,
|
||||||
|
@ -967,7 +967,7 @@ class ActMain : AppCompatActivity()
|
||||||
post_helper.in_reply_to_id = null
|
post_helper.in_reply_to_id = null
|
||||||
post_helper.attachment_list = null
|
post_helper.attachment_list = null
|
||||||
post_helper.emojiMapCustom =
|
post_helper.emojiMapCustom =
|
||||||
App1.custom_emoji_lister.getMap(account.host, account.isMisskey)
|
App1.custom_emoji_lister.getMap(account.hostAscii, account.isMisskey)
|
||||||
|
|
||||||
|
|
||||||
etQuickToot.hideKeyboard()
|
etQuickToot.hideKeyboard()
|
||||||
|
@ -978,7 +978,7 @@ class ActMain : AppCompatActivity()
|
||||||
status : TootStatus
|
status : TootStatus
|
||||||
) {
|
) {
|
||||||
etQuickToot.setText("")
|
etQuickToot.setText("")
|
||||||
posted_acct = target_account.acct
|
posted_acct = target_account.acctAscii
|
||||||
posted_status_id = status.id
|
posted_status_id = status.id
|
||||||
posted_reply_id = status.in_reply_to_id
|
posted_reply_id = status.in_reply_to_id
|
||||||
posted_redraft_id = null
|
posted_redraft_id = null
|
||||||
|
@ -1600,7 +1600,7 @@ class ActMain : AppCompatActivity()
|
||||||
ivIcon.imageTintList = ColorStateList.valueOf(column.getHeaderNameColor())
|
ivIcon.imageTintList = ColorStateList.valueOf(column.getHeaderNameColor())
|
||||||
|
|
||||||
//
|
//
|
||||||
val ac = AcctColor.load(column.access_info.acct)
|
val ac = AcctColor.load(column.access_info.acctAscii)
|
||||||
if(AcctColor.hasColorForeground(ac)) {
|
if(AcctColor.hasColorForeground(ac)) {
|
||||||
vAcctColor.setBackgroundColor(ac.color_fg)
|
vAcctColor.setBackgroundColor(ac.color_fg)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1829,7 +1829,7 @@ class ActMain : AppCompatActivity()
|
||||||
if(account != null) {
|
if(account != null) {
|
||||||
var column = app_state.column_list.firstOrNull {
|
var column = app_state.column_list.firstOrNull {
|
||||||
it.type == ColumnType.NOTIFICATIONS
|
it.type == ColumnType.NOTIFICATIONS
|
||||||
&& account.acct == it.access_info.acct
|
&& account.acctAscii == it.access_info.acctAscii
|
||||||
&& ! it.system_notification_not_related
|
&& ! it.system_notification_not_related
|
||||||
}
|
}
|
||||||
if(column != null) {
|
if(column != null) {
|
||||||
|
@ -2029,7 +2029,7 @@ class ActMain : AppCompatActivity()
|
||||||
if(sa.username != ta.username) {
|
if(sa.username != ta.username) {
|
||||||
showToast(this@ActMain, true, R.string.user_name_not_match)
|
showToast(this@ActMain, true, R.string.user_name_not_match)
|
||||||
} else {
|
} else {
|
||||||
showToast(this@ActMain, false, R.string.access_token_updated_for, sa.acct)
|
showToast(this@ActMain, false, R.string.access_token_updated_for, sa.acctPretty)
|
||||||
|
|
||||||
// DBの情報を更新する
|
// DBの情報を更新する
|
||||||
sa.updateTokenInfo(token_info)
|
sa.updateTokenInfo(token_info)
|
||||||
|
@ -2039,7 +2039,7 @@ class ActMain : AppCompatActivity()
|
||||||
|
|
||||||
// 自動でリロードする
|
// 自動でリロードする
|
||||||
for(it in app_state.column_list) {
|
for(it in app_state.column_list) {
|
||||||
if(it.access_info.acct == sa.acct) {
|
if(it.access_info.acctAscii == sa.acctAscii) {
|
||||||
it.startLoading()
|
it.startLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2156,7 +2156,7 @@ class ActMain : AppCompatActivity()
|
||||||
null,
|
null,
|
||||||
object : DlgTextInput.Callback {
|
object : DlgTextInput.Callback {
|
||||||
override fun onOK(dialog : Dialog, text : String) {
|
override fun onOK(dialog : Dialog, text : String) {
|
||||||
checkAccessToken(null, dialog, sa.host, text, sa)
|
checkAccessToken(null, dialog, sa.hostAscii, text, sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEmptyError() {
|
override fun onEmptyError() {
|
||||||
|
@ -2180,7 +2180,7 @@ class ActMain : AppCompatActivity()
|
||||||
val done_list = ArrayList<SavedAccount>()
|
val done_list = ArrayList<SavedAccount>()
|
||||||
for(column in app_state.column_list) {
|
for(column in app_state.column_list) {
|
||||||
val a = column.access_info
|
val a = column.access_info
|
||||||
if(a.acct != account.acct) continue
|
if(a.acctAscii != account.acctAscii) continue
|
||||||
if(done_list.contains(a)) continue
|
if(done_list.contains(a)) continue
|
||||||
done_list.add(a)
|
done_list.add(a)
|
||||||
if(! a.isNA) a.reloadSetting(this@ActMain)
|
if(! a.isNA) a.reloadSetting(this@ActMain)
|
||||||
|
@ -2361,7 +2361,7 @@ class ActMain : AppCompatActivity()
|
||||||
if(statusInfo != null) {
|
if(statusInfo != null) {
|
||||||
if(accessInfo.isNA ||
|
if(accessInfo.isNA ||
|
||||||
statusInfo.statusId == null ||
|
statusInfo.statusId == null ||
|
||||||
! statusInfo.host.equals(accessInfo.host, ignoreCase = true)
|
! statusInfo.host.equals(accessInfo.hostAscii, ignoreCase = true)
|
||||||
) {
|
) {
|
||||||
Action_Toot.conversationOtherInstance(
|
Action_Toot.conversationOtherInstance(
|
||||||
this@ActMain,
|
this@ActMain,
|
||||||
|
@ -2385,7 +2385,7 @@ class ActMain : AppCompatActivity()
|
||||||
// opener.linkInfo をチェックしてメンションを判別する
|
// opener.linkInfo をチェックしてメンションを判別する
|
||||||
val mention = opener.linkInfo?.mention
|
val mention = opener.linkInfo?.mention
|
||||||
if(mention != null) {
|
if(mention != null) {
|
||||||
val fullAcct = getFullAcctOrNull(accessInfo, mention.acct, mention.url)
|
val fullAcct = getFullAcctOrNull(accessInfo, mention.acctAscii, mention.url)
|
||||||
if(fullAcct != null) {
|
if(fullAcct != null) {
|
||||||
val (user, host) = fullAcct.splitFullAcct()
|
val (user, host) = fullAcct.splitFullAcct()
|
||||||
if(host != null) {
|
if(host != null) {
|
||||||
|
@ -2487,7 +2487,7 @@ class ActMain : AppCompatActivity()
|
||||||
|
|
||||||
fun showColumnMatchAccount(account : SavedAccount) {
|
fun showColumnMatchAccount(account : SavedAccount) {
|
||||||
for(column in app_state.column_list) {
|
for(column in app_state.column_list) {
|
||||||
if(account.acct == column.access_info.acct) {
|
if(account.acctAscii == column.access_info.acctAscii) {
|
||||||
column.fireRebindAdapterItems()
|
column.fireRebindAdapterItems()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,21 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal const val EXTRA_ACCT = "acct"
|
internal const val EXTRA_ACCT_ASCII = "acctAscii"
|
||||||
|
internal const val EXTRA_ACCT_PRETTY = "acctPretty"
|
||||||
internal const val EXTRA_SHOW_NOTIFICATION_SOUND = "show_notification_sound"
|
internal const val EXTRA_SHOW_NOTIFICATION_SOUND = "show_notification_sound"
|
||||||
internal const val REQUEST_CODE_NOTIFICATION_SOUND = 2
|
internal const val REQUEST_CODE_NOTIFICATION_SOUND = 2
|
||||||
|
|
||||||
fun open(
|
fun open(
|
||||||
activity : Activity,
|
activity : Activity,
|
||||||
full_acct : String,
|
fullAcctAscii : String,
|
||||||
|
fullAcctPretty: String,
|
||||||
bShowNotificationSound : Boolean,
|
bShowNotificationSound : Boolean,
|
||||||
requestCode : Int
|
requestCode : Int
|
||||||
) {
|
) {
|
||||||
val intent = Intent(activity, ActNickname::class.java)
|
val intent = Intent(activity, ActNickname::class.java)
|
||||||
intent.putExtra(EXTRA_ACCT, full_acct)
|
intent.putExtra(EXTRA_ACCT_ASCII, fullAcctAscii)
|
||||||
|
intent.putExtra(EXTRA_ACCT_PRETTY, fullAcctPretty)
|
||||||
intent.putExtra(EXTRA_SHOW_NOTIFICATION_SOUND, bShowNotificationSound)
|
intent.putExtra(EXTRA_SHOW_NOTIFICATION_SOUND, bShowNotificationSound)
|
||||||
activity.startActivityForResult(intent, requestCode)
|
activity.startActivityForResult(intent, requestCode)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +47,8 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
private var show_notification_sound : Boolean = false
|
private var show_notification_sound : Boolean = false
|
||||||
private lateinit var acct : String
|
private lateinit var acctAscii : String
|
||||||
|
private lateinit var acctPretty : String
|
||||||
private var color_fg : Int = 0
|
private var color_fg : Int = 0
|
||||||
private var color_bg : Int = 0
|
private var color_bg : Int = 0
|
||||||
private var notification_sound_uri : String? = null
|
private var notification_sound_uri : String? = null
|
||||||
|
@ -73,7 +77,8 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
|
||||||
App1.setActivityTheme(this)
|
App1.setActivityTheme(this)
|
||||||
|
|
||||||
val intent = intent
|
val intent = intent
|
||||||
this.acct = intent.getStringExtra(EXTRA_ACCT) !!
|
this.acctAscii = intent.getStringExtra(EXTRA_ACCT_ASCII) !!
|
||||||
|
this.acctPretty = intent.getStringExtra(EXTRA_ACCT_PRETTY) !!
|
||||||
this.show_notification_sound = intent.getBooleanExtra(EXTRA_SHOW_NOTIFICATION_SOUND, false)
|
this.show_notification_sound = intent.getBooleanExtra(EXTRA_SHOW_NOTIFICATION_SOUND, false)
|
||||||
|
|
||||||
initUI()
|
initUI()
|
||||||
|
@ -148,9 +153,9 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
|
||||||
findViewById<View>(R.id.llNotificationSound).visibility =
|
findViewById<View>(R.id.llNotificationSound).visibility =
|
||||||
if(show_notification_sound) View.VISIBLE else View.GONE
|
if(show_notification_sound) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
tvAcct.text = acct
|
tvAcct.text = acctPretty
|
||||||
|
|
||||||
val ac = AcctColor.load(acct)
|
val ac = AcctColor.load(acctAscii)
|
||||||
color_bg = ac.color_bg
|
color_bg = ac.color_bg
|
||||||
color_fg = ac.color_fg
|
color_fg = ac.color_fg
|
||||||
etNickname.setText(if(ac.nickname == null) "" else ac.nickname)
|
etNickname.setText(if(ac.nickname == null) "" else ac.nickname)
|
||||||
|
@ -163,7 +168,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
|
||||||
private fun save() {
|
private fun save() {
|
||||||
if(bLoading) return
|
if(bLoading) return
|
||||||
AcctColor(
|
AcctColor(
|
||||||
acct,
|
acctAscii,
|
||||||
etNickname.text.toString().trim { it <= ' ' },
|
etNickname.text.toString().trim { it <= ' ' },
|
||||||
color_fg,
|
color_fg,
|
||||||
color_bg,
|
color_bg,
|
||||||
|
@ -173,7 +178,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
|
||||||
|
|
||||||
private fun show() {
|
private fun show() {
|
||||||
val s = etNickname.text.toString().trim { it <= ' ' }
|
val s = etNickname.text.toString().trim { it <= ' ' }
|
||||||
tvPreview.text = s.notEmpty() ?: acct
|
tvPreview.text = s.notEmpty() ?: acctPretty
|
||||||
tvPreview.textColor = color_fg.notZero() ?: getAttributeColor(this, R.attr.colorTimeSmall)
|
tvPreview.textColor = color_fg.notZero() ?: getAttributeColor(this, R.attr.colorTimeSmall)
|
||||||
tvPreview.backgroundColor = color_bg
|
tvPreview.backgroundColor = color_bg
|
||||||
}
|
}
|
||||||
|
|
|
@ -507,7 +507,7 @@ class ActPost : AppCompatActivity(),
|
||||||
R.id.btnPlugin -> openMushroom()
|
R.id.btnPlugin -> openMushroom()
|
||||||
R.id.btnEmojiPicker -> post_helper.openEmojiPickerFromMore()
|
R.id.btnEmojiPicker -> post_helper.openEmojiPickerFromMore()
|
||||||
R.id.btnFeaturedTag -> post_helper.openFeaturedTagList(
|
R.id.btnFeaturedTag -> post_helper.openFeaturedTagList(
|
||||||
featuredTagCache[account?.acct ?: ""]?.list
|
featuredTagCache[account?.acctAscii ?: ""]?.list
|
||||||
)
|
)
|
||||||
R.id.ibSchedule -> performSchedule()
|
R.id.ibSchedule -> performSchedule()
|
||||||
R.id.ibScheduleReset -> resetSchedule()
|
R.id.ibScheduleReset -> resetSchedule()
|
||||||
|
@ -774,7 +774,7 @@ class ActPost : AppCompatActivity(),
|
||||||
|
|
||||||
// 元レスに含まれていたメンションを複製
|
// 元レスに含まれていたメンションを複製
|
||||||
reply_status.mentions?.forEach { mention ->
|
reply_status.mentions?.forEach { mention ->
|
||||||
val who_acct = mention.acct
|
val who_acct = mention.acctAscii
|
||||||
// 空データなら追加しない
|
// 空データなら追加しない
|
||||||
if(who_acct.isEmpty()) return@forEach
|
if(who_acct.isEmpty()) return@forEach
|
||||||
// 自分なら追加しない
|
// 自分なら追加しない
|
||||||
|
@ -783,6 +783,12 @@ class ActPost : AppCompatActivity(),
|
||||||
// 既出なら追加しない
|
// 既出なら追加しない
|
||||||
if(mention_list.contains(strMention)) return@forEach
|
if(mention_list.contains(strMention)) return@forEach
|
||||||
mention_list.add(strMention)
|
mention_list.add(strMention)
|
||||||
|
|
||||||
|
/*
|
||||||
|
FIXME インスタンスのバージョンが3.1.0 以降ならメンションのホスト部分にIDNドメインを使いたいが、
|
||||||
|
投稿画面でのアカウント切り替え時にタンスのバージョンが異なると破綻する可能性が高い。
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mention_list.isNotEmpty()) {
|
if(mention_list.isNotEmpty()) {
|
||||||
|
@ -1299,7 +1305,7 @@ class ActPost : AppCompatActivity(),
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
// インスタンス情報を確認する
|
// インスタンス情報を確認する
|
||||||
val info = TootInstance.getCached(account.host)
|
val info = TootInstance.getCached(account.hostAscii)
|
||||||
if(info == null || info.isExpire) {
|
if(info == null || info.isExpire) {
|
||||||
// 情報がないか古いなら再取得
|
// 情報がないか古いなら再取得
|
||||||
|
|
||||||
|
@ -1390,6 +1396,7 @@ class ActPost : AppCompatActivity(),
|
||||||
val time : Long
|
val time : Long
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// key is SavedfAccount.acctAscii
|
||||||
private val featuredTagCache = ConcurrentHashMap<String, FeaturedTagCache>()
|
private val featuredTagCache = ConcurrentHashMap<String, FeaturedTagCache>()
|
||||||
private var lastFeaturedTagTask : TootTaskRunner? = null
|
private var lastFeaturedTagTask : TootTaskRunner? = null
|
||||||
|
|
||||||
|
@ -1401,7 +1408,7 @@ class ActPost : AppCompatActivity(),
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val cache = featuredTagCache[account.acct]
|
val cache = featuredTagCache[account.acctAscii]
|
||||||
|
|
||||||
btnFeaturedTag.vg(cache?.list?.isNotEmpty() == true)
|
btnFeaturedTag.vg(cache?.list?.isNotEmpty() == true)
|
||||||
|
|
||||||
|
@ -1417,13 +1424,13 @@ class ActPost : AppCompatActivity(),
|
||||||
|
|
||||||
override fun background(client : TootApiClient) : TootApiResult? {
|
override fun background(client : TootApiClient) : TootApiResult? {
|
||||||
return if(account.isMisskey) {
|
return if(account.isMisskey) {
|
||||||
featuredTagCache[account.acct] =
|
featuredTagCache[account.acctAscii] =
|
||||||
FeaturedTagCache(emptyList(), SystemClock.elapsedRealtime())
|
FeaturedTagCache(emptyList(), SystemClock.elapsedRealtime())
|
||||||
TootApiResult()
|
TootApiResult()
|
||||||
} else {
|
} else {
|
||||||
client.request("/api/v1/featured_tags")?.also { result ->
|
client.request("/api/v1/featured_tags")?.also { result ->
|
||||||
val list = parseList(::TootTag, result.jsonArray)
|
val list = parseList(::TootTag, result.jsonArray)
|
||||||
featuredTagCache[account.acct] =
|
featuredTagCache[account.acctAscii] =
|
||||||
FeaturedTagCache(list, SystemClock.elapsedRealtime())
|
FeaturedTagCache(list, SystemClock.elapsedRealtime())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1449,16 +1456,15 @@ class ActPost : AppCompatActivity(),
|
||||||
btnAccount.setTextColor(getAttributeColor(this, android.R.attr.textColorPrimary))
|
btnAccount.setTextColor(getAttributeColor(this, android.R.attr.textColorPrimary))
|
||||||
btnAccount.setBackgroundResource(R.drawable.btn_bg_transparent)
|
btnAccount.setBackgroundResource(R.drawable.btn_bg_transparent)
|
||||||
} else {
|
} else {
|
||||||
post_helper.setInstance(a.host, a.isMisskey)
|
post_helper.setInstance(a.hostAscii, a.isMisskey)
|
||||||
|
|
||||||
// 先読みしてキャッシュに保持しておく
|
// 先読みしてキャッシュに保持しておく
|
||||||
App1.custom_emoji_lister.getList(a.host, a.isMisskey) {
|
App1.custom_emoji_lister.getList(a.hostAscii, a.isMisskey) {
|
||||||
// 何もしない
|
// 何もしない
|
||||||
}
|
}
|
||||||
|
|
||||||
val acct = a.acct
|
val ac = AcctColor.load(a.acctAscii)
|
||||||
val ac = AcctColor.load(acct)
|
val nickname = if(AcctColor.hasNickname(ac)) ac.nickname else a.acctPretty
|
||||||
val nickname = if(AcctColor.hasNickname(ac)) ac.nickname else acct
|
|
||||||
btnAccount.text = nickname
|
btnAccount.text = nickname
|
||||||
|
|
||||||
if(AcctColor.hasColorBackground(ac)) {
|
if(AcctColor.hasColorBackground(ac)) {
|
||||||
|
@ -1502,7 +1508,7 @@ class ActPost : AppCompatActivity(),
|
||||||
) { ai ->
|
) { ai ->
|
||||||
|
|
||||||
// 別タンスのアカウントに変更したならならin_reply_toの変換が必要
|
// 別タンスのアカウントに変更したならならin_reply_toの変換が必要
|
||||||
if(in_reply_to_id != null && ! ai.host.equals(account?.host, ignoreCase = true)) {
|
if(in_reply_to_id != null && ! ai.matchHost(account?.hostAscii) ) {
|
||||||
startReplyConversion(ai)
|
startReplyConversion(ai)
|
||||||
} else {
|
} else {
|
||||||
setAccountWithVisibilityConversion(ai)
|
setAccountWithVisibilityConversion(ai)
|
||||||
|
@ -2031,7 +2037,7 @@ class ActPost : AppCompatActivity(),
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val instance = TootInstance.getCached(account.host)
|
val instance = TootInstance.getCached(account.hostAscii)
|
||||||
if(instance?.instanceType == TootInstance.InstanceType.Pixelfed) {
|
if(instance?.instanceType == TootInstance.InstanceType.Pixelfed) {
|
||||||
if(in_reply_to_id != null) {
|
if(in_reply_to_id != null) {
|
||||||
showToast(this, true, R.string.pixelfed_does_not_allow_reply_with_media)
|
showToast(this, true, R.string.pixelfed_does_not_allow_reply_with_media)
|
||||||
|
@ -2569,7 +2575,7 @@ class ActPost : AppCompatActivity(),
|
||||||
post_helper.attachment_list = this.attachment_list
|
post_helper.attachment_list = this.attachment_list
|
||||||
|
|
||||||
post_helper.emojiMapCustom =
|
post_helper.emojiMapCustom =
|
||||||
App1.custom_emoji_lister.getMap(account.host, account.isMisskey)
|
App1.custom_emoji_lister.getMap(account.hostAscii, account.isMisskey)
|
||||||
|
|
||||||
post_helper.redraft_status_id = redraft_status_id
|
post_helper.redraft_status_id = redraft_status_id
|
||||||
|
|
||||||
|
@ -2585,7 +2591,7 @@ class ActPost : AppCompatActivity(),
|
||||||
status : TootStatus
|
status : TootStatus
|
||||||
) {
|
) {
|
||||||
val data = Intent()
|
val data = Intent()
|
||||||
data.putExtra(EXTRA_POSTED_ACCT, target_account.acct)
|
data.putExtra(EXTRA_POSTED_ACCT, target_account.acctAscii)
|
||||||
status.id.putTo(data, EXTRA_POSTED_STATUS_ID)
|
status.id.putTo(data, EXTRA_POSTED_STATUS_ID)
|
||||||
redraft_status_id?.putTo(data, EXTRA_POSTED_REDRAFT_ID)
|
redraft_status_id?.putTo(data, EXTRA_POSTED_REDRAFT_ID)
|
||||||
status.in_reply_to_id?.putTo(data, EXTRA_POSTED_REPLY_ID)
|
status.in_reply_to_id?.putTo(data, EXTRA_POSTED_REPLY_ID)
|
||||||
|
@ -2597,7 +2603,7 @@ class ActPost : AppCompatActivity(),
|
||||||
override fun onScheduledPostComplete(target_account : SavedAccount) {
|
override fun onScheduledPostComplete(target_account : SavedAccount) {
|
||||||
showToast(this@ActPost, false, getString(R.string.scheduled_status_sent))
|
showToast(this@ActPost, false, getString(R.string.scheduled_status_sent))
|
||||||
val data = Intent()
|
val data = Intent()
|
||||||
data.putExtra(EXTRA_POSTED_ACCT, target_account.acct)
|
data.putExtra(EXTRA_POSTED_ACCT, target_account.acctAscii)
|
||||||
setResult(RESULT_OK, data)
|
setResult(RESULT_OK, data)
|
||||||
isPostComplete = true
|
isPostComplete = true
|
||||||
this@ActPost.finish()
|
this@ActPost.finish()
|
||||||
|
|
|
@ -301,47 +301,47 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBusyFav(account : SavedAccount, status : TootStatus) : Boolean {
|
fun isBusyFav(account : SavedAccount, status : TootStatus) : Boolean {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
return map_busy_fav.contains(key)
|
return map_busy_fav.contains(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBusyFav(account : SavedAccount, status : TootStatus) {
|
fun setBusyFav(account : SavedAccount, status : TootStatus) {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
map_busy_fav.add(key)
|
map_busy_fav.add(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetBusyFav(account : SavedAccount, status : TootStatus) {
|
fun resetBusyFav(account : SavedAccount, status : TootStatus) {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
map_busy_fav.remove(key)
|
map_busy_fav.remove(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBusyBookmark(account : SavedAccount, status : TootStatus) : Boolean {
|
fun isBusyBookmark(account : SavedAccount, status : TootStatus) : Boolean {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
return map_busy_bookmark.contains(key)
|
return map_busy_bookmark.contains(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBusyBookmark(account : SavedAccount, status : TootStatus) {
|
fun setBusyBookmark(account : SavedAccount, status : TootStatus) {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
map_busy_bookmark.add(key)
|
map_busy_bookmark.add(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetBusyBookmark(account : SavedAccount, status : TootStatus) {
|
fun resetBusyBookmark(account : SavedAccount, status : TootStatus) {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
map_busy_bookmark.remove(key)
|
map_busy_bookmark.remove(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBusyBoost(account : SavedAccount, status : TootStatus) : Boolean {
|
fun isBusyBoost(account : SavedAccount, status : TootStatus) : Boolean {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
return map_busy_boost.contains(key)
|
return map_busy_boost.contains(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBusyBoost(account : SavedAccount, status : TootStatus) {
|
fun setBusyBoost(account : SavedAccount, status : TootStatus) {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
map_busy_boost.add(key)
|
map_busy_boost.add(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetBusyBoost(account : SavedAccount, status : TootStatus) {
|
fun resetBusyBoost(account : SavedAccount, status : TootStatus) {
|
||||||
val key = account.acct + ":" + status.busyKey
|
val key = account.acctAscii + ":" + status.busyKey
|
||||||
map_busy_boost.remove(key)
|
map_busy_boost.remove(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ class AppState(internal val context : Context, internal val pref : SharedPrefere
|
||||||
if(voice_set == null || voice_set.isEmpty()) {
|
if(voice_set == null || voice_set.isEmpty()) {
|
||||||
log.d("TextToSpeech.getVoices returns null or empty set.")
|
log.d("TextToSpeech.getVoices returns null or empty set.")
|
||||||
} else {
|
} else {
|
||||||
val lang = Locale.getDefault().toLanguageTag()
|
val lang = defaultLocale(context).toLanguageTag()
|
||||||
for(v in voice_set) {
|
for(v in voice_set) {
|
||||||
log.d(
|
log.d(
|
||||||
"Voice %s %s %s",
|
"Voice %s %s %s",
|
||||||
|
|
|
@ -263,10 +263,9 @@ class Column(
|
||||||
override fun handleResult(result : TootApiResult?) {
|
override fun handleResult(result : TootApiResult?) {
|
||||||
val filter_list = this.filter_list
|
val filter_list = this.filter_list
|
||||||
if(filter_list != null) {
|
if(filter_list != null) {
|
||||||
val stream_acct = access_info.acct
|
log.d("update filters for ${access_info.acctAscii}")
|
||||||
log.d("update filters for $stream_acct")
|
|
||||||
for(column in App1.getAppState(context).column_list) {
|
for(column in App1.getAppState(context).column_list) {
|
||||||
if(column.access_info.acct == stream_acct) {
|
if(column.access_info == access_info) {
|
||||||
column.onFiltersChanged2(filter_list)
|
column.onFiltersChanged2(filter_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,8 +360,7 @@ class Column(
|
||||||
|
|
||||||
val type = ColumnType.parse(typeId)
|
val type = ColumnType.parse(typeId)
|
||||||
|
|
||||||
fun getIconId() : Int =
|
fun getIconId() : Int = type.iconId(access_info.acctAscii)
|
||||||
type.iconId(access_info.acct)
|
|
||||||
|
|
||||||
fun getColumnName(long : Boolean) =
|
fun getColumnName(long : Boolean) =
|
||||||
type.name2(this, long) ?: type.name1(context)
|
type.name2(this, long) ?: type.name1(context)
|
||||||
|
@ -903,8 +901,8 @@ class Column(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 以下は保存には必要ないが、カラムリスト画面で使う
|
// 以下は保存には必要ないが、カラムリスト画面で使う
|
||||||
val ac = AcctColor.load(access_info.acct)
|
val ac = AcctColor.load(access_info.acctAscii)
|
||||||
dst[KEY_COLUMN_ACCESS] = if(AcctColor.hasNickname(ac)) ac.nickname else access_info.acct
|
dst[KEY_COLUMN_ACCESS] = if(AcctColor.hasNickname(ac)) ac.nickname else access_info.acctPretty
|
||||||
dst[KEY_COLUMN_ACCESS_COLOR] = ac.color_fg
|
dst[KEY_COLUMN_ACCESS_COLOR] = ac.color_fg
|
||||||
dst[KEY_COLUMN_ACCESS_COLOR_BG] = ac.color_bg
|
dst[KEY_COLUMN_ACCESS_COLOR_BG] = ac.color_bg
|
||||||
dst[KEY_COLUMN_NAME] = getColumnName(true)
|
dst[KEY_COLUMN_NAME] = getColumnName(true)
|
||||||
|
@ -916,7 +914,7 @@ class Column(
|
||||||
type : ColumnType,
|
type : ColumnType,
|
||||||
params : Array<out Any>
|
params : Array<out Any>
|
||||||
) : Boolean {
|
) : Boolean {
|
||||||
if(type != this.type || ai.acct != access_info.acct) return false
|
if(type != this.type || ai != access_info) return false
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
when(type) {
|
when(type) {
|
||||||
|
@ -1038,7 +1036,7 @@ class Column(
|
||||||
callback : (account : SavedAccount, status : TootStatus) -> Boolean
|
callback : (account : SavedAccount, status : TootStatus) -> Boolean
|
||||||
// callback return true if rebind view required
|
// callback return true if rebind view required
|
||||||
) {
|
) {
|
||||||
if(! access_info.host.equals(target_instance, ignoreCase = true)) return
|
if(! access_info.matchHost(target_instance)) return
|
||||||
|
|
||||||
var bChanged = false
|
var bChanged = false
|
||||||
|
|
||||||
|
@ -1068,7 +1066,7 @@ class Column(
|
||||||
who_id : EntityId,
|
who_id : EntityId,
|
||||||
removeFromUserList : Boolean = false
|
removeFromUserList : Boolean = false
|
||||||
) {
|
) {
|
||||||
if(target_account.acct != access_info.acct) return
|
if(target_account != access_info) return
|
||||||
|
|
||||||
val INVALID_ACCOUNT = - 1L
|
val INVALID_ACCOUNT = - 1L
|
||||||
|
|
||||||
|
@ -1121,13 +1119,13 @@ class Column(
|
||||||
|
|
||||||
// misskeyカラムやプロフカラムでブロック成功した時に呼ばれる
|
// misskeyカラムやプロフカラムでブロック成功した時に呼ばれる
|
||||||
fun updateFollowIcons(target_account : SavedAccount) {
|
fun updateFollowIcons(target_account : SavedAccount) {
|
||||||
if(target_account.acct != access_info.acct) return
|
if(target_account != access_info) return
|
||||||
|
|
||||||
fireShowContent(reason = "updateFollowIcons", reset = true)
|
fireShowContent(reason = "updateFollowIcons", reset = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeUser(targetAccount : SavedAccount, columnType : ColumnType, who_id : EntityId) {
|
fun removeUser(targetAccount : SavedAccount, columnType : ColumnType, who_id : EntityId) {
|
||||||
if(type == columnType && targetAccount.acct == access_info.acct) {
|
if(type == columnType && targetAccount == access_info ) {
|
||||||
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
||||||
for(o in list_data) {
|
for(o in list_data) {
|
||||||
if(o is TootAccountRef) {
|
if(o is TootAccountRef) {
|
||||||
|
@ -1148,7 +1146,7 @@ class Column(
|
||||||
|
|
||||||
if(is_dispose.get() || bInitialLoading || bRefreshLoading) return
|
if(is_dispose.get() || bInitialLoading || bRefreshLoading) return
|
||||||
|
|
||||||
if(tl_host.equals(access_info.host, ignoreCase = true)) {
|
if(tl_host.equals(access_info.hostAscii, ignoreCase = true)) {
|
||||||
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
||||||
for(o in list_data) {
|
for(o in list_data) {
|
||||||
if(o is TootStatus) {
|
if(o is TootStatus) {
|
||||||
|
@ -1203,7 +1201,7 @@ class Column(
|
||||||
fun removeNotificationOne(target_account : SavedAccount, notification : TootNotification) {
|
fun removeNotificationOne(target_account : SavedAccount, notification : TootNotification) {
|
||||||
if(! isNotificationColumn) return
|
if(! isNotificationColumn) return
|
||||||
|
|
||||||
if(access_info.acct != target_account.acct) return
|
if(access_info != target_account) return
|
||||||
|
|
||||||
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
||||||
for(o in list_data) {
|
for(o in list_data) {
|
||||||
|
@ -1268,7 +1266,7 @@ class Column(
|
||||||
|
|
||||||
val domain = IDN.toASCII(domainArg,IDN.ALLOW_UNASSIGNED)
|
val domain = IDN.toASCII(domainArg,IDN.ALLOW_UNASSIGNED)
|
||||||
|
|
||||||
if(target_account.host != access_info.host) return
|
if(target_account.hostAscii != access_info.hostAscii) return
|
||||||
if(access_info.isPseudo) return
|
if(access_info.isPseudo) return
|
||||||
|
|
||||||
if(type == ColumnType.DOMAIN_BLOCKS) {
|
if(type == ColumnType.DOMAIN_BLOCKS) {
|
||||||
|
@ -1281,7 +1279,7 @@ class Column(
|
||||||
// ブロックしたのとドメイン部分が一致するアカウントからのステータスと通知をすべて除去する
|
// ブロックしたのとドメイン部分が一致するアカウントからのステータスと通知をすべて除去する
|
||||||
val reDomain = Pattern.compile("\\A[^@]+@\\Q$domain\\E\\z", Pattern.CASE_INSENSITIVE)
|
val reDomain = Pattern.compile("\\A[^@]+@\\Q$domain\\E\\z", Pattern.CASE_INSENSITIVE)
|
||||||
val checker =
|
val checker =
|
||||||
{ account : TootAccount? -> if(account == null ) false else reDomain.matcher(account.acct).find() }
|
{ account : TootAccount? -> if(account == null ) false else reDomain.matcher(account.acctAscii).find() }
|
||||||
|
|
||||||
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
val tmp_list = ArrayList<TimelineItem>(list_data.size)
|
||||||
|
|
||||||
|
@ -1307,7 +1305,7 @@ class Column(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onListListUpdated(account : SavedAccount) {
|
fun onListListUpdated(account : SavedAccount) {
|
||||||
if(type == ColumnType.LIST_LIST && access_info.acct == account.acct) {
|
if(type == ColumnType.LIST_LIST && access_info == account) {
|
||||||
startLoading()
|
startLoading()
|
||||||
val vh = viewHolder
|
val vh = viewHolder
|
||||||
vh?.onListListUpdated()
|
vh?.onListListUpdated()
|
||||||
|
@ -1315,7 +1313,7 @@ class Column(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onListNameUpdated(account : SavedAccount, item : TootList) {
|
fun onListNameUpdated(account : SavedAccount, item : TootList) {
|
||||||
if(access_info.acct != account.acct) return
|
if(access_info != account) return
|
||||||
when(type) {
|
when(type) {
|
||||||
ColumnType.LIST_LIST -> {
|
ColumnType.LIST_LIST -> {
|
||||||
startLoading()
|
startLoading()
|
||||||
|
@ -1340,11 +1338,11 @@ class Column(
|
||||||
who : TootAccount,
|
who : TootAccount,
|
||||||
bAdd : Boolean
|
bAdd : Boolean
|
||||||
) {
|
) {
|
||||||
if(type == ColumnType.LIST_TL && access_info.acct == account.acct && list_id == profile_id) {
|
if(type == ColumnType.LIST_TL && access_info == account && list_id == profile_id) {
|
||||||
if(! bAdd) {
|
if(! bAdd) {
|
||||||
removeAccountInTimeline(account, who.id)
|
removeAccountInTimeline(account, who.id)
|
||||||
}
|
}
|
||||||
} else if(type == ColumnType.LIST_MEMBER && access_info.acct == account.acct && list_id == profile_id) {
|
} else if(type == ColumnType.LIST_MEMBER && access_info == account && list_id == profile_id) {
|
||||||
if(! bAdd) {
|
if(! bAdd) {
|
||||||
removeAccountInTimeline(account, who.id)
|
removeAccountInTimeline(account, who.id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ private val unsupportedRefresh : ColumnTask_Refresh.(client : TootApiClient) ->
|
||||||
private val unsupportedGap : ColumnTask_Gap.(client : TootApiClient) -> TootApiResult? =
|
private val unsupportedGap : ColumnTask_Gap.(client : TootApiClient) -> TootApiResult? =
|
||||||
{ TootApiResult("gap reading not supported.") }
|
{ TootApiResult("gap reading not supported.") }
|
||||||
|
|
||||||
private val unusedIconId : (acct : String) -> Int =
|
private val unusedIconId : (String) -> Int =
|
||||||
{ R.drawable.ic_question }
|
{ R.drawable.ic_question }
|
||||||
|
|
||||||
private val unusedName : (context : Context) -> String =
|
private val unusedName : (context : Context) -> String =
|
||||||
|
@ -43,7 +43,7 @@ private val unusedName2 : Column.(long : Boolean) -> String? =
|
||||||
|
|
||||||
enum class ColumnType(
|
enum class ColumnType(
|
||||||
val id : Int = 0,
|
val id : Int = 0,
|
||||||
val iconId : (acct : String) -> Int = unusedIconId,
|
val iconId : (acct:String) -> Int = unusedIconId,
|
||||||
val name1 : (context : Context) -> String = unusedName,
|
val name1 : (context : Context) -> String = unusedName,
|
||||||
val name2 : Column.(long : Boolean) -> String? = unusedName2,
|
val name2 : Column.(long : Boolean) -> String? = unusedName2,
|
||||||
val loading : ColumnTask_Loading.(client : TootApiClient) -> TootApiResult?,
|
val loading : ColumnTask_Loading.(client : TootApiClient) -> TootApiResult?,
|
||||||
|
|
|
@ -1171,15 +1171,13 @@ class ColumnViewHolder(
|
||||||
val column = this.column
|
val column = this.column
|
||||||
if(column == null || column.is_dispose.get()) return@Runnable
|
if(column == null || column.is_dispose.get()) return@Runnable
|
||||||
|
|
||||||
val acct = column.access_info.acct
|
val ac = AcctColor.load(column.access_info.acctAscii)
|
||||||
val ac = AcctColor.load(acct)
|
|
||||||
|
|
||||||
val nickname = ac.nickname
|
val nickname = ac.nickname
|
||||||
tvColumnContext.text = if(nickname != null && nickname.isNotEmpty())
|
tvColumnContext.text = if(nickname != null && nickname.isNotEmpty())
|
||||||
nickname
|
nickname
|
||||||
else
|
else
|
||||||
column.access_info.prettyAcct
|
column.access_info.acctPretty
|
||||||
|
|
||||||
|
|
||||||
tvColumnContext.setTextColor(
|
tvColumnContext.setTextColor(
|
||||||
ac.color_fg.notZero()
|
ac.color_fg.notZero()
|
||||||
|
@ -2640,7 +2638,7 @@ class ColumnViewHolder(
|
||||||
|
|
||||||
private fun addReaction(item : TootAnnouncement, sample : TootAnnouncement.Reaction?) {
|
private fun addReaction(item : TootAnnouncement, sample : TootAnnouncement.Reaction?) {
|
||||||
val column = column ?: return
|
val column = column ?: return
|
||||||
val host = column.access_info.host
|
val host = column.access_info.hostAscii
|
||||||
val isMisskey = column.isMisskey
|
val isMisskey = column.isMisskey
|
||||||
if(sample == null) {
|
if(sample == null) {
|
||||||
EmojiPicker(activity, host, isMisskey) { name, _, _, unicode, customEmoji ->
|
EmojiPicker(activity, host, isMisskey) { name, _, _, unicode, customEmoji ->
|
||||||
|
|
|
@ -412,7 +412,7 @@ internal class DlgContextMenu(
|
||||||
// 疑似アカウントではドメインブロックできない
|
// 疑似アカウントではドメインブロックできない
|
||||||
// 自ドメインはブロックできない
|
// 自ドメインはブロックできない
|
||||||
btnDomainBlock.vg(
|
btnDomainBlock.vg(
|
||||||
! (access_info.isPseudo || access_info.host.equals(who_host, ignoreCase = true))
|
! (access_info.isPseudo || access_info.matchHost(who_host))
|
||||||
)
|
)
|
||||||
|
|
||||||
btnDomainTimeline.vg(
|
btnDomainTimeline.vg(
|
||||||
|
@ -525,9 +525,9 @@ internal class DlgContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUserHost() : String {
|
private fun getUserHost() : String {
|
||||||
return when(val who_host = whoRef?.get()?.host) {
|
return when(val who_host = whoRef?.get()?.hostAscii) {
|
||||||
"?" -> column.instance_uri
|
"?" -> column.instance_uri
|
||||||
null, "" -> access_info.host
|
null, "" -> access_info.hostAscii
|
||||||
else -> who_host
|
else -> who_host
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -766,6 +766,7 @@ internal class DlgContextMenu(
|
||||||
ActNickname.open(
|
ActNickname.open(
|
||||||
activity,
|
activity,
|
||||||
access_info.getFullAcct(who),
|
access_info.getFullAcct(who),
|
||||||
|
access_info.getFullPrettyAcct(who),
|
||||||
true,
|
true,
|
||||||
ActMain.REQUEST_CODE_NICKNAME
|
ActMain.REQUEST_CODE_NICKNAME
|
||||||
)
|
)
|
||||||
|
@ -783,10 +784,10 @@ internal class DlgContextMenu(
|
||||||
showToast(activity, false, R.string.domain_block_from_pseudo)
|
showToast(activity, false, R.string.domain_block_from_pseudo)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
val who_host = who.host
|
val who_host = who.hostAscii
|
||||||
|
|
||||||
// 自分のドメインではブロックできない
|
// 自分のドメインではブロックできない
|
||||||
if(access_info.host.equals(who_host, ignoreCase = true)) {
|
if(access_info.matchHost(who_host)) {
|
||||||
showToast(activity, false, R.string.domain_block_from_local)
|
showToast(activity, false, R.string.domain_block_from_local)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -800,7 +801,7 @@ internal class DlgContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.btnOpenTimeline -> {
|
R.id.btnOpenTimeline -> {
|
||||||
val who_host = who.host
|
val who_host = who.hostAscii
|
||||||
@Suppress("ControlFlowWithEmptyBody")
|
@Suppress("ControlFlowWithEmptyBody")
|
||||||
if(who_host.isEmpty() || who_host == "?") {
|
if(who_host.isEmpty() || who_host == "?") {
|
||||||
// 何もしない
|
// 何もしない
|
||||||
|
@ -810,7 +811,7 @@ internal class DlgContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.btnDomainTimeline -> {
|
R.id.btnDomainTimeline -> {
|
||||||
val who_host = who.host
|
val who_host = who.hostAscii
|
||||||
@Suppress("ControlFlowWithEmptyBody")
|
@Suppress("ControlFlowWithEmptyBody")
|
||||||
if(who_host.isEmpty() || who_host == "?") {
|
if(who_host.isEmpty() || who_host == "?") {
|
||||||
// 何もしない
|
// 何もしない
|
||||||
|
@ -885,7 +886,7 @@ internal class DlgContextMenu(
|
||||||
activity,
|
activity,
|
||||||
access_info,
|
access_info,
|
||||||
pos,
|
pos,
|
||||||
who.host,
|
who.hostAscii,
|
||||||
status,
|
status,
|
||||||
ColumnType.ACCOUNT_AROUND
|
ColumnType.ACCOUNT_AROUND
|
||||||
, allowPseudo = false
|
, allowPseudo = false
|
||||||
|
@ -895,7 +896,7 @@ internal class DlgContextMenu(
|
||||||
activity,
|
activity,
|
||||||
access_info,
|
access_info,
|
||||||
pos,
|
pos,
|
||||||
who.host,
|
who.hostAscii,
|
||||||
status,
|
status,
|
||||||
ColumnType.LOCAL_AROUND
|
ColumnType.LOCAL_AROUND
|
||||||
)
|
)
|
||||||
|
@ -904,7 +905,7 @@ internal class DlgContextMenu(
|
||||||
activity,
|
activity,
|
||||||
access_info,
|
access_info,
|
||||||
pos,
|
pos,
|
||||||
who.host,
|
who.hostAscii,
|
||||||
status,
|
status,
|
||||||
ColumnType.FEDERATED_AROUND
|
ColumnType.FEDERATED_AROUND
|
||||||
)
|
)
|
||||||
|
@ -914,13 +915,13 @@ internal class DlgContextMenu(
|
||||||
R.id.btnOpenAccountInAdminWebUi ->
|
R.id.btnOpenAccountInAdminWebUi ->
|
||||||
App1.openBrowser(
|
App1.openBrowser(
|
||||||
activity,
|
activity,
|
||||||
"https://${access_info.host}/admin/accounts/${who.id}"
|
"https://${access_info.hostAscii}/admin/accounts/${who.id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
R.id.btnOpenInstanceInAdminWebUi ->
|
R.id.btnOpenInstanceInAdminWebUi ->
|
||||||
App1.openBrowser(
|
App1.openBrowser(
|
||||||
activity,
|
activity,
|
||||||
"https://${access_info.host}/admin/instances/${who.host}"
|
"https://${access_info.hostAscii}/admin/instances/${who.hostAscii}"
|
||||||
)
|
)
|
||||||
|
|
||||||
R.id.btnBoostWithVisibility -> {
|
R.id.btnBoostWithVisibility -> {
|
||||||
|
|
|
@ -1093,7 +1093,7 @@ internal class ItemViewHolder(
|
||||||
} else {
|
} else {
|
||||||
val m = reply.mentions?.find { it.id == accountId }
|
val m = reply.mentions?.find { it.id == accountId }
|
||||||
if(m != null) {
|
if(m != null) {
|
||||||
AcctColor.getNicknameWithColor(access_info,m.acct)
|
AcctColor.getNicknameWithColor(access_info,m.acctAscii)
|
||||||
} else {
|
} else {
|
||||||
SpannableString("ID(${accountId})")
|
SpannableString("ID(${accountId})")
|
||||||
}
|
}
|
||||||
|
@ -1409,12 +1409,12 @@ internal class ItemViewHolder(
|
||||||
try {
|
try {
|
||||||
if(! Column.useInstanceTicker) return
|
if(! Column.useInstanceTicker) return
|
||||||
|
|
||||||
val host = who.host
|
val host = who.hostAscii
|
||||||
|
|
||||||
// LTLでホスト名が同じならTickerを表示しない
|
// LTLでホスト名が同じならTickerを表示しない
|
||||||
when(column.type) {
|
when(column.type) {
|
||||||
ColumnType.LOCAL, ColumnType.LOCAL_AROUND -> {
|
ColumnType.LOCAL, ColumnType.LOCAL_AROUND -> {
|
||||||
if(host == access_info.host) return
|
if(host == access_info.hostAscii) return
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -2142,7 +2142,7 @@ internal class ItemViewHolder(
|
||||||
is TootTag -> {
|
is TootTag -> {
|
||||||
// search_tag は#を含まない
|
// search_tag は#を含まない
|
||||||
val tagEncoded = item.name.encodePercent()
|
val tagEncoded = item.name.encodePercent()
|
||||||
val host = access_info.host
|
val host = access_info.hostAscii
|
||||||
val url = "https://$host/tags/$tagEncoded"
|
val url = "https://$host/tags/$tagEncoded"
|
||||||
Action_HashTag.timelineOtherInstance(
|
Action_HashTag.timelineOtherInstance(
|
||||||
activity = activity,
|
activity = activity,
|
||||||
|
@ -2469,7 +2469,7 @@ internal class ItemViewHolder(
|
||||||
setPadding(paddingH, paddingV, paddingH, paddingV)
|
setPadding(paddingH, paddingV, paddingH, paddingV)
|
||||||
|
|
||||||
val emoji = status.custom_emojis?.get(customCode)
|
val emoji = status.custom_emojis?.get(customCode)
|
||||||
?: App1.custom_emoji_lister.getMap(access_info.host, true)
|
?: App1.custom_emoji_lister.getMap(access_info.hostAscii, true)
|
||||||
?.get(customCode)
|
?.get(customCode)
|
||||||
|
|
||||||
val emojiUrl = emoji?.let {
|
val emojiUrl = emoji?.let {
|
||||||
|
|
|
@ -991,7 +991,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
for(t in thread_list) {
|
for(t in thread_list) {
|
||||||
if(! t.isAlive) continue
|
if(! t.isAlive) continue
|
||||||
if(job.isJobCancelled) t.cancel()
|
if(job.isJobCancelled) t.cancel()
|
||||||
liveSet.add(t.account.host)
|
liveSet.add(t.account.hostAscii)
|
||||||
}
|
}
|
||||||
if(liveSet.isEmpty()) break
|
if(liveSet.isEmpty()) break
|
||||||
|
|
||||||
|
@ -1076,7 +1076,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
|
|
||||||
val wps_log = wps.log
|
val wps_log = wps.log
|
||||||
if(wps_log.isNotEmpty())
|
if(wps_log.isNotEmpty())
|
||||||
log.d("PushSubscriptionHelper: ${account.acct} $wps_log")
|
log.d("PushSubscriptionHelper: ${account.acctPretty} $wps_log")
|
||||||
|
|
||||||
if(job.isJobCancelled) return
|
if(job.isJobCancelled) return
|
||||||
|
|
||||||
|
@ -1243,14 +1243,14 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
val dataList = dstListData
|
val dataList = dstListData
|
||||||
val first = dataList.firstOrNull()
|
val first = dataList.firstOrNull()
|
||||||
if(first == null) {
|
if(first == null) {
|
||||||
log.d("showNotification[${account.acct}/$notification_tag] cancel notification.")
|
log.d("showNotification[${account.acctPretty}/$notification_tag] cancel notification.")
|
||||||
if(Build.VERSION.SDK_INT >= 23 && Pref.bpDivideNotification(pref)) {
|
if(Build.VERSION.SDK_INT >= 23 && Pref.bpDivideNotification(pref)) {
|
||||||
notification_manager.activeNotifications?.forEach {
|
notification_manager.activeNotifications?.forEach {
|
||||||
if(it != null &&
|
if(it != null &&
|
||||||
it.id == NOTIFICATION_ID &&
|
it.id == NOTIFICATION_ID &&
|
||||||
it.tag.startsWith("$notification_tag/")
|
it.tag.startsWith("$notification_tag/")
|
||||||
) {
|
) {
|
||||||
log.d("cancel: ${it.tag} context=${account.acct} $notification_tag")
|
log.d("cancel: ${it.tag} context=${account.acctPretty} $notification_tag")
|
||||||
notification_manager.cancel(it.tag, NOTIFICATION_ID)
|
notification_manager.cancel(it.tag, NOTIFICATION_ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1267,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
) {
|
) {
|
||||||
// 先頭にあるデータが同じなら、通知を更新しない
|
// 先頭にあるデータが同じなら、通知を更新しない
|
||||||
// このマーカーは端末再起動時にリセットされるので、再起動後は通知が出るはず
|
// このマーカーは端末再起動時にリセットされるので、再起動後は通知が出るはず
|
||||||
log.d("showNotification[${account.acct}] id=${first.notification.id} is already shown.")
|
log.d("showNotification[${account.acctPretty}] id=${first.notification.id} is already shown.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1302,8 +1302,6 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
|
|
||||||
createNotification(itemTag,notificationId = item.notification.id.toString()) { builder ->
|
createNotification(itemTag,notificationId = item.notification.id.toString()) { builder ->
|
||||||
|
|
||||||
val myAcct = item.access_info.acct
|
|
||||||
|
|
||||||
builder.setWhen(item.notification.time_created_at)
|
builder.setWhen(item.notification.time_created_at)
|
||||||
|
|
||||||
val summary = getNotificationLine(item)
|
val summary = getNotificationLine(item)
|
||||||
|
@ -1313,11 +1311,11 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
builder.setStyle(
|
builder.setStyle(
|
||||||
NotificationCompat.BigTextStyle()
|
NotificationCompat.BigTextStyle()
|
||||||
.setBigContentTitle(summary)
|
.setBigContentTitle(summary)
|
||||||
.setSummaryText(myAcct)
|
.setSummaryText(item.access_info.acctPretty)
|
||||||
.bigText(content)
|
.bigText(content)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
builder.setContentText(myAcct)
|
builder.setContentText(item.access_info.acctPretty)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Build.VERSION.SDK_INT < 26) {
|
if(Build.VERSION.SDK_INT < 26) {
|
||||||
|
@ -1369,18 +1367,16 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
}
|
}
|
||||||
// リストにない通知は消さない。ある通知をユーザが指で削除した際に他の通知が残ってほしい場合がある
|
// リストにない通知は消さない。ある通知をユーザが指で削除した際に他の通知が残ってほしい場合がある
|
||||||
} else {
|
} else {
|
||||||
log.d("showNotification[${account.acct}] creating notification(1)")
|
log.d("showNotification[${account.acctPretty}] creating notification(1)")
|
||||||
createNotification(notification_tag) { builder ->
|
createNotification(notification_tag) { builder ->
|
||||||
|
|
||||||
builder.setWhen(first.notification.time_created_at)
|
builder.setWhen(first.notification.time_created_at)
|
||||||
|
|
||||||
var a = getNotificationLine(first)
|
var a = getNotificationLine(first)
|
||||||
|
|
||||||
val myAcct = account.acct
|
|
||||||
|
|
||||||
if(dataList.size == 1) {
|
if(dataList.size == 1) {
|
||||||
builder.setContentTitle(a)
|
builder.setContentTitle(a)
|
||||||
builder.setContentText(myAcct)
|
builder.setContentText( account.acctPretty)
|
||||||
} else {
|
} else {
|
||||||
val header =
|
val header =
|
||||||
context.getString(R.string.notification_count, dataList.size)
|
context.getString(R.string.notification_count, dataList.size)
|
||||||
|
@ -1389,7 +1385,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
|
|
||||||
val style = NotificationCompat.InboxStyle()
|
val style = NotificationCompat.InboxStyle()
|
||||||
.setBigContentTitle(header)
|
.setBigContentTitle(header)
|
||||||
.setSummaryText(myAcct)
|
.setSummaryText( account.acctPretty)
|
||||||
for(i in 0 .. 4) {
|
for(i in 0 .. 4) {
|
||||||
if(i >= dataList.size) break
|
if(i >= dataList.size) break
|
||||||
val item = dataList[i]
|
val item = dataList[i]
|
||||||
|
@ -1454,7 +1450,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
notificationId : String? = null,
|
notificationId : String? = null,
|
||||||
setContent : (builder : NotificationCompat.Builder) -> Unit
|
setContent : (builder : NotificationCompat.Builder) -> Unit
|
||||||
) {
|
) {
|
||||||
log.d("showNotification[${account.acct}] creating notification(1)")
|
log.d("showNotification[${account.acctPretty}] creating notification(1)")
|
||||||
|
|
||||||
val builder = if(Build.VERSION.SDK_INT >= 26) {
|
val builder = if(Build.VERSION.SDK_INT >= 26) {
|
||||||
// Android 8 から、通知のスタイルはユーザが管理することになった
|
// Android 8 から、通知のスタイルはユーザが管理することになった
|
||||||
|
@ -1523,15 +1519,15 @@ class PollingWorker private constructor(contextArg : Context) {
|
||||||
// Android 7.0 ではグループを指定しないと勝手に通知が束ねられてしまう。
|
// Android 7.0 ではグループを指定しないと勝手に通知が束ねられてしまう。
|
||||||
// 束ねられた通知をタップしても pi_click が実行されないので困るため、
|
// 束ねられた通知をタップしても pi_click が実行されないので困るため、
|
||||||
// アカウント別にグループキーを設定する
|
// アカウント別にグループキーを設定する
|
||||||
setGroup(context.packageName + ":" + account.acct)
|
setGroup(context.packageName + ":" + account.acctAscii)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.d("showNotification[${account.acct}] creating notification(3)")
|
log.d("showNotification[${account.acctPretty}] creating notification(3)")
|
||||||
|
|
||||||
setContent(builder)
|
setContent(builder)
|
||||||
|
|
||||||
log.d("showNotification[${account.acct}] set notification...")
|
log.d("showNotification[${account.acctPretty}] set notification...")
|
||||||
|
|
||||||
notification_manager.notify(notification_tag, NOTIFICATION_ID, builder.build())
|
notification_manager.notify(notification_tag, NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ internal class StreamReader(
|
||||||
|
|
||||||
private fun fireDeleteId(id : EntityId) {
|
private fun fireDeleteId(id : EntityId) {
|
||||||
|
|
||||||
val tl_host = access_info.host
|
val tl_host = access_info.hostAscii
|
||||||
runOnMainLooper {
|
runOnMainLooper {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(bDisposed.get()) return@synchronized
|
if(bDisposed.get()) return@synchronized
|
||||||
|
|
|
@ -113,7 +113,7 @@ internal class ViewHolderHeaderInstance(
|
||||||
btnEmail.isEnabled = email.isNotEmpty()
|
btnEmail.isEnabled = email.isNotEmpty()
|
||||||
|
|
||||||
val contact_acct =
|
val contact_acct =
|
||||||
instance.contact_account?.let { who -> "@" + who.username + "@" + who.host } ?: ""
|
instance.contact_account?.let { who -> "@" + who.username + "@" + who.hostAscii } ?: ""
|
||||||
btnContact.text = contact_acct
|
btnContact.text = contact_acct
|
||||||
btnContact.isEnabled = contact_acct.isNotEmpty()
|
btnContact.isEnabled = contact_acct.isNotEmpty()
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ internal class ViewHolderHeaderInstance(
|
||||||
, activity.nextPosition(column)
|
, activity.nextPosition(column)
|
||||||
, ColumnType.SEARCH
|
, ColumnType.SEARCH
|
||||||
|
|
||||||
, args = arrayOf("@" + who.username + "@" + who.host, true)
|
, args = arrayOf("@" + who.username + "@" + who.hostAscii, true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,10 +99,11 @@ fun makeAccountListNonPseudo(
|
||||||
val list_other_host = ArrayList<SavedAccount>()
|
val list_other_host = ArrayList<SavedAccount>()
|
||||||
for(a in SavedAccount.loadAccountList(context)) {
|
for(a in SavedAccount.loadAccountList(context)) {
|
||||||
if(a.isPseudo) continue
|
if(a.isPseudo) continue
|
||||||
(if(pickup_host == null || pickup_host.equals(
|
(if(pickup_host == null || pickup_host.equals(a.hostAscii, ignoreCase = true) || pickup_host.equals(a.hostPretty, ignoreCase = true))
|
||||||
a.host,
|
list_same_host
|
||||||
ignoreCase = true
|
else
|
||||||
)) list_same_host else list_other_host).add(a)
|
list_other_host
|
||||||
|
).add(a)
|
||||||
}
|
}
|
||||||
SavedAccount.sort(list_same_host)
|
SavedAccount.sort(list_same_host)
|
||||||
SavedAccount.sort(list_other_host)
|
SavedAccount.sort(list_other_host)
|
||||||
|
@ -154,12 +155,8 @@ const val CROSS_ACCOUNT_REMOTE_INSTANCE = 3
|
||||||
internal fun calcCrossAccountMode(
|
internal fun calcCrossAccountMode(
|
||||||
timeline_account : SavedAccount,
|
timeline_account : SavedAccount,
|
||||||
action_account : SavedAccount
|
action_account : SavedAccount
|
||||||
) : Int {
|
) : Int =when{
|
||||||
return if(! timeline_account.host.equals(action_account.host, ignoreCase = true)) {
|
timeline_account == action_account -> NOT_CROSS_ACCOUNT
|
||||||
CROSS_ACCOUNT_REMOTE_INSTANCE
|
timeline_account.matchHost(action_account.hostAscii) -> CROSS_ACCOUNT_SAME_INSTANCE
|
||||||
} else if(! timeline_account.acct.equals(action_account.acct, ignoreCase = true)) {
|
else -> CROSS_ACCOUNT_REMOTE_INSTANCE
|
||||||
CROSS_ACCOUNT_SAME_INSTANCE
|
|
||||||
} else {
|
|
||||||
NOT_CROSS_ACCOUNT
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,7 +240,7 @@ object Action_Account {
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnType.PROFILE_DIRECTORY -> {
|
ColumnType.PROFILE_DIRECTORY -> {
|
||||||
activity.addColumn(pos, ai, type, ai.host)
|
activity.addColumn(pos, ai, type, ai.hostAscii)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> activity.addColumn(pos, ai, type, *args)
|
else -> activity.addColumn(pos, ai, type, *args)
|
||||||
|
|
|
@ -47,7 +47,7 @@ object Action_Filter {
|
||||||
if( filterList != null) {
|
if( filterList != null) {
|
||||||
showToast(activity, false, R.string.delete_succeeded)
|
showToast(activity, false, R.string.delete_succeeded)
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
if( column.access_info.acct == access_info.acct){
|
if( column.access_info == access_info ){
|
||||||
column.onFilterDeleted(filter,filterList)
|
column.onFilterDeleted(filter,filterList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
import jp.juggler.subwaytooter.table.UserRelation
|
import jp.juggler.subwaytooter.table.UserRelation
|
||||||
import jp.juggler.subwaytooter.util.EmptyCallback
|
import jp.juggler.subwaytooter.util.EmptyCallback
|
||||||
import jp.juggler.util.*
|
import jp.juggler.util.*
|
||||||
import java.net.IDN
|
|
||||||
|
|
||||||
object Action_Follow {
|
object Action_Follow {
|
||||||
|
|
||||||
|
@ -193,12 +192,12 @@ object Action_Follow {
|
||||||
// 検索APIを呼び出さないようにする
|
// 検索APIを呼び出さないようにする
|
||||||
val result = client.request("/api/v1/accounts/${userId}")
|
val result = client.request("/api/v1/accounts/${userId}")
|
||||||
?: return null
|
?: return null
|
||||||
who.acct == parser.account(result.jsonObject)?.acct
|
who.acctAscii == parser.account(result.jsonObject)?.acctAscii
|
||||||
}
|
}
|
||||||
|
|
||||||
if(! skipAccountSync) {
|
if(! skipAccountSync) {
|
||||||
// 同タンスのIDではなかった場合、検索APIを使う
|
// 同タンスのIDではなかった場合、検索APIを使う
|
||||||
val (result, ar) = client.syncAccountByAcct(access_info, who.acct)
|
val (result, ar) = client.syncAccountByAcct(access_info, who.acctAscii)
|
||||||
val user = ar?.get() ?: return result
|
val user = ar?.get() ?: return result
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
|
@ -346,7 +345,7 @@ object Action_Follow {
|
||||||
|
|
||||||
// リモートユーザの同期
|
// リモートユーザの同期
|
||||||
if(who.isRemote) {
|
if(who.isRemote) {
|
||||||
val (result, ar) = client.syncAccountByAcct(access_info, who.acct)
|
val (result, ar) = client.syncAccountByAcct(access_info, who.acctAscii)
|
||||||
val user = ar?.get() ?: return result
|
val user = ar?.get() ?: return result
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
|
@ -573,7 +572,7 @@ object Action_Follow {
|
||||||
activity,
|
activity,
|
||||||
bAuto = false,
|
bAuto = false,
|
||||||
message = activity.getString(R.string.account_picker_follow),
|
message = activity.getString(R.string.account_picker_follow),
|
||||||
accountListArg = makeAccountListNonPseudo(activity, account.host)
|
accountListArg = makeAccountListNonPseudo(activity, account.hostAscii)
|
||||||
) { ai ->
|
) { ai ->
|
||||||
followRemote(
|
followRemote(
|
||||||
activity,
|
activity,
|
||||||
|
@ -643,7 +642,7 @@ object Action_Follow {
|
||||||
column.removeUser(access_info, ColumnType.FOLLOW_REQUESTS, who.id)
|
column.removeUser(access_info, ColumnType.FOLLOW_REQUESTS, who.id)
|
||||||
|
|
||||||
// 他のカラムでもフォロー状態の表示更新が必要
|
// 他のカラムでもフォロー状態の表示更新が必要
|
||||||
if(column.access_info.acct == access_info.acct
|
if(column.access_info == access_info
|
||||||
&& column.type != ColumnType.FOLLOW_REQUESTS
|
&& column.type != ColumnType.FOLLOW_REQUESTS
|
||||||
) {
|
) {
|
||||||
column.fireRebindAdapterItems()
|
column.fireRebindAdapterItems()
|
||||||
|
|
|
@ -122,22 +122,34 @@ object Action_HashTag {
|
||||||
val list_other = ArrayList<SavedAccount>()
|
val list_other = ArrayList<SavedAccount>()
|
||||||
for(a in account_list) {
|
for(a in account_list) {
|
||||||
if( acctAscii == null){
|
if( acctAscii == null){
|
||||||
if(! host.equals(a.host, ignoreCase = true)) {
|
when {
|
||||||
list_other.add(a)
|
! host.equals(a.hostAscii, ignoreCase = true) -> {
|
||||||
} else if(a.isPseudo) {
|
list_other.add(a)
|
||||||
list_original_pseudo.add(a)
|
}
|
||||||
} else {
|
a.isPseudo -> {
|
||||||
list_original.add(a)
|
list_original_pseudo.add(a)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
list_original.add(a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(a.isPseudo) {
|
when {
|
||||||
|
|
||||||
// acctからidを取得できない
|
// acctからidを取得できない
|
||||||
}else if(a.isMisskey) {
|
a.isPseudo -> {
|
||||||
|
}
|
||||||
|
|
||||||
// ミスキーのアカウント別タグTLは未対応
|
// ミスキーのアカウント別タグTLは未対応
|
||||||
}else if(! host.equals(a.host, ignoreCase = true)) {
|
a.isMisskey -> {
|
||||||
list_other.add(a)
|
}
|
||||||
} else {
|
|
||||||
list_original.add(a)
|
! host.equals(a.hostAscii, ignoreCase = true) -> {
|
||||||
|
list_other.add(a)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
list_original.add(a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,8 +175,8 @@ object Action_HashTag {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,
|
a.acctAscii,
|
||||||
a.prettyAcct
|
a.acctPretty
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{ timeline(activity, pos, a, tag_without_sharp,acctAscii) }
|
{ timeline(activity, pos, a, tag_without_sharp,acctAscii) }
|
||||||
|
@ -174,8 +186,8 @@ object Action_HashTag {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,
|
a.acctAscii,
|
||||||
a.prettyAcct
|
a.acctPretty
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{ timeline(activity, pos, a, tag_without_sharp,acctAscii) }
|
{ timeline(activity, pos, a, tag_without_sharp,acctAscii) }
|
||||||
|
@ -185,8 +197,8 @@ object Action_HashTag {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,
|
a.acctAscii,
|
||||||
a.prettyAcct
|
a.acctPretty
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{ timeline(activity, pos, a, tag_without_sharp,acctAscii) }
|
{ timeline(activity, pos, a, tag_without_sharp,acctAscii) }
|
||||||
|
|
|
@ -48,7 +48,7 @@ object Action_Instance {
|
||||||
App1.openBrowser(activity, "https://$host/explore")
|
App1.openBrowser(activity, "https://$host/explore")
|
||||||
|
|
||||||
// ホスト名部分が一致するならそのアカウントで開く
|
// ホスト名部分が一致するならそのアカウントで開く
|
||||||
accessInfo.host == host ->
|
accessInfo.hostAscii == host ->
|
||||||
activity.addColumn(
|
activity.addColumn(
|
||||||
false,
|
false,
|
||||||
pos,
|
pos,
|
||||||
|
@ -83,7 +83,7 @@ object Action_Instance {
|
||||||
ColumnType.PROFILE_DIRECTORY.name1(activity)
|
ColumnType.PROFILE_DIRECTORY.name1(activity)
|
||||||
)
|
)
|
||||||
) { ai ->
|
) { ai ->
|
||||||
profileDirectory(activity, ai, ai.host)
|
profileDirectory(activity, ai, ai.hostAscii)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ object Action_Instance {
|
||||||
// 指定タンスのアカウントを持ってるか?
|
// 指定タンスのアカウントを持ってるか?
|
||||||
val account_list = ArrayList<SavedAccount>()
|
val account_list = ArrayList<SavedAccount>()
|
||||||
for(a in SavedAccount.loadAccountList(activity)) {
|
for(a in SavedAccount.loadAccountList(activity)) {
|
||||||
if(host.equals(a.host, ignoreCase = true)) account_list.add(a)
|
if(host.equals(a.hostAscii, ignoreCase = true)) account_list.add(a)
|
||||||
}
|
}
|
||||||
if(account_list.isEmpty()) {
|
if(account_list.isEmpty()) {
|
||||||
// 持ってないなら疑似アカウントを追加する
|
// 持ってないなら疑似アカウントを追加する
|
||||||
|
@ -159,7 +159,7 @@ object Action_Instance {
|
||||||
activity : ActMain, access_info : SavedAccount, domain : String, bBlock : Boolean
|
activity : ActMain, access_info : SavedAccount, domain : String, bBlock : Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if(access_info.host.equals(domain, ignoreCase = true)) {
|
if(access_info.matchHost(domain)) {
|
||||||
showToast(activity, false, R.string.it_is_you)
|
showToast(activity, false, R.string.it_is_you)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ object Action_Instance {
|
||||||
a.isMisskey -> continue@label
|
a.isMisskey -> continue@label
|
||||||
|
|
||||||
// 閲覧アカウントとホスト名が同じならステータスIDの変換が必要ない
|
// 閲覧アカウントとホスト名が同じならステータスIDの変換が必要ない
|
||||||
a.host.equals(access_info.host, ignoreCase = true) -> {
|
a.matchHost(access_info.hostAscii) -> {
|
||||||
if(! allowPseudo && a.isPseudo) continue@label
|
if(! allowPseudo && a.isPseudo) continue@label
|
||||||
account_list1.add(a)
|
account_list1.add(a)
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ object Action_Instance {
|
||||||
message = "select account to read timeline",
|
message = "select account to read timeline",
|
||||||
accountListArg = account_list1
|
accountListArg = account_list1
|
||||||
) { ai ->
|
) { ai ->
|
||||||
if(! ai.isNA && ai.host.equals(access_info.host, ignoreCase = true)) {
|
if(! ai.isNA && ai.matchHost(access_info.hostAscii)) {
|
||||||
timelinePublicAround2(activity, ai, pos, status.id, type)
|
timelinePublicAround2(activity, ai, pos, status.id, type)
|
||||||
} else {
|
} else {
|
||||||
timelinePublicAround3(activity, ai, pos, status, type)
|
timelinePublicAround3(activity, ai, pos, status, type)
|
||||||
|
|
|
@ -60,7 +60,7 @@ object Action_ListMember {
|
||||||
|
|
||||||
// リモートユーザの解決
|
// リモートユーザの解決
|
||||||
if(! access_info.isLocalUser(local_who)) {
|
if(! access_info.isLocalUser(local_who)) {
|
||||||
val (r2, ar) = client.syncAccountByAcct(access_info, local_who.acct)
|
val (r2, ar) = client.syncAccountByAcct(access_info, local_who.acctAscii)
|
||||||
val user = ar?.get() ?: return r2
|
val user = ar?.get() ?: return r2
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ object Action_Notification {
|
||||||
if(result.jsonObject != null) {
|
if(result.jsonObject != null) {
|
||||||
// ok. api have return empty object.
|
// ok. api have return empty object.
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
if(column.isNotificationColumn && column.access_info.acct == target_account.acct) {
|
if(column.isNotificationColumn && column.access_info == target_account ) {
|
||||||
column.removeNotifications()
|
column.removeNotifications()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ object Action_Toot {
|
||||||
status : TootStatus?
|
status : TootStatus?
|
||||||
) {
|
) {
|
||||||
if(status == null) return
|
if(status == null) return
|
||||||
val who_host = timeline_account.host
|
val who_host = timeline_account.hostAscii
|
||||||
|
|
||||||
AccountPicker.pick(
|
AccountPicker.pick(
|
||||||
activity,
|
activity,
|
||||||
|
@ -194,13 +194,13 @@ object Action_Toot {
|
||||||
}
|
}
|
||||||
|
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
column.findStatus(access_info.host, new_status.id) { account, status ->
|
column.findStatus(access_info.hostAscii, new_status.id) { account, status ->
|
||||||
|
|
||||||
// 同タンス別アカウントでもカウントは変化する
|
// 同タンス別アカウントでもカウントは変化する
|
||||||
status.favourites_count = new_status.favourites_count
|
status.favourites_count = new_status.favourites_count
|
||||||
|
|
||||||
// 同アカウントならfav状態を変化させる
|
// 同アカウントならfav状態を変化させる
|
||||||
if(access_info.acct == account.acct) {
|
if(access_info == account ) {
|
||||||
status.favourited = new_status.favourited
|
status.favourited = new_status.favourited
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ object Action_Toot {
|
||||||
status : TootStatus?
|
status : TootStatus?
|
||||||
) {
|
) {
|
||||||
if(status == null) return
|
if(status == null) return
|
||||||
val who_host = timeline_account.host
|
val who_host = timeline_account.hostAscii
|
||||||
|
|
||||||
AccountPicker.pick(
|
AccountPicker.pick(
|
||||||
activity,
|
activity,
|
||||||
|
@ -330,10 +330,10 @@ object Action_Toot {
|
||||||
|
|
||||||
new_status != null -> {
|
new_status != null -> {
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
column.findStatus(access_info.host, new_status.id) { account, status ->
|
column.findStatus(access_info.hostAscii, new_status.id) { account, status ->
|
||||||
|
|
||||||
// 同アカウントならブックマーク状態を伝播する
|
// 同アカウントならブックマーク状態を伝播する
|
||||||
if(access_info.acct == account.acct) {
|
if(access_info == account ) {
|
||||||
status.bookmarked = new_status.bookmarked
|
status.bookmarked = new_status.bookmarked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ object Action_Toot {
|
||||||
) {
|
) {
|
||||||
status ?: return
|
status ?: return
|
||||||
|
|
||||||
val who_host = timeline_account.host
|
val who_host = timeline_account.hostAscii
|
||||||
val status_owner = timeline_account.getFullAcct(status.account)
|
val status_owner = timeline_account.getFullAcct(status.account)
|
||||||
|
|
||||||
val isPrivateToot = timeline_account.isMastodon &&
|
val isPrivateToot = timeline_account.isMastodon &&
|
||||||
|
@ -371,7 +371,7 @@ object Action_Toot {
|
||||||
if(isPrivateToot) {
|
if(isPrivateToot) {
|
||||||
val list = ArrayList<SavedAccount>()
|
val list = ArrayList<SavedAccount>()
|
||||||
for(a in SavedAccount.loadAccountList(activity)) {
|
for(a in SavedAccount.loadAccountList(activity)) {
|
||||||
if(a.acct == status_owner) list.add(a)
|
if(a.acctAscii == status_owner) list.add(a)
|
||||||
}
|
}
|
||||||
if(list.isEmpty()) {
|
if(list.isEmpty()) {
|
||||||
showToast(activity, false, R.string.boost_private_toot_not_allowed)
|
showToast(activity, false, R.string.boost_private_toot_not_allowed)
|
||||||
|
@ -434,7 +434,7 @@ object Action_Toot {
|
||||||
// Mastodonは非公開トゥートをブーストできるのは本人だけ
|
// Mastodonは非公開トゥートをブーストできるのは本人だけ
|
||||||
val isPrivateToot = access_info.isMastodon &&
|
val isPrivateToot = access_info.isMastodon &&
|
||||||
arg_status.visibility == TootVisibility.PrivateFollowers
|
arg_status.visibility == TootVisibility.PrivateFollowers
|
||||||
if(isPrivateToot && access_info.acct != status_owner_acct) {
|
if(isPrivateToot && access_info.acctAscii != status_owner_acct) {
|
||||||
showToast(activity, false, R.string.boost_private_toot_not_allowed)
|
showToast(activity, false, R.string.boost_private_toot_not_allowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -587,15 +587,13 @@ object Action_Toot {
|
||||||
val count = max(0, (arg_status.reblogs_count ?: 1) - 1)
|
val count = max(0, (arg_status.reblogs_count ?: 1) - 1)
|
||||||
|
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
column.findStatus(access_info.host, arg_status.id) { account, status ->
|
column.findStatus(access_info.hostAscii, arg_status.id) { account, status ->
|
||||||
|
|
||||||
// 同タンス別アカウントでもカウントは変化する
|
// 同タンス別アカウントでもカウントは変化する
|
||||||
status.reblogs_count = count
|
status.reblogs_count = count
|
||||||
|
|
||||||
// 同アカウントならreblogged状態を変化させる
|
// 同アカウントならreblogged状態を変化させる
|
||||||
if(access_info.acct == account.acct &&
|
if(access_info == account && status.myRenoteId == unrenoteId ) {
|
||||||
status.myRenoteId == unrenoteId
|
|
||||||
) {
|
|
||||||
status.myRenoteId = null
|
status.myRenoteId = null
|
||||||
status.reblogged = false
|
status.reblogged = false
|
||||||
}
|
}
|
||||||
|
@ -623,12 +621,12 @@ object Action_Toot {
|
||||||
}
|
}
|
||||||
|
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
column.findStatus(access_info.host, new_status.id) { account, status ->
|
column.findStatus(access_info.hostAscii, new_status.id) { account, status ->
|
||||||
|
|
||||||
// 同タンス別アカウントでもカウントは変化する
|
// 同タンス別アカウントでもカウントは変化する
|
||||||
status.reblogs_count = new_status.reblogs_count
|
status.reblogs_count = new_status.reblogs_count
|
||||||
|
|
||||||
if(access_info.acct == account.acct) {
|
if(access_info == account ) {
|
||||||
|
|
||||||
// 同アカウントならreblog状態を変化させる
|
// 同アカウントならreblog状態を変化させる
|
||||||
when {
|
when {
|
||||||
|
@ -689,7 +687,7 @@ object Action_Toot {
|
||||||
if(result.jsonObject != null) {
|
if(result.jsonObject != null) {
|
||||||
showToast(activity, false, R.string.delete_succeeded)
|
showToast(activity, false, R.string.delete_succeeded)
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
column.onStatusRemoved(access_info.host, status_id)
|
column.onStatusRemoved(access_info.hostAscii, status_id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showToast(activity, false, result.error)
|
showToast(activity, false, result.error)
|
||||||
|
@ -731,7 +729,7 @@ object Action_Toot {
|
||||||
access_info : SavedAccount,
|
access_info : SavedAccount,
|
||||||
status : TootStatus
|
status : TootStatus
|
||||||
) {
|
) {
|
||||||
if(access_info.isNA || ! access_info.host.equals(status.host_access, ignoreCase = true)) {
|
if(access_info.isNA || ! access_info.matchHost(status.host_access)) {
|
||||||
conversationOtherInstance(activity, pos, status)
|
conversationOtherInstance(activity, pos, status)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -845,11 +843,11 @@ object Action_Toot {
|
||||||
// 疑似アカウントは後でまとめて処理する
|
// 疑似アカウントは後でまとめて処理する
|
||||||
if(a.isPseudo) continue
|
if(a.isPseudo) continue
|
||||||
|
|
||||||
if(status_id_original != null && a.host.equals(host_original, ignoreCase = true)) {
|
if(status_id_original != null && a.matchHost(host_original)) {
|
||||||
// アクセス情報+ステータスID でアクセスできるなら
|
// アクセス情報+ステータスID でアクセスできるなら
|
||||||
// 同タンスのアカウントならステータスIDの変換なしに表示できる
|
// 同タンスのアカウントならステータスIDの変換なしに表示できる
|
||||||
local_account_list.add(a)
|
local_account_list.add(a)
|
||||||
} else if(status_id_access != null && a.host.equals(host_access, ignoreCase = true)) {
|
} else if(status_id_access != null && a.matchHost(host_access)) {
|
||||||
// 既に変換済みのステータスIDがあるなら、そのアカウントでもステータスIDの変換は必要ない
|
// 既に変換済みのステータスIDがあるなら、そのアカウントでもステータスIDの変換は必要ない
|
||||||
access_account_list.add(a)
|
access_account_list.add(a)
|
||||||
} else {
|
} else {
|
||||||
|
@ -887,8 +885,8 @@ object Action_Toot {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,
|
a.acctAscii,
|
||||||
a.prettyAcct
|
a.acctPretty
|
||||||
)
|
)
|
||||||
) { conversationLocal(activity, pos, a, status_id_original) }
|
) { conversationLocal(activity, pos, a, status_id_original) }
|
||||||
}
|
}
|
||||||
|
@ -902,7 +900,8 @@ object Action_Toot {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,a.prettyAcct
|
a.acctAscii,
|
||||||
|
a.acctPretty
|
||||||
)
|
)
|
||||||
) { conversationLocal(activity, pos, a, status_id_access) }
|
) { conversationLocal(activity, pos, a, status_id_access) }
|
||||||
}
|
}
|
||||||
|
@ -915,7 +914,8 @@ object Action_Toot {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,a.prettyAcct
|
a.acctAscii,
|
||||||
|
a.acctPretty
|
||||||
)
|
)
|
||||||
) { conversationRemote(activity, pos, a, url) }
|
) { conversationRemote(activity, pos, a, url) }
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +1010,7 @@ object Action_Toot {
|
||||||
|
|
||||||
// step 1: choose account
|
// step 1: choose account
|
||||||
|
|
||||||
val host = statusArg.account.host
|
val host = statusArg.account.hostAscii
|
||||||
val local_account_list = ArrayList<SavedAccount>()
|
val local_account_list = ArrayList<SavedAccount>()
|
||||||
val other_account_list = ArrayList<SavedAccount>()
|
val other_account_list = ArrayList<SavedAccount>()
|
||||||
|
|
||||||
|
@ -1019,7 +1019,7 @@ object Action_Toot {
|
||||||
// 検索APIはログイン必須なので疑似アカウントは使えない
|
// 検索APIはログイン必須なので疑似アカウントは使えない
|
||||||
if(a.isPseudo) continue
|
if(a.isPseudo) continue
|
||||||
|
|
||||||
if(a.host.equals(host, ignoreCase = true)) {
|
if(a.matchHost(host)) {
|
||||||
local_account_list.add(a)
|
local_account_list.add(a)
|
||||||
} else {
|
} else {
|
||||||
other_account_list.add(a)
|
other_account_list.add(a)
|
||||||
|
@ -1034,7 +1034,8 @@ object Action_Toot {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,a.prettyAcct
|
a.acctAscii,
|
||||||
|
a.acctPretty
|
||||||
)
|
)
|
||||||
) { step2(a) }
|
) { step2(a) }
|
||||||
}
|
}
|
||||||
|
@ -1045,7 +1046,8 @@ object Action_Toot {
|
||||||
AcctColor.getStringWithNickname(
|
AcctColor.getStringWithNickname(
|
||||||
activity,
|
activity,
|
||||||
R.string.open_in_account,
|
R.string.open_in_account,
|
||||||
a.acct,a.prettyAcct
|
a.acctAscii,
|
||||||
|
a.acctPretty
|
||||||
)
|
)
|
||||||
) { step2(a) }
|
) { step2(a) }
|
||||||
}
|
}
|
||||||
|
@ -1089,9 +1091,9 @@ object Action_Toot {
|
||||||
|
|
||||||
new_status != null -> {
|
new_status != null -> {
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
if(access_info.acct == column.access_info.acct) {
|
if(access_info == column.access_info ) {
|
||||||
column.findStatus(
|
column.findStatus(
|
||||||
access_info.host,
|
access_info.hostAscii,
|
||||||
new_status.id
|
new_status.id
|
||||||
) { _, status ->
|
) { _, status ->
|
||||||
status.pinned = bSet
|
status.pinned = bSet
|
||||||
|
@ -1171,10 +1173,10 @@ object Action_Toot {
|
||||||
quotedRenote : Boolean = false
|
quotedRenote : Boolean = false
|
||||||
) {
|
) {
|
||||||
status ?: return
|
status ?: return
|
||||||
val who_host = timeline_account.host
|
val who_host = timeline_account.hostAscii
|
||||||
|
|
||||||
val accountCallback : SavedAccountCallback = { ai ->
|
val accountCallback : SavedAccountCallback = { ai ->
|
||||||
if(ai.host.equals(status.host_access, ignoreCase = true)) {
|
if(ai.matchHost(status.host_access)) {
|
||||||
// アクセス元ホストが同じならステータスIDを使って返信できる
|
// アクセス元ホストが同じならステータスIDを使って返信できる
|
||||||
reply(activity, ai, status, quotedRenote = quotedRenote)
|
reply(activity, ai, status, quotedRenote = quotedRenote)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1292,8 +1294,8 @@ object Action_Toot {
|
||||||
val ls = local_status
|
val ls = local_status
|
||||||
if(ls != null) {
|
if(ls != null) {
|
||||||
for(column in App1.getAppState(activity).column_list) {
|
for(column in App1.getAppState(activity).column_list) {
|
||||||
if(access_info.acct == column.access_info.acct) {
|
if(access_info == column.access_info ) {
|
||||||
column.findStatus(access_info.host, ls.id) { _, status ->
|
column.findStatus(access_info.hostAscii, ls.id) { _, status ->
|
||||||
status.muted = bMute
|
status.muted = bMute
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -1315,7 +1317,7 @@ object Action_Toot {
|
||||||
activity : ActMain,
|
activity : ActMain,
|
||||||
access_info : SavedAccount,
|
access_info : SavedAccount,
|
||||||
arg_status : TootStatus,
|
arg_status : TootStatus,
|
||||||
status_owner_acct : String,
|
status_owner_acct : String, // acctAscii
|
||||||
nCrossAccountMode : Int,
|
nCrossAccountMode : Int,
|
||||||
callback : EmptyCallback?,
|
callback : EmptyCallback?,
|
||||||
bSet : Boolean = true,
|
bSet : Boolean = true,
|
||||||
|
@ -1324,7 +1326,7 @@ object Action_Toot {
|
||||||
if(access_info.isPseudo || ! access_info.isMisskey) return
|
if(access_info.isPseudo || ! access_info.isMisskey) return
|
||||||
|
|
||||||
// 自分の投稿にはリアクション出来ない
|
// 自分の投稿にはリアクション出来ない
|
||||||
if(access_info.acct == status_owner_acct) {
|
if(access_info.acctAscii == status_owner_acct) {
|
||||||
showToast(activity, false, R.string.it_is_you)
|
showToast(activity, false, R.string.it_is_you)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import jp.juggler.subwaytooter.table.UserRelation
|
||||||
import jp.juggler.subwaytooter.util.TootApiResultCallback
|
import jp.juggler.subwaytooter.util.TootApiResultCallback
|
||||||
import jp.juggler.util.*
|
import jp.juggler.util.*
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import java.net.IDN
|
||||||
|
|
||||||
object Action_User {
|
object Action_User {
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ object Action_User {
|
||||||
}
|
}
|
||||||
// フォローアイコンの表示更新が走る
|
// フォローアイコンの表示更新が走る
|
||||||
column.updateFollowIcons(access_info)
|
column.updateFollowIcons(access_info)
|
||||||
} else if(column.access_info.acct == access_info.acct) {
|
} else if(column.access_info == access_info ) {
|
||||||
when {
|
when {
|
||||||
! relation.muting -> {
|
! relation.muting -> {
|
||||||
if(column.type == ColumnType.MUTES) {
|
if(column.type == ColumnType.MUTES) {
|
||||||
|
@ -288,7 +289,7 @@ object Action_User {
|
||||||
}
|
}
|
||||||
// フォローアイコンの表示更新が走る
|
// フォローアイコンの表示更新が走る
|
||||||
column.updateFollowIcons(access_info)
|
column.updateFollowIcons(access_info)
|
||||||
} else if(column.access_info.acct == access_info.acct) {
|
} else if(column.access_info == access_info ) {
|
||||||
|
|
||||||
when {
|
when {
|
||||||
|
|
||||||
|
@ -392,7 +393,7 @@ object Action_User {
|
||||||
who : TootAccount?
|
who : TootAccount?
|
||||||
) {
|
) {
|
||||||
if(who?.url == null) return
|
if(who?.url == null) return
|
||||||
val who_host = who.host
|
val who_host = who.hostAscii
|
||||||
|
|
||||||
AccountPicker.pick(
|
AccountPicker.pick(
|
||||||
activity,
|
activity,
|
||||||
|
@ -404,7 +405,7 @@ object Action_User {
|
||||||
),
|
),
|
||||||
accountListArg = makeAccountListNonPseudo(activity, who_host)
|
accountListArg = makeAccountListNonPseudo(activity, who_host)
|
||||||
) { ai ->
|
) { ai ->
|
||||||
if(ai.host.equals(access_info.host, ignoreCase = true)) {
|
if(ai.matchHost(access_info.hostAscii)) {
|
||||||
activity.addColumn(pos, ai, ColumnType.PROFILE, who.id)
|
activity.addColumn(pos, ai, ColumnType.PROFILE, who.id)
|
||||||
} else {
|
} else {
|
||||||
profileFromUrlOrAcct(activity, pos, ai, who.url, access_info.getFullAcct(who))
|
profileFromUrlOrAcct(activity, pos, ai, who.url, access_info.getFullAcct(who))
|
||||||
|
@ -432,16 +433,17 @@ object Action_User {
|
||||||
pos : Int,
|
pos : Int,
|
||||||
access_info : SavedAccount?,
|
access_info : SavedAccount?,
|
||||||
url : String,
|
url : String,
|
||||||
host : String,
|
hostArg : String,
|
||||||
user : String,
|
user : String,
|
||||||
original_url : String = url
|
original_url : String = url
|
||||||
) {
|
) {
|
||||||
val acct = "$user@$host"
|
val hostAscii = IDN.toASCII(hostArg,IDN.ALLOW_UNASSIGNED)
|
||||||
|
val acctAscii = "$user@$hostAscii"
|
||||||
|
|
||||||
if(access_info?.isPseudo == false) {
|
if(access_info?.isPseudo == false) {
|
||||||
// 文脈のアカウントがあり、疑似アカウントではない
|
// 文脈のアカウントがあり、疑似アカウントではない
|
||||||
|
|
||||||
if(access_info.host.equals(host, ignoreCase = true)) {
|
if(access_info.matchHost(hostAscii)) {
|
||||||
|
|
||||||
// 文脈のアカウントと同じインスタンスなら、アカウントIDを探して開いてしまう
|
// 文脈のアカウントと同じインスタンスなら、アカウントIDを探して開いてしまう
|
||||||
TootTaskRunner(activity).run(access_info, object : TootTask {
|
TootTaskRunner(activity).run(access_info, object : TootTask {
|
||||||
|
@ -449,7 +451,7 @@ object Action_User {
|
||||||
var who : TootAccount? = null
|
var who : TootAccount? = null
|
||||||
|
|
||||||
override fun background(client : TootApiClient) : TootApiResult? {
|
override fun background(client : TootApiClient) : TootApiResult? {
|
||||||
val (result, ar) = client.syncAccountByAcct(access_info, acct)
|
val (result, ar) = client.syncAccountByAcct(access_info, acctAscii)
|
||||||
who = ar?.get()
|
who = ar?.get()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -468,7 +470,7 @@ object Action_User {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 文脈のアカウントと異なるインスタンスなら、別アカウントで開く
|
// 文脈のアカウントと異なるインスタンスなら、別アカウントで開く
|
||||||
profileFromUrlOrAcct(activity, pos, access_info, url, acct)
|
profileFromUrlOrAcct(activity, pos, access_info, url, acctAscii)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -481,16 +483,16 @@ object Action_User {
|
||||||
// chrome tab で開く
|
// chrome tab で開く
|
||||||
App1.openCustomTab(activity, original_url)
|
App1.openCustomTab(activity, original_url)
|
||||||
} else {
|
} else {
|
||||||
val(asciiAcct,prettyAcct)=TootAccount.acctAndPrettyAcct("$user@$host")
|
val(_,acctPretty)=TootAccount.acctAndPrettyAcct(acctAscii)
|
||||||
AccountPicker.pick(
|
AccountPicker.pick(
|
||||||
activity,
|
activity,
|
||||||
bAllowPseudo = false,
|
bAllowPseudo = false,
|
||||||
bAuto = false,
|
bAuto = false,
|
||||||
message = activity.getString(
|
message = activity.getString(
|
||||||
R.string.account_picker_open_user_who,
|
R.string.account_picker_open_user_who,
|
||||||
AcctColor.getNickname(asciiAcct,prettyAcct)
|
AcctColor.getNickname(acctAscii,acctPretty)
|
||||||
),
|
),
|
||||||
accountListArg = makeAccountListNonPseudo(activity, host),
|
accountListArg = makeAccountListNonPseudo(activity, hostAscii),
|
||||||
extra_callback = { ll, pad_se, pad_tb ->
|
extra_callback = { ll, pad_se, pad_tb ->
|
||||||
|
|
||||||
// chrome tab で開くアクションを追加
|
// chrome tab で開くアクションを追加
|
||||||
|
@ -514,7 +516,7 @@ object Action_User {
|
||||||
ll.addView(b, 0)
|
ll.addView(b, 0)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
profileFromUrlOrAcct(activity, pos, it, url, acct)
|
profileFromUrlOrAcct(activity, pos, it, url, acctAscii)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -658,7 +660,7 @@ object Action_User {
|
||||||
activity : ActMain, access_info : SavedAccount, who : TootAccount?
|
activity : ActMain, access_info : SavedAccount, who : TootAccount?
|
||||||
) {
|
) {
|
||||||
if(who == null) return
|
if(who == null) return
|
||||||
val who_host = who.host
|
val who_host = who.hostAscii
|
||||||
|
|
||||||
val initial_text = "@" + access_info.getFullAcct(who) + " "
|
val initial_text = "@" + access_info.getFullAcct(who) + " "
|
||||||
AccountPicker.pick(
|
AccountPicker.pick(
|
||||||
|
|
|
@ -12,7 +12,7 @@ object TootAccountMap{
|
||||||
val watcher: String
|
val watcher: String
|
||||||
|
|
||||||
init{
|
init{
|
||||||
this.acct = parser.getFullAcct(who.acct)
|
this.acct = parser.getFullAcct(who.acctAscii)
|
||||||
|
|
||||||
this.watcher =when(parser.serviceType){
|
this.watcher =when(parser.serviceType){
|
||||||
ServiceType.MASTODON -> requireNotNull(parser.accessHost)
|
ServiceType.MASTODON -> requireNotNull(parser.accessHost)
|
||||||
|
|
|
@ -30,7 +30,7 @@ class TootApiClient(
|
||||||
// アカウントがある場合に使用する
|
// アカウントがある場合に使用する
|
||||||
var account : SavedAccount? = null
|
var account : SavedAccount? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
instance = value?.host
|
instance = value?.hostAscii
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1534,7 +1534,7 @@ fun TootApiClient.syncStatus(
|
||||||
)
|
)
|
||||||
.status(result.jsonObject)
|
.status(result.jsonObject)
|
||||||
?.apply {
|
?.apply {
|
||||||
if(host.equals(accessInfo.host, ignoreCase = true)) {
|
if(host.equals(accessInfo.hostAscii, ignoreCase = true)) {
|
||||||
return Pair(result, this)
|
return Pair(result, this)
|
||||||
}
|
}
|
||||||
uri.letNotEmpty { url = it }
|
uri.letNotEmpty { url = it }
|
||||||
|
|
|
@ -23,7 +23,7 @@ class TootParser(
|
||||||
val misskeyAccountDetailMap = HashMap<EntityId, TootAccount>()
|
val misskeyAccountDetailMap = HashMap<EntityId, TootAccount>()
|
||||||
|
|
||||||
val accessHost : String?
|
val accessHost : String?
|
||||||
get() = linkHelper.host
|
get() = linkHelper.hostAscii
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(linkHelper.isMisskey) serviceType = ServiceType.MISSKEY
|
if(linkHelper.isMisskey) serviceType = ServiceType.MISSKEY
|
||||||
|
|
|
@ -30,13 +30,13 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
val id : EntityId
|
val id : EntityId
|
||||||
|
|
||||||
// Equals username for local users, includes @domain for remote ones
|
// Equals username for local users, includes @domain for remote ones
|
||||||
val acct : String // punycode
|
val acctAscii : String // punycode
|
||||||
val prettyAcct : String // unicode
|
val prettyAcct : String // unicode
|
||||||
|
|
||||||
// The username of the account /[A-Za-z0-9_]{1,30}/
|
// The username of the account /[A-Za-z0-9_]{1,30}/
|
||||||
val username : String
|
val username : String
|
||||||
|
|
||||||
val host : String // punycode
|
val hostAscii : String // punycode
|
||||||
|
|
||||||
// The account's display name
|
// The account's display name
|
||||||
val display_name : String
|
val display_name : String
|
||||||
|
@ -99,10 +99,10 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
val isPro : Boolean
|
val isPro : Boolean
|
||||||
|
|
||||||
val isLocal :Boolean
|
val isLocal :Boolean
|
||||||
get() = !acct.contains('@')
|
get() = !acctAscii.contains('@')
|
||||||
|
|
||||||
val isRemote :Boolean
|
val isRemote :Boolean
|
||||||
get() = acct.contains('@')
|
get() = acctAscii.contains('@')
|
||||||
|
|
||||||
// user_hides_network is preference, not exposed in API
|
// user_hides_network is preference, not exposed in API
|
||||||
// val user_hides_network : Boolean
|
// val user_hides_network : Boolean
|
||||||
|
@ -129,7 +129,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
|
|
||||||
val remoteHost = src.string("host")
|
val remoteHost = src.string("host")
|
||||||
val tmpHost = (remoteHost ?: parser.accessHost ?: error("missing host")).toLowerCase(Locale.JAPAN)
|
val tmpHost = (remoteHost ?: parser.accessHost ?: error("missing host")).toLowerCase(Locale.JAPAN)
|
||||||
this.host = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
this.hostAscii = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
val prettyHost = IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
val prettyHost = IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
|
|
||||||
this.custom_emojis =
|
this.custom_emojis =
|
||||||
|
@ -138,7 +138,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
this.profile_emojis = null
|
this.profile_emojis = null
|
||||||
|
|
||||||
this.username = src.notEmptyOrThrow("username")
|
this.username = src.notEmptyOrThrow("username")
|
||||||
this.url = "https://$host/@$username"
|
this.url = "https://$hostAscii/@$username"
|
||||||
|
|
||||||
//
|
//
|
||||||
sv = src.string("name")
|
sv = src.string("name")
|
||||||
|
@ -162,7 +162,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
|
|
||||||
this.id = EntityId.mayDefault(src.string("id"))
|
this.id = EntityId.mayDefault(src.string("id"))
|
||||||
|
|
||||||
this.acct = when {
|
this.acctAscii = when {
|
||||||
|
|
||||||
// アクセス元から見て内部ユーザなら short acct
|
// アクセス元から見て内部ユーザなら short acct
|
||||||
remoteHost?.equals(
|
remoteHost?.equals(
|
||||||
|
@ -171,7 +171,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
) != false -> username
|
) != false -> username
|
||||||
|
|
||||||
// アクセス元から見て外部ユーザならfull acct
|
// アクセス元から見て外部ユーザならfull acct
|
||||||
else -> "$username@$host"
|
else -> "$username@$hostAscii"
|
||||||
}
|
}
|
||||||
|
|
||||||
this.prettyAcct = when {
|
this.prettyAcct = when {
|
||||||
|
@ -270,9 +270,9 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
findHostFromUrl(tmpAcct, hostAccess, url)
|
findHostFromUrl(tmpAcct, hostAccess, url)
|
||||||
?: throw RuntimeException("can't get host from acct or url")
|
?: throw RuntimeException("can't get host from acct or url")
|
||||||
).toLowerCase(Locale.JAPAN)
|
).toLowerCase(Locale.JAPAN)
|
||||||
this.host = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
this.hostAscii = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
val prettyHost = IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
val prettyHost = IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
this.acct = if( !tmpAcct.contains('@') ) tmpAcct else "$username@$host"
|
this.acctAscii = if( !tmpAcct.contains('@') ) tmpAcct else "$username@$hostAscii"
|
||||||
this.prettyAcct = if( !tmpAcct.contains('@') ) tmpAcct else "$username@$prettyHost"
|
this.prettyAcct = if( !tmpAcct.contains('@') ) tmpAcct else "$username@$prettyHost"
|
||||||
|
|
||||||
this.followers_count = src.long("followers_count")
|
this.followers_count = src.long("followers_count")
|
||||||
|
@ -297,10 +297,10 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
val tmpHost = (findHostFromUrl(sv, null, url)
|
val tmpHost = (findHostFromUrl(sv, null, url)
|
||||||
?: throw RuntimeException("can't get host from acct or url")
|
?: throw RuntimeException("can't get host from acct or url")
|
||||||
).toLowerCase(Locale.JAPAN)
|
).toLowerCase(Locale.JAPAN)
|
||||||
this.host = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
this.hostAscii = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
val prettyHost=IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
val prettyHost=IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
|
|
||||||
this.acct = this.username + "@" + this.host
|
this.acctAscii = this.username + "@" + this.hostAscii
|
||||||
this.prettyAcct = this.username + "@" + prettyHost
|
this.prettyAcct = this.username + "@" + prettyHost
|
||||||
|
|
||||||
this.followers_count = src.long("followers_count")
|
this.followers_count = src.long("followers_count")
|
||||||
|
@ -323,10 +323,10 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
val tmpHost = (findHostFromUrl(null, null, url)
|
val tmpHost = (findHostFromUrl(null, null, url)
|
||||||
?: throw RuntimeException("can't get host from url")
|
?: throw RuntimeException("can't get host from url")
|
||||||
).toLowerCase(Locale.JAPAN)
|
).toLowerCase(Locale.JAPAN)
|
||||||
this.host = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
this.hostAscii = IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
val prettyHost = IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
val prettyHost = IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
|
|
||||||
this.acct = this.username + "@" + host
|
this.acctAscii = this.username + "@" + hostAscii
|
||||||
this.prettyAcct = this.username + "@" + prettyHost
|
this.prettyAcct = this.username + "@" + prettyHost
|
||||||
|
|
||||||
this.followers_count = null
|
this.followers_count = null
|
||||||
|
@ -655,15 +655,13 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
|
||||||
|
|
||||||
|
|
||||||
fun acctAndPrettyAcct(src : String) : Pair<String, String> {
|
fun acctAndPrettyAcct(src : String) : Pair<String, String> {
|
||||||
val cols = src.split('@')
|
val cols = src.split("@")
|
||||||
|
if(cols.size < 2 ) return Pair(src,src)
|
||||||
val username = cols[0]
|
val username = cols[0]
|
||||||
return if(cols.size == 1)
|
return Pair(
|
||||||
Pair(username, username)
|
"$username@${IDN.toASCII(cols[1], IDN.ALLOW_UNASSIGNED)}",
|
||||||
else
|
"$username@${IDN.toUnicode(cols[1], IDN.ALLOW_UNASSIGNED)}"
|
||||||
Pair(
|
)
|
||||||
username + "@" + IDN.toASCII(cols[1], IDN.ALLOW_UNASSIGNED),
|
|
||||||
username + "@" + IDN.toUnicode(cols[1], IDN.ALLOW_UNASSIGNED)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,22 @@ import jp.juggler.util.JsonObject
|
||||||
class TootMention(
|
class TootMention(
|
||||||
val id : EntityId, // Account ID
|
val id : EntityId, // Account ID
|
||||||
val url : String, // URL of user's profile (can be remote)
|
val url : String, // URL of user's profile (can be remote)
|
||||||
val acct : String, // Equals username for local users, includes @domain for remote ones
|
acctArg : String, // Equals username for local users, includes @domain for remote ones
|
||||||
val username : String // The username of the account
|
val username : String // The username of the account
|
||||||
) {
|
) {
|
||||||
|
val acctAscii: String
|
||||||
|
val acctPretty:String
|
||||||
|
|
||||||
|
init{
|
||||||
|
val(acctAscii,acctPretty)=TootAccount.acctAndPrettyAcct(acctArg)
|
||||||
|
this.acctAscii = acctAscii
|
||||||
|
this.acctPretty = acctPretty
|
||||||
|
}
|
||||||
|
|
||||||
constructor(src : JsonObject) : this(
|
constructor(src : JsonObject) : this(
|
||||||
id = EntityId.mayDefault(src.string("id")),
|
id = EntityId.mayDefault(src.string("id")),
|
||||||
url = src.notEmptyOrThrow("url"),
|
url = src.notEmptyOrThrow("url"),
|
||||||
acct = src.notEmptyOrThrow("acct"),
|
acctArg = src.notEmptyOrThrow("acct"),
|
||||||
username = src.notEmptyOrThrow("username")
|
username = src.notEmptyOrThrow("username")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ class TootStatus(parser : TootParser, src : JsonObject) : TimelineItem() {
|
||||||
|
|
||||||
// 投稿元タンスのホスト名
|
// 投稿元タンスのホスト名
|
||||||
val host_original : String
|
val host_original : String
|
||||||
get() = account.host
|
get() = account.hostAscii
|
||||||
|
|
||||||
// 取得タンスのホスト名。トゥート検索サービスでは提供されずnullになる
|
// 取得タンスのホスト名。トゥート検索サービスでは提供されずnullになる
|
||||||
val host_access : String?
|
val host_access : String?
|
||||||
|
@ -646,7 +646,7 @@ class TootStatus(parser : TootParser, src : JsonObject) : TimelineItem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
mentions?.forEach {
|
mentions?.forEach {
|
||||||
if(fullAcctMe != access_info.getFullAcct(it.acct))
|
if(fullAcctMe != access_info.getFullAcct(it.acctAscii))
|
||||||
return@hasReceipt TootVisibility.DirectSpecified
|
return@hasReceipt TootVisibility.DirectSpecified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ object AccountPicker {
|
||||||
for(a in account_list) {
|
for(a in account_list) {
|
||||||
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
|
|
||||||
val ac = AcctColor.load(a.acct)
|
val ac = AcctColor.load(a.acctAscii)
|
||||||
|
|
||||||
val b = Button(activity)
|
val b = Button(activity)
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ object AccountPicker {
|
||||||
b.layoutParams = lp
|
b.layoutParams = lp
|
||||||
b.minHeight = (0.5f + 32f * density).toInt()
|
b.minHeight = (0.5f + 32f * density).toInt()
|
||||||
|
|
||||||
val sb = SpannableStringBuilder(if(AcctColor.hasNickname(ac)) ac.nickname else a.prettyAcct)
|
val sb = SpannableStringBuilder(if(AcctColor.hasNickname(ac)) ac.nickname else a.acctPretty)
|
||||||
if( a.last_notification_error?.isNotEmpty() == true) {
|
if( a.last_notification_error?.isNotEmpty() == true) {
|
||||||
sb.append("\n")
|
sb.append("\n")
|
||||||
val start = sb.length
|
val start = sb.length
|
||||||
|
|
|
@ -142,9 +142,8 @@ class DlgListMember(
|
||||||
//
|
//
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
val acct = a.acct
|
val ac = AcctColor.load(a.acctAscii)
|
||||||
val ac = AcctColor.load(acct)
|
val nickname = if(AcctColor.hasNickname(ac)) ac.nickname else a.acctPretty
|
||||||
val nickname = if(AcctColor.hasNickname(ac)) ac.nickname else acct
|
|
||||||
btnListOwner.text = nickname
|
btnListOwner.text = nickname
|
||||||
|
|
||||||
if(AcctColor.hasColorBackground(ac)) {
|
if(AcctColor.hasColorBackground(ac)) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ object ReportForm {
|
||||||
|
|
||||||
val cbForward : CheckBox = view.findViewById(R.id.cbForward)
|
val cbForward : CheckBox = view.findViewById(R.id.cbForward)
|
||||||
val tvForwardDesc:TextView = view.findViewById(R.id.tvForwardDesc)
|
val tvForwardDesc:TextView = view.findViewById(R.id.tvForwardDesc)
|
||||||
val canForward = access_info.host != who.host
|
val canForward = access_info.hostAscii != who.hostAscii
|
||||||
|
|
||||||
|
|
||||||
cbForward.isChecked = false
|
cbForward.isChecked = false
|
||||||
|
@ -43,7 +43,7 @@ object ReportForm {
|
||||||
}else{
|
}else{
|
||||||
cbForward.visibility = View.VISIBLE
|
cbForward.visibility = View.VISIBLE
|
||||||
tvForwardDesc.visibility = View.VISIBLE
|
tvForwardDesc.visibility = View.VISIBLE
|
||||||
cbForward.text = activity.getString(R.string.report_forward_to,who.host)
|
cbForward.text = activity.getString(R.string.report_forward_to,who.hostAscii)
|
||||||
}
|
}
|
||||||
|
|
||||||
tvUser.text = who.prettyAcct
|
tvUser.text = who.prettyAcct
|
||||||
|
|
|
@ -177,7 +177,7 @@ class AcctColor {
|
||||||
val nickname = ac.nickname
|
val nickname = ac.nickname
|
||||||
return if(nickname != null && nickname.isNotEmpty()) nickname.sanitizeBDI() else prettyAcct
|
return if(nickname != null && nickname.isNotEmpty()) nickname.sanitizeBDI() else prettyAcct
|
||||||
}
|
}
|
||||||
fun getNickname(sa:SavedAccount) : String = getNickname(sa.acct,sa.prettyAcct)
|
fun getNickname(sa:SavedAccount) : String = getNickname(sa.acctAscii,sa.acctPretty)
|
||||||
|
|
||||||
fun getNickname(sa:SavedAccount,who:TootAccount) : String = getNickname(sa.getFullAcct(who),sa.getFullPrettyAcct(who))
|
fun getNickname(sa:SavedAccount,who:TootAccount) : String = getNickname(sa.getFullAcct(who),sa.getFullPrettyAcct(who))
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.util.regex.Pattern
|
||||||
|
|
||||||
class SavedAccount(
|
class SavedAccount(
|
||||||
val db_id : Long,
|
val db_id : Long,
|
||||||
val acct : String,
|
acctArg : String,
|
||||||
hostArg : String? = null,
|
hostArg : String? = null,
|
||||||
var token_info : JsonObject? = null,
|
var token_info : JsonObject? = null,
|
||||||
var loginAccount : TootAccount? = null, // 疑似アカウントではnull
|
var loginAccount : TootAccount? = null, // 疑似アカウントではnull
|
||||||
|
@ -31,8 +31,8 @@ class SavedAccount(
|
||||||
|
|
||||||
val username : String
|
val username : String
|
||||||
|
|
||||||
override val host : String // punycode
|
override val hostAscii : String // punycode
|
||||||
override val prettyHost : String // unicode
|
override val hostPretty : String // unicode
|
||||||
|
|
||||||
var visibility : TootVisibility = TootVisibility.Public
|
var visibility : TootVisibility = TootVisibility.Public
|
||||||
var confirm_boost : Boolean = false
|
var confirm_boost : Boolean = false
|
||||||
|
@ -71,30 +71,32 @@ class SavedAccount(
|
||||||
var last_subscription_error : String? = null
|
var last_subscription_error : String? = null
|
||||||
var last_push_endpoint : String? = null
|
var last_push_endpoint : String? = null
|
||||||
|
|
||||||
val prettyAcct :String
|
val acctAscii :String
|
||||||
|
val acctPretty :String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val pos = acct.indexOf('@')
|
val pos = acctArg.indexOf('@')
|
||||||
|
val tmpHost:String?
|
||||||
if(pos == - 1) {
|
if(pos == - 1) {
|
||||||
this.username = acct
|
this.username = acctArg
|
||||||
prettyAcct = acct
|
acctAscii = acctArg
|
||||||
|
acctPretty = acctArg
|
||||||
|
tmpHost = null
|
||||||
} else {
|
} else {
|
||||||
this.username = acct.substring(0, pos)
|
this.username = acctArg.substring(0, pos)
|
||||||
prettyAcct = username+"@"+IDN.toUnicode(acct.substring(pos+1),IDN.ALLOW_UNASSIGNED)
|
tmpHost = acctArg.substring(pos+1).toLowerCase(Locale.JAPAN)
|
||||||
|
acctAscii= username+"@"+IDN.toASCII(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
|
acctPretty = username+"@"+IDN.toUnicode(tmpHost,IDN.ALLOW_UNASSIGNED)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(username.isEmpty()) throw RuntimeException("missing username in acct")
|
if(username.isEmpty()) throw RuntimeException("missing username in acct")
|
||||||
|
|
||||||
val host = if(hostArg != null && hostArg.isNotEmpty()) {
|
val host = hostArg?.notEmpty()?.toLowerCase(Locale.JAPAN)
|
||||||
hostArg
|
?: tmpHost
|
||||||
} else {
|
?: error("missing host in acct")
|
||||||
val hostInAcct = if(pos == - 1) "" else acct.substring(pos + 1)
|
|
||||||
if(hostInAcct.isEmpty()) throw RuntimeException("missing host in acct")
|
|
||||||
hostInAcct
|
|
||||||
}.toLowerCase(Locale.JAPAN)
|
|
||||||
|
|
||||||
this.host = IDN.toASCII(host,IDN.ALLOW_UNASSIGNED)
|
this.hostAscii = IDN.toASCII(host,IDN.ALLOW_UNASSIGNED)
|
||||||
this.prettyHost = IDN.toUnicode(host,IDN.ALLOW_UNASSIGNED)
|
this.hostPretty = IDN.toUnicode(host,IDN.ALLOW_UNASSIGNED)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(context : Context, cursor : Cursor) : this(
|
constructor(context : Context, cursor : Cursor) : this(
|
||||||
|
@ -111,7 +113,7 @@ class SavedAccount(
|
||||||
} else {
|
} else {
|
||||||
TootParser(
|
TootParser(
|
||||||
context,
|
context,
|
||||||
LinkHelper.newLinkHelper(this@SavedAccount.host, misskeyVersion = misskeyVersion)
|
LinkHelper.newLinkHelper(this@SavedAccount.hostAscii, misskeyVersion = misskeyVersion)
|
||||||
).account(jsonAccount)
|
).account(jsonAccount)
|
||||||
?: error("missing loginAccount for $strAccount")
|
?: error("missing loginAccount for $strAccount")
|
||||||
}
|
}
|
||||||
|
@ -161,7 +163,7 @@ class SavedAccount(
|
||||||
}
|
}
|
||||||
|
|
||||||
val isNA : Boolean
|
val isNA : Boolean
|
||||||
get() = "?@?" == acct
|
get() = "?@?" == acctAscii
|
||||||
|
|
||||||
val isPseudo : Boolean
|
val isPseudo : Boolean
|
||||||
get() = username == "?"
|
get() = username == "?"
|
||||||
|
@ -282,17 +284,17 @@ class SavedAccount(
|
||||||
this.sound_uri = b.sound_uri
|
this.sound_uri = b.sound_uri
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFullAcct(who : TootAccount?) : String = getFullAcct(who?.acct)
|
fun getFullAcct(who : TootAccount?) : String = getFullAcct(who?.acctAscii)
|
||||||
fun getFullPrettyAcct(who : TootAccount?) : String = getFullPrettyAcct(who?.prettyAcct)
|
fun getFullPrettyAcct(who : TootAccount?) : String = getFullPrettyAcct(who?.prettyAcct)
|
||||||
|
|
||||||
private fun isLocalUser(acct : String?) : Boolean {
|
private fun isLocalUser(acct : String?) : Boolean {
|
||||||
acct ?: return false
|
acct ?: return false
|
||||||
val pos = acct.indexOf('@')
|
val pos = acct.indexOf('@')
|
||||||
return pos == - 1 || host.equals(acct.substring(pos + 1), ignoreCase = true)
|
return pos == - 1 || matchHost( acct.substring(pos + 1) )
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isLocalUser(who : TootAccount?) : Boolean {
|
fun isLocalUser(who : TootAccount?) : Boolean {
|
||||||
return isLocalUser(who?.acct)
|
return isLocalUser(who?.acctAscii)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isRemoteUser(who : TootAccount) : Boolean {
|
fun isRemoteUser(who : TootAccount) : Boolean {
|
||||||
|
@ -305,24 +307,24 @@ class SavedAccount(
|
||||||
|
|
||||||
fun getUserUrl(who : TootAccount) : String =
|
fun getUserUrl(who : TootAccount) : String =
|
||||||
who.url ?: if(who.isRemote) {
|
who.url ?: if(who.isRemote) {
|
||||||
"https://${IDN.toUnicode(who.host, IDN.ALLOW_UNASSIGNED)}/@${who.username}"
|
"https://${IDN.toUnicode(who.hostAscii, IDN.ALLOW_UNASSIGNED)}/@${who.username}"
|
||||||
} else {
|
} else {
|
||||||
"https://$prettyHost/@${who.username}"
|
"https://$hostPretty/@${who.username}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isMe(who : TootAccount?) : Boolean {
|
fun isMe(who : TootAccount?) : Boolean {
|
||||||
if(who == null || who.username != this.username) return false
|
if(who == null || who.username != this.username) return false
|
||||||
//
|
//
|
||||||
val who_acct = who.acct
|
val who_acct = who.acctAscii
|
||||||
val pos = who_acct.indexOf('@')
|
val pos = who_acct.indexOf('@')
|
||||||
if(pos == - 1) return true // local user have no acct
|
if(pos == - 1) return true // local user have no acct
|
||||||
return who_acct.substring(pos + 1).equals(this.host, ignoreCase = true)
|
return who_acct.substring(pos + 1).equals(this.hostAscii, ignoreCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isMe(who_acct : String) : Boolean {
|
fun isMe(who_acct : String) : Boolean {
|
||||||
// 自分のユーザ名部分
|
// 自分のユーザ名部分
|
||||||
var pos = this.acct.indexOf('@')
|
var pos = this.acctAscii.indexOf('@')
|
||||||
val me_user = this.acct.substring(0, pos)
|
val me_user = this.acctAscii.substring(0, pos)
|
||||||
|
|
||||||
//
|
//
|
||||||
pos = who_acct.indexOf('@')
|
pos = who_acct.indexOf('@')
|
||||||
|
@ -331,25 +333,25 @@ class SavedAccount(
|
||||||
// リモートユーザならホスト名部分の比較も必要
|
// リモートユーザならホスト名部分の比較も必要
|
||||||
val who_user = who_acct.substring(0, pos)
|
val who_user = who_acct.substring(0, pos)
|
||||||
val who_host = who_acct.substring(pos + 1)
|
val who_host = who_acct.substring(pos + 1)
|
||||||
return who_user == me_user && ( who_host.equals(this.host, ignoreCase = true) || who_host.equals(this.prettyHost, ignoreCase = true) )
|
return who_user == me_user && ( who_host.equals(this.hostAscii, ignoreCase = true) || who_host.equals(this.hostPretty, ignoreCase = true) )
|
||||||
}
|
}
|
||||||
|
|
||||||
fun supplyBaseUrl(url : String?) : String? {
|
fun supplyBaseUrl(url : String?) : String? {
|
||||||
return when {
|
return when {
|
||||||
url == null || url.isEmpty() -> return null
|
url == null || url.isEmpty() -> return null
|
||||||
url[0] == '/' -> "https://$host$url"
|
url[0] == '/' -> "https://$hostAscii$url"
|
||||||
else -> url
|
else -> url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isNicoru(account : TootAccount?) : Boolean {
|
fun isNicoru(account : TootAccount?) : Boolean {
|
||||||
var host = this.host
|
var host = this.hostAscii
|
||||||
var host_start = 0
|
var host_start = 0
|
||||||
val acct = account?.acct
|
val acct = account?.acctAscii
|
||||||
if(acct != null) {
|
if(acct != null) {
|
||||||
val pos = acct.indexOf('@')
|
val pos = acct.indexOf('@')
|
||||||
if(pos != - 1) {
|
if(pos != - 1) {
|
||||||
host = account.acct
|
host = account.acctAscii
|
||||||
host_start = pos + 1
|
host_start = pos + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -925,8 +927,8 @@ class SavedAccount(
|
||||||
return 0L
|
return 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isNicoru(acct : String?) : Boolean {
|
fun isNicoru(acct:String) : Boolean {
|
||||||
return acct != null && reAtNicoruHost.matcher(acct).find()
|
return reAtNicoruHost.matcher(acct).find()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun charAtLower(src : CharSequence, pos : Int) : Char {
|
private fun charAtLower(src : CharSequence, pos : Int) : Char {
|
||||||
|
@ -1126,4 +1128,13 @@ class SavedAccount(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other : Any?) : Boolean =
|
||||||
|
when(other) {
|
||||||
|
is SavedAccount -> acctAscii == other.acctAscii
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode() : Int = acctAscii.hashCode()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import jp.juggler.subwaytooter.App1
|
||||||
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.EntityId
|
import jp.juggler.subwaytooter.api.entity.EntityId
|
||||||
|
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.span.EmojiImageSpan
|
import jp.juggler.subwaytooter.span.EmojiImageSpan
|
||||||
import jp.juggler.subwaytooter.span.HighlightSpan
|
import jp.juggler.subwaytooter.span.HighlightSpan
|
||||||
|
@ -504,20 +505,31 @@ object HTMLDecoder {
|
||||||
for(item in mentionList) {
|
for(item in mentionList) {
|
||||||
if(sb.isNotEmpty()) sb.append(" ")
|
if(sb.isNotEmpty()) sb.append(" ")
|
||||||
|
|
||||||
val rawAcct = item.acct
|
val fullAcct = getFullAcctOrNull(linkHelper, item.acctAscii,item.url)
|
||||||
val fullAcct = getFullAcctOrNull(linkHelper, rawAcct,item.url)
|
|
||||||
|
val linkInfo = if( fullAcct != null){
|
||||||
|
val(fullAcctAscii,fullAcctPretty) = TootAccount.acctAndPrettyAcct(fullAcct)
|
||||||
|
LinkInfo(
|
||||||
|
url = item.url,
|
||||||
|
caption = "@" + if( Pref.bpMentionFullAcct(App1.pref)) {
|
||||||
|
fullAcctPretty
|
||||||
|
} else {
|
||||||
|
item.acctPretty
|
||||||
|
},
|
||||||
|
ac = AcctColor.load(fullAcctAscii),
|
||||||
|
mention = item,
|
||||||
|
tag = link_tag
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
LinkInfo(
|
||||||
|
url = item.url,
|
||||||
|
caption = "@" + item.acctPretty,
|
||||||
|
ac = null,
|
||||||
|
mention = item,
|
||||||
|
tag = link_tag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val linkInfo = LinkInfo(
|
|
||||||
url = item.url,
|
|
||||||
caption = "@" + if(fullAcct != null && Pref.bpMentionFullAcct(App1.pref)) {
|
|
||||||
fullAcct
|
|
||||||
} else {
|
|
||||||
rawAcct
|
|
||||||
},
|
|
||||||
ac = if(fullAcct != null) AcctColor.load(fullAcct) else null,
|
|
||||||
mention = item,
|
|
||||||
tag = link_tag
|
|
||||||
)
|
|
||||||
val start = sb.length
|
val start = sb.length
|
||||||
sb.append(linkInfo.caption)
|
sb.append(linkInfo.caption)
|
||||||
val end = sb.length
|
val end = sb.length
|
||||||
|
@ -598,7 +610,7 @@ object HTMLDecoder {
|
||||||
|
|
||||||
// Account.note does not have mentions metadata.
|
// Account.note does not have mentions metadata.
|
||||||
// fallback to resolve acct by mention URL.
|
// fallback to resolve acct by mention URL.
|
||||||
val rawAcct = mention?.acct ?: originalCaption.toString().substring(1)
|
val rawAcct = mention?.acctPretty ?: originalCaption.toString().substring(1)
|
||||||
val fullAcct = getFullAcctOrNull(options.linkHelper, rawAcct,href)
|
val fullAcct = getFullAcctOrNull(options.linkHelper, rawAcct,href)
|
||||||
|
|
||||||
if(fullAcct != null) {
|
if(fullAcct != null) {
|
||||||
|
@ -608,7 +620,7 @@ object HTMLDecoder {
|
||||||
linkInfo.mention = TootMention(
|
linkInfo.mention = TootMention(
|
||||||
id = EntityId.DEFAULT,
|
id = EntityId.DEFAULT,
|
||||||
url = href,
|
url = href,
|
||||||
acct = fullAcct ,
|
acctArg = fullAcct ,
|
||||||
username = rawAcct.splitFullAcct().first
|
username = rawAcct.splitFullAcct().first
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,26 +8,26 @@ import java.net.IDN
|
||||||
interface LinkHelper {
|
interface LinkHelper {
|
||||||
|
|
||||||
// SavedAccountのロード時にhostを供給する必要があった
|
// SavedAccountのロード時にhostを供給する必要があった
|
||||||
val host : String? // punycode
|
val hostAscii : String? // punycode
|
||||||
val prettyHost : String? // unicode
|
val hostPretty : String? // unicode
|
||||||
|
|
||||||
// fun findAcct(url : String?) : String? = null
|
// fun findAcct(url : String?) : String? = null
|
||||||
// fun colorFromAcct(acct : String?) : AcctColor? = null
|
// fun colorFromAcct(acct : String?) : AcctColor? = null
|
||||||
|
|
||||||
// user とか user@host とかを user@host に変換する
|
// user とか user@host とかを user@host に変換する
|
||||||
// nullや空文字列なら ?@? を返す
|
// nullや空文字列なら ?@? を返す
|
||||||
fun getFullAcct(acct : String?) : String = when {
|
fun getFullAcct(acctAscii : String?) : String = when {
|
||||||
acct?.isEmpty() != false -> "?@?"
|
acctAscii?.isEmpty() != false -> "?@?"
|
||||||
acct.contains('@') -> acct
|
acctAscii.contains('@') -> acctAscii
|
||||||
else -> "$acct@$host"
|
else -> "$acctAscii@$hostAscii"
|
||||||
}
|
}
|
||||||
|
|
||||||
// user とか user@host とかを user@host に変換する
|
// user とか user@host とかを user@host に変換する
|
||||||
// nullや空文字列なら ?@? を返す
|
// nullや空文字列なら ?@? を返す
|
||||||
fun getFullPrettyAcct(prettyAcct : String?) : String = when {
|
fun getFullPrettyAcct(acctPretty : String?) : String = when {
|
||||||
prettyAcct?.isEmpty() != false -> "?@?"
|
acctPretty?.isEmpty() != false -> "?@?"
|
||||||
prettyAcct.contains('@') -> prettyAcct
|
acctPretty.contains('@') -> acctPretty
|
||||||
else -> "$prettyAcct@$prettyHost"
|
else -> "$acctPretty@$hostPretty"
|
||||||
}
|
}
|
||||||
|
|
||||||
val misskeyVersion : Int
|
val misskeyVersion : Int
|
||||||
|
@ -40,13 +40,19 @@ interface LinkHelper {
|
||||||
val isMastodon : Boolean
|
val isMastodon : Boolean
|
||||||
get() = misskeyVersion <= 0
|
get() = misskeyVersion <= 0
|
||||||
|
|
||||||
|
fun matchHost(host : String?) : Boolean =
|
||||||
|
host != null && (
|
||||||
|
host.equals(hostAscii, ignoreCase = true) ||
|
||||||
|
host.equals(hostPretty, ignoreCase = true)
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newLinkHelper(hostArg : String?, misskeyVersion : Int = 0) = object : LinkHelper {
|
fun newLinkHelper(hostArg : String?, misskeyVersion : Int = 0) = object : LinkHelper {
|
||||||
|
|
||||||
override val host : String? =
|
override val hostAscii : String? =
|
||||||
hostArg?.let { IDN.toASCII(hostArg, IDN.ALLOW_UNASSIGNED) }
|
hostArg?.let { IDN.toASCII(hostArg, IDN.ALLOW_UNASSIGNED) }
|
||||||
override val prettyHost : String? =
|
override val hostPretty : String? =
|
||||||
hostArg?.let { IDN.toUnicode(hostArg, IDN.ALLOW_UNASSIGNED) }
|
hostArg?.let { IDN.toUnicode(hostArg, IDN.ALLOW_UNASSIGNED) }
|
||||||
|
|
||||||
override val misskeyVersion : Int
|
override val misskeyVersion : Int
|
||||||
|
@ -54,13 +60,14 @@ interface LinkHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
val nullHost = object : LinkHelper {
|
val nullHost = object : LinkHelper {
|
||||||
override val host : String? = null
|
override val hostAscii : String? = null
|
||||||
override val prettyHost : String? = null
|
override val hostPretty : String? = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// user や user@host から user@host を返す
|
// user や user@host から user@host を返す
|
||||||
|
// ただし host部分がpunycodeかunicodeかは分からない
|
||||||
fun getFullAcctOrNull(
|
fun getFullAcctOrNull(
|
||||||
linkHelper : LinkHelper?,
|
linkHelper : LinkHelper?,
|
||||||
rawAcct : String,
|
rawAcct : String,
|
||||||
|
@ -81,8 +88,8 @@ fun getFullAcctOrNull(
|
||||||
// https://fedibird.com/@noellabo/103350050191159092
|
// https://fedibird.com/@noellabo/103350050191159092
|
||||||
// に含まれるメンションををリモートから見るとmentions メタデータがない。
|
// に含まれるメンションををリモートから見るとmentions メタデータがない。
|
||||||
// この場合アクセス元のホストを補うのは誤りなのだが、他の方法で解決できないなら仕方ない…
|
// この場合アクセス元のホストを補うのは誤りなのだが、他の方法で解決できないなら仕方ない…
|
||||||
if(linkHelper?.host?.endsWith('?') == false)
|
if(linkHelper?.hostAscii?.endsWith('?') == false)
|
||||||
return "$rawAcct@${linkHelper.host}"
|
return "$rawAcct@${linkHelper.hostAscii}"
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -855,11 +855,11 @@ object MisskeyMarkdownDecoder {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
val userHost = when {
|
val userHost = when {
|
||||||
host.isEmpty() -> linkHelper.host
|
host.isEmpty() -> linkHelper.hostAscii
|
||||||
else -> host
|
else -> host
|
||||||
} ?: "?"
|
}?.toLowerCase(Locale.JAPAN) ?: "?"
|
||||||
|
|
||||||
when(userHost.toLowerCase(Locale.JAPAN)) {
|
when(userHost) {
|
||||||
|
|
||||||
// https://github.com/syuilo/misskey/pull/3603
|
// https://github.com/syuilo/misskey/pull/3603
|
||||||
|
|
||||||
|
@ -884,16 +884,18 @@ object MisskeyMarkdownDecoder {
|
||||||
val userUrl = "https://$userHost/@$username"
|
val userUrl = "https://$userHost/@$username"
|
||||||
|
|
||||||
val shortAcct = when {
|
val shortAcct = when {
|
||||||
|
|
||||||
host.isEmpty()
|
host.isEmpty()
|
||||||
|| host.equals(linkHelper.host, ignoreCase = true) ->
|
|| host.equals(linkHelper.hostAscii, ignoreCase = true)
|
||||||
username
|
|| host.equals(linkHelper.hostPretty, ignoreCase = true) -> username
|
||||||
else ->
|
|
||||||
"$username@$host"
|
else -> "$username@$host"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val mentions = prepareMentions()
|
val mentions = prepareMentions()
|
||||||
|
|
||||||
if(mentions.find { m -> m.acct == shortAcct } == null) {
|
if(mentions.find { m -> m.acctAscii == shortAcct || m.acctPretty == shortAcct } == null) {
|
||||||
mentions.add(
|
mentions.add(
|
||||||
TootMention(
|
TootMention(
|
||||||
jp.juggler.subwaytooter.api.entity.EntityId.DEFAULT
|
jp.juggler.subwaytooter.api.entity.EntityId.DEFAULT
|
||||||
|
@ -922,7 +924,7 @@ object MisskeyMarkdownDecoder {
|
||||||
if(tag.isNotEmpty() && linkHelper != null) {
|
if(tag.isNotEmpty() && linkHelper != null) {
|
||||||
appendLink(
|
appendLink(
|
||||||
"#$tag",
|
"#$tag",
|
||||||
"https://${linkHelper.host}/tags/" + tag.encodePercent()
|
"https://${linkHelper.hostAscii}/tags/" + tag.encodePercent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -27,17 +27,17 @@ object NotificationHelper {
|
||||||
) = when(trackingName) {
|
) = when(trackingName) {
|
||||||
"" -> createNotificationChannel(
|
"" -> createNotificationChannel(
|
||||||
context,
|
context,
|
||||||
account.acct, // id
|
account.acctAscii, // id
|
||||||
account.acct, // name
|
account.acctPretty, // name
|
||||||
context.getString(R.string.notification_channel_description, account.acct),
|
context.getString(R.string.notification_channel_description, account.acctPretty),
|
||||||
NotificationManager.IMPORTANCE_DEFAULT // : NotificationManager.IMPORTANCE_LOW;
|
NotificationManager.IMPORTANCE_DEFAULT // : NotificationManager.IMPORTANCE_LOW;
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> createNotificationChannel(
|
else -> createNotificationChannel(
|
||||||
context,
|
context,
|
||||||
"${account.acct}/$trackingName", // id
|
"${account.acctAscii}/$trackingName", // id
|
||||||
"${account.acct}/$trackingName", // name
|
"${account.acctPretty}/$trackingName", // name
|
||||||
context.getString(R.string.notification_channel_description, account.acct),
|
context.getString(R.string.notification_channel_description, account.acctPretty),
|
||||||
NotificationManager.IMPORTANCE_DEFAULT // : NotificationManager.IMPORTANCE_LOW;
|
NotificationManager.IMPORTANCE_DEFAULT // : NotificationManager.IMPORTANCE_LOW;
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -580,7 +580,7 @@ class PostHelper(
|
||||||
val request_builder = body_string.toRequestBody(MEDIA_TYPE_JSON).toPost()
|
val request_builder = body_string.toRequestBody(MEDIA_TYPE_JSON).toPost()
|
||||||
|
|
||||||
if(! Pref.bpDontDuplicationCheck(pref)) {
|
if(! Pref.bpDontDuplicationCheck(pref)) {
|
||||||
val digest = (body_string + account.acct).digestSHA256Hex()
|
val digest = (body_string + account.acctAscii).digestSHA256Hex()
|
||||||
request_builder.header("Idempotency-Key", digest)
|
request_builder.header("Idempotency-Key", digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class PushSubscriptionHelper(
|
||||||
|
|
||||||
fun clearLastCheck(account : SavedAccount) {
|
fun clearLastCheck(account : SavedAccount) {
|
||||||
synchronized(lastCheckedMap) {
|
synchronized(lastCheckedMap) {
|
||||||
lastCheckedMap.remove(account.acct)
|
lastCheckedMap.remove(account.acctAscii)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@ class PushSubscriptionHelper(
|
||||||
private fun isRecentlyChecked() : Boolean {
|
private fun isRecentlyChecked() : Boolean {
|
||||||
if(verbose) return false
|
if(verbose) return false
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val acct = account.acct
|
val acctAscii = account.acctAscii
|
||||||
synchronized(lastCheckedMap) {
|
synchronized(lastCheckedMap) {
|
||||||
val lastChecked = lastCheckedMap[acct]
|
val lastChecked = lastCheckedMap[acctAscii]
|
||||||
val rv = lastChecked != null && now - lastChecked < 3600000L
|
val rv = lastChecked != null && now - lastChecked < 3600000L
|
||||||
if(! rv) lastCheckedMap[acct] = now
|
if(! rv) lastCheckedMap[acctAscii] = now
|
||||||
return rv
|
return rv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ class PushSubscriptionHelper(
|
||||||
|
|
||||||
return client.http(
|
return client.http(
|
||||||
jsonObject {
|
jsonObject {
|
||||||
put("acct", account.acct)
|
put("acct", account.acctAscii)
|
||||||
put("deviceId", deviceId)
|
put("deviceId", deviceId)
|
||||||
put("endpoint", endpoint)
|
put("endpoint", endpoint)
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ class PushSubscriptionHelper(
|
||||||
// 2018/9/1 の上記コミット以降、Misskeyでもサーバ公開鍵を得られるようになった
|
// 2018/9/1 の上記コミット以降、Misskeyでもサーバ公開鍵を得られるようになった
|
||||||
|
|
||||||
val endpoint =
|
val endpoint =
|
||||||
"${PollingWorker.APP_SERVER}/webpushcallback/${device_id.encodePercent()}/${account.acct.encodePercent()}/$flags/$clientIdentifier/misskey"
|
"${PollingWorker.APP_SERVER}/webpushcallback/${device_id.encodePercent()}/${account.acctAscii.encodePercent()}/$flags/$clientIdentifier/misskey"
|
||||||
|
|
||||||
// アプリサーバが過去のendpoint urlに410を返せるよう、状態を通知する
|
// アプリサーバが過去のendpoint urlに410を返せるよう、状態を通知する
|
||||||
val r = registerEndpoint(client,device_id,endpoint.toUri().encodedPath!!)
|
val r = registerEndpoint(client,device_id,endpoint.toUri().encodedPath!!)
|
||||||
|
@ -313,7 +313,7 @@ class PushSubscriptionHelper(
|
||||||
val clientIdentifier = "$accessToken$install_id".digestSHA256Base64Url()
|
val clientIdentifier = "$accessToken$install_id".digestSHA256Base64Url()
|
||||||
|
|
||||||
val endpoint =
|
val endpoint =
|
||||||
"${PollingWorker.APP_SERVER}/webpushcallback/${device_id.encodePercent()}/${account.acct.encodePercent()}/$flags/$clientIdentifier"
|
"${PollingWorker.APP_SERVER}/webpushcallback/${device_id.encodePercent()}/${account.acctAscii.encodePercent()}/$flags/$clientIdentifier"
|
||||||
|
|
||||||
if(oldSubscription?.endpoint == endpoint) {
|
if(oldSubscription?.endpoint == endpoint) {
|
||||||
// 既に登録済みで、endpointも一致している
|
// 既に登録済みで、endpointも一致している
|
||||||
|
|
|
@ -3,6 +3,7 @@ package jp.juggler.util
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
|
@ -335,3 +336,11 @@ fun <T> Array<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
||||||
//fun <T> Collection<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
//fun <T> Collection<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
||||||
//fun <T> Iterable<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
//fun <T> Iterable<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
||||||
//fun <T> Sequence<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
//fun <T> Sequence<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
|
||||||
|
|
||||||
|
fun defaultLocale(context:Context)=
|
||||||
|
if( Build.VERSION.SDK_INT >= 24){
|
||||||
|
context.resources.configuration.locales[0]
|
||||||
|
}else{
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
context.resources.configuration.locale
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package it.sephiroth.android.library.exif2
|
package it.sephiroth.android.library.exif2
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.SparseIntArray
|
import android.util.SparseIntArray
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
@ -2381,13 +2383,15 @@ class ExifInterface {
|
||||||
val seconds = coord[2].toDouble()
|
val seconds = coord[2].toDouble()
|
||||||
ref = ref.substring(0, 1)
|
ref = ref.substring(0, 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String.format(
|
String.format(
|
||||||
Locale.ENGLISH,
|
Locale.ENGLISH,
|
||||||
"%1$.0f° %2$.0f' %3$.0f\" %4\$s",
|
"%1$.0f° %2$.0f' %3$.0f\" %4\$s",
|
||||||
degrees,
|
degrees,
|
||||||
minutes,
|
minutes,
|
||||||
seconds,
|
seconds,
|
||||||
ref.toUpperCase(Locale.getDefault())
|
ref.toUpperCase(Locale.ENGLISH)
|
||||||
)
|
)
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
|
|
Loading…
Reference in New Issue