Revert "Use typed HomeRow in HomeRowLoadingState.Success"

This reverts commit 2c6e7a57f0.
This commit is contained in:
Damontecres 2026-01-23 18:18:59 -05:00
parent 2c6e7a57f0
commit 45e023d1b2
No known key found for this signature in database
3 changed files with 79 additions and 176 deletions

View file

@ -34,7 +34,6 @@ import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.main.HomePageContent import com.github.damontecres.wholphin.ui.main.HomePageContent
import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.util.ApiRequestPager import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.HomeRow
import com.github.damontecres.wholphin.util.HomeRowLoadingState import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -62,16 +61,7 @@ abstract class RecommendedViewModel(
viewModelScope.launchIO { viewModelScope.launchIO {
val row = rows.value.getOrNull(position.row) val row = rows.value.getOrNull(position.row)
if (row is HomeRowLoadingState.Success) { if (row is HomeRowLoadingState.Success) {
when (row.data) { (row.items as? ApiRequestPager<*>)?.refreshItem(position.column, itemId)
is HomeRow.BaseItemHomeRow -> {
(row.data.items as? ApiRequestPager<*>)?.refreshItem(
position.column,
itemId,
)
}
is HomeRow.GenreHowRow -> {}
}
} }
} }
} }

View file

@ -54,7 +54,6 @@ import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup import com.github.damontecres.wholphin.ui.components.DialogPopup
import com.github.damontecres.wholphin.ui.components.EpisodeName import com.github.damontecres.wholphin.ui.components.EpisodeName
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.Genre
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.QuickDetails import com.github.damontecres.wholphin.ui.components.QuickDetails
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
@ -70,7 +69,6 @@ import com.github.damontecres.wholphin.ui.playback.playable
import com.github.damontecres.wholphin.ui.playback.scale import com.github.damontecres.wholphin.ui.playback.scale
import com.github.damontecres.wholphin.ui.rememberPosition import com.github.damontecres.wholphin.ui.rememberPosition
import com.github.damontecres.wholphin.ui.tryRequestFocus import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.HomeRow
import com.github.damontecres.wholphin.util.HomeRowLoadingState import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -184,13 +182,6 @@ fun HomePage(
} }
} }
fun HomeRowLoadingState.getItem(index: Int) =
when (val data = (this as? HomeRowLoadingState.Success)?.data) {
is HomeRow.BaseItemHomeRow -> data.items.getOrNull(index)
is HomeRow.GenreHowRow -> data.items.getOrNull(index)
null -> null
}
@Composable @Composable
fun HomePageContent( fun HomePageContent(
homeRows: List<HomeRowLoadingState>, homeRows: List<HomeRowLoadingState>,
@ -207,7 +198,7 @@ fun HomePageContent(
var position by rememberPosition() var position by rememberPosition()
val focusedItem = val focusedItem =
position.let { position.let {
homeRows.getOrNull(it.row)?.getItem(it.column) (homeRows.getOrNull(it.row) as? HomeRowLoadingState.Success)?.items?.getOrNull(it.column)
} }
val rowFocusRequesters = remember(homeRows) { List(homeRows.size) { FocusRequester() } } val rowFocusRequesters = remember(homeRows) { List(homeRows.size) { FocusRequester() } }
@ -220,7 +211,7 @@ fun HomePageContent(
} else { } else {
// Waiting for the first home row to load, then focus on it // Waiting for the first home row to load, then focus on it
homeRows homeRows
.indexOfFirst { it is HomeRowLoadingState.Success && it.data.isNotEmpty() } .indexOfFirst { it is HomeRowLoadingState.Success && it.items.isNotEmpty() }
.takeIf { it >= 0 } .takeIf { it >= 0 }
?.let { ?.let {
rowFocusRequesters[it].tryRequestFocus() rowFocusRequesters[it].tryRequestFocus()
@ -237,29 +228,17 @@ fun HomePageContent(
} }
} }
LaunchedEffect(onUpdateBackdrop, focusedItem) { LaunchedEffect(onUpdateBackdrop, focusedItem) {
(focusedItem as? BaseItem)?.let { onUpdateBackdrop.invoke(it) } focusedItem?.let { onUpdateBackdrop.invoke(it) }
} }
Box(modifier = modifier) { Box(modifier = modifier) {
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
val headerModifier = HomePageHeader(
Modifier item = focusedItem,
.padding(top = 48.dp, bottom = 32.dp, start = 32.dp) modifier =
.fillMaxHeight(.33f) Modifier
when (focusedItem) { .padding(top = 48.dp, bottom = 32.dp, start = 32.dp)
is BaseItem -> { .fillMaxHeight(.33f),
HomePageHeader( )
item = focusedItem,
modifier = headerModifier,
)
}
is Genre -> {
Text(
text = focusedItem.name,
modifier = headerModifier,
)
}
}
LazyColumn( LazyColumn(
state = listState, state = listState,
verticalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp),
@ -328,55 +307,73 @@ fun HomePageContent(
} }
is HomeRowLoadingState.Success -> { is HomeRowLoadingState.Success -> {
if (row.data.isNotEmpty()) { if (row.items.isNotEmpty()) {
when (row.data) { val viewOptions = row.viewOptions
is HomeRow.BaseItemHomeRow -> { ItemRow(
BaseItemRow( title = row.title,
row = row, items = row.items,
rowData = row.data, onClickItem = { index, item ->
onClickItem = { index, item -> onClickItem.invoke(RowColumn(rowIndex, index), item)
onClickItem.invoke(RowColumn(rowIndex, index), item) },
}, onLongClickItem = { index, item ->
onLongClickItem = { index, item -> onLongClickItem.invoke(RowColumn(rowIndex, index), item)
onLongClickItem.invoke( },
RowColumn(rowIndex, index), modifier =
item, Modifier
) .fillMaxWidth()
}, .focusGroup()
onCardFocus = { index -> .focusRequester(rowFocusRequesters[rowIndex])
position = RowColumn(rowIndex, index) .animateItem(),
if (onFocusPosition != null) { horizontalPadding = viewOptions.spacing.dp,
val nonEmptyRowBefore = cardContent = { index, item, cardModifier, onClick, onLongClick ->
homeRows BannerCard(
.subList(0, rowIndex) name = item?.data?.seriesName ?: item?.name,
.count { item = item,
it is HomeRowLoadingState.Success && it.data.isEmpty() aspectRatio = viewOptions.aspectRatio.ratio,
} imageType = viewOptions.imageType.imageType,
onFocusPosition.invoke( imageContentScale = viewOptions.contentScale.scale,
RowColumn( cornerText = item?.ui?.episdodeUnplayedCornerText,
rowIndex - nonEmptyRowBefore, played = item?.data?.userData?.played ?: false,
index, favorite = item?.favorite ?: false,
), playPercent =
) item?.data?.userData?.playedPercentage
} ?: 0.0,
}, onClick = onClick,
onClickPlay = { index -> onLongClick = onLongClick,
row.data.items.get(index)?.let { modifier =
onClickPlay.invoke( cardModifier
RowColumn(rowIndex, index), .onFocusChanged {
it, if (it.isFocused) {
) position = RowColumn(rowIndex, index)
} // item?.let(onUpdateBackdrop)
}, }
modifier = Modifier, if (it.isFocused && onFocusPosition != null) {
focusRequester = rowFocusRequesters[rowIndex], val nonEmptyRowBefore =
homeRows
.subList(0, rowIndex)
.count {
it is HomeRowLoadingState.Success && it.items.isEmpty()
}
onFocusPosition.invoke(
RowColumn(
rowIndex - nonEmptyRowBefore,
index,
),
)
}
}.onKeyEvent {
if (isPlayKeyUp(it) && item?.type?.playable == true) {
Timber.v("Clicked play on ${item.id}")
onClickPlay.invoke(position, item)
return@onKeyEvent true
}
return@onKeyEvent false
},
interactionSource = null,
cardHeight = viewOptions.heightDp.dp,
) )
} },
)
is HomeRow.GenreHowRow -> {
TODO()
}
}
} }
} }
} }
@ -478,62 +475,3 @@ fun HomePageHeader(
} }
} }
} }
@Composable
fun BaseItemRow(
row: HomeRowLoadingState.Success,
rowData: HomeRow.BaseItemHomeRow,
onClickItem: (Int, BaseItem) -> Unit,
onLongClickItem: (Int, BaseItem) -> Unit,
onClickPlay: (Int) -> Unit,
onCardFocus: (Int) -> Unit,
modifier: Modifier = Modifier,
focusRequester: FocusRequester = remember { FocusRequester() },
) {
val viewOptions = row.viewOptions
ItemRow(
title = row.title,
items = rowData.items,
onClickItem = onClickItem,
onLongClickItem = onLongClickItem,
modifier =
modifier
.fillMaxWidth()
.focusGroup()
.focusRequester(focusRequester),
horizontalPadding = viewOptions.spacing.dp,
cardContent = { index, item, cardModifier, onClick, onLongClick ->
BannerCard(
name = item?.data?.seriesName ?: item?.name,
item = item,
aspectRatio = viewOptions.aspectRatio.ratio,
imageType = viewOptions.imageType.imageType,
imageContentScale = viewOptions.contentScale.scale,
cornerText = item?.ui?.episdodeUnplayedCornerText,
played = item?.data?.userData?.played ?: false,
favorite = item?.favorite ?: false,
playPercent =
item?.data?.userData?.playedPercentage
?: 0.0,
onClick = onClick,
onLongClick = onLongClick,
modifier =
cardModifier
.onFocusChanged {
if (it.isFocused) {
onCardFocus.invoke(index)
}
}.onKeyEvent {
if (isPlayKeyUp(it) && item?.type?.playable == true) {
Timber.v("Clicked play on ${item.id}")
onClickPlay.invoke(index)
return@onKeyEvent true
}
return@onKeyEvent false
},
interactionSource = null,
cardHeight = viewOptions.heightDp.dp,
)
},
)
}

