add transitions,

This commit is contained in:
darthpaul 2022-09-20 00:58:39 +01:00
parent 77994d408e
commit f41e8cc4e0
3 changed files with 119 additions and 94 deletions

View File

@ -11,11 +11,13 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.MediaStore import android.provider.MediaStore
import android.view.* import android.view.*
import android.view.animation.OvershootInterpolator
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.* import androidx.core.view.*
import androidx.transition.*
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
@ -43,15 +45,22 @@ import kotlinx.android.synthetic.main.layout_flash.flash_off
import kotlinx.android.synthetic.main.layout_flash.flash_on import kotlinx.android.synthetic.main.layout_flash.flash_on
import kotlinx.android.synthetic.main.layout_flash.flash_toggle_group import kotlinx.android.synthetic.main.layout_flash.flash_toggle_group
import kotlinx.android.synthetic.main.layout_media_size.media_size_toggle_group import kotlinx.android.synthetic.main.layout_media_size.media_size_toggle_group
import kotlinx.android.synthetic.main.layout_top.change_resolution
import kotlinx.android.synthetic.main.layout_top.default_icons
import kotlinx.android.synthetic.main.layout_top.settings
import kotlinx.android.synthetic.main.layout_top.toggle_flash
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener { class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
companion object { private companion object {
private const val CAPTURE_ANIMATION_DURATION = 500L const val CAPTURE_ANIMATION_DURATION = 500L
private const val PHOTO_MODE_INDEX = 1 const val PHOTO_MODE_INDEX = 1
private const val VIDEO_MODE_INDEX = 0 const val VIDEO_MODE_INDEX = 0
} }
lateinit var mTimerHandler: Handler lateinit var mTimerHandler: Handler
private lateinit var defaultScene: Scene
private lateinit var mediaSizeScene: Scene
private lateinit var flashModeScene: Scene
private lateinit var mOrientationEventListener: OrientationEventListener private lateinit var mOrientationEventListener: OrientationEventListener
private lateinit var mFocusCircleView: FocusCircleView private lateinit var mFocusCircleView: FocusCircleView
private lateinit var mCameraImpl: MyCameraImpl private lateinit var mCameraImpl: MyCameraImpl
@ -269,14 +278,16 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
initButtons() initButtons()
defaultScene = Scene(top_options, default_icons)
mediaSizeScene = Scene(top_options, media_size_toggle_group)
flashModeScene = Scene(top_options, flash_toggle_group)
ViewCompat.setOnApplyWindowInsetsListener(view_holder) { _, windowInsets -> ViewCompat.setOnApplyWindowInsetsListener(view_holder) { _, windowInsets ->
val safeInsetBottom = windowInsets.displayCutout?.safeInsetBottom ?: 0 val safeInsetBottom = windowInsets.displayCutout?.safeInsetBottom ?: 0
val safeInsetTop = windowInsets.displayCutout?.safeInsetTop ?: 0 val safeInsetTop = windowInsets.displayCutout?.safeInsetTop ?: 0
listOf(toggle_flash, flash_toggle_group, media_size_toggle_group).forEach { view -> top_options.updateLayoutParams<ViewGroup.MarginLayoutParams> {
view.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin = safeInsetTop
topMargin = safeInsetTop
}
} }
val marginBottom = safeInsetBottom + navigationBarHeight + resources.getDimensionPixelSize(R.dimen.bigger_margin) val marginBottom = safeInsetBottom + navigationBarHeight + resources.getDimensionPixelSize(R.dimen.bigger_margin)
@ -321,6 +332,14 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
val initialFlashlightState = FLASH_OFF val initialFlashlightState = FLASH_OFF
mPreview!!.setFlashlightState(initialFlashlightState) mPreview!!.setFlashlightState(initialFlashlightState)
updateFlashlightState(initialFlashlightState) updateFlashlightState(initialFlashlightState)
initFlashModeTransitionNames()
}
private fun initFlashModeTransitionNames() {
val baseName = getString(R.string.toggle_flash)
flash_auto.transitionName = "$baseName$FLASH_AUTO"
flash_off.transitionName = "$baseName$FLASH_OFF"
flash_on.transitionName = "$baseName$FLASH_ON"
} }
private fun initButtons() { private fun initButtons() {
@ -371,6 +390,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
else -> R.drawable.ic_flash_auto_vector else -> R.drawable.ic_flash_auto_vector
} }
toggle_flash.setImageResource(flashDrawable) toggle_flash.setImageResource(flashDrawable)
toggle_flash.transitionName = "${getString(R.string.toggle_flash)}$state"
} }
private fun shutterPressed() { private fun shutterPressed() {
@ -678,23 +698,21 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
} }
private fun closeOptions(): Boolean { private fun closeOptions(): Boolean {
if (media_size_toggle_group.isVisible()) { if (media_size_toggle_group.isVisible() ||
media_size_toggle_group.beGone() flash_toggle_group.isVisible()
showTopIcons() ) {
val transitionSet = createTransition()
TransitionManager.go(defaultScene, transitionSet)
return true return true
} }
if (flash_toggle_group.isVisible()) {
flash_toggle_group.beGone()
showTopIcons()
return true
}
return false return false
} }
override fun displaySelectedResolution(resolutionOption: ResolutionOption) { override fun displaySelectedResolution(resolutionOption: ResolutionOption) {
val imageRes = resolutionOption.imageDrawableResId val imageRes = resolutionOption.imageDrawableResId
change_resolution.setImageResource(imageRes) change_resolution.setImageResource(imageRes)
change_resolution.transitionName = "${resolutionOption.buttonViewId}"
} }
override fun showImageSizes( override fun showImageSizes(
@ -732,6 +750,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
layoutParams = params layoutParams = params
icon = AppCompatResources.getDrawable(context, resolutionOption.imageDrawableResId) icon = AppCompatResources.getDrawable(context, resolutionOption.imageDrawableResId)
id = resolutionOption.buttonViewId id = resolutionOption.buttonViewId
transitionName = "${resolutionOption.buttonViewId}"
setOnClickListener { setOnClickListener {
onClick.invoke(id) onClick.invoke(id)
} }
@ -739,28 +758,33 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
} }
private fun showResolutionOptions() { private fun showResolutionOptions() {
hideTopIcons() val transitionSet = createTransition()
media_size_toggle_group.beVisible() TransitionManager.go(mediaSizeScene, transitionSet)
media_size_toggle_group.children.map { it as MaterialButton }.forEach(::setButtonColors) media_size_toggle_group.children.map { it as MaterialButton }.forEach(::setButtonColors)
} }
private fun createTransition(): Transition {
val fadeTransition = Fade()
val changeBounds = ChangeBounds().apply {
interpolator = OvershootInterpolator()
}
return TransitionSet().apply {
addTransition(changeBounds)
addTransition(fadeTransition)
this.duration = 200L
}
}
override fun showFlashOptions(photoCapture: Boolean) { override fun showFlashOptions(photoCapture: Boolean) {
val transitionSet = createTransition()
TransitionManager.go(flashModeScene, transitionSet)
flash_auto.beVisibleIf(photoCapture) flash_auto.beVisibleIf(photoCapture)
hideTopIcons()
flash_toggle_group.beVisible()
flash_toggle_group.check(config.flashlightState.toFlashModeId()) flash_toggle_group.check(config.flashlightState.toFlashModeId())
flash_toggle_group.beVisible()
flash_toggle_group.children.map { it as MaterialButton }.forEach(::setButtonColors) flash_toggle_group.children.map { it as MaterialButton }.forEach(::setButtonColors)
} }
private fun showTopIcons() {
listOf(toggle_flash, change_resolution).forEach { it.beVisible() }
settings.beVisibleIf(!is3rdPartyIntent())
}
private fun hideTopIcons() {
listOf(toggle_flash, change_resolution, settings).forEach { it.beInvisible() }
}
private fun setButtonColors(button: MaterialButton) { private fun setButtonColors(button: MaterialButton) {
val primaryColor = getProperPrimaryColor() val primaryColor = getProperPrimaryColor()
val states = arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)) val states = arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked))

View File

@ -5,8 +5,8 @@
android:id="@+id/view_holder" android:id="@+id/view_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/black"
android:animateLayoutChanges="true" android:animateLayoutChanges="true"
android:background="@android:color/black"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">
<androidx.camera.view.PreviewView <androidx.camera.view.PreviewView
@ -14,6 +14,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<View <View
android:id="@+id/shutter_animation" android:id="@+id/shutter_animation"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -21,78 +22,25 @@
android:alpha="0" android:alpha="0"
android:background="@android:color/black" /> android:background="@android:color/black" />
<include <FrameLayout
layout="@layout/layout_media_size" android:id="@+id/top_options"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/settings"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent">
tools:visibility="visible" />
<include <include layout="@layout/layout_top" />
layout="@layout/layout_flash"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/settings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<ImageView <include
android:id="@+id/toggle_flash" layout="@layout/layout_media_size"
android:layout_width="@dimen/top_icon_size" />
android:layout_height="@dimen/top_icon_size"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:layout_weight="1"
android:contentDescription="@string/toggle_flash"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flash_off_vector"
app:layout_constraintEnd_toStartOf="@id/change_resolution"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include
layout="@layout/layout_flash"
android:visibility="gone" />
<ImageView </FrameLayout>
android:id="@+id/change_resolution"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:contentDescription="@string/resolution"
android:padding="@dimen/normal_margin"
app:layout_constraintEnd_toStartOf="@id/settings"
app:layout_constraintStart_toEndOf="@id/toggle_flash"
app:layout_constraintTop_toTopOf="@id/toggle_flash"
tools:src="@drawable/ic_photo_4x3" />
<ImageView
android:id="@+id/settings"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:contentDescription="@string/settings"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_settings_cog_vector"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/change_resolution"
app:layout_constraintTop_toTopOf="@id/toggle_flash" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/top_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="settings,change_resolution,toggle_flash" />
<View <View
android:id="@+id/bottom_overlay" android:id="@+id/bottom_overlay"

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/default_icons"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/toggle_flash"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:layout_weight="1"
android:contentDescription="@string/toggle_flash"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flash_off_vector"
app:layout_constraintEnd_toStartOf="@id/change_resolution"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/change_resolution"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:contentDescription="@string/resolution"
android:padding="@dimen/normal_margin"
android:transitionName="one_by_one"
app:layout_constraintEnd_toStartOf="@id/settings"
app:layout_constraintStart_toEndOf="@id/toggle_flash"
app:layout_constraintTop_toTopOf="@id/toggle_flash"
tools:src="@drawable/ic_photo_4x3" />
<ImageView
android:id="@+id/settings"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:contentDescription="@string/settings"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_settings_cog_vector"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/change_resolution"
app:layout_constraintTop_toTopOf="@id/toggle_flash" />
</androidx.constraintlayout.widget.ConstraintLayout>