Aperture: Move all the remaining views changes to livedata observers

Change-Id: I541055c76a1acfbe56fd794e25b6ddd9dc6ac9de
diff --git a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
index 71d4d64..b52a709 100644
--- a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
@@ -148,6 +148,7 @@
 open class CameraActivity : AppCompatActivity() {
     // Views
     private val aspectRatioButton by lazy { findViewById<Button>(R.id.aspectRatioButton) }
+    private val cameraModeButtonsGroup by lazy { findViewById<Group>(R.id.cameraModeButtonsGroup) }
     private val cameraModeHighlight by lazy { findViewById<MaterialButton>(R.id.cameraModeHighlight) }
     private val capturePreviewLayout by lazy { findViewById<CapturePreviewLayout>(R.id.capturePreviewLayout) }
     private val countDownView by lazy { findViewById<CountDownView>(R.id.countDownView) }
@@ -168,7 +169,7 @@
     private val modeSelectorLayout by lazy { findViewById<ConstraintLayout>(R.id.modeSelectorLayout) }
     private val photoModeButton by lazy { findViewById<MaterialButton>(R.id.photoModeButton) }
     private val previewBlurView by lazy { findViewById<PreviewBlurView>(R.id.previewBlurView) }
-    private val primaryBarLayoutGroupPhoto by lazy { findViewById<Group>(R.id.primaryBarLayoutGroupPhoto) }
+    private val primaryBarLayout by lazy { findViewById<ConstraintLayout>(R.id.primaryBarLayout) }
     private val proButton by lazy { findViewById<ImageButton>(R.id.proButton) }
     private val qrModeButton by lazy { findViewById<MaterialButton>(R.id.qrModeButton) }
     private val secondaryBottomBarLayout by lazy { findViewById<ConstraintLayout>(R.id.secondaryBottomBarLayout) }
@@ -176,7 +177,7 @@
     private val settingsButton by lazy { findViewById<Button>(R.id.settingsButton) }
     private val shutterButton by lazy { findViewById<ImageButton>(R.id.shutterButton) }
     private val timerButton by lazy { findViewById<Button>(R.id.timerButton) }
-    private val videoDuration by lazy { findViewById<MaterialButton>(R.id.videoDuration) }
+    private val videoDurationButton by lazy { findViewById<MaterialButton>(R.id.videoDurationButton) }
     private val videoFrameRateButton by lazy { findViewById<Button>(R.id.videoFrameRateButton) }
     private val videoModeButton by lazy { findViewById<MaterialButton>(R.id.videoModeButton) }
     private val videoQualityButton by lazy { findViewById<Button>(R.id.videoQualityButton) }
@@ -875,20 +876,31 @@
             // Update secondary bar buttons
             flashButton.isVisible = camera.hasFlashUnit
 
-            updateSecondaryBarButtons()
+            updateSecondaryTopBarButtons()
         }
 
         // Observe camera mode
         model.cameraMode.observe(this) {
             val cameraMode = it ?: return@observe
 
-            // Update secondary bar buttons
+            // Update secondary top bar buttons
             aspectRatioButton.isVisible = cameraMode != CameraMode.VIDEO
             videoQualityButton.isVisible = cameraMode == CameraMode.VIDEO
             videoFrameRateButton.isVisible = cameraMode == CameraMode.VIDEO
             micButton.isVisible = cameraMode == CameraMode.VIDEO
 
-            updateSecondaryBarButtons()
+            updateSecondaryTopBarButtons()
+
+            // Update secondary bottom bar buttons
+            secondaryBottomBarLayout.isVisible = cameraMode != CameraMode.QR
+
+            // Update primary bar buttons
+            primaryBarLayout.isVisible = cameraMode != CameraMode.QR
+
+            // Update Google Lens button
+            googleLensButton.isVisible = cameraMode == CameraMode.QR && isGoogleLensAvailable
+
+            updatePrimaryBarButtons()
 
             // Update camera mode buttons
             qrModeButton.isEnabled = cameraMode != CameraMode.QR
@@ -909,27 +921,6 @@
                     }
                 }.start()
             }
-
-            // Setup UI depending on camera mode
-            when (cameraMode) {
-                CameraMode.QR -> {
-                    secondaryBottomBarLayout.isVisible = false
-                    primaryBarLayoutGroupPhoto.isVisible = false
-                    googleLensButton.isVisible = isGoogleLensAvailable
-                }
-
-                CameraMode.PHOTO -> {
-                    secondaryBottomBarLayout.isVisible = true
-                    primaryBarLayoutGroupPhoto.isVisible = true
-                    googleLensButton.isVisible = false
-                }
-
-                CameraMode.VIDEO -> {
-                    secondaryBottomBarLayout.isVisible = true
-                    primaryBarLayoutGroupPhoto.isVisible = true
-                    googleLensButton.isVisible = false
-                }
-            }
         }
 
         // Observe single capture mode
