Browse Source

Utilize more KTX extensions (#7348)

Taco 2 years ago
parent
commit
c2520bff12
20 changed files with 89 additions and 98 deletions
  1. 1 1
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt
  2. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt
  3. 7 9
      app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt
  4. 5 13
      app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/SearchableNucleusController.kt
  5. 6 4
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesController.kt
  6. 2 1
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
  7. 2 1
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterSheet.kt
  8. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/PageIndicatorTextView.kt
  9. 4 4
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
  10. 7 8
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderNavigationOverlayView.kt
  11. 3 2
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt
  12. 2 1
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt
  13. 7 9
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchHelper.kt
  14. 2 7
      app/src/main/java/eu/kanade/tachiyomi/util/lang/StringExtensions.kt
  15. 1 1
      app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt
  16. 13 12
      app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt
  17. 4 3
      app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt
  18. 2 1
      app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt
  19. 10 12
      app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt
  20. 6 5
      app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiAppBarLayout.kt

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt

@@ -29,7 +29,7 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
     override suspend fun doWork(): Result {
         val preferences = Injekt.get<PreferencesHelper>()
         val notifier = BackupNotifier(context)
-        val uri = inputData.getString(LOCATION_URI_KEY)?.let { Uri.parse(it) }
+        val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
             ?: preferences.backupsDirectory().get().toUri()
         val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupConst.BACKUP_ALL)
         val isAutoBackup = inputData.getBoolean(IS_AUTO_BACKUP_KEY, true)

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt

@@ -4,6 +4,7 @@ import android.app.PendingIntent
 import android.content.Context
 import android.content.Intent
 import android.net.Uri
+import androidx.core.net.toUri
 import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
 import eu.kanade.tachiyomi.ui.main.MainActivity
 
@@ -53,7 +54,7 @@ object NotificationHandler {
     }
 
     fun openUrl(context: Context, url: String): PendingIntent {
-        val notificationIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+        val notificationIntent = Intent(Intent.ACTION_VIEW, url.toUri())
         return PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)
     }
 }

+ 7 - 9
app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt

@@ -1,13 +1,13 @@
 package eu.kanade.tachiyomi.data.saver
 
 import android.annotation.SuppressLint
-import android.content.ContentValues
 import android.content.Context
 import android.graphics.Bitmap
 import android.net.Uri
 import android.os.Build
 import android.os.Environment
 import android.provider.MediaStore
+import androidx.core.content.contentValuesOf
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.util.storage.DiskUtil
 import eu.kanade.tachiyomi.util.storage.cacheImageDir
