[fix] Crash when page initialized before view model

This commit is contained in:
acite
2025-09-20 14:16:46 +08:00
parent 92f0e8543e
commit a298cb75e2
3 changed files with 153 additions and 137 deletions

View File

@@ -187,7 +187,7 @@ fun ComicScreen(
HorizontalDivider(thickness = 1.5.dp) HorizontalDivider(thickness = 1.5.dp)
LazyVerticalStaggeredGrid( LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(128.dp), columns = StaggeredGridCells.Adaptive(136.dp),
contentPadding = PaddingValues(8.dp), contentPadding = PaddingValues(8.dp),
verticalItemSpacing = 8.dp, verticalItemSpacing = 8.dp,
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),

View File

@@ -118,156 +118,168 @@ fun VideoScreen(
val tabIndex by videoScreenViewModel.tabIndex val tabIndex by videoScreenViewModel.tabIndex
var menuVisibility by videoScreenViewModel.menuVisibility var menuVisibility by videoScreenViewModel.menuVisibility
var searchFilter by videoScreenViewModel.searchFilter var searchFilter by videoScreenViewModel.searchFilter
var doneInit by videoScreenViewModel.doneInit
CardPage(title = "Videos") { if (doneInit)
Box(Modifier.fillMaxSize()) CardPage(title = "Videos") {
{ Box(Modifier.fillMaxSize())
Column( {
modifier = Modifier.fillMaxSize() Column(
) { modifier = Modifier.fillMaxSize()
// TopRow(videoScreenViewModel); ) {
Row(Modifier.padding(bottom = 4.dp)) // TopRow(videoScreenViewModel);
{ Row(Modifier.padding(bottom = 4.dp))
Card(
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(horizontal = 2.dp)
.size(36.dp),
onClick = {
menuVisibility = !menuVisibility
})
{ {
Box(Modifier.fillMaxSize()) Card(
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(horizontal = 2.dp)
.size(36.dp),
onClick = {
menuVisibility = !menuVisibility
})
{ {
Box(Modifier.fillMaxSize())
{
Icon(
modifier = Modifier
.size(30.dp)
.align(Alignment.Center),
imageVector = Icons.Default.Menu,
contentDescription = "Catalogue"
)
}
}
Card(
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(horizontal = 2.dp)
.height(36.dp),
onClick = {
menuVisibility = !menuVisibility
})
{
Box(Modifier.fillMaxHeight())
{
Text(
text = videoScreenViewModel.videoLibrary.classes.getOrNull(
tabIndex
)
?: "",
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Bold,
modifier = Modifier
.align(Alignment.CenterStart)
.padding(horizontal = 8.dp),
maxLines = 1
)
}
}
Row(
modifier = Modifier
.height(36.dp)
.widthIn(max = 240.dp)
.background(colorScheme.primary, RoundedCornerShape(8.dp))
.padding(horizontal = 6.dp)
) {
Icon( Icon(
modifier = Modifier modifier = Modifier
.size(30.dp) .size(30.dp)
.align(Alignment.Center), .align(Alignment.CenterVertically),
imageVector = Icons.Default.Menu, imageVector = Icons.Default.Search,
contentDescription = "Catalogue" contentDescription = "Catalogue"
) )
} Spacer(Modifier.width(4.dp))
} BasicTextField(
value = searchFilter,
Card( onValueChange = { searchFilter = it },
shape = RoundedCornerShape(8.dp), textStyle = LocalTextStyle.current.copy(
colors = CardDefaults.cardColors(containerColor = colorScheme.primary), fontSize = 18.sp,
modifier = Modifier color = Color.White,
.align(Alignment.CenterVertically) textAlign = TextAlign.Start
.padding(horizontal = 2.dp)
.height(36.dp),
onClick = {
menuVisibility = !menuVisibility
})
{
Box(Modifier.fillMaxHeight())
{
Text(
text = videoScreenViewModel.videoLibrary.classes.getOrNull(tabIndex)
?: "",
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Bold,
modifier = Modifier
.align(Alignment.CenterStart)
.padding(horizontal = 8.dp),
maxLines = 1
)
}
}
Row(
modifier = Modifier
.height(36.dp).widthIn(max = 240.dp)
.background(colorScheme.primary, RoundedCornerShape(8.dp))
.padding(horizontal = 6.dp)
) {
Icon(
modifier = Modifier
.size(30.dp).align(Alignment.CenterVertically),
imageVector = Icons.Default.Search,
contentDescription = "Catalogue"
)
Spacer(Modifier.width(4.dp))
BasicTextField(
value = searchFilter,
onValueChange = { searchFilter = it },
textStyle = LocalTextStyle.current.copy(
fontSize = 18.sp,
color = Color.White,
textAlign = TextAlign.Start
),
singleLine = true,
modifier = Modifier.align(Alignment.CenterVertically)
)
}
}
HorizontalDivider(Modifier.padding(bottom = 8.dp), 1.5.dp, DividerDefaults.color)
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(160.dp),
contentPadding = PaddingValues(8.dp),
verticalItemSpacing = 8.dp,
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
state = state,
modifier = Modifier.fillMaxSize()
) {
items(
items = videoScreenViewModel.videoLibrary.classesMap.getOrDefault(
videoScreenViewModel.videoLibrary.classes.getOrNull(
tabIndex
), listOf()
).filter { it.video.name.contains(searchFilter) },
key = { "${it.klass}/${it.id}" }
) { video ->
androidx.compose.foundation.layout.Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
) {
VideoCard(video, navController, videoScreenViewModel)
}
}
}
}
AnimatedVisibility(
visible = menuVisibility,
enter = slideInHorizontally(initialOffsetX = { full -> full }),
exit = slideOutHorizontally(targetOffsetX = { full -> full }),
modifier = Modifier.align(Alignment.CenterEnd)
) {
Card(
Modifier
.fillMaxHeight()
.width(200.dp)
.align(Alignment.CenterEnd),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.surface)
)
{
LazyColumn {
items(videoScreenViewModel.videoLibrary.classes) { item ->
CatalogueItemRow(
item = Pair(
videoScreenViewModel.videoLibrary.classes.indexOf(item),
item
), ),
onItemClick = { singleLine = true,
menuVisibility = false modifier = Modifier.align(Alignment.CenterVertically)
videoScreenViewModel.setTabIndex(
videoScreenViewModel.videoLibrary.classes.indexOf(
item
)
)
}
) )
} }
} }
HorizontalDivider(
Modifier.padding(bottom = 8.dp),
1.5.dp,
DividerDefaults.color
)
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(160.dp),
contentPadding = PaddingValues(8.dp),
verticalItemSpacing = 8.dp,
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(
8.dp
),
state = state,
modifier = Modifier.fillMaxSize()
) {
items(
items = videoScreenViewModel.videoLibrary.classesMap.getOrDefault(
videoScreenViewModel.videoLibrary.classes.getOrNull(
tabIndex
), listOf()
).filter { it.video.name.contains(searchFilter) },
key = { "${it.klass}/${it.id}" }
) { video ->
androidx.compose.foundation.layout.Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
) {
VideoCard(video, navController, videoScreenViewModel)
}
}
}
}
AnimatedVisibility(
visible = menuVisibility,
enter = slideInHorizontally(initialOffsetX = { full -> full }),
exit = slideOutHorizontally(targetOffsetX = { full -> full }),
modifier = Modifier.align(Alignment.CenterEnd)
) {
Card(
Modifier
.fillMaxHeight()
.width(200.dp)
.align(Alignment.CenterEnd),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.surface)
)
{
LazyColumn {
items(videoScreenViewModel.videoLibrary.classes) { item ->
CatalogueItemRow(
item = Pair(
videoScreenViewModel.videoLibrary.classes.indexOf(item),
item
),
onItemClick = {
menuVisibility = false
videoScreenViewModel.setTabIndex(
videoScreenViewModel.videoLibrary.classes.indexOf(
item
)
)
}
)
}
}
}
} }
} }
} }
}
} }
@Composable @Composable

