Aperture: Implement timer
Change-Id: If01b6ae761eb2f80f75e771026d0a6931fdd2652
diff --git a/app/src/main/java/org/lineageos/aperture/MainActivity.kt b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
index 316500b..ac96bc6 100644
--- a/app/src/main/java/org/lineageos/aperture/MainActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
@@ -48,9 +48,12 @@
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.google.android.material.chip.Chip
import com.google.android.material.slider.Slider
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import org.lineageos.aperture.ui.GridView
import org.lineageos.aperture.utils.CameraFacing
import org.lineageos.aperture.utils.CameraMode
@@ -75,6 +78,8 @@
private val recordChip by lazy { findViewById<Chip>(R.id.recordChip) }
private val settingsButton by lazy { findViewById<ImageView>(R.id.settingsButton) }
private val shutterButton by lazy { findViewById<ImageView>(R.id.shutterButton) }
+ private val timerButton by lazy { findViewById<ImageView>(R.id.timerButton) }
+ private val timerChip by lazy { findViewById<Chip>(R.id.timerChip) }
private val torchButton by lazy { findViewById<ImageView>(R.id.torchButton) }
private val videoModeButton by lazy { findViewById<ImageView>(R.id.videoModeButton) }
private val viewFinder by lazy { findViewById<PreviewView>(R.id.viewFinder) }
@@ -147,6 +152,7 @@
effectButton.setOnClickListener { cyclePhotoEffects() }
gridButton.setOnClickListener { toggleGrid() }
+ timerButton.setOnClickListener { toggleTimerMode() }
torchButton.setOnClickListener { toggleTorchMode() }
flashButton.setOnClickListener { cycleFlashMode() }
settingsButton.setOnClickListener { openSettings() }
@@ -163,9 +169,11 @@
flipCameraButton.setOnClickListener { flipCamera() }
shutterButton.setOnClickListener {
- when (cameraMode) {
- CameraMode.PHOTO -> takePhoto()
- CameraMode.VIDEO -> captureVideo()
+ startTimerAndRun {
+ when (cameraMode) {
+ CameraMode.PHOTO -> takePhoto()
+ CameraMode.VIDEO -> captureVideo()
+ }
}
}
@@ -299,12 +307,12 @@
@androidx.camera.view.video.ExperimentalVideo
private fun canRestartCamera(): Boolean {
if (cameraMode == CameraMode.PHOTO) {
- // Check if we're taking a photo
- if (isTakingPhoto)
+ // Check if we're taking a photo or if timer is running
+ if (isTakingPhoto || timerChip.isVisible)
return false
} else if (cameraMode == CameraMode.VIDEO) {
- // Check for a recording in progress
- if (cameraController.isRecording)
+ // Check for a recording in progress or if timer is running
+ if (cameraController.isRecording || timerChip.isVisible)
return false
}
@@ -462,6 +470,7 @@
// Update icons from last state
updateCameraModeButtons()
toggleRecordingChipVisibility()
+ updateTimerModeIcon()
updatePhotoEffectIcon()
updateGridIcon()
updateFlashModeIcon()
@@ -556,6 +565,34 @@
}
/**
+ * Update the timer mode button icon based on the value set in settings
+ */
+ private fun updateTimerModeIcon() {
+ timerButton.setImageDrawable(
+ ContextCompat.getDrawable(
+ this,
+ when (sharedPreferences.timerMode) {
+ 3 -> R.drawable.ic_timer_3
+ 10 -> R.drawable.ic_timer_10
+ else -> R.drawable.ic_timer_off
+ }
+ )
+ )
+ }
+
+ /**
+ * Toggle timer mode
+ */
+ private fun toggleTimerMode() {
+ sharedPreferences.timerMode = when (sharedPreferences.timerMode) {
+ 0 -> 3
+ 3 -> 10
+ else -> 0
+ }
+ updateTimerModeIcon()
+ }
+
+ /**
* Update the torch mode button icon based on the value set in camera
*/
private fun updateTorchModeIcon() {
@@ -830,6 +867,29 @@
}
}
+ @androidx.camera.view.video.ExperimentalVideo
+ private fun startTimerAndRun(runnable: () -> Unit) {
+ if (sharedPreferences.timerMode <= 0 || !canRestartCamera()) {
+ runnable()
+ return
+ }
+
+ lifecycleScope.launch {
+ shutterButton.isEnabled = false
+ timerChip.isVisible = true
+
+ for (i in sharedPreferences.timerMode downTo 0) {
+ timerChip.text = "$i"
+ delay(1000)
+ }
+
+ timerChip.isVisible = false
+ shutterButton.isEnabled = true
+
+ runnable()
+ }
+ }
+
companion object {
private const val LOG_TAG = "Aperture"
diff --git a/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt b/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt
index 7872d95..d2ca50c 100644
--- a/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt
+++ b/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt
@@ -226,6 +226,20 @@
}
}
+// Timer mode
+private const val TIMER_MODE_KEY = "timer_mode"
+private const val TIMER_MODE_DEFAULT = 0
+
+internal var SharedPreferences.timerMode: Int
+ get() {
+ return getInt(TIMER_MODE_KEY, TIMER_MODE_DEFAULT)
+ }
+ set(value) {
+ edit {
+ putInt(TIMER_MODE_KEY, value)
+ }
+ }
+
// Last saved URI
private const val LAST_SAVED_URI_KEY = "saved_uri"
diff --git a/app/src/main/res/drawable/ic_timer_10.xml b/app/src/main/res/drawable/ic_timer_10.xml
new file mode 100644
index 0000000..2d4f946
--- /dev/null
+++ b/app/src/main/res/drawable/ic_timer_10.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.75,17.225H10.55V8.775H7.55V10.6H8.75ZM13.2,17.225H14.4Q15.15,17.225 15.688,16.7Q16.225,16.175 16.225,15.425V10.6Q16.225,9.85 15.688,9.312Q15.15,8.775 14.4,8.775H13.2Q12.45,8.775 11.925,9.312Q11.4,9.85 11.4,10.6V15.425Q11.4,16.175 11.925,16.7Q12.45,17.225 13.2,17.225ZM13.2,15.425Q13.2,15.425 13.2,15.425Q13.2,15.425 13.2,15.425V10.6Q13.2,10.6 13.2,10.6Q13.2,10.6 13.2,10.6H14.4Q14.4,10.6 14.4,10.6Q14.4,10.6 14.4,10.6V15.425Q14.4,15.425 14.4,15.425Q14.4,15.425 14.4,15.425ZM9,3V1H15V3ZM12,22Q10.15,22 8.512,21.288Q6.875,20.575 5.65,19.35Q4.425,18.125 3.712,16.488Q3,14.85 3,13Q3,11.15 3.712,9.512Q4.425,7.875 5.65,6.65Q6.875,5.425 8.512,4.713Q10.15,4 12,4Q13.55,4 14.975,4.5Q16.4,5 17.65,5.95L19.05,4.55L20.45,5.95L19.05,7.35Q20,8.6 20.5,10.025Q21,11.45 21,13Q21,14.85 20.288,16.488Q19.575,18.125 18.35,19.35Q17.125,20.575 15.488,21.288Q13.85,22 12,22ZM12,20Q14.9,20 16.95,17.95Q19,15.9 19,13Q19,10.1 16.95,8.05Q14.9,6 12,6Q9.1,6 7.05,8.05Q5,10.1 5,13Q5,15.9 7.05,17.95Q9.1,20 12,20Z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_timer_3.xml b/app/src/main/res/drawable/ic_timer_3.xml
new file mode 100644
index 0000000..30c1d4a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_timer_3.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8.95,17.225H13.175Q14.05,17.225 14.675,16.688Q15.3,16.15 15.3,15.4V14.1Q15.3,13.525 14.838,13.137Q14.375,12.75 13.725,12.75Q14.375,12.75 14.838,12.35Q15.3,11.95 15.3,11.375V10.575Q15.3,9.825 14.675,9.3Q14.05,8.775 13.175,8.775H8.95V10.575H13.175V11.85H11.075V13.65H13.175V15.4H8.95ZM9,3V1H15V3ZM12,22Q10.15,22 8.512,21.288Q6.875,20.575 5.65,19.35Q4.425,18.125 3.712,16.488Q3,14.85 3,13Q3,11.15 3.712,9.512Q4.425,7.875 5.65,6.65Q6.875,5.425 8.512,4.713Q10.15,4 12,4Q13.55,4 14.975,4.5Q16.4,5 17.65,5.95L19.05,4.55L20.45,5.95L19.05,7.35Q20,8.6 20.5,10.025Q21,11.45 21,13Q21,14.85 20.288,16.488Q19.575,18.125 18.35,19.35Q17.125,20.575 15.488,21.288Q13.85,22 12,22ZM12,20Q14.9,20 16.95,17.95Q19,15.9 19,13Q19,10.1 16.95,8.05Q14.9,6 12,6Q9.1,6 7.05,8.05Q5,10.1 5,13Q5,15.9 7.05,17.95Q9.1,20 12,20Z" />
+</vector>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 1be3332..6b30374 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -158,6 +158,19 @@
app:layout_constraintTop_toBottomOf="@+id/topButtonsLayout"
app:rippleColor="#00ffffff" />
+ <com.google.android.material.chip.Chip
+ android:id="@+id/timerChip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:textColor="@color/white"
+ android:visibility="gone"
+ app:chipSurfaceColor="@color/black"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/topButtonsLayout"
+ app:rippleColor="#00ffffff" />
+
<com.google.android.material.slider.Slider
android:id="@+id/zoomLevel"
android:layout_width="250dp"