(マストドン2.4以降)アカウント表示名、ノート、フィールドのカスタム絵文字対応
This commit is contained in:
parent
36e2bf8e68
commit
3fc92b35f3
|
@ -12,8 +12,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
|
||||
versionCode 244
|
||||
versionName "2.4.4"
|
||||
versionCode 245
|
||||
versionName "2.4.5"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// https://stackoverflow.com/questions/47791227/java-lang-illegalstateexception-dex-archives-setting-dex-extension-only-for
|
||||
|
|
|
@ -799,8 +799,9 @@ class ActAccountSetting
|
|||
|
||||
val decodeOptions = DecodeOptions(
|
||||
context = this@ActAccountSetting,
|
||||
linkHelper = account,
|
||||
emojiMapProfile = src.profile_emojis,
|
||||
linkHelper = account
|
||||
emojiMapCustom = src.custom_emojis
|
||||
)
|
||||
|
||||
val display_name = src.display_name
|
||||
|
@ -828,59 +829,64 @@ class ActAccountSetting
|
|||
if(src.source?.fields != null) {
|
||||
val fields = src.source.fields
|
||||
listEtFieldName.forEachIndexed { i, et ->
|
||||
et.setText(
|
||||
decodeOptions.decodeEmoji(
|
||||
when {
|
||||
i >= fields.size -> ""
|
||||
else -> fields[i].first
|
||||
}
|
||||
)
|
||||
val text = decodeOptions.decodeEmoji(
|
||||
when {
|
||||
i >= fields.size -> ""
|
||||
else -> fields[i].first
|
||||
}
|
||||
)
|
||||
et.setText( text )
|
||||
et.isEnabled = true
|
||||
val invalidator = NetworkEmojiInvalidator(et.handler,et)
|
||||
invalidator.register(text)
|
||||
}
|
||||
|
||||
listEtFieldValue.forEachIndexed { i, et ->
|
||||
et.setText(
|
||||
decodeOptions.decodeEmoji(
|
||||
when {
|
||||
i >= fields.size -> ""
|
||||
else -> fields[i].second
|
||||
}
|
||||
)
|
||||
val text =decodeOptions.decodeEmoji(
|
||||
when {
|
||||
i >= fields.size -> ""
|
||||
else -> fields[i].second
|
||||
}
|
||||
)
|
||||
et.setText( text )
|
||||
et.isEnabled = true
|
||||
val invalidator = NetworkEmojiInvalidator(et.handler,et)
|
||||
invalidator.register(text)
|
||||
}
|
||||
|
||||
} else {
|
||||
val fields = src.fields
|
||||
|
||||
listEtFieldName.forEachIndexed { i, et ->
|
||||
et.setText(
|
||||
decodeOptions.decodeEmoji(
|
||||
when {
|
||||
fields == null || i >= fields.size -> ""
|
||||
else -> fields[i].first
|
||||
}
|
||||
)
|
||||
val text = decodeOptions.decodeEmoji(
|
||||
when {
|
||||
fields == null || i >= fields.size -> ""
|
||||
else -> fields[i].first
|
||||
}
|
||||
)
|
||||
et.setText(text)
|
||||
et.isEnabled = true
|
||||
val invalidator = NetworkEmojiInvalidator(et.handler,et)
|
||||
invalidator.register(text)
|
||||
}
|
||||
|
||||
listEtFieldValue.forEachIndexed { i, et ->
|
||||
et.text = decodeOptions.decodeHTML(
|
||||
val text = decodeOptions.decodeHTML(
|
||||
when {
|
||||
fields == null || i >= fields.size -> ""
|
||||
else -> fields[i].second
|
||||
}
|
||||
)
|
||||
et.text = text
|
||||
et.isEnabled = true
|
||||
val invalidator = NetworkEmojiInvalidator(et.handler,et)
|
||||
invalidator.register(text)
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
profile_busy = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun updateCredential(key : String, value : Any) {
|
||||
|
|
|
@ -231,7 +231,9 @@ internal class ViewHolderHeaderProfile(
|
|||
context = activity,
|
||||
decodeEmoji = true,
|
||||
linkHelper = access_info,
|
||||
short = true
|
||||
short = true,
|
||||
emojiMapCustom = who.custom_emojis,
|
||||
emojiMapProfile = who.profile_emojis
|
||||
)
|
||||
|
||||
val content_color = column.content_color
|
||||
|
@ -248,24 +250,31 @@ internal class ViewHolderHeaderProfile(
|
|||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val nameText = decodeOptions.decodeEmoji(item.first)
|
||||
val nameInvalidator = NetworkEmojiInvalidator(activity.handler, nameView)
|
||||
nameInvalidator.register(nameText)
|
||||
|
||||
nameLp.topMargin = (density * 6f).toInt()
|
||||
nameView.layoutParams = nameLp
|
||||
nameView.text = decodeOptions.decodeEmoji(item.first)
|
||||
nameView.text = nameText
|
||||
nameView.setTextColor(c)
|
||||
nameView.typeface = nameTypeface
|
||||
nameView.movementMethod = MyLinkMovementMethod
|
||||
llFields.addView(nameView)
|
||||
|
||||
//
|
||||
// 値の方はHTMLエンコードされている
|
||||
val valueView = MyTextView(activity)
|
||||
val valueLp = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val valueText = decodeOptions.decodeHTML(item.second)
|
||||
val valueInvalidator = NetworkEmojiInvalidator(activity.handler, valueView)
|
||||
valueInvalidator.register(valueText)
|
||||
|
||||
valueLp.startMargin = (density * 32f).toInt()
|
||||
valueView.layoutParams = valueLp
|
||||
valueView.text =
|
||||
decodeOptions.decodeHTML(item.second) // 値の方はHTML文字参照のエンコードが行われている
|
||||
valueView.text = valueText
|
||||
valueView.setTextColor(c)
|
||||
valueView.typeface = valueTypeface
|
||||
valueView.movementMethod = MyLinkMovementMethod
|
||||
|
|
|
@ -82,10 +82,13 @@ open class TootAccount(
|
|||
|
||||
val fields : ArrayList<Pair<String, String>>?
|
||||
|
||||
val custom_emojis : java.util.HashMap<String, CustomEmoji>?
|
||||
|
||||
init {
|
||||
var sv : String?
|
||||
|
||||
// 絵文字データは先に読んでおく
|
||||
this.custom_emojis = parseMapOrNull(::CustomEmoji, src.optJSONArray("emojis") )
|
||||
this.profile_emojis = parseMapOrNull(::NicoProfileEmoji, src.optJSONArray("profile_emojis"))
|
||||
|
||||
// 疑似アカウントにacctとusernameだけ
|
||||
|
@ -104,7 +107,9 @@ open class TootAccount(
|
|||
parser.linkHelper,
|
||||
short = true,
|
||||
decodeEmoji = true,
|
||||
emojiMapProfile = this.profile_emojis
|
||||
emojiMapProfile = this.profile_emojis,
|
||||
emojiMapCustom = this.custom_emojis,
|
||||
unwrapEmojiImageTag = true
|
||||
).decodeHTML(this.note)
|
||||
|
||||
this.source = parseSource(src.optJSONObject("source"))
|
||||
|
@ -218,7 +223,11 @@ open class TootAccount(
|
|||
val sv = reWhitespace.matcher(display_name).replaceAll(" ")
|
||||
|
||||
// decode emoji code
|
||||
return DecodeOptions(context, emojiMapProfile = profile_emojis).decodeEmoji(sv)
|
||||
return DecodeOptions(
|
||||
context,
|
||||
emojiMapProfile = profile_emojis,
|
||||
emojiMapCustom = custom_emojis
|
||||
).decodeEmoji(sv)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -19,7 +19,8 @@ class DecodeOptions(
|
|||
var linkTag : Any? = null,
|
||||
var emojiMapCustom : HashMap<String, CustomEmoji>? = null,
|
||||
var emojiMapProfile : HashMap<String, NicoProfileEmoji>? = null,
|
||||
var highlightTrie : WordTrieTree? = null
|
||||
var highlightTrie : WordTrieTree? = null,
|
||||
var unwrapEmojiImageTag :Boolean = false
|
||||
) {
|
||||
|
||||
internal fun isMediaAttachment(url : String?) : Boolean {
|
||||
|
|
|
@ -35,6 +35,8 @@ object HTMLDecoder {
|
|||
private val reTag = Pattern.compile("<(/?)(\\w+)")
|
||||
private val reTagEnd = Pattern.compile("(/?)>$")
|
||||
private val reHref = Pattern.compile("\\bhref=\"([^\"]*)\"")
|
||||
private val reAttribute = Pattern.compile("\\s+([A-Za-z0-9:_-]+)\\s*=([\"'])([^>]*?)\\2")
|
||||
private val reShortcode = Pattern.compile(":[A-Za-z0-9_-]+:")
|
||||
|
||||
private val block_tag : HashSet<String> by lazy {
|
||||
val set = HashSet<String>()
|
||||
|
@ -286,7 +288,24 @@ object HTMLDecoder {
|
|||
}
|
||||
|
||||
if("img" == tag) {
|
||||
sb_tmp.append("<img/>")
|
||||
var replaced = false
|
||||
if(options.unwrapEmojiImageTag) {
|
||||
val attrs = parseAttributes(text)
|
||||
val cssClass = attrs["class"]
|
||||
val title = attrs["title"]
|
||||
if(cssClass != null
|
||||
&& title != null
|
||||
&& cssClass.contains("emojione")
|
||||
&& reShortcode.matcher(title).find()
|
||||
) {
|
||||
replaced = true
|
||||
sb_tmp.append(options.decodeEmoji(title))
|
||||
}
|
||||
}
|
||||
|
||||
if(! replaced) {
|
||||
sb_tmp.append("<img/>")
|
||||
}
|
||||
} else {
|
||||
for(child in child_nodes) {
|
||||
child.encodeSpan(options, sb_tmp)
|
||||
|
@ -299,9 +318,9 @@ object HTMLDecoder {
|
|||
val start = sb.length
|
||||
|
||||
sb.append(
|
||||
encodeUrl(options,sb_tmp.toString(),href)
|
||||
encodeUrl(options, sb_tmp.toString(), href)
|
||||
)
|
||||
|
||||
|
||||
val end = sb.length
|
||||
|
||||
if(end > start) {
|
||||
|
@ -368,7 +387,6 @@ object HTMLDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun encodeUrl(
|
||||
options : DecodeOptions,
|
||||
display_url : String,
|
||||
|
@ -379,7 +397,7 @@ object HTMLDecoder {
|
|||
if(context == null || ! options.short) {
|
||||
return display_url
|
||||
}
|
||||
|
||||
|
||||
if(! display_url.startsWith("http")) {
|
||||
if(display_url.startsWith("@") && href != null && Pref.bpMentionFullAcct(App1.pref)) {
|
||||
// メンションをfull acct にする
|
||||
|
@ -392,9 +410,9 @@ object HTMLDecoder {
|
|||
return display_url
|
||||
}
|
||||
|
||||
|
||||
|
||||
if( options.isMediaAttachment(href)) {
|
||||
|
||||
if(options.isMediaAttachment(href)) {
|
||||
val sb = SpannableStringBuilder()
|
||||
sb.append(href)
|
||||
val start = 0
|
||||
|
@ -431,7 +449,19 @@ object HTMLDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
fun decodeHTML( options : DecodeOptions, src : String? ) : SpannableStringBuilder {
|
||||
// split attributes
|
||||
private fun parseAttributes(text : String) : HashMap<String, String> {
|
||||
val dst = HashMap<String, String>()
|
||||
val m = reAttribute.matcher(text)
|
||||
while(m.find()) {
|
||||
val name = m.group(1).toLowerCase()
|
||||
val value = decodeEntity(m.group(3))
|
||||
dst[name] = value
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
fun decodeHTML(options : DecodeOptions, src : String?) : SpannableStringBuilder {
|
||||
|
||||
val sb = SpannableStringBuilder()
|
||||
|
||||
|
|
Loading…
Reference in New Issue