diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/Extensions.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/Extensions.kt index c05198ea..c7b2469b 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/Extensions.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/Extensions.kt @@ -24,6 +24,7 @@ import org.jellyfin.sdk.model.api.BaseItemDto import org.jellyfin.sdk.model.extensions.ticks import timber.log.Timber import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes @@ -186,3 +187,11 @@ val BaseItemDto.timeRemaining: Duration? fun Player.seekBack(amount: Duration) = seekTo((currentPosition - amount.inWholeMilliseconds).coerceAtLeast(0L)) fun Player.seekForward(amount: Duration) = seekTo((currentPosition + amount.inWholeMilliseconds).coerceAtMost(duration)) + +@OptIn(ExperimentalContracts::class) +inline fun , R> T.letNotEmpty(block: (T) -> R): R? { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } + return if (this.isNotEmpty()) block(this) else null +} diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/components/PlayButtons.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/components/PlayButtons.kt index 0dcba34f..3c62f6df 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/components/PlayButtons.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/components/PlayButtons.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusState +import androidx.compose.ui.focus.focusProperties import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRestorer import androidx.compose.ui.focus.onFocusChanged @@ -26,6 +27,7 @@ import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.dolphin.R +import com.github.damontecres.dolphin.ui.tryRequestFocus import kotlin.time.Duration @Composable @@ -109,3 +111,84 @@ fun PlayButtons( } } } + +@Composable +fun ExpandablePlayButtons( + resumePosition: Duration, + watched: Boolean, + playOnClick: (position: Duration) -> Unit, + watchOnClick: () -> Unit, + moreOnClick: () -> Unit, + buttonOnFocusChanged: (FocusState) -> Unit, + modifier: Modifier = Modifier, +) { + val firstFocus = remember { FocusRequester() } + LazyRow( + horizontalArrangement = Arrangement.spacedBy(16.dp), + contentPadding = PaddingValues(8.dp), + modifier = + modifier + .focusGroup() + .focusProperties { + onEnter = { + firstFocus.tryRequestFocus() + } + }, + ) { + if (resumePosition > Duration.ZERO) { + item { +// LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } + ExpandablePlayButton( + R.string.resume, + resumePosition, + Icons.Default.PlayArrow, + playOnClick, + Modifier + .onFocusChanged(buttonOnFocusChanged) + .focusRequester(firstFocus), + ) + } + item { + ExpandablePlayButton( + R.string.restart, + Duration.ZERO, + Icons.Default.Refresh, + playOnClick, + Modifier.onFocusChanged(buttonOnFocusChanged), + ) + } + } else { + item { + ExpandablePlayButton( + R.string.play, + Duration.ZERO, + Icons.Default.PlayArrow, + playOnClick, + Modifier + .onFocusChanged(buttonOnFocusChanged) + .focusRequester(firstFocus), + ) + } + } + // Watched button + item { + ExpandableFaButton( + title = if (watched) R.string.mark_unwatched else R.string.mark_watched, + iconStringRes = if (watched) R.string.fa_eye else R.string.fa_eye_slash, + onClick = watchOnClick, + modifier = Modifier.onFocusChanged(buttonOnFocusChanged), + ) + } + + // More button + item { + ExpandablePlayButton( + R.string.more, + Duration.ZERO, + Icons.Default.MoreVert, + { moreOnClick.invoke() }, + Modifier.onFocusChanged(buttonOnFocusChanged), + ) + } + } +} diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/MovieDetails.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/MovieDetails.kt deleted file mode 100644 index 20875656..00000000 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/MovieDetails.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.github.damontecres.dolphin.ui.detail - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.tv.material3.Button -import androidx.tv.material3.Text -import com.github.damontecres.dolphin.data.model.Video -import com.github.damontecres.dolphin.preferences.UserPreferences -import com.github.damontecres.dolphin.ui.components.ErrorMessage -import com.github.damontecres.dolphin.ui.components.LoadingPage -import com.github.damontecres.dolphin.ui.nav.Destination -import com.github.damontecres.dolphin.ui.nav.NavigationManager -import com.github.damontecres.dolphin.util.LoadingState -import dagger.hilt.android.lifecycle.HiltViewModel -import org.jellyfin.sdk.api.client.ApiClient -import org.jellyfin.sdk.model.extensions.ticks -import javax.inject.Inject -import kotlin.time.Duration.Companion.seconds - -@HiltViewModel -class MovieViewModel - @Inject - constructor( - api: ApiClient, - ) : LoadingItemViewModel