diff --git a/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt b/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt index 9776ee47..1d8aa000 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.kt @@ -1191,7 +1191,7 @@ internal class ItemViewHolder( enlargeEmoji = 1.5f, enlargeCustomEmoji = 1.5f ) - val ssb = MisskeyReaction.toSpannableStringBuilder(misskeyReaction,options) + val ssb = MisskeyReaction.toSpannableStringBuilder(misskeyReaction,options,boost_status) ssb.append(" ") ssb.append(who.decodeDisplayName(activity) .intoStringResource(activity, string_id)) @@ -2546,7 +2546,7 @@ internal class ItemViewHolder( val key = entry.key val count = entry.value if(count <= 0) continue - val ssb = MisskeyReaction.toSpannableStringBuilder(key,options) + val ssb = MisskeyReaction.toSpannableStringBuilder(key,options,status) .also{ it.append(" $count")} val b = Button(activity).apply { @@ -2599,7 +2599,7 @@ internal class ItemViewHolder( llExtra.addView(box) } - private fun addReaction(status : TootStatus, codeArg : String?) { + private fun addReaction(status : TootStatus, code : String?) { if(status.myReaction?.isNotEmpty() == true) { activity.showToast(false, R.string.already_reactioned) @@ -2608,7 +2608,7 @@ internal class ItemViewHolder( if(access_info.isPseudo || ! access_info.isMisskey) return - if(codeArg == null) { + if(code == null) { EmojiPicker(activity, access_info,closeOnSelected = true) { name, instance, _, _, _ -> val item = EmojiMap.sShortNameToEmojiInfo[name] val code = if(item == null || instance != null) { @@ -2636,12 +2636,8 @@ internal class ItemViewHolder( TootTaskRunner(activity, progress_style = TootTaskRunner.PROGRESS_NONE).run(access_info, object : TootTask { - var code :String = codeArg - override suspend fun background(client : TootApiClient) : TootApiResult? { - code = MisskeyReaction.toLegacyReaction(client,code) - val params = access_info.putMisskeyApiToken().apply { put("noteId", status.id.toString()) put("reaction", code) diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt index 6fb1d857..aa596090 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt @@ -1309,7 +1309,7 @@ object Action_Toot { nCrossAccountMode: Int, callback: () -> Unit, bSet: Boolean = true, - codeArg: String? = null + code: String? = null ) { if (access_info.isPseudo || !access_info.isMisskey) return @@ -1319,34 +1319,31 @@ object Action_Toot { return } - if (codeArg == null) { - if (bSet) - EmojiPicker(activity, access_info, closeOnSelected = true) { name, instance, _, _, _ -> - val item = EmojiMap.sShortNameToEmojiInfo[name] - val newCode = if (item == null || instance != null) { - ":$name:" - } else { - item.unified - } - reaction( - activity, - access_info, - arg_status, - status_owner_acct, - nCrossAccountMode, - callback, - bSet, - newCode - ) - }.show() + if (code == null) { + if (!bSet) error("will not happen") + EmojiPicker(activity, access_info, closeOnSelected = true) { name, instance, _, _, _ -> + val item = EmojiMap.sShortNameToEmojiInfo[name] + val newCode = if (item == null || instance != null) { + ":$name:" + } else { + item.unified + } + reaction( + activity, + access_info, + arg_status, + status_owner_acct, + nCrossAccountMode, + callback, + bSet, + newCode + ) + }.show() return } - TootTaskRunner(activity, TootTaskRunner.PROGRESS_NONE).run(access_info, object : TootTask { - var code: String = codeArg - override suspend fun background(client: TootApiClient): TootApiResult? { val target_status = if (nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE) { @@ -1378,8 +1375,6 @@ object Action_Toot { // 成功すると204 no content } else { - code = MisskeyReaction.toLegacyReaction(client, code) - client.request( "/api/notes/reactions/create", access_info.putMisskeyApiToken().apply { @@ -1433,7 +1428,7 @@ object Action_Toot { status_owner, calcCrossAccountMode(timeline_account, action_account), activity.reaction_complete_callback, - codeArg = code + code = code ) } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/MisskeyReaction.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/MisskeyReaction.kt index bd92f8b0..1fff1375 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/MisskeyReaction.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/MisskeyReaction.kt @@ -1,15 +1,9 @@ package jp.juggler.subwaytooter.api.entity -import android.graphics.drawable.PictureDrawable import android.text.Spannable import android.text.SpannableStringBuilder -import android.widget.ImageView -import com.bumptech.glide.Glide -import jp.juggler.emoji.EmojiMap -import jp.juggler.subwaytooter.ActMain import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.Pref -import jp.juggler.subwaytooter.api.TootApiClient import jp.juggler.subwaytooter.span.NetworkEmojiSpan import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.util.DecodeOptions @@ -46,51 +40,58 @@ object MisskeyReaction { "star" to "\u2B50", // リモートからのFavを示す代替リアクション。ピッカーには表示しない ) - fun toSpannableStringBuilder(code: String, options: DecodeOptions): SpannableStringBuilder { + private val reCustomEmoji = """\A:([^:]+):\z""".toRegex() + + fun toSpannableStringBuilder( + code: String, + options: DecodeOptions, + status:TootStatus? + ): SpannableStringBuilder { + // 古い形式の絵文字はUnicode絵文字にする oldReactions[code]?.let { return EmojiDecoder.decodeEmoji(options, it) } - // カスタム絵文字 - val customCode = code.replace(":", "") - if (customCode != code) { - val accessInfo = options.linkHelper as? SavedAccount - if (accessInfo != null) { - val emojiUrl = - App1.custom_emoji_lister - .getMap(accessInfo) - ?.get(customCode) - ?.let { - if (Pref.bpDisableEmojiAnimation(App1.pref)) { - it.static_url - } else { - it.url - } - } - if (emojiUrl != null) - return SpannableStringBuilder(code).apply { - setSpan( - NetworkEmojiSpan(emojiUrl, scale = options.enlargeCustomEmoji), - 0, - length, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - } - + fun CustomEmoji.toSpannableStringBuilder():SpannableStringBuilder?{ + return if (Pref.bpDisableEmojiAnimation(App1.pref)) { + static_url + } else { + url + }?.let{ + SpannableStringBuilder(code).apply { + setSpan( + NetworkEmojiSpan(it, scale = options.enlargeCustomEmoji), + 0, + length, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } } } + + // カスタム絵文字 + val customCode = reCustomEmoji.find(code)?.groupValues?.elementAtOrNull(1) + if(customCode != null){ + var ce = status?.custom_emojis?.get( customCode) + if(ce != null) return ce.toSpannableStringBuilder()?: EmojiDecoder.decodeEmoji(options, code) + + val accessInfo = options.linkHelper as? SavedAccount + + val cols = customCode.split("@",limit = 2) + val key = cols.elementAtOrNull(0) + val domain = cols.elementAtOrNull(1) + if( domain == null || domain=="" || domain=="." || domain == accessInfo?.apiHost?.ascii ){ + if( accessInfo != null){ + ce = App1.custom_emoji_lister + .getMap(accessInfo) + ?.get(key) + if(ce != null) return ce.toSpannableStringBuilder()?: EmojiDecoder.decodeEmoji(options, code) + } + } + } + // unicode絵文字、もしくは :xxx: などのshortcode表現 return EmojiDecoder.decodeEmoji(options, code) } - - // Misskey v12 未満はレガシーなリアクションを送ることになる - suspend fun toLegacyReaction(client: TootApiClient, code: String): String { - val(ti,ri) = TootInstance.get(client) - if(ti!=null && ! ti.versionGE(TootInstance.MISSKEY_VERSION_12)){ - val entry = oldReactions.entries.firstOrNull { it.value == code } - if( entry != null && entry.key != "star") return entry.key - } - return code - } } 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 cd0896bd..2e6e0d8c 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 @@ -20,6 +20,7 @@ import java.util.regex.Pattern import kotlin.collections.ArrayList import kotlin.collections.LinkedHashMap import kotlin.math.abs +import kotlin.math.max import kotlin.math.min class FilterTrees( @@ -927,6 +928,18 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() { return list } + private fun getAnotherReactionExpression(reaction:String):String{ + // :reaction: => reaction + // :reaction@xxx: => reaction@xxx + val customCode = reaction.replace(":","") + + // reaction => :reaction@.: + return if( customCode != reaction && !customCode.contains("@")) + ":${customCode}@.:" + else + reaction + } + // return true if updated fun increaseReaction(reaction: String?, byMe: Boolean, caller: String): Boolean { reaction ?: return false @@ -948,8 +961,17 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() { map = LinkedHashMap() this.reactionCounts = map } - map[reaction] = (map[reaction] ?: 0) + 1 + + val anotherExpression = getAnotherReactionExpression(reaction) + + for( entry in map){ + if( entry.key == reaction || entry.key == anotherExpression){ + map[entry.key] = entry.value +1 + return true + } + } + map[reaction] = 1 return true } } @@ -975,8 +997,16 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() { map = LinkedHashMap() this.reactionCounts = map } - map[reaction] = (map[reaction] ?: 1) - 1 + val anotherExpression = getAnotherReactionExpression(reaction) + + for( entry in map){ + if( entry.key == reaction || entry.key == anotherExpression){ + map[entry.key] = max(0,entry.value -1) + return true + } + } + map[reaction] = 0 return true } }