ui: Fix compile errors in first build
Composable API mismatches with tv-material 1.0.1: NavigationDrawerItem takes leadingContent/content (not icon/label), Card needs no shape. Move VideoListItem to top level so its supertype reference resolves. Pass onOpenVideo by name because the trailing lambda slot on VideoListScreen goes to the non-functional viewModel parameter. Nullable search param on local channel listings; make StateFlow collection use collectAsState directly to avoid a JVM signature clash. Verified by building app-debug.apk inside the container (JDK 21 installed there for this purpose).
This commit is contained in:
parent
59029438ad
commit
7eecfd72ac
8 changed files with 60 additions and 59 deletions
|
|
@ -72,7 +72,7 @@ interface PeerTubeApi {
|
|||
|
||||
@GET("video-channels")
|
||||
suspend fun channels(
|
||||
@Query("search") search: String,
|
||||
@Query("search") search: String?,
|
||||
@Query("searchTarget") searchTarget: String = "local",
|
||||
@Query("start") start: Long,
|
||||
@Query("count") count: Int,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import net.jeena.jtubetv.data.api.PeerTubeApi
|
|||
import net.jeena.jtubetv.data.api.TokenResponse
|
||||
import net.jeena.jtubetv.data.auth.TokenStore
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Authenticator
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ sealed interface SessionState {
|
|||
|
||||
class AppViewModel(private val repository: PeerTubeRepository = AppGraph.repository) : ViewModel() {
|
||||
|
||||
val sessionState: StateFlow<SessionState> = _sessionState
|
||||
private val _sessionState = MutableStateFlow<SessionState>(SessionState.Loading)
|
||||
val sessionState: StateFlow<SessionState> = _sessionState
|
||||
|
||||
val loginError = MutableStateFlow<String?>(null)
|
||||
val loggingIn = MutableStateFlow(false)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ sealed interface ListSource {
|
|||
data class Channel(val handle: String, val displayName: String) : ListSource
|
||||
}
|
||||
|
||||
/** One list row: a plain video, or a history entry (same video, server metadata). */
|
||||
sealed interface VideoListItem {
|
||||
data class Video(val video: net.jeena.jtubetv.data.api.VideoDto) : VideoListItem
|
||||
data class HistoryEntry(val history: net.jeena.jtubetv.data.api.HistoryElement) : VideoListItem
|
||||
}
|
||||
|
||||
class VideoListViewModel(
|
||||
private val repository: PeerTubeRepository,
|
||||
val source: ListSource,
|
||||
|
|
@ -53,12 +59,6 @@ class VideoListViewModel(
|
|||
if (items.isEmpty() && loadingInitial) loadMore(force = true)
|
||||
}
|
||||
|
||||
/** History/search entries can hide the underlying video shape. */
|
||||
sealed interface VideoListItem {
|
||||
data class Video(val video: net.jeena.jtubetv.data.api.VideoDto) : VideoListItem
|
||||
data class HistoryEntry(val history: net.jeena.jtubetv.data.api.HistoryElement) : VideoListItem
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun factory(source: ListSource): ViewModelProvider.Factory =
|
||||
object : ViewModelProvider.Factory {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
|
|
@ -119,8 +120,6 @@ private fun ChannelCard(channel: VideoChannelDto, onClick: () -> Unit) {
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 6.dp),
|
||||
shape = androidx.compose.foundation.shape.RoundedCornerShape(8.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(12.dp)) {
|
||||
val avatar = channel.avatars.maxByOrNull { it.width }
|
||||
|
|
|
|||
|
|
@ -60,43 +60,9 @@ fun HomeScreen() {
|
|||
}
|
||||
|
||||
NavigationDrawer(drawerContent = {
|
||||
NavigationDrawerColumn(
|
||||
selected = destination,
|
||||
onSelect = {
|
||||
destination = it
|
||||
channelDetails = null
|
||||
},
|
||||
)
|
||||
}) {
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
when (destination) {
|
||||
Destination.LocalVideos ->
|
||||
VideoListScreen(ListSource.LocalVideos) { playingVideo = it.shortUUID }
|
||||
Destination.MyVideos ->
|
||||
VideoListScreen(ListSource.MyVideos) { playingVideo = it.shortUUID }
|
||||
Destination.Channels -> ChannelsScreen(
|
||||
onOpenChannel = { handle -> channelDetails = handle },
|
||||
)
|
||||
Destination.Search ->
|
||||
VideoListScreen(ListSource.Search) { playingVideo = it.shortUUID }
|
||||
Destination.Subscriptions ->
|
||||
VideoListScreen(ListSource.Subscriptions) { playingVideo = it.shortUUID }
|
||||
Destination.History ->
|
||||
VideoListScreen(ListSource.History) { playingVideo = it.shortUUID }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NavigationDrawerColumn(
|
||||
selected: Destination,
|
||||
onSelect: (Destination) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
androidx.compose.foundation.layout.Column(
|
||||
modifier = Modifier.width(220.dp).padding(vertical = 16.dp),
|
||||
) {
|
||||
androidx.compose.foundation.layout.Column(modifier = modifier.width(220.dp).padding(vertical = 16.dp)) {
|
||||
Text(
|
||||
text = "JTube",
|
||||
modifier = Modifier.padding(start = 28.dp, bottom = 16.dp),
|
||||
|
|
@ -104,13 +70,54 @@ private fun NavigationDrawerColumn(
|
|||
)
|
||||
Destination.entries.forEach { dest ->
|
||||
NavigationDrawerItem(
|
||||
icon = { Icon(imageVector = dest.icon(), contentDescription = null) },
|
||||
label = { Text(dest.title) },
|
||||
selected = dest == selected,
|
||||
onClick = { onSelect(dest) },
|
||||
selected = dest == destination,
|
||||
onClick = {
|
||||
destination = dest
|
||||
channelDetails = null
|
||||
},
|
||||
leadingContent = {
|
||||
Icon(imageVector = dest.icon(), contentDescription = null)
|
||||
},
|
||||
content = { Text(dest.title) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
when (destination) {
|
||||
Destination.LocalVideos ->
|
||||
VideoListScreen(
|
||||
source = ListSource.LocalVideos,
|
||||
onOpenVideo = { playingVideo = it.shortUUID },
|
||||
)
|
||||
Destination.MyVideos ->
|
||||
VideoListScreen(
|
||||
source = ListSource.MyVideos,
|
||||
onOpenVideo = { playingVideo = it.shortUUID },
|
||||
)
|
||||
Destination.Channels -> ChannelsScreen(
|
||||
onOpenChannel = { handle -> channelDetails = handle },
|
||||
)
|
||||
Destination.Search ->
|
||||
VideoListScreen(
|
||||
source = ListSource.Search,
|
||||
onOpenVideo = { playingVideo = it.shortUUID },
|
||||
)
|
||||
Destination.Subscriptions ->
|
||||
VideoListScreen(
|
||||
source = ListSource.Subscriptions,
|
||||
onOpenVideo = { playingVideo = it.shortUUID },
|
||||
)
|
||||
Destination.History ->
|
||||
VideoListScreen(
|
||||
source = ListSource.History,
|
||||
onOpenVideo = { playingVideo = it.shortUUID },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Destination.icon(): androidx.compose.ui.graphics.vector.ImageVector =
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ fun SetupScreen(
|
|||
val url = rememberSaveable { mutableStateOf("https://tube.jeena.net") }
|
||||
val username = rememberSaveable { mutableStateOf("") }
|
||||
val password = rememberSaveable { mutableStateOf("") }
|
||||
val busy = loggingIn.collectAsStateFlow()
|
||||
val message = error.collectAsStateFlow()
|
||||
val busy = loggingIn.collectAsState()
|
||||
val message = error.collectAsState()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -92,11 +92,3 @@ fun SetupScreen(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StateFlow<Boolean>.collectAsStateFlow(): State<Boolean> =
|
||||
collectAsState()
|
||||
|
||||
@Composable
|
||||
private fun StateFlow<String?>.collectAsStateFlow(): State<String?> =
|
||||
collectAsState()
|
||||
|
|
@ -27,6 +27,7 @@ import net.jeena.jtubetv.R
|
|||
import net.jeena.jtubetv.data.api.VideoDto
|
||||
import net.jeena.jtubetv.ui.list.PagedListViewModel
|
||||
import net.jeena.jtubetv.ui.list.ListSource
|
||||
import net.jeena.jtubetv.ui.list.VideoListItem
|
||||
import net.jeena.jtubetv.ui.list.VideoListViewModel
|
||||
|
||||
@Composable
|
||||
|
|
@ -82,10 +83,11 @@ fun VideoListScreen(
|
|||
}
|
||||
|
||||
LazyColumn(modifier = Modifier.fillMaxSize().padding(vertical = 8.dp)) {
|
||||
itemsIndexed(items) { index, item ->
|
||||
val video = when (item) {
|
||||
is VideoListViewModel.VideoListItem.HistoryEntry -> item.history.video
|
||||
is VideoListViewModel.VideoListItem.Video -> item.video
|
||||
itemsIndexed<VideoListItem>(items) { index, item ->
|
||||
val video: VideoDto = when (item) {
|
||||
is VideoListItem.HistoryEntry -> item.history.video
|
||||
is VideoListItem.Video -> item.video
|
||||
else -> return@itemsIndexed
|
||||
}
|
||||
VideoCard(
|
||||
video = video,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue