mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
feat: Add AudioRecordingStart and VideoRecordingStart
This commit is contained in:
parent
e7989e2eba
commit
261753ad75
@ -23,9 +23,8 @@ import app.myzel394.alibi.ui.enums.Screen
|
||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
||||
import app.myzel394.alibi.ui.screens.AboutScreen
|
||||
import app.myzel394.alibi.ui.screens.AudioRecorderScreen
|
||||
import app.myzel394.alibi.ui.screens.RecorderScreen
|
||||
import app.myzel394.alibi.ui.screens.CustomRecordingNotificationsScreen
|
||||
import app.myzel394.alibi.ui.screens.POCVideo
|
||||
import app.myzel394.alibi.ui.screens.SettingsScreen
|
||||
import app.myzel394.alibi.ui.screens.WelcomeScreen
|
||||
|
||||
@ -73,9 +72,10 @@ fun Navigation(
|
||||
scaleOut(targetScale = SCALE_IN) + fadeOut(tween(durationMillis = 150))
|
||||
}
|
||||
) {
|
||||
AudioRecorderScreen(
|
||||
RecorderScreen(
|
||||
navController = navController,
|
||||
audioRecorder = audioRecorder,
|
||||
videoRecorder = videoRecorder,
|
||||
)
|
||||
}
|
||||
composable(
|
||||
|
@ -0,0 +1,90 @@
|
||||
package app.myzel394.alibi.ui.components.AudioRecorder.atoms
|
||||
|
||||
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.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.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.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.db.AppSettings
|
||||
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||
|
||||
@Composable
|
||||
fun AudioRecordingStart(
|
||||
audioRecorder: AudioRecorderModel,
|
||||
appSettings: AppSettings,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
// We can't get the current `notificationDetails` inside the
|
||||
// `onPermissionAvailable` function. We'll instead use this hack
|
||||
// with `LaunchedEffect` to get the current value.
|
||||
var startRecording by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(startRecording) {
|
||||
if (startRecording) {
|
||||
startRecording = false
|
||||
|
||||
audioRecorder.startRecording(context, appSettings)
|
||||
}
|
||||
}
|
||||
|
||||
PermissionRequester(
|
||||
permission = Manifest.permission.RECORD_AUDIO,
|
||||
icon = Icons.Default.Mic,
|
||||
onPermissionAvailable = {
|
||||
startRecording = true
|
||||
}
|
||||
) { trigger ->
|
||||
val label = stringResource(R.string.ui_audioRecorder_action_start_label)
|
||||
|
||||
Button(
|
||||
onClick = trigger,
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
contentDescription = label
|
||||
}
|
||||
.size(200.dp)
|
||||
.clip(shape = CircleShape),
|
||||
colors = ButtonDefaults.outlinedButtonColors(),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Mic,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(80.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
|
||||
Text(
|
||||
label,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package app.myzel394.alibi.ui.components.AudioRecorder.atoms
|
||||
|
||||
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.filled.CameraAlt
|
||||
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.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.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.db.AppSettings
|
||||
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
||||
|
||||
@Composable
|
||||
fun VideoRecordingStart(
|
||||
videoRecorder: VideoRecorderModel,
|
||||
appSettings: AppSettings,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
// We can't get the current `notificationDetails` inside the
|
||||
// `onPermissionAvailable` function. We'll instead use this hack
|
||||
// with `LaunchedEffect` to get the current value.
|
||||
var startRecording by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(startRecording) {
|
||||
if (startRecording) {
|
||||
startRecording = false
|
||||
|
||||
videoRecorder.startRecording(context, appSettings)
|
||||
}
|
||||
}
|
||||
|
||||
PermissionRequester(
|
||||
permission = Manifest.permission.RECORD_AUDIO,
|
||||
icon = Icons.Default.Mic,
|
||||
onPermissionAvailable = {
|
||||
startRecording = true
|
||||
}
|
||||
) { trigger ->
|
||||
val label = stringResource(R.string.ui_videoRecorder_action_start_label)
|
||||
|
||||
Button(
|
||||
onClick = trigger,
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
contentDescription = label
|
||||
}
|
||||
.size(200.dp)
|
||||
.clip(shape = CircleShape),
|
||||
colors = ButtonDefaults.outlinedButtonColors(),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.CameraAlt,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(80.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
|
||||
Text(
|
||||
label,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package app.myzel394.alibi.ui.components.AudioRecorder.molecules
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@ -11,9 +10,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Mic
|
||||
import androidx.compose.material.icons.filled.Save
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
@ -21,15 +18,8 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
@ -37,18 +27,20 @@ import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.myzel394.alibi.R
|
||||
import app.myzel394.alibi.dataStore
|
||||
import app.myzel394.alibi.db.AppSettings
|
||||
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
|
||||
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
|
||||
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.AudioRecordingStart
|
||||
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.VideoRecordingStart
|
||||
import app.myzel394.alibi.ui.effects.rememberForceUpdateOnLifeCycleChange
|
||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
@Composable
|
||||
fun StartRecording(
|
||||
audioRecorder: AudioRecorderModel,
|
||||
videoRecorder: VideoRecorderModel,
|
||||
// Loading this from parent, because if we load it ourselves
|
||||
// and permissions have already been granted, initial
|
||||
// settings will be used, instead of the actual settings.
|
||||
@ -57,70 +49,26 @@ fun StartRecording(
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
// We can't get the current `notificationDetails` inside the
|
||||
// `onPermissionAvailable` function. We'll instead use this hack
|
||||
// with `LaunchedEffect` to get the current value.
|
||||
var startRecording by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(startRecording) {
|
||||
if (startRecording) {
|
||||
startRecording = false
|
||||
|
||||
audioRecorder.startRecording(context, appSettings)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
PermissionRequester(
|
||||
permission = Manifest.permission.RECORD_AUDIO,
|
||||
icon = Icons.Default.Mic,
|
||||
onPermissionAvailable = {
|
||||
startRecording = true
|
||||
},
|
||||
) { trigger ->
|
||||
val label = stringResource(R.string.ui_audioRecorder_action_start_label)
|
||||
Button(
|
||||
onClick = trigger,
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
contentDescription = label
|
||||
}
|
||||
.size(200.dp)
|
||||
.clip(shape = CircleShape),
|
||||
colors = ButtonDefaults.outlinedButtonColors(),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Mic,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(80.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
|
||||
Text(
|
||||
label,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
val settings = LocalContext
|
||||
.current
|
||||
.dataStore
|
||||
.data
|
||||
.collectAsState(initial = AppSettings.getDefaultInstance())
|
||||
.value
|
||||
|
||||
AudioRecordingStart(
|
||||
audioRecorder = audioRecorder,
|
||||
appSettings = appSettings,
|
||||
)
|
||||
VideoRecordingStart(
|
||||
videoRecorder = videoRecorder,
|
||||
appSettings = appSettings,
|
||||
)
|
||||
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.ui_audioRecorder_action_start_description,
|
||||
settings.maxDuration / 1000 / 60
|
||||
appSettings.maxDuration / 1000 / 60
|
||||
),
|
||||
style = MaterialTheme.typography.bodySmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
|
@ -48,14 +48,16 @@ import app.myzel394.alibi.helpers.AudioBatchesFolder
|
||||
import app.myzel394.alibi.helpers.BatchesFolder
|
||||
import app.myzel394.alibi.ui.effects.rememberSettings
|
||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AudioRecorderScreen(
|
||||
fun RecorderScreen(
|
||||
navController: NavController,
|
||||
audioRecorder: AudioRecorderModel,
|
||||
videoRecorder: VideoRecorderModel,
|
||||
) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val context = LocalContext.current
|
||||
@ -299,7 +301,9 @@ fun AudioRecorderScreen(
|
||||
RecordingStatus(audioRecorder = audioRecorder)
|
||||
else
|
||||
StartRecording(
|
||||
audioRecorder = audioRecorder, appSettings = appSettings,
|
||||
audioRecorder = audioRecorder,
|
||||
videoRecorder = videoRecorder,
|
||||
appSettings = appSettings,
|
||||
onSaveLastRecording = ::saveRecording,
|
||||
)
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
<string name="ui_permissions_request">Please grant the permission to continue</string>
|
||||
<string name="ui_permissions_permanentlyDenied_message">You will be redirected to the app settings to grant the permission there.</string>
|
||||
|
||||
<string name="ui_audioRecorder_action_start_label">Start Recording</string>
|
||||
<string name="ui_audioRecorder_action_start_label">Start Audio Recording</string>
|
||||
<string name="ui_audioRecorder_action_saveOldRecording_label">Save Recording from <xliff:g name="date">%s</xliff:g></string>
|
||||
<string name="ui_audioRecorder_action_delete_label">Delete</string>
|
||||
<string name="ui_audioRecorder_action_delete_confirm_title">Delete Recording?</string>
|
||||
@ -138,4 +138,5 @@
|
||||
<string name="ui_settings_value_videoQuality_values_hd">HD</string>
|
||||
<string name="ui_settings_value_videoQuality_values_sd">Standard</string>
|
||||
<string name="ui_settings_value_videoQuality_values_lowest">Lowest</string>
|
||||
<string name="ui_videoRecorder_action_start_label">Start Video Recording</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user