mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
Merge pull request #80 from Myzel394/fix-71-improve-landscape
Improve landscape
This commit is contained in:
commit
38fc299fc6
@ -1,3 +1,9 @@
|
|||||||
|
# services
|
||||||
|
|
||||||
|
This folder contains all available services.
|
||||||
|
|
||||||
|
## VideoRecorderService
|
||||||
|
|
||||||
I found it a bit confusing on how to properly handle the services, so I made this diagram
|
I found it a bit confusing on how to properly handle the services, so I made this diagram
|
||||||
to help me understand it better. I hope it helps you too.
|
to help me understand it better. I hope it helps you too.
|
||||||
|
|
||||||
|
@ -194,7 +194,9 @@ class VideoRecorderService :
|
|||||||
selectedCamera,
|
selectedCamera,
|
||||||
videoCapture
|
videoCapture
|
||||||
)
|
)
|
||||||
cameraControl = CameraControl(camera!!)
|
cameraControl = CameraControl(camera!!).also {
|
||||||
|
it.init()
|
||||||
|
}
|
||||||
onCameraControlAvailable()
|
onCameraControlAvailable()
|
||||||
|
|
||||||
_cameraAvailableListener.complete(Unit)
|
_cameraAvailableListener.complete(Unit)
|
||||||
@ -309,17 +311,25 @@ class VideoRecorderService :
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CameraControl(
|
class CameraControl(
|
||||||
val camera: Camera
|
val camera: Camera,
|
||||||
|
// Save state for optimistic updates
|
||||||
|
var torchEnabled: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
fun init() {
|
||||||
|
torchEnabled = camera.cameraInfo.torchState.value == TorchState.ON
|
||||||
|
}
|
||||||
|
|
||||||
fun enableTorch() {
|
fun enableTorch() {
|
||||||
|
torchEnabled = true
|
||||||
camera.cameraControl.enableTorch(true)
|
camera.cameraControl.enableTorch(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableTorch() {
|
fun disableTorch() {
|
||||||
|
torchEnabled = false
|
||||||
camera.cameraControl.enableTorch(false)
|
camera.cameraControl.enableTorch(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isTorchEnabled(): Boolean {
|
fun isHardwareTorchReallyEnabled(): Boolean {
|
||||||
return camera.cameraInfo.torchState.value == TorchState.ON
|
return camera.cameraInfo.torchState.value == TorchState.ON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import android.os.Build
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
val BIG_PRIMARY_BUTTON_SIZE = 64.dp
|
val BIG_PRIMARY_BUTTON_SIZE = 64.dp
|
||||||
|
val BIG_PRIMARY_BUTTON_MAX_WIDTH = 450.dp
|
||||||
|
|
||||||
val SHEET_BOTTOM_OFFSET = 24.dp
|
val SHEET_BOTTOM_OFFSET = 24.dp
|
||||||
val MAX_AMPLITUDE = 20000
|
val MAX_AMPLITUDE = 20000
|
||||||
|
14
app/src/main/java/app/myzel394/alibi/ui/README.md
Normal file
14
app/src/main/java/app/myzel394/alibi/ui/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# ui
|
||||||
|
|
||||||
|
This folder contains all user interfaces. The folder is structured as follows:
|
||||||
|
|
||||||
|
* `components`: contains all reusable components
|
||||||
|
* `atoms`, `molecules`, `organisms`, `pages`: contains components that are generic and can be
|
||||||
|
reused in different contexts
|
||||||
|
* `<name>Screen/{atoms,molecules,organisms,pages}`: contains components that are specific to a
|
||||||
|
screen
|
||||||
|
* `screens`: contains all screens. Screens are composed of components from the `components` folder
|
||||||
|
* `models`: contains view models used by the screens
|
||||||
|
* `utils`: contains general utility functions
|
||||||
|
|
||||||
|
The root Kotlin files are used for the general setup of the UI.
|
@ -1,6 +1,6 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.atoms
|
package app.myzel394.alibi.ui.components.RecorderScreen.atoms
|
||||||
|
|
||||||
import android.Manifest
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
@ -11,10 +11,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Mic
|
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -25,12 +22,10 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.myzel394.alibi.R
|
|
||||||
import app.myzel394.alibi.ui.utils.PermissionHelper
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@ -41,8 +36,10 @@ fun BigButton(
|
|||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit = {},
|
onLongClick: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
val orientation = LocalConfiguration.current.orientation
|
||||||
|
|
||||||
BoxWithConstraints {
|
BoxWithConstraints {
|
||||||
val isLarge = maxWidth > 500.dp
|
val isLarge = maxWidth > 500.dp && orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -61,11 +61,18 @@ fun RealtimeAudioVisualizer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
val screenWidth = with(LocalDensity.current) { configuration.screenWidthDp.dp.toPx() }
|
// Use greater value of width and height to make sure the amplitudes are shown
|
||||||
|
// when the user rotates the device
|
||||||
|
val availableSpace = with(LocalDensity.current) {
|
||||||
|
Math.max(
|
||||||
|
configuration.screenWidthDp.dp.toPx(),
|
||||||
|
configuration.screenHeightDp.dp.toPx()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(screenWidth) {
|
LaunchedEffect(availableSpace) {
|
||||||
// Add 1 to allow the visualizer to overflow the screen
|
// Add 1 to allow the visualizer to overflow the screen
|
||||||
audioRecorder.setMaxAmplitudesAmount(ceil(screenWidth.toInt() / BOX_DIFF).toInt() + 1)
|
audioRecorder.setMaxAmplitudesAmount(ceil(availableSpace.toInt() / BOX_DIFF).toInt() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas(modifier = modifier) {
|
Canvas(modifier = modifier) {
|
||||||
|
@ -1,45 +1,22 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.InsertDriveFile
|
import androidx.compose.material.icons.automirrored.filled.InsertDriveFile
|
||||||
import androidx.compose.material.icons.filled.Mic
|
import androidx.compose.material.icons.filled.Mic
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
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.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
|
||||||
import androidx.compose.ui.semantics.semantics
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import app.myzel394.alibi.R
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.db.AppSettings
|
import app.myzel394.alibi.db.AppSettings
|
||||||
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.BigButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.BigButton
|
||||||
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
||||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||||
import app.myzel394.alibi.ui.utils.PermissionHelper
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AudioRecordingStart(
|
fun AudioRecordingStart(
|
||||||
@ -62,7 +39,7 @@ fun AudioRecordingStart(
|
|||||||
|
|
||||||
PermissionRequester(
|
PermissionRequester(
|
||||||
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
icon = Icons.Default.InsertDriveFile,
|
icon = Icons.AutoMirrored.Filled.InsertDriveFile,
|
||||||
onPermissionAvailable = {
|
onPermissionAvailable = {
|
||||||
startRecording = true
|
startRecording = true
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -14,6 +17,8 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.DeleteButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.DeleteButton
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.PauseResumeButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.PauseResumeButton
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.SaveButton
|
||||||
@ -23,6 +28,8 @@ import kotlinx.coroutines.delay
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RecordingControl(
|
fun RecordingControl(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
orientation: Int = LocalConfiguration.current.orientation,
|
||||||
initialDelay: Long = 0L,
|
initialDelay: Long = 0L,
|
||||||
isPaused: Boolean,
|
isPaused: Boolean,
|
||||||
recordingTime: Long,
|
recordingTime: Long,
|
||||||
@ -85,8 +92,55 @@ fun RecordingControl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (orientation) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE -> {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.alpha(saveButtonAlpha),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
SaveButton(
|
||||||
|
onSave = onSave,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.alpha(pauseButtonAlpha),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
PauseResumeButton(
|
||||||
|
isPaused = isPaused,
|
||||||
|
onChange = onPauseResume,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.alpha(deleteButtonAlpha),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
DeleteButton(
|
||||||
|
onDelete = onDelete,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -119,4 +173,6 @@ fun RecordingControl(
|
|||||||
SaveButton(onSave = onSave)
|
SaveButton(onSave = onSave)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -40,6 +40,7 @@ fun RecordingStatus(
|
|||||||
progress: Float,
|
progress: Float,
|
||||||
recordingStart: LocalDateTime,
|
recordingStart: LocalDateTime,
|
||||||
maxDuration: Long,
|
maxDuration: Long,
|
||||||
|
progressModifier: Modifier = Modifier.width(300.dp),
|
||||||
) {
|
) {
|
||||||
val animateIn = rememberInitialRecordingAnimation(recordingTime)
|
val animateIn = rememberInitialRecordingAnimation(recordingTime)
|
||||||
|
|
||||||
@ -73,9 +74,8 @@ fun RecordingStatus(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
progress = progress,
|
progress = { progress },
|
||||||
modifier = Modifier
|
modifier = progressModifier,
|
||||||
.width(300.dp)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,50 +2,18 @@ package app.myzel394.alibi.ui.components.RecorderScreen.molecules
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
|
||||||
import androidx.compose.foundation.indication
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.InsertDriveFile
|
||||||
import androidx.compose.material.icons.filled.CameraAlt
|
import androidx.compose.material.icons.filled.CameraAlt
|
||||||
import androidx.compose.material.icons.filled.InsertDriveFile
|
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
|
||||||
import androidx.compose.ui.semantics.semantics
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import app.myzel394.alibi.R
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.db.AppSettings
|
import app.myzel394.alibi.db.AppSettings
|
||||||
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
|
|
||||||
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
|
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.BigButton
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.BigButton
|
||||||
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
||||||
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
||||||
@ -83,7 +51,7 @@ fun VideoRecordingStart(
|
|||||||
|
|
||||||
PermissionRequester(
|
PermissionRequester(
|
||||||
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
icon = Icons.Default.InsertDriveFile,
|
icon = Icons.AutoMirrored.Filled.InsertDriveFile,
|
||||||
onPermissionAvailable = {
|
onPermissionAvailable = {
|
||||||
showSheet = true
|
showSheet = true
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
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.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
@ -16,6 +19,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RealtimeAudioVisualizer
|
import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RealtimeAudioVisualizer
|
||||||
@ -33,6 +37,7 @@ fun AudioRecordingStatus(
|
|||||||
audioRecorder: AudioRecorderModel,
|
audioRecorder: AudioRecorderModel,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val configuration = LocalConfiguration.current.orientation
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
@ -62,6 +67,61 @@ fun AudioRecordingStatus(
|
|||||||
.weight(1f),
|
.weight(1f),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
when (configuration) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE -> {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement
|
||||||
|
.spacedBy(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.weight(3f),
|
||||||
|
) {
|
||||||
|
RecordingStatus(
|
||||||
|
recordingTime = audioRecorder.recordingTime,
|
||||||
|
progress = audioRecorder.progress,
|
||||||
|
recordingStart = audioRecorder.recordingStart,
|
||||||
|
maxDuration = audioRecorder.settings!!.maxDuration,
|
||||||
|
progressModifier = Modifier.fillMaxWidth(.9f),
|
||||||
|
)
|
||||||
|
|
||||||
|
MicrophoneStatus(audioRecorder)
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordingControl(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
isPaused = audioRecorder.isPaused,
|
||||||
|
recordingTime = audioRecorder.recordingTime,
|
||||||
|
onDelete = {
|
||||||
|
scope.launch {
|
||||||
|
runCatching {
|
||||||
|
audioRecorder.stopRecording(context)
|
||||||
|
}
|
||||||
|
runCatching {
|
||||||
|
audioRecorder.destroyService(context)
|
||||||
|
}
|
||||||
|
audioRecorder.batchesFolder!!.deleteRecordings()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onPauseResume = {
|
||||||
|
if (audioRecorder.isPaused) {
|
||||||
|
audioRecorder.resumeRecording()
|
||||||
|
} else {
|
||||||
|
audioRecorder.pauseRecording()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSave = {
|
||||||
|
audioRecorder.onRecordingSave(false)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
RecordingStatus(
|
RecordingStatus(
|
||||||
recordingTime = audioRecorder.recordingTime,
|
recordingTime = audioRecorder.recordingTime,
|
||||||
progress = audioRecorder.progress,
|
progress = audioRecorder.progress,
|
||||||
@ -105,4 +165,6 @@ fun AudioRecordingStatus(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -9,13 +10,13 @@ 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
|
||||||
|
import androidx.compose.foundation.layout.requiredWidthIn
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.text.ClickableText
|
import androidx.compose.foundation.text.ClickableText
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Save
|
import androidx.compose.material.icons.filled.Save
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -29,6 +30,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -40,6 +42,7 @@ import androidx.compose.ui.text.withStyle
|
|||||||
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.db.AppSettings
|
import app.myzel394.alibi.db.AppSettings
|
||||||
|
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_MAX_WIDTH
|
||||||
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
|
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.AudioRecordingStart
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.AudioRecordingStart
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.QuickMaxDurationSelector
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.QuickMaxDurationSelector
|
||||||
@ -64,6 +67,7 @@ fun StartRecording(
|
|||||||
showAudioRecorder: Boolean,
|
showAudioRecorder: Boolean,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val orientation = LocalConfiguration.current.orientation
|
||||||
|
|
||||||
val label = stringResource(
|
val label = stringResource(
|
||||||
R.string.ui_recorder_action_start_description_2,
|
R.string.ui_recorder_action_start_description_2,
|
||||||
@ -98,10 +102,33 @@ fun StartRecording(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(bottom = 32.dp),
|
.padding(bottom = if (orientation == Configuration.ORIENTATION_PORTRAIT) 32.dp else 16.dp),
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
when (orientation) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE -> {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
if (showAudioRecorder)
|
||||||
|
AudioRecordingStart(
|
||||||
|
audioRecorder = audioRecorder,
|
||||||
|
appSettings = appSettings,
|
||||||
|
)
|
||||||
|
VideoRecordingStart(
|
||||||
|
videoRecorder = videoRecorder,
|
||||||
|
appSettings = appSettings,
|
||||||
|
onHideAudioRecording = onHideTopBar,
|
||||||
|
onShowAudioRecording = onShowTopBar,
|
||||||
|
showPreview = !showAudioRecorder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
if (showAudioRecorder)
|
if (showAudioRecorder)
|
||||||
@ -116,6 +143,9 @@ fun StartRecording(
|
|||||||
onShowAudioRecording = onShowTopBar,
|
onShowAudioRecording = onShowTopBar,
|
||||||
showPreview = !showAudioRecorder,
|
showPreview = !showAudioRecorder,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val forceUpdate = rememberForceUpdateOnLifeCycleChange()
|
val forceUpdate = rememberForceUpdateOnLifeCycleChange()
|
||||||
Column(
|
Column(
|
||||||
@ -133,6 +163,7 @@ fun StartRecording(
|
|||||||
TextButton(
|
TextButton(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.requiredWidthIn(max = BIG_PRIMARY_BUTTON_MAX_WIDTH)
|
||||||
.height(BIG_PRIMARY_BUTTON_SIZE)
|
.height(BIG_PRIMARY_BUTTON_SIZE)
|
||||||
.semantics {
|
.semantics {
|
||||||
contentDescription = label
|
contentDescription = label
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
package app.myzel394.alibi.ui.components.RecorderScreen.organisms
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
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.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
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
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
@ -16,9 +19,14 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
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.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -37,28 +45,96 @@ import kotlinx.coroutines.launch
|
|||||||
fun VideoRecordingStatus(
|
fun VideoRecordingStatus(
|
||||||
videoRecorder: VideoRecorderModel,
|
videoRecorder: VideoRecorderModel,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val orientation = LocalConfiguration.current.orientation
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val availableCameras = CameraInfo.queryAvailableCameras(context)
|
|
||||||
|
|
||||||
KeepScreenOn()
|
KeepScreenOn()
|
||||||
|
|
||||||
|
when (orientation) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE -> {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement
|
||||||
|
.spacedBy(32.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxWidth(0.9f)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
|
) {
|
||||||
|
_VideoGeneralInfo(videoRecorder)
|
||||||
|
_VideoRecordingStatus(videoRecorder)
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxWidth(0.9f)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement
|
||||||
|
.spacedBy(32.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
_VideoControls(videoRecorder)
|
||||||
|
HorizontalDivider()
|
||||||
|
_PrimitiveControls(videoRecorder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize(),
|
.fillMaxSize()
|
||||||
|
.padding(bottom = 32.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
Box {}
|
Box {}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement
|
verticalArrangement = Arrangement
|
||||||
.spacedBy(24.dp),
|
.spacedBy(16.dp),
|
||||||
|
) {
|
||||||
|
_VideoGeneralInfo(videoRecorder)
|
||||||
|
_VideoRecordingStatus(videoRecorder)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement
|
||||||
|
.spacedBy(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
_VideoControls(videoRecorder)
|
||||||
|
HorizontalDivider()
|
||||||
|
_PrimitiveControls(videoRecorder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun _VideoGeneralInfo(videoRecorder: VideoRecorderModel) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val availableCameras = CameraInfo.queryAvailableCameras(context)
|
||||||
|
val orientation = LocalConfiguration.current.orientation
|
||||||
|
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement
|
||||||
|
.spacedBy(if (orientation == Configuration.ORIENTATION_LANDSCAPE) 12.dp else 24.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.CameraAlt,
|
Icons.Default.CameraAlt,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(64.dp)
|
modifier = Modifier.size(if (orientation == Configuration.ORIENTATION_LANDSCAPE) 48.dp else 64.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (videoRecorder.isStartingRecording) {
|
if (videoRecorder.isStartingRecording) {
|
||||||
@ -98,49 +174,25 @@ fun VideoRecordingStatus(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (videoRecorder.isStartingRecording) {
|
@Composable
|
||||||
Text(
|
fun _VideoRecordingStatus(videoRecorder: VideoRecorderModel) {
|
||||||
stringResource(R.string.ui_videoRecorder_info_starting),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
RecordingStatus(
|
RecordingStatus(
|
||||||
recordingTime = videoRecorder.recordingTime,
|
recordingTime = videoRecorder.recordingTime,
|
||||||
progress = videoRecorder.progress,
|
progress = videoRecorder.progress,
|
||||||
recordingStart = videoRecorder.recordingStart,
|
recordingStart = videoRecorder.recordingStart,
|
||||||
maxDuration = videoRecorder.settings!!.maxDuration,
|
maxDuration = videoRecorder.settings!!.maxDuration,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
@Composable
|
||||||
verticalArrangement = Arrangement
|
fun _PrimitiveControls(videoRecorder: VideoRecorderModel) {
|
||||||
.spacedBy(32.dp),
|
val context = LocalContext.current
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
val scope = rememberCoroutineScope()
|
||||||
modifier = Modifier.padding(bottom = 32.dp),
|
|
||||||
) {
|
|
||||||
if (!videoRecorder.isStartingRecording) {
|
|
||||||
val cameraControl = videoRecorder.recorderService!!.cameraControl!!
|
|
||||||
if (cameraControl.hasTorchAvailable()) {
|
|
||||||
val isTorchEnabled = cameraControl.isTorchEnabled()
|
|
||||||
|
|
||||||
TorchStatus(
|
|
||||||
enabled = isTorchEnabled,
|
|
||||||
onChange = {
|
|
||||||
if (isTorchEnabled) {
|
|
||||||
cameraControl.disableTorch()
|
|
||||||
} else {
|
|
||||||
cameraControl.enableTorch()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalDivider()
|
|
||||||
|
|
||||||
if (!videoRecorder.isStartingRecording) {
|
|
||||||
RecordingControl(
|
RecordingControl(
|
||||||
|
orientation = Configuration.ORIENTATION_PORTRAIT,
|
||||||
// There may be some edge cases where the app may crash if the
|
// There may be some edge cases where the app may crash if the
|
||||||
// user stops or pauses the recording too soon, so we simply add a
|
// user stops or pauses the recording too soon, so we simply add a
|
||||||
// small delay to prevent that
|
// small delay to prevent that
|
||||||
@ -169,9 +221,27 @@ fun VideoRecordingStatus(
|
|||||||
videoRecorder.onRecordingSave(false)
|
videoRecorder.onRecordingSave(false)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun _VideoControls(videoRecorder: VideoRecorderModel) {
|
||||||
|
if (!videoRecorder.isStartingRecording) {
|
||||||
|
val cameraControl = videoRecorder.recorderService!!.cameraControl!!
|
||||||
|
if (cameraControl.hasTorchAvailable()) {
|
||||||
|
var torchEnabled by rememberSaveable { mutableStateOf(cameraControl.torchEnabled) }
|
||||||
|
|
||||||
|
TorchStatus(
|
||||||
|
enabled = torchEnabled,
|
||||||
|
onChange = {
|
||||||
|
if (torchEnabled) {
|
||||||
|
torchEnabled = false
|
||||||
|
cameraControl.disableTorch()
|
||||||
} else {
|
} else {
|
||||||
Box {}
|
torchEnabled = true
|
||||||
|
cameraControl.enableTorch()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -305,7 +305,9 @@ fun DCIMFolderExplanationDialog(
|
|||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(32.dp),
|
verticalArrangement = Arrangement.spacedBy(32.dp),
|
||||||
) {
|
) {
|
||||||
@ -408,7 +410,9 @@ fun InternalFolderExplanationDialog(
|
|||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(32.dp),
|
verticalArrangement = Arrangement.spacedBy(32.dp),
|
||||||
) {
|
) {
|
||||||
@ -525,7 +529,8 @@ fun SelectionSheet(
|
|||||||
)
|
)
|
||||||
if (!SUPPORTS_SAVING_VIDEOS_IN_CUSTOM_FOLDERS) {
|
if (!SUPPORTS_SAVING_VIDEOS_IN_CUSTOM_FOLDERS) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(horizontal = 32.dp, vertical = 12.dp),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 32.dp, vertical = 12.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package app.myzel394.alibi.ui.components.atoms
|
package app.myzel394.alibi.ui.components.atoms
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -10,9 +9,9 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||||
import androidx.compose.material.icons.filled.Cancel
|
import androidx.compose.material.icons.filled.Cancel
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.OpenInNew
|
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
@ -21,14 +20,14 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
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.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
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 androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
@ -173,7 +172,7 @@ fun PermissionRequester(
|
|||||||
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
|
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.OpenInNew,
|
Icons.AutoMirrored.Filled.OpenInNew,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package app.myzel394.alibi.ui.components.atoms
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Rotate90DegreesCw
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.myzel394.alibi.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RotateDeviceToPortrait(
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.widthIn(max = 300.dp),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Rotate90DegreesCw,
|
||||||
|
contentDescription = stringResource(R.string.ui_rotateDevice_portrait_label),
|
||||||
|
modifier = Modifier.size(48.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.tertiary,
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.ui_rotateDevice_portrait_label))
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package app.myzel394.alibi.ui.screens
|
package app.myzel394.alibi.ui.screens
|
||||||
|
|
||||||
import android.widget.Space
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@ -17,8 +16,8 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.OpenInNew
|
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@ -42,11 +41,10 @@ import androidx.compose.ui.semantics.contentDescription
|
|||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavController
|
|
||||||
import app.myzel394.alibi.R
|
|
||||||
import app.myzel394.alibi.BuildConfig
|
import app.myzel394.alibi.BuildConfig
|
||||||
import app.myzel394.alibi.ui.TRANSLATION_HELP_URL
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.ui.REPO_URL
|
import app.myzel394.alibi.ui.REPO_URL
|
||||||
|
import app.myzel394.alibi.ui.TRANSLATION_HELP_URL
|
||||||
import app.myzel394.alibi.ui.components.AboutScreen.atoms.DonationsTile
|
import app.myzel394.alibi.ui.components.AboutScreen.atoms.DonationsTile
|
||||||
import app.myzel394.alibi.ui.components.AboutScreen.atoms.GPGKeyOverview
|
import app.myzel394.alibi.ui.components.AboutScreen.atoms.GPGKeyOverview
|
||||||
|
|
||||||
@ -68,9 +66,10 @@ fun AboutScreen(
|
|||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackNavigate) {
|
IconButton(onClick = onBackNavigate) {
|
||||||
|
val label = stringResource(R.string.goBack)
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.ArrowBack,
|
Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
contentDescription = "Back"
|
contentDescription = label,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -159,7 +158,7 @@ fun AboutScreen(
|
|||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.OpenInNew,
|
Icons.AutoMirrored.Filled.OpenInNew,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(ButtonDefaults.IconSize)
|
modifier = Modifier.size(ButtonDefaults.IconSize)
|
||||||
)
|
)
|
||||||
@ -196,7 +195,7 @@ fun AboutScreen(
|
|||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.OpenInNew,
|
Icons.AutoMirrored.Filled.OpenInNew,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(ButtonDefaults.IconSize)
|
modifier = Modifier.size(ButtonDefaults.IconSize)
|
||||||
)
|
)
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
package app.myzel394.alibi.ui.screens
|
package app.myzel394.alibi.ui.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.gestures.scrollable
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@ -29,22 +22,20 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
|
||||||
import androidx.compose.ui.semantics.semantics
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavController
|
|
||||||
import app.myzel394.alibi.R
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.dataStore
|
import app.myzel394.alibi.dataStore
|
||||||
import app.myzel394.alibi.db.AppSettings
|
import app.myzel394.alibi.db.AppSettings
|
||||||
import app.myzel394.alibi.db.NotificationSettings
|
import app.myzel394.alibi.db.NotificationSettings
|
||||||
import app.myzel394.alibi.ui.components.CustomRecordingNotificationsScreen.atoms.LandingElement
|
import app.myzel394.alibi.ui.components.CustomRecordingNotificationsScreen.atoms.LandingElement
|
||||||
import app.myzel394.alibi.ui.components.CustomRecordingNotificationsScreen.atoms.NotificationPresetSelect
|
|
||||||
import app.myzel394.alibi.ui.components.CustomRecordingNotificationsScreen.molecules.EditNotificationInput
|
|
||||||
import app.myzel394.alibi.ui.components.CustomRecordingNotificationsScreen.organisms.NotificationEditor
|
import app.myzel394.alibi.ui.components.CustomRecordingNotificationsScreen.organisms.NotificationEditor
|
||||||
|
import app.myzel394.alibi.ui.components.atoms.RotateDeviceToPortrait
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@ -80,9 +71,10 @@ fun CustomRecordingNotificationsScreen(
|
|||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackNavigate) {
|
IconButton(onClick = onBackNavigate) {
|
||||||
|
val label = stringResource(R.string.goBack)
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.ArrowBack,
|
Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
contentDescription = "Back"
|
contentDescription = label,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -92,6 +84,10 @@ fun CustomRecordingNotificationsScreen(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
) { padding ->
|
) { padding ->
|
||||||
|
val orientation = LocalConfiguration.current.orientation
|
||||||
|
|
||||||
|
when (orientation) {
|
||||||
|
Configuration.ORIENTATION_PORTRAIT -> {
|
||||||
if (showEditor) {
|
if (showEditor) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
@ -121,4 +117,17 @@ fun CustomRecordingNotificationsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
RotateDeviceToPortrait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@ -38,21 +38,21 @@ import app.myzel394.alibi.dataStore
|
|||||||
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
|
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AboutTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AboutTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderEncoderTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderEncoderTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderFrameRateTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderOutputFormatTile
|
||||||
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderSamplingRateTile
|
||||||
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderShowAllMicrophonesTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.CustomNotificationTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.CustomNotificationTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DeleteRecordingsImmediatelyTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DeleteRecordingsImmediatelyTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DividerTitle
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DividerTitle
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderQualityTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.EnableAppLockTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.ImportExport
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.ImportExport
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.InAppLanguagePicker
|
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.IntervalDurationTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.IntervalDurationTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.MaxDurationTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.MaxDurationTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderOutputFormatTile
|
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderSamplingRateTile
|
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.SaveFolderTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.SaveFolderTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderShowAllMicrophonesTile
|
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.EnableAppLockTile
|
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderBitrateTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderBitrateTile
|
||||||
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderFrameRateTile
|
||||||
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderQualityTile
|
||||||
|
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.InAppLanguagePicker
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ThemeSelector
|
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ThemeSelector
|
||||||
import app.myzel394.alibi.ui.components.atoms.GlobalSwitch
|
import app.myzel394.alibi.ui.components.atoms.GlobalSwitch
|
||||||
import app.myzel394.alibi.ui.components.atoms.MessageBox
|
import app.myzel394.alibi.ui.components.atoms.MessageBox
|
||||||
@ -99,9 +99,10 @@ fun SettingsScreen(
|
|||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackNavigate) {
|
IconButton(onClick = onBackNavigate) {
|
||||||
|
val label = stringResource(R.string.goBack)
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.ArrowBack,
|
Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
contentDescription = "Back"
|
contentDescription = label,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="app_name">Alibi</string>
|
<string name="app_name">Alibi</string>
|
||||||
|
|
||||||
<string name="dialog_close_cancel_label">Cancel</string>
|
<string name="dialog_close_cancel_label">Cancel</string>
|
||||||
@ -189,4 +189,6 @@
|
|||||||
<string name="ui_settings_option_saveFolder_explainMediaFolder_openFolderExplanation">Tap on a folder to open it in the Files app</string>
|
<string name="ui_settings_option_saveFolder_explainMediaFolder_openFolderExplanation">Tap on a folder to open it in the Files app</string>
|
||||||
<string name="ui_videoRecorder_action_start_settings_cameraLens_unknown_label">Unknown</string>
|
<string name="ui_videoRecorder_action_start_settings_cameraLens_unknown_label">Unknown</string>
|
||||||
<string name="ui_settings_option_saveFolder_explainInternalFolder_explanation">To protect your privacy, Alibi stores its batches into its own private, encrypted storage. This storage is only accessible by Alibi and can\'t be accessed by other apps or by a possible intruder. Once you save the recording, you will be asked where you want to save the recording to.</string>
|
<string name="ui_settings_option_saveFolder_explainInternalFolder_explanation">To protect your privacy, Alibi stores its batches into its own private, encrypted storage. This storage is only accessible by Alibi and can\'t be accessed by other apps or by a possible intruder. Once you save the recording, you will be asked where you want to save the recording to.</string>
|
||||||
|
<string name="ui_rotateDevice_portrait_label">Please rotate your device to portait mode</string>
|
||||||
|
<string name="goBack">Back</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user