Merge pull request #81 from materoy/master

Add camera preview
This commit is contained in:
Myzel394 2024-03-23 12:29:33 +01:00 committed by GitHub
commit 24928661c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 107 additions and 79 deletions

View File

@ -1,56 +1,56 @@
package app.myzel394.alibi.ui.components.RecorderScreen.atoms package app.myzel394.alibi.ui.components.RecorderScreen.atoms
import android.util.Log
import android.view.ViewGroup import android.view.ViewGroup
import androidx.camera.core.CameraSelector import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import app.myzel394.alibi.ui.utils.getCameraProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
fun CameraPreview( fun CameraPreview(
modifier: Modifier = Modifier, modifier: Modifier,
scaleType: PreviewView.ScaleType = PreviewView.ScaleType.FILL_CENTER,
cameraSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA cameraSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
) { ) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val lifecycleOwner = LocalLifecycleOwner.current val lifecycleOwner = LocalLifecycleOwner.current
Box(modifier = modifier) {
// Video preview
AndroidView( AndroidView(
modifier = modifier,
factory = { context -> factory = { context ->
val previewView = PreviewView(context).apply { val previewView = PreviewView(context).apply {
this.scaleType = scaleType
layoutParams = ViewGroup.LayoutParams( layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT,
) )
} }
// CameraX Preview UseCase
val previewUseCase = Preview.Builder() val previewUseCase = Preview.Builder()
.build() .build()
.also { .also { it.setSurfaceProvider(previewView.surfaceProvider) }
it.setSurfaceProvider(previewView.surfaceProvider)
}
coroutineScope.launch { coroutineScope.launch {
val cameraProvider = ProcessCameraProvider.getInstance(context).get() val cameraProvider = context.getCameraProvider()
try { try {
// Must unbind the use-cases before rebinding them.
cameraProvider.unbindAll() cameraProvider.unbindAll()
cameraProvider.bindToLifecycle( cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, previewUseCase lifecycleOwner,
cameraSelector,
previewUseCase
) )
} catch (ex: Exception) { } catch (ex: Exception) {
Log.e("CameraPreview", "Use case binding failed", ex)
} }
} }
previewView previewView
} },
) )
}
} }

View File

@ -33,6 +33,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.myzel394.alibi.R import app.myzel394.alibi.R
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.CameraPreview
import app.myzel394.alibi.dataStore import app.myzel394.alibi.dataStore
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveCurrentNowModal import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveCurrentNowModal
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.TorchStatus import app.myzel394.alibi.ui.components.RecorderScreen.atoms.TorchStatus
@ -54,6 +55,11 @@ fun VideoRecordingStatus(
when (orientation) { when (orientation) {
Configuration.ORIENTATION_LANDSCAPE -> { Configuration.ORIENTATION_LANDSCAPE -> {
Box {
CameraPreview(
modifier = Modifier,
cameraSelector = videoRecorder.cameraSelector
)
Row( Row(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.SpaceEvenly, horizontalArrangement = Arrangement.SpaceEvenly,
@ -88,8 +94,15 @@ fun VideoRecordingStatus(
} }
} }
} }
}
else -> { else -> {
Box {
CameraPreview(
modifier = Modifier,
cameraSelector = videoRecorder.cameraSelector
)
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -97,8 +110,6 @@ fun VideoRecordingStatus(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween, verticalArrangement = Arrangement.SpaceBetween,
) { ) {
Box {}
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement verticalArrangement = Arrangement
@ -120,6 +131,7 @@ fun VideoRecordingStatus(
} }
} }
} }
}
} }

View File

@ -0,0 +1,16 @@
package app.myzel394.alibi.ui.utils
import android.content.Context
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
suspend fun Context.getCameraProvider(): ProcessCameraProvider = suspendCoroutine { continuation ->
ProcessCameraProvider.getInstance(this).also { future ->
future.addListener({
continuation.resume(future.get())
}, ContextCompat.getMainExecutor(this))
}
}