Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,20 @@ enum class DeviceRotation {
* Returns the clockwise rotation in degrees needed inside a window at [windowRotation] so that
* UI elements remain oriented upright against physical gravity (`this` device rotation).
*
* An upside-down (`180°`) delta is mapped to `0` so camera controls and layouts never flip
* upside-down.
* An upside-down (`180°`) delta returns [fallbackOn180Degrees] (defaulting to `0`) so camera
* controls and layouts never flip upside-down and stateful callers can retain their previous
* upright gravity angle.
*/
fun toGravityRotationDegrees(windowRotation: DeviceRotation): Int {
fun toGravityRotationDegrees(
windowRotation: DeviceRotation,
fallbackOn180Degrees: Int = 0
): Int {
val rawDelta =
(
(windowRotation.toClockwiseRotationDegrees() - toClockwiseRotationDegrees()) %
360 + 360
) % 360
return if (rawDelta == 180) 0 else rawDelta
return if (rawDelta == 180) fallbackOn180Degrees else rawDelta
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,24 @@ class DeviceRotationTest {
)
).isEqualTo(90)

// Upside-down delta (180°) clamps to 0° so UI never flips upside-down
// Upside-down delta (180°) defaults to 0° and honors stateful fallbackOn180Degrees
assertThat(
DeviceRotation.Rotated180.toGravityRotationDegrees(
windowRotation = DeviceRotation.Natural
)
).isEqualTo(0)
assertThat(
DeviceRotation.Rotated180.toGravityRotationDegrees(
windowRotation = DeviceRotation.Natural,
fallbackOn180Degrees = 270
)
).isEqualTo(270)
assertThat(
DeviceRotation.Rotated90.toGravityRotationDegrees(
windowRotation = DeviceRotation.Rotated270
windowRotation = DeviceRotation.Rotated270,
fallbackOn180Degrees = 90
)
).isEqualTo(0)
).isEqualTo(90)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fun CameraErrorDialog(
) {
Surface(
modifier = Modifier
.rotateLayoutToGravity()
.padding(horizontal = 24.dp)
.widthIn(min = 280.dp, max = 560.dp)
.pointerInput(Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,10 @@ private fun LockSwitchCaptureButtonNucleus(
}
) {
Icon(
modifier = Modifier.size(switchHeight * .75f).align(Alignment.Center),
modifier = Modifier
.size(switchHeight * .75f)
.align(Alignment.Center)
.animateToUpright(),
tint = Color.White,
painter = if (shouldBeLocked()) {
painterResource(R.drawable.ic_lock)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,18 @@ internal fun CaptureScaffoldLayout(
heightDp = maxHeight,
isFullScreenCompactPhone = isFullScreenCompactPhone
)
val isCompactPortraitBacked = layoutMode == CameraLayoutMode.COMPACT ||
layoutMode == CameraLayoutMode.COMPACT_SLIM
val outerGravityRotationState = if (isCompactPortraitBacked) {
LocalGravityRotationState.current
} else {
DefaultGravityRotationState
}

CompositionLocalProvider(LocalCameraLayoutMode provides layoutMode) {
CompositionLocalProvider(
LocalCameraLayoutMode provides layoutMode,
LocalGravityRotationState provides outerGravityRotationState
) {
val resolvedSlots = slots ?: CaptureSlots(
topBar = indicatorRow,
topBarTrailingContent = topBarTrailingContent,
Expand All @@ -223,7 +233,6 @@ internal fun CaptureScaffoldLayout(
snackBar = snackBar,
errorDialog = errorDialog
)

when (layoutMode) {
CameraLayoutMode.COMPACT,
CameraLayoutMode.COMPACT_SLIM -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ import com.google.jetpackcamera.model.DeviceRotation
import com.google.jetpackcamera.model.ExternalCaptureMode
import com.google.jetpackcamera.model.LensFacing
import com.google.jetpackcamera.model.LensToZoom
import com.google.jetpackcamera.ui.components.capture.quicksettings.QuickSettingsContent
import com.google.jetpackcamera.ui.components.capture.quicksettings.QuickSettingsScaffoldContent
import com.google.jetpackcamera.ui.components.capture.quicksettings.ui.FlashModeIndicator
import com.google.jetpackcamera.ui.components.capture.quicksettings.ui.HdrIndicator
Expand Down Expand Up @@ -735,25 +734,14 @@ object CaptureScaffoldDefaults {
showMoreSettingsButton: Boolean = true
) {
if (controller != null) {
if (LocalActiveCaptureLayout.current == "CompactPortraitLayout") {
QuickSettingsScaffoldContent(
quickSettingsUiState = uiState,
onNavigateToSettings = onNavigateToSettings,
quickSettingsController = controller,
modifier = modifier,
showMoreSettingsButton = showMoreSettingsButton
)
} else if (uiState is QuickSettingsUiState.Available) {
QuickSettingsContent(
quickSettingsUiState = uiState,
quickSettingsController = controller,
onNavigateToSettings = onNavigateToSettings,
modifier = modifier
.padding(vertical = 20.dp)
.testTag(QUICK_SETTINGS_BOTTOM_SHEET),
showMoreSettingsButton = showMoreSettingsButton
)
}
val isFloatingCard = LocalActiveCaptureLayout.current != "CompactPortraitLayout"
QuickSettingsScaffoldContent(
quickSettingsUiState = uiState,
onNavigateToSettings = onNavigateToSettings,
quickSettingsController = controller,
modifier = if (isFloatingCard) modifier.padding(top = 20.dp) else modifier,
showMoreSettingsButton = showMoreSettingsButton
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ fun CameraControlIconButton(
val backgroundStyle = LocalCameraControlBackgroundStyle.current
FilledIconButton(
onClick = onClick,
modifier = modifier.size(CameraControlIconButtonSize),
modifier = modifier
.size(CameraControlIconButtonSize)
.animateToUpright(),
enabled = enabled,
shape = CircleShape,
colors = IconButtonDefaults.filledIconButtonColors(
Expand Down Expand Up @@ -546,7 +548,9 @@ fun PauseResumeToggleButton(
currentRecordingState !is VideoRecordingState.Active.Paused
)
},
modifier = modifier.size(size)
modifier = modifier
.size(size)
.animateToUpright()
) {
Icon(
modifier = Modifier
Expand Down Expand Up @@ -602,6 +606,7 @@ fun AmplitudeToggleButton(
FilledIconToggleButton(
modifier = modifier
.size(buttonSize)
.animateToUpright()
.testTag(AUDIO_INPUT_TOGGLE)
.semantics {
stateDescription = if (audioUiState is AudioUiState.Enabled.On) {
Expand Down Expand Up @@ -1310,7 +1315,9 @@ fun StabilizationIcon(stabilizationUiState: StabilizationUiState, modifier: Modi
) {
if (displayedState != null) {
Icon(
modifier = Modifier.size(IconButtonDefaults.smallIconSize),
modifier = Modifier
.size(IconButtonDefaults.smallIconSize)
.animateToUpright(),
painter = when (displayedState) {
is StabilizationUiState.Specific ->
when (displayedState.stabilizationMode) {
Expand Down Expand Up @@ -1395,7 +1402,9 @@ fun VideoQualityIcon(videoQuality: VideoQuality, modifier: Modifier = Modifier)
) {
if (displayedQuality != null) {
Icon(
modifier = Modifier.size(IconButtonDefaults.smallIconSize),
modifier = Modifier
.size(IconButtonDefaults.smallIconSize)
.animateToUpright(),
painter = when (displayedQuality) {
VideoQuality.SD ->
painterResource(R.drawable.video_resolution_sd_icon)
Expand Down Expand Up @@ -1589,6 +1598,7 @@ fun FlipCameraButton(
contentDescription = contentDescription,
modifier = Modifier
.size(IconButtonDefaults.largeIconSize)
.animateToUpright()
.rotate(animatedRotation.value)
)
}
Expand Down
Loading
Loading