mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Various fixes
This commit is contained in:
parent
d8a58a6d96
commit
2879cd477c
7 changed files with 72 additions and 22 deletions
|
|
@ -149,15 +149,15 @@ class MusicService
|
||||||
shuffled: Boolean,
|
shuffled: Boolean,
|
||||||
) {
|
) {
|
||||||
Timber.d("setQueue: %s items, shuffled=%s", items.size, shuffled)
|
Timber.d("setQueue: %s items, shuffled=%s", items.size, shuffled)
|
||||||
start()
|
|
||||||
val mediaItems =
|
val mediaItems =
|
||||||
items
|
items
|
||||||
.filter { it.type == BaseItemKind.AUDIO }
|
.filter { it.type == BaseItemKind.AUDIO }
|
||||||
.map(::convert)
|
.map(::convert)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
updateQueueSize()
|
|
||||||
player.setMediaItems(mediaItems)
|
player.setMediaItems(mediaItems)
|
||||||
player.shuffleModeEnabled = shuffled
|
player.shuffleModeEnabled = shuffled
|
||||||
|
updateQueueSize()
|
||||||
|
start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
|
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.services.BackdropService
|
import com.github.damontecres.wholphin.services.BackdropService
|
||||||
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||||
|
|
@ -105,13 +106,14 @@ abstract class RecommendedViewModel(
|
||||||
|
|
||||||
fun update(
|
fun update(
|
||||||
@StringRes title: Int,
|
@StringRes title: Int,
|
||||||
|
viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
|
||||||
block: suspend () -> List<BaseItem>,
|
block: suspend () -> List<BaseItem>,
|
||||||
): Deferred<HomeRowLoadingState> =
|
): Deferred<HomeRowLoadingState> =
|
||||||
viewModelScope.async(Dispatchers.IO) {
|
viewModelScope.async(Dispatchers.IO) {
|
||||||
val titleStr = context.getString(title)
|
val titleStr = context.getString(title)
|
||||||
val row =
|
val row =
|
||||||
try {
|
try {
|
||||||
HomeRowLoadingState.Success(titleStr, block.invoke())
|
HomeRowLoadingState.Success(titleStr, block.invoke(), viewOptions)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
HomeRowLoadingState.Error(titleStr, null, ex)
|
HomeRowLoadingState.Error(titleStr, null, ex)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.ServerRepository
|
import com.github.damontecres.wholphin.data.ServerRepository
|
||||||
|
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
|
|
@ -18,6 +19,8 @@ import com.github.damontecres.wholphin.services.MediaReportService
|
||||||
import com.github.damontecres.wholphin.services.NavigationManager
|
import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.services.SuggestionService
|
import com.github.damontecres.wholphin.services.SuggestionService
|
||||||
import com.github.damontecres.wholphin.services.SuggestionsResource
|
import com.github.damontecres.wholphin.services.SuggestionsResource
|
||||||
|
import com.github.damontecres.wholphin.ui.AspectRatio
|
||||||
|
import com.github.damontecres.wholphin.ui.Cards
|
||||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||||
import com.github.damontecres.wholphin.ui.data.RowColumn
|
import com.github.damontecres.wholphin.ui.data.RowColumn
|
||||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||||
|
|
@ -31,6 +34,7 @@ import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
|
|
@ -88,7 +92,15 @@ class RecommendedMusicViewModel
|
||||||
?.maxItemsPerRow
|
?.maxItemsPerRow
|
||||||
?: AppPreference.HomePageItems.defaultValue.toInt()
|
?: AppPreference.HomePageItems.defaultValue.toInt()
|
||||||
|
|
||||||
update(R.string.recently_released) {
|
val jobs = mutableListOf<Deferred<HomeRowLoadingState>>()
|
||||||
|
val viewOptions =
|
||||||
|
HomeRowViewOptions(
|
||||||
|
aspectRatio = AspectRatio.SQUARE,
|
||||||
|
heightDp = Cards.HEIGHT_EPISODE,
|
||||||
|
showTitles = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
update(R.string.recently_released, viewOptions) {
|
||||||
val request =
|
val request =
|
||||||
GetItemsRequest(
|
GetItemsRequest(
|
||||||
parentId = parentId,
|
parentId = parentId,
|
||||||
|
|
@ -103,9 +115,9 @@ class RecommendedMusicViewModel
|
||||||
enableTotalRecordCount = false,
|
enableTotalRecordCount = false,
|
||||||
)
|
)
|
||||||
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
|
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
|
||||||
}
|
}.also(jobs::add)
|
||||||
|
|
||||||
update(R.string.recently_added) {
|
update(R.string.recently_added, viewOptions) {
|
||||||
val request =
|
val request =
|
||||||
GetItemsRequest(
|
GetItemsRequest(
|
||||||
parentId = parentId,
|
parentId = parentId,
|
||||||
|
|
@ -120,9 +132,9 @@ class RecommendedMusicViewModel
|
||||||
enableTotalRecordCount = false,
|
enableTotalRecordCount = false,
|
||||||
)
|
)
|
||||||
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
|
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
|
||||||
}
|
}.also(jobs::add)
|
||||||
|
|
||||||
update(R.string.top_unwatched) {
|
update(R.string.top_unwatched, viewOptions) {
|
||||||
val request =
|
val request =
|
||||||
GetItemsRequest(
|
GetItemsRequest(
|
||||||
parentId = parentId,
|
parentId = parentId,
|
||||||
|
|
@ -138,7 +150,7 @@ class RecommendedMusicViewModel
|
||||||
enableTotalRecordCount = false,
|
enableTotalRecordCount = false,
|
||||||
)
|
)
|
||||||
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
|
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
|
||||||
}
|
}.also(jobs::add)
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -181,9 +193,14 @@ class RecommendedMusicViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading.value == LoadingState.Loading || loading.value == LoadingState.Pending) {
|
for (i in 0..<jobs.size) {
|
||||||
|
val result = jobs[i].await()
|
||||||
|
if (result.completed) {
|
||||||
|
Timber.v("First success")
|
||||||
loading.setValueOnMain(LoadingState.Success)
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
}
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,14 @@ 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
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
import com.github.damontecres.wholphin.data.model.CollectionFolderFilter
|
import com.github.damontecres.wholphin.data.model.CollectionFolderFilter
|
||||||
import com.github.damontecres.wholphin.data.model.GetItemsFilter
|
import com.github.damontecres.wholphin.data.model.GetItemsFilter
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
|
import com.github.damontecres.wholphin.services.MusicService
|
||||||
import com.github.damontecres.wholphin.ui.components.CollectionFolderGrid
|
import com.github.damontecres.wholphin.ui.components.CollectionFolderGrid
|
||||||
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||||
import com.github.damontecres.wholphin.ui.components.GenreCardGrid
|
import com.github.damontecres.wholphin.ui.components.GenreCardGrid
|
||||||
|
|
@ -33,16 +37,35 @@ import com.github.damontecres.wholphin.ui.components.ViewOptionsSquare
|
||||||
import com.github.damontecres.wholphin.ui.data.AlbumSortOptions
|
import com.github.damontecres.wholphin.ui.data.AlbumSortOptions
|
||||||
import com.github.damontecres.wholphin.ui.data.ArtistSortOptions
|
import com.github.damontecres.wholphin.ui.data.ArtistSortOptions
|
||||||
import com.github.damontecres.wholphin.ui.data.SongSortOptions
|
import com.github.damontecres.wholphin.ui.data.SongSortOptions
|
||||||
|
import com.github.damontecres.wholphin.ui.launchDefault
|
||||||
import com.github.damontecres.wholphin.ui.logTab
|
import com.github.damontecres.wholphin.ui.logTab
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
|
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class CollectionFolderMusicViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val musicService: MusicService,
|
||||||
|
) : ViewModel() {
|
||||||
|
fun play(item: BaseItem) {
|
||||||
|
if (item.type == BaseItemKind.AUDIO) {
|
||||||
|
viewModelScope.launchDefault {
|
||||||
|
musicService.setQueue(listOf(item), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CollectionFolderMusic(
|
fun CollectionFolderMusic(
|
||||||
preferences: UserPreferences,
|
preferences: UserPreferences,
|
||||||
destination: Destination.MediaItem,
|
destination: Destination.MediaItem,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
viewModel: CollectionFolderMusicViewModel = hiltViewModel(),
|
||||||
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
|
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val rememberedTabIndex =
|
val rememberedTabIndex =
|
||||||
|
|
@ -174,7 +197,7 @@ fun CollectionFolderMusic(
|
||||||
3 -> {
|
3 -> {
|
||||||
GenreCardGrid(
|
GenreCardGrid(
|
||||||
itemId = destination.itemId,
|
itemId = destination.itemId,
|
||||||
includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM, BaseItemKind.AUDIO),
|
includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM),
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|
@ -187,7 +210,7 @@ fun CollectionFolderMusic(
|
||||||
CollectionFolderGrid(
|
CollectionFolderGrid(
|
||||||
preferences = preferences,
|
preferences = preferences,
|
||||||
onClickItem = { _, item ->
|
onClickItem = { _, item ->
|
||||||
preferencesViewModel.navigationManager.navigateTo(item.destination())
|
viewModel.play(item)
|
||||||
},
|
},
|
||||||
itemId = destination.itemId,
|
itemId = destination.itemId,
|
||||||
viewModelKey = "${destination.itemId}_songs",
|
viewModelKey = "${destination.itemId}_songs",
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,9 @@ fun AlbumDetailsPage(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
favorite = album.favorite,
|
favorite = album.favorite,
|
||||||
|
buttonOnFocusChanged = {
|
||||||
|
if (it.isFocused) scope.launch { bringIntoViewRequester.bringIntoView() }
|
||||||
|
},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.onFocusChanged {
|
.onFocusChanged {
|
||||||
|
|
@ -389,7 +392,7 @@ fun AlbumDetailsPage(
|
||||||
itemsIndexed(state.songs) { index, song ->
|
itemsIndexed(state.songs) { index, song ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.TopStart,
|
||||||
) {
|
) {
|
||||||
SongListItem(
|
SongListItem(
|
||||||
song = song,
|
song = song,
|
||||||
|
|
@ -415,9 +418,7 @@ fun AlbumDetailsPage(
|
||||||
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
// .padding(horizontal = 16.dp)
|
|
||||||
.fillMaxWidth(.75f)
|
.fillMaxWidth(.75f)
|
||||||
.align(Alignment.Center)
|
|
||||||
.ifElse(
|
.ifElse(
|
||||||
index == 0,
|
index == 0,
|
||||||
Modifier
|
Modifier
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,9 @@ fun ArtistDetailsPage(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
favorite = artist.favorite,
|
favorite = artist.favorite,
|
||||||
|
buttonOnFocusChanged = {
|
||||||
|
if (it.isFocused) scope.launch { bringIntoViewRequester.bringIntoView() }
|
||||||
|
},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.onFocusChanged {
|
.onFocusChanged {
|
||||||
|
|
@ -415,7 +418,7 @@ fun ArtistDetailsPage(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = Modifier.fillMaxWidth(.75f),
|
||||||
showArtist = false,
|
showArtist = false,
|
||||||
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ 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
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.FocusState
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.focusRestorer
|
import androidx.compose.ui.focus.focusRestorer
|
||||||
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
|
|
@ -24,6 +26,7 @@ import kotlin.time.Duration
|
||||||
fun MusicExpandableButtons(
|
fun MusicExpandableButtons(
|
||||||
actions: MusicButtonActions,
|
actions: MusicButtonActions,
|
||||||
favorite: Boolean,
|
favorite: Boolean,
|
||||||
|
buttonOnFocusChanged: (FocusState) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val firstFocus = remember { FocusRequester() }
|
val firstFocus = remember { FocusRequester() }
|
||||||
|
|
@ -43,7 +46,8 @@ fun MusicExpandableButtons(
|
||||||
onClick = { actions.onClickPlay.invoke(false) },
|
onClick = { actions.onClickPlay.invoke(false) },
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.focusRequester(firstFocus),
|
.focusRequester(firstFocus)
|
||||||
|
.onFocusChanged(buttonOnFocusChanged),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item("shuffle") {
|
item("shuffle") {
|
||||||
|
|
@ -51,7 +55,7 @@ fun MusicExpandableButtons(
|
||||||
title = R.string.shuffle,
|
title = R.string.shuffle,
|
||||||
iconStringRes = R.string.fa_shuffle,
|
iconStringRes = R.string.fa_shuffle,
|
||||||
onClick = { actions.onClickPlay.invoke(true) },
|
onClick = { actions.onClickPlay.invoke(true) },
|
||||||
modifier = Modifier,
|
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item("instant_mix") {
|
item("instant_mix") {
|
||||||
|
|
@ -59,7 +63,7 @@ fun MusicExpandableButtons(
|
||||||
title = R.string.instant_mix,
|
title = R.string.instant_mix,
|
||||||
iconStringRes = R.string.fa_compass,
|
iconStringRes = R.string.fa_compass,
|
||||||
onClick = actions.onClickInstantMix,
|
onClick = actions.onClickInstantMix,
|
||||||
modifier = Modifier,
|
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item("favorite") {
|
item("favorite") {
|
||||||
|
|
@ -68,7 +72,7 @@ fun MusicExpandableButtons(
|
||||||
iconStringRes = R.string.fa_heart,
|
iconStringRes = R.string.fa_heart,
|
||||||
onClick = actions.onClickFavorite,
|
onClick = actions.onClickFavorite,
|
||||||
iconColor = if (favorite) Color.Red else Color.Unspecified,
|
iconColor = if (favorite) Color.Red else Color.Unspecified,
|
||||||
modifier = Modifier,
|
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item("more") {
|
item("more") {
|
||||||
|
|
@ -77,7 +81,7 @@ fun MusicExpandableButtons(
|
||||||
resume = Duration.ZERO,
|
resume = Duration.ZERO,
|
||||||
icon = Icons.Default.MoreVert,
|
icon = Icons.Default.MoreVert,
|
||||||
onClick = { actions.onClickMore.invoke() },
|
onClick = { actions.onClickMore.invoke() },
|
||||||
modifier = Modifier,
|
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue