mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
feat: Add more animations to recording start
This commit is contained in:
parent
b6346ef0e3
commit
096cf56436
@ -1,42 +0,0 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.atoms
|
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.animation.expandHorizontally
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RecordingProgress(
|
|
||||||
recordingTime: Long,
|
|
||||||
progress: Float,
|
|
||||||
) {
|
|
||||||
// Only show animation when the recording has just started
|
|
||||||
val recordingJustStarted = recordingTime <= 1L
|
|
||||||
var progressVisible by remember { mutableStateOf(!recordingJustStarted) }
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
progressVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = progressVisible,
|
|
||||||
enter = expandHorizontally(
|
|
||||||
tween(1000)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
LinearProgressIndicator(
|
|
||||||
progress = progress,
|
|
||||||
modifier = Modifier
|
|
||||||
.width(300.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.atoms
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import app.myzel394.alibi.ui.components.atoms.Pulsating
|
|
||||||
import app.myzel394.alibi.ui.utils.formatDuration
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RecordingTime(
|
|
||||||
time: Long,
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
) {
|
|
||||||
Pulsating {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(16.dp)
|
|
||||||
.clip(CircleShape)
|
|
||||||
.background(Color.Red)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
Text(
|
|
||||||
text = formatDuration(time * 1000),
|
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +1,103 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.EaseOutElastic
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.animation.core.spring
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.DeleteButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.DeleteButton
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.PauseResumeButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.PauseResumeButton
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveButton
|
||||||
|
import app.myzel394.alibi.ui.utils.RandomStack
|
||||||
|
import app.myzel394.alibi.ui.utils.rememberInitialRecordingAnimation
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RecordingControl(
|
fun RecordingControl(
|
||||||
isPaused: Boolean,
|
isPaused: Boolean,
|
||||||
|
recordingTime: Long,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
onPauseResume: () -> Unit,
|
onPauseResume: () -> Unit,
|
||||||
onSave: () -> Unit,
|
onSave: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val animateIn = rememberInitialRecordingAnimation(recordingTime)
|
||||||
|
|
||||||
|
var deleteButtonAlphaIsIn by rememberSaveable {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
val deleteButtonAlpha by animateFloatAsState(
|
||||||
|
if (deleteButtonAlphaIsIn) 1f else 0f,
|
||||||
|
label = "deleteButtonAlpha",
|
||||||
|
animationSpec = tween(durationMillis = 500)
|
||||||
|
)
|
||||||
|
|
||||||
|
var pauseButtonAlphaIsIn by rememberSaveable {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
val pauseButtonAlpha by animateFloatAsState(
|
||||||
|
if (pauseButtonAlphaIsIn) 1f else 0f,
|
||||||
|
label = "pauseButtonAlpha",
|
||||||
|
animationSpec = tween(durationMillis = 500)
|
||||||
|
)
|
||||||
|
|
||||||
|
var saveButtonAlphaIsIn by rememberSaveable {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
val saveButtonAlpha by animateFloatAsState(
|
||||||
|
if (saveButtonAlphaIsIn) 1f else 0f,
|
||||||
|
label = "saveButtonAlpha",
|
||||||
|
animationSpec = tween(durationMillis = 500)
|
||||||
|
)
|
||||||
|
|
||||||
|
LaunchedEffect(animateIn) {
|
||||||
|
if (animateIn) {
|
||||||
|
val stack = RandomStack.of(arrayOf(1, 2, 3).asIterable())
|
||||||
|
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
val next = stack.popRandom()
|
||||||
|
when (next) {
|
||||||
|
1 -> {
|
||||||
|
deleteButtonAlphaIsIn = true
|
||||||
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
pauseButtonAlphaIsIn = true
|
||||||
|
}
|
||||||
|
|
||||||
|
3 -> {
|
||||||
|
saveButtonAlphaIsIn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(250)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f),
|
.weight(1f)
|
||||||
|
.alpha(deleteButtonAlpha),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
DeleteButton(onDelete = onDelete)
|
DeleteButton(onDelete = onDelete)
|
||||||
@ -32,6 +105,8 @@ fun RecordingControl(
|
|||||||
|
|
||||||
Box(
|
Box(
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.alpha(pauseButtonAlpha),
|
||||||
) {
|
) {
|
||||||
PauseResumeButton(
|
PauseResumeButton(
|
||||||
isPaused = isPaused,
|
isPaused = isPaused,
|
||||||
@ -42,7 +117,8 @@ fun RecordingControl(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f),
|
.weight(1f)
|
||||||
|
.alpha(saveButtonAlpha),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
SaveButton(onSave = onSave)
|
SaveButton(onSave = onSave)
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.expandHorizontally
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.myzel394.alibi.R
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RecordingProgress
|
import app.myzel394.alibi.ui.components.atoms.Pulsating
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RecordingTime
|
import app.myzel394.alibi.ui.utils.formatDuration
|
||||||
import app.myzel394.alibi.ui.utils.isSameDay
|
import app.myzel394.alibi.ui.utils.isSameDay
|
||||||
|
import app.myzel394.alibi.ui.utils.rememberInitialRecordingAnimation
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.format.FormatStyle
|
import java.time.format.FormatStyle
|
||||||
@ -28,51 +41,87 @@ fun RecordingStatus(
|
|||||||
recordingStart: LocalDateTime,
|
recordingStart: LocalDateTime,
|
||||||
maxDuration: Long,
|
maxDuration: Long,
|
||||||
) {
|
) {
|
||||||
|
val animateIn = rememberInitialRecordingAnimation(recordingTime)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
RecordingTime(recordingTime)
|
Row(
|
||||||
RecordingProgress(
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
recordingTime = recordingTime,
|
horizontalArrangement = Arrangement.Center,
|
||||||
progress = progress,
|
) {
|
||||||
)
|
Pulsating {
|
||||||
|
Box(
|
||||||
Text(
|
modifier = Modifier
|
||||||
text = stringResource(
|
.size(16.dp)
|
||||||
R.string.ui_recorder_info_saveNowTime,
|
.clip(CircleShape)
|
||||||
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).format(
|
.background(Color.Red)
|
||||||
LocalDateTime.now().minusSeconds(
|
|
||||||
min(
|
|
||||||
maxDuration / 1000,
|
|
||||||
recordingTime
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
}
|
||||||
style = MaterialTheme.typography.bodySmall,
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
textAlign = TextAlign.Center,
|
Text(
|
||||||
)
|
text = formatDuration(recordingTime * 1000),
|
||||||
|
style = MaterialTheme.typography.headlineLarge,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
AnimatedVisibility(
|
||||||
text = recordingStart.let {
|
visible = animateIn,
|
||||||
if (isSameDay(it, LocalDateTime.now())) {
|
enter = expandHorizontally(
|
||||||
stringResource(
|
tween(1000)
|
||||||
R.string.ui_recorder_info_startTime_short,
|
)
|
||||||
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
|
) {
|
||||||
.format(it)
|
LinearProgressIndicator(
|
||||||
)
|
progress = progress,
|
||||||
} else {
|
modifier = Modifier
|
||||||
stringResource(
|
.width(300.dp)
|
||||||
R.string.ui_recorder_info_startTime_full,
|
)
|
||||||
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT)
|
}
|
||||||
.format(it)
|
|
||||||
)
|
AnimatedVisibility(visible = animateIn, enter = fadeIn()) {
|
||||||
}
|
Text(
|
||||||
},
|
text = stringResource(
|
||||||
style = MaterialTheme.typography.bodySmall,
|
R.string.ui_recorder_info_saveNowTime,
|
||||||
textAlign = TextAlign.Center,
|
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT)
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
.format(
|
||||||
)
|
LocalDateTime.now().minusSeconds(
|
||||||
|
min(
|
||||||
|
maxDuration / 1000,
|
||||||
|
recordingTime
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(visible = animateIn, enter = fadeIn()) {
|
||||||
|
Text(
|
||||||
|
text = recordingStart.let {
|
||||||
|
if (isSameDay(it, LocalDateTime.now())) {
|
||||||
|
stringResource(
|
||||||
|
R.string.ui_recorder_info_startTime_short,
|
||||||
|
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
|
||||||
|
.format(it)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
stringResource(
|
||||||
|
R.string.ui_recorder_info_startTime_full,
|
||||||
|
DateTimeFormatter.ofLocalizedDateTime(
|
||||||
|
FormatStyle.MEDIUM,
|
||||||
|
FormatStyle.SHORT
|
||||||
|
)
|
||||||
|
.format(it)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,19 +1,10 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.animation.expandHorizontally
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@ -24,13 +15,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.DeleteButton
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.PauseResumeButton
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RealtimeAudioVisualizer
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RealtimeAudioVisualizer
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RecordingProgress
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RecordingTime
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveButton
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.MicrophoneStatus
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.MicrophoneStatus
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingControl
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingControl
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingStatus
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingStatus
|
||||||
@ -80,6 +65,7 @@ fun AudioRecordingStatus(
|
|||||||
|
|
||||||
RecordingControl(
|
RecordingControl(
|
||||||
isPaused = audioRecorder.isPaused,
|
isPaused = audioRecorder.isPaused,
|
||||||
|
recordingTime = audioRecorder.recordingTime,
|
||||||
onDelete = {
|
onDelete = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.animation.expandHorizontally
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
@ -19,29 +13,17 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.CameraAlt
|
import androidx.compose.material.icons.filled.CameraAlt
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.util.TypedValueCompat
|
|
||||||
import app.myzel394.alibi.R
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.DeleteButton
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.PauseResumeButton
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RecordingProgress
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RecordingTime
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveButton
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.TorchStatus
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.TorchStatus
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingControl
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingControl
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingStatus
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingStatus
|
||||||
@ -152,6 +134,7 @@ fun VideoRecordingStatus(
|
|||||||
|
|
||||||
RecordingControl(
|
RecordingControl(
|
||||||
isPaused = videoRecorder.isPaused,
|
isPaused = videoRecorder.isPaused,
|
||||||
|
recordingTime = videoRecorder.recordingTime,
|
||||||
onDelete = {
|
onDelete = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
|
22
app/src/main/java/app/myzel394/alibi/ui/utils/animations.kt
Normal file
22
app/src/main/java/app/myzel394/alibi/ui/utils/animations.kt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package app.myzel394.alibi.ui.utils
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberInitialRecordingAnimation(recordingTime: Long): Boolean {
|
||||||
|
// Only show animation when the recording has just started
|
||||||
|
val recordingJustStarted = recordingTime <= 1L
|
||||||
|
var progressVisible by rememberSaveable { mutableStateOf(!recordingJustStarted) }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
progressVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return progressVisible
|
||||||
|
}
|
40
app/src/main/java/app/myzel394/alibi/ui/utils/stack.kt
Normal file
40
app/src/main/java/app/myzel394/alibi/ui/utils/stack.kt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package app.myzel394.alibi.ui.utils
|
||||||
|
|
||||||
|
// A stack that allows you to randomly pop items from it
|
||||||
|
class RandomStack<T> {
|
||||||
|
private val stack = mutableListOf<T>()
|
||||||
|
|
||||||
|
fun push(item: T) {
|
||||||
|
stack.add(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pop(): T {
|
||||||
|
val index = stack.size - 1
|
||||||
|
val item = stack[index]
|
||||||
|
|
||||||
|
stack.removeAt(index)
|
||||||
|
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popRandom(): T {
|
||||||
|
val index = (0..<stack.size).random()
|
||||||
|
val item = stack[index]
|
||||||
|
|
||||||
|
stack.removeAt(index)
|
||||||
|
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEmpty() = stack.isEmpty()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun <T> of(items: Iterable<T>): RandomStack<T> {
|
||||||
|
val stack = RandomStack<T>()
|
||||||
|
|
||||||
|
items.forEach(stack::push)
|
||||||
|
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user