in shared/src/commonMain/kotlin/org/jetbrains/kotlinconf/screens/SpeakersScreen.kt [56:186]
fun SpeakersScreen(
onSpeaker: (SpeakerId) -> Unit,
viewModel: SpeakersViewModel = koinViewModel(),
) {
var searchState by rememberSaveable { mutableStateOf(MainHeaderContainerState.Title) }
var searchText by rememberSaveable { mutableStateOf("") }
val uiState = viewModel.speakers.collectAsStateWithLifecycle().value
val gridState = rememberLazyGridState()
LaunchedEffect(searchState, searchText) {
if (searchState == MainHeaderContainerState.Search) {
if (gridState.firstVisibleItemIndex > 1) {
gridState.scrollToItem(0)
} else {
gridState.animateScrollToItem(0)
}
}
viewModel.setSearchText(searchText)
}
Column(Modifier.fillMaxSize().background(color = KotlinConfTheme.colors.mainBackground)) {
MainHeaderContainer(
state = searchState,
titleContent = {
MainHeaderTitleBar(
title = stringResource(Res.string.speakers_title),
endContent = {
TopMenuButton(
icon = UiRes.drawable.search_24,
onClick = { searchState = MainHeaderContainerState.Search },
contentDescription = stringResource(UiRes.string.main_header_search_hint)
)
}
)
},
searchContent = {
NavigationBackHandler(
state = rememberNavigationEventState(NavigationEventInfo.None),
isBackEnabled = true,
onBackCompleted = {
searchState = MainHeaderContainerState.Title
searchText = ""
},
)
MainHeaderSearchBar(
searchValue = searchText,
onSearchValueChange = { searchText = it },
onClose = {
searchState = MainHeaderContainerState.Title
searchText = ""
},
onClear = { searchText = "" },
)
}
)
Divider(1.dp, KotlinConfTheme.colors.strokePale)
AnimatedContent(
uiState,
modifier = Modifier.fillMaxSize().clipToBounds(),
contentKey = {
when (uiState) {
is SpeakersUiState.Content -> 1
SpeakersUiState.Error, SpeakersUiState.Loading -> 2
}
},
transitionSpec = { FadingAnimationSpec }
) { targetState ->
when (targetState) {
is SpeakersUiState.Content -> {
ScrollToTopHandler(gridState)
HideKeyboardOnDragHandler(gridState)
val speakers = targetState.speakers
LazyVerticalGrid(
state = gridState,
columns = GridCells.Adaptive(300.dp),
modifier = Modifier.fillMaxSize(),
) {
if (searchState == MainHeaderContainerState.Search) {
item(span = { GridItemSpan(maxLineSpan) }, key = "number-of-speakers") {
Text(
text = pluralStringResource(
Res.plurals.speakers_number_of_results,
speakers.size,
speakers.size
),
color = KotlinConfTheme.colors.secondaryText,
style = KotlinConfTheme.typography.text2,
modifier = Modifier
.animateItem()
.padding(horizontal = 12.dp)
.padding(top = 12.dp, bottom = 4.dp)
.semantics { liveRegion = LiveRegionMode.Polite }
)
}
}
items(speakers, key = { it.speaker.id.id }) { speakerWithHighlights ->
val speaker = speakerWithHighlights.speaker
SpeakerCard(
name = speaker.name,
nameHighlights = speakerWithHighlights.nameHighlights,
title = speaker.position,
titleHighlights = speakerWithHighlights.titleHighlights,
photoUrl = speaker.photoUrl,
modifier = Modifier
.animateItem()
.fillMaxWidth()
.padding(12.dp),
onClick = { onSpeaker(speaker.id) },
)
}
}
}
SpeakersUiState.Error, SpeakersUiState.Loading -> {
NormalErrorWithLoading(
message = stringResource(Res.string.speakers_error_no_data),
isLoading = uiState is SpeakersUiState.Loading,
modifier = Modifier.fillMaxSize(),
onRetry = { viewModel.refresh() },
)
}
}
}
}
}