Skip to content

Commit

Permalink
Elapsed time UI (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kimblebee authored Oct 15, 2024
1 parent 6867c2e commit a55ecae
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -529,13 +529,22 @@ private suspend fun startVideoRecordingInternal(
when (onVideoRecordEvent) {
is VideoRecordEvent.Finalize -> {
when (onVideoRecordEvent.error) {
ERROR_NONE, ERROR_DURATION_LIMIT_REACHED ->
ERROR_NONE -> {
onVideoRecord(
CameraUseCase.OnVideoRecordEvent.OnVideoRecorded(
onVideoRecordEvent.outputResults.outputUri
onVideoRecordEvent.outputResults.outputUri,
onVideoRecordEvent.recordingStats.recordedDurationNanos
)
)

}
ERROR_DURATION_LIMIT_REACHED -> {
onVideoRecord(
CameraUseCase.OnVideoRecordEvent.OnVideoRecorded(
onVideoRecordEvent.outputResults.outputUri,
(maxDurationMillis * 1_000_000) // cleanly display the max duration
)
)
}
else ->
onVideoRecord(
CameraUseCase.OnVideoRecordEvent.OnVideoRecordError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ interface CameraUseCase {
* Represents the events for video recording.
*/
sealed interface OnVideoRecordEvent {
data class OnVideoRecorded(val savedUri: Uri) : OnVideoRecordEvent
data class OnVideoRecorded(
val savedUri: Uri,
val finalDurationNanos: Long
) : OnVideoRecordEvent

data class OnVideoRecordStatus(
val audioAmplitude: Double,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ sealed interface PreviewUiState {
val isDebugMode: Boolean = false
) : PreviewUiState
}

// todo(kc): add ElapsedTimeUiState class
/**
* Defines the current state of Video Recording
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ class PreviewViewModel @AssistedInject constructor(
isDebugMode = isDebugMode,
currentLogicalCameraId = cameraState.debugInfo.logicalCameraId,
currentPhysicalCameraId = cameraState.debugInfo.physicalCameraId
// TODO(kc): set elapsed time UI state once VideoRecordingState
// refactor is complete.
)
}
}
Expand Down Expand Up @@ -645,6 +647,7 @@ class PreviewViewModel @AssistedInject constructor(
when (it) {
is CameraUseCase.OnVideoRecordEvent.OnVideoRecorded -> {
Log.d(TAG, "cameraUseCase.startRecording OnVideoRecorded")
timer = it.finalDurationNanos
onVideoCapture(VideoCaptureEvent.VideoSaved(it.savedUri))
snackbarToShow = SnackbarData(
cookie = cookie,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ private fun ControlsBottom(
if (previewUiState.isDebugMode) {
CurrentCameraIdText(physicalCameraId, logicalCameraId)
}
ElapsedTimeText(
modifier = Modifier.testTag(ELAPSED_TIME_TAG),
videoRecordingState = videoRecordingState,
elapsedNs = previewUiState.recordingElapsedTimeNanos
)
}
}

Expand All @@ -255,6 +260,7 @@ private fun ControlsBottom(
.height(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
// Row that holds flip camera, capture button, and audio
Row(Modifier.weight(1f), horizontalArrangement = Arrangement.SpaceEvenly) {
if (!isQuickSettingsOpen && videoRecordingState == VideoRecordingState.INACTIVE) {
FlipCameraButton(
Expand Down Expand Up @@ -516,6 +522,7 @@ private fun Preview_ControlsBottom() {
systemConstraints = TYPICAL_SYSTEM_CONSTRAINTS,
videoRecordingState = VideoRecordingState.INACTIVE,
audioAmplitude = 0.0

)
}
}
Expand All @@ -538,6 +545,7 @@ private fun Preview_ControlsBottom_NoZoomLevel() {
systemConstraints = TYPICAL_SYSTEM_CONSTRAINTS,
videoRecordingState = VideoRecordingState.INACTIVE,
audioAmplitude = 0.0

)
}
}
Expand Down Expand Up @@ -588,6 +596,7 @@ private fun Preview_ControlsBottom_NoFlippableCamera() {
),
videoRecordingState = VideoRecordingState.INACTIVE,
audioAmplitude = 0.0

)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ import androidx.camera.core.DynamicRange as CXDynamicRange
import androidx.camera.core.SurfaceRequest
import androidx.camera.viewfinder.compose.MutableCoordinateTransformer
import androidx.camera.viewfinder.surface.ImplementationMode
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.EaseOutExpo
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.border
Expand Down Expand Up @@ -93,6 +96,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
Expand All @@ -103,6 +107,7 @@ import com.google.jetpackcamera.feature.preview.ui.theme.PreviewPreviewTheme
import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.LowLightBoost
import com.google.jetpackcamera.settings.model.Stabilization
import kotlin.time.Duration.Companion.nanoseconds
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
Expand All @@ -112,6 +117,27 @@ import kotlinx.coroutines.flow.onCompletion
private const val TAG = "PreviewScreen"
private const val BLINK_TIME = 100L

@Composable
fun ElapsedTimeText(
modifier: Modifier = Modifier,
videoRecordingState: VideoRecordingState,
elapsedNs: Long
) {
AnimatedVisibility(
visible = (videoRecordingState == VideoRecordingState.ACTIVE),
enter = fadeIn(),
exit = fadeOut(animationSpec = tween(delayMillis = 1000))
) {
Text(
modifier = modifier,
text = elapsedNs.nanoseconds.toComponents { minutes, seconds, _ ->
"%02d:%02d".format(minutes, seconds)
},
textAlign = TextAlign.Center
)
}
}

@Composable
fun AmplitudeVisualizer(
modifier: Modifier = Modifier,
Expand Down Expand Up @@ -439,6 +465,7 @@ fun LowLightBoostIcon(lowLightBoost: LowLightBoost, modifier: Modifier = Modifie
modifier = modifier.alpha(0.5f)
)
}

LowLightBoost.DISABLED -> {
}
}
Expand Down Expand Up @@ -625,7 +652,8 @@ fun ToggleButton(
onToggleWhenDisabled()
}
}
).semantics {
)
.semantics {
stateDescription = when (toggleState) {
ToggleState.Left -> leftIconDescription
ToggleState.Right -> rightIconDescription
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ const val HDR_VIDEO_UNSUPPORTED_ON_LENS_TAG = "HdrVideoUnsupportedOnDeviceTag"
const val ZOOM_RATIO_TAG = "ZoomRatioTag"
const val LOGICAL_CAMERA_ID_TAG = "LogicalCameraIdTag"
const val PHYSICAL_CAMERA_ID_TAG = "PhysicalCameraIdTag"
const val ELAPSED_TIME_TAG = "ElapsedTimeTag"

0 comments on commit a55ecae

Please sign in to comment.