Aperture: Cleanup previous and next collections extensions

Let them return null if the array is empty

Change-Id: Ic825f3a97b5166ed6fde040f21d362e6c45f3a98
diff --git a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
index 894484d..b6a1d9d 100644
--- a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
@@ -262,10 +262,14 @@
                 ) {
                     if (e2.x > e1.x) {
                         // Left to right
-                        changeCameraMode(cameraMode.previous())
+                        cameraMode.previous()?.let {
+                            changeCameraMode(it)
+                        }
                     } else {
                         // Right to left
-                        changeCameraMode(cameraMode.next())
+                        cameraMode.next()?.let {
+                            changeCameraMode(it)
+                        }
                     }
                 }
                 return true
@@ -1955,21 +1959,20 @@
         }
 
         val currentVideoQuality = videoQuality
-        val newVideoQuality = supportedVideoQualities.toList().sortedWith { a, b ->
+
+        supportedVideoQualities.toList().sortedWith { a, b ->
             listOf(Quality.SD, Quality.HD, Quality.FHD, Quality.UHD).let {
                 it.indexOf(a) - it.indexOf(b)
             }
-        }.next(currentVideoQuality)
+        }.next(currentVideoQuality)?.takeUnless {
+            it == currentVideoQuality
+        }?.let {
+            videoQuality = it
 
-        if (newVideoQuality == currentVideoQuality) {
-            return
+            sharedPreferences.videoQuality = it
+
+            bindCameraUseCases()
         }
-
-        videoQuality = newVideoQuality
-
-        sharedPreferences.videoQuality = videoQuality
-
-        bindCameraUseCases()
     }
 
     private fun cycleVideoFrameRate() {
@@ -1998,29 +2001,29 @@
         }
 
         val currentVideoDynamicRange = videoDynamicRange
-        val newVideoDynamicRange =
-            supportedVideoDynamicRanges.toList().sorted().next(currentVideoDynamicRange)
 
