Dodaj seryjne zdjęcia załadunku i rozładunku
This commit is contained in:
@@ -62,6 +62,7 @@ import androidx.compose.material.icons.outlined.CalendarToday
|
|||||||
import androidx.compose.material.icons.outlined.CheckCircle
|
import androidx.compose.material.icons.outlined.CheckCircle
|
||||||
import androidx.compose.material.icons.outlined.CloudUpload
|
import androidx.compose.material.icons.outlined.CloudUpload
|
||||||
import androidx.compose.material.icons.outlined.BugReport
|
import androidx.compose.material.icons.outlined.BugReport
|
||||||
|
import androidx.compose.material.icons.outlined.Collections
|
||||||
import androidx.compose.material.icons.outlined.ContentCopy
|
import androidx.compose.material.icons.outlined.ContentCopy
|
||||||
import androidx.compose.material.icons.outlined.Factory
|
import androidx.compose.material.icons.outlined.Factory
|
||||||
import androidx.compose.material.icons.outlined.Delete
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
@@ -190,6 +191,11 @@ private enum class RouteLocationPermissionPurpose {
|
|||||||
RestoreRequiredTracking,
|
RestoreRequiredTracking,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum class RouteStageCameraMode {
|
||||||
|
Single,
|
||||||
|
Multiple,
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DriverApp(
|
fun DriverApp(
|
||||||
viewModel: DriverViewModel,
|
viewModel: DriverViewModel,
|
||||||
@@ -4425,6 +4431,8 @@ private fun RouteStageScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
var cameraUri by remember { mutableStateOf<Uri?>(null) }
|
var cameraUri by remember { mutableStateOf<Uri?>(null) }
|
||||||
|
var pendingCameraMode by remember { mutableStateOf<RouteStageCameraMode?>(null) }
|
||||||
|
var showMultiplePhotoCamera by remember(stage) { mutableStateOf(false) }
|
||||||
var showPreciseLocationPermissionDialog by remember { mutableStateOf(false) }
|
var showPreciseLocationPermissionDialog by remember { mutableStateOf(false) }
|
||||||
var voiceDictationActive by remember(stage) { mutableStateOf(false) }
|
var voiceDictationActive by remember(stage) { mutableStateOf(false) }
|
||||||
val route = state.displaySelectedRoute
|
val route = state.displaySelectedRoute
|
||||||
@@ -4479,6 +4487,7 @@ private fun RouteStageScreen(
|
|||||||
cameraUri = null
|
cameraUri = null
|
||||||
}
|
}
|
||||||
val cameraPermissionLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { grants ->
|
val cameraPermissionLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { grants ->
|
||||||
|
val requestedMode = pendingCameraMode
|
||||||
val pendingUri = cameraUri
|
val pendingUri = cameraUri
|
||||||
val cameraGranted = grants[Manifest.permission.CAMERA] == true || hasPermission(context, Manifest.permission.CAMERA)
|
val cameraGranted = grants[Manifest.permission.CAMERA] == true || hasPermission(context, Manifest.permission.CAMERA)
|
||||||
val fineLocationGranted = grants[Manifest.permission.ACCESS_FINE_LOCATION] == true ||
|
val fineLocationGranted = grants[Manifest.permission.ACCESS_FINE_LOCATION] == true ||
|
||||||
@@ -4486,14 +4495,43 @@ private fun RouteStageScreen(
|
|||||||
if (!canLaunchCameraWithLocationPolicy(state.requirePreciseLocationForPhotos, fineLocationGranted)) {
|
if (!canLaunchCameraWithLocationPolicy(state.requirePreciseLocationForPhotos, fineLocationGranted)) {
|
||||||
showPreciseLocationPermissionDialog = true
|
showPreciseLocationPermissionDialog = true
|
||||||
cameraUri = null
|
cameraUri = null
|
||||||
|
pendingCameraMode = null
|
||||||
return@rememberLauncherForActivityResult
|
return@rememberLauncherForActivityResult
|
||||||
}
|
}
|
||||||
if (cameraGranted && pendingUri != null) cameraLauncher.launch(pendingUri)
|
if (cameraGranted) {
|
||||||
|
when (requestedMode) {
|
||||||
|
RouteStageCameraMode.Single -> {
|
||||||
|
if (pendingUri != null) cameraLauncher.launch(pendingUri)
|
||||||
|
}
|
||||||
|
RouteStageCameraMode.Multiple -> {
|
||||||
|
showMultiplePhotoCamera = true
|
||||||
|
}
|
||||||
|
null -> Unit
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cameraUri = null
|
||||||
|
}
|
||||||
|
pendingCameraMode = null
|
||||||
}
|
}
|
||||||
val pickerLauncher = rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
|
val pickerLauncher = rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
|
||||||
if (uri != null) onUpload(uri, "gallery", PhotoUploadMetadata())
|
if (uri != null) onUpload(uri, "gallery", PhotoUploadMetadata())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showMultiplePhotoCamera) {
|
||||||
|
MultiplePhotoCameraScreen(
|
||||||
|
stage = stage,
|
||||||
|
onPhotoCaptured = { uri ->
|
||||||
|
coroutineScope.launch {
|
||||||
|
onUpload(uri, "camera", cameraPhotoMetadata(context))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClose = {
|
||||||
|
showMultiplePhotoCamera = false
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
BoxWithConstraints(Modifier.fillMaxSize()) {
|
BoxWithConstraints(Modifier.fillMaxSize()) {
|
||||||
val horizontalPadding = screenHorizontalPaddingDp(maxWidth.value.toInt()).dp
|
val horizontalPadding = screenHorizontalPaddingDp(maxWidth.value.toInt()).dp
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -4573,19 +4611,37 @@ private fun RouteStageScreen(
|
|||||||
if (showPhotoActions) {
|
if (showPhotoActions) {
|
||||||
item {
|
item {
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
CargoActionButton("Zrób nowe zdjęcie", Icons.Outlined.CameraAlt, TppTheme.colors.forest) {
|
RouteStageCameraActions(
|
||||||
|
onSinglePhoto = {
|
||||||
val newUri = createCameraUri(context)
|
val newUri = createCameraUri(context)
|
||||||
cameraUri = newUri
|
cameraUri = newUri
|
||||||
|
pendingCameraMode = RouteStageCameraMode.Single
|
||||||
val missingPermissions = cameraCapturePermissions(
|
val missingPermissions = cameraCapturePermissions(
|
||||||
context = context,
|
context = context,
|
||||||
requirePreciseLocation = state.requirePreciseLocationForPhotos,
|
requirePreciseLocation = state.requirePreciseLocationForPhotos,
|
||||||
)
|
)
|
||||||
if (missingPermissions.isEmpty()) {
|
if (missingPermissions.isEmpty()) {
|
||||||
|
pendingCameraMode = null
|
||||||
cameraLauncher.launch(newUri)
|
cameraLauncher.launch(newUri)
|
||||||
} else {
|
} else {
|
||||||
cameraPermissionLauncher.launch(missingPermissions)
|
cameraPermissionLauncher.launch(missingPermissions)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onMultiplePhotos = {
|
||||||
|
cameraUri = null
|
||||||
|
pendingCameraMode = RouteStageCameraMode.Multiple
|
||||||
|
val missingPermissions = cameraCapturePermissions(
|
||||||
|
context = context,
|
||||||
|
requirePreciseLocation = state.requirePreciseLocationForPhotos,
|
||||||
|
)
|
||||||
|
if (missingPermissions.isEmpty()) {
|
||||||
|
pendingCameraMode = null
|
||||||
|
showMultiplePhotoCamera = true
|
||||||
|
} else {
|
||||||
|
cameraPermissionLauncher.launch(missingPermissions)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
if (state.allowGalleryUploads) {
|
if (state.allowGalleryUploads) {
|
||||||
CargoActionButton("Dodaj zdjęcie z galerii", Icons.Outlined.AddPhotoAlternate, TppTheme.colors.containerGreen) {
|
CargoActionButton("Dodaj zdjęcie z galerii", Icons.Outlined.AddPhotoAlternate, TppTheme.colors.containerGreen) {
|
||||||
pickerLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
|
pickerLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
|
||||||
@@ -5492,6 +5548,107 @@ private fun RouteStageDocumentationBlock(
|
|||||||
private fun formatRouteWeight(weight: Double): String =
|
private fun formatRouteWeight(weight: Double): String =
|
||||||
if (weight % 1.0 == 0.0) "${weight.toInt()} t" else String.format(Locale("pl", "PL"), "%.3f t", weight)
|
if (weight % 1.0 == 0.0) "${weight.toInt()} t" else String.format(Locale("pl", "PL"), "%.3f t", weight)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RouteStageCameraActions(
|
||||||
|
onSinglePhoto: () -> Unit,
|
||||||
|
onMultiplePhotos: () -> Unit,
|
||||||
|
) {
|
||||||
|
BoxWithConstraints(Modifier.fillMaxWidth()) {
|
||||||
|
if (maxWidth >= 300.dp) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
|
) {
|
||||||
|
RouteStageCameraActionButton(
|
||||||
|
label = "Jedno zdjęcie",
|
||||||
|
icon = Icons.Outlined.CameraAlt,
|
||||||
|
color = TppTheme.colors.forest,
|
||||||
|
compact = true,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = onSinglePhoto,
|
||||||
|
)
|
||||||
|
RouteStageCameraActionButton(
|
||||||
|
label = "Wiele zdjęć",
|
||||||
|
icon = Icons.Outlined.Collections,
|
||||||
|
color = TppTheme.colors.navy,
|
||||||
|
compact = true,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = onMultiplePhotos,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
|
RouteStageCameraActionButton(
|
||||||
|
label = "Jedno zdjęcie",
|
||||||
|
icon = Icons.Outlined.CameraAlt,
|
||||||
|
color = TppTheme.colors.forest,
|
||||||
|
compact = false,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
onClick = onSinglePhoto,
|
||||||
|
)
|
||||||
|
RouteStageCameraActionButton(
|
||||||
|
label = "Wiele zdjęć",
|
||||||
|
icon = Icons.Outlined.Collections,
|
||||||
|
color = TppTheme.colors.navy,
|
||||||
|
compact = false,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
onClick = onMultiplePhotos,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RouteStageCameraActionButton(
|
||||||
|
label: String,
|
||||||
|
icon: ImageVector,
|
||||||
|
color: Color,
|
||||||
|
compact: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier.height(if (compact) 76.dp else 64.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = color),
|
||||||
|
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
) {
|
||||||
|
if (compact) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(22.dp),
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = label,
|
||||||
|
color = Color.White,
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Icon(icon, contentDescription = null, tint = Color.White)
|
||||||
|
Spacer(Modifier.width(10.dp))
|
||||||
|
Text(
|
||||||
|
text = label,
|
||||||
|
color = Color.White,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CargoActionButton(label: String, icon: ImageVector, color: Color, onClick: () -> Unit) {
|
private fun CargoActionButton(label: String, icon: ImageVector, color: Color, onClick: () -> Unit) {
|
||||||
Button(
|
Button(
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
package pl.firmatpp.kierowca.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.camera.core.ImageCapture
|
||||||
|
import androidx.camera.core.ImageCaptureException
|
||||||
|
import androidx.camera.view.CameraController
|
||||||
|
import androidx.camera.view.LifecycleCameraController
|
||||||
|
import androidx.camera.view.PreviewView
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||||
|
import androidx.compose.material.icons.outlined.CameraAlt
|
||||||
|
import androidx.compose.material.icons.outlined.CheckCircle
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
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.unit.dp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
|
import java.io.File
|
||||||
|
import pl.firmatpp.kierowca.ui.theme.TppTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun MultiplePhotoCameraScreen(
|
||||||
|
stage: String,
|
||||||
|
onPhotoCaptured: (Uri) -> Unit,
|
||||||
|
onClose: () -> Unit,
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
|
val currentOnPhotoCaptured by rememberUpdatedState(onPhotoCaptured)
|
||||||
|
val cameraController = remember(context) {
|
||||||
|
LifecycleCameraController(context).apply {
|
||||||
|
setEnabledUseCases(CameraController.IMAGE_CAPTURE)
|
||||||
|
imageCaptureMode = ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var capturedCount by remember { mutableIntStateOf(0) }
|
||||||
|
var isCapturing by remember { mutableStateOf(false) }
|
||||||
|
var cameraUnavailable by remember { mutableStateOf(false) }
|
||||||
|
var cameraError by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
|
DisposableEffect(cameraController, lifecycleOwner) {
|
||||||
|
runCatching {
|
||||||
|
cameraController.bindToLifecycle(lifecycleOwner)
|
||||||
|
}.onFailure {
|
||||||
|
cameraUnavailable = true
|
||||||
|
cameraError = "Nie udało się uruchomić aparatu."
|
||||||
|
}
|
||||||
|
|
||||||
|
onDispose {
|
||||||
|
cameraController.unbind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BackHandler {
|
||||||
|
if (!isCapturing) onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Black),
|
||||||
|
) {
|
||||||
|
AndroidView(
|
||||||
|
factory = { previewContext ->
|
||||||
|
PreviewView(previewContext).apply {
|
||||||
|
controller = cameraController
|
||||||
|
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
|
||||||
|
scaleType = PreviewView.ScaleType.FILL_CENTER
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.background(Color.Black.copy(alpha = 0.62f))
|
||||||
|
.statusBarsPadding()
|
||||||
|
.padding(horizontal = 8.dp, vertical = 10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onClose,
|
||||||
|
enabled = !isCapturing,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.AutoMirrored.Outlined.ArrowBack,
|
||||||
|
contentDescription = "Wróć",
|
||||||
|
tint = Color.White,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = if (stage == "loading") "Zdjęcia załadunku" else "Zdjęcia rozładunku",
|
||||||
|
color = Color.White,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Wykonano: $capturedCount",
|
||||||
|
color = Color.White.copy(alpha = 0.78f),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.background(Color.Black.copy(alpha = 0.68f))
|
||||||
|
.navigationBarsPadding()
|
||||||
|
.padding(horizontal = 20.dp, vertical = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
|
) {
|
||||||
|
cameraError?.let { message ->
|
||||||
|
Text(
|
||||||
|
text = message,
|
||||||
|
color = Color.White,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(Color(0xFF8C1D18), RoundedCornerShape(6.dp))
|
||||||
|
.padding(10.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
) {
|
||||||
|
Spacer(Modifier.size(112.dp, 52.dp))
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (isCapturing || cameraUnavailable) return@Button
|
||||||
|
|
||||||
|
val photoFile = createMultipleCameraFile(context)
|
||||||
|
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
|
||||||
|
isCapturing = true
|
||||||
|
cameraController.takePicture(
|
||||||
|
outputOptions,
|
||||||
|
ContextCompat.getMainExecutor(context),
|
||||||
|
object : ImageCapture.OnImageSavedCallback {
|
||||||
|
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||||
|
isCapturing = false
|
||||||
|
cameraError = null
|
||||||
|
capturedCount += 1
|
||||||
|
currentOnPhotoCaptured(cameraFileUri(context, photoFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(exception: ImageCaptureException) {
|
||||||
|
isCapturing = false
|
||||||
|
photoFile.delete()
|
||||||
|
cameraError = "Nie udało się zapisać zdjęcia. Spróbuj ponownie."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
enabled = !isCapturing && !cameraUnavailable,
|
||||||
|
modifier = Modifier.size(78.dp),
|
||||||
|
shape = CircleShape,
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.White,
|
||||||
|
disabledContainerColor = Color.White.copy(alpha = 0.55f),
|
||||||
|
),
|
||||||
|
contentPadding = ButtonDefaults.ContentPadding,
|
||||||
|
) {
|
||||||
|
if (isCapturing) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.size(28.dp),
|
||||||
|
color = TppTheme.colors.forest,
|
||||||
|
strokeWidth = 3.dp,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.CameraAlt,
|
||||||
|
contentDescription = "Zrób zdjęcie",
|
||||||
|
tint = TppTheme.colors.forest,
|
||||||
|
modifier = Modifier.size(32.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = onClose,
|
||||||
|
enabled = !isCapturing,
|
||||||
|
modifier = Modifier.size(width = 112.dp, height = 52.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = TppTheme.colors.forest,
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(6.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.CheckCircle,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Gotowe",
|
||||||
|
color = Color.White,
|
||||||
|
modifier = Modifier.padding(start = 6.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMultipleCameraFile(context: Context): File {
|
||||||
|
val directory = File(context.cacheDir, "camera").apply { mkdirs() }
|
||||||
|
return File.createTempFile("ladunek-", ".jpg", directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cameraFileUri(context: Context, file: File): Uri =
|
||||||
|
FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
|
||||||
Reference in New Issue
Block a user