めいすきーのリアクションの@を含む絵文字の表示
This commit is contained in:
parent
2b8f0a63cc
commit
1902b58fc0
|
@ -1191,7 +1191,7 @@ internal class ItemViewHolder(
|
||||||
enlargeEmoji = 1.5f,
|
enlargeEmoji = 1.5f,
|
||||||
enlargeCustomEmoji = 1.5f
|
enlargeCustomEmoji = 1.5f
|
||||||
)
|
)
|
||||||
val ssb = MisskeyReaction.toSpannableStringBuilder(misskeyReaction,options)
|
val ssb = MisskeyReaction.toSpannableStringBuilder(misskeyReaction,options,boost_status)
|
||||||
ssb.append(" ")
|
ssb.append(" ")
|
||||||
ssb.append(who.decodeDisplayName(activity)
|
ssb.append(who.decodeDisplayName(activity)
|
||||||
.intoStringResource(activity, string_id))
|
.intoStringResource(activity, string_id))
|
||||||
|
@ -2546,7 +2546,7 @@ internal class ItemViewHolder(
|
||||||
val key = entry.key
|
val key = entry.key
|
||||||
val count = entry.value
|
val count = entry.value
|
||||||
if(count <= 0) continue
|
if(count <= 0) continue
|
||||||
val ssb = MisskeyReaction.toSpannableStringBuilder(key,options)
|
val ssb = MisskeyReaction.toSpannableStringBuilder(key,options,status)
|
||||||
.also{ it.append(" $count")}
|
.also{ it.append(" $count")}
|
||||||
|
|
||||||
val b = Button(activity).apply {
|
val b = Button(activity).apply {
|
||||||
|
@ -2599,7 +2599,7 @@ internal class ItemViewHolder(
|
||||||
llExtra.addView(box)
|
llExtra.addView(box)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addReaction(status : TootStatus, codeArg : String?) {
|
private fun addReaction(status : TootStatus, code : String?) {
|
||||||
|
|
||||||
if(status.myReaction?.isNotEmpty() == true) {
|
if(status.myReaction?.isNotEmpty() == true) {
|
||||||
activity.showToast(false, R.string.already_reactioned)
|
activity.showToast(false, R.string.already_reactioned)
|
||||||
|
@ -2608,7 +2608,7 @@ internal class ItemViewHolder(
|
||||||
|
|
||||||
if(access_info.isPseudo || ! access_info.isMisskey) return
|
if(access_info.isPseudo || ! access_info.isMisskey) return
|
||||||
|
|
||||||
if(codeArg == null) {
|
if(code == null) {
|
||||||
EmojiPicker(activity, access_info,closeOnSelected = true) { name, instance, _, _, _ ->
|
EmojiPicker(activity, access_info,closeOnSelected = true) { name, instance, _, _, _ ->
|
||||||
val item = EmojiMap.sShortNameToEmojiInfo[name]
|
val item = EmojiMap.sShortNameToEmojiInfo[name]
|
||||||
val code = if(item == null || instance != null) {
|
val code = if(item == null || instance != null) {
|
||||||
|
@ -2636,12 +2636,8 @@ internal class ItemViewHolder(
|
||||||
TootTaskRunner(activity, progress_style = TootTaskRunner.PROGRESS_NONE).run(access_info,
|
TootTaskRunner(activity, progress_style = TootTaskRunner.PROGRESS_NONE).run(access_info,
|
||||||
object : TootTask {
|
object : TootTask {
|
||||||
|
|
||||||
var code :String = codeArg
|
|
||||||
|
|
||||||
override suspend fun background(client : TootApiClient) : TootApiResult? {
|
override suspend fun background(client : TootApiClient) : TootApiResult? {
|
||||||
|
|
||||||
code = MisskeyReaction.toLegacyReaction(client,code)
|
|
||||||
|
|
||||||
val params = access_info.putMisskeyApiToken().apply {
|
val params = access_info.putMisskeyApiToken().apply {
|
||||||
put("noteId", status.id.toString())
|
put("noteId", status.id.toString())
|
||||||
put("reaction", code)
|
put("reaction", code)
|
||||||
|
|
|
@ -1309,7 +1309,7 @@ object Action_Toot {
|
||||||
nCrossAccountMode: Int,
|
nCrossAccountMode: Int,
|
||||||
callback: () -> Unit,
|
callback: () -> Unit,
|
||||||
bSet: Boolean = true,
|
bSet: Boolean = true,
|
||||||
codeArg: String? = null
|
code: String? = null
|
||||||
) {
|
) {
|
||||||
if (access_info.isPseudo || !access_info.isMisskey) return
|
if (access_info.isPseudo || !access_info.isMisskey) return
|
||||||
|
|
||||||
|
@ -1319,34 +1319,31 @@ object Action_Toot {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codeArg == null) {
|
if (code == null) {
|
||||||
if (bSet)
|
if (!bSet) error("will not happen")
|
||||||
EmojiPicker(activity, access_info, closeOnSelected = true) { name, instance, _, _, _ ->
|
EmojiPicker(activity, access_info, closeOnSelected = true) { name, instance, _, _, _ ->
|
||||||
val item = EmojiMap.sShortNameToEmojiInfo[name]
|
val item = EmojiMap.sShortNameToEmojiInfo[name]
|
||||||
val newCode = if (item == null || instance != null) {
|
val newCode = if (item == null || instance != null) {
|
||||||
":$name:"
|
":$name:"
|
||||||
} else {
|
} else {
|
||||||
item.unified
|
item.unified
|
||||||
}
|
}
|
||||||
reaction(
|
reaction(
|
||||||
activity,
|
activity,
|
||||||
access_info,
|
access_info,
|
||||||
arg_status,
|
arg_status,
|
||||||
status_owner_acct,
|
status_owner_acct,
|
||||||
nCrossAccountMode,
|
nCrossAccountMode,
|
||||||
callback,
|
callback,
|
||||||
bSet,
|
bSet,
|
||||||
newCode
|
newCode
|
||||||
)
|
)
|
||||||
}.show()
|
}.show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TootTaskRunner(activity, TootTaskRunner.PROGRESS_NONE).run(access_info, object : TootTask {
|
TootTaskRunner(activity, TootTaskRunner.PROGRESS_NONE).run(access_info, object : TootTask {
|
||||||
|
|
||||||
var code: String = codeArg
|
|
||||||
|
|
||||||
override suspend fun background(client: TootApiClient): TootApiResult? {
|
override suspend fun background(client: TootApiClient): TootApiResult? {
|
||||||
|
|
||||||
val target_status = if (nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE) {
|
val target_status = if (nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE) {
|
||||||
|
@ -1378,8 +1375,6 @@ object Action_Toot {
|
||||||
// 成功すると204 no content
|
// 成功すると204 no content
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
code = MisskeyReaction.toLegacyReaction(client, code)
|
|
||||||
|
|
||||||
client.request(
|
client.request(
|
||||||
"/api/notes/reactions/create",
|
"/api/notes/reactions/create",
|
||||||
access_info.putMisskeyApiToken().apply {
|
access_info.putMisskeyApiToken().apply {
|
||||||
|
@ -1433,7 +1428,7 @@ object Action_Toot {
|
||||||
status_owner,
|
status_owner,
|
||||||
calcCrossAccountMode(timeline_account, action_account),
|
calcCrossAccountMode(timeline_account, action_account),
|
||||||
activity.reaction_complete_callback,
|
activity.reaction_complete_callback,
|
||||||
codeArg = code
|
code = code
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
package jp.juggler.subwaytooter.api.entity
|
package jp.juggler.subwaytooter.api.entity
|
||||||
|
|
||||||
import android.graphics.drawable.PictureDrawable
|
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableStringBuilder
|
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.App1
|
||||||
import jp.juggler.subwaytooter.Pref
|
import jp.juggler.subwaytooter.Pref
|
||||||
import jp.juggler.subwaytooter.api.TootApiClient
|
|
||||||
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
|
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount
|
import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
import jp.juggler.subwaytooter.util.DecodeOptions
|
import jp.juggler.subwaytooter.util.DecodeOptions
|
||||||
|
@ -46,51 +40,58 @@ object MisskeyReaction {
|
||||||
"star" to "\u2B50", // リモートからのFavを示す代替リアクション。ピッカーには表示しない
|
"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絵文字にする
|
// 古い形式の絵文字はUnicode絵文字にする
|
||||||
oldReactions[code]?.let {
|
oldReactions[code]?.let {
|
||||||
return EmojiDecoder.decodeEmoji(options, it)
|
return EmojiDecoder.decodeEmoji(options, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// カスタム絵文字
|
fun CustomEmoji.toSpannableStringBuilder():SpannableStringBuilder?{
|
||||||
val customCode = code.replace(":", "")
|
return if (Pref.bpDisableEmojiAnimation(App1.pref)) {
|
||||||
if (customCode != code) {
|
static_url
|
||||||
val accessInfo = options.linkHelper as? SavedAccount
|
} else {
|
||||||
if (accessInfo != null) {
|
url
|
||||||
val emojiUrl =
|
}?.let{
|
||||||
App1.custom_emoji_lister
|
SpannableStringBuilder(code).apply {
|
||||||
.getMap(accessInfo)
|
setSpan(
|
||||||
?.get(customCode)
|
NetworkEmojiSpan(it, scale = options.enlargeCustomEmoji),
|
||||||
?.let {
|
0,
|
||||||
if (Pref.bpDisableEmojiAnimation(App1.pref)) {
|
length,
|
||||||
it.static_url
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
} else {
|
)
|
||||||
it.url
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if (emojiUrl != null)
|
|
||||||
return SpannableStringBuilder(code).apply {
|
|
||||||
setSpan(
|
|
||||||
NetworkEmojiSpan(emojiUrl, 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表現
|
// unicode絵文字、もしくは :xxx: などのshortcode表現
|
||||||
return EmojiDecoder.decodeEmoji(options, code)
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.regex.Pattern
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.LinkedHashMap
|
import kotlin.collections.LinkedHashMap
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class FilterTrees(
|
class FilterTrees(
|
||||||
|
@ -927,6 +928,18 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
||||||
return list
|
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
|
// return true if updated
|
||||||
fun increaseReaction(reaction: String?, byMe: Boolean, caller: String): Boolean {
|
fun increaseReaction(reaction: String?, byMe: Boolean, caller: String): Boolean {
|
||||||
reaction ?: return false
|
reaction ?: return false
|
||||||
|
@ -948,8 +961,17 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
||||||
map = LinkedHashMap()
|
map = LinkedHashMap()
|
||||||
this.reactionCounts = map
|
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
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -975,8 +997,16 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
||||||
map = LinkedHashMap()
|
map = LinkedHashMap()
|
||||||
this.reactionCounts = map
|
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
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue