@@ -2,6 +2,12 @@ package com.foke.together.presenter.screen
22
33import android.content.Context
44import androidx.camera.view.PreviewView
5+ import androidx.compose.animation.core.animateFloatAsState
6+ import androidx.compose.animation.core.tween
7+ import androidx.compose.animation.AnimatedVisibility
8+ import androidx.compose.animation.scaleIn
9+ import androidx.compose.animation.scaleOut
10+ import androidx.compose.foundation.background
511import androidx.compose.foundation.layout.Arrangement
612import androidx.compose.foundation.layout.Box
713import androidx.compose.foundation.layout.Column
@@ -11,6 +17,7 @@ import androidx.compose.foundation.layout.fillMaxSize
1117import androidx.compose.foundation.layout.fillMaxWidth
1218import androidx.compose.foundation.layout.padding
1319import androidx.compose.foundation.layout.wrapContentHeight
20+ import androidx.compose.foundation.shape.RoundedCornerShape
1421import androidx.compose.material3.BottomAppBar
1522import androidx.compose.material3.ExperimentalMaterial3Api
1623import androidx.compose.material3.Text
@@ -20,12 +27,16 @@ import androidx.compose.runtime.mutableStateOf
2027import androidx.compose.runtime.remember
2128import androidx.compose.ui.Alignment
2229import androidx.compose.ui.Modifier
30+ import androidx.compose.ui.draw.alpha
31+ import androidx.compose.ui.draw.clip
32+ import androidx.compose.ui.graphics.Color
2333import androidx.compose.ui.platform.LocalContext
2434import androidx.compose.ui.res.stringResource
2535import androidx.compose.ui.text.font.FontWeight
2636import androidx.compose.ui.text.style.TextAlign
2737import androidx.compose.ui.tooling.preview.Devices
2838import androidx.compose.ui.tooling.preview.Preview
39+ import androidx.compose.ui.unit.dp
2940import androidx.compose.ui.unit.sp
3041import androidx.compose.ui.viewinterop.AndroidView
3142import androidx.hilt.navigation.compose.hiltViewModel
@@ -34,9 +45,11 @@ import androidx.lifecycle.compose.LifecycleEventEffect
3445import androidx.lifecycle.compose.LocalLifecycleOwner
3546import androidx.lifecycle.compose.collectAsStateWithLifecycle
3647import com.foke.together.presenter.R
48+ import com.foke.together.presenter.component.AppBottomBar
3749import com.foke.together.presenter.component.AppTopBar
3850import com.foke.together.presenter.component.BasicScaffold
3951import com.foke.together.presenter.screen.state.InternalCameraState
52+ import com.foke.together.presenter.theme.AppTheme
4053import com.foke.together.presenter.theme.FourCutTogetherTheme
4154import com.foke.together.presenter.viewmodel.InternelCameraViewModel
4255import com.foke.together.util.AppLog
@@ -55,6 +68,8 @@ fun InternalCameraScreenRoot(
5568 val context = LocalContext .current
5669 val captureCount by viewModel.captureCount.collectAsStateWithLifecycle()
5770 val progress by viewModel.progressState.collectAsStateWithLifecycle()
71+ val isFlashAnimationVisible by viewModel.flashAnimationState.collectAsStateWithLifecycle()
72+ val countdownSeconds by viewModel.countdownSeconds.collectAsStateWithLifecycle()
5873 LifecycleEventEffect (Lifecycle .Event .ON_START ) {
5974 viewModel.setCaptureTimer(context) { navigateToGenerateImage() }
6075 AppLog .d(TAG , " LifecycleEventEffect. ON_START" , " " )
@@ -71,6 +86,8 @@ fun InternalCameraScreenRoot(
7186 state = state,
7287 captureCount = captureCount,
7388 progress = progress,
89+ isFlashAnimationVisible = isFlashAnimationVisible,
90+ countdownSeconds = countdownSeconds,
7491 initialPreview = { context, previewView ->
7592 viewModel.initial(context, lifecycleOwner, previewView)
7693 },
@@ -86,9 +103,16 @@ fun InternalCameraScreen(
86103 state : InternalCameraState ,
87104 captureCount : Int ,
88105 progress : Float ,
106+ isFlashAnimationVisible : Boolean ,
107+ countdownSeconds : Int ,
89108 initialPreview : (Context , PreviewView ) -> Unit ,
90109 releasePreview : (Context ) -> Unit ,
91110){
111+ val previewAlpha by animateFloatAsState(
112+ targetValue = if (isFlashAnimationVisible) 0.0f else 1.0f ,
113+ animationSpec = tween(durationMillis = if (isFlashAnimationVisible) 50 else 150 ),
114+ label = " preview_alpha"
115+ )
92116 BasicScaffold (
93117 modifier = Modifier .fillMaxSize(),
94118 topBar = {
@@ -98,7 +122,14 @@ fun InternalCameraScreen(
98122 )
99123 },
100124 bottomBar = {
101- BottomAppBar { }
125+ AppBottomBar {
126+ Text (
127+ modifier = Modifier .fillMaxWidth().wrapContentHeight(),
128+ text = stringResource(id = R .string.camera_exclamation_text),
129+ style = AppTheme .typography.title,
130+ textAlign = TextAlign .Center
131+ )
132+ }
102133 }
103134 ){ paddingValues ->
104135 Column (
@@ -111,28 +142,50 @@ fun InternalCameraScreen(
111142 verticalArrangement = Arrangement .SpaceEvenly ,
112143 horizontalAlignment = Alignment .CenterHorizontally ,
113144 ){
114- Text (
115- modifier = Modifier .fillMaxWidth().wrapContentHeight(),
116- text = stringResource(id = R .string.camera_exclamation_text),
117- fontWeight = FontWeight .Bold ,
118- fontSize = 24 .sp,
119- textAlign = TextAlign .Center
120- )
121145 Box (
122- modifier = Modifier .aspectRatio(1.5f ).fillMaxHeight()
146+ modifier = Modifier .aspectRatio(1.5f ).fillMaxHeight(0.8f ),
123147 ) {
124148 AndroidView (
125- modifier = Modifier .align(Alignment .Center ).fillMaxSize(),
149+ modifier = Modifier
150+ .align(Alignment .Center )
151+ .fillMaxSize()
152+ .clip(RoundedCornerShape (AppTheme .size.icon))
153+ .alpha(previewAlpha)
154+ .background(
155+ color = AppTheme .colorScheme.bottom
156+ ),
126157 factory = { context ->
127158 PreviewView (context).also { preview ->
128159 initialPreview(context, preview)
160+
129161 }
130162 },
131163 onRelease = { previewView ->
132164 releasePreview(previewView.context)
133165 }
134-
135166 )
167+
168+ // Countdown overlay
169+ this @Column.AnimatedVisibility (
170+ visible = countdownSeconds > 0 ,
171+ enter = scaleIn(),
172+ exit = scaleOut(),
173+ modifier = Modifier .align(Alignment .Center )
174+ ) {
175+ Text (
176+ text = countdownSeconds.toString(),
177+ fontSize = 80 .sp,
178+ fontWeight = FontWeight .Bold ,
179+ color = Color .White ,
180+ modifier = Modifier
181+ .background(
182+ Color .Black .copy(alpha = 0.5f ),
183+ shape = AppTheme .shapes.container
184+ )
185+ .padding(24 .dp)
186+ )
187+ }
188+
136189 }
137190 }
138191 }
@@ -147,11 +200,15 @@ fun InternalScreenPreview(){
147200 val state by remember { mutableStateOf(InternalCameraState ()) }
148201 val captureCount by remember{ mutableStateOf(1 ) }
149202 val progress by remember{ mutableStateOf(1f )}
203+ val isFlashAnimationVisible by remember{ mutableStateOf(false )}
204+ val countdownSeconds by remember{ mutableStateOf(3 )}
150205 FourCutTogetherTheme () {
151206 InternalCameraScreen (
152207 state = state,
153208 captureCount = captureCount,
154209 progress = progress,
210+ isFlashAnimationVisible = isFlashAnimationVisible,
211+ countdownSeconds = countdownSeconds,
155212 initialPreview = { context, previewView ->
156213
157214 },
0 commit comments