-        if (newVideoDynamicRange == currentVideoDynamicRange) {
-            return
+        supportedVideoDynamicRanges.toList().sorted().next(currentVideoDynamicRange)?.takeUnless {
+            it == currentVideoDynamicRange
+        }?.let {
+            videoDynamicRange = it
+
+            sharedPreferences.videoDynamicRange = it
+
+            bindCameraUseCases()
         }
-
-        videoDynamicRange = newVideoDynamicRange
-
-        sharedPreferences.videoDynamicRange = videoDynamicRange
-
-        bindCameraUseCases()
     }
 
     /**
      * Set the specified grid mode, also updating the icon
      */
     private fun cycleGridMode() {
-        gridMode = gridMode.next()
+        gridMode.next()?.let {
+            gridMode = it
 
-        sharedPreferences.lastGridMode = gridMode
+            sharedPreferences.lastGridMode = it
 
-        changeGridMode(gridMode)
+            changeGridMode(gridMode)
+        }
     }
 
     private fun changeGridMode(gridMode: GridMode) {
@@ -2031,9 +2034,11 @@
      * Toggle timer mode
      */
     private fun toggleTimerMode() {
-        timerMode = timerMode.next()
+        timerMode.next()?.let {
+            timerMode = it
 
-        sharedPreferences.timerMode = timerMode
+            sharedPreferences.timerMode = it
+        }
     }
 
     /**
@@ -2050,18 +2055,19 @@
      */
     private fun cycleFlashMode() {
         val currentFlashMode = flashMode
-        val newFlashMode = when (cameraMode) {
+
+        when (cameraMode) {
             CameraMode.PHOTO -> FlashMode.PHOTO_ALLOWED_MODES.next(currentFlashMode)
             CameraMode.VIDEO -> FlashMode.VIDEO_ALLOWED_MODES.next(currentFlashMode)
             else -> FlashMode.OFF
-        }
+        }?.let {
+            changeFlashMode(it)
 
-        changeFlashMode(newFlashMode)
-
-        when (cameraMode) {
-            CameraMode.PHOTO -> sharedPreferences.photoFlashMode = newFlashMode
-            CameraMode.VIDEO -> sharedPreferences.videoFlashMode = newFlashMode
-            else -> {}
+            when (cameraMode) {
+                CameraMode.PHOTO -> sharedPreferences.photoFlashMode = it
+                CameraMode.VIDEO -> sharedPreferences.videoFlashMode = it
+                else -> {}
+            }
         }
 
         if (cameraMode == CameraMode.PHOTO && !sharedPreferences.forceTorchHelpShown &&
@@ -2124,17 +2130,16 @@
         }
 
         val currentExtensionMode = photoEffect
-        val newExtensionMode = camera.supportedExtensionModes.next(currentExtensionMode)
 
-        if (newExtensionMode == currentExtensionMode) {
-            return
+        camera.supportedExtensionModes.next(currentExtensionMode)?.takeUnless {
+            it == currentExtensionMode
+        }?.let {
+            photoEffect = it
+
+            sharedPreferences.photoEffect = it
+
+            bindCameraUseCases()
         }
-
-        photoEffect = newExtensionMode
-
-        sharedPreferences.photoEffect = photoEffect
-
-        bindCameraUseCases()
     }
 
     private fun setBrightScreen(brightScreen: Boolean) {
diff --git a/app/src/main/java/org/lineageos/aperture/ext/Array.kt b/app/src/main/java/org/lineageos/aperture/ext/Array.kt
new file mode 100644
index 0000000..f6c1664
--- /dev/null
+++ b/app/src/main/java/org/lineageos/aperture/ext/Array.kt
@@ -0,0 +1,32 @@
+/*
+ * SPDX-FileCopyrightText: 2022-2023 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.aperture.ext
+
+/**
+ * Get the next element in the array relative to the [current] element.
+ *
+ * If the element is the last in the array or it's not present in the array
+ * it will return the first element.
+ * If the array is empty, null will be returned.
+ *
+ * @param current The element to use as cursor
+ *
+ * @return [T] Either the next element, the first element or null
+ */
+fun <T> Array<T>.next(current: T) = getOrElse(indexOf(current) + 1) { firstOrNull() }
+
+/**
+ * Get the previous element in the array relative to the [current] element.
+ *
+ * If the element is the first in the array or it's not present in the array
+ * it will return the last element.
+ * If the array is empty, null will be returned.
+ *
+ * @param current The element to use as cursor
+ *
+ * @return [T] Either the previous element, the last element or null
+ */
+fun <T> Array<T>.previous(current: T) = getOrElse(indexOf(current) - 1) { lastOrNull() }
diff --git a/app/src/main/java/org/lineageos/aperture/ext/Collections.kt b/app/src/main/java/org/lineageos/aperture/ext/Collections.kt
deleted file mode 100644
index 2d8ff76..0000000
--- a/app/src/main/java/org/lineageos/aperture/ext/Collections.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 The LineageOS Project
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package org.lineageos.aperture.ext
-
-/**
- * Get the next item in the array.
- * If the element is the last of the list or it's not present in the list
- * it will return the first item.
- */
-internal fun <T> Array<T>.next(current: T): T {
-    val currentIndex = indexOf(current)
-    return getOrElse(currentIndex + 1) { first() }
-}
-
-/**
- * Get the previous item in the array.
- * If the element is the first of the list or it's not present in the list
- * it will return the last item.
- */
-internal fun <T> Array<T>.previous(current: T): T {
-    val currentIndex = indexOf(current)
-    return getOrElse(currentIndex - 1) { last() }
-}
-
-/**
- * Get the next item in the list.
- * If the element is the last of the list or it's not present in the list
- * it will return the first item.
- */
-internal fun <T> List<T>.next(current: T): T {
-    val currentIndex = indexOf(current)
-    return getOrElse(currentIndex + 1) { first() }
-}
-
-/**
- * Get the previous item in the list.
- * If the element is the first of the list or it's not present in the list
- * it will return the last item.
- */
-internal fun <T> List<T>.previous(current: T): T {
-    val currentIndex = indexOf(current)
-    return getOrElse(currentIndex - 1) { last() }
-}
diff --git a/app/src/main/java/org/lineageos/aperture/ext/List.kt b/app/src/main/java/org/lineageos/aperture/ext/List.kt
new file mode 100644
index 0000000..2395fbd
--- /dev/null
+++ b/app/src/main/java/org/lineageos/aperture/ext/List.kt
@@ -0,0 +1,32 @@
+/*
+ * SPDX-FileCopyrightText: 2022-2023 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.aperture.ext
+
+/**
+ * Get the next element in the list relative to the [current] element.
+ *
+ * If the element is the last in the list or it's not present in the list
+ * it will return the first element.
+ * If the list is empty, null will be returned.
+ *
+ * @param current The element to use as cursor
+ *
+ * @return [E] Either the next element, the first element or null
+ */
+fun <E> List<E>.next(current: E) = getOrElse(indexOf(current) + 1) { firstOrNull() }
+
+/**
+ * Get the previous element in the list relative to the [current] element.
+ *
+ * If the element is the first in the list or it's not present in the list
+ * it will return the last element.
+ * If the list is empty, null will be returned.
+ *
+ * @param current The element to use as cursor
+ *
+ * @return [E] Either the previous element, the last element or null
+ */
+fun <E> List<E>.previous(current: E) = getOrElse(indexOf(current) - 1) { lastOrNull() }