From 65637e9e2be0e45f17488b5100b7e9ce0ca1b153 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Tue, 7 Jul 2020 13:36:29 -0700 Subject: [PATCH] Use A-C version of Resources.getSpanned (#12358) --- .../java/org/mozilla/fenix/ext/Resources.kt | 98 ------------------- .../mozilla/fenix/search/SearchFragment.kt | 10 +- 2 files changed, 4 insertions(+), 104 deletions(-) delete mode 100644 app/src/main/java/org/mozilla/fenix/ext/Resources.kt diff --git a/app/src/main/java/org/mozilla/fenix/ext/Resources.kt b/app/src/main/java/org/mozilla/fenix/ext/Resources.kt deleted file mode 100644 index ccfe19c4b..000000000 --- a/app/src/main/java/org/mozilla/fenix/ext/Resources.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.ext - -import android.content.res.Configuration -import android.content.res.Resources -import android.os.Build -import android.os.Build.VERSION.SDK_INT -import android.text.SpannableString -import android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE -import androidx.annotation.StringRes -import java.util.Formatter - -// Credit to Michael Spitsin https://medium.com/@programmerr47/working-with-spans-in-android-ca4ab1327bc4 -@Suppress("SpreadOperator") -fun Resources.getSpannable(@StringRes id: Int, spanParts: List>>): CharSequence { - val resultCreator = SpannableStringCreator() - Formatter( - SpannableAppendable(resultCreator, spanParts), - getLocale(configuration) - ).format(getString(id), *spanParts.map { it.first }.toTypedArray()) - return resultCreator.toSpannableString() -} - -private fun getLocale(configuration: Configuration) = - if (SDK_INT >= Build.VERSION_CODES.N) { - configuration.locales[0] - } else { - @Suppress("Deprecation") - configuration.locale - } - -class SpannableStringCreator { - private val parts = ArrayList() - private var length = 0 - private val spanMap: MutableMap> = HashMap() - - fun append(newText: CharSequence, spans: Iterable) = apply { - val end = newText.length - parts.add(newText) - spanMap[(length..length + end)] = spans - length += end - } - - fun append(newText: CharSequence) = apply { - parts.add(newText) - length += newText.length - } - - fun toSpannableString() = SpannableString(parts.joinToString("")).apply { - spanMap.forEach { entry -> - val range = entry.key - entry.value.forEach { - setSpan(it, range.first, range.last, SPAN_EXCLUSIVE_EXCLUSIVE) - } - } - } -} - -class SpannableAppendable( - private val creator: SpannableStringCreator, - spanParts: List>> -) : Appendable { - - private val spansMap = spanParts.toMap().mapKeys { entry -> entry.key.let { it as? CharSequence ?: it.toString() } } - - override fun append(csq: CharSequence?) = apply { creator.appendSmart(csq, spansMap) } - - override fun append(csq: CharSequence?, start: Int, end: Int) = apply { - if (csq != null) { - if (start in 0 until end && end <= csq.length) { - append(csq.subSequence(start, end)) - } else { - throw IndexOutOfBoundsException("start " + start + ", end " + end + ", s.length() " + csq.length) - } - } - } - - override fun append(c: Char) = apply { creator.append(c.toString()) } - - private fun SpannableStringCreator.appendSmart(csq: CharSequence?, spanDict: Map>) { - if (csq != null) { - if (csq in spanDict) { - append(csq, spanDict.getValue(csq)) - } else { - val possibleMatchDict = spanDict.filter { it.key.toString() == csq } - if (possibleMatchDict.isNotEmpty()) { - val spanDictEntry = possibleMatchDict.entries.toList()[0] - append(spanDictEntry.key, spanDictEntry.value) - } else { - append(csq) - } - } - } - } -} diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt index 37bc6d5f0..1490ae2a1 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt @@ -40,6 +40,7 @@ import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.content.hasCamera import mozilla.components.support.ktx.android.content.isPermissionGranted +import mozilla.components.support.ktx.android.content.res.getSpanned import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.ui.autocomplete.InlineAutocompleteEditText import org.mozilla.fenix.BrowserDirection @@ -50,7 +51,6 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.searchengine.CustomSearchEngineStore import org.mozilla.fenix.components.searchengine.FenixSearchEngineProvider import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.getSpannable import org.mozilla.fenix.ext.hideToolbar import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings @@ -225,12 +225,10 @@ class SearchFragment : Fragment(), UserInteractionHandler { search_scan_button.isChecked = false activity?.let { AlertDialog.Builder(it).apply { - val spannable = resources.getSpannable( + val spannable = resources.getSpanned( R.string.qr_scanner_confirmation_dialog_message, - listOf( - getString(R.string.app_name) to listOf(StyleSpan(BOLD)), - result to listOf(StyleSpan(ITALIC)) - ) + getString(R.string.app_name) to StyleSpan(BOLD), + result to StyleSpan(ITALIC) ) setMessage(spannable) setNegativeButton(R.string.qr_scanner_dialog_negative) { dialog: DialogInterface, _ ->