@@ -940,10 +931,7 @@
             galleryButtonCardView.isInvisible = inSingleCaptureMode
 
             // Update camera mode buttons
-            cameraModeHighlight.isInvisible = inSingleCaptureMode
-            photoModeButton.isInvisible = inSingleCaptureMode
-            videoModeButton.isInvisible = inSingleCaptureMode
-            qrModeButton.isInvisible = inSingleCaptureMode
+            updateCameraModeButtons()
         }
 
         // Observe camera state
@@ -956,12 +944,21 @@
             effectButton.isEnabled = cameraState == CameraState.IDLE
             settingsButton.isEnabled = cameraState == CameraState.IDLE
 
-            updateSecondaryBarButtons()
+            updateSecondaryTopBarButtons()
 
             // Update primary bar buttons
             galleryButton.isEnabled = cameraState == CameraState.IDLE
             // Shutter button must stay enabled
             flipCameraButton.isEnabled = cameraState == CameraState.IDLE
+            videoRecordingStateButton.isVisible = cameraState.isRecordingVideo
+
+            updatePrimaryBarButtons()
+
+            // Update camera mode buttons
+            updateCameraModeButtons()
+
+            // Update video duration button
+            videoDurationButton.isVisible = cameraState.isRecordingVideo
         }
 
         // Observe screen rotation
@@ -1038,7 +1035,7 @@
         // Observe photo capture mode
         model.photoCaptureMode.observe(this) {
             // Update secondary bar buttons
-            updateSecondaryBarButtons()
+            updateSecondaryTopBarButtons()
         }
 
         // Observe photo aspect ratio
@@ -1124,7 +1121,7 @@
                 }
             )
 
-            updateSecondaryBarButtons()
+            updateSecondaryTopBarButtons()
         }
 
         // Observe video frame rate
@@ -1156,7 +1153,7 @@
         // Observe video recording
         model.videoRecording.observe(this) {
             // Update secondary bar buttons
-            updateSecondaryBarButtons()
+            updateSecondaryTopBarButtons()
         }
 
         // Request camera permissions
@@ -1444,6 +1441,9 @@
         // Disallow state changes while we are about to prepare for recording video
         cameraState = CameraState.PRE_RECORDING_VIDEO
 
