forked from agzam/vyatsu-schedule
153 lines
6.5 KiB
Kotlin
153 lines
6.5 KiB
Kotlin
package agzam.vyatsu.ui.groups
|
|||
|
|
|
||
|
|
import agzam.vyatsu.domain.model.Group
|
||
|
|
import androidx.compose.foundation.clickable
|
||
|
|
import androidx.compose.foundation.layout.Arrangement
|
||
|
|
import androidx.compose.foundation.layout.Box
|
||
|
|
import androidx.compose.foundation.layout.Column
|
||
|
|
import androidx.compose.foundation.layout.Row
|
||
|
|
import androidx.compose.foundation.layout.Spacer
|
||
|
|
import androidx.compose.foundation.layout.WindowInsets
|
||
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
||
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||
|
|
import androidx.compose.foundation.layout.height
|
||
|
|
import androidx.compose.foundation.layout.padding
|
||
|
|
import androidx.compose.foundation.layout.systemBars
|
||
|
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
||
|
|
import androidx.compose.foundation.lazy.items
|
||
|
|
import androidx.compose.material.icons.Icons
|
||
|
|
import androidx.compose.material.icons.filled.Clear
|
||
|
|
import androidx.compose.material.icons.filled.Refresh
|
||
|
|
import androidx.compose.material.icons.filled.Search
|
||
|
|
import androidx.compose.material3.CircularProgressIndicator
|
||
|
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||
|
|
import androidx.compose.material3.HorizontalDivider
|
||
|
|
import androidx.compose.material3.Icon
|
||
|
|
import androidx.compose.material3.IconButton
|
||
|
|
import androidx.compose.material3.MaterialTheme
|
||
|
|
import androidx.compose.material3.Scaffold
|
||
|
|
import androidx.compose.material3.SearchBar
|
||
|
|
import androidx.compose.material3.SearchBarDefaults
|
||
|
|
import androidx.compose.material3.Text
|
||
|
|
import androidx.compose.material3.TextButton
|
||
|
|
import androidx.compose.runtime.Composable
|
||
|
|
import androidx.compose.runtime.collectAsState
|
||
|
|
import androidx.compose.runtime.getValue
|
||
|
|
import androidx.compose.runtime.mutableStateOf
|
||
|
|
import androidx.compose.runtime.remember
|
||
|
|
import androidx.compose.runtime.setValue
|
||
|
|
import androidx.compose.ui.Alignment
|
||
|
|
import androidx.compose.ui.Modifier
|
||
|
|
import androidx.compose.ui.unit.dp
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Страница выбора группы
|
||
|
|
* @author Agzam
|
||
|
|
*/
|
||
|
|
@OptIn(ExperimentalMaterial3Api::class)
|
||
|
|
@Composable
|
||
|
|
fun GroupPickerScreen(viewModel: GroupPickerViewModel, onGroupPicked: (Group) -> Unit) {
|
||
|
|
val state by viewModel.uiState.collectAsState()
|
||
|
|
var isSearchActive by remember { mutableStateOf(false) }
|
||
|
|
|
||
|
|
Scaffold { innerPadding ->
|
||
|
|
Column(
|
||
|
|
Modifier
|
||
|
|
.fillMaxSize()
|
||
|
|
.windowInsetsPadding(WindowInsets.systemBars)
|
||
|
|
.padding(innerPadding)
|
||
|
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||
|
|
) {
|
||
|
|
if (!isSearchActive) {
|
||
|
|
Row(
|
||
|
|
Modifier
|
||
|
|
.fillMaxWidth()
|
||
|
|
.padding(bottom = 8.dp),
|
||
|
|
verticalAlignment = Alignment.CenterVertically
|
||
|
|
) {
|
||
|
|
Text(
|
||
|
|
text = "Выберите группу",
|
||
|
|
style = MaterialTheme.typography.headlineSmall,
|
||
|
|
modifier = Modifier.weight(1f)
|
||
|
|
)
|
||
|
|
IconButton(onClick = { viewModel.refresh() }) {
|
||
|
|
Icon(Icons.Default.Refresh, contentDescription = "Обновить")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (state.isLoading && state.groups.isEmpty()) {
|
||
|
|
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||
|
|
CircularProgressIndicator()
|
||
|
|
}
|
||
|
|
return@Column
|
||
|
|
}
|
||
|
|
if (state.error != null && state.groups.isEmpty()) {
|
||
|
|
Column(Modifier.fillMaxWidth()) {
|
||
|
|
Text(state.error.orEmpty(), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.error)
|
||
|
|
TextButton(onClick = { viewModel.retry() }) { Text("Повторить") }
|
||
|
|
}
|
||
|
|
return@Column
|
||
|
|
}
|
||
|
|
SearchBar(
|
||
|
|
modifier = Modifier.fillMaxWidth(),
|
||
|
|
expanded = isSearchActive,
|
||
|
|
onExpandedChange = { isSearchActive = it },
|
||
|
|
inputField = {
|
||
|
|
SearchBarDefaults.InputField(
|
||
|
|
query = state.searchQuery,
|
||
|
|
onQueryChange = { viewModel.search(it) },
|
||
|
|
onSearch = { isSearchActive = false },
|
||
|
|
expanded = isSearchActive,
|
||
|
|
onExpandedChange = { isSearchActive = it },
|
||
|
|
placeholder = { Text("Поиск группы") },
|
||
|
|
leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) },
|
||
|
|
trailingIcon = {
|
||
|
|
if (isSearchActive && state.searchQuery.isNotEmpty()) {
|
||
|
|
IconButton(onClick = { viewModel.search("") }) {
|
||
|
|
Icon(Icons.Default.Clear, contentDescription = "Очистить")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
)
|
||
|
|
}
|
||
|
|
) {
|
||
|
|
GroupList(
|
||
|
|
groups = state.filteredGroups,
|
||
|
|
onPick = { group ->
|
||
|
|
isSearchActive = false
|
||
|
|
onGroupPicked(group)
|
||
|
|
}
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!isSearchActive) {
|
||
|
|
Spacer(modifier = Modifier.height(8.dp))
|
||
|
|
GroupList(state.filteredGroups, onGroupPicked)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@Composable
|
||
|
|
private fun GroupList(groups: List<Group>, onPick: (Group) -> Unit) {
|
||
|
|
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||
|
|
items(groups) { group ->
|
||
|
|
Column(modifier = Modifier.fillMaxWidth() .clickable { onPick(group) }) {
|
||
|
|
Box(
|
||
|
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp).padding(horizontal = 16.dp),
|
||
|
|
contentAlignment = Alignment.CenterStart
|
||
|
|
) {
|
||
|
|
Text(group.name, style = MaterialTheme.typography.bodyMedium)
|
||
|
|
// XXX: стоит ли добавлять факультет или это засорит интерфейс
|
||
|
|
// Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.Bottom) {
|
||
|
|
// if (group.faculty.isNotEmpty()) Text(text = group.faculty + " · ", color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||
|
|
// }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
HorizontalDivider(thickness = 1.dp, color = MaterialTheme.colorScheme.outlineVariant)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|