New feature: flashlight (#61)

This commit is contained in:
pynicolas
2025-11-12 08:12:06 +01:00
committed by GitHub
parent ffdd2e077e
commit 7fc4e4e603
11 changed files with 54 additions and 4 deletions

View File

@@ -18,6 +18,7 @@ import android.graphics.Bitmap
import android.util.Log
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.LinearLayout
import androidx.camera.core.CameraControl
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
@@ -136,7 +137,9 @@ fun bindCameraUseCases(
captureController.imageCapture = imageCapture
val cameraProvider = cameraProviderFuture.get()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageAnalysis, preview, imageCapture)
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector,
imageAnalysis, preview, imageCapture)
captureController.cameraControl = camera.cameraControl
}
@Composable
@@ -197,6 +200,7 @@ fun replaceColor(bitmap: Bitmap, toReplace: Color, replacement: Color): Bitmap {
fun Point.toOffset() = Offset(x.toFloat(), y.toFloat())
class CameraCaptureController {
var cameraControl: CameraControl? = null
var imageCapture: ImageCapture? = null
private val executor = Executors.newSingleThreadExecutor()

View File

@@ -45,6 +45,10 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.filled.FlashOff
import androidx.compose.material.icons.filled.FlashOn
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
@@ -93,7 +97,8 @@ data class CameraUiState(
val captureState: CaptureState,
val showDetectionError: Boolean,
val isLandscape: Boolean,
val isDebugMode: Boolean
val isDebugMode: Boolean,
val isTorchEnabled: Boolean,
)
const val CAPTURED_IMAGE_DISPLAY_DURATION = 1500L
@@ -112,6 +117,7 @@ fun CameraScreen(
val document by viewModel.documentUiModel.collectAsStateWithLifecycle()
val thumbnailCoords = remember { mutableStateOf(Offset.Zero) }
var isDebugMode by remember { mutableStateOf(false) }
var isTorchEnabled by remember { mutableStateOf(false) }
BackHandler { navigation.back() }
@@ -168,7 +174,8 @@ fun CameraScreen(
captureState,
showDetectionError,
isLandscape = isLandscape,
isDebugMode),
isDebugMode,
isTorchEnabled),
onCapture = {
previewView?.bitmap?.let {
Log.i("FairScan", "Pressed <Capture>")
@@ -180,6 +187,9 @@ fun CameraScreen(
},
onFinalizePressed = onFinalizePressed,
onDebugModeSwitched = { isDebugMode = !isDebugMode },
onTorchSwitched = {
isTorchEnabled = !isTorchEnabled
captureController.cameraControl?.enableTorch(isTorchEnabled) },
thumbnailCoords = thumbnailCoords,
navigation = navigation
)
@@ -193,6 +203,7 @@ private fun CameraScreenScaffold(
onCapture: () -> Unit,
onFinalizePressed: () -> Unit,
onDebugModeSwitched: () -> Unit,
onTorchSwitched: () -> Unit,
thumbnailCoords: MutableState<Offset>,
navigation: Navigation,
) {
@@ -225,6 +236,7 @@ private fun CameraScreenScaffold(
cameraPreview,
cameraUiState,
onCapture,
onTorchSwitched,
modifier.clickable(onClick = onPageCountClick))
}
if (cameraUiState.captureState is CaptureState.CapturePreview) {
@@ -238,6 +250,7 @@ private fun CameraPreviewBox(
cameraPreview: @Composable (() -> Unit),
cameraUiState: CameraUiState,
onCapture: () -> Unit,
onTorchSwitched: () -> Unit,
modifier: Modifier,
) {
Box(
@@ -257,6 +270,20 @@ private fun CameraPreviewBox(
.align(Alignment.BottomCenter)
.padding(16.dp)
)
IconButton(
onClick = onTorchSwitched,
modifier = Modifier.align(Alignment.BottomStart)
) {
val torchEnabled = cameraUiState.isTorchEnabled
val icon = if (torchEnabled) Icons.Default.FlashOn else Icons.Default.FlashOff
Icon(
imageVector = icon,
contentDescription =
stringResource(
if (torchEnabled) R.string.turn_off_torch else R.string.turn_on_torch),
tint = Color.White
)
}
}
}
@@ -479,10 +506,11 @@ private fun ScreenPreview(captureState: CaptureState, rotationDegrees: Float = 0
listState = LazyListState(),
),
cameraUiState = CameraUiState(pageCount = 4, LiveAnalysisState(), captureState,
false, rotationDegrees > 0, false),
false, rotationDegrees > 0, false, false),
onCapture = {},
onFinalizePressed = {},
onDebugModeSwitched = {},
onTorchSwitched = {},
thumbnailCoords = thumbnailCoords,
navigation = dummyNavigation()
)

View File

@@ -40,6 +40,8 @@
<string name="share">Sdílet</string>
<string name="share_pdf">Sdílet PDF</string>
<string name="storage_permission_denied">Nelze uložit PDF: přístup zakázán</string>
<string name="turn_off_torch">Vypnout svítilnu</string>
<string name="turn_on_torch">Zapnout svítilnu</string>
<string name="unknown_size">Neznámá velikost</string>
<string name="version">Verze</string>
<string name="view_the_full_license">Zobrazit úplnou licenci</string>

View File

@@ -39,6 +39,8 @@
<string name="share">Teilen</string>
<string name="share_pdf">PDF teilen</string>
<string name="storage_permission_denied">PDF-Datei kann nicht gespeichert werden: Berechtigung verweigert</string>
<string name="turn_off_torch">Taschenlampe ausschalten</string>
<string name="turn_on_torch">Taschenlampe einschalten</string>
<string name="unknown_size">Unbekannte Größe</string>
<string name="version">Version</string>
<string name="view_the_full_license">Vollständige Lizenz anzeigen</string>

View File

@@ -39,6 +39,8 @@
<string name="share">Compartir</string>
<string name="share_pdf">Compartir PDF</string>
<string name="storage_permission_denied">No se puede guardar el archivo PDF: permiso denegado</string>
<string name="turn_off_torch">Apagar linterna</string>
<string name="turn_on_torch">Encender linterna</string>
<string name="unknown_size">Tamaño desconocido</string>
<string name="version">Versión</string>
<string name="view_the_full_license">Ver la licencia completa</string>

View File

@@ -39,6 +39,8 @@
<string name="share">Partager</string>
<string name="share_pdf">Partager le PDF</string>
<string name="storage_permission_denied">Impossible denregistrer le fichier PDF : permission refusée</string>
<string name="turn_off_torch">Éteindre la torche</string>
<string name="turn_on_torch">Allumer la torche</string>
<string name="unknown_size">Taille inconnue</string>
<string name="version">Version</string>
<string name="view_the_full_license">Voir la licence complète</string>

View File

@@ -39,6 +39,8 @@
<string name="share">Condividi</string>
<string name="share_pdf">Condividi PDF</string>
<string name="storage_permission_denied">Impossibile salvare il file PDF: autorizzazione negata</string>
<string name="turn_off_torch">Spegni la torcia</string>
<string name="turn_on_torch">Accendi la torcia</string>
<string name="unknown_size">Dimensione sconosciuta</string>
<string name="version">Versione</string>
<string name="view_the_full_license">Vedi la licenza completa</string>

View File

@@ -39,6 +39,8 @@
<string name="share">Compartilhar</string>
<string name="share_pdf">Compartilhar PDF</string>
<string name="storage_permission_denied">Não foi possível salvar o arquivo PDF: permissão negada</string>
<string name="turn_off_torch">Desligar lanterna</string>
<string name="turn_on_torch">Ligar lanterna</string>
<string name="unknown_size">Tamanho desconhecido</string>
<string name="version">Versão</string>
<string name="view_the_full_license">Ver licença completa</string>

View File

@@ -39,6 +39,8 @@
<string name="share">Поделиться</string>
<string name="share_pdf">Поделиться PDF</string>
<string name="storage_permission_denied">Не удается сохранить файл PDF: в разрешении отказано</string>
<string name="turn_off_torch">Выключить фонарик</string>
<string name="turn_on_torch">Включить фонарик</string>
<string name="unknown_size">Неизвестный размер</string>
<string name="version">Версия</string>
<string name="view_the_full_license">Просмотреть полную лицензию</string>

View File

@@ -39,6 +39,8 @@
<string name="share">共享</string>
<string name="share_pdf">共享 PDF</string>
<string name="storage_permission_denied">无法保存PDF文件权限被拒绝</string>
<string name="turn_off_torch">关闭手电筒</string>
<string name="turn_on_torch">打开手电筒</string>
<string name="unknown_size">未知大小</string>
<string name="version">版本</string>
<string name="view_the_full_license">查看完整许可证</string>

View File

@@ -40,6 +40,8 @@
<string name="share">Share</string>
<string name="share_pdf">Share PDF</string>
<string name="storage_permission_denied">Cannot save PDF file: permission was denied</string>
<string name="turn_off_torch">Turn off torch</string>
<string name="turn_on_torch">Turn on torch</string>
<string name="unknown_size">Unknown size</string>
<string name="version">Version</string>
<string name="view_the_full_license">View the full license</string>