@@ -39,15 +39,13 @@ class ImageSaver(
         val pictureDir =
             MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
 
-        val contentValues = ContentValues().apply {
-            put(MediaStore.Images.Media.DISPLAY_NAME, image.name)
-            put(MediaStore.Images.Media.MIME_TYPE, type.mime)
-            put(
-                MediaStore.Images.Media.RELATIVE_PATH,
+        val contentValues = contentValuesOf(
+            MediaStore.Images.Media.DISPLAY_NAME to image.name,
+            MediaStore.Images.Media.MIME_TYPE to type.mime,
+            MediaStore.Images.Media.RELATIVE_PATH to
                 "${Environment.DIRECTORY_PICTURES}/${context.getString(R.string.app_name)}/" +
-                    (image.location as Location.Pictures).relativePath,
-            )
-        }
+                (image.location as Location.Pictures).relativePath,
+        )
 
         val picture = context.contentResolver.insert(
             pictureDir,

+ 5 - 13
app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/SearchableNucleusController.kt

@@ -2,14 +2,14 @@ package eu.kanade.tachiyomi.ui.base.controller
 
 import android.app.Activity
 import android.os.Bundle
-import android.text.Editable
-import android.text.TextWatcher
 import android.text.style.CharacterStyle
 import android.view.Menu
 import android.view.MenuInflater
 import android.view.MenuItem
 import androidx.annotation.StringRes
 import androidx.appcompat.widget.SearchView
+import androidx.core.text.getSpans
+import androidx.core.widget.doAfterTextChanged
 import androidx.viewbinding.ViewBinding
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
@@ -59,17 +59,9 @@ abstract class SearchableNucleusController<VB : ViewBinding, P : BasePresenter<*
         val searchAutoComplete: SearchView.SearchAutoComplete = searchView.findViewById(
             R.id.search_src_text,
         )
-        searchAutoComplete.addTextChangedListener(object : TextWatcher {
-            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
-
-            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
-
-            override fun afterTextChanged(editable: Editable) {
-                editable.getSpans(0, editable.length, CharacterStyle::class.java)
-                    .forEach { editable.removeSpan(it) }
-            }
-        },
-        )
+        searchAutoComplete.doAfterTextChanged { editable ->
+            editable?.getSpans<CharacterStyle>()?.forEach { editable.removeSpan(it) }
+        }
 
         searchView.queryTextEvents()
             .onEach {

+ 6 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesController.kt

@@ -19,7 +19,9 @@ import androidx.preference.Preference
 import androidx.preference.PreferenceGroupAdapter
 import androidx.preference.PreferenceManager
 import androidx.preference.PreferenceScreen
+import androidx.preference.get
 import androidx.preference.getOnBindEditTextListener
+import androidx.preference.isNotEmpty
 import androidx.recyclerview.widget.LinearLayoutManager
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
@@ -111,8 +113,8 @@ class SourcePreferencesController(bundle: Bundle? = null) :
             source.setupPreferenceScreen(newScreen)
 
             // Reparent the preferences
-            while (newScreen.preferenceCount != 0) {
-                val pref = newScreen.getPreference(0)
+            while (newScreen.isNotEmpty()) {
+                val pref = newScreen[0]
                 pref.isIconSpaceReserved = false
                 pref.order = Int.MAX_VALUE // reset to default order
 
@@ -143,7 +145,7 @@ class SourcePreferencesController(bundle: Bundle? = null) :
         val screen = preference.parent!!
 
         lastOpenPreferencePosition = (0 until screen.preferenceCount).indexOfFirst {
-            screen.getPreference(it) === preference
+            screen[it] === preference
         }
 
         val f = when (preference) {
@@ -169,7 +171,7 @@ class SourcePreferencesController(bundle: Bundle? = null) :
     override fun <T : Preference> findPreference(key: CharSequence): T? {
         // We track [lastOpenPreferencePosition] when displaying the dialog
         // [key] isn't useful since there may be duplicates
-        return preferenceScreen!!.getPreference(lastOpenPreferencePosition!!) as T
+        return preferenceScreen!![lastOpenPreferencePosition!!] as T
     }
 }
 

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt

@@ -8,6 +8,7 @@ import android.view.MenuInflater
 import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
+import androidx.core.view.get
 import androidx.core.view.isVisible
 import androidx.core.view.updatePadding
 import androidx.recyclerview.widget.GridLayoutManager
@@ -202,7 +203,7 @@ open class BrowseSourceController(bundle: Bundle) :
         numColumnsJob?.cancel()
 
         var oldPosition = RecyclerView.NO_POSITION
-        val oldRecycler = binding.catalogueView.getChildAt(1)
+        val oldRecycler = binding.catalogueView[1]
         if (oldRecycler is RecyclerView) {
             oldPosition = (oldRecycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
             oldRecycler.adapter = null

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterSheet.kt

@@ -6,6 +6,7 @@ import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.core.view.get
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.IFlexible
 import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
@@ -55,7 +56,7 @@ class SourceFilterSheet(
         init {
             recycler.adapter = adapter
             recycler.setHasFixedSize(true)
-            (binding.root.getChildAt(1) as ViewGroup).addView(recycler)
+            (binding.root[1] as ViewGroup).addView(recycler)
             addView(binding.root)
             binding.filterBtn.setOnClickListener { onFilterClicked() }
             binding.resetBtn.setOnClickListener { onResetClicked() }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/reader/PageIndicatorTextView.kt

@@ -3,11 +3,11 @@ package eu.kanade.tachiyomi.ui.reader
 import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Color
-import android.text.Spannable
 import android.text.SpannableString
 import android.text.style.ScaleXSpan
 import android.util.AttributeSet
 import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.text.set
 import eu.kanade.tachiyomi.widget.OutlineSpan
 
 /**
@@ -31,10 +31,10 @@ class PageIndicatorTextView(
         // Also add a bit of spacing between each character, as the stroke overlaps them
         val finalText = SpannableString(currText.asIterable().joinToString("\u00A0")).apply {
             // Apply text outline
-            setSpan(spanOutline, 1, length - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+            set(1, length - 1, spanOutline)
 
             for (i in 1..lastIndex step 2) {
-                setSpan(ScaleXSpan(0.2f), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+                set(i, i + 1, ScaleXSpan(0.2f))
             }
         }
 

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt

@@ -30,7 +30,7 @@ import android.view.animation.AnimationUtils
 import android.widget.FrameLayout
 import android.widget.Toast
 import androidx.core.graphics.ColorUtils
-import androidx.core.transition.addListener
+import androidx.core.transition.doOnEnd
 import androidx.core.view.WindowCompat
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.WindowInsetsControllerCompat
@@ -621,9 +621,9 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
         updateCropBordersShortcut()
         if (window.sharedElementEnterTransition is MaterialContainerTransform) {
             // Wait until transition is complete to avoid crash on API 26
-            window.sharedElementEnterTransition.addListener(
-                onEnd = { setOrientation(presenter.getMangaOrientationType()) },
-            )
+            window.sharedElementEnterTransition.doOnEnd {
+                setOrientation(presenter.getMangaOrientationType())
+            }
         } else {
             setOrientation(presenter.getMangaOrientationType())
         }

+ 7 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderNavigationOverlayView.kt

@@ -8,7 +8,8 @@ import android.util.AttributeSet
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewPropertyAnimator
-import androidx.core.graphics.withSave
+import androidx.core.graphics.withScale
+import androidx.core.graphics.withTranslation
 import androidx.core.view.isVisible
 import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
 import eu.kanade.tachiyomi.ui.reader.viewer.navigation.DisabledNavigation
@@ -63,17 +64,15 @@ class ReaderNavigationOverlayView(context: Context, attributeSet: AttributeSet)
         navigation?.regions?.forEach { region ->
             val rect = region.rectF
 
-            canvas?.withSave {
-                // Scale rect from 1f,1f to screen width and height
-                scale(width.toFloat(), height.toFloat())
+            // Scale rect from 1f,1f to screen width and height
+            canvas?.withScale(width.toFloat(), height.toFloat()) {
                 regionPaint.color = context.getColor(region.type.colorRes)
                 drawRect(rect, regionPaint)
             }
-            // Don't want scale anymore because it messes with drawText
-            canvas?.withSave {
-                // Translate origin to rect start (left, top)
-                translate((width * rect.left), (height * rect.top))
 
+            // Don't want scale anymore because it messes with drawText
+            // Translate origin to rect start (left, top)
+            canvas?.withTranslation(x = (width * rect.left), y = (height * rect.top)) {
                 // Calculate center of rect width on screen
                 val x = width * (abs(rect.left - rect.right) / 2)
 

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt

@@ -16,6 +16,7 @@ import androidx.annotation.AttrRes
 import androidx.annotation.CallSuper
 import androidx.annotation.StyleRes
 import androidx.appcompat.widget.AppCompatImageView
+import androidx.core.os.postDelayed
 import androidx.core.view.isVisible
 import coil.dispose
 import coil.imageLoader
@@ -110,7 +111,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
 
     private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) {
         if (config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale) {
-            handler?.postDelayed({
+            handler?.postDelayed(500) {
                 val point = when (config!!.zoomStartPosition) {
                     ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F)
                     ZoomStartPosition.RIGHT -> if (forward) PointF(sWidth.toFloat(), 0F) else PointF(0F, 0F)
@@ -123,7 +124,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
                     .withEasing(EASE_IN_OUT_QUAD)
                     .withInterruptible(true)
                     .start()
-            }, 500,)
+            }
         }
     }
 

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt

@@ -9,6 +9,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.widget.LinearLayout
 import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.view.updatePadding
 import com.google.android.material.progressindicator.CircularProgressIndicator
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
@@ -55,7 +56,7 @@ class PagerTransitionHolder(
         orientation = VERTICAL
         gravity = Gravity.CENTER
         val sidePadding = 64.dpToPx
-        setPadding(sidePadding, 0, sidePadding, 0)
+        updatePadding(left = sidePadding, right = sidePadding)
 
         val transitionView = ReaderTransitionView(context)
         addView(transitionView)

+ 7 - 9
app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchHelper.kt

@@ -7,6 +7,8 @@ import androidx.preference.Preference
 import androidx.preference.PreferenceCategory
 import androidx.preference.PreferenceGroup
 import androidx.preference.PreferenceManager
+import androidx.preference.forEach
+import androidx.preference.get
 import eu.kanade.tachiyomi.ui.setting.SettingsAdvancedController
 import eu.kanade.tachiyomi.ui.setting.SettingsAppearanceController
 import eu.kanade.tachiyomi.ui.setting.SettingsBackupController
@@ -56,7 +58,7 @@ object SettingsSearchHelper {
                 val settingsPrefScreen = ctrl.setupPreferenceScreen(preferenceManager.createPreferenceScreen(context))
                 val prefCount = settingsPrefScreen.preferenceCount
                 for (i in 0 until prefCount) {
-                    val rootPref = settingsPrefScreen.getPreference(i)
+                    val rootPref = settingsPrefScreen[i]
                     if (rootPref.title == null) continue // no title, not a preference. (note: only info notes appear to not have titles)
                     getSettingSearchResult(ctrl, rootPref, "${settingsPrefScreen.title}")
                 }
@@ -86,18 +88,14 @@ object SettingsSearchHelper {
         when {
             pref is PreferenceGroup -> {
                 val breadcrumbsStr = addLocalizedBreadcrumb(breadcrumbs, "${pref.title}")
-
-                for (x in 0 until pref.preferenceCount) {
-                    val subPref = pref.getPreference(x)
-                    getSettingSearchResult(ctrl, subPref, breadcrumbsStr) // recursion
+                pref.forEach {
+                    getSettingSearchResult(ctrl, it, breadcrumbsStr) // recursion
                 }
             }
             pref is PreferenceCategory -> {
                 val breadcrumbsStr = addLocalizedBreadcrumb(breadcrumbs, "${pref.title}")
-
-                for (x in 0 until pref.preferenceCount) {
-                    val subPref = pref.getPreference(x)
-                    getSettingSearchResult(ctrl, subPref, breadcrumbsStr) // recursion
+                pref.forEach {
+                    getSettingSearchResult(ctrl, it, breadcrumbsStr) // recursion
                 }
             }
             (pref.title != null && pref.isVisible) -> {

+ 2 - 7
app/src/main/java/eu/kanade/tachiyomi/util/lang/StringExtensions.kt

@@ -1,7 +1,6 @@
 package eu.kanade.tachiyomi.util.lang
 
-import android.os.Build
-import android.text.Html
+import androidx.core.text.parseAsHtml
 import net.greypanther.natsort.CaseInsensitiveSimpleNaturalComparator
 import java.nio.charset.StandardCharsets
 import kotlin.math.floor
@@ -64,9 +63,5 @@ fun String.takeBytes(n: Int): String {
  * HTML-decode the string
  */
 fun String.htmlDecode(): String {
-    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-        Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY).toString()
-    } else {
-        Html.fromHtml(this).toString()
-    }
+    return this.parseAsHtml().toString()
 }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt

@@ -262,7 +262,7 @@ fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) {
 }
 
 fun Context.defaultBrowserPackageName(): String? {
-    val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("http://"))
+    val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri())
     return packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
         ?.activityInfo?.packageName
         ?.takeUnless { it in DeviceUtil.invalidDefaultBrowsers }

+ 13 - 12
app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt

@@ -16,6 +16,7 @@ import androidx.core.graphics.alpha
 import androidx.core.graphics.applyCanvas
 import androidx.core.graphics.blue
 import androidx.core.graphics.createBitmap
+import androidx.core.graphics.get
 import androidx.core.graphics.green
 import androidx.core.graphics.red
 import com.hippo.unifile.UniFile
@@ -273,14 +274,14 @@ object ImageUtil {
         val leftOffsetX = left - offsetX
         val rightOffsetX = right + offsetX
 
-        val topLeftPixel = image.getPixel(left, top)
-        val topRightPixel = image.getPixel(right, top)
-        val midLeftPixel = image.getPixel(left, midY)
-        val midRightPixel = image.getPixel(right, midY)
-        val topCenterPixel = image.getPixel(midX, top)
-        val botLeftPixel = image.getPixel(left, bot)
-        val bottomCenterPixel = image.getPixel(midX, bot)
-        val botRightPixel = image.getPixel(right, bot)
+        val topLeftPixel = image[left, top]
+        val topRightPixel = image[right, top]
+        val midLeftPixel = image[left, midY]
+        val midRightPixel = image[right, midY]
+        val topCenterPixel = image[midX, top]
+        val botLeftPixel = image[left, bot]
+        val bottomCenterPixel = image[midX, bot]
+        val botRightPixel = image[right, bot]
 
         val topLeftIsDark = topLeftPixel.isDark()
         val topRightIsDark = topRightPixel.isDark()
@@ -333,8 +334,8 @@ object ImageUtil {
             var whiteStreak = false
             val notOffset = x == left || x == right
             inner@ for ((index, y) in (0 until image.height step image.height / 25).withIndex()) {
-                val pixel = image.getPixel(x, y)
-                val pixelOff = image.getPixel(x + (if (x < image.width / 2) -offsetX else offsetX), y)
+                val pixel = image[x, y]
+                val pixelOff = image[x + (if (x < image.width / 2) -offsetX else offsetX), y]
                 if (pixel.isWhite()) {
                     whitePixelsStreak++
                     whitePixels++
@@ -425,8 +426,8 @@ object ImageUtil {
         val topCornersIsDark = topLeftIsDark && topRightIsDark
         val botCornersIsDark = botLeftIsDark && botRightIsDark
 
-        val topOffsetCornersIsDark = image.getPixel(leftOffsetX, top).isDark() && image.getPixel(rightOffsetX, top).isDark()
-        val botOffsetCornersIsDark = image.getPixel(leftOffsetX, bot).isDark() && image.getPixel(rightOffsetX, bot).isDark()
+        val topOffsetCornersIsDark = image[leftOffsetX, top].isDark() && image[rightOffsetX, top].isDark()
+        val botOffsetCornersIsDark = image[leftOffsetX, bot].isDark() && image[rightOffsetX, bot].isDark()
 
         val gradient = when {
             darkBG && botCornersIsWhite -> {

+ 4 - 3
app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt

@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.widget
 
 import android.content.Context
 import android.util.AttributeSet
+import androidx.core.content.withStyledAttributes
 import androidx.recyclerview.widget.GridLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import kotlin.math.max
@@ -27,9 +28,9 @@ class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: Att
     init {
         if (attrs != null) {
             val attrsArray = intArrayOf(android.R.attr.columnWidth)
-            val array = context.obtainStyledAttributes(attrs, attrsArray)
-            columnWidth = array.getDimensionPixelSize(0, -1)
-            array.recycle()
+            context.withStyledAttributes(attrs, attrsArray) {
+                columnWidth = getDimensionPixelSize(0, -1)
+            }
         }
 
         layoutManager = manager

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt

@@ -9,6 +9,7 @@ import androidx.annotation.AttrRes
 import androidx.annotation.CallSuper
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.core.view.isVisible
+import androidx.core.view.updatePadding
 import androidx.recyclerview.widget.RecyclerView
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.util.system.getResourceColor
@@ -230,7 +231,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
                 is SeparatorHolder -> {
                     val view = holder.itemView
                     val item = items[position] as Item.Separator
-                    view.setPadding(0, item.paddingTop, 0, item.paddingBottom)
+                    view.updatePadding(top = item.paddingTop, bottom = item.paddingBottom)
                 }
                 is RadioHolder -> {
                     val item = items[position] as Item.Radio

+ 10 - 12
app/src/main/java/eu/kanade/tachiyomi/widget/MaterialSpinnerView.kt

@@ -11,6 +11,7 @@ import androidx.annotation.ArrayRes
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.appcompat.view.menu.MenuBuilder
 import androidx.appcompat.widget.PopupMenu
+import androidx.core.content.withStyledAttributes
 import androidx.core.view.forEach
 import androidx.core.view.get
 import com.fredporciuncula.flow.preferences.Preference
@@ -51,16 +52,15 @@ class MaterialSpinnerView @JvmOverloads constructor(context: Context, attrs: Att
     init {
         addView(binding.root)
 
-        val attr = context.obtainStyledAttributes(attrs, R.styleable.MaterialSpinnerView)
+        context.withStyledAttributes(set = attrs, attrs = R.styleable.MaterialSpinnerView) {
+            val title = getString(R.styleable.MaterialSpinnerView_title).orEmpty()
+            binding.title.text = title
 
-        val title = attr.getString(R.styleable.MaterialSpinnerView_title).orEmpty()
-        binding.title.text = title
-
-        val entries = (attr.getTextArray(R.styleable.MaterialSpinnerView_android_entries) ?: emptyArray()).map { it.toString() }
-        this.entries = entries
-        binding.details.text = entries.firstOrNull().orEmpty()
-
-        attr.recycle()
+            val viewEntries = (getTextArray(R.styleable.MaterialSpinnerView_android_entries)
+                ?: emptyArray()).map { it.toString() }
+            entries = viewEntries
+            binding.details.text = viewEntries.firstOrNull().orEmpty()
+        }
     }
 
     fun setSelection(selection: Int) {
@@ -152,9 +152,7 @@ class MaterialSpinnerView @JvmOverloads constructor(context: Context, attrs: Att
         popup.menu.forEach {
             it.icon = emptyIcon
         }
-        popup.menu.getItem(selectedPosition)?.let {
-            it.icon = checkmarkIcon
-        }
+        popup.menu[selectedPosition].icon = checkmarkIcon
         popup.setOnMenuItemClickListener { menuItem ->
             val pos = menuClicked(menuItem)
             onItemClick(pos)

+ 6 - 5
app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiAppBarLayout.kt

@@ -12,6 +12,8 @@ import android.util.AttributeSet
 import android.view.animation.LinearInterpolator
 import android.widget.TextView
 import androidx.annotation.FloatRange
+import androidx.core.graphics.drawable.updateBounds
+import androidx.core.graphics.withTranslation
 import androidx.lifecycle.coroutineScope
 import androidx.lifecycle.findViewTreeLifecycleOwner
 import com.google.android.material.shape.MaterialShapeDrawable
@@ -84,15 +86,14 @@ class TachiyomiAppBarLayout @JvmOverloads constructor(
 
     override fun draw(canvas: Canvas) {
         super.draw(canvas)
-        val saveCount = canvas.save()
-        canvas.translate(0f, -currentOffset.toFloat())
-        statusBarForeground?.draw(canvas)
-        canvas.restoreToCount(saveCount)
+        canvas.withTranslation(y = -currentOffset.toFloat()) {
+            statusBarForeground?.draw(this)
+        }
     }
 
     override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
         super.onLayout(changed, l, t, r, b)
-        statusBarForeground?.setBounds(0, 0, width, paddingTop)
+        statusBarForeground?.updateBounds(right = width, bottom = paddingTop)
     }
 
     override fun onOffsetChanged(offset: Int) {