+        // Update duration text
+        videoDurationButton.text = TimeUtils.convertNanosToString(0)
+
         // Create output options object which contains file + metadata
         val outputOptions = StorageUtils.getVideoMediaStoreOutputOptions(
             contentResolver,
@@ -1460,23 +1460,6 @@
                 videoAudioConfig,
                 cameraExecutor
             ) {
-                val updateRecordingStatus = { enabled: Boolean, duration: Long ->
-                    // Hide mode buttons
-                    photoModeButton.isInvisible = enabled || singleCaptureMode
-                    videoModeButton.isInvisible = enabled || singleCaptureMode
-                    qrModeButton.isInvisible = enabled || singleCaptureMode
-
-                    // Update duration text and visibility state
-                    videoDuration.text = TimeUtils.convertNanosToString(duration)
-                    videoDuration.isVisible = enabled
-
-                    // Update video recording pause/resume button visibility state
-                    if (duration == 0L) {
-                        flipCameraButton.isInvisible = enabled
-                        videoRecordingStateButton.isVisible = enabled
-                    }
-                }
-
                 when (it) {
                     is VideoRecordEvent.Start -> runOnUiThread {
                         cameraState = CameraState.RECORDING_VIDEO
@@ -1494,13 +1477,13 @@
                     }
 
                     is VideoRecordEvent.Status -> runOnUiThread {
-                        updateRecordingStatus(true, it.recordingStats.recordedDurationNanos)
+                        videoDurationButton.text =
+                            TimeUtils.convertNanosToString(it.recordingStats.recordedDurationNanos)
                     }
 
                     is VideoRecordEvent.Finalize -> {
                         runOnUiThread {
                             startShutterAnimation(ShutterAnimation.VideoEnd)
-                            updateRecordingStatus(false, 0)
                         }
                         cameraSoundsUtils.playStopVideoRecording()
                         if (it.error != VideoRecordEvent.Finalize.ERROR_NO_VALID_DATA) {
@@ -1903,7 +1886,7 @@
      * Some UI elements requires checking more than one value, this function will be called
      * when one of these values will change.
      */
-    private fun updateSecondaryBarButtons() {
+    private fun updateSecondaryTopBarButtons() {
         runOnUiThread {
             val camera = model.camera.value ?: return@runOnUiThread
             val cameraMode = model.cameraMode.value ?: return@runOnUiThread
@@ -1931,6 +1914,33 @@
         }
     }
 
+    /**
+     * Some UI elements requires checking more than one value, this function will be called
+     * when one of these values will change.
+     */
+    private fun updatePrimaryBarButtons() {
+        runOnUiThread {
+            val cameraMode = model.cameraMode.value ?: return@runOnUiThread
+            val cameraState = model.cameraState.value ?: return@runOnUiThread
+
+            flipCameraButton.isInvisible =
+                cameraMode == CameraMode.QR || cameraState.isRecordingVideo
+        }
+    }
+
+    /**
+     * Some UI elements requires checking more than one value, this function will be called
+     * when one of these values will change.
+     */
+    private fun updateCameraModeButtons() {
+        runOnUiThread {
+            val inSingleCaptureMode = model.inSingleCaptureMode.value ?: return@runOnUiThread
+            val cameraState = model.cameraState.value ?: return@runOnUiThread
+
+            cameraModeButtonsGroup.isInvisible = cameraState.isRecordingVideo || inSingleCaptureMode
+        }
+    }
+
     private fun cycleAspectRatio() {
         if (!canRestartCamera()) {
             return
diff --git a/app/src/main/java/org/lineageos/aperture/camera/CameraState.kt b/app/src/main/java/org/lineageos/aperture/camera/CameraState.kt
index 3ac06ac..02ebfe9 100644
--- a/app/src/main/java/org/lineageos/aperture/camera/CameraState.kt
+++ b/app/src/main/java/org/lineageos/aperture/camera/CameraState.kt
@@ -5,10 +5,12 @@
 
 package org.lineageos.aperture.camera
 
-enum class CameraState {
+enum class CameraState(
+    val isRecordingVideo: Boolean = false,
+) {
     IDLE,
     TAKING_PHOTO,
     PRE_RECORDING_VIDEO,
-    RECORDING_VIDEO,
-    RECORDING_VIDEO_PAUSED,
+    RECORDING_VIDEO(true),
+    RECORDING_VIDEO_PAUSED(true),
 }
diff --git a/app/src/main/res/layout/activity_camera.xml b/app/src/main/res/layout/activity_camera.xml
index 36e867b..139ee23 100644
--- a/app/src/main/res/layout/activity_camera.xml
+++ b/app/src/main/res/layout/activity_camera.xml
@@ -278,12 +278,6 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent">
 
-        <androidx.constraintlayout.widget.Group
-            android:id="@+id/primaryBarLayoutGroupPhoto"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:constraint_referenced_ids="galleryButtonCardView,shutterButton,flipCameraButton" />
-
         <ImageButton
             android:id="@+id/shutterButton"
             android:layout_width="75dp"
@@ -319,19 +313,6 @@
         </androidx.cardview.widget.CardView>
 
         <ImageButton
-            android:id="@+id/googleLensButton"
-            android:layout_width="60dp"
-            android:layout_height="60dp"
-            android:layout_marginStart="32dp"
-            android:background="@null"
-            android:contentDescription="@string/google_lens_button_description"
-            android:scaleType="center"
-            android:src="@drawable/ic_google_lens"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
-
-        <ImageButton
             android:id="@+id/flipCameraButton"
             android:layout_width="60dp"
             android:layout_height="60dp"
@@ -358,6 +339,19 @@
             app:layout_constraintTop_toTopOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
 
+    <ImageButton
+        android:id="@+id/googleLensButton"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:layout_marginStart="32dp"
+        android:background="@null"
+        android:contentDescription="@string/google_lens_button_description"
+        android:scaleType="center"
+        android:src="@drawable/ic_google_lens"
+        android:visibility="gone"
+        app:layout_constraintBottom_toTopOf="@+id/modeSelectorLayout"
+        app:layout_constraintStart_toStartOf="parent" />
+
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/modeSelectorLayout"
         android:layout_width="match_parent"
@@ -367,6 +361,12 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent">
 
+        <androidx.constraintlayout.widget.Group
+            android:id="@+id/cameraModeButtonsGroup"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            app:constraint_referenced_ids="cameraModeHighlight,photoModeButton,videoModeButton,qrModeButton" />
+
         <Button
             android:id="@+id/cameraModeHighlight"
             android:layout_width="wrap_content"
@@ -429,7 +429,7 @@
             app:layout_constraintTop_toTopOf="parent" />
 
         <Button
-            android:id="@+id/videoDuration"
+            android:id="@+id/videoDurationButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:backgroundTint="@color/rec_red"