Updates to buttons

This commit is contained in:
Damontecres 2025-12-23 16:48:56 -05:00
parent 6046799b91
commit f27415de0f
No known key found for this signature in database
6 changed files with 104 additions and 44 deletions

View file

@ -4,6 +4,7 @@ import android.content.Context
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem
import com.github.damontecres.wholphin.data.model.NavPinType import com.github.damontecres.wholphin.data.model.NavPinType
import com.github.damontecres.wholphin.services.SeerrServerRepository
import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
@ -24,6 +25,7 @@ class NavDrawerItemRepository
private val api: ApiClient, private val api: ApiClient,
private val serverRepository: ServerRepository, private val serverRepository: ServerRepository,
private val serverPreferencesDao: ServerPreferencesDao, private val serverPreferencesDao: ServerPreferencesDao,
private val seerrServerRepository: SeerrServerRepository,
) { ) {
suspend fun getNavDrawerItems(): List<NavDrawerItem> { suspend fun getNavDrawerItems(): List<NavDrawerItem> {
val user = serverRepository.currentUser.value val user = serverRepository.currentUser.value
@ -46,7 +48,13 @@ class NavDrawerItemRepository
setOf() setOf()
} }
val builtins = listOf(NavDrawerItem.Favorites, NavDrawerItem.Discover) val builtins =
if (seerrServerRepository.active()) {
listOf(NavDrawerItem.Favorites, NavDrawerItem.Discover)
} else {
listOf(NavDrawerItem.Favorites)
}
val libraries = val libraries =
userViews userViews
.filter { it.collectionType in supportedCollectionTypes || it.id in recordingFolders } .filter { it.collectionType in supportedCollectionTypes || it.id in recordingFolders }

View file

@ -21,6 +21,7 @@ import dagger.hilt.android.scopes.ActivityScoped
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import timber.log.Timber import timber.log.Timber
@ -51,6 +52,11 @@ class SeerrServerRepository
} }
} }
/**
* Whether Seerr integration is currently active of not
*/
suspend fun active(): Boolean = current.firstOrNull() != null && seerrApi.active
fun clear() { fun clear() {
_currentServer.update { null } _currentServer.update { null }
_currentUser.update { null } _currentUser.update { null }

View file

@ -65,6 +65,8 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
@Composable @Composable
fun DiscoverMovieDetails( fun DiscoverMovieDetails(
@ -142,6 +144,16 @@ fun DiscoverMovieDetails(
files = listOf(), files = listOf(),
) )
}, },
goToOnClick = {
movie.mediaInfo?.jellyfinMediaId?.toUUIDOrNull()?.let {
viewModel.navigateTo(
Destination.MediaItem(
itemId = it,
type = BaseItemKind.MOVIE,
),
)
}
},
moreOnClick = { moreOnClick = {
moreDialog = moreDialog =
DialogParams( DialogParams(
@ -214,6 +226,7 @@ fun DiscoverMovieDetailsContent(
cancelOnClick: () -> Unit, cancelOnClick: () -> Unit,
trailerOnClick: (Trailer) -> Unit, trailerOnClick: (Trailer) -> Unit,
overviewOnClick: () -> Unit, overviewOnClick: () -> Unit,
goToOnClick: () -> Unit,
moreOnClick: () -> Unit, moreOnClick: () -> Unit,
onClickItem: (Int, DiscoverItem) -> Unit, onClickItem: (Int, DiscoverItem) -> Unit,
onClickPerson: (Person) -> Unit, onClickPerson: (Person) -> Unit,
@ -262,6 +275,7 @@ fun DiscoverMovieDetailsContent(
requestOnClick = requestOnClick, requestOnClick = requestOnClick,
cancelOnClick = cancelOnClick, cancelOnClick = cancelOnClick,
moreOnClick = moreOnClick, moreOnClick = moreOnClick,
goToOnClick = goToOnClick,
buttonOnFocusChanged = { buttonOnFocusChanged = {
if (it.isFocused) { if (it.isFocused) {
position = HEADER_ROW position = HEADER_ROW

View file

@ -7,7 +7,6 @@ import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -28,6 +27,7 @@ fun ExpandableDiscoverButtons(
availability: SeerrAvailability, availability: SeerrAvailability,
requestOnClick: () -> Unit, requestOnClick: () -> Unit,
cancelOnClick: () -> Unit, cancelOnClick: () -> Unit,
goToOnClick: () -> Unit,
moreOnClick: () -> Unit, moreOnClick: () -> Unit,
buttonOnFocusChanged: (FocusState) -> Unit, buttonOnFocusChanged: (FocusState) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -41,32 +41,71 @@ fun ExpandableDiscoverButtons(
.focusGroup() .focusGroup()
.focusRestorer(firstFocus), .focusRestorer(firstFocus),
) { ) {
if (availability == SeerrAvailability.UNKNOWN) { val text =
item("first") { when (availability) {
ExpandableFaButton( SeerrAvailability.UNKNOWN -> R.string.request
title = R.string.request,
iconStringRes = R.string.fa_download, SeerrAvailability.PENDING,
onClick = requestOnClick, SeerrAvailability.PROCESSING,
modifier = -> R.string.pending
Modifier
.focusRequester(firstFocus) SeerrAvailability.PARTIALLY_AVAILABLE,
.onFocusChanged(buttonOnFocusChanged), SeerrAvailability.AVAILABLE,
) -> R.string.go_to
SeerrAvailability.DELETED -> R.string.delete // TODO
} }
} else if (availability == SeerrAvailability.PENDING || availability == SeerrAvailability.PROCESSING) { val icon =
item("first") { when (availability) {
ExpandableFaButton( SeerrAvailability.UNKNOWN -> R.string.fa_download
title = R.string.pending,
iconStringRes = R.string.fa_clock, SeerrAvailability.PENDING,
onClick = { SeerrAvailability.PROCESSING,
// TODO show request dialog? -> R.string.fa_clock
},
modifier = SeerrAvailability.PARTIALLY_AVAILABLE,
Modifier SeerrAvailability.AVAILABLE,
.focusRequester(firstFocus) -> R.string.fa_play
.onFocusChanged(buttonOnFocusChanged),
) SeerrAvailability.DELETED -> R.string.fa_video // TODO
} }
item("first") {
ExpandableFaButton(
title = text,
iconStringRes = icon,
onClick = {
when (availability) {
SeerrAvailability.UNKNOWN -> {
requestOnClick.invoke()
}
SeerrAvailability.PENDING,
SeerrAvailability.PROCESSING,
-> {
cancelOnClick.invoke()
}
SeerrAvailability.PARTIALLY_AVAILABLE,
SeerrAvailability.AVAILABLE,
-> {
goToOnClick.invoke()
}
SeerrAvailability.DELETED -> {
// TODO
}
}
},
modifier =
Modifier
.focusRequester(firstFocus)
.onFocusChanged(buttonOnFocusChanged),
)
}
if (availability == SeerrAvailability.PENDING || availability == SeerrAvailability.PROCESSING) {
// TODO should only show if user can cancel
item("cancel") { item("cancel") {
ExpandablePlayButton( ExpandablePlayButton(
title = R.string.cancel, title = R.string.cancel,
@ -78,21 +117,6 @@ fun ExpandableDiscoverButtons(
.onFocusChanged(buttonOnFocusChanged), .onFocusChanged(buttonOnFocusChanged),
) )
} }
} else if (availability == SeerrAvailability.PARTIALLY_AVAILABLE || availability == SeerrAvailability.AVAILABLE) {
item("first") {
ExpandablePlayButton(
title = R.string.go_to,
icon = Icons.Default.PlayArrow,
onClick = {
// TODO go to the item
},
resume = Duration.ZERO,
modifier =
Modifier
.focusRequester(firstFocus)
.onFocusChanged(buttonOnFocusChanged),
)
}
} }
// More button // More button

View file

@ -111,7 +111,7 @@ class NavDrawerViewModel
val setupNavigationManager: SetupNavigationManager, val setupNavigationManager: SetupNavigationManager,
val backdropService: BackdropService, val backdropService: BackdropService,
) : ViewModel() { ) : ViewModel() {
private var all: List<NavDrawerItem>? = null // private var all: List<NavDrawerItem>? = null
val moreLibraries = MutableLiveData<List<NavDrawerItem>>(null) val moreLibraries = MutableLiveData<List<NavDrawerItem>>(null)
val libraries = MutableLiveData<List<NavDrawerItem>>(listOf()) val libraries = MutableLiveData<List<NavDrawerItem>>(listOf())
val selectedIndex = MutableLiveData(-1) val selectedIndex = MutableLiveData(-1)
@ -119,8 +119,8 @@ class NavDrawerViewModel
fun init() { fun init() {
viewModelScope.launchIO { viewModelScope.launchIO {
val all = all ?: navDrawerItemRepository.getNavDrawerItems() val all = navDrawerItemRepository.getNavDrawerItems()
this@NavDrawerViewModel.all = all // this@NavDrawerViewModel.all = all
val libraries = navDrawerItemRepository.getFilteredNavDrawerItems(all) val libraries = navDrawerItemRepository.getFilteredNavDrawerItems(all)
val moreLibraries = all.toMutableList().apply { removeAll(libraries) } val moreLibraries = all.toMutableList().apply { removeAll(libraries) }

View file

@ -6,9 +6,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
@ -26,6 +30,7 @@ import com.github.damontecres.wholphin.ui.cards.ItemRow
import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.setValueOnMain import com.github.damontecres.wholphin.ui.setValueOnMain
import com.github.damontecres.wholphin.ui.tryRequestFocus
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import javax.inject.Inject import javax.inject.Inject
@ -75,6 +80,8 @@ fun SeerrDiscoverPage(
val movies by viewModel.discoverMovies.observeAsState(listOf()) val movies by viewModel.discoverMovies.observeAsState(listOf())
val tv by viewModel.discoverTv.observeAsState(listOf()) val tv by viewModel.discoverTv.observeAsState(listOf())
val focusRequester = remember { FocusRequester() }
LaunchedEffect(movies) { if (movies.isNotEmpty()) focusRequester.tryRequestFocus() }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
Column( Column(
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
@ -99,6 +106,7 @@ fun SeerrDiscoverPage(
modifier = mod, modifier = mod,
) )
}, },
modifier = Modifier.focusRequester(focusRequester),
) )
ItemRow( ItemRow(
title = stringResource(R.string.tv_shows), title = stringResource(R.string.tv_shows),