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.postcapture
17
18 import android.content.Context
19 import android.content.Intent
20 import android.net.Uri
21 import androidx.compose.foundation.Canvas
22 import androidx.compose.foundation.layout.Arrangement
23 import androidx.compose.foundation.layout.Box
24 import androidx.compose.foundation.layout.Row
25 import androidx.compose.foundation.layout.Spacer
26 import androidx.compose.foundation.layout.fillMaxSize
27 import androidx.compose.foundation.layout.fillMaxWidth
28 import androidx.compose.foundation.layout.padding
29 import androidx.compose.foundation.layout.size
30 import androidx.compose.foundation.shape.CircleShape
31 import androidx.compose.material.icons.Icons
32 import androidx.compose.material.icons.filled.Delete
33 import androidx.compose.material.icons.filled.Share
34 import androidx.compose.material3.Icon
35 import androidx.compose.material3.IconButton
36 import androidx.compose.material3.IconButtonDefaults
37 import androidx.compose.material3.MaterialTheme
38 import androidx.compose.material3.Text
39 import androidx.compose.runtime.Composable
40 import androidx.compose.runtime.LaunchedEffect
41 import androidx.compose.runtime.collectAsState
42 import androidx.compose.runtime.getValue
43 import androidx.compose.runtime.remember
44 import androidx.compose.ui.Alignment
45 import androidx.compose.ui.Modifier
46 import androidx.compose.ui.draw.shadow
47 import androidx.compose.ui.geometry.Size
48 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
49 import androidx.compose.ui.graphics.nativeCanvas
50 import androidx.compose.ui.platform.LocalContext
51 import androidx.compose.ui.unit.dp
52 import androidx.hilt.navigation.compose.hiltViewModel
53 import com.google.jetpackcamera.core.common.loadAndRotateBitmap
54
55 @Composable
56 fun PostCaptureScreen(viewModel: PostCaptureViewModel = hiltViewModel(), imageUri: Uri?) {
57 val uiState: PostCaptureUiState by viewModel.uiState.collectAsState()
58 val context = LocalContext.current
59
60 LaunchedEffect(imageUri) {
61 viewModel.setLastCapturedImageUri(imageUri)
62 }
63
64 Box(modifier = Modifier.fillMaxSize()) {
65 uiState.imageUri?.let { uri ->
66 val bitmap = remember(uri) {
67 // TODO(yasith): Get the image rotation from the image
68 loadAndRotateBitmap(context, uri, 270f)
69 }
70
71 if (bitmap != null) {
72 Canvas(modifier = Modifier.fillMaxSize()) {
73 drawIntoCanvas { canvas ->
74 val scale = maxOf(
75 size.width / bitmap.width,
76 size.height / bitmap.height
77 )
78 val imageSize = Size(bitmap.width * scale, bitmap.height * scale)
79 canvas.nativeCanvas.drawBitmap(
80 bitmap,
81 null,
82 android.graphics.RectF(
83 0f,
84 0f,
85 imageSize.width,
86 imageSize.height
87 ),
88 null
89 )
90 }
91 }
92 }
93 } ?: Text(
94 text = "No Image Captured",
95 modifier = Modifier.align(Alignment.Center)
96 )
97
98 Row(
99 modifier = Modifier
100 .fillMaxWidth()
101 .align(Alignment.BottomCenter)
102 .padding(16.dp),
103 horizontalArrangement = Arrangement.SpaceAround
104 ) {
105 // Delete Image Button
106 IconButton(
107 onClick = { viewModel.deleteImage(context.contentResolver) },
108 modifier = Modifier
109 .size(56.dp)
110 .shadow(10.dp, CircleShape),
111 colors = IconButtonDefaults.iconButtonColors(
112 containerColor = MaterialTheme.colorScheme.surface
113 )
114 ) {
115 Icon(
116 imageVector = Icons.Default.Delete,
117 contentDescription = "Delete",
118 tint = MaterialTheme.colorScheme.onSurface
119 )
120 }
121
122 Spacer(modifier = Modifier.weight(1f))
123
124 // Share Image Button
125 IconButton(
126 onClick = {
127 imageUri?.let {
128 shareImage(context, it)
129 }
130 },
131 modifier = Modifier
132 .size(56.dp)
133 .shadow(10.dp, CircleShape),
134 colors = IconButtonDefaults.iconButtonColors(
135 containerColor = MaterialTheme.colorScheme.surface
136 )
137 ) {
138 Icon(
139 imageVector = Icons.Default.Share,
140 contentDescription = "Share",
141 tint = MaterialTheme.colorScheme.onSurface
142 )
143 }
144 }
145 }
146 }
147
148 /**
149 * Starts an intent to share an image
150 *
151 * @param context The application context
152 * @param imagePath The path to the image to share
153 */
shareImagenull154 private fun shareImage(context: Context, uri: Uri) {
155 val intent = Intent(Intent.ACTION_SEND).apply {
156 type = "image/jpeg"
157 putExtra(Intent.EXTRA_STREAM, uri)
158 }
159 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
160 context.startActivity(Intent.createChooser(intent, "Share Image"))
161 }
162