diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bf1b4ed49..7fdc3fafe 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -44,8 +44,8 @@
diff --git a/app/src/main/java/com/google/jetpackcamera/MainActivity.kt b/app/src/main/java/com/google/jetpackcamera/MainActivity.kt
index 2e13a2e58..32c3002af 100644
--- a/app/src/main/java/com/google/jetpackcamera/MainActivity.kt
+++ b/app/src/main/java/com/google/jetpackcamera/MainActivity.kt
@@ -38,6 +38,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
@@ -102,6 +103,7 @@ class MainActivity : ComponentActivity() {
}
is Success -> {
+ val previewMode = remember { getPreviewMode() }
// TODO(kimblebee@): add app setting to enable/disable dynamic color
JetpackCameraTheme(
darkTheme = isInDarkMode(uiState = uiState),
@@ -117,7 +119,7 @@ class MainActivity : ComponentActivity() {
) {
JcaApp(
onPreviewViewModel = { previewViewModel = it },
- previewMode = getPreviewMode()
+ previewMode = previewMode
)
}
}
diff --git a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewScreen.kt b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewScreen.kt
index 1b7657366..599189a2f 100644
--- a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewScreen.kt
+++ b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewScreen.kt
@@ -31,24 +31,27 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.jetpackcamera.feature.preview.ui.BlinkState
import com.google.jetpackcamera.feature.preview.ui.CameraControlsOverlay
import com.google.jetpackcamera.feature.preview.ui.PreviewDisplay
import com.google.jetpackcamera.feature.preview.ui.ScreenFlashScreen
+import com.google.jetpackcamera.feature.preview.ui.SmoothImmersiveRotationEffect
import com.google.jetpackcamera.feature.preview.ui.TestableToast
+import com.google.jetpackcamera.feature.preview.ui.rotatedLayout
import com.google.jetpackcamera.feature.quicksettings.QuickSettingsScreenOverlay
import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.CaptureMode
@@ -71,13 +74,16 @@ fun PreviewScreen(
Log.d(TAG, "PreviewScreen")
onPreviewViewModel(viewModel)
- val previewUiState: PreviewUiState by viewModel.previewUiState.collectAsState()
+ // For this screen, force an immersive view with smooth rotation.
+ SmoothImmersiveRotationEffect(LocalContext.current)
+
+ val previewUiState: PreviewUiState by viewModel.previewUiState.collectAsStateWithLifecycle()
val screenFlashUiState: ScreenFlash.ScreenFlashUiState
- by viewModel.screenFlash.screenFlashUiState.collectAsState()
+ by viewModel.screenFlash.screenFlashUiState.collectAsStateWithLifecycle()
val surfaceRequest: SurfaceRequest?
- by viewModel.surfaceRequest.collectAsState()
+ by viewModel.surfaceRequest.collectAsStateWithLifecycle()
LifecycleStartEffect(Unit) {
viewModel.startCamera()
@@ -163,7 +169,7 @@ private fun ContentScreen(
)
QuickSettingsScreenOverlay(
- modifier = Modifier,
+ modifier = Modifier.rotatedLayout(),
isOpen = previewUiState.quickSettingsIsOpen,
toggleIsOpen = onToggleQuickSettings,
currentCameraSettings = previewUiState.currentCameraSettings,
@@ -175,6 +181,7 @@ private fun ContentScreen(
)
// relative-grid style overlay on top of preview display
CameraControlsOverlay(
+ modifier = Modifier.rotatedLayout(),
previewUiState = previewUiState,
onNavigateToSettings = onNavigateToSettings,
previewMode = previewMode,
diff --git a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/PreviewScreenComponents.kt b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/PreviewScreenComponents.kt
index a5838696e..4e5419c10 100644
--- a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/PreviewScreenComponents.kt
+++ b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/PreviewScreenComponents.kt
@@ -29,12 +29,10 @@ import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.rememberTransformableState
import androidx.compose.foundation.gestures.transformable
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
@@ -56,10 +54,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.google.jetpackcamera.feature.preview.R
@@ -67,6 +67,7 @@ import com.google.jetpackcamera.feature.preview.VideoRecordingState
import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.Stabilization
import com.google.jetpackcamera.settings.model.SupportedStabilizationMode
+import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
private const val TAG = "PreviewScreen"
@@ -132,11 +133,12 @@ fun PreviewDisplay(
val currentOnFlipCamera by rememberUpdatedState(onFlipCamera)
surfaceRequest?.let {
- BoxWithConstraints(
- Modifier
+ Box(
+ modifier
.testTag(PREVIEW_DISPLAY)
.fillMaxSize()
.background(Color.Black)
+ .wrapContentSize()
.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = { offset ->
@@ -145,28 +147,46 @@ fun PreviewDisplay(
currentOnFlipCamera()
}
)
- },
+ }
+ .layout { measurable, constraints ->
+ val maxWidth = constraints.maxWidth.toFloat()
+ val maxHeight = constraints.maxHeight.toFloat()
+ val maxAspectRatio: Float = maxWidth / maxHeight
+ val aspectRatioFloat: Float = aspectRatio.ratio.toFloat()
+
+ val correctAspectRation = if (
+ (maxAspectRatio > 1 && aspectRatioFloat < 1) ||
+ (maxAspectRatio < 1 && aspectRatioFloat > 1)
+ ) {
+ 1 / aspectRatioFloat
+ } else {
+ aspectRatioFloat
+ }
+ val shouldUseMaxWidth = maxAspectRatio <= correctAspectRation
+ val width = if (shouldUseMaxWidth) maxWidth else maxHeight * correctAspectRation
+ val height =
+ if (!shouldUseMaxWidth) maxHeight else maxWidth / correctAspectRation
+
+ val placeable = measurable.measure(
+ Constraints.fixed(
+ width.roundToInt(),
+ height.roundToInt()
+ )
+ )
+
+ layout(placeable.width, placeable.height) {
+ placeable.place(0, 0)
+ }
+ }
+ .transformable(state = transformableState)
+ .alpha(blinkState.alpha),
contentAlignment = Alignment.Center
) {
- val maxAspectRatio: Float = maxWidth / maxHeight
- val aspectRatioFloat: Float = aspectRatio.ratio.toFloat()
- val shouldUseMaxWidth = maxAspectRatio <= aspectRatioFloat
- val width = if (shouldUseMaxWidth) maxWidth else maxHeight * aspectRatioFloat
- val height = if (!shouldUseMaxWidth) maxHeight else maxWidth / aspectRatioFloat
- Box(
- modifier = Modifier
- .width(width)
- .height(height)
- .transformable(state = transformableState)
- .alpha(blinkState.alpha)
-
- ) {
- CameraXViewfinder(
- modifier = Modifier.fillMaxSize(),
- surfaceRequest = it
- )
- }
+ CameraXViewfinder(
+ modifier = Modifier.fillMaxSize(),
+ surfaceRequest = it
+ )
}
}
}
diff --git a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/RotationUtil.kt b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/RotationUtil.kt
new file mode 100644
index 000000000..e1ee2b3b0
--- /dev/null
+++ b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/ui/RotationUtil.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.jetpackcamera.feature.preview.ui
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.os.Build
+import android.view.Surface
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT
+import android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS
+import androidx.activity.ComponentActivity
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.unit.Constraints
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
+
+/**
+ * As long as this composable is active, the window will go into immersive mode and prevents the
+ * rotation animation on configuration change. This will prevent the UI items from visually changing.
+ *
+ * When used in combination with a composable that renders the same UI in both landscape and portrait,
+ * it can create a smooth continuous feel between those two orientations.
+ */
+@Composable
+fun SmoothImmersiveRotationEffect(context: Context) = DisposableEffect(context) {
+ var currentRotationAnimation: Int? = null
+ context.getActivity()?.window?.let { window ->
+ window.attributes = window.attributes.apply {
+ currentRotationAnimation = rotationAnimation
+ rotationAnimation = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ROTATION_ANIMATION_SEAMLESS
+ } else {
+ ROTATION_ANIMATION_JUMPCUT
+ }
+ }
+ WindowCompat.getInsetsController(window, window.decorView).apply {
+ systemBarsBehavior =
+ WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ hide(WindowInsetsCompat.Type.systemBars())
+ }
+ }
+ onDispose {
+ context.getActivity()?.window?.let { window ->
+ if (currentRotationAnimation != null) {
+ window.attributes = window.attributes.apply {
+ rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE
+ }
+ }
+ WindowCompat.getInsetsController(window, window.decorView).apply {
+ show(WindowInsetsCompat.Type.systemBars())
+ }
+ }
+ }
+}
+
+/**
+ * Rotate a layout based on the current screen orientation. The UI will always be laid out in a way
+ * that width <= height, and rotated afterwards.
+ */
+@Composable
+fun Modifier.rotatedLayout(): Modifier {
+ var currentOrientation by remember { mutableIntStateOf(Surface.ROTATION_0) }
+ val currentDegrees = currentOrientation * 90f
+ val newOrientation = LocalConfiguration.current.orientation
+ val display = LocalView.current.display
+ LaunchedEffect(newOrientation, display) {
+ val newRotation = display.rotation
+ if (currentOrientation != newRotation) {
+ currentOrientation = newRotation
+ }
+ }
+ return this then Modifier.fillMaxSize().layout { measurable, constraints ->
+ val height = maxOf(constraints.maxWidth, constraints.maxHeight)
+ val width = minOf(constraints.maxWidth, constraints.maxHeight)
+ val placeable = measurable.measure(
+ Constraints.fixed(width, height)
+ )
+ layout(placeable.width, placeable.height) {
+ placeable.placeWithLayer(0, 0) {
+ if (constraints.maxWidth > constraints.maxHeight) {
+ rotationZ = -currentDegrees
+ }
+ }
+ }
+ }
+}
+
+private fun Context.getActivity(): ComponentActivity? = when (this) {
+ is ComponentActivity -> this
+ is ContextWrapper -> baseContext.getActivity()
+ else -> null
+}
diff --git a/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/QuickSettingsScreen.kt b/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/QuickSettingsScreen.kt
index fb34228a0..29f3be0e2 100644
--- a/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/QuickSettingsScreen.kt
+++ b/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/QuickSettingsScreen.kt
@@ -23,6 +23,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
@@ -45,7 +47,6 @@ import com.google.jetpackcamera.feature.quicksettings.ui.QuickFlipCamera
import com.google.jetpackcamera.feature.quicksettings.ui.QuickSetCaptureMode
import com.google.jetpackcamera.feature.quicksettings.ui.QuickSetFlash
import com.google.jetpackcamera.feature.quicksettings.ui.QuickSetRatio
-import com.google.jetpackcamera.feature.quicksettings.ui.QuickSettingsGrid
import com.google.jetpackcamera.quicksettings.R
import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.CameraAppSettings
@@ -128,6 +129,7 @@ private enum class IsExpandedQuickSetting {
/**
* The UI component for quick settings when it is expanded.
*/
+@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun ExpandedQuickSettingsUi(
currentCameraSettings: CameraAppSettings,
@@ -151,48 +153,37 @@ private fun ExpandedQuickSettingsUi(
// to change the order of display just move these lines of code above or below each other
when (shouldShowQuickSetting) {
IsExpandedQuickSetting.NONE -> {
- val displayedQuickSettings: Array<@Composable () -> Unit> =
- arrayOf(
- {
- QuickSetFlash(
- modifier = Modifier.testTag(QUICK_SETTINGS_FLASH_BUTTON),
- onClick = { f: FlashMode -> onFlashModeClick(f) },
- currentFlashMode = currentCameraSettings.flashMode
- )
- },
- {
- QuickFlipCamera(
- modifier = Modifier.testTag(QUICK_SETTINGS_FLIP_CAMERA_BUTTON),
- setLensFacing = { l: LensFacing -> onLensFaceClick(l) },
- currentLensFacing = currentCameraSettings.cameraLensFacing
- )
- },
- {
- QuickSetRatio(
- modifier = Modifier.testTag(QUICK_SETTINGS_RATIO_BUTTON),
- onClick = {
- setVisibleQuickSetting(
- IsExpandedQuickSetting.ASPECT_RATIO
- )
- },
- ratio = currentCameraSettings.aspectRatio,
- currentRatio = currentCameraSettings.aspectRatio
+ FlowRow {
+ QuickSetFlash(
+ modifier = Modifier.testTag(QUICK_SETTINGS_FLASH_BUTTON),
+ onClick = { f: FlashMode -> onFlashModeClick(f) },
+ currentFlashMode = currentCameraSettings.flashMode
+ )
+ QuickFlipCamera(
+ modifier = Modifier.testTag(QUICK_SETTINGS_FLIP_CAMERA_BUTTON),
+ setLensFacing = { l: LensFacing -> onLensFaceClick(l) },
+ currentLensFacing = currentCameraSettings.cameraLensFacing
+ )
+ QuickSetRatio(
+ modifier = Modifier.testTag(QUICK_SETTINGS_RATIO_BUTTON),
+ onClick = {
+ setVisibleQuickSetting(
+ IsExpandedQuickSetting.ASPECT_RATIO
)
},
- {
- QuickSetCaptureMode(
- modifier = Modifier.testTag(QUICK_SETTINGS_CAPTURE_MODE_BUTTON),
- setCaptureMode = { c: CaptureMode -> onCaptureModeClick(c) },
- currentCaptureMode = currentCameraSettings.captureMode
- )
- }
+ ratio = currentCameraSettings.aspectRatio,
+ currentRatio = currentCameraSettings.aspectRatio
)
- QuickSettingsGrid(quickSettingsButtons = displayedQuickSettings)
+ QuickSetCaptureMode(
+ modifier = Modifier.testTag(QUICK_SETTINGS_CAPTURE_MODE_BUTTON),
+ setCaptureMode = { c: CaptureMode -> onCaptureModeClick(c) },
+ currentCaptureMode = currentCameraSettings.captureMode
+ )
+ }
}
// if a setting that can be expanded is selected, show it
IsExpandedQuickSetting.ASPECT_RATIO -> {
ExpandedQuickSetRatio(
-
setRatio = onAspectRatioClick,
currentRatio = currentCameraSettings.aspectRatio
)
diff --git a/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/ui/QuickSettingsComponents.kt b/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/ui/QuickSettingsComponents.kt
index 631fb33da..7c65851a6 100644
--- a/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/ui/QuickSettingsComponents.kt
+++ b/feature/quicksettings/src/main/java/com/google/jetpackcamera/feature/quicksettings/ui/QuickSettingsComponents.kt
@@ -19,13 +19,12 @@ import androidx.annotation.DrawableRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -33,7 +32,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
@@ -52,45 +50,37 @@ import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.CaptureMode
import com.google.jetpackcamera.settings.model.FlashMode
import com.google.jetpackcamera.settings.model.LensFacing
-import kotlin.math.min
// completed components ready to go into preview screen
+@OptIn(ExperimentalLayoutApi::class)
@Composable
fun ExpandedQuickSetRatio(
setRatio: (aspectRatio: AspectRatio) -> Unit,
currentRatio: AspectRatio,
modifier: Modifier = Modifier
) {
- val buttons: Array<@Composable () -> Unit> =
- arrayOf(
- {
- QuickSetRatio(
- onClick = { setRatio(AspectRatio.THREE_FOUR) },
- ratio = AspectRatio.THREE_FOUR,
- currentRatio = currentRatio,
- isHighlightEnabled = true
- )
- },
- {
- QuickSetRatio(
- onClick = { setRatio(AspectRatio.NINE_SIXTEEN) },
- ratio = AspectRatio.NINE_SIXTEEN,
- currentRatio = currentRatio,
- isHighlightEnabled = true
- )
- },
- {
- QuickSetRatio(
- modifier = Modifier.testTag(QUICK_SETTINGS_RATIO_1_1_BUTTON),
- onClick = { setRatio(AspectRatio.ONE_ONE) },
- ratio = AspectRatio.ONE_ONE,
- currentRatio = currentRatio,
- isHighlightEnabled = true
- )
- }
+ FlowRow(modifier) {
+ QuickSetRatio(
+ onClick = { setRatio(AspectRatio.THREE_FOUR) },
+ ratio = AspectRatio.THREE_FOUR,
+ currentRatio = currentRatio,
+ isHighlightEnabled = true
+ )
+ QuickSetRatio(
+ onClick = { setRatio(AspectRatio.NINE_SIXTEEN) },
+ ratio = AspectRatio.NINE_SIXTEEN,
+ currentRatio = currentRatio,
+ isHighlightEnabled = true
)
- ExpandedQuickSetting(modifier = modifier, quickSettingButtons = buttons)
+ QuickSetRatio(
+ modifier = Modifier.testTag(QUICK_SETTINGS_RATIO_1_1_BUTTON),
+ onClick = { setRatio(AspectRatio.ONE_ONE) },
+ ratio = AspectRatio.ONE_ONE,
+ currentRatio = currentRatio,
+ isHighlightEnabled = true
+ )
+ }
}
@Composable
@@ -276,77 +266,6 @@ fun QuickSettingUiItem(
}
}
-/**
- * Should you want to have an expanded view of a single quick setting
- */
-@Composable
-fun ExpandedQuickSetting(
- modifier: Modifier = Modifier,
- vararg quickSettingButtons: @Composable () -> Unit
-) {
- val expandedNumOfColumns =
- min(
- quickSettingButtons.size,
- (
- (
- LocalConfiguration.current.screenWidthDp.dp - (
- dimensionResource(
- id = R.dimen.quick_settings_ui_horizontal_padding
- ) * 2
- )
- ) /
- (
- dimensionResource(id = R.dimen.quick_settings_ui_item_icon_size) +
- (dimensionResource(id = R.dimen.quick_settings_ui_item_padding) * 2)
- )
- ).toInt()
- )
- LazyVerticalGrid(
- modifier = modifier.fillMaxWidth(),
- columns = GridCells.Fixed(count = expandedNumOfColumns)
- ) {
- items(quickSettingButtons.size) { i ->
- quickSettingButtons[i]()
- }
- }
-}
-
-/**
- * Algorithm to determine dimensions of QuickSettings Icon layout
- */
-@Composable
-fun QuickSettingsGrid(
- modifier: Modifier = Modifier,
- vararg quickSettingsButtons: @Composable () -> Unit
-) {
- val initialNumOfColumns =
- min(
- quickSettingsButtons.size,
- (
- (
- LocalConfiguration.current.screenWidthDp.dp - (
- dimensionResource(
- id = R.dimen.quick_settings_ui_horizontal_padding
- ) * 2
- )
- ) /
- (
- dimensionResource(id = R.dimen.quick_settings_ui_item_icon_size) +
- (dimensionResource(id = R.dimen.quick_settings_ui_item_padding) * 2)
- )
- ).toInt()
- )
-
- LazyVerticalGrid(
- modifier = modifier.fillMaxWidth(),
- columns = GridCells.Fixed(count = initialNumOfColumns)
- ) {
- items(quickSettingsButtons.size) { i ->
- quickSettingsButtons[i]()
- }
- }
-}
-
/**
* The top bar indicators for quick settings items.
*/
diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts
index 30a2251c4..bb979097d 100644
--- a/feature/settings/build.gradle.kts
+++ b/feature/settings/build.gradle.kts
@@ -90,6 +90,10 @@ dependencies {
implementation(libs.compose.ui.tooling.preview)
debugImplementation(libs.compose.ui.tooling)
+ // Compose - Lifecycle utilities
+ implementation(libs.androidx.lifecycle.viewmodel.compose)
+ implementation(libs.androidx.lifecycle.runtime.compose)
+
// Compose - Integration with ViewModels with Navigation and Hilt
implementation(libs.hilt.navigation.compose)
diff --git a/feature/settings/src/main/java/com/google/jetpackcamera/settings/SettingsScreen.kt b/feature/settings/src/main/java/com/google/jetpackcamera/settings/SettingsScreen.kt
index 63b39a90a..bc2e8013b 100644
--- a/feature/settings/src/main/java/com/google/jetpackcamera/settings/SettingsScreen.kt
+++ b/feature/settings/src/main/java/com/google/jetpackcamera/settings/SettingsScreen.kt
@@ -22,12 +22,12 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.CaptureMode
import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS
@@ -56,7 +56,7 @@ fun SettingsScreen(
viewModel: SettingsViewModel = hiltViewModel(),
onNavigateBack: () -> Unit
) {
- val settingsUiState by viewModel.settingsUiState.collectAsState()
+ val settingsUiState by viewModel.settingsUiState.collectAsStateWithLifecycle()
SettingsScreen(
uiState = settingsUiState,