diff --git a/CHANGELOG.md b/CHANGELOG.md
index f56c083f..3b2413ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changed
- Swapped positions of camera switch and image preview buttons ([#157])
+- Updated and animated the switch camera button
## [1.2.0] - 2025-09-09
### Added
diff --git a/app/src/main/kotlin/org/fossify/camera/activities/MainActivity.kt b/app/src/main/kotlin/org/fossify/camera/activities/MainActivity.kt
index 4b77e826..6ea43a1f 100644
--- a/app/src/main/kotlin/org/fossify/camera/activities/MainActivity.kt
+++ b/app/src/main/kotlin/org/fossify/camera/activities/MainActivity.kt
@@ -1,7 +1,7 @@
package org.fossify.camera.activities
+import android.animation.ObjectAnimator
import android.annotation.SuppressLint
-import android.app.Activity
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
@@ -15,6 +15,7 @@ import android.widget.LinearLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.content.ContextCompat
import androidx.core.view.*
+import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.transition.*
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
@@ -45,11 +46,12 @@ import kotlin.math.abs
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
private companion object {
- const val CAPTURE_ANIMATION_DURATION = 500L
- const val PHOTO_MODE_INDEX = 1
- const val VIDEO_MODE_INDEX = 0
+ private const val ANIMATION_DURATION = 500L
+ private const val PHOTO_MODE_INDEX = 1
+ private const val VIDEO_MODE_INDEX = 0
private const val MIN_SWIPE_DISTANCE_X = 100
private const val TIMER_2_SECONDS = 2001
+ private const val SWITCH_CAMERA_ROTATION_ANGLE = 180f
}
private val binding by viewBinding(ActivityMainBinding::inflate)
@@ -372,7 +374,11 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
private fun initButtons() = binding.apply {
timerText.setFactory { layoutInflater.inflate(R.layout.timer_text, null) }
- toggleCamera.setOnClickListener { mPreview!!.toggleFrontBackCamera() }
+ toggleCamera.setOnClickListener {
+ animateCameraToggle()
+ mPreview!!.toggleFrontBackCamera()
+ }
+
lastPhotoVideoPreview.setOnClickListener { showLastMediaPreview() }
layoutTop.apply {
@@ -423,6 +429,15 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
setTimerModeIcon(config.timerMode)
}
+ private fun animateCameraToggle() {
+ ObjectAnimator.ofFloat(binding.toggleCamera, "rotation", 0f, SWITCH_CAMERA_ROTATION_ANGLE)
+ .apply {
+ duration = ANIMATION_DURATION
+ interpolator = FastOutSlowInInterpolator()
+ start()
+ }
+ }
+
private fun selectTimerMode(timerMode: TimerMode) {
config.timerMode = timerMode
setTimerModeIcon(timerMode)
@@ -565,7 +580,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
runOnUiThread {
if (!isDestroyed) {
val options = RequestOptions()
- .centerCrop()
+ .circleCrop()
.diskCacheStrategy(DiskCacheStrategy.NONE)
Glide.with(this)
@@ -685,10 +700,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
}
- override fun onChangeCamera(frontCamera: Boolean) {
- binding.toggleCamera.setImageResource(if (frontCamera) R.drawable.ic_camera_rear_vector else R.drawable.ic_camera_front_vector)
- }
-
override fun onPhotoCaptureStart() {
toggleActionButtons(enabled = false)
}
@@ -709,7 +720,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
override fun shutterAnimation() {
binding.shutterAnimation.alpha = 1.0f
- binding.shutterAnimation.animate().alpha(0f).setDuration(CAPTURE_ANIMATION_DURATION).start()
+ binding.shutterAnimation.animate().alpha(0f).setDuration(ANIMATION_DURATION).start()
}
override fun onMediaSaved(uri: Uri) {
@@ -719,14 +730,14 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
Intent().apply {
data = uri
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- setResult(Activity.RESULT_OK, this)
+ setResult(RESULT_OK, this)
}
finish()
} else if (isVideoCaptureIntent()) {
Intent().apply {
data = uri
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- setResult(Activity.RESULT_OK, this)
+ setResult(RESULT_OK, this)
}
finish()
}
@@ -736,7 +747,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
if (isImageCaptureIntent()) {
Intent().apply {
putExtra("data", bitmap)
- setResult(Activity.RESULT_OK, this)
+ setResult(RESULT_OK, this)
}
finish()
}
@@ -967,7 +978,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
if (isImageCaptureIntent()) {
- setResult(Activity.RESULT_OK)
+ setResult(RESULT_OK)
finish()
}
}
diff --git a/app/src/main/kotlin/org/fossify/camera/implementations/CameraXPreviewListener.kt b/app/src/main/kotlin/org/fossify/camera/implementations/CameraXPreviewListener.kt
index e5c7c454..98192e15 100644
--- a/app/src/main/kotlin/org/fossify/camera/implementations/CameraXPreviewListener.kt
+++ b/app/src/main/kotlin/org/fossify/camera/implementations/CameraXPreviewListener.kt
@@ -10,7 +10,7 @@ interface CameraXPreviewListener {
fun setCameraAvailable(available: Boolean) {}
fun setHasFrontAndBackCamera(hasFrontAndBack: Boolean)
fun setFlashAvailable(available: Boolean)
- fun onChangeCamera(frontCamera: Boolean)
+ fun onChangeCamera(frontCamera: Boolean) {}
fun shutterAnimation()
fun onMediaSaved(uri: Uri)
fun onImageCaptured(bitmap: Bitmap)
diff --git a/app/src/main/res/drawable/camera_button_background.xml b/app/src/main/res/drawable/camera_button_background.xml
new file mode 100644
index 00000000..dfa235fc
--- /dev/null
+++ b/app/src/main/res/drawable/camera_button_background.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_camera_front_vector.xml b/app/src/main/res/drawable/ic_camera_front_vector.xml
deleted file mode 100644
index 8ea93d6f..00000000
--- a/app/src/main/res/drawable/ic_camera_front_vector.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_camera_rear_vector.xml b/app/src/main/res/drawable/ic_camera_rear_vector.xml
deleted file mode 100644
index e213dd9b..00000000
--- a/app/src/main/res/drawable/ic_camera_rear_vector.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_flip_camera_vector.xml b/app/src/main/res/drawable/ic_flip_camera_vector.xml
new file mode 100644
index 00000000..216fec39
--- /dev/null
+++ b/app/src/main/res/drawable/ic_flip_camera_vector.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 79349bf2..7446e465 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -112,13 +112,13 @@
tools:text="00:00"
tools:visibility="visible" />
-
- 64dp
+ 56dp
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index fbe9cde2..dab58bdf 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,6 +1,6 @@
- 56dp
+ 48dp
72dp
48dp
24dp