Misskeyのカスタム絵文字の入力補完でaliasesに対応。Misskeyのプロフカラムで情報が足りない問題に対応。
This commit is contained in:
parent
0c00e5060c
commit
9c12e5f85d
|
@ -12,6 +12,7 @@ import jp.juggler.emoji.EmojiMap201709
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.action.Action_Follow
|
import jp.juggler.subwaytooter.action.Action_Follow
|
||||||
import jp.juggler.subwaytooter.action.Action_User
|
import jp.juggler.subwaytooter.action.Action_User
|
||||||
|
import jp.juggler.subwaytooter.api.MisskeyAccountDetailMap
|
||||||
import jp.juggler.subwaytooter.api.entity.TootAccount
|
import jp.juggler.subwaytooter.api.entity.TootAccount
|
||||||
import jp.juggler.subwaytooter.api.entity.TootAccountRef
|
import jp.juggler.subwaytooter.api.entity.TootAccountRef
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||||
|
@ -129,6 +130,7 @@ internal class ViewHolderHeaderProfile(
|
||||||
override fun bindData(column : Column) {
|
override fun bindData(column : Column) {
|
||||||
super.bindData(column)
|
super.bindData(column)
|
||||||
|
|
||||||
|
|
||||||
if(! activity.timeline_font_size_sp.isNaN()) {
|
if(! activity.timeline_font_size_sp.isNaN()) {
|
||||||
tvMovedName.textSize = activity.timeline_font_size_sp
|
tvMovedName.textSize = activity.timeline_font_size_sp
|
||||||
tvMoved.textSize = activity.timeline_font_size_sp
|
tvMoved.textSize = activity.timeline_font_size_sp
|
||||||
|
@ -142,6 +144,13 @@ internal class ViewHolderHeaderProfile(
|
||||||
val whoRef = column.who_account
|
val whoRef = column.who_account
|
||||||
this.whoRef = whoRef
|
this.whoRef = whoRef
|
||||||
val who = whoRef?.get()
|
val who = whoRef?.get()
|
||||||
|
|
||||||
|
// Misskeyの場合はNote中のUserエンティティと /api/users/show の情報量がかなり異なる
|
||||||
|
val whoDetail = if(who == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
MisskeyAccountDetailMap.get(access_info, who.id)
|
||||||
|
}
|
||||||
|
|
||||||
showColor()
|
showColor()
|
||||||
|
|
||||||
|
@ -184,7 +193,7 @@ internal class ViewHolderHeaderProfile(
|
||||||
access_info.supplyBaseUrl(who.avatar)
|
access_info.supplyBaseUrl(who.avatar)
|
||||||
)
|
)
|
||||||
|
|
||||||
val name = whoRef.decoded_display_name
|
val name = whoDetail?.decodeDisplayName(activity) ?: whoRef.decoded_display_name
|
||||||
tvDisplayName.text = name
|
tvDisplayName.text = name
|
||||||
name_invalidator.register(name)
|
name_invalidator.register(name)
|
||||||
|
|
||||||
|
@ -193,7 +202,7 @@ internal class ViewHolderHeaderProfile(
|
||||||
|
|
||||||
val sb = SpannableStringBuilder()
|
val sb = SpannableStringBuilder()
|
||||||
sb.append("@").append(access_info.getFullAcct(who))
|
sb.append("@").append(access_info.getFullAcct(who))
|
||||||
if(who.locked) {
|
if(whoDetail?.locked ?: who.locked) {
|
||||||
sb.append(" ")
|
sb.append(" ")
|
||||||
val start = sb.length
|
val start = sb.length
|
||||||
sb.append("locked")
|
sb.append("locked")
|
||||||
|
@ -208,7 +217,7 @@ internal class ViewHolderHeaderProfile(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(who.bot){
|
if(who.bot) {
|
||||||
sb.append(" ")
|
sb.append(" ")
|
||||||
val start = sb.length
|
val start = sb.length
|
||||||
sb.append("bot")
|
sb.append("bot")
|
||||||
|
@ -229,9 +238,12 @@ internal class ViewHolderHeaderProfile(
|
||||||
tvNote.text = note
|
tvNote.text = note
|
||||||
note_invalidator.register(note)
|
note_invalidator.register(note)
|
||||||
|
|
||||||
btnStatusCount.text = activity.getString(R.string.statuses) + "\n" + who.statuses_count
|
btnStatusCount.text = activity.getString(R.string.statuses) + "\n" +
|
||||||
btnFollowing.text = activity.getString(R.string.following) + "\n" + who.following_count
|
(whoDetail?.statuses_count ?: who.statuses_count)
|
||||||
btnFollowers.text = activity.getString(R.string.followers) + "\n" + who.followers_count
|
btnFollowing.text = activity.getString(R.string.following) + "\n" +
|
||||||
|
(whoDetail?.following_count ?: who.following_count)
|
||||||
|
btnFollowers.text = activity.getString(R.string.followers) + "\n" +
|
||||||
|
(whoDetail?.followers_count ?: who.followers_count)
|
||||||
|
|
||||||
val relation = UserRelation.load(access_info.db_id, who.id)
|
val relation = UserRelation.load(access_info.db_id, who.id)
|
||||||
Styler.setFollowIcon(activity, btnFollow, ivFollowedBy, relation, who)
|
Styler.setFollowIcon(activity, btnFollow, ivFollowedBy, relation, who)
|
||||||
|
@ -259,8 +271,7 @@ internal class ViewHolderHeaderProfile(
|
||||||
short = true,
|
short = true,
|
||||||
emojiMapProfile = who.profile_emojis
|
emojiMapProfile = who.profile_emojis
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
val content_color = column.content_color
|
val content_color = column.content_color
|
||||||
val c = if(content_color != 0) content_color else default_color
|
val c = if(content_color != 0) content_color else default_color
|
||||||
|
|
||||||
|
@ -295,18 +306,18 @@ internal class ViewHolderHeaderProfile(
|
||||||
)
|
)
|
||||||
|
|
||||||
val valueText = decodeOptions.decodeHTML(item.value)
|
val valueText = decodeOptions.decodeHTML(item.value)
|
||||||
if(item.verified_at > 0L){
|
if(item.verified_at > 0L) {
|
||||||
valueText.append('\n')
|
valueText.append('\n')
|
||||||
|
|
||||||
val start = valueText.length
|
val start = valueText.length
|
||||||
valueText.append( activity.getString(R.string.verified_at))
|
valueText.append(activity.getString(R.string.verified_at))
|
||||||
valueText.append( ": ")
|
valueText.append(": ")
|
||||||
valueText.append(TootStatus.formatTime(activity,item.verified_at,false))
|
valueText.append(TootStatus.formatTime(activity, item.verified_at, false))
|
||||||
val end = valueText.length
|
val end = valueText.length
|
||||||
|
|
||||||
valueText.setSpan(
|
valueText.setSpan(
|
||||||
ForegroundColorSpan(Color.BLACK or 0x7fbc99)
|
ForegroundColorSpan(Color.BLACK or 0x7fbc99)
|
||||||
,start,end,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +331,7 @@ internal class ViewHolderHeaderProfile(
|
||||||
valueView.typeface = valueTypeface
|
valueView.typeface = valueTypeface
|
||||||
valueView.movementMethod = MyLinkMovementMethod
|
valueView.movementMethod = MyLinkMovementMethod
|
||||||
|
|
||||||
if(item.verified_at > 0L){
|
if(item.verified_at > 0L) {
|
||||||
valueView.setBackgroundColor(0x337fbc99)
|
valueView.setBackgroundColor(0x337fbc99)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package jp.juggler.subwaytooter.api
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.api.entity.*
|
||||||
|
import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
object MisskeyAccountDetailMap {
|
||||||
|
|
||||||
|
private class AccountKey(
|
||||||
|
val db_id : Long,
|
||||||
|
val id : EntityId
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun hashCode() : Int {
|
||||||
|
val h1 = (db_id xor db_id.ushr(32)).toInt()
|
||||||
|
val h2 = id.hashCode()
|
||||||
|
return (h1 xor h2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other : Any?) : Boolean {
|
||||||
|
return other is AccountKey && other.db_id == db_id && other.id == id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val accountMap = ConcurrentHashMap<AccountKey, TootAccount>()
|
||||||
|
|
||||||
|
fun fromAccount(parser : TootParser, src : TootAccount, id : EntityId) {
|
||||||
|
// SavedAccountが不明なら何もしない
|
||||||
|
val access_info = parser.linkHelper as? SavedAccount ?: return
|
||||||
|
|
||||||
|
// アカウントのjsonがフォロー数を含まないなら何もしない
|
||||||
|
if((src.followers_count ?: - 1) < 0L) return
|
||||||
|
|
||||||
|
val key = AccountKey(access_info.db_id, id)
|
||||||
|
accountMap[key] = src
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(accessInfo : SavedAccount, id : EntityId) : TootAccount? {
|
||||||
|
return accountMap[AccountKey(accessInfo.db_id, id)]
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ class TootParser(
|
||||||
var misskeyDecodeProfilePin :Boolean = false
|
var misskeyDecodeProfilePin :Boolean = false
|
||||||
) {
|
) {
|
||||||
val misskeyUserRelationMap = HashMap<EntityId, UserRelation>()
|
val misskeyUserRelationMap = HashMap<EntityId, UserRelation>()
|
||||||
|
val misskeyAccountDetailMap = HashMap<EntityId, TootAccount>()
|
||||||
|
|
||||||
init{
|
init{
|
||||||
if(linkHelper.isMisskey) serviceType = ServiceType.MISSKEY
|
if(linkHelper.isMisskey) serviceType = ServiceType.MISSKEY
|
||||||
|
|
|
@ -2,15 +2,25 @@ package jp.juggler.subwaytooter.api.entity
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.util.notEmptyOrThrow
|
import jp.juggler.subwaytooter.util.notEmptyOrThrow
|
||||||
import jp.juggler.subwaytooter.util.parseString
|
import jp.juggler.subwaytooter.util.parseString
|
||||||
|
import org.json.JSONArray
|
||||||
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
class CustomEmoji(
|
class CustomEmoji(
|
||||||
val shortcode : String, // shortcode (コロンを含まない)
|
val shortcode : String, // shortcode (コロンを含まない)
|
||||||
val url : String, // 画像URL
|
val url : String, // 画像URL
|
||||||
val static_url : String? // アニメーションなしの画像URL
|
val static_url : String?, // アニメーションなしの画像URL
|
||||||
|
val aliases : ArrayList<String>? = null,
|
||||||
|
val alias:String? =null
|
||||||
) : Mappable<String> {
|
) : Mappable<String> {
|
||||||
|
|
||||||
|
fun makeAlias(alias : String) = CustomEmoji (
|
||||||
|
shortcode= this.shortcode,
|
||||||
|
url = this.url,
|
||||||
|
static_url = this.static_url,
|
||||||
|
alias = alias
|
||||||
|
)
|
||||||
|
|
||||||
override val mapKey : String
|
override val mapKey : String
|
||||||
get() = shortcode
|
get() = shortcode
|
||||||
|
|
||||||
|
@ -24,31 +34,31 @@ class CustomEmoji(
|
||||||
}
|
}
|
||||||
val decodeMisskey : (JSONObject) -> CustomEmoji = { src ->
|
val decodeMisskey : (JSONObject) -> CustomEmoji = { src ->
|
||||||
val url = src.parseString("url") ?: error("missing url")
|
val url = src.parseString("url") ?: error("missing url")
|
||||||
val name = src.parseString("name") ?: error("missing name")
|
|
||||||
|
|
||||||
// 使い方が分からない val aliases = parseAliases(src.optJSONArray("aliases"))
|
|
||||||
|
|
||||||
CustomEmoji(
|
CustomEmoji(
|
||||||
shortcode = name,
|
shortcode = src.parseString("name") ?: error("missing name"),
|
||||||
url = url,
|
url = url,
|
||||||
static_url = url
|
static_url = url,
|
||||||
|
aliases = parseAliases(src.optJSONArray("aliases"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// private fun parseAliases(src : JSONArray?) : ArrayList<String>? {
|
private fun parseAliases(src : JSONArray?) : ArrayList<String>? {
|
||||||
// var dst = null as ArrayList<String>?
|
var dst = null as ArrayList<String>?
|
||||||
// if(src != null) {
|
if(src != null) {
|
||||||
// val size = src.length()
|
val size = src.length()
|
||||||
// for(i in 0 until size) {
|
if( size > 0){
|
||||||
// val str = src.parseString(i) ?: continue
|
dst = ArrayList(size)
|
||||||
// if(str.isNotEmpty()) {
|
for(i in 0 until size) {
|
||||||
// if(dst == null) dst = ArrayList(size)
|
val str = src.parseString(i) ?: continue
|
||||||
// dst.add(str)
|
if(str.isNotEmpty()) {
|
||||||
// }
|
dst.add(str)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// return dst
|
}
|
||||||
// }
|
}
|
||||||
|
return if(dst?.isNotEmpty() == true ) dst else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,13 @@ package jp.juggler.subwaytooter.api.entity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
|
import jp.juggler.subwaytooter.api.MisskeyAccountDetailMap
|
||||||
import jp.juggler.subwaytooter.api.TootParser
|
import jp.juggler.subwaytooter.api.TootParser
|
||||||
import jp.juggler.subwaytooter.table.UserRelation
|
|
||||||
import jp.juggler.subwaytooter.table.UserRelationMisskey
|
import jp.juggler.subwaytooter.table.UserRelationMisskey
|
||||||
import jp.juggler.subwaytooter.util.*
|
import jp.juggler.subwaytooter.util.*
|
||||||
|
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.util.*
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
open class TootAccount(parser : TootParser, src : JSONObject) {
|
open class TootAccount(parser : TootParser, src : JSONObject) {
|
||||||
|
@ -252,7 +250,7 @@ open class TootAccount(parser : TootParser, src : JSONObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UserRelationMisskey.fromAccount(parser,src,id)
|
UserRelationMisskey.fromAccount(parser,src,id)
|
||||||
|
MisskeyAccountDetailMap.fromAccount(parser,this,id)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,11 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
get() = SystemClock.elapsedRealtime()
|
get() = SystemClock.elapsedRealtime()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CacheItem(val instance : String, var list : ArrayList<CustomEmoji>?) {
|
internal class CacheItem(
|
||||||
|
val instance : String,
|
||||||
|
var list : ArrayList<CustomEmoji>? = null,
|
||||||
|
var listWithAliases : ArrayList<CustomEmoji>? = null
|
||||||
|
) {
|
||||||
|
|
||||||
// 参照された時刻
|
// 参照された時刻
|
||||||
var time_used : Long = 0
|
var time_used : Long = 0
|
||||||
|
@ -44,6 +48,7 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
internal class Request(
|
internal class Request(
|
||||||
val instance : String,
|
val instance : String,
|
||||||
val isMisskey : Boolean,
|
val isMisskey : Boolean,
|
||||||
|
val reportWithAliases : Boolean = false,
|
||||||
val onListLoaded : (list : ArrayList<CustomEmoji>) -> Unit?
|
val onListLoaded : (list : ArrayList<CustomEmoji>) -> Unit?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,7 +58,7 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
// エラーキャッシュ
|
// エラーキャッシュ
|
||||||
internal val cache_error = ConcurrentHashMap<String, Long>()
|
internal val cache_error = ConcurrentHashMap<String, Long>()
|
||||||
|
|
||||||
private val cache_error_item = CacheItem("error", null)
|
private val cache_error_item = CacheItem("error")
|
||||||
|
|
||||||
// ロード要求
|
// ロード要求
|
||||||
internal val queue = ConcurrentLinkedQueue<Request>()
|
internal val queue = ConcurrentLinkedQueue<Request>()
|
||||||
|
@ -100,7 +105,36 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
if(item != null) return item.list
|
if(item != null) return item.list
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.add(Request(instance, isMisskey, onListLoaded))
|
queue.add(Request(instance, isMisskey, onListLoaded = onListLoaded))
|
||||||
|
worker.notifyEx()
|
||||||
|
} catch(ex : Throwable) {
|
||||||
|
log.trace(ex)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getListWithAliases(
|
||||||
|
_instance : String,
|
||||||
|
isMisskey : Boolean,
|
||||||
|
onListLoaded : (list : ArrayList<CustomEmoji>) -> Unit
|
||||||
|
) : ArrayList<CustomEmoji>? {
|
||||||
|
try {
|
||||||
|
if(_instance.isEmpty()) return null
|
||||||
|
val instance = _instance.toLowerCase()
|
||||||
|
|
||||||
|
synchronized(cache) {
|
||||||
|
val item = getCached(elapsedTime, instance)
|
||||||
|
if(item != null) return item.listWithAliases
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.add(
|
||||||
|
Request(
|
||||||
|
instance,
|
||||||
|
isMisskey,
|
||||||
|
reportWithAliases = true,
|
||||||
|
onListLoaded = onListLoaded
|
||||||
|
)
|
||||||
|
)
|
||||||
worker.notifyEx()
|
worker.notifyEx()
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
|
@ -141,8 +175,9 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
val item = getCached(elapsedTime, request.instance)
|
val item = getCached(elapsedTime, request.instance)
|
||||||
return@synchronized if(item != null) {
|
return@synchronized if(item != null) {
|
||||||
val list = item.list
|
val list = item.list
|
||||||
if(list != null) {
|
val listWithAliases = item.listWithAliases
|
||||||
fireCallback(request, list)
|
if(list != null && listWithAliases != null) {
|
||||||
|
fireCallback(request, list, listWithAliases)
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -154,6 +189,7 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
if(cached) continue
|
if(cached) continue
|
||||||
|
|
||||||
var list : ArrayList<CustomEmoji>? = null
|
var list : ArrayList<CustomEmoji>? = null
|
||||||
|
var listWithAlias : ArrayList<CustomEmoji>? = null
|
||||||
try {
|
try {
|
||||||
val data = if(request.isMisskey) {
|
val data = if(request.isMisskey) {
|
||||||
App1.getHttpCachedString("https://" + request.instance + "/api/meta") { builder ->
|
App1.getHttpCachedString("https://" + request.instance + "/api/meta") { builder ->
|
||||||
|
@ -165,29 +201,32 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
} else {
|
} else {
|
||||||
App1.getHttpCachedString("https://" + request.instance + "/api/v1/custom_emojis")
|
App1.getHttpCachedString("https://" + request.instance + "/api/v1/custom_emojis")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data != null) {
|
if(data != null) {
|
||||||
list = decodeEmojiList(data, request.instance, request.isMisskey)
|
val a = decodeEmojiList(data, request.instance, request.isMisskey)
|
||||||
|
list = a
|
||||||
|
listWithAlias = makeListWithAlias(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(cache) {
|
synchronized(cache) {
|
||||||
val now = elapsedTime
|
val now = elapsedTime
|
||||||
if(list == null) {
|
if(list == null || listWithAlias == null) {
|
||||||
cache_error.put(request.instance, now)
|
cache_error.put(request.instance, now)
|
||||||
} else {
|
} else {
|
||||||
var item : CacheItem? = cache[request.instance]
|
var item : CacheItem? = cache[request.instance]
|
||||||
if(item == null) {
|
if(item == null) {
|
||||||
item = CacheItem(request.instance, list)
|
item = CacheItem(request.instance, list, listWithAlias)
|
||||||
cache[request.instance] = item
|
cache[request.instance] = item
|
||||||
} else {
|
} else {
|
||||||
item.list = list
|
item.list = list
|
||||||
|
item.listWithAliases = listWithAlias
|
||||||
item.time_update = now
|
item.time_update = now
|
||||||
}
|
}
|
||||||
fireCallback(request, list)
|
fireCallback(request, list, listWithAlias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
|
@ -197,8 +236,21 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fireCallback(request : Request, list : ArrayList<CustomEmoji>) {
|
|
||||||
handler.post { request.onListLoaded(list) }
|
private fun fireCallback(
|
||||||
|
request : Request,
|
||||||
|
list : ArrayList<CustomEmoji>,
|
||||||
|
listWithAliases : ArrayList<CustomEmoji>
|
||||||
|
) {
|
||||||
|
handler.post {
|
||||||
|
request.onListLoaded(
|
||||||
|
if(request.reportWithAliases) {
|
||||||
|
listWithAliases
|
||||||
|
} else {
|
||||||
|
list
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// キャッシュの掃除
|
// キャッシュの掃除
|
||||||
|
@ -243,6 +295,23 @@ class CustomEmojiLister(internal val context : Context) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun makeListWithAlias(list : ArrayList<CustomEmoji>?) : ArrayList<CustomEmoji> {
|
||||||
|
val dst = ArrayList<CustomEmoji>()
|
||||||
|
if( list != null) {
|
||||||
|
dst.addAll(list)
|
||||||
|
for(item in list) {
|
||||||
|
val aliases = item.aliases ?: continue
|
||||||
|
for(alias in aliases) {
|
||||||
|
if( alias.equals(item.shortcode,ignoreCase = true)) continue
|
||||||
|
dst.add(item.makeAlias(alias))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst.sortWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.alias ?: it.shortcode })
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,21 +36,21 @@ object EmojiDecoder {
|
||||||
return when(cp) {
|
return when(cp) {
|
||||||
- 1 -> true
|
- 1 -> true
|
||||||
cpColon -> false
|
cpColon -> false
|
||||||
// rubyの (Letter | Mark | Decimal_Number) はNG
|
// rubyの (Letter | Mark | Decimal_Number) はNG
|
||||||
// ftp://unicode.org/Public/5.1.0/ucd/UCD.html#General_Category_Values
|
// ftp://unicode.org/Public/5.1.0/ucd/UCD.html#General_Category_Values
|
||||||
else -> when(java.lang.Character.getType(cp).toByte()) {
|
else -> when(java.lang.Character.getType(cp).toByte()) {
|
||||||
// Letter
|
// Letter
|
||||||
// LCはエイリアスなので文字から得られることはないはず
|
// LCはエイリアスなので文字から得られることはないはず
|
||||||
Character.UPPERCASE_LETTER,
|
Character.UPPERCASE_LETTER,
|
||||||
Character.LOWERCASE_LETTER,
|
Character.LOWERCASE_LETTER,
|
||||||
Character.TITLECASE_LETTER,
|
Character.TITLECASE_LETTER,
|
||||||
Character.MODIFIER_LETTER,
|
Character.MODIFIER_LETTER,
|
||||||
Character.OTHER_LETTER -> false
|
Character.OTHER_LETTER -> false
|
||||||
// Mark
|
// Mark
|
||||||
Character.NON_SPACING_MARK,
|
Character.NON_SPACING_MARK,
|
||||||
Character.COMBINING_SPACING_MARK,
|
Character.COMBINING_SPACING_MARK,
|
||||||
Character.ENCLOSING_MARK -> false
|
Character.ENCLOSING_MARK -> false
|
||||||
// Decimal_Number
|
// Decimal_Number
|
||||||
Character.DECIMAL_DIGIT_NUMBER -> false
|
Character.DECIMAL_DIGIT_NUMBER -> false
|
||||||
|
|
||||||
else -> true
|
else -> true
|
||||||
|
@ -106,7 +106,7 @@ object EmojiDecoder {
|
||||||
sb.append(text)
|
sb.append(text)
|
||||||
val end = sb.length
|
val end = sb.length
|
||||||
sb.setSpan(
|
sb.setSpan(
|
||||||
NetworkEmojiSpan(url,scale = options.enlargeCustomEmoji),
|
NetworkEmojiSpan(url, scale = options.enlargeCustomEmoji),
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
@ -177,7 +177,7 @@ object EmojiDecoder {
|
||||||
val c = s[i ++]
|
val c = s[i ++]
|
||||||
sb.append(
|
sb.append(
|
||||||
when(c) {
|
when(c) {
|
||||||
// https://github.com/tateisu/SubwayTooter/issues/69
|
// https://github.com/tateisu/SubwayTooter/issues/69
|
||||||
'\u00AD' -> '-'
|
'\u00AD' -> '-'
|
||||||
else -> c
|
else -> c
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.util.ArrayList
|
||||||
import jp.juggler.subwaytooter.R
|
import jp.juggler.subwaytooter.R
|
||||||
import jp.juggler.subwaytooter.Styler
|
import jp.juggler.subwaytooter.Styler
|
||||||
import jp.juggler.subwaytooter.view.MyEditText
|
import jp.juggler.subwaytooter.view.MyEditText
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
internal class PopupAutoCompleteAcct(
|
internal class PopupAutoCompleteAcct(
|
||||||
|
@ -30,6 +31,9 @@ internal class PopupAutoCompleteAcct(
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal val log = LogCategory("PopupAutoCompleteAcct")
|
internal val log = LogCategory("PopupAutoCompleteAcct")
|
||||||
|
|
||||||
|
// 絵文字ショートコードにマッチするとても雑な正規表現
|
||||||
|
private val reLastShortCode = Pattern.compile(""":([^\s:]+):\z""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val acct_popup : PopupWindow
|
private val acct_popup : PopupWindow
|
||||||
|
@ -135,7 +139,7 @@ internal class PopupAutoCompleteAcct(
|
||||||
if(acct[0] == ' ') {
|
if(acct[0] == ' ') {
|
||||||
// 絵文字ショートコード
|
// 絵文字ショートコード
|
||||||
if(! EmojiDecoder.canStartShortCode(sb, start)) sb.append(' ')
|
if(! EmojiDecoder.canStartShortCode(sb, start)) sb.append(' ')
|
||||||
sb.append(acct.subSequence(2, acct.length))
|
sb.append( findShortCode(acct.toString()))
|
||||||
} else {
|
} else {
|
||||||
// @user@host, #hashtag
|
// @user@host, #hashtag
|
||||||
// 直後に空白を付与する
|
// 直後に空白を付与する
|
||||||
|
@ -159,6 +163,14 @@ internal class PopupAutoCompleteAcct(
|
||||||
updatePosition()
|
updatePosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun findShortCode(acct : String) : String {
|
||||||
|
val m = reLastShortCode.matcher(acct)
|
||||||
|
if(m.find()) return m.group(0)
|
||||||
|
return acct
|
||||||
|
}
|
||||||
|
|
||||||
fun updatePosition() {
|
fun updatePosition() {
|
||||||
|
|
||||||
val location = IntArray(2)
|
val location = IntArray(2)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.os.SystemClock
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.text.*
|
import android.text.*
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import jp.juggler.emoji.EmojiMap201709
|
import jp.juggler.emoji.EmojiMap201709
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ import java.util.regex.Pattern
|
||||||
import jp.juggler.subwaytooter.App1
|
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.Styler
|
||||||
import jp.juggler.subwaytooter.api.TootApiClient
|
import jp.juggler.subwaytooter.api.TootApiClient
|
||||||
import jp.juggler.subwaytooter.api.TootApiResult
|
import jp.juggler.subwaytooter.api.TootApiResult
|
||||||
import jp.juggler.subwaytooter.api.TootTask
|
import jp.juggler.subwaytooter.api.TootTask
|
||||||
|
@ -159,7 +161,7 @@ class PostHelper(
|
||||||
|
|
||||||
if(! bConfirmTag) {
|
if(! bConfirmTag) {
|
||||||
|
|
||||||
if( !account.isMisskey
|
if(! account.isMisskey
|
||||||
&& visibility != TootVisibility.Public
|
&& visibility != TootVisibility.Public
|
||||||
&& reTag.matcher(content).find()
|
&& reTag.matcher(content).find()
|
||||||
) {
|
) {
|
||||||
|
@ -228,18 +230,18 @@ class PostHelper(
|
||||||
|
|
||||||
var credential_tmp : TootAccount? = null
|
var credential_tmp : TootAccount? = null
|
||||||
|
|
||||||
val parser = TootParser(activity, account )
|
val parser = TootParser(activity, account)
|
||||||
|
|
||||||
fun getInstanceInformation(client : TootApiClient) : TootApiResult? {
|
fun getInstanceInformation(client : TootApiClient) : TootApiResult? {
|
||||||
val result = if( account.isMisskey){
|
val result = if(account.isMisskey) {
|
||||||
val params = JSONObject().apply{
|
val params = JSONObject().apply {
|
||||||
put("dummy",1)
|
put("dummy", 1)
|
||||||
}
|
}
|
||||||
client.request("/api/meta",params.toPostRequestBuilder())
|
client.request("/api/meta", params.toPostRequestBuilder())
|
||||||
}else{
|
} else {
|
||||||
client.request("/api/v1/instance")
|
client.request("/api/v1/instance")
|
||||||
}
|
}
|
||||||
instance_tmp = parseItem(::TootInstance,parser , result?.jsonObject)
|
instance_tmp = parseItem(::TootInstance, parser, result?.jsonObject)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,15 +257,15 @@ class PostHelper(
|
||||||
|
|
||||||
// 元の投稿を削除する
|
// 元の投稿を削除する
|
||||||
if(redraft_status_id != null) {
|
if(redraft_status_id != null) {
|
||||||
result = if( isMisskey ){
|
result = if(isMisskey) {
|
||||||
val params = account.putMisskeyApiToken(JSONObject()).apply{
|
val params = account.putMisskeyApiToken(JSONObject()).apply {
|
||||||
put("noteId",redraft_status_id)
|
put("noteId", redraft_status_id)
|
||||||
}
|
}
|
||||||
client.request(
|
client.request(
|
||||||
"/api/notes/delete",
|
"/api/notes/delete",
|
||||||
params.toPostRequestBuilder()
|
params.toPostRequestBuilder()
|
||||||
)
|
)
|
||||||
}else{
|
} else {
|
||||||
client.request(
|
client.request(
|
||||||
"/api/v1/statuses/$redraft_status_id",
|
"/api/v1/statuses/$redraft_status_id",
|
||||||
Request.Builder().delete()
|
Request.Builder().delete()
|
||||||
|
@ -283,16 +285,17 @@ class PostHelper(
|
||||||
account.instance = instance
|
account.instance = instance
|
||||||
}
|
}
|
||||||
|
|
||||||
if( visibility == TootVisibility.WebSetting) {
|
if(visibility == TootVisibility.WebSetting) {
|
||||||
visibility_checked = if(account.isMisskey || instance.versionGE(TootInstance.VERSION_1_6)) {
|
visibility_checked =
|
||||||
null
|
if(account.isMisskey || instance.versionGE(TootInstance.VERSION_1_6)) {
|
||||||
} else {
|
null
|
||||||
val r2 = getCredential(client)
|
} else {
|
||||||
val credential_tmp = this.credential_tmp ?: return r2
|
val r2 = getCredential(client)
|
||||||
val privacy = credential_tmp.source?.privacy
|
val credential_tmp = this.credential_tmp ?: return r2
|
||||||
?: return TootApiResult(activity.getString(R.string.cant_get_web_setting_visibility))
|
val privacy = credential_tmp.source?.privacy
|
||||||
TootVisibility.parseMastodon(privacy)
|
?: return TootApiResult(activity.getString(R.string.cant_get_web_setting_visibility))
|
||||||
}
|
TootVisibility.parseMastodon(privacy)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val json = JSONObject()
|
val json = JSONObject()
|
||||||
|
@ -308,34 +311,43 @@ class PostHelper(
|
||||||
)
|
)
|
||||||
if(visibility_checked != null) {
|
if(visibility_checked != null) {
|
||||||
|
|
||||||
if( visibility_checked == TootVisibility.DirectSpecified ){
|
if(visibility_checked == TootVisibility.DirectSpecified) {
|
||||||
val userIds = JSONArray()
|
val userIds = JSONArray()
|
||||||
val reMention = Pattern.compile("(?:\\A|\\s)@([a-zA-Z0-9_]{1,20})(?:@([\\w.:-]+))?(?:\\z|\\s)")
|
val reMention =
|
||||||
|
Pattern.compile("(?:\\A|\\s)@([a-zA-Z0-9_]{1,20})(?:@([\\w.:-]+))?(?:\\z|\\s)")
|
||||||
val m = reMention.matcher(content)
|
val m = reMention.matcher(content)
|
||||||
while(m.find()){
|
while(m.find()) {
|
||||||
val username = m.group(1)
|
val username = m.group(1)
|
||||||
val host = m.group(2)
|
val host = m.group(2)
|
||||||
val queryParams = account.putMisskeyApiToken(JSONObject())
|
val queryParams = account.putMisskeyApiToken(JSONObject())
|
||||||
if(username?.isNotEmpty()==true) queryParams.put("username",username)
|
if(username?.isNotEmpty() == true) queryParams.put(
|
||||||
if(host?.isNotEmpty()==true) queryParams.put("host",host)
|
"username",
|
||||||
result = client.request("/api/users/show",queryParams.toPostRequestBuilder())
|
username
|
||||||
|
)
|
||||||
|
if(host?.isNotEmpty() == true) queryParams.put("host", host)
|
||||||
|
result = client.request(
|
||||||
|
"/api/users/show",
|
||||||
|
queryParams.toPostRequestBuilder()
|
||||||
|
)
|
||||||
val id = result?.jsonObject?.parseString("id")
|
val id = result?.jsonObject?.parseString("id")
|
||||||
if( id?.isNotEmpty() == true ){
|
if(id?.isNotEmpty() == true) {
|
||||||
userIds.put( id)
|
userIds.put(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
json.put("visibility",if( userIds.length() == 0 ){
|
json.put(
|
||||||
"private"
|
"visibility", if(userIds.length() == 0) {
|
||||||
}else{
|
"private"
|
||||||
json.put("visibleUserIds",userIds)
|
} else {
|
||||||
"specified"
|
json.put("visibleUserIds", userIds)
|
||||||
})
|
"specified"
|
||||||
}else {
|
}
|
||||||
json.put("visibility",visibility_checked.strMisskey)
|
)
|
||||||
|
} else {
|
||||||
|
json.put("visibility", visibility_checked.strMisskey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(spoiler_text?.isNotEmpty() == true ) {
|
if(spoiler_text?.isNotEmpty() == true) {
|
||||||
json.put(
|
json.put(
|
||||||
"cw",
|
"cw",
|
||||||
EmojiDecoder.decodeShortCode(
|
EmojiDecoder.decodeShortCode(
|
||||||
|
@ -349,7 +361,7 @@ class PostHelper(
|
||||||
json.put("replyId", in_reply_to_id.toString())
|
json.put("replyId", in_reply_to_id.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
json.put("viaMobile",true)
|
json.put("viaMobile", true)
|
||||||
|
|
||||||
if(attachment_list != null) {
|
if(attachment_list != null) {
|
||||||
val array = JSONArray()
|
val array = JSONArray()
|
||||||
|
@ -359,31 +371,34 @@ class PostHelper(
|
||||||
array.put(a.id.toString())
|
array.put(a.id.toString())
|
||||||
|
|
||||||
// Misskeyの場合、NSFWするにはアップロード済みの画像を drive/files/update で更新する
|
// Misskeyの場合、NSFWするにはアップロード済みの画像を drive/files/update で更新する
|
||||||
if( bNSFW){
|
if(bNSFW) {
|
||||||
val params = account.putMisskeyApiToken(JSONObject())
|
val params = account.putMisskeyApiToken(JSONObject())
|
||||||
.put("fileId",a.id.toString())
|
.put("fileId", a.id.toString())
|
||||||
.put("isSensitive",true)
|
.put("isSensitive", true)
|
||||||
val r = client.request("/api/drive/files/update",params.toPostRequestBuilder())
|
val r = client.request(
|
||||||
if(r==null|| r.error!=null ) return r
|
"/api/drive/files/update",
|
||||||
|
params.toPostRequestBuilder()
|
||||||
|
)
|
||||||
|
if(r == null || r.error != null) return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( array.length() > 0) json.put("mediaIds", array)
|
if(array.length() > 0) json.put("mediaIds", array)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(enquete_items?.isNotEmpty() == true) {
|
if(enquete_items?.isNotEmpty() == true) {
|
||||||
val choices = JSONArray().apply {
|
val choices = JSONArray().apply {
|
||||||
for(item in enquete_items) {
|
for(item in enquete_items) {
|
||||||
val text =EmojiDecoder.decodeShortCode(
|
val text = EmojiDecoder.decodeShortCode(
|
||||||
item,
|
item,
|
||||||
emojiMapCustom = emojiMapCustom
|
emojiMapCustom = emojiMapCustom
|
||||||
)
|
)
|
||||||
if( text.isEmpty() ) continue
|
if(text.isEmpty()) continue
|
||||||
put(text)
|
put(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( choices.length() > 0 ) {
|
if(choices.length() > 0) {
|
||||||
json.put("poll",JSONObject().apply {
|
json.put("poll", JSONObject().apply {
|
||||||
put("choices",choices)
|
put("choices", choices)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,19 +468,21 @@ class PostHelper(
|
||||||
val digest = (body_string + account.acct).digestSHA256Hex()
|
val digest = (body_string + account.acct).digestSHA256Hex()
|
||||||
request_builder.header("Idempotency-Key", digest)
|
request_builder.header("Idempotency-Key", digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = if(isMisskey){
|
result = if(isMisskey) {
|
||||||
client.request("/api/notes/create", request_builder)
|
client.request("/api/notes/create", request_builder)
|
||||||
// TODO {"error":{}} が返ってきた時にどう扱えばいい?
|
// TODO {"error":{}} が返ってきた時にどう扱えばいい?
|
||||||
}else{
|
} else {
|
||||||
client.request("/api/v1/statuses", request_builder)
|
client.request("/api/v1/statuses", request_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
val status = parser.status(if(isMisskey) {
|
val status = parser.status(
|
||||||
result?.jsonObject?.optJSONObject("createdNote") ?: result?.jsonObject
|
if(isMisskey) {
|
||||||
}else{
|
result?.jsonObject?.optJSONObject("createdNote") ?: result?.jsonObject
|
||||||
result?.jsonObject
|
} else {
|
||||||
})
|
result?.jsonObject
|
||||||
|
}
|
||||||
|
)
|
||||||
this.status = status
|
this.status = status
|
||||||
if(status != null) {
|
if(status != null) {
|
||||||
|
|
||||||
|
@ -664,18 +681,21 @@ class PostHelper(
|
||||||
et, last_colon, end, null, picker_caption_emoji, open_picker_emoji
|
et, last_colon, end, null, picker_caption_emoji, open_picker_emoji
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// 絵文字を部分一致で検索
|
|
||||||
|
val code_list = ArrayList<CharSequence>()
|
||||||
val limit = 100
|
val limit = 100
|
||||||
val s = src.substring(last_colon + 1, end).toLowerCase().replace('-', '_')
|
|
||||||
val code_list = EmojiDecoder.searchShortCode(activity, s, limit)
|
|
||||||
log.d("checkEmoji: search for %s, result=%d", s, code_list.size)
|
|
||||||
|
|
||||||
// カスタム絵文字を検索
|
// カスタム絵文字を検索
|
||||||
val instance = this@PostHelper.instance
|
val instance = this@PostHelper.instance
|
||||||
if(instance != null && instance.isNotEmpty() ) {
|
if(instance != null && instance.isNotEmpty()) {
|
||||||
val custom_list = App1.custom_emoji_lister.getList(instance,isMisskey, onEmojiListLoad)
|
val custom_list = App1.custom_emoji_lister.getListWithAliases(
|
||||||
|
instance,
|
||||||
|
isMisskey,
|
||||||
|
onEmojiListLoad
|
||||||
|
)
|
||||||
if(custom_list != null) {
|
if(custom_list != null) {
|
||||||
val needle = src.substring(last_colon + 1, end)
|
val needle = src.substring(last_colon + 1, end)
|
||||||
|
|
||||||
for(item in custom_list) {
|
for(item in custom_list) {
|
||||||
if(code_list.size >= limit) break
|
if(code_list.size >= limit) break
|
||||||
if(! item.shortcode.contains(needle)) continue
|
if(! item.shortcode.contains(needle)) continue
|
||||||
|
@ -689,14 +709,43 @@ class PostHelper(
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
)
|
)
|
||||||
sb.append(' ')
|
sb.append(' ')
|
||||||
|
if(item.alias != null) {
|
||||||
|
val start = sb.length
|
||||||
|
sb.append(":")
|
||||||
|
sb.append(item.alias)
|
||||||
|
sb.append(": → ")
|
||||||
|
sb.setSpan(
|
||||||
|
ForegroundColorSpan(
|
||||||
|
Styler.getAttributeColor(
|
||||||
|
activity,
|
||||||
|
R.attr.colorTimeSmall
|
||||||
|
)
|
||||||
|
),
|
||||||
|
start,
|
||||||
|
sb.length,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
sb.append(':')
|
sb.append(':')
|
||||||
sb.append(item.shortcode)
|
sb.append(item.shortcode)
|
||||||
sb.append(':')
|
sb.append(':')
|
||||||
|
|
||||||
code_list.add(sb)
|
code_list.add(sb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通常の絵文字を部分一致で検索
|
||||||
|
val remain = limit - code_list.size
|
||||||
|
if(remain > 0) {
|
||||||
|
val s = src.substring(last_colon + 1, end).toLowerCase().replace('-', '_')
|
||||||
|
val src = EmojiDecoder.searchShortCode(activity, s, remain)
|
||||||
|
log.d("checkEmoji: search for %s, result=%d", s, src.size)
|
||||||
|
code_list.addAll(src)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
openPopup()?.setList(
|
openPopup()?.setList(
|
||||||
et,
|
et,
|
||||||
last_colon,
|
last_colon,
|
||||||
|
@ -731,8 +780,8 @@ class PostHelper(
|
||||||
this.instance = instance
|
this.instance = instance
|
||||||
this.isMisskey = isMisskey
|
this.isMisskey = isMisskey
|
||||||
|
|
||||||
if(instance != null ) {
|
if(instance != null) {
|
||||||
App1.custom_emoji_lister.getList(instance, isMisskey,onEmojiListLoad)
|
App1.custom_emoji_lister.getList(instance, isMisskey, onEmojiListLoad)
|
||||||
}
|
}
|
||||||
|
|
||||||
val popup = this.popup
|
val popup = this.popup
|
||||||
|
@ -841,7 +890,7 @@ class PostHelper(
|
||||||
.appendEmoji(name, instance, bInstanceHasCustomEmoji)
|
.appendEmoji(name, instance, bInstanceHasCustomEmoji)
|
||||||
|
|
||||||
val newSelection = sb.length
|
val newSelection = sb.length
|
||||||
if(end < src_length) sb.append(src.subSequence(end, src_length) )
|
if(end < src_length) sb.append(src.subSequence(end, src_length))
|
||||||
|
|
||||||
et.text = sb
|
et.text = sb
|
||||||
et.setSelection(newSelection)
|
et.setSelection(newSelection)
|
||||||
|
@ -864,11 +913,11 @@ class PostHelper(
|
||||||
val end = Math.min(src_length, et.selectionEnd)
|
val end = Math.min(src_length, et.selectionEnd)
|
||||||
|
|
||||||
val sb = SpannableStringBuilder()
|
val sb = SpannableStringBuilder()
|
||||||
.append(src.subSequence(0, start) )
|
.append(src.subSequence(0, start))
|
||||||
.appendEmoji(name, instance, bInstanceHasCustomEmoji)
|
.appendEmoji(name, instance, bInstanceHasCustomEmoji)
|
||||||
|
|
||||||
val newSelection = sb.length
|
val newSelection = sb.length
|
||||||
if(end < src_length) sb.append(src.subSequence(end, src_length) )
|
if(end < src_length) sb.append(src.subSequence(end, src_length))
|
||||||
|
|
||||||
et.text = sb
|
et.text = sb
|
||||||
et.setSelection(newSelection)
|
et.setSelection(newSelection)
|
||||||
|
|
Loading…
Reference in New Issue