View File

@@ -47,6 +47,7 @@ class VideoScreenViewModel @Inject constructor(
var imageLoader: ImageLoader? = null; var imageLoader: ImageLoader? = null;
var menuVisibility = mutableStateOf(false) var menuVisibility = mutableStateOf(false)
var searchFilter = mutableStateOf("") var searchFilter = mutableStateOf("")
var doneInit = mutableStateOf(false)
suspend fun init() { suspend fun init() {
fetchManager.configured.filter { it }.first() fetchManager.configured.filter { it }.first()
@@ -69,7 +70,8 @@ class VideoScreenViewModel @Inject constructor(
val r = vl.sortedWith(compareBy(naturalOrder()) { it.video.name }) val r = vl.sortedWith(compareBy(naturalOrder()) { it.video.name })
videoLibrary.classesMap[videoLibrary.classes[0]]?.addAll(r) videoLibrary.classesMap[videoLibrary.classes[0]]?.addAll(r)
} }
} else { }
else {
videoLibrary.classes.add("Offline") videoLibrary.classes.add("Offline")
videoLibrary.updatingMap[0] = true videoLibrary.updatingMap[0] = true
videoLibrary.classesMap["Offline"] = mutableStateListOf<Video>() videoLibrary.classesMap["Offline"] = mutableStateListOf<Video>()
@@ -85,6 +87,8 @@ class VideoScreenViewModel @Inject constructor(
videoLibrary.classesMap[videoLibrary.classes[0]]?.addAll(jsonQuery) videoLibrary.classesMap[videoLibrary.classes[0]]?.addAll(jsonQuery)
} }
doneInit.value = true
} }
fun setTabIndex(index: Int) { fun setTabIndex(index: Int) {