diff --git a/app/build.gradle b/app/build.gradle index eed689f9..ecb2055f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -137,9 +137,14 @@ dependencies { implementation project(':emoji') implementation project(':apng_android') - implementation "androidx.appcompat:appcompat:$appcompat_version" + def emojiVersion = "1.0.0-rc01" + implementation "androidx.emoji2:emoji2:$emojiVersion" + implementation "androidx.emoji2:emoji2-bundled:$emojiVersion" + implementation "androidx.emoji2:emoji2-views:$emojiVersion" + implementation "androidx.emoji2:emoji2-views-helper:$emojiVersion" + // DrawerLayout implementation "androidx.drawerlayout:drawerlayout:1.1.1" @@ -157,7 +162,7 @@ dependencies { // Recyclerview implementation "androidx.recyclerview:recyclerview:1.2.1" - kapt 'androidx.annotation:annotation:1.2.0' + kapt 'androidx.annotation:annotation:1.3.0' // https://firebase.google.com/support/release-notes/android implementation "com.google.firebase:firebase-messaging:23.0.0" @@ -228,7 +233,7 @@ dependencies { implementation 'com.astuetz:pagerslidingtabstrip:1.0.1' - implementation 'com.google.android.exoplayer:exoplayer:2.15.1' + implementation 'com.google.android.exoplayer:exoplayer:2.16.0' /* WARNING: [Processor] Library '…\exoplayer-ui-2.12.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway. Example of androidX reference: 'androidx/core/app/NotificationCompat$Builder' diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt b/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt index e5e9d66f..02791d69 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt @@ -343,7 +343,7 @@ class ActMain : AppCompatActivity(), density = appState.density completionHelper = CompletionHelper(this, pref, appState.handler) - EmojiDecoder.handleUnicodeEmoji = PrefB.bpInAppUnicodeEmoji(pref) + EmojiDecoder.useTwemoji = PrefB.bpUseTwemoji(pref) acctPadLr = (0.5f + 4f * density).toInt() reloadTextSize() diff --git a/app/src/main/java/jp/juggler/subwaytooter/Styler.kt b/app/src/main/java/jp/juggler/subwaytooter/Styler.kt index 685054a3..243a6395 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Styler.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/Styler.kt @@ -12,9 +12,10 @@ import android.widget.ImageButton import android.widget.ImageView import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat -import jp.juggler.subwaytooter.emoji.EmojiMap import jp.juggler.subwaytooter.api.entity.TootAccount import jp.juggler.subwaytooter.api.entity.TootVisibility +import jp.juggler.subwaytooter.emoji.EmojiMap +import jp.juggler.subwaytooter.pref.PrefB import jp.juggler.subwaytooter.pref.PrefI import jp.juggler.subwaytooter.pref.pref import jp.juggler.subwaytooter.span.EmojiImageSpan @@ -384,14 +385,24 @@ fun SpannableStringBuilder.appendMisskeyReaction( emojiUtf16: String, text: String ): SpannableStringBuilder { - val start = this.length - this.append(text) - val end = this.length - this.setSpan( - EmojiMap.unicodeMap[emojiUtf16]!!.createSpan(context), - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ) + val emoji = EmojiMap.unicodeMap[emojiUtf16] + when { + emoji == null -> + append("text") + + PrefB.bpUseTwemoji(context) -> { + val start = this.length + append(text) + val end = this.length + this.setSpan( + emoji.createSpan(context), + start, end, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + else -> + this.append(emoji.unifiedCode) + } return this } diff --git a/app/src/main/java/jp/juggler/subwaytooter/appsetting/AppSettingItem.kt b/app/src/main/java/jp/juggler/subwaytooter/appsetting/AppSettingItem.kt index e085e19d..e174da2f 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/appsetting/AppSettingItem.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/appsetting/AppSettingItem.kt @@ -784,7 +784,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett sw(PrefB.bpEmojioneShortcode, R.string.emojione_shortcode_support) { desc = R.string.emojione_shortcode_support_desc } - sw(PrefB.bpInAppUnicodeEmoji, R.string.in_app_unicode_emoji) + sw(PrefB.bpUseTwemoji, R.string.use_twemoji_emoji) sw(PrefB.bpKeepReactionSpace, R.string.keep_reaction_space) } diff --git a/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ViewHolderHeaderProfile.kt b/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ViewHolderHeaderProfile.kt index b144e67e..95810cdb 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ViewHolderHeaderProfile.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ViewHolderHeaderProfile.kt @@ -568,39 +568,50 @@ internal class ViewHolderHeaderProfile( } } - private fun encodeAcctText(who: TootAccount, whoDetail: TootAccount?) = SpannableStringBuilder().apply { - append("@") - append(accessInfo.getFullAcct(who).pretty) - if (whoDetail?.locked ?: who.locked) { - append(" ") - val emoji = EmojiMap.shortNameMap["lock"] - if (emoji != null) { - appendSpan("locked", emoji.createSpan(activity)) - } else { - append("locked") - } - } + private fun encodeAcctText(who: TootAccount, whoDetail: TootAccount?) = + SpannableStringBuilder().apply { + append("@") + append(accessInfo.getFullAcct(who).pretty) + if (whoDetail?.locked ?: who.locked) { + append(" ") + val emoji = EmojiMap.shortNameMap["lock"] + when { + emoji == null -> + append("locked") + PrefB.bpUseTwemoji(App1.pref) -> + appendSpan("locked", emoji.createSpan(activity)) + else -> + append(emoji.unifiedCode) + } - if (who.bot) { - append(" ") - val emoji = EmojiMap.shortNameMap["robot_face"] - if (emoji != null) { - appendSpan("bot", emoji.createSpan(activity)) - } else { - append("bot") } - } - if (who.suspended) { - append(" ") - val emoji = EmojiMap.shortNameMap["cross_mark"] - if (emoji != null) { - appendSpan("suspended", emoji.createSpan(activity)) - } else { - append("suspended") + if (who.bot) { + append(" ") + val emoji = EmojiMap.shortNameMap["robot_face"] + when { + emoji == null -> + append("bot") + PrefB.bpUseTwemoji(App1.pref) -> + appendSpan("bot", emoji.createSpan(activity)) + else -> + append(emoji.unifiedCode) + } + } + + if (who.suspended) { + append(" ") + val emoji = EmojiMap.shortNameMap["cross_mark"] + when { + emoji == null -> + append("suspended") + PrefB.bpUseTwemoji(App1.pref) -> + appendSpan("suspended", emoji.createSpan(activity)) + else -> + append(emoji.unifiedCode) + } } } - } private fun encodeMisskeyExtra(whoDetail: TootAccount?) = SpannableStringBuilder().apply { var s = whoDetail?.location diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/EmojiPicker.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/EmojiPicker.kt index 1ac23440..379bc127 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/dialog/EmojiPicker.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/EmojiPicker.kt @@ -6,6 +6,7 @@ import android.app.Dialog import android.graphics.Typeface import android.graphics.drawable.PictureDrawable import android.util.SparseArray +import android.util.TypedValue import android.view.* import android.widget.* import androidx.annotation.StringRes @@ -463,8 +464,13 @@ class EmojiPicker( val view: View val item = page.emojiList[position] var unicodeEmoji = item.unicodeEmoji - if (unicodeEmoji != null) { - + if (unicodeEmoji == null) { + view = viewOld ?: NetworkEmojiView(activity).apply { + layoutParams = AbsListView.LayoutParams(wh, wh) + } + view.setTag(R.id.btnAbout, item) + (view as? NetworkEmojiView)?.setEmoji(customEmojiMap[item.name]?.url) + } else if(PrefB.bpUseTwemoji(App1.pref)){ view = viewOld ?: ImageView(activity).apply { layoutParams = AbsListView.LayoutParams(wh, wh) @@ -486,12 +492,22 @@ class EmojiPicker( .into(view) } } - } else { - view = viewOld ?: NetworkEmojiView(activity).apply { - layoutParams = AbsListView.LayoutParams(wh, wh) - } + }else{ + view = viewOld + ?: TextView(activity).apply { + layoutParams = AbsListView.LayoutParams(wh, wh) + } + view.setTag(R.id.btnAbout, item) - (view as? NetworkEmojiView)?.setEmoji(customEmojiMap[item.name]?.url) + + if (view is TextView && view.activity?.isDestroyed == false) { + if (page.hasSkinTone) unicodeEmoji = applySkinTone(unicodeEmoji) + + view.text = unicodeEmoji.unifiedCode + view.gravity = Gravity.CENTER + view.setLineSpacing(0f,0f) + view.setTextSize(TypedValue.COMPLEX_UNIT_PX, wh.toFloat()*0.7f) + } } return view diff --git a/app/src/main/java/jp/juggler/subwaytooter/pref/PrefB.kt b/app/src/main/java/jp/juggler/subwaytooter/pref/PrefB.kt index 5676065b..fa8378de 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/pref/PrefB.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/pref/PrefB.kt @@ -319,9 +319,9 @@ object PrefB { false ) - val bpInAppUnicodeEmoji = BooleanPref( - "InAppUnicodeEmoji", - true + val bpUseTwemoji = BooleanPref( + "UseTwemoji", + false ) val bpKeepReactionSpace = BooleanPref( @@ -347,4 +347,4 @@ object PrefB { "MfmDecorationShowUnsupportedMarkup", true ) -} \ No newline at end of file +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/span/SvgEmojiSpan.kt b/app/src/main/java/jp/juggler/subwaytooter/span/SvgEmojiSpan.kt index ad510e88..14fcb527 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/span/SvgEmojiSpan.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/span/SvgEmojiSpan.kt @@ -8,14 +8,16 @@ import android.text.style.ReplacementSpan import androidx.annotation.IntRange import com.caverock.androidsvg.SVG import jp.juggler.subwaytooter.emoji.UnicodeEmoji +import jp.juggler.subwaytooter.pref.PrefB import jp.juggler.util.LogCategory // 絵文字リソースの種類によって異なるスパンを作る -fun UnicodeEmoji.createSpan(context: Context, scale: Float = 1f) = if (isSvg) { - SvgEmojiSpan(context, assetsName!!, scale = scale) -} else { - EmojiImageSpan(context, drawableId, scale = scale) -} +fun UnicodeEmoji.createSpan(context: Context, scale: Float = 1f) = + if (isSvg) { + SvgEmojiSpan(context, assetsName!!, scale = scale) + } else { + EmojiImageSpan(context, drawableId, scale = scale) + } // SVG絵文字スパン class SvgEmojiSpan internal constructor( diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt b/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt index ba04279c..94304ae9 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt @@ -7,11 +7,11 @@ import android.text.Spanned import android.util.SparseBooleanArray import androidx.annotation.DrawableRes import jp.juggler.subwaytooter.App1 -import jp.juggler.subwaytooter.pref.PrefB import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.emoji.CustomEmoji import jp.juggler.subwaytooter.emoji.EmojiMap import jp.juggler.subwaytooter.emoji.UnicodeEmoji +import jp.juggler.subwaytooter.pref.PrefB import jp.juggler.subwaytooter.pref.pref import jp.juggler.subwaytooter.span.EmojiImageSpan import jp.juggler.subwaytooter.span.HighlightSpan @@ -32,13 +32,14 @@ object EmojiDecoder { private const val cpZwsp = '\u200B'.code - var handleUnicodeEmoji = true + var useTwemoji = true - fun customEmojiSeparator(pref: SharedPreferences) = if (PrefB.bpCustomEmojiSeparatorZwsp(pref)) { - '\u200B' - } else { - ' ' - } + fun customEmojiSeparator(pref: SharedPreferences) = + if (PrefB.bpCustomEmojiSeparatorZwsp(pref)) { + '\u200B' + } else { + ' ' + } // タンス側が落ち着いたら [^[:almun:]_] から [:space:]に切り替える // private fun isHeadOrAfterWhitespace( s:CharSequence,index:Int):Boolean { @@ -168,26 +169,33 @@ object EmojiDecoder { fun addImageSpan(text: String, emoji: UnicodeEmoji) { val context = options.context - if (context == null) { - openNormalText() - sb.append(text) - } else { - closeNormalText() - val start = sb.length - sb.append(text) - val end = sb.length - sb.setSpan( - emoji.createSpan(context, scale = options.enlargeEmoji), - start, - end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ) + when { + context == null -> { + openNormalText() + sb.append(text) + } + PrefB.bpUseTwemoji(context) -> { + closeNormalText() + val start = sb.length + sb.append(text) + val end = sb.length + sb.setSpan( + emoji.createSpan(context, scale = options.enlargeEmoji), + start, + end, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + else -> { + openNormalText() + sb.append(emoji.unifiedCode) + } } } fun addUnicodeString(s: String) { - if (!handleUnicodeEmoji) { + if (!useTwemoji) { openNormalText() sb.append(s) return @@ -466,16 +474,21 @@ object EmojiDecoder { val emoji = EmojiMap.shortNameMap[shortCode] ?: continue val sb = SpannableStringBuilder() - val start = 0 - sb.append(' ') - val end = sb.length - sb.setSpan( - emoji.createSpan(context), - start, - end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ) + if(PrefB.bpUseTwemoji(context)){ + val start = 0 + sb.append(' ') + val end = sb.length + + sb.setSpan( + emoji.createSpan(context), + start, + end, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + }else{ + sb.append(emoji.unifiedCode) + } sb.append(' ') .append(':') diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 940688d0..125b2571 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1101,4 +1101,5 @@ (Misskey)未対応のマークアップを表示する 添付メディアの説明文を表示する 背景パターン + Twemoji絵文字を使う diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7df43b84..82c2b1c9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1112,4 +1112,5 @@ (Misskey)Show unsupported markups Show media description Background pattern + Use Twemoji emoji diff --git a/build.gradle b/build.gradle index c8d63227..e75974b8 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext.target_sdk_version = 31 ext.compile_sdk_version = 31 - ext.appcompat_version = '1.3.1' + ext.appcompat_version = '1.4.0-rc01' ext.lifecycle_version = "2.4.0" ext.arch_version = "2.1.0"