mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add preset input picker functionality
Added functionality to `Choose preset input` button. The picker allows the user to select a preset input from a list of loaded preset playlists. The selected preset input is then used to populate the ExoPlayer with the corresponding media items. PiperOrigin-RevId: 704626144
This commit is contained in:
parent
6689fee2b2
commit
dc21f3add2
@ -30,7 +30,10 @@ 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.selection.selectable
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.RadioButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
@ -88,10 +91,13 @@ class EffectActivity : ComponentActivity() {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
InputChooser(
|
InputChooser(
|
||||||
onException = { coroutineScope.launch { snackbarHostState.showSnackbar(it) } }
|
playlistHolderList,
|
||||||
) { uri ->
|
onException = { message ->
|
||||||
|
coroutineScope.launch { snackbarHostState.showSnackbar(message) }
|
||||||
|
},
|
||||||
|
) { mediaItems ->
|
||||||
exoPlayer.apply {
|
exoPlayer.apply {
|
||||||
setMediaItem(MediaItem.fromUri(uri))
|
setMediaItems(mediaItems)
|
||||||
prepare()
|
prepare()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,44 +112,105 @@ class EffectActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InputChooser(onException: (String) -> Unit, onNewUri: (Uri) -> Unit) {
|
private fun InputChooser(
|
||||||
var showLocalFilePicker by remember { mutableStateOf(false) }
|
playlistHolderList: List<PlaylistHolder>,
|
||||||
|
onException: (String) -> Unit,
|
||||||
|
onNewMediaItems: (List<MediaItem>) -> Unit,
|
||||||
|
) {
|
||||||
|
var showPresetInputChooser by remember { mutableStateOf(false) }
|
||||||
|
var showLocalFileChooser by remember { mutableStateOf(false) }
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(vertical = dimensionResource(id = R.dimen.small_padding)),
|
modifier = Modifier.padding(vertical = dimensionResource(id = R.dimen.small_padding)),
|
||||||
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.small_padding)),
|
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.small_padding)),
|
||||||
) {
|
) {
|
||||||
Button(onClick = { onException("Button is not yet implemented.") }) {
|
Button(onClick = { showPresetInputChooser = true }) {
|
||||||
Text(text = stringResource(id = R.string.choose_preset_input))
|
Text(text = stringResource(id = R.string.choose_preset_input))
|
||||||
}
|
}
|
||||||
Button(onClick = { showLocalFilePicker = true }) {
|
Button(onClick = { showLocalFileChooser = true }) {
|
||||||
Text(text = stringResource(id = R.string.choose_local_file))
|
Text(text = stringResource(id = R.string.choose_local_file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (showLocalFilePicker) {
|
if (showPresetInputChooser) {
|
||||||
LocalFilePicker(
|
if (playlistHolderList.isNotEmpty()) {
|
||||||
onException = {
|
PresetInputChooser(
|
||||||
onException(it)
|
playlistHolderList,
|
||||||
showLocalFilePicker = false
|
onDismissRequest = { showPresetInputChooser = false },
|
||||||
|
) { mediaItems ->
|
||||||
|
onNewMediaItems(mediaItems)
|
||||||
|
showPresetInputChooser = false
|
||||||
}
|
}
|
||||||
) { uri ->
|
} else {
|
||||||
onNewUri(uri)
|
onException(stringResource(id = R.string.no_loaded_playlists_error))
|
||||||
showLocalFilePicker = false
|
showPresetInputChooser = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (showLocalFileChooser) {
|
||||||
|
LocalFileChooser(
|
||||||
|
onException = { message ->
|
||||||
|
onException(message)
|
||||||
|
showLocalFileChooser = false
|
||||||
|
}
|
||||||
|
) { mediaItems ->
|
||||||
|
onNewMediaItems(mediaItems)
|
||||||
|
showLocalFileChooser = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PresetInputChooser(
|
||||||
|
playlistHolderList: List<PlaylistHolder>,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
onInputSelected: (List<MediaItem>) -> Unit,
|
||||||
|
) {
|
||||||
|
var selectedOption by remember { mutableStateOf(playlistHolderList.first()) }
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
title = { Text(stringResource(id = R.string.choose_preset_input)) },
|
||||||
|
confirmButton = {
|
||||||
|
Button(onClick = { onInputSelected(selectedOption.mediaItems) }) {
|
||||||
|
Text(text = stringResource(id = R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Column {
|
||||||
|
playlistHolderList.forEach { playlistHolder ->
|
||||||
|
Row(
|
||||||
|
Modifier.fillMaxWidth()
|
||||||
|
.selectable(
|
||||||
|
(playlistHolder == selectedOption),
|
||||||
|
onClick = { selectedOption = playlistHolder },
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
RadioButton(
|
||||||
|
selected = (playlistHolder == selectedOption),
|
||||||
|
onClick = { selectedOption = playlistHolder },
|
||||||
|
)
|
||||||
|
Text(playlistHolder.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun LocalFilePicker(onException: (String) -> Unit, onFileSelected: (Uri) -> Unit) {
|
private fun LocalFileChooser(
|
||||||
|
onException: (String) -> Unit,
|
||||||
|
onFileSelected: (List<MediaItem>) -> Unit,
|
||||||
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val localFilePickerLauncher =
|
val localFileChooserLauncher =
|
||||||
rememberLauncherForActivityResult(
|
rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.OpenDocument(),
|
contract = ActivityResultContracts.OpenDocument(),
|
||||||
onResult = { uri: Uri? ->
|
onResult = { uri: Uri? ->
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
onFileSelected(uri)
|
onFileSelected(listOf(MediaItem.fromUri(uri)))
|
||||||
} else {
|
} else {
|
||||||
onException("File couldn't be opened. Please try again.")
|
onException(getString(R.string.can_not_open_file_error))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -152,9 +219,9 @@ class EffectActivity : ComponentActivity() {
|
|||||||
contract = ActivityResultContracts.RequestPermission(),
|
contract = ActivityResultContracts.RequestPermission(),
|
||||||
onResult = { isGranted: Boolean ->
|
onResult = { isGranted: Boolean ->
|
||||||
if (isGranted) {
|
if (isGranted) {
|
||||||
localFilePickerLauncher.launch(arrayOf("video/*"))
|
localFileChooserLauncher.launch(arrayOf("video/*"))
|
||||||
} else {
|
} else {
|
||||||
onException("Permission was not granted.")
|
onException(getString(R.string.permission_not_granted_error))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -164,7 +231,7 @@ class EffectActivity : ComponentActivity() {
|
|||||||
else Manifest.permission.READ_EXTERNAL_STORAGE
|
else Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
val permissionCheck = ContextCompat.checkSelfPermission(context, permission)
|
val permissionCheck = ContextCompat.checkSelfPermission(context, permission)
|
||||||
if (permissionCheck == android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
if (permissionCheck == android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||||
localFilePickerLauncher.launch(arrayOf("video/*"))
|
localFileChooserLauncher.launch(arrayOf("video/*"))
|
||||||
} else {
|
} else {
|
||||||
permissionLauncher.launch(permission)
|
permissionLauncher.launch(permission)
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,7 @@
|
|||||||
<string name="apply_effects">Apply effects</string>
|
<string name="apply_effects">Apply effects</string>
|
||||||
<string name="ok">OK</string>
|
<string name="ok">OK</string>
|
||||||
<string name="playlist_loading_error">Error loading playlist from %1$s: %2$s</string>
|
<string name="playlist_loading_error">Error loading playlist from %1$s: %2$s</string>
|
||||||
|
<string name="no_loaded_playlists_error">There are no loaded preset inputs.</string>
|
||||||
|
<string name="can_not_open_file_error">"File couldn't be opened. Please try again."</string>
|
||||||
|
<string name="permission_not_granted_error">"Permission was not granted."</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user