fix: Improve camera-info.kt and CamerasSelection

This commit is contained in:
Myzel394 2023-12-04 09:27:28 +01:00
parent 7f757f46f3
commit 8a3bfcae4d
No known key found for this signature in database
GPG Key ID: 50098FCA22080F0F
6 changed files with 121 additions and 104 deletions

View File

@ -1,5 +1,4 @@
package app.myzel394.alibi.ui.components.RecorderScreen.atoms import androidx.camera.core.ExperimentalLensFacing
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
@ -28,6 +27,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.myzel394.alibi.ui.utils.CameraInfo import app.myzel394.alibi.ui.utils.CameraInfo
@Composable @Composable
fun CameraSelectionButton( fun CameraSelectionButton(
cameraID: CameraInfo.Lens, cameraID: CameraInfo.Lens,

View File

@ -1,10 +1,13 @@
package app.myzel394.alibi.ui.components.RecorderScreen.molecules package app.myzel394.alibi.ui.components.RecorderScreen.molecules
import CameraSelectionButton
import androidx.annotation.OptIn
import androidx.camera.core.CameraSelector
import androidx.camera.core.ExperimentalLensFacing
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import app.myzel394.alibi.R import app.myzel394.alibi.R
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.CameraSelectionButton
import app.myzel394.alibi.ui.models.VideoRecorderSettingsModel import app.myzel394.alibi.ui.models.VideoRecorderSettingsModel
import app.myzel394.alibi.ui.utils.CameraInfo import app.myzel394.alibi.ui.utils.CameraInfo
@ -24,23 +27,23 @@ fun CamerasSelection(
CameraSelectionButton( CameraSelectionButton(
cameraID = CameraInfo.Lens.BACK, cameraID = CameraInfo.Lens.BACK,
label = stringResource(R.string.ui_videoRecorder_action_start_settings_cameraLens_back_label), label = stringResource(R.string.ui_videoRecorder_action_start_settings_cameraLens_back_label),
selected = videoSettings.cameraID == 0, selected = videoSettings.cameraID == CameraInfo.Lens.BACK.androidValue,
onSelected = { onSelected = {
videoSettings.cameraID = 0 videoSettings.cameraID = CameraInfo.Lens.BACK.androidValue
}, },
) )
CameraSelectionButton( CameraSelectionButton(
cameraID = CameraInfo.Lens.FRONT, cameraID = CameraInfo.Lens.FRONT,
label = stringResource(R.string.ui_videoRecorder_action_start_settings_cameraLens_front_label), label = stringResource(R.string.ui_videoRecorder_action_start_settings_cameraLens_front_label),
selected = videoSettings.cameraID == 1, selected = videoSettings.cameraID == CameraInfo.Lens.FRONT.androidValue,
onSelected = { onSelected = {
videoSettings.cameraID = 1 videoSettings.cameraID = CameraInfo.Lens.FRONT.androidValue
}, },
) )
} else { } else {
cameras.forEach { camera -> cameras.forEach { camera ->
CameraSelectionButton( CameraSelectionButton(
cameraID = CameraInfo.CAMERA_INT_TO_LENS_MAP[camera.id]!!, cameraID = camera.lens,
selected = videoSettings.cameraID == camera.id, selected = videoSettings.cameraID == camera.id,
onSelected = { onSelected = {
videoSettings.cameraID = camera.id videoSettings.cameraID = camera.id

View File

@ -1,6 +1,7 @@
package app.myzel394.alibi.ui.components.RecorderScreen.molecules package app.myzel394.alibi.ui.components.RecorderScreen.molecules
import android.Manifest import android.Manifest
import androidx.camera.core.CameraSelector
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitEachGesture import androidx.compose.foundation.gestures.awaitEachGesture
@ -10,6 +11,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -26,6 +28,10 @@ import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -45,12 +51,12 @@ import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.CameraPreview import app.myzel394.alibi.ui.components.RecorderScreen.atoms.CameraPreview
import app.myzel394.alibi.ui.components.atoms.GlobalSwitch import app.myzel394.alibi.ui.components.atoms.GlobalSwitch
import app.myzel394.alibi.ui.components.atoms.PermissionRequester import app.myzel394.alibi.ui.components.atoms.PermissionRequester
import app.myzel394.alibi.ui.effects.rememberPrevious
import app.myzel394.alibi.ui.models.VideoRecorderSettingsModel import app.myzel394.alibi.ui.models.VideoRecorderSettingsModel
import app.myzel394.alibi.ui.utils.CameraInfo import app.myzel394.alibi.ui.utils.CameraInfo
@OptIn( @OptIn(
ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class,
ExperimentalComposeUiApi::class
) )
@Composable @Composable
fun VideoRecorderPreparationSheet( fun VideoRecorderPreparationSheet(
@ -69,19 +75,34 @@ fun VideoRecorderPreparationSheet(
videoSettings.init(context) videoSettings.init(context)
} }
if (showPreview)
CameraPreview(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
)
else {
ModalBottomSheet( ModalBottomSheet(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
sheetState = sheetState, sheetState = sheetState,
dragHandle = if (showPreview) {
null
} else null,
) { ) {
Box( Box(
modifier = Modifier
.pointerInput(Unit) {
awaitEachGesture {
while (true) {
val event = awaitPointerEvent()
if (!event.changes.elementAt(0).pressed) {
onPreviewHidden()
break
}
}
}
}
) { ) {
if (showPreview) {
CameraPreview(
modifier = Modifier
.fillMaxSize(),
cameraSelector = videoSettings.cameraSelector,
)
} else
Column( Column(
modifier = Modifier modifier = Modifier
.padding(horizontal = 16.dp, vertical = 24.dp), .padding(horizontal = 16.dp, vertical = 24.dp),
@ -119,6 +140,9 @@ fun VideoRecorderPreparationSheet(
) )
} }
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text( Text(
stringResource(R.string.ui_videoRecorder_action_start_settings_cameraLens_selection_label), stringResource(R.string.ui_videoRecorder_action_start_settings_cameraLens_selection_label),
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
@ -129,46 +153,17 @@ fun VideoRecorderPreparationSheet(
cameras = cameras, cameras = cameras,
videoSettings = videoSettings, videoSettings = videoSettings,
) )
Box(
modifier = Modifier
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE)
)
} }
}
}
}
Popup(
alignment = Alignment.BottomCenter,
) {
val label = val label =
stringResource(R.string.ui_videoRecorder_action_start_settings_start_label) stringResource(R.string.ui_videoRecorder_action_start_settings_start_label)
Box( Column(
modifier = Modifier verticalArrangement = Arrangement.spacedBy(8.dp),
.pointerInput(Unit) { horizontalAlignment = Alignment.CenterHorizontally,
awaitEachGesture {
while (true) {
val event = awaitPointerEvent()
// consume all changes
if (!event.changes.elementAt(0).pressed) {
onPreviewHidden()
break
}
}
}
}
.let {
if (showPreview) it.alpha(0.2f) else it
}
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.padding(16.dp)
.fillMaxWidth() .fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE) .height(BIG_PRIMARY_BUTTON_SIZE)
.clip(CircleShape) .clip(CircleShape)
@ -193,6 +188,15 @@ fun VideoRecorderPreparationSheet(
color = MaterialTheme.colorScheme.onPrimary, color = MaterialTheme.colorScheme.onPrimary,
) )
} }
Text(
stringResource(
R.string.ui_videoRecorder_action_preview_label
),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
} }
} }
} }

View File

@ -11,14 +11,18 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import app.myzel394.alibi.ui.utils.CameraInfo
import app.myzel394.alibi.ui.utils.PermissionHelper import app.myzel394.alibi.ui.utils.PermissionHelper
class VideoRecorderSettingsModel : ViewModel() { class VideoRecorderSettingsModel : ViewModel() {
var enableAudio by mutableStateOf(true) var enableAudio by mutableStateOf(true)
var cameraID by mutableIntStateOf(CameraSelector.LENS_FACING_BACK) var cameraID by mutableIntStateOf(CameraInfo.Lens.BACK.androidValue)
val cameraSelector: CameraSelector
get() = CameraSelector.Builder().requireLensFacing(cameraID).build()
fun init(context: Context) { fun init(context: Context) {
enableAudio = PermissionHelper.hasGranted(context, Manifest.permission.RECORD_AUDIO) enableAudio = PermissionHelper.hasGranted(context, Manifest.permission.RECORD_AUDIO)
cameraID = CameraSelector.LENS_FACING_BACK cameraID = CameraInfo.Lens.BACK.androidValue
} }
} }

View File

@ -4,22 +4,28 @@ import android.content.Context
import android.hardware.camera2.CameraCharacteristics import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager import android.hardware.camera2.CameraManager
import android.hardware.camera2.CameraMetadata import android.hardware.camera2.CameraMetadata
import androidx.annotation.OptIn
import androidx.camera.core.CameraSelector
import androidx.camera.core.ExperimentalLensFacing
@OptIn(ExperimentalLensFacing::class)
data class CameraInfo( data class CameraInfo(
val lens: Lens,
val id: Int, val id: Int,
) { ) {
enum class Lens(val androidValue: Int) { enum class Lens(val androidValue: Int) {
BACK(CameraMetadata.LENS_FACING_BACK), BACK(CameraSelector.LENS_FACING_BACK),
FRONT(CameraMetadata.LENS_FACING_FRONT), FRONT(CameraSelector.LENS_FACING_FRONT),
EXTERNAL(CameraMetadata.LENS_FACING_EXTERNAL), EXTERNAL(CameraSelector.LENS_FACING_EXTERNAL),
} }
val lens: Lens
get() = CAMERA_INT_TO_LENS_MAP[id]!!
companion object { companion object {
val CAMERA_INT_TO_LENS_MAP = mapOf( val CAMERA_INT_TO_LENS_MAP = mapOf(
0 to Lens.BACK, CameraSelector.LENS_FACING_BACK to Lens.BACK,
1 to Lens.FRONT, CameraSelector.LENS_FACING_FRONT to Lens.FRONT,
2 to Lens.EXTERNAL, CameraSelector.LENS_FACING_EXTERNAL to Lens.EXTERNAL,
) )
fun queryAvailableCameras(context: Context): List<CameraInfo> { fun queryAvailableCameras(context: Context): List<CameraInfo> {
@ -36,7 +42,6 @@ data class CameraInfo(
fun fromCameraId(cameraId: String, lensFacing: Int): CameraInfo { fun fromCameraId(cameraId: String, lensFacing: Int): CameraInfo {
return CameraInfo( return CameraInfo(
lens = CAMERA_INT_TO_LENS_MAP[lensFacing]!!,
id = cameraId.toInt(), id = cameraId.toInt(),
) )
} }

View File

@ -147,4 +147,5 @@
<string name="ui_videoRecorder_action_start_settings_start_label">Start Recording</string> <string name="ui_videoRecorder_action_start_settings_start_label">Start Recording</string>
<string name="ui_videoRecorder_action_start_settings_label">Prepare your recording</string> <string name="ui_videoRecorder_action_start_settings_label">Prepare your recording</string>
<string name="ui_videoRecorder_action_start_settings_cameraLens_selection_label">Select camera</string> <string name="ui_videoRecorder_action_start_settings_cameraLens_selection_label">Select camera</string>
<string name="ui_videoRecorder_action_preview_label">Hold down on button to preview your camera</string>
</resources> </resources>