New emoji picker (#2395)
* Update to Emoji2 * Hopefully fix the emoji picker preference * Switch to released Filemojicompat version * Filemojicompat version as an own var * Remove an unused import * Small cleanup * Correct onDisplayPreferenceDialog; test TuskyApplication * Use TextViews instead of EmojiTextViews * Recreate the Main Activity if the emoji pack is updated * Enable coreLibraryDesugaring (for Java Streams); update Filemojicompat, downgrade Emoji2 * Update emoji font versions to 14 * Use FilemojiCompat 3.2.0-beta01 * Make ktLint happy again * Remove coreLibraryDesugaring and a FIXME * Use EmojiPickerPreference.get() * Disable emoji pack import * Update FilemojiCompat to Beta 2 * Update FilemojiCompat to Beta 3 * Update FilemojiCompat to Beta 3.2.0 final * Update FilemojiCompat to 3.2.1
This commit is contained in:
parent
2fcd6fdc14
commit
f15b3e61bb
32 changed files with 109 additions and 782 deletions
|
@ -37,7 +37,7 @@ import androidx.core.view.WindowCompat
|
|||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsCompat.Type.systemBars
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji2.text.EmojiCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.viewpager2.widget.MarginPageTransformer
|
||||
|
|
|
@ -26,7 +26,7 @@ import androidx.core.view.OnReceiveContentListener
|
|||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.emoji.widget.EmojiEditTextHelper
|
||||
import androidx.emoji2.viewsintegration.EmojiEditTextHelper
|
||||
|
||||
class EditTextTyped @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
|
|
@ -1,240 +0,0 @@
|
|||
package com.keylesspalace.tusky.components.preference
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RadioButton
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.SplashActivity
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.databinding.DialogEmojicompatBinding
|
||||
import com.keylesspalace.tusky.databinding.ItemEmojiPrefBinding
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont.Companion.BLOBMOJI
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont.Companion.FONTS
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont.Companion.NOTOEMOJI
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont.Companion.SYSTEM_DEFAULT
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont.Companion.TWEMOJI
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.show
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import okhttp3.OkHttpClient
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* This Preference lets the user select their preferred emoji font
|
||||
*/
|
||||
class EmojiPreference(
|
||||
context: Context,
|
||||
private val okHttpClient: OkHttpClient
|
||||
) : Preference(context) {
|
||||
|
||||
private lateinit var selected: EmojiCompatFont
|
||||
private lateinit var original: EmojiCompatFont
|
||||
private val radioButtons = mutableListOf<RadioButton>()
|
||||
private var updated = false
|
||||
private var currentNeedsUpdate = false
|
||||
|
||||
private val downloadDisposables = MutableList<Disposable?>(FONTS.size) { null }
|
||||
|
||||
override fun onAttachedToHierarchy(preferenceManager: PreferenceManager) {
|
||||
super.onAttachedToHierarchy(preferenceManager)
|
||||
|
||||
// Find out which font is currently active
|
||||
selected = EmojiCompatFont.byId(
|
||||
PreferenceManager.getDefaultSharedPreferences(context).getInt(key, 0)
|
||||
)
|
||||
// We'll use this later to determine if anything has changed
|
||||
original = selected
|
||||
summary = selected.getDisplay(context)
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
val binding = DialogEmojicompatBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
setupItem(BLOBMOJI, binding.itemBlobmoji)
|
||||
setupItem(TWEMOJI, binding.itemTwemoji)
|
||||
setupItem(NOTOEMOJI, binding.itemNotoemoji)
|
||||
setupItem(SYSTEM_DEFAULT, binding.itemNomoji)
|
||||
|
||||
AlertDialog.Builder(context)
|
||||
.setView(binding.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> onDialogOk() }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun setupItem(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
|
||||
// Initialize all the views
|
||||
binding.emojiName.text = font.getDisplay(context)
|
||||
binding.emojiCaption.setText(font.caption)
|
||||
binding.emojiThumbnail.setImageResource(font.img)
|
||||
|
||||
// There needs to be a list of all the radio buttons in order to uncheck them when one is selected
|
||||
radioButtons.add(binding.emojiRadioButton)
|
||||
updateItem(font, binding)
|
||||
|
||||
// Set actions
|
||||
binding.emojiDownload.setOnClickListener { startDownload(font, binding) }
|
||||
binding.emojiDownloadCancel.setOnClickListener { cancelDownload(font, binding) }
|
||||
binding.emojiRadioButton.setOnClickListener { radioButton: View -> select(font, radioButton as RadioButton) }
|
||||
binding.root.setOnClickListener {
|
||||
select(font, binding.emojiRadioButton)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startDownload(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
|
||||
// Switch to downloading style
|
||||
binding.emojiDownload.hide()
|
||||
binding.emojiCaption.visibility = View.INVISIBLE
|
||||
binding.emojiProgress.show()
|
||||
binding.emojiProgress.progress = 0
|
||||
binding.emojiDownloadCancel.show()
|
||||
font.downloadFontFile(context, okHttpClient)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ progress ->
|
||||
// The progress is returned as a float between 0 and 1, or -1 if it could not determined
|
||||
if (progress >= 0) {
|
||||
binding.emojiProgress.isIndeterminate = false
|
||||
val max = binding.emojiProgress.max.toFloat()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
binding.emojiProgress.setProgress((max * progress).toInt(), true)
|
||||
} else {
|
||||
binding.emojiProgress.progress = (max * progress).toInt()
|
||||
}
|
||||
} else {
|
||||
binding.emojiProgress.isIndeterminate = true
|
||||
}
|
||||
},
|
||||
{
|
||||
Toast.makeText(context, R.string.download_failed, Toast.LENGTH_SHORT).show()
|
||||
updateItem(font, binding)
|
||||
},
|
||||
{
|
||||
finishDownload(font, binding)
|
||||
}
|
||||
).also { downloadDisposables[font.id] = it }
|
||||
}
|
||||
|
||||
private fun cancelDownload(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
|
||||
font.deleteDownloadedFile(context)
|
||||
downloadDisposables[font.id]?.dispose()
|
||||
downloadDisposables[font.id] = null
|
||||
updateItem(font, binding)
|
||||
}
|
||||
|
||||
private fun finishDownload(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
|
||||
select(font, binding.emojiRadioButton)
|
||||
updateItem(font, binding)
|
||||
// Set the flag to restart the app (because an update has been downloaded)
|
||||
if (selected === original && currentNeedsUpdate) {
|
||||
updated = true
|
||||
currentNeedsUpdate = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a font both visually and logically
|
||||
*
|
||||
* @param font The font to be selected
|
||||
* @param radio The radio button associated with it's visual item
|
||||
*/
|
||||
private fun select(font: EmojiCompatFont, radio: RadioButton) {
|
||||
selected = font
|
||||
radioButtons.forEach { radioButton ->
|
||||
radioButton.isChecked = radioButton == radio
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a "consistent" state is reached, i.e. it's not downloading the font
|
||||
*
|
||||
* @param font The font to be displayed
|
||||
* @param binding The ItemEmojiPrefBinding to show the item in
|
||||
*/
|
||||
private fun updateItem(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
|
||||
// There's no download going on
|
||||
binding.emojiProgress.hide()
|
||||
binding.emojiDownloadCancel.hide()
|
||||
binding.emojiCaption.show()
|
||||
if (font.isDownloaded(context)) {
|
||||
// Make it selectable
|
||||
binding.emojiDownload.hide()
|
||||
binding.emojiRadioButton.show()
|
||||
binding.root.isClickable = true
|
||||
} else {
|
||||
// Make it downloadable
|
||||
binding.emojiDownload.show()
|
||||
binding.emojiRadioButton.hide()
|
||||
binding.root.isClickable = false
|
||||
}
|
||||
|
||||
// Select it if necessary
|
||||
if (font === selected) {
|
||||
binding.emojiRadioButton.isChecked = true
|
||||
// Update available
|
||||
if (!font.isDownloaded(context)) {
|
||||
currentNeedsUpdate = true
|
||||
}
|
||||
} else {
|
||||
binding.emojiRadioButton.isChecked = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveSelectedFont() {
|
||||
val index = selected.id
|
||||
Log.i(TAG, "saveSelectedFont: Font ID: $index")
|
||||
PreferenceManager
|
||||
.getDefaultSharedPreferences(context)
|
||||
.edit()
|
||||
.putInt(key, index)
|
||||
.apply()
|
||||
summary = selected.getDisplay(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked ok -> save the selected font and offer to restart the app if something changed
|
||||
*/
|
||||
private fun onDialogOk() {
|
||||
saveSelectedFont()
|
||||
if (selected !== original || updated) {
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(R.string.restart_required)
|
||||
.setMessage(R.string.restart_emoji)
|
||||
.setNegativeButton(R.string.later, null)
|
||||
.setPositiveButton(R.string.restart) { _, _ ->
|
||||
// Restart the app
|
||||
// From https://stackoverflow.com/a/17166729/5070653
|
||||
val launchIntent = Intent(context, SplashActivity::class.java)
|
||||
val mPendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0x1f973, // This is the codepoint of the party face emoji :D
|
||||
launchIntent,
|
||||
NotificationHelper.pendingIntentFlags(false)
|
||||
)
|
||||
val mgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
mgr.set(
|
||||
AlarmManager.RTC,
|
||||
System.currentTimeMillis() + 100,
|
||||
mPendingIntent
|
||||
)
|
||||
exitProcess(0)
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "EmojiPreference"
|
||||
}
|
||||
}
|
|
@ -38,14 +38,11 @@ import com.mikepenz.iconics.IconicsDrawable
|
|||
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizePx
|
||||
import okhttp3.OkHttpClient
|
||||
import de.c1710.filemojicompat_ui.views.picker.preference.EmojiPickerPreference
|
||||
import javax.inject.Inject
|
||||
|
||||
class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
||||
|
||||
@Inject
|
||||
lateinit var okhttpclient: OkHttpClient
|
||||
|
||||
@Inject
|
||||
lateinit var accountManager: AccountManager
|
||||
|
||||
|
@ -65,11 +62,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
|||
icon = makeIcon(GoogleMaterial.Icon.gmd_palette)
|
||||
}
|
||||
|
||||
emojiPreference(okhttpclient) {
|
||||
setDefaultValue("system_default")
|
||||
setIcon(R.drawable.ic_emoji_24dp)
|
||||
key = PrefKeys.EMOJI
|
||||
setSummary(R.string.system_default)
|
||||
emojiPreference(requireActivity()) {
|
||||
setTitle(R.string.emoji_style)
|
||||
icon = makeIcon(GoogleMaterial.Icon.gmd_sentiment_satisfied)
|
||||
}
|
||||
|
@ -300,6 +293,12 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||
if (!EmojiPickerPreference.onDisplayPreferenceDialog(this, preference)) {
|
||||
super.onDisplayPreferenceDialog(preference)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): PreferencesFragment {
|
||||
return PreferencesFragment()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue