diff --git a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt index 11554506..aa609f40 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt @@ -642,6 +642,18 @@ sealed interface AppPreference { indexToValue = { ShowNextUpWhen.forNumber(it) }, valueToIndex = { it.number }, ) + + val ShowClock = + AppSwitchPreference( + title = R.string.show_clock, + defaultValue = true, + getter = { it.interfacePreferences.showClock }, + setter = { prefs, value -> + prefs.updateInterfacePreferences { showClock = value } + }, + summaryOn = R.string.enabled, + summaryOff = R.string.disabled, + ) } } @@ -709,6 +721,7 @@ val advancedPreferences = title = R.string.ui_interface, preferences = listOf( + AppPreference.ShowClock, AppPreference.CombineContinueNext, // Temporarily disabled, see https://github.com/damontecres/Wholphin/pull/127#issuecomment-3478058418 // AppPreference.NavDrawerSwitchOnFocus, diff --git a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreferencesSerializer.kt b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreferencesSerializer.kt index bb90e4a8..b76b6423 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreferencesSerializer.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreferencesSerializer.kt @@ -73,6 +73,7 @@ class AppPreferencesSerializer appThemeColors = AppPreference.ThemeColors.defaultValue navDrawerSwitchOnFocus = AppPreference.NavDrawerSwitchOnFocus.defaultValue + showClock = AppPreference.ShowClock.defaultValue }.build() }.build() diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedMovie.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedMovie.kt index 3c7e438a..e56747a0 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedMovie.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedMovie.kt @@ -158,6 +158,7 @@ fun RecommendedMovie( onClickItem = onClickItem, onLongClickItem = {}, onFocusPosition = onFocusPosition, + showClock = preferences.appPreferences.interfacePreferences.showClock, modifier = modifier, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedTvShow.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedTvShow.kt index d6f733a9..98b03cb4 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedTvShow.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/RecommendedTvShow.kt @@ -170,6 +170,7 @@ fun RecommendedTvShow( onClickItem = onClickItem, onLongClickItem = {}, onFocusPosition = onFocusPosition, + showClock = preferences.appPreferences.interfacePreferences.showClock, modifier = modifier, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverviewContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverviewContent.kt index 0629ce6d..6c19f62f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverviewContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverviewContent.kt @@ -132,6 +132,12 @@ fun SeriesOverviewContent( modifier = Modifier, ) { item { + val paddingValues = + if (preferences.appPreferences.interfacePreferences.showClock) { + PaddingValues(start = 16.dp, end = 100.dp) + } else { + PaddingValues(start = 16.dp, end = 16.dp) + } TabRow( selectedTabIndex = focusTabIndex, modifier = @@ -140,7 +146,7 @@ fun SeriesOverviewContent( focusRequesters.size > selectedTabIndex, { Modifier.focusRestorer(focusRequesters[selectedTabIndex]) }, ).focusRequester(tabRowFocusRequester) - .padding(horizontal = 16.dp) + .padding(paddingValues) .fillMaxWidth() .onFocusChanged { if (!it.isFocused) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt index 4e3ed0d2..64c00953 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt @@ -171,6 +171,7 @@ fun HomePage( ) }, loadingState = loading, + showClock = preferences.appPreferences.interfacePreferences.showClock, modifier = modifier, ) dialog?.let { params -> @@ -205,6 +206,7 @@ fun HomePageContent( homeRows: List, onClickItem: (BaseItem) -> Unit, onLongClickItem: (BaseItem) -> Unit, + showClock: Boolean, modifier: Modifier = Modifier, onFocusPosition: ((RowColumn) -> Unit)? = null, loadingState: LoadingState? = null, @@ -342,7 +344,7 @@ fun HomePageContent( Box( modifier = Modifier - .padding(16.dp) + .padding(if (showClock) 40.dp else 20.dp) .size(40.dp) .align(Alignment.TopEnd), ) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt index de463e99..db304e94 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -27,6 +28,7 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue @@ -74,13 +76,16 @@ import com.github.damontecres.wholphin.ui.setValueOnMain import com.github.damontecres.wholphin.ui.spacedByWithFooter import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.util.TimeFormatter import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.DeviceProfile import timber.log.Timber +import java.time.LocalTime import java.util.UUID import javax.inject.Inject @@ -431,13 +436,35 @@ fun NavDrawer( } }, ) { - // Drawer content - DestinationContent( - destination = destination, - preferences = preferences, - deviceProfile = deviceProfile, + Box( modifier = Modifier.fillMaxSize(), - ) + ) { + // Drawer content + DestinationContent( + destination = destination, + preferences = preferences, + deviceProfile = deviceProfile, + modifier = Modifier.fillMaxSize(), + ) + if (preferences.appPreferences.interfacePreferences.showClock) { + var now by remember { mutableStateOf(LocalTime.now()) } + LaunchedEffect(Unit) { + if (isActive) { + now = LocalTime.now() + } + } + Text( + text = TimeFormatter.format(now), +// style = MaterialTheme.typography.titleMedium, + fontSize = 18.sp, + color = MaterialTheme.colorScheme.onSurface, + modifier = + Modifier + .align(Alignment.TopEnd) + .padding(vertical = 16.dp, horizontal = 24.dp), + ) + } + } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt index 5df69f4b..f7afb526 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt @@ -282,6 +282,7 @@ fun SeekBar( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, ) { + val remaining = ((player.duration - position) / 1000).seconds Text( text = (position / 1000).seconds.toString(), color = MaterialTheme.colorScheme.onSurface, @@ -291,7 +292,7 @@ fun SeekBar( .padding(8.dp), ) Text( - text = "-" + ((player.duration - position) / 1000).seconds.toString(), + text = "-$remaining", color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.labelLarge, modifier = diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt index 912cb214..9d050b02 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -56,9 +57,15 @@ import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.letNotEmpty import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.util.TimeFormatter +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive import org.jellyfin.sdk.model.api.MediaSegmentDto import org.jellyfin.sdk.model.api.TrickplayInfo +import java.time.LocalTime import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds private val titleTextSize = 28.sp private val subtitleTextSize = 18.sp @@ -74,6 +81,7 @@ fun PlaybackOverlay( playerControls: Player, controllerViewState: ControllerViewState, showPlay: Boolean, + showClock: Boolean, previousEnabled: Boolean, nextEnabled: Boolean, seekEnabled: Boolean, @@ -144,6 +152,7 @@ fun PlaybackOverlay( playerControls = playerControls, controllerViewState = controllerViewState, showPlay = showPlay, + showClock = showClock, previousEnabled = previousEnabled, nextEnabled = nextEnabled, seekEnabled = seekEnabled, @@ -415,6 +424,7 @@ fun Controller( subtitleStreams: List, playerControls: Player, controllerViewState: ControllerViewState, + showClock: Boolean, showPlay: Boolean, previousEnabled: Boolean, nextEnabled: Boolean, @@ -453,12 +463,40 @@ fun Controller( fontSize = titleTextSize, ) } - subtitle?.let { - Text( - text = it, - style = MaterialTheme.typography.titleMedium, - fontSize = subtitleTextSize, - ) + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = + Modifier + .fillMaxWidth() + .align(Alignment.End), + ) { + subtitle?.let { + Text( + text = it, + style = MaterialTheme.typography.titleMedium, + fontSize = subtitleTextSize, + ) + } + if (showClock) { + var remaining by remember { mutableStateOf((playerControls.duration - playerControls.currentPosition).milliseconds) } + LaunchedEffect(playerControls) { + while (isActive) { + remaining = + (playerControls.duration - playerControls.currentPosition).milliseconds + delay(1.seconds) + } + } + val endTime = LocalTime.now().plusSeconds(remaining.inWholeSeconds) + val endTimeStr = TimeFormatter.format(endTime) + Text( + text = "Ends $endTimeStr", + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.labelLarge, + modifier = + Modifier + .padding(end = 32.dp), + ) + } } } PlaybackControls( diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt index caf4f1ee..b2c8749f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt @@ -387,6 +387,7 @@ fun PlaybackPage( viewModel.playItemInPlaylist(it) }, currentSegment = currentSegment, + showClock = preferences.appPreferences.interfacePreferences.showClock, ) } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/util/AppUpgradeHandler.kt b/app/src/main/java/com/github/damontecres/wholphin/util/AppUpgradeHandler.kt index 9f16828d..b010750c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/util/AppUpgradeHandler.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/util/AppUpgradeHandler.kt @@ -89,4 +89,11 @@ suspend fun upgradeApp( } } } + if (previous.isEqualOrBefore(Version.fromString("0.2.5-11-g0"))) { + appPreferences.updateData { + it.updateInterfacePreferences { + showClock = AppPreference.ShowClock.defaultValue + } + } + } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/util/Formatting.kt b/app/src/main/java/com/github/damontecres/wholphin/util/Formatting.kt index 94595b0a..9622dee7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/util/Formatting.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/util/Formatting.kt @@ -18,8 +18,11 @@ import org.jellyfin.sdk.model.api.MediaStreamType import java.time.LocalDate import java.time.LocalDateTime import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle import java.util.Locale +val TimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) + /** * Format a [LocalDateTime] as `Aug 24, 2000` */ diff --git a/app/src/main/proto/WholphinDataStore.proto b/app/src/main/proto/WholphinDataStore.proto index f6023e49..bdfd92a4 100644 --- a/app/src/main/proto/WholphinDataStore.proto +++ b/app/src/main/proto/WholphinDataStore.proto @@ -88,6 +88,7 @@ message InterfacePreferences { map remembered_tabs = 3; AppThemeColors app_theme_colors = 4; bool nav_drawer_switch_on_focus = 5; + bool show_clock = 6; } message AppPreferences { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1e927476..a6a3287e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,6 +138,7 @@ Watch live %1$d years old Play with transcoding + Show Clock Aired Episode Order Create new playlist Add to playlist