mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-19 07:15:25 +02:00
fix: Improve camera-info.kt and CamerasSelection
This commit is contained in:
parent
7f757f46f3
commit
8a3bfcae4d
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user