migrating to ViewBinding part 3: EmojiPreference (#2094)

This commit is contained in:
Konrad Pozniak 2021-03-07 19:06:05 +01:00 committed by GitHub
parent ff69a2ad0d
commit 22bed19d90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 103 deletions

View File

@ -8,14 +8,23 @@ import android.os.Build
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.* import android.widget.RadioButton
import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.SplashActivity import com.keylesspalace.tusky.SplashActivity
import com.keylesspalace.tusky.databinding.DialogEmojicompatBinding
import com.keylesspalace.tusky.databinding.ItemEmojiPrefBinding
import com.keylesspalace.tusky.util.EmojiCompatFont 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.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.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -50,94 +59,85 @@ class EmojiPreference(
} }
override fun onClick() { override fun onClick() {
val view = LayoutInflater.from(context).inflate(R.layout.dialog_emojicompat, null) val binding = DialogEmojicompatBinding.inflate(LayoutInflater.from(context))
viewIds.forEachIndexed { index, viewId ->
setupItem(view.findViewById(viewId), FONTS[index]) setupItem(BLOBMOJI, binding.itemBlobmoji)
} setupItem(TWEMOJI, binding.itemTwemoji)
setupItem(NOTOEMOJI, binding.itemNotoemoji)
setupItem(SYSTEM_DEFAULT, binding.itemNomoji)
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setView(view) .setView(binding.root)
.setPositiveButton(android.R.string.ok) { _, _ -> onDialogOk() } .setPositiveButton(android.R.string.ok) { _, _ -> onDialogOk() }
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.show() .show()
} }
private fun setupItem(container: View, font: EmojiCompatFont) { private fun setupItem(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
val title: TextView = container.findViewById(R.id.emojicompat_name)
val caption: TextView = container.findViewById(R.id.emojicompat_caption)
val thumb: ImageView = container.findViewById(R.id.emojicompat_thumb)
val download: ImageButton = container.findViewById(R.id.emojicompat_download)
val cancel: ImageButton = container.findViewById(R.id.emojicompat_download_cancel)
val radio: RadioButton = container.findViewById(R.id.emojicompat_radio)
// Initialize all the views // Initialize all the views
title.text = font.getDisplay(container.context) binding.emojiName.text = font.getDisplay(context)
caption.setText(font.caption) binding.emojiCaption.setText(font.caption)
thumb.setImageResource(font.img) 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 // There needs to be a list of all the radio buttons in order to uncheck them when one is selected
radioButtons.add(radio) radioButtons.add(binding.emojiRadioButton)
updateItem(font, container) updateItem(font, binding)
// Set actions // Set actions
download.setOnClickListener { startDownload(font, container) } binding.emojiDownload.setOnClickListener { startDownload(font, binding) }
cancel.setOnClickListener { cancelDownload(font, container) } binding.emojiDownloadCancel.setOnClickListener { cancelDownload(font, binding) }
radio.setOnClickListener { radioButton: View -> select(font, radioButton as RadioButton) } binding.emojiRadioButton.setOnClickListener { radioButton: View -> select(font, radioButton as RadioButton) }
container.setOnClickListener { containerView: View -> binding.root.setOnClickListener {
select(font, containerView.findViewById(R.id.emojicompat_radio)) select(font, binding.emojiRadioButton)
} }
} }
private fun startDownload(font: EmojiCompatFont, container: View) { private fun startDownload(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
val download: ImageButton = container.findViewById(R.id.emojicompat_download)
val caption: TextView = container.findViewById(R.id.emojicompat_caption)
val progressBar: ProgressBar = container.findViewById(R.id.emojicompat_progress)
val cancel: ImageButton = container.findViewById(R.id.emojicompat_download_cancel)
// Switch to downloading style // Switch to downloading style
download.visibility = View.GONE binding.emojiDownload.hide()
caption.visibility = View.INVISIBLE binding.emojiCaption.visibility = View.INVISIBLE
progressBar.visibility = View.VISIBLE binding.emojiProgress.show()
progressBar.progress = 0 binding.emojiProgress.progress = 0
cancel.visibility = View.VISIBLE binding.emojiDownloadCancel.show()
font.downloadFontFile(context, okHttpClient) font.downloadFontFile(context, okHttpClient)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
{ progress -> { progress ->
// The progress is returned as a float between 0 and 1, or -1 if it could not determined // The progress is returned as a float between 0 and 1, or -1 if it could not determined
if (progress >= 0) { if (progress >= 0) {
progressBar.isIndeterminate = false binding.emojiProgress.isIndeterminate = false
val max = progressBar.max.toFloat() val max = binding.emojiProgress.max.toFloat()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
progressBar.setProgress((max * progress).toInt(), true) binding.emojiProgress.setProgress((max * progress).toInt(), true)
} else { } else {
progressBar.progress = (max * progress).toInt() binding.emojiProgress.progress = (max * progress).toInt()
} }
} else { } else {
progressBar.isIndeterminate = true binding.emojiProgress.isIndeterminate = true
} }
}, },
{ {
Toast.makeText(context, R.string.download_failed, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.download_failed, Toast.LENGTH_SHORT).show()
updateItem(font, container) updateItem(font, binding)
}, },
{ {
finishDownload(font, container) finishDownload(font, binding)
} }
).also { downloadDisposables[font.id] = it } ).also { downloadDisposables[font.id] = it }
} }
private fun cancelDownload(font: EmojiCompatFont, container: View) { private fun cancelDownload(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
font.deleteDownloadedFile(container.context) font.deleteDownloadedFile(context)
downloadDisposables[font.id]?.dispose() downloadDisposables[font.id]?.dispose()
downloadDisposables[font.id] = null downloadDisposables[font.id] = null
updateItem(font, container) updateItem(font, binding)
} }
private fun finishDownload(font: EmojiCompatFont, container: View) { private fun finishDownload(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
select(font, container.findViewById(R.id.emojicompat_radio)) select(font, binding.emojiRadioButton)
updateItem(font, container) updateItem(font, binding)
// Set the flag to restart the app (because an update has been downloaded) // Set the flag to restart the app (because an update has been downloaded)
if (selected === original && currentNeedsUpdate) { if (selected === original && currentNeedsUpdate) {
updated = true updated = true
@ -153,54 +153,43 @@ class EmojiPreference(
*/ */
private fun select(font: EmojiCompatFont, radio: RadioButton) { private fun select(font: EmojiCompatFont, radio: RadioButton) {
selected = font selected = font
// Uncheck all the other buttons radioButtons.forEach { radioButton ->
for (other in radioButtons) { radioButton.isChecked = radioButton == radio
if (other !== radio) {
other.isChecked = false
}
} }
radio.isChecked = true
} }
/** /**
* Called when a "consistent" state is reached, i.e. it's not downloading the font * Called when a "consistent" state is reached, i.e. it's not downloading the font
* *
* @param font The font to be displayed * @param font The font to be displayed
* @param container The ConstraintLayout containing the item * @param binding The ItemEmojiPrefBinding to show the item in
*/ */
private fun updateItem(font: EmojiCompatFont, container: View) { private fun updateItem(font: EmojiCompatFont, binding: ItemEmojiPrefBinding) {
// Assignments
val download: ImageButton = container.findViewById(R.id.emojicompat_download)
val caption: TextView = container.findViewById(R.id.emojicompat_caption)
val progress: ProgressBar = container.findViewById(R.id.emojicompat_progress)
val cancel: ImageButton = container.findViewById(R.id.emojicompat_download_cancel)
val radio: RadioButton = container.findViewById(R.id.emojicompat_radio)
// There's no download going on // There's no download going on
progress.visibility = View.GONE binding.emojiProgress.hide()
cancel.visibility = View.GONE binding.emojiDownloadCancel.hide()
caption.visibility = View.VISIBLE binding.emojiCaption.show()
if (font.isDownloaded(context)) { if (font.isDownloaded(context)) {
// Make it selectable // Make it selectable
download.visibility = View.GONE binding.emojiDownload.hide()
radio.visibility = View.VISIBLE binding.emojiRadioButton.show()
container.isClickable = true binding.root.isClickable = true
} else { } else {
// Make it downloadable // Make it downloadable
download.visibility = View.VISIBLE binding.emojiDownload.show()
radio.visibility = View.GONE binding.emojiRadioButton.hide()
container.isClickable = false binding.root.isClickable = false
} }
// Select it if necessary // Select it if necessary
if (font === selected) { if (font === selected) {
radio.isChecked = true binding.emojiRadioButton.isChecked = true
// Update available // Update available
if (!font.isDownloaded(context)) { if (!font.isDownloaded(context)) {
currentNeedsUpdate = true currentNeedsUpdate = true
} }
} else { } else {
radio.isChecked = false binding.emojiRadioButton.isChecked = false
} }
} }
@ -246,13 +235,5 @@ class EmojiPreference(
companion object { companion object {
private const val TAG = "EmojiPreference" private const val TAG = "EmojiPreference"
// Please note that this array must sorted in the same way as the fonts.
private val viewIds = intArrayOf(
R.id.item_nomoji,
R.id.item_blobmoji,
R.id.item_twemoji,
R.id.item_notoemoji
)
} }
} }

View File

@ -256,27 +256,27 @@ class EmojiCompatFont(
private const val CHUNK_SIZE = 4096L private const val CHUNK_SIZE = 4096L
// The system font gets some special behavior... // The system font gets some special behavior...
private val SYSTEM_DEFAULT = EmojiCompatFont("system-default", val SYSTEM_DEFAULT = EmojiCompatFont("system-default",
"System Default", "System Default",
R.string.caption_systememoji, R.string.caption_systememoji,
R.drawable.ic_emoji_34dp, R.drawable.ic_emoji_34dp,
"", "",
"0") "0")
private val BLOBMOJI = EmojiCompatFont("Blobmoji", val BLOBMOJI = EmojiCompatFont("Blobmoji",
"Blobmoji", "Blobmoji",
R.string.caption_blobmoji, R.string.caption_blobmoji,
R.drawable.ic_blobmoji, R.drawable.ic_blobmoji,
"https://tusky.app/hosted/emoji/BlobmojiCompat.ttf", "https://tusky.app/hosted/emoji/BlobmojiCompat.ttf",
"12.0.0" "12.0.0"
) )
private val TWEMOJI = EmojiCompatFont("Twemoji", val TWEMOJI = EmojiCompatFont("Twemoji",
"Twemoji", "Twemoji",
R.string.caption_twemoji, R.string.caption_twemoji,
R.drawable.ic_twemoji, R.drawable.ic_twemoji,
"https://tusky.app/hosted/emoji/TwemojiCompat.ttf", "https://tusky.app/hosted/emoji/TwemojiCompat.ttf",
"12.0.0" "12.0.0"
) )
private val NOTOEMOJI = EmojiCompatFont("NotoEmoji", val NOTOEMOJI = EmojiCompatFont("NotoEmoji",
"Noto Emoji", "Noto Emoji",
R.string.caption_notoemoji, R.string.caption_notoemoji,
R.drawable.ic_notoemoji, R.drawable.ic_notoemoji,

View File

@ -2,7 +2,6 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/emojicompat_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
@ -11,7 +10,7 @@
<!--This is a thumbnail picture--> <!--This is a thumbnail picture-->
<ImageView <ImageView
android:id="@+id/emojicompat_thumb" android:id="@+id/emojiThumbnail"
android:layout_width="42dp" android:layout_width="42dp"
android:layout_height="42dp" android:layout_height="42dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
@ -25,22 +24,22 @@
<!--This is the font's name--> <!--This is the font's name-->
<TextView <TextView
android:id="@+id/emojicompat_name" android:id="@+id/emojiName"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
android:layout_marginEnd="72dp" android:layout_marginEnd="72dp"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textSize="?attr/status_text_medium" android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toTopOf="@+id/emojicompat_caption" app:layout_constraintBottom_toTopOf="@+id/emojiCaption"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/emojicompat_thumb" app:layout_constraintStart_toEndOf="@+id/emojiThumbnail"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="@string/system_default" /> tools:text="@string/system_default" />
<!--A short caption…--> <!--A short caption…-->
<TextView <TextView
android:id="@+id/emojicompat_caption" android:id="@+id/emojiCaption"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="72dp" android:layout_marginEnd="72dp"
@ -49,14 +48,14 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="@id/emojicompat_name" app:layout_constraintStart_toStartOf="@id/emojiName"
app:layout_constraintTop_toBottomOf="@id/emojicompat_name" app:layout_constraintTop_toBottomOf="@id/emojiName"
app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_chainStyle="packed"
tools:text="@string/caption_blobmoji" /> tools:text="@string/caption_blobmoji" />
<!--This progress bar is shown while the font is downloading.--> <!--This progress bar is shown while the font is downloading.-->
<ProgressBar <ProgressBar
android:id="@+id/emojicompat_progress" android:id="@+id/emojiProgress"
style="?android:attr/progressBarStyleHorizontal" style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -65,12 +64,12 @@
android:indeterminate="false" android:indeterminate="false"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/emojicompat_name" app:layout_constraintStart_toStartOf="@id/emojiName"
app:layout_constraintTop_toBottomOf="@id/emojicompat_name" /> app:layout_constraintTop_toBottomOf="@id/emojiName" />
<!--Click on it and the font will be downloaded!--> <!--Click on it and the font will be downloaded!-->
<ImageButton <ImageButton
android:id="@+id/emojicompat_download" android:id="@+id/emojiDownload"
android:layout_width="42dp" android:layout_width="42dp"
android:layout_height="42dp" android:layout_height="42dp"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
@ -80,13 +79,13 @@
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/emojicompat_caption" app:layout_constraintStart_toEndOf="@id/emojiCaption"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_file_download_black_24dp" /> app:srcCompat="@drawable/ic_file_download_black_24dp" />
<!--You should be able to cancel the download--> <!--You should be able to cancel the download-->
<ImageButton <ImageButton
android:id="@+id/emojicompat_download_cancel" android:id="@+id/emojiDownloadCancel"
android:layout_width="42dp" android:layout_width="42dp"
android:layout_height="42dp" android:layout_height="42dp"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
@ -96,20 +95,20 @@
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/emojicompat_name" app:layout_constraintStart_toEndOf="@id/emojiName"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_cancel_24dp" /> app:srcCompat="@drawable/ic_cancel_24dp" />
<!--You'll probably want to select an emoji font, don't you?--> <!--You'll probably want to select an emoji font, don't you?-->
<androidx.appcompat.widget.AppCompatRadioButton <androidx.appcompat.widget.AppCompatRadioButton
android:id="@+id/emojicompat_radio" android:id="@+id/emojiRadioButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="visible" android:visibility="visible"
app:buttonTint="@color/compound_button_color" app:buttonTint="@color/compound_button_color"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/emojicompat_name" app:layout_constraintStart_toEndOf="@id/emojiName"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>