1 /* <lambda>null2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.jetpackcamera.feature.preview.ui 17 18 import android.graphics.RectF 19 import android.net.Uri 20 import androidx.compose.animation.AnimatedContent 21 import androidx.compose.foundation.Canvas 22 import androidx.compose.foundation.border 23 import androidx.compose.foundation.clickable 24 import androidx.compose.foundation.layout.Box 25 import androidx.compose.foundation.layout.padding 26 import androidx.compose.foundation.layout.size 27 import androidx.compose.foundation.shape.RoundedCornerShape 28 import androidx.compose.runtime.Composable 29 import androidx.compose.ui.Modifier 30 import androidx.compose.ui.draw.clip 31 import androidx.compose.ui.graphics.Color 32 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas 33 import androidx.compose.ui.graphics.nativeCanvas 34 import androidx.compose.ui.platform.LocalContext 35 import androidx.compose.ui.unit.dp 36 import com.google.jetpackcamera.core.common.loadAndRotateBitmap 37 import kotlin.math.min 38 39 @Composable 40 fun ImageWell( 41 modifier: Modifier = Modifier, 42 imageWellUiState: ImageWellUiState = ImageWellUiState.NoPreviousCapture, 43 onClick: (uri: Uri?) -> Unit 44 ) { 45 val context = LocalContext.current 46 47 when (imageWellUiState) { 48 is ImageWellUiState.LastCapture -> { 49 val bitmap = loadAndRotateBitmap(context, imageWellUiState.uri, 270f) 50 51 bitmap?.let { 52 Box( 53 modifier = modifier 54 .size(120.dp) 55 .padding(18.dp) 56 .border(2.dp, Color.White, RoundedCornerShape(16.dp)) 57 .clip(RoundedCornerShape(16.dp)) 58 .clickable(onClick = { onClick(imageWellUiState.uri) }) 59 ) { 60 AnimatedContent( 61 targetState = bitmap 62 ) { targetBitmap -> 63 Canvas( 64 modifier = Modifier 65 .size(110.dp) 66 ) { 67 drawIntoCanvas { canvas -> 68 val canvasSize = min(size.width, size.height) 69 70 val scale = canvasSize / min( 71 targetBitmap.width, 72 targetBitmap.height 73 ) 74 75 val imageWidth = targetBitmap.width * scale 76 val imageHeight = targetBitmap.height * scale 77 78 val offsetX = (canvasSize - imageWidth) / 2f 79 val offsetY = (canvasSize - imageHeight) / 2f 80 81 canvas.nativeCanvas.drawBitmap( 82 targetBitmap, 83 null, 84 RectF( 85 offsetX, 86 offsetY, 87 offsetX + imageWidth, 88 offsetY + imageHeight 89 ), 90 null 91 ) 92 } 93 } 94 } 95 } 96 } 97 } 98 99 is ImageWellUiState.NoPreviousCapture -> { 100 } 101 } 102 } 103 104 // TODO(yasith): Add support for Video 105 sealed interface ImageWellUiState { 106 data object NoPreviousCapture : ImageWellUiState 107 108 data class LastCapture(val uri: Uri) : ImageWellUiState 109 } 110