diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 845d084..374876d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -62,6 +62,7 @@ android:hardwareAccelerated="true" android:supportsPictureInPicture="true" android:windowSoftInputMode="adjustResize" + android:launchMode="singleTop" android:exported="true" /> ) -> Unit) { try { videoPlayerCallback = callback - val intent = Intent(this, VideoPlayerActivity::class.java) + + val intent = Intent(this, VideoPlayerActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) + } + videoPlayerLauncher.launch(intent) } catch (e: Exception) { e.printStackTrace() diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/VideoPlayerActivity.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/VideoPlayerActivity.kt index 08e20a1..9c426a2 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/VideoPlayerActivity.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/VideoPlayerActivity.kt @@ -38,6 +38,11 @@ class VideoPlayerActivity : ComponentActivity() { } } } + + override fun onPause() { + super.onPause() + VideoPlayerObject.implementation.pause() + } } @RequiresApi(Build.VERSION_CODES.O) diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/controls/VideoPlayerControls.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/controls/VideoPlayerControls.kt index 23204cc..8342a0a 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/controls/VideoPlayerControls.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/controls/VideoPlayerControls.kt @@ -79,7 +79,6 @@ import nl.jknaapen.fladder.utility.ImmersiveSystemBars import nl.jknaapen.fladder.utility.defaultSelected import nl.jknaapen.fladder.utility.leanBackEnabled import nl.jknaapen.fladder.utility.visible -import kotlin.math.absoluteValue import kotlin.time.Duration.Companion.seconds @@ -143,7 +142,8 @@ fun CustomVideoControls( // Restart the multiplier LaunchedEffect(lastSeekInteraction.longValue) { - delay(2.seconds) + delay(1.seconds) + if (currentSkipTime == 0L) return@LaunchedEffect player?.seekTo(position + currentSkipTime) currentSkipTime = 0L } @@ -167,18 +167,12 @@ fun CustomVideoControls( if (!showControls) { when (keyEvent.key) { DirectionLeft -> { - if (currentSkipTime == 0L) { - player?.seekTo(position - backwardSpeed.inWholeMilliseconds) - } currentSkipTime -= backwardSpeed.inWholeMilliseconds updateSeekInteraction() return@onKeyEvent true } DirectionRight -> { - if (currentSkipTime.absoluteValue == 0L) { - player?.seekTo(position + forwardSpeed.inWholeMilliseconds) - } currentSkipTime += forwardSpeed.inWholeMilliseconds updateSeekInteraction() return@onKeyEvent true diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/AudioSelection.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/AudioSelection.kt index 8b7403a..8ba6573 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/AudioSelection.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/AudioSelection.kt @@ -19,7 +19,6 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import nl.jknaapen.fladder.objects.VideoPlayerObject import nl.jknaapen.fladder.utility.clearAudioTrack -import nl.jknaapen.fladder.utility.conditional import nl.jknaapen.fladder.utility.setInternalAudioTrack @OptIn(UnstableApi::class) @@ -32,15 +31,31 @@ fun AudioPicker( val audioTracks by VideoPlayerObject.audioTracks.collectAsState(listOf()) val internalAudioTracks by VideoPlayerObject.exoAudioTracks - val focusRequester = remember { FocusRequester() } + val focusOffTrack = remember { FocusRequester() } + val focusRequesters = remember(internalAudioTracks) { + internalAudioTracks.associateWith { FocusRequester() } + } val listState = rememberLazyListState() - LaunchedEffect(selectedIndex) { - if (selectedIndex == -1) return@LaunchedEffect - listState.scrollToItem( - audioTracks.indexOfFirst { it.index == selectedIndex.toLong() } - ) + LaunchedEffect(selectedIndex, audioTracks, internalAudioTracks) { + if (selectedIndex == -1) { + focusOffTrack.requestFocus() + return@LaunchedEffect + } + + val serverTrackIndex = audioTracks.indexOfFirst { it.index == selectedIndex.toLong() } + + if (serverTrackIndex <= 0) { + focusOffTrack.requestFocus() + return@LaunchedEffect + } + + val internalIndex = serverTrackIndex - 1 + val lazyColumnIndex = internalIndex + 1 + + listState.scrollToItem(lazyColumnIndex) + focusRequesters[internalAudioTracks[internalIndex]]?.requestFocus() } CustomModalBottomSheet( @@ -54,48 +69,40 @@ fun AudioPicker( .padding(horizontal = 8.dp, vertical = 16.dp), ) { item { - val selectedOff = -1 == selectedIndex + val selectedOff = selectedIndex == -1 TrackButton( modifier = Modifier .fillMaxWidth() - .conditional(selectedOff) { - focusRequester(focusRequester) - }, + .focusRequester(focusOffTrack), onClick = { VideoPlayerObject.setAudioTrackIndex(-1) player.clearAudioTrack() }, selected = selectedOff ) { - Text( - text = "Off", - ) + Text("Off") } } + internalAudioTracks.forEachIndexed { index, track -> val serverTrack = audioTracks.elementAtOrNull(index + 1) - val selected = serverTrack?.index == selectedIndex.toLong() + val selected = serverTrack?.index?.toInt() == selectedIndex + item { TrackButton( modifier = Modifier .fillMaxWidth() - .conditional(selected) { - focusRequester(focusRequester) - }, + .focusRequester(focusRequesters[track]!!), onClick = { - serverTrack?.index?.let { - VideoPlayerObject.setAudioTrackIndex(it.toInt()) - } + serverTrack?.index?.let { VideoPlayerObject.setAudioTrackIndex(it.toInt()) } player.setInternalAudioTrack(track) }, selected = selected ) { - Text( - text = serverTrack?.name ?: "", - ) + Text(serverTrack?.name ?: "") } } } } } -} \ No newline at end of file +} diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/ChapterSelectionSheet.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/ChapterSelectionSheet.kt index a36c971..c0c4078 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/ChapterSelectionSheet.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/ChapterSelectionSheet.kt @@ -2,18 +2,20 @@ package nl.jknaapen.fladder.composables.dialogs import Chapter import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme @@ -22,20 +24,18 @@ 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.remember -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.focus.FocusRequester import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import nl.jknaapen.fladder.objects.VideoPlayerObject -import nl.jknaapen.fladder.utility.conditional +import nl.jknaapen.fladder.utility.highlightOnFocus @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -47,27 +47,23 @@ internal fun ChapterSelectionSheet( val chapters = playbackData?.chapters ?: listOf() val currentPosition by VideoPlayerObject.position.collectAsState(0L) - val focusRequester = remember { FocusRequester() } + val focusRequesters = remember(chapters) { + chapters.associateWith { FocusRequester() } + } if (chapters.isEmpty()) return - var currentChapter: Chapter? by remember { - mutableStateOf( - chapters[chapters.indexOfCurrent( - currentPosition - )] - ) - } - val lazyListState = rememberLazyListState() - LaunchedEffect(chapters, currentPosition) { - val chapter = chapters.indexOfCurrent(currentPosition) - lazyListState.animateScrollToItem( - chapter - ) - currentChapter = chapters[chapter] - focusRequester.requestFocus() + val currentChapterIndex = remember(currentPosition) { + chapters.indexOfCurrent(currentPosition) + } + + val currentChapter = chapters.getOrNull(currentChapterIndex) + + LaunchedEffect(currentChapter) { + lazyListState.animateScrollToItem(chapters.indexOf(currentChapter)) + focusRequesters[currentChapter]?.requestFocus() } CustomModalBottomSheet( @@ -76,6 +72,8 @@ internal fun ChapterSelectionSheet( Column( modifier = Modifier .fillMaxWidth() + .fillMaxHeight(0.55f) + .wrapContentHeight() .padding(horizontal = 16.dp, vertical = 16.dp) .wrapContentHeight(), verticalArrangement = Arrangement.spacedBy(8.dp) @@ -90,36 +88,11 @@ internal fun ChapterSelectionSheet( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { chapters.forEachIndexed { index, chapter -> - val selectedChapter = currentChapter == chapter val isCurrentChapter = chapters.indexOfCurrent(currentPosition) == index item { Column( modifier = Modifier - .background( - color = if (selectedChapter) Color.White.copy(alpha = 0.25f) else Color.Black.copy( - alpha = 0.75f - ), - shape = RoundedCornerShape(8.dp) - ) - .aspectRatio(1.67f) - .border( - width = 2.dp, - color = Color.White.copy(alpha = if (selectedChapter) 0.45f else 0f), - shape = RoundedCornerShape(8.dp) - ) - .conditional(selectedChapter) { - focusRequester(focusRequester) - } - .onFocusChanged { - if (it.isFocused) { - currentChapter = chapter - } - } - .clickable( - onClick = { - onSelected(chapter) - } - ) + .padding(horizontal = 8.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy( @@ -127,33 +100,48 @@ internal fun ChapterSelectionSheet( alignment = Alignment.CenterVertically ), ) { + AsyncImage( + model = chapter.url, + modifier = Modifier + .focusRequester(focusRequesters[chapter]!!) + .highlightOnFocus( + color = MaterialTheme.colorScheme.primary, + width = 3.dp, + shape = RoundedCornerShape(24.dp) + ) + .clickable( + onClick = { + onSelected(chapter) + } + ) + .aspectRatio(1.67f) + .clip(shape = RoundedCornerShape(24.dp)) + .weight(1f), + contentDescription = "", + contentScale = ContentScale.FillBounds + ) Row( horizontalArrangement = Arrangement.spacedBy( 8.dp, - alignment = Alignment.CenterHorizontally + alignment = Alignment.Start ), verticalAlignment = Alignment.CenterVertically, ) { + if (isCurrentChapter) + Box( + modifier = Modifier + .size(16.dp) + .background( + color = MaterialTheme.colorScheme.primary, + shape = CircleShape + ) + ) Text( chapter.name, style = MaterialTheme.typography.bodyLarge, color = Color.White ) } - AsyncImage( - model = chapter.url, - modifier = Modifier - .clip( - shape = RoundedCornerShape(24.dp) - ) - .heightIn(min = 125.dp, max = 150.dp) - .border( - width = 2.dp, - color = Color.White.copy(alpha = if (isCurrentChapter) 1f else 0f), - shape = RoundedCornerShape(24.dp) - ), - contentDescription = "" - ) } } } @@ -163,9 +151,13 @@ internal fun ChapterSelectionSheet( } private fun List.indexOfCurrent(currentPosition: Long): Int { - return this.indexOfFirst { chapter -> - val nextChapterTime = - this.getOrNull(this.indexOf(chapter) + 1)?.time ?: Long.MAX_VALUE - currentPosition >= chapter.time && currentPosition < nextChapterTime + if (isEmpty()) return 0 + + for (i in indices) { + val chapter = this[i] + val nextTime = getOrNull(i + 1)?.time ?: Long.MAX_VALUE + if (currentPosition in chapter.time until nextTime) return i } -} \ No newline at end of file + + return if (currentPosition < first().time) 0 else lastIndex +} diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/CustomModalBottomSheet.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/CustomModalBottomSheet.kt index c72907d..0627d75 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/CustomModalBottomSheet.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/CustomModalBottomSheet.kt @@ -6,10 +6,10 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.SheetValue import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -29,7 +29,11 @@ internal fun CustomModalBottomSheet( content: @Composable () -> Unit, ) { val modalBottomSheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true + skipPartiallyExpanded = true, + confirmValueChange = { newValue -> + newValue == SheetValue.Expanded || + newValue == SheetValue.Hidden + } ) LaunchedEffect(Unit) { @@ -47,7 +51,6 @@ internal fun CustomModalBottomSheet( Box( modifier = Modifier .fillMaxWidth() - .wrapContentHeight() .displayCutoutPadding() .background( shape = RoundedCornerShape(16.dp), diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/SubtitlePicker.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/SubtitlePicker.kt index eb24fb4..728412b 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/SubtitlePicker.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/SubtitlePicker.kt @@ -20,7 +20,6 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import nl.jknaapen.fladder.objects.VideoPlayerObject import nl.jknaapen.fladder.utility.clearSubtitleTrack -import nl.jknaapen.fladder.utility.conditional import nl.jknaapen.fladder.utility.setInternalSubtitleTrack @OptIn(UnstableApi::class) @@ -33,16 +32,27 @@ fun SubtitlePicker( val subTitles by VideoPlayerObject.subtitleTracks.collectAsState(listOf()) val internalSubTracks by VideoPlayerObject.exoSubTracks - val focusRequester = remember { FocusRequester() } + val focusOffTrack = remember { FocusRequester() } + + val focusRequesters = remember(internalSubTracks) { + internalSubTracks.associateWith { FocusRequester() } + } val listState = rememberLazyListState() - LaunchedEffect(selectedIndex, subTitles) { - if (selectedIndex == -1) return@LaunchedEffect - listState.scrollToItem( - subTitles.indexOfFirst { it.index == selectedIndex.toLong() } - ) - focusRequester.requestFocus() + LaunchedEffect(selectedIndex, subTitles, internalSubTracks) { + val serverSubIndex = subTitles.indexOfFirst { it.index == selectedIndex.toLong() } + + if (serverSubIndex <= 0) { + focusOffTrack.requestFocus() + return@LaunchedEffect + } + + val internalIndex = serverSubIndex - 1 + val lazyColumnIndex = internalIndex + 1 + + listState.scrollToItem(lazyColumnIndex) + focusRequesters[internalSubTracks[internalIndex]]?.requestFocus() } CustomModalBottomSheet( @@ -60,9 +70,7 @@ fun SubtitlePicker( TrackButton( modifier = Modifier .fillMaxWidth() - .conditional(selectedOff) { - focusRequester(focusRequester) - }, + .focusRequester(focusOffTrack), onClick = { VideoPlayerObject.setSubtitleTrackIndex(-1) player.clearSubtitleTrack() @@ -81,9 +89,7 @@ fun SubtitlePicker( TrackButton( modifier = Modifier .fillMaxWidth() - .conditional(selected) { - focusRequester(focusRequester) - }, + .focusRequester(focusRequesters[subtitle]!!), onClick = { serverSub?.index?.let { VideoPlayerObject.setSubtitleTrackIndex(it.toInt()) diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/TrackButton.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/TrackButton.kt index 1eacd1e..e673f3d 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/TrackButton.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/dialogs/TrackButton.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.unit.dp import io.github.rabehx.iconsax.Iconsax import io.github.rabehx.iconsax.filled.TickSquare import nl.jknaapen.fladder.composables.controls.CustomButton -import nl.jknaapen.fladder.utility.defaultSelected @Composable internal fun TrackButton( @@ -33,8 +32,7 @@ internal fun TrackButton( backgroundColor = Color.White.copy(alpha = 0.25f), modifier = modifier .padding(vertical = 6.dp, horizontal = 12.dp) - .defaultMinSize(minHeight = 40.dp) - .defaultSelected(selected), + .defaultMinSize(minHeight = 40.dp), onClick = onClick, ) { Row( diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/overlays/NextUpOverlay.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/overlays/NextUpOverlay.kt index 5363173..f8e4e7f 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/overlays/NextUpOverlay.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/composables/overlays/NextUpOverlay.kt @@ -165,22 +165,29 @@ internal fun NextUpOverlay( .padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp), ) { - Text( - "Next-up in $timeUntilNextVideo seconds", - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onSurface - ) - Box( - modifier = Modifier - .align(alignment = Alignment.CenterHorizontally) - .fillMaxWidth(fraction = 0.1f) - .heightIn(2.dp) - .background( - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f), - shape = RoundedCornerShape(16.dp), - ) - ) - MediaInfo() + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Text( + "Next-up in $timeUntilNextVideo seconds", + style = MaterialTheme.typography.titleLarge, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.onSurface + ) + Box( + modifier = Modifier + .align(alignment = Alignment.CenterHorizontally) + .fillMaxWidth(fraction = 0.1f) + .heightIn(2.dp) + .background( + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f), + shape = RoundedCornerShape(16.dp), + ) + ) + MediaInfo() + } Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/messengers/VideoPlayerImplementation.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/messengers/VideoPlayerImplementation.kt index 167be48..dfa2703 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/messengers/VideoPlayerImplementation.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/messengers/VideoPlayerImplementation.kt @@ -61,7 +61,6 @@ class VideoPlayerImplementation( ) .build() - player?.stop() player?.clearMediaItems() player?.setMediaItem(mediaItem) diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/player/ExoPlayer.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/player/ExoPlayer.kt index e9b51b5..47263df 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/player/ExoPlayer.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/player/ExoPlayer.kt @@ -58,8 +58,6 @@ internal fun ExoPlayer( val videoHost = VideoPlayerObject val context = LocalContext.current - var initialized = false - val extractorsFactory = DefaultExtractorsFactory().apply { val isLowRamDevice = context.getSystemService()?.isLowRamDevice == true setTsExtractorTimestampSearchBytes( @@ -146,7 +144,7 @@ internal fun ExoPlayer( it.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } } - + videoHost.setPlaybackState( PlaybackState( position = exoPlayer.currentPosition, @@ -167,13 +165,17 @@ internal fun ExoPlayer( override fun onTracksChanged(tracks: Tracks) { super.onTracksChanged(tracks) - if (!initialized) { - initialized = true + val subTracks = exoPlayer.getSubtitleTracks() + val audioTracks = exoPlayer.getAudioTracks() + + if (subTracks.isEmpty() && audioTracks.isEmpty()) return + + if (subTracks != VideoPlayerObject.exoSubTracks.value || audioTracks != VideoPlayerObject.exoAudioTracks.value) { VideoPlayerObject.implementation.playbackData.value?.let { exoPlayer.properlySetSubAndAudioTracks(it) } - VideoPlayerObject.exoSubTracks.value = exoPlayer.getSubtitleTracks() - VideoPlayerObject.exoAudioTracks.value = exoPlayer.getAudioTracks() + VideoPlayerObject.exoSubTracks.value = subTracks + VideoPlayerObject.exoAudioTracks.value = audioTracks } } } diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/Modifiers.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/Modifiers.kt index a196ae8..cb64fa0 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/Modifiers.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/Modifiers.kt @@ -3,6 +3,7 @@ package nl.jknaapen.fladder.utility import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -13,13 +14,13 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -42,7 +43,7 @@ fun Modifier.highlightOnFocus( ) .border( width = width, - color = color.copy(alpha = 0.5f), + color = color.copy(alpha = 0.8f), ) } else if (width != 0.dp) { @@ -54,7 +55,7 @@ fun Modifier.highlightOnFocus( ) .border( width = width, - color = color.copy(alpha = 0.5f), + color = color.copy(alpha = 0.8f), shape = shape ) } else { @@ -104,12 +105,23 @@ fun Modifier.conditional(condition: Boolean, modifier: Modifier.() -> Modifier): fun Modifier.visible( visible: Boolean, ): Modifier { - val alphaAnimated by animateFloatAsState(if (visible) 1f else 0f) + val alphaAnimated by animateFloatAsState( + targetValue = if (visible) 1f else 0f, + label = "AlphaAnimation" + ) + return this .graphicsLayer { alpha = alphaAnimated } .then( - if (!visible) Modifier.pointerInput(Unit) {} else Modifier + if (!visible) { + //Collapse composable to disable input blocking + Modifier + .size(0.dp) + .clipToBounds() + } else { + Modifier + } ) } diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/TrackHelper.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/TrackHelper.kt index e2f45b9..2f907d8 100644 --- a/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/TrackHelper.kt +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/utility/TrackHelper.kt @@ -56,6 +56,7 @@ fun ExoPlayer.setInternalAudioTrack(audioTrack: InternalTrack) { selector.setParameters( selector.buildUponParameters() .setRendererDisabled(audioTrack.rendererIndex, false) + .setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, false) .build() ) @@ -74,8 +75,12 @@ fun ExoPlayer.clearAudioTrack(disable: Boolean = true) { selector.setParameters( selector.buildUponParameters() .setRendererDisabled(C.TRACK_TYPE_AUDIO, disable) + .setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, disable) .build() ) + + this.trackSelectionParameters = selector.parameters.buildUpon() + .build() } @OptIn(UnstableApi::class) @@ -110,21 +115,27 @@ fun ExoPlayer.getSubtitleTracks(): List { fun ExoPlayer.clearSubtitleTrack() { val selector = trackSelector as? DefaultTrackSelector ?: return val newParams = selector.buildUponParameters() - .setRendererDisabled(C.TRACK_TYPE_TEXT, false) // keep text renderer active - .setPreferredTextLanguage(null) // don't auto-pick a language - .setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true) // <– disables selection of *any* text track + .setRendererDisabled(C.TRACK_TYPE_TEXT, false) + .setPreferredTextLanguage(null) + .setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true) .build() selector.setParameters(newParams) + + this.trackSelectionParameters = selector.parameters.buildUpon() + .build() } @OptIn(UnstableApi::class) fun ExoPlayer.enableSubtitles(language: String? = null) { val selector = trackSelector as? DefaultTrackSelector ?: return val newParams = selector.buildUponParameters() - .setTrackTypeDisabled(C.TRACK_TYPE_TEXT, false) // allow text again - .setPreferredTextLanguage(language) // optional: auto-pick by language + .setTrackTypeDisabled(C.TRACK_TYPE_TEXT, false) + .setPreferredTextLanguage(language) .build() selector.setParameters(newParams) + + this.trackSelectionParameters = selector.parameters.buildUpon() + .build() }