Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ private fun ContentScreen(
},
imageWell = { modifier ->
if (captureUiState.externalCaptureMode == ExternalCaptureMode.Standard) {
(captureUiState.imageWellUiState as? ImageWellUiState.LastCapture)?.let {
(captureUiState.imageWellUiState as? ImageWellUiState.Content)?.let {
ImageWell(
modifier = modifier,
imageWellUiState = it,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class PreviewViewModel @Inject constructor(
*/
fun imageWellToRepository() {
(captureUiState.value as? CaptureUiState.Ready)
?.let { it.imageWellUiState as? ImageWellUiState.LastCapture }
?.let { it.imageWellUiState as? ImageWellUiState.Content }
?.let { postCurrentMediaToMediaRepository(it.mediaDescriptor) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import com.google.jetpackcamera.ui.uistate.capture.ImageWellUiState
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalAnimationApi::class)
@Composable
fun ImageWell(
imageWellUiState: ImageWellUiState.LastCapture,
imageWellUiState: ImageWellUiState.Content,
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = RoundedCornerShape(16.dp),
Expand Down Expand Up @@ -100,7 +100,7 @@ private fun ImageWellPreview() {
uri = Uri.EMPTY,
thumbnail = previewBitmap
)
val imageWellUiState = ImageWellUiState.LastCapture(
val imageWellUiState = ImageWellUiState.Content(
mediaDescriptor = mediaDescriptor
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import com.google.jetpackcamera.data.media.MediaDescriptor
sealed interface ImageWellUiState {
data object Unavailable : ImageWellUiState

data class LastCapture(val mediaDescriptor: MediaDescriptor.Content) : ImageWellUiState
data class Content(val mediaDescriptor: MediaDescriptor.Content) : ImageWellUiState

companion object
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ private val ORDERED_UI_SUPPORTED_ASPECT_RATIOS = listOf(
AspectRatio.ONE_ONE
)

/**
* Creates an [AspectRatioUiState] from [CameraAppSettings].
*
* @param cameraAppSettings The current camera application settings.
*
* @return An [AspectRatioUiState] representing the available aspect ratios and the currently
* selected one. If only one or no aspect ratios are supported, it returns
* [AspectRatioUiState.Unavailable].
*/
fun AspectRatioUiState.Companion.from(cameraAppSettings: CameraAppSettings): AspectRatioUiState {
val supportedAspectRatios = ORDERED_UI_SUPPORTED_ASPECT_RATIOS.toSet()
val availableAspectRatios =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ import com.google.jetpackcamera.core.camera.VideoRecordingState
import com.google.jetpackcamera.settings.model.CameraAppSettings
import com.google.jetpackcamera.ui.uistate.capture.AudioUiState

/**
* Creates an [AudioUiState] from the given camera application settings.
*
* @param cameraAppSettings The current settings of the camera application.
* @param cameraState The current state of the camera, used to get the audio amplitude.
* @return [AudioUiState.Enabled.On] if audio is enabled, containing the current amplitude,
* or [AudioUiState.Enabled.Mute] if audio is disabled.
*/
fun AudioUiState.Companion.from(
cameraAppSettings: CameraAppSettings,
cameraState: CameraState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ import com.google.jetpackcamera.core.camera.VideoRecordingState
import com.google.jetpackcamera.settings.model.CameraAppSettings
import com.google.jetpackcamera.ui.uistate.capture.CaptureButtonUiState

/**
* Creates a [CaptureButtonUiState] based on the current camera settings and state.
*
* This function determines the UI state for the capture button based on the capture mode, video
* recording status, and whether the recording has been locked.
*
* @param cameraAppSettings The current application settings, used to determine the capture mode.
* @param cameraState The current state of the camera, used to check video recording status.
* @param lockedState A boolean indicating whether the video recording is currently in a locked state.
*
* @return A [CaptureButtonUiState] representing the current state of the capture button.
* - [CaptureButtonUiState.Enabled.Idle] if not recording.
* - [CaptureButtonUiState.Enabled.Recording.PressedRecording] if recording is active but not locked.
* - [CaptureButtonUiState.Enabled.Recording.LockedRecording] if recording is active and locked.
*/
fun CaptureButtonUiState.Companion.from(
cameraAppSettings: CameraAppSettings,
cameraState: CameraState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@ private val ORDERED_UI_SUPPORTED_CAPTURE_MODES = listOf(
CaptureMode.VIDEO_ONLY
)

/**
* Creates a [CaptureModeToggleUiState] based on the current camera and system state.
*
* This adapter determines whether the simplified capture mode toggle (between IMAGE_ONLY and
* VIDEO_ONLY) should be available and what its state should be. The toggle is generally
* unavailable if video is recording or if the current capture mode is STANDARD.
*
* @param systemConstraints The constraints of the entire camera system.
* @param cameraAppSettings The current settings of the camera.
* @param cameraState The real-time state of the camera hardware.
* @param externalCaptureMode The mode influencing UI based on how the camera was launched.
* @return A [CaptureModeToggleUiState] which is either [CaptureModeToggleUiState.Available]
* containing the states for the image and video-only modes, or
* [CaptureModeToggleUiState.Unavailable] if the toggle should not be shown.
*/
fun CaptureModeToggleUiState.Companion.from(
systemConstraints: CameraSystemConstraints,
cameraAppSettings: CameraAppSettings,
Expand Down Expand Up @@ -75,6 +90,19 @@ fun CaptureModeToggleUiState.Companion.from(
)
}

/**
* Creates a [CaptureModeUiState] for the full capture mode selection UI (e.g., in quick settings).
*
* This adapter is responsible for determining the list of all available and selectable capture
* modes ([CaptureMode.STANDARD], [CaptureMode.IMAGE_ONLY], [CaptureMode.VIDEO_ONLY]) based on the
* current system and camera constraints.
*
* @param systemConstraints The constraints of the entire camera system.
* @param cameraAppSettings The current settings of the camera.
* @param externalCaptureMode The mode influencing UI based on how the camera was launched.
* @return A [CaptureModeUiState.Available] object containing the currently selected capture mode
* and a list of all available modes, each represented as a [SingleSelectableUiState].
*/
fun CaptureModeUiState.Companion.from(
systemConstraints: CameraSystemConstraints,
cameraAppSettings: CameraAppSettings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ import com.google.jetpackcamera.ui.uistate.capture.CaptureModeUiState
import com.google.jetpackcamera.ui.uistate.capture.ConcurrentCameraUiState
import com.google.jetpackcamera.ui.uistate.capture.StreamConfigUiState

/**
* Creates a [ConcurrentCameraUiState] based on the current camera and system state.
*
* This function determines the availability and current selection of the concurrent camera feature.
* It synthesizes various states and settings to decide if the concurrent camera mode can be
* enabled. The feature is considered disabled if any of the following conditions are true:
* - The device hardware does not support concurrent cameras.
* - The camera was launched with an external intent for single image capture.
* - The selected capture mode is exclusively for single image capture (`IMAGE_ONLY`).
* - An HDR mode (either HLG10 for video or ULTRA_HDR for images) is active.
* - The stream configuration is set to `SINGLE_STREAM`.
* - Low Light Boost flash mode is active.
*
* @param cameraAppSettings The current application-level camera settings.
* @param systemConstraints The capabilities and limitations of the device's camera hardware.
* @param externalCaptureMode The mode indicating if the camera was launched by an external intent.
* @param captureModeUiState The current state of the capture mode selection UI.
* @param streamConfigUiState The current state of the stream configuration UI.
* @return A [ConcurrentCameraUiState.Available] object containing the currently selected
* concurrent camera mode and a boolean indicating if the feature is currently enabled and
* can be interacted with.
*/
fun ConcurrentCameraUiState.Companion.from(
cameraAppSettings: CameraAppSettings,
systemConstraints: CameraSystemConstraints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ fun debugUiState(
/**
* Constructs a [DebugUiState] based on the current camera and application state.
*
* This is a private factory function that determines whether the debug UI should be fully
* enabled and open, enabled but closed, or completely disabled. It gathers and transforms
* the necessary data for the UI.
*
* @param systemConstraints The system-level constraints for the current camera.
* @param cameraAppSettings The current application-level camera settings.
* @param cameraState The real-time state of the camera.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ import com.google.jetpackcamera.core.camera.CameraState
import com.google.jetpackcamera.core.camera.VideoRecordingState
import com.google.jetpackcamera.ui.uistate.capture.ElapsedTimeUiState

/**
* Creates an [ElapsedTimeUiState] based on the current [CameraState].
*
* This function translates the [VideoRecordingState] from the core camera layer into a UI-specific
* state for displaying the elapsed time of a video recording. It handles different recording
* phases: active recording, the final time after recording stops, and the initial state when
* a recording is starting.
*
* @param cameraState The real-time state from the camera, which includes the video recording status.
*
* @return An [ElapsedTimeUiState.Enabled] state containing the elapsed time in nanoseconds.
* - For [VideoRecordingState.Active], it provides the ongoing elapsed time.
* - For [VideoRecordingState.Inactive], it provides the final duration of the last recording.
* - For [VideoRecordingState.Starting], it provides an initial value of 0.
*/
fun ElapsedTimeUiState.Companion.from(cameraState: CameraState): ElapsedTimeUiState {
val videoRecordingState = cameraState.videoRecordingState
return when (videoRecordingState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ private val ORDERED_UI_SUPPORTED_FLASH_MODES = listOf(
FlashMode.LOW_LIGHT_BOOST
)

/**
* Creates the initial [FlashModeUiState] from the given camera settings and system constraints.
*
* This factory function determines the set of available flash modes based on hardware support
* and current camera settings (like HDR or concurrent mode). If only [FlashMode.OFF] is available,
* or no modes are supported, it returns [FlashModeUiState.Unavailable].
*
* @param cameraAppSettings The current settings of the camera, used to determine which flash modes
* might be disabled due to other active settings (e.g., HDR).
* @param systemConstraints The hardware capabilities of the camera system, used to get the list
* of supported flash modes for the current lens.
* @return A [FlashModeUiState] which is either [Available] if multiple flash modes can be shown,
* or [Unavailable] if the flash controls should be hidden.
*/
fun FlashModeUiState.Companion.from(
cameraAppSettings: CameraAppSettings,
systemConstraints: CameraSystemConstraints
Expand Down Expand Up @@ -81,6 +95,20 @@ fun FlashModeUiState.Companion.from(
}
}

/**
* Updates an existing [FlashModeUiState] based on new camera settings and state.
*
* This function efficiently updates the flash UI state without recreating it from scratch if
* possible. It checks for changes in supported modes, selected mode, and the real-time status
* of Low Light Boost.
*
* @param cameraAppSettings The current application settings for the camera.
* @param systemConstraints The hardware capabilities of the camera system.
* @param cameraState The real-time state from the camera, used to check [LowLightBoostState].
* @return An updated [FlashModeUiState]. This may be the same instance if no relevant
* state has changed, a copied instance with minor updates, or a completely new instance if
* supported flash modes have changed.
*/
fun FlashModeUiState.updateFrom(
cameraAppSettings: CameraAppSettings,
systemConstraints: CameraSystemConstraints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ private val ORDERED_UI_SUPPORTED_LENS_FACINGS = listOf(

)

/**
* Creates a [FlipLensUiState] based on the current camera settings and system constraints.
*
* This function determines the UI state for the lens flipping control (e.g., front/back camera
* button). It gathers the list of all physically available lenses from the system constraints
* and combines it with the currently selected lens from the application settings.
*
* @param cameraAppSettings The current application settings, used to determine the currently
* selected [LensFacing].
* @param systemConstraints The hardware capabilities of the camera system, used to get the list
* of all available lenses on the device.
* @return A [FlipLensUiState.Available] object containing the currently selected lens and a list
* of all available lenses for the UI to display.
*/
fun FlipLensUiState.Companion.from(
cameraAppSettings: CameraAppSettings,
systemConstraints: CameraSystemConstraints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ import com.google.jetpackcamera.core.camera.CameraState
import com.google.jetpackcamera.core.camera.FocusState
import com.google.jetpackcamera.ui.uistate.capture.FocusMeteringUiState

/**
* Updates an existing [FocusMeteringUiState] based on a new [CameraState].
*
* This factory function translates the [FocusState] into its corresponding UI representation.
*
* @param cameraState The new, real-time state from the camera.
* @return The existing [FocusMeteringUiState] instance if no change is detected, or a new
* [FocusMeteringUiState] reflecting the updated camera focus state.
*/
fun FocusMeteringUiState.updateFrom(cameraState: CameraState): FocusMeteringUiState {
val focusState = cameraState.focusState
return when (this) {
Expand All @@ -45,6 +54,17 @@ fun FocusMeteringUiState.updateFrom(cameraState: CameraState): FocusMeteringUiSt
}
}

/**
* Creates a [FocusMeteringUiState] from the given [CameraState].
*
* This factory function translates the low-level [FocusState] from the core camera layer into its
* corresponding UI representation. It maps the coordinates and status (e.g., RUNNING, SUCCESS)
* to the appropriate [FocusMeteringUiState] subtype, which can be either [FocusMeteringUiState.Unspecified]
* or [FocusMeteringUiState.Specified].
*
* @param cameraState The real-time state from the camera containing the focus information.
* @return A [FocusMeteringUiState] that represents the current focus state for the UI.
*/
fun FocusMeteringUiState.Companion.from(cameraState: CameraState): FocusMeteringUiState {
return when (val focusState = cameraState.focusState) {
is FocusState.Unspecified -> FocusMeteringUiState.Unspecified
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@ import com.google.jetpackcamera.settings.model.CameraSystemConstraints
import com.google.jetpackcamera.settings.model.forCurrentLens
import com.google.jetpackcamera.ui.uistate.capture.HdrUiState

/**
* Creates an [HdrUiState] based on the current camera settings, system constraints, and capture mode.
*
* This function determines whether the High Dynamic Range (HDR) feature is available for the user
* to interact with. The availability depends on a combination of hardware support for specific
* HDR formats ([DynamicRange.HLG10] for video, [ImageOutputFormat.JPEG_ULTRA_HDR] for images) and
* various other settings that may conflict with HDR, such as flash mode or concurrent camera mode.
*
* The logic is tailored to the [ExternalCaptureMode]:
* - **ImageCapture / MultipleImageCapture**: Checks for `JPEG_ULTRA_HDR` support.
* - **VideoCapture**: Checks for `HLG10` dynamic range support.
* - **Standard**: Checks for support for either `HLG10` or `JPEG_ULTRA_HDR`.
*
* In all cases, HDR is disabled if `LOW_LIGHT_BOOST` flash mode is active. For video and standard
* modes, it is also disabled if concurrent camera mode is active.
*
* @param cameraAppSettings The current application and camera settings.
* @param systemConstraints The capabilities and limitations of the device's camera hardware.
* @param externalCaptureMode The mode indicating how the camera was launched (e.g., via an
* external intent), which influences which HDR formats are relevant.
*
* @return [HdrUiState.Available] if the feature is supported and not blocked by other settings,
* otherwise returns [HdrUiState.Unavailable].
*/
fun HdrUiState.Companion.from(
cameraAppSettings: CameraAppSettings,
systemConstraints: CameraSystemConstraints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ import com.google.jetpackcamera.core.camera.VideoRecordingState
import com.google.jetpackcamera.data.media.MediaDescriptor
import com.google.jetpackcamera.ui.uistate.capture.ImageWellUiState

/**
* Creates an [ImageWellUiState] for a given [MediaDescriptor] and [VideoRecordingState].
*
* This function determines the state of the image well, a component that displays the
* [MediaDescriptor]'s thumbnail. This state will be unavailable if any of the following are true:
* - mediaDescriptor is not MediaDescriptor.Content
* - mediaDescriptor does not have a thumbnail
*
* @param mediaDescriptor the media's correlating [MediaDescriptor]
* @param videoRecordingState The current state of video recording.
* @return [ImageWellUiState.Content] only if the mediaDescriptor is MediaDescriptor.Content,
* has a non-null thumbnail, and video recording state is inactive.
* otherwise return [ImageWellUiState.Unavailable]
*/
fun ImageWellUiState.Companion.from(
mediaDescriptor: MediaDescriptor,
videoRecordingState: VideoRecordingState
Expand All @@ -27,7 +41,7 @@ fun ImageWellUiState.Companion.from(
mediaDescriptor.thumbnail != null &&
videoRecordingState is VideoRecordingState.Inactive
) {
ImageWellUiState.LastCapture(mediaDescriptor = mediaDescriptor)
ImageWellUiState.Content(mediaDescriptor = mediaDescriptor)
} else {
ImageWellUiState.Unavailable
}
Expand Down

This file was deleted.

Loading
Loading