diff --git a/demos/effect/build.gradle b/demos/effect/build.gradle index beca6c5686..aef25c1342 100644 --- a/demos/effect/build.gradle +++ b/demos/effect/build.gradle @@ -74,6 +74,7 @@ dependencies { implementation 'androidx.compose.material3:material3' implementation 'com.google.android.material:material:' + androidxMaterialVersion + implementation project(modulePrefix + 'lib-exoplayer') implementation project(modulePrefix + 'lib-ui') // For detecting and debugging leaks only. LeakCanary is not needed for demo app to work. diff --git a/demos/effect/src/main/AndroidManifest.xml b/demos/effect/src/main/AndroidManifest.xml index f85a8a2ec7..5d8f7a560a 100644 --- a/demos/effect/src/main/AndroidManifest.xml +++ b/demos/effect/src/main/AndroidManifest.xml @@ -19,6 +19,8 @@ + + + exoPlayer.apply { + setMediaItem(MediaItem.fromUri(uri)) + prepare() } - ) - PlayerScreen() + } + PlayerScreen(exoPlayer) Effects( - onButtonClick = { - coroutineScope.launch { - snackbarHostState.showSnackbar(message = "Button is not yet implemented.") - } + onException = { message -> + coroutineScope.launch { snackbarHostState.showSnackbar(message) } } ) } @@ -83,25 +100,76 @@ class EffectActivity : ComponentActivity() { } @Composable - fun InputChooser(onButtonClick: () -> Unit) { + fun InputChooser(onException: (String) -> Unit, onNewUri: (Uri) -> Unit) { + var showLocalFilePicker by remember { mutableStateOf(false) } Row( modifier = Modifier.padding(vertical = dimensionResource(id = R.dimen.small_padding)), horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.small_padding)), ) { - Button(onClick = onButtonClick) { + Button(onClick = { onException("Button is not yet implemented.") }) { Text(text = stringResource(id = R.string.choose_preset_input)) } - Button(onClick = onButtonClick) { + Button(onClick = { showLocalFilePicker = true }) { Text(text = stringResource(id = R.string.choose_local_file)) } } + if (showLocalFilePicker) { + LocalFilePicker( + onException = { + onException(it) + showLocalFilePicker = false + } + ) { uri -> + onNewUri(uri) + showLocalFilePicker = false + } + } + } + + @OptIn(UnstableApi::class) + @Composable + fun LocalFilePicker(onException: (String) -> Unit, onFileSelected: (Uri) -> Unit) { + val context = LocalContext.current + val localFilePickerLauncher = + rememberLauncherForActivityResult( + contract = ActivityResultContracts.OpenDocument(), + onResult = { uri: Uri? -> + if (uri != null) { + onFileSelected(uri) + } else { + onException("File couldn't be opened. Please try again.") + } + }, + ) + val permissionLauncher = + rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission(), + onResult = { isGranted: Boolean -> + if (isGranted) { + localFilePickerLauncher.launch(arrayOf("video/*")) + } else { + onException("Permission was not granted.") + } + }, + ) + LaunchedEffect(Unit) { + val permission = + if (SDK_INT >= 33) Manifest.permission.READ_MEDIA_VIDEO + else Manifest.permission.READ_EXTERNAL_STORAGE + val permissionCheck = ContextCompat.checkSelfPermission(context, permission) + if (permissionCheck == android.content.pm.PackageManager.PERMISSION_GRANTED) { + localFilePickerLauncher.launch(arrayOf("video/*")) + } else { + permissionLauncher.launch(permission) + } + } } @Composable - fun PlayerScreen() { + fun PlayerScreen(exoPlayer: ExoPlayer) { val context = LocalContext.current AndroidView( - factory = { PlayerView(context).apply {} }, + factory = { PlayerView(context).apply { player = exoPlayer } }, modifier = Modifier.height(dimensionResource(id = R.dimen.android_view_height)) .padding(all = dimensionResource(id = R.dimen.small_padding)), @@ -109,7 +177,9 @@ class EffectActivity : ComponentActivity() { } @Composable - fun Effects(onButtonClick: () -> Unit) { - Button(onClick = onButtonClick) { Text(text = stringResource(id = R.string.apply_effects)) } + fun Effects(onException: (String) -> Unit) { + Button(onClick = { onException("Button is not yet implemented.") }) { + Text(text = stringResource(id = R.string.apply_effects)) + } } }