View file

@ -2,7 +2,6 @@ package com.github.damontecres.wholphin.util
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.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.ui.components.Genre
/** /**
* Generic state for loading something from the API * Generic state for loading something from the API
@ -60,15 +59,9 @@ sealed interface HomeRowLoadingState {
data class Success( data class Success(
override val title: String, override val title: String,
val items: List<BaseItem?>,
val viewOptions: HomeRowViewOptions = HomeRowViewOptions(), val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
val data: HomeRow, ) : HomeRowLoadingState
) : HomeRowLoadingState {
constructor(
title: String,
items: List<BaseItem?>,
viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : this(title, viewOptions, HomeRow.BaseItemHomeRow(items))
}
data class Error( data class Error(
override val title: String, override val title: String,
@ -80,24 +73,6 @@ sealed interface HomeRowLoadingState {
} }
} }
sealed interface HomeRow {
fun isEmpty(): Boolean
fun isNotEmpty(): Boolean = !isEmpty()
data class BaseItemHomeRow(
val items: List<BaseItem?>,
) : HomeRow {
override fun isEmpty(): Boolean = items.isEmpty()
}
data class GenreHowRow(
val items: List<Genre>,
) : HomeRow {
override fun isEmpty(): Boolean = items.isEmpty()
}
}
/** /**
* Generic state for loading something from the API * Generic state for loading something from the API
* *