diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.kt b/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.kt index f72b8abd..b320d051 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.kt @@ -257,11 +257,11 @@ class ActAccountSetting setContentView(R.layout.act_account_setting) App1.initEdgeToEdge(this) - val root :View = findViewById(R.id.svContent) + val root : View = findViewById(R.id.svContent) Styler.fixHorizontalPadding(root) - - ActAppSettingChild.setSwitchColor(this,pref,root) + + ActAppSettingChild.setSwitchColor(this, pref, root) tvInstance = findViewById(R.id.tvInstance) tvUser = findViewById(R.id.tvUser) @@ -368,7 +368,7 @@ class ActAccountSetting name_invalidator = NetworkEmojiInvalidator(handler, etDisplayName) note_invalidator = NetworkEmojiInvalidator(handler, etNote) default_text_invalidator = NetworkEmojiInvalidator(handler, etDefaultText) - + listFieldNameInvalidator = listEtFieldName.map { NetworkEmojiInvalidator(handler, it) } @@ -418,7 +418,7 @@ class ActAccountSetting override fun afterTextChanged(s : Editable?) { val num = etMaxTootChars.parseInt() - if( num != null && num >= 0){ + if(num != null && num >= 0) { saveUIToData() } } @@ -426,11 +426,11 @@ class ActAccountSetting } - private fun EditText.parseInt():Int?{ + private fun EditText.parseInt() : Int? { val sv = this.text?.toString() ?: return null - return try{ - Integer.parseInt(sv,10) - }catch(ex:Throwable){ + return try { + Integer.parseInt(sv, 10) + } catch(ex : Throwable) { null } } @@ -472,7 +472,7 @@ class ActAccountSetting etDefaultText.setText(a.default_text) etMaxTootChars.setText(a.max_toot_chars.toString()) - + loading = false val enabled = ! a.isPseudo @@ -543,14 +543,14 @@ class ActAccountSetting account.confirm_unfavourite = cbConfirmUnfavourite.isChecked account.confirm_post = cbConfirmToot.isChecked account.default_text = etDefaultText.text.toString() - + val num = etMaxTootChars.parseInt() - account.max_toot_chars = if( num != null && num >= 0){ + account.max_toot_chars = if(num != null && num >= 0) { num - }else{ + } else { 0 } - + account.saveSetting() } @@ -677,7 +677,7 @@ class ActAccountSetting var bChanged = false try { loading = true - + val tmpVisibility = TootVisibility.parseMastodon(json.parseString("posting:default:visibility")) if(tmpVisibility != null) { @@ -953,12 +953,6 @@ class ActAccountSetting emojiMapProfile = src.profile_emojis, emojiMapCustom = src.custom_emojis ) - // fieldsのnameにはカスタム絵文字が適用されない - val decodeOptionsNoCustomEmoji = DecodeOptions( - context = this@ActAccountSetting, - linkHelper = account, - emojiMapProfile = src.profile_emojis - ) val display_name = src.display_name val name = decodeOptions.decodeEmoji(display_name) @@ -993,7 +987,10 @@ class ActAccountSetting if(src.source?.fields != null) { val fields = src.source.fields listEtFieldName.forEachIndexed { i, et -> - val text = decodeOptionsNoCustomEmoji.decodeEmoji( + // いつからかfields name にもカスタム絵文字が使えるようになった + // https://github.com/tootsuite/mastodon/pull/11350 + // しかし + val text = decodeOptions.decodeEmoji( when { i >= fields.size -> "" else -> fields[i].name @@ -1022,7 +1019,9 @@ class ActAccountSetting val fields = src.fields listEtFieldName.forEachIndexed { i, et -> - val text = decodeOptionsNoCustomEmoji.decodeEmoji( + // いつからかfields name にもカスタム絵文字が使えるようになった + // https://github.com/tootsuite/mastodon/pull/11350 + val text = decodeOptions.decodeEmoji( when { fields == null || i >= fields.size -> "" else -> fields[i].name @@ -1576,11 +1575,13 @@ class ActAccountSetting } + @Suppress("DEPRECATION") progress.isIndeterminate = true + + @Suppress("DEPRECATION") progress.setMessage("preparing image…") - progress.setOnCancelListener { - task.cancel(true) - } + + progress.setOnCancelListener { task.cancel(true) } progress.show() task.executeOnExecutor(App1.task_executor) diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt b/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt index c01db01e..4a9fcfdd 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt @@ -844,7 +844,11 @@ class ActPost : AppCompatActivity(), // 再編集の場合はdefault_textは反映されない - val decodeOptions = DecodeOptions(this, mentionFullAcct = true) + val decodeOptions = DecodeOptions( + this, + mentionFullAcct = true, + mentions = base_status.mentions + ) var text : CharSequence = if(account.isMisskey) { base_status.content ?: "" @@ -862,12 +866,14 @@ class ActPost : AppCompatActivity(), val src_enquete = base_status.enquete val src_items = src_enquete?.items when { - src_items == null ->{ + src_items == null -> { } + src_enquete.pollType == TootPollsType.FriendsNico && src_enquete.type != TootPolls.TYPE_ENQUETE -> { // フレニコAPIのアンケート結果は再編集の対象外 } + else -> { spEnquete.setSelection( if(src_enquete.pollType == TootPollsType.FriendsNico) { @@ -888,6 +894,7 @@ class ActPost : AppCompatActivity(), src_index == src_items.size - 1 && choice.text == "\uD83E\uDD14" -> { // :thinking_face: は再現しない } + else -> { et.setText(decodeOptions.decodeEmoji(choice.text)) ++ src_index @@ -1590,6 +1597,7 @@ class ActPost : AppCompatActivity(), pa.attachment?.isAudio == true -> { // can't set focus } + else -> a.addAction(getString(R.string.set_focus_point)) { openFocusPoint(pa) } diff --git a/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt b/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt index 1e057f64..79f80260 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt @@ -1156,7 +1156,7 @@ internal class ItemViewHolder( setAcct(tvFollowerAcct, access_info.getFullAcct(who), who.acct) - who.setLastStatusText(tvLastStatusAt,access_info) + who.setAccountExtra(tvLastStatusAt,access_info) val relation = UserRelation.load(access_info.db_id, who.id) diff --git a/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt b/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt index b2e15f7d..482ba380 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderProfile.kt @@ -216,7 +216,7 @@ internal class ViewHolderHeaderProfile( tvCreated.text = TootStatus.formatTime(tvCreated.context, (whoDetail ?: who).time_created_at, true) - who.setLastStatusText(tvLastStatusAt,access_info,fromProfileHeader = true) + who.setAccountExtra(tvLastStatusAt,access_info,fromProfileHeader = true) ivBackground.setImageUrl( @@ -338,17 +338,10 @@ internal class ViewHolderHeaderProfile( llFields.visibility = View.VISIBLE - // fieldsのnameにはカスタム絵文字が適用されない - val nameDecodeOptions = DecodeOptions( - context = activity, - decodeEmoji = true, - linkHelper = access_info, - short = true, - emojiMapProfile = who.profile_emojis - ) - - // valueはMisskeyならMFM、MastodonならHTML - val valueDecodeOptions = DecodeOptions( + // fieldsのnameにはカスタム絵文字が適用されるようになった + // https://github.com/tootsuite/mastodon/pull/11350 + // fieldsのvalueはMisskeyならMFM、MastodonならHTML + val fieldDecodeOptions = DecodeOptions( context = activity, decodeEmoji = true, linkHelper = access_info, @@ -368,7 +361,7 @@ internal class ViewHolderHeaderProfile( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT ) - val nameText = nameDecodeOptions.decodeEmoji(item.name) + val nameText = fieldDecodeOptions.decodeEmoji(item.name) val nameInvalidator = NetworkEmojiInvalidator(activity.handler, nameView) nameInvalidator.register(nameText) @@ -387,7 +380,7 @@ internal class ViewHolderHeaderProfile( LinearLayout.LayoutParams.WRAP_CONTENT ) - val valueText = valueDecodeOptions.decodeHTML(item.value) + val valueText = fieldDecodeOptions.decodeHTML(item.value) if(item.verified_at > 0L) { valueText.append('\n') diff --git a/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderSearch.kt b/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderSearch.kt index 159f72e0..3226da23 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderSearch.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ViewHolderHeaderSearch.kt @@ -26,11 +26,9 @@ internal class ViewHolderHeaderSearch( override fun bindData(column : Column) { super.bindData(column) - val html = column.getHeaderDesc() ?: "" - val sv = DecodeOptions(activity, access_info,decodeEmoji = true).decodeHTML( html) - - tvSearchDesc.text = sv tvSearchDesc.textColor = column.getContentColor() + tvSearchDesc.text = DecodeOptions(activity, access_info, decodeEmoji = true) + .decodeHTML(column.getHeaderDesc() ?: "") } override fun onViewRecycled() { diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAccount.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAccount.kt index 83847454..2c774c7b 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAccount.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAccount.kt @@ -378,13 +378,13 @@ open class TootAccount(parser : TootParser, src : JSONObject) { } } - fun setLastStatusText( - tvLastStatusAt : TextView, + fun setAccountExtra( + tv : TextView, accessInfo : SavedAccount, fromProfileHeader : Boolean = false ) { val pref = App1.pref - val context = tvLastStatusAt.context + val context = tv.context var sb : SpannableStringBuilder? = null fun prepareSb() = sb?.apply { append('\n') } ?: SpannableStringBuilder().also { sb = it } @@ -416,19 +416,21 @@ open class TootAccount(parser : TootParser, src : JSONObject) { .decodeHTML(note) .replaceAllEx(reNoteLineFeed, " ") .trimEx() - prepareSb().append( - if(decodedNote is SpannableStringBuilder && decodedNote.length > 200) { - decodedNote.replace(200, decodedNote.length, "…") - } else { - decodedNote - } - ) + if(decodedNote.isNotBlank()) { + prepareSb().append( + if(decodedNote is SpannableStringBuilder && decodedNote.length > 200) { + decodedNote.replace(200, decodedNote.length, "…") + } else { + decodedNote + } + ) + } } } - if(vg(tvLastStatusAt, sb != null)) { - tvLastStatusAt.text = sb - tvLastStatusAt.movementMethod = MyLinkMovementMethod + if(vg(tv, sb != null)) { + tv.text = sb + tv.movementMethod = MyLinkMovementMethod } } @@ -449,28 +451,37 @@ open class TootAccount(parser : TootParser, src : JSONObject) { internal val reAccountUrl : Pattern = Pattern.compile("""\Ahttps://(\w[\w.-]*\w)/@(\w+[\w-]*)(?:@(\w[\w.-]*\w))?(?=\z|[?#])""") + // host,user + internal val reAccountUrl2 : Pattern = + Pattern.compile("""\Ahttps://(\w[\w.-]*\w)/users/(\w|\w+[\w-]*\w)(?=\z|[?#])""") + fun getAcctFromUrl(url : String?) : String? { url ?: return null - val m = reAccountUrl.matcher(url) - return if(m.find()) { - val host = m.group(1) - val user = m.group(2).decodePercent() + var m = reAccountUrl.matcher(url) + if(m.find()) { + val host = m.groupOrNull(1) + val user = m.groupOrNull(2)?.decodePercent() val instance = m.groupOrNull(3)?.decodePercent() - if(instance?.isNotEmpty() == true) { + return if(instance?.isNotEmpty() == true) { "$user@$instance" } else { "$user@$host" } - } else { - null } + + m = reAccountUrl2.matcher(url) + if(m.find()) { + val host = m.groupOrNull(1) + val user = m.groupOrNull(2)?.decodePercent() + + return "$user@$host" + } + + return null } - // host,user - internal val reAccountUrl2 : Pattern = - Pattern.compile("""\Ahttps://(\w[\w.-]*\w)/users/(\w|\w+[\w-]*\w)(?=\z|[?#])""") private fun parseSource(src : JSONObject?) : Source? { src ?: return null diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootPolls.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootPolls.kt index b7002f92..45fa0f23 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootPolls.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootPolls.kt @@ -107,7 +107,8 @@ class TootPolls private constructor( attachmentList = list_attachment, linkTag = status, emojiMapCustom = status.custom_emojis, - emojiMapProfile = status.profile_emojis + emojiMapProfile = status.profile_emojis, + mentions = status.mentions ).decodeHTML(this.question ?: "?") } @@ -124,7 +125,8 @@ class TootPolls private constructor( attachmentList = list_attachment, linkTag = status, emojiMapCustom = status.custom_emojis, - emojiMapProfile = status.profile_emojis + emojiMapProfile = status.profile_emojis, + mentions = status.mentions ).decodeHTML(this.question ?: "?") this.items = parseChoiceListMastodon( @@ -178,7 +180,8 @@ class TootPolls private constructor( attachmentList = list_attachment, linkTag = status, emojiMapCustom = status.custom_emojis, - emojiMapProfile = status.profile_emojis + emojiMapProfile = status.profile_emojis, + mentions = status.mentions ).decodeHTML(this.question ?: "?") this.items = parseChoiceListFriendsNico( diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt index e65a0bb3..be9c13ed 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootStatus.kt @@ -280,7 +280,8 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { emojiMapCustom = custom_emojis, emojiMapProfile = profile_emojis, attachmentList = media_attachments, - highlightTrie = parser.highlightTrie + highlightTrie = parser.highlightTrie, + mentions = null // MisskeyはMFMをパースし終わるまでメンションが分からない ) this.decoded_content = options.decodeHTML(content) @@ -290,14 +291,9 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { } // Markdownのデコード結果からmentionsを読むのだった - this.mentions = - (decoded_content as? MisskeyMarkdownDecoder.SpannableStringBuilderEx)?.mentions - this.decoded_mentions = HTMLDecoder.decodeMentions( - parser.linkHelper, - this.mentions, - this - ) ?: EMPTY_SPANNABLE - + val mentions1 = (decoded_content as? MisskeyMarkdownDecoder.SpannableStringBuilderEx)?.mentions + + val sv = src.parseString("cw")?.cleanCW() this.spoiler_text = when { sv == null -> "" // CWなし @@ -305,6 +301,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { else -> sv } + // ハイライト検出のためにDecodeOptionsを作り直す? options = DecodeOptions( parser.context, parser.linkHelper, @@ -313,7 +310,8 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { emojiMapCustom = custom_emojis, emojiMapProfile = profile_emojis, attachmentList = media_attachments, - highlightTrie = parser.highlightTrie + highlightTrie = parser.highlightTrie, + mentions = null // MisskeyはMFMをパースし終わるまでメンションが分からない ) this.decoded_spoiler_text = options.decodeHTML(spoiler_text) @@ -321,6 +319,15 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { if(options.highlight_sound != null && this.highlight_sound == null) { this.highlight_sound = options.highlight_sound } + + val mentions2 = (decoded_spoiler_text as? MisskeyMarkdownDecoder.SpannableStringBuilderEx)?.mentions + + this.mentions = mergeMentions(mentions1,mentions2) + this.decoded_mentions = HTMLDecoder.decodeMentions( + parser.linkHelper, + this.mentions, + this + ) ?: EMPTY_SPANNABLE // contentを読んだ後にアンケートのデコード this.enquete = TootPolls.parse( @@ -410,7 +417,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { this.uri = src.parseString("uri") ?: error("missing uri") this.id = findStatusIdFromUri(uri, url) ?: EntityId.DEFAULT - this.time_created_at = TootStatus.parseTime(this.created_at) + this.time_created_at = parseTime(this.created_at) this.media_attachments = parseListOrNull( ::TootAttachment, parser, @@ -470,7 +477,8 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { emojiMapCustom = custom_emojis, emojiMapProfile = profile_emojis, attachmentList = media_attachments, - highlightTrie = parser.highlightTrie + highlightTrie = parser.highlightTrie, + mentions = mentions ) this.decoded_content = options.decodeHTML(content) @@ -486,11 +494,13 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { else -> sv } + // ハイライト検出のためにDecodeOptionsを作り直す? options = DecodeOptions( parser.context, emojiMapCustom = custom_emojis, emojiMapProfile = profile_emojis, - highlightTrie = parser.highlightTrie + highlightTrie = parser.highlightTrie, + mentions = mentions ) this.decoded_spoiler_text = options.decodeEmoji(spoiler_text) @@ -533,6 +543,18 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { } } + private fun mergeMentions( + mentions1 : java.util.ArrayList?, + mentions2 : java.util.ArrayList? + ) : java.util.ArrayList? { + val size = (mentions1?.size?:0) + (mentions2?.size?:0) + if( size == 0) return null + val dst = ArrayList(size) + if(mentions1!=null) dst.addAll(mentions1) + if(mentions2!=null) dst.addAll(mentions2) + return dst + } + /////////////////////////////////////////////////// // ユーティリティ @@ -545,14 +567,14 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { fun checkMuted() : Boolean { // app mute - val muted_app = TootStatus.muted_app + val muted_app = muted_app if(muted_app != null) { val name = application?.name if(name != null && muted_app.contains(name)) return true } // word mute - val muted_word = TootStatus.muted_word + val muted_word = muted_word if(muted_word != null) { if(muted_word.matchShort(decoded_content)) return true if(muted_word.matchShort(decoded_spoiler_text)) return true @@ -971,15 +993,15 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { if(uri?.isNotEmpty() == true) { // https://friends.nico/users/(who)/statuses/(status_id) var m = reTootUriAP1.matcher(uri) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // https://server/@user/(status_id) m = reTootUriAP2.matcher(uri) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // https://misskey.xyz/notes/5b802367744b650030a13640 m = reStatusPageMisskey.matcher(uri) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // https://pl.at7s.me/objects/feeb4399-cd7a-48c8-8999-b58868daaf43 // tootsearch中の投稿からIDを読めるようにしたい @@ -989,11 +1011,11 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { // https://pl.telteltel.com/notice/9fGFPu4LAgbrTby0xc m = reStatusPageNotice.matcher(uri) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // tag:mstdn.osaka,2017-12-19:objectId=5672321:objectType=Status m = reTootUriOS.matcher(uri) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) log.w("can't parse status uri: $uri") } @@ -1002,15 +1024,15 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { // https://friends.nico/users/(who)/statuses/(status_id) var m = reTootUriAP1.matcher(url) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // https://friends.nico/@(who)/(status_id) m = reTootUriAP2.matcher(url) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // https://misskey.xyz/notes/5b802367744b650030a13640 m = reStatusPageMisskey.matcher(url) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) // https://pl.at7s.me/objects/feeb4399-cd7a-48c8-8999-b58868daaf43 // tootsearch中の投稿からIDを読めるようにしたい @@ -1020,7 +1042,7 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() { // https://pl.telteltel.com/notice/9fGFPu4LAgbrTby0xc m = reStatusPageNotice.matcher(url) - if(m.find()) return EntityId(m.group(2)) + if(m.find()) return EntityId(m.group(2)!!) log.w("can't parse status URL: $url") diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/DecodeOptions.kt b/app/src/main/java/jp/juggler/subwaytooter/util/DecodeOptions.kt index 575fe023..0c15eefd 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/DecodeOptions.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/DecodeOptions.kt @@ -5,6 +5,7 @@ import android.text.Spannable import jp.juggler.subwaytooter.api.entity.CustomEmoji import jp.juggler.subwaytooter.api.entity.NicoProfileEmoji import jp.juggler.subwaytooter.api.entity.TootAttachmentLike +import jp.juggler.subwaytooter.api.entity.TootMention import jp.juggler.subwaytooter.table.HighlightWord import jp.juggler.util.WordTrieTree import java.util.* @@ -22,7 +23,8 @@ class DecodeOptions( var unwrapEmojiImageTag : Boolean = false, var enlargeCustomEmoji : Float = 1f, var forceHtml : Boolean = false, // force use HTML instead of Misskey Markdown - var mentionFullAcct : Boolean = false + var mentionFullAcct : Boolean = false, + var mentions: ArrayList? = null ) { internal fun isMediaAttachment(url : String?) : Boolean { diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/HTMLDecoder.kt b/app/src/main/java/jp/juggler/subwaytooter/util/HTMLDecoder.kt index fce4419b..844280d3 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/HTMLDecoder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/HTMLDecoder.kt @@ -435,12 +435,15 @@ object HTMLDecoder { for(item in src_list) { if(sb.isNotEmpty()) sb.append(" ") val start = sb.length + sb.append('@') - if(Pref.bpMentionFullAcct(App1.pref)) { - sb.append(linkHelper.getFullAcct(item.acct)) - } else { - sb.append(item.acct) - } + .append( + if(Pref.bpMentionFullAcct(App1.pref)) { + linkHelper.getFullAcct(item.acct) + } else { + item.acct + } + ) val end = sb.length val url = item.url if(end > start) { @@ -510,6 +513,20 @@ object HTMLDecoder { '@' -> { // @mention if(options.mentionFullAcct || Pref.bpMentionFullAcct(App1.pref)) { + + // https://github.com/tateisu/SubwayTooter/issues/108 + // check mentions to skip getAcctFromUrl + val mentions = options.mentions + if( mentions != null){ + for( it in mentions){ + if( it.url == href ){ + val acct = it.acct + if( acct.contains('@')) return "@$acct" + } + } + } + + // Account.note does not have mentions metadata. we can't drop resolving by mention URL. val acct = TootAccount.getAcctFromUrl(href) if(acct != null) return "@$acct" } diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/TootTextEncoder.kt b/app/src/main/java/jp/juggler/subwaytooter/util/TootTextEncoder.kt index 2e8f4ccb..68b778cf 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/TootTextEncoder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/TootTextEncoder.kt @@ -63,7 +63,7 @@ object TootTextEncoder { sb.addAfterLine( "\n") intent.putExtra(ActText.EXTRA_CONTENT_START, sb.length) - sb.append(DecodeOptions(context, access_info).decodeHTML(status.content)) + sb.append(DecodeOptions(context, access_info,mentions = status.mentions).decodeHTML(status.content)) encodePolls(sb,context,status) @@ -90,7 +90,7 @@ object TootTextEncoder { sb.append(sv).append("\n\n") } - sb.append(DecodeOptions(context, access_info).decodeHTML(status.content)) + sb.append(DecodeOptions(context, access_info,mentions=status.mentions).decodeHTML(status.content)) encodePolls(sb,context,status) diff --git a/app/src/main/java/jp/juggler/util/StringUtils.kt b/app/src/main/java/jp/juggler/util/StringUtils.kt index 5c554760..628f052d 100644 --- a/app/src/main/java/jp/juggler/util/StringUtils.kt +++ b/app/src/main/java/jp/juggler/util/StringUtils.kt @@ -327,7 +327,7 @@ fun Bundle.parseString(key : String) : String? { // Pattern fun Matcher.groupOrNull(g : Int) : String? = - if(groupCount() >= g) { + if(g in 0 until groupCount() ) { group(g) } else { null