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