めいすきーのリアクションの@を含む絵文字の表示

This commit is contained in:
tateisu 2021-01-03 20:49:21 +09:00
parent 2b8f0a63cc
commit 1902b58fc0
4 changed files with 102 additions and 80 deletions

View File

@ -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)

View File

@ -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
)
}
}

View File

@ -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
}
}

View File

@ -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
}
}