mirror of
https://github.com/n08i40k/polytechnic-android.git
synced 2025-12-06 17:57:46 +03:00
2.3.0
This commit is contained in:
@@ -29,6 +29,7 @@ import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||
import ru.n08i40k.polytechnic.next.ui.widgets.GroupSelector
|
||||
import ru.n08i40k.polytechnic.next.ui.widgets.RoleSelector
|
||||
import ru.n08i40k.polytechnic.next.ui.widgets.TeacherNameSelector
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@@ -105,17 +106,26 @@ internal fun RegisterForm(
|
||||
|
||||
Spacer(modifier = Modifier.size(10.dp))
|
||||
|
||||
OutlinedTextField(
|
||||
value = username,
|
||||
singleLine = true,
|
||||
onValueChange = {
|
||||
username = it
|
||||
usernameError = false
|
||||
},
|
||||
label = { Text(stringResource(R.string.username)) },
|
||||
isError = usernameError,
|
||||
readOnly = loading
|
||||
)
|
||||
if (role != UserRole.TEACHER) {
|
||||
OutlinedTextField(
|
||||
value = username,
|
||||
singleLine = true,
|
||||
onValueChange = {
|
||||
username = it
|
||||
usernameError = false
|
||||
},
|
||||
label = { Text(stringResource(R.string.username)) },
|
||||
isError = usernameError,
|
||||
readOnly = loading
|
||||
)
|
||||
} else {
|
||||
TeacherNameSelector(
|
||||
value = username,
|
||||
isError = usernameError,
|
||||
readOnly = loading,
|
||||
onValueChange = { username = it ?: "" }
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = password,
|
||||
@@ -135,7 +145,8 @@ internal fun RegisterForm(
|
||||
GroupSelector(
|
||||
value = group,
|
||||
isError = groupError,
|
||||
readOnly = loading
|
||||
readOnly = loading,
|
||||
teacher = role == UserRole.TEACHER
|
||||
) {
|
||||
groupError = false
|
||||
group = it
|
||||
|
||||
@@ -8,19 +8,31 @@ import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||
|
||||
data class BottomNavItem(
|
||||
@StringRes val label: Int,
|
||||
val icon: ImageVector,
|
||||
val route: String,
|
||||
val isAdmin: Boolean = false
|
||||
val requiredRole: UserRole? = null
|
||||
)
|
||||
|
||||
object Constants {
|
||||
val bottomNavItem = listOf(
|
||||
BottomNavItem(R.string.profile, Icons.Filled.AccountCircle, "profile"),
|
||||
BottomNavItem(R.string.replacer, Icons.Filled.Create, "replacer", true),
|
||||
BottomNavItem(R.string.replacer, Icons.Filled.Create, "replacer", UserRole.ADMIN),
|
||||
BottomNavItem(
|
||||
R.string.teacher_schedule,
|
||||
Icons.Filled.Person,
|
||||
"teacher-main-schedule",
|
||||
UserRole.TEACHER
|
||||
),
|
||||
BottomNavItem(R.string.schedule, Icons.Filled.DateRange, "schedule"),
|
||||
BottomNavItem(R.string.teachers, Icons.Filled.Person, "teacher-schedule")
|
||||
BottomNavItem(
|
||||
R.string.teachers,
|
||||
Icons.Filled.Person,
|
||||
"teacher-user-schedule",
|
||||
UserRole.STUDENT
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -61,6 +61,7 @@ import kotlinx.coroutines.runBlocking
|
||||
import ru.n08i40k.polytechnic.next.MainViewModel
|
||||
import ru.n08i40k.polytechnic.next.PolytechnicApplication
|
||||
import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.model.Profile
|
||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||
import ru.n08i40k.polytechnic.next.settings.settingsDataStore
|
||||
import ru.n08i40k.polytechnic.next.ui.icons.AppIcons
|
||||
@@ -70,7 +71,8 @@ import ru.n08i40k.polytechnic.next.ui.icons.appicons.filled.Telegram
|
||||
import ru.n08i40k.polytechnic.next.ui.main.profile.ProfileScreen
|
||||
import ru.n08i40k.polytechnic.next.ui.main.replacer.ReplacerScreen
|
||||
import ru.n08i40k.polytechnic.next.ui.main.schedule.group.GroupScheduleScreen
|
||||
import ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.TeacherScheduleScreen
|
||||
import ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.main.TeacherMainScheduleScreen
|
||||
import ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.user.TeacherUserScheduleScreen
|
||||
import ru.n08i40k.polytechnic.next.ui.model.GroupScheduleViewModel
|
||||
import ru.n08i40k.polytechnic.next.ui.model.ProfileUiState
|
||||
import ru.n08i40k.polytechnic.next.ui.model.ProfileViewModel
|
||||
@@ -84,15 +86,27 @@ import ru.n08i40k.polytechnic.next.ui.model.profileViewModel
|
||||
private fun NavHostContainer(
|
||||
navController: NavHostController,
|
||||
padding: PaddingValues,
|
||||
profileViewModel: ProfileViewModel,
|
||||
groupScheduleViewModel: GroupScheduleViewModel,
|
||||
teacherScheduleViewModel: TeacherScheduleViewModel,
|
||||
scheduleReplacerViewModel: ScheduleReplacerViewModel?
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val profileUiState by profileViewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
val profile: Profile? = when (profileUiState) {
|
||||
is ProfileUiState.NoProfile -> null
|
||||
is ProfileUiState.HasProfile ->
|
||||
(profileUiState as ProfileUiState.HasProfile).profile
|
||||
}
|
||||
|
||||
if (profile == null)
|
||||
return
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = "schedule",
|
||||
startDestination = if (profile.role == UserRole.TEACHER) "teacher-main-schedule" else "schedule",
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
enterTransition = {
|
||||
slideIn(
|
||||
@@ -126,8 +140,16 @@ private fun NavHostContainer(
|
||||
GroupScheduleScreen(groupScheduleViewModel) { groupScheduleViewModel.refresh() }
|
||||
}
|
||||
|
||||
composable("teacher-schedule") {
|
||||
TeacherScheduleScreen(teacherScheduleViewModel) {
|
||||
composable("teacher-user-schedule") {
|
||||
TeacherUserScheduleScreen(teacherScheduleViewModel) {
|
||||
if (it.isNotEmpty()) teacherScheduleViewModel.fetch(
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composable("teacher-main-schedule") {
|
||||
TeacherMainScheduleScreen(teacherScheduleViewModel) {
|
||||
if (it.isNotEmpty()) teacherScheduleViewModel.fetch(
|
||||
it
|
||||
)
|
||||
@@ -231,14 +253,14 @@ private fun TopNavBar(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomNavBar(navController: NavHostController, isAdmin: Boolean) {
|
||||
private fun BottomNavBar(navController: NavHostController, userRole: UserRole) {
|
||||
NavigationBar {
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
|
||||
val currentRoute = navBackStackEntry?.destination?.route
|
||||
|
||||
Constants.bottomNavItem.forEach {
|
||||
if (it.isAdmin && !isAdmin)
|
||||
if (it.requiredRole != null && it.requiredRole != userRole && userRole != UserRole.ADMIN)
|
||||
return@forEach
|
||||
|
||||
NavigationBarItem(
|
||||
@@ -303,17 +325,17 @@ fun MainScreen(
|
||||
// schedule replacer view model
|
||||
val profileUiState by profileViewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
val isAdmin = when (profileUiState) {
|
||||
is ProfileUiState.NoProfile -> false
|
||||
is ProfileUiState.HasProfile -> {
|
||||
val profile = (profileUiState as ProfileUiState.HasProfile).profile
|
||||
|
||||
profile.role == UserRole.ADMIN
|
||||
}
|
||||
val profile: Profile? = when (profileUiState) {
|
||||
is ProfileUiState.NoProfile -> null
|
||||
is ProfileUiState.HasProfile ->
|
||||
(profileUiState as ProfileUiState.HasProfile).profile
|
||||
}
|
||||
|
||||
if (profile == null)
|
||||
return
|
||||
|
||||
val scheduleReplacerViewModel: ScheduleReplacerViewModel? =
|
||||
if (isAdmin) hiltViewModel(LocalContext.current as ComponentActivity)
|
||||
if (profile.role == UserRole.ADMIN) hiltViewModel(LocalContext.current as ComponentActivity)
|
||||
else null
|
||||
|
||||
// nav controller
|
||||
@@ -321,11 +343,12 @@ fun MainScreen(
|
||||
val navController = rememberNavController()
|
||||
Scaffold(
|
||||
topBar = { TopNavBar(remoteConfigViewModel) },
|
||||
bottomBar = { BottomNavBar(navController, isAdmin) }
|
||||
bottomBar = { BottomNavBar(navController, profile.role) }
|
||||
) { paddingValues ->
|
||||
NavHostContainer(
|
||||
navController,
|
||||
paddingValues,
|
||||
profileViewModel,
|
||||
groupScheduleViewModel,
|
||||
teacherScheduleViewModel,
|
||||
scheduleReplacerViewModel
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.android.volley.ClientError
|
||||
import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.data.users.impl.FakeProfileRepository
|
||||
import ru.n08i40k.polytechnic.next.model.Profile
|
||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||
import ru.n08i40k.polytechnic.next.network.request.profile.ProfileChangeGroup
|
||||
import ru.n08i40k.polytechnic.next.ui.widgets.GroupSelector
|
||||
|
||||
@@ -65,10 +66,10 @@ internal fun ChangeGroupDialog(
|
||||
|
||||
GroupSelector(
|
||||
value = group,
|
||||
onValueChange = { group = it },
|
||||
isError = groupError,
|
||||
readOnly = processing
|
||||
)
|
||||
readOnly = processing,
|
||||
teacher = profile.role == UserRole.TEACHER
|
||||
) { group = it }
|
||||
|
||||
val focusManager = LocalFocusManager.current
|
||||
Button(
|
||||
|
||||
@@ -61,7 +61,9 @@ fun DayPager(groupOrTeacher: GroupOrTeacher = FakeScheduleRepository.exampleGrou
|
||||
) { page ->
|
||||
DayCard(
|
||||
modifier = Modifier.graphicsLayer {
|
||||
val offset = pagerState.getOffsetDistanceInPages(page).absoluteValue
|
||||
val offset = pagerState.getOffsetDistanceInPages(
|
||||
page.coerceIn(0, pagerState.pageCount - 1)
|
||||
).absoluteValue
|
||||
|
||||
lerp(
|
||||
start = 1f, stop = 0.95f, fraction = 1f - offset.coerceIn(0f, 1f)
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.main
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import kotlinx.coroutines.delay
|
||||
import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.data.MockAppContainer
|
||||
import ru.n08i40k.polytechnic.next.ui.main.schedule.DayPager
|
||||
import ru.n08i40k.polytechnic.next.ui.model.ProfileUiState
|
||||
import ru.n08i40k.polytechnic.next.ui.model.TeacherScheduleUiState
|
||||
import ru.n08i40k.polytechnic.next.ui.model.TeacherScheduleViewModel
|
||||
import ru.n08i40k.polytechnic.next.ui.model.profileViewModel
|
||||
import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent
|
||||
|
||||
@Composable
|
||||
private fun rememberUpdatedLifecycleOwner(): LifecycleOwner {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
return remember { lifecycleOwner }
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
fun TeacherMainScheduleScreen(
|
||||
teacherScheduleViewModel: TeacherScheduleViewModel = TeacherScheduleViewModel(
|
||||
MockAppContainer(
|
||||
LocalContext.current
|
||||
)
|
||||
),
|
||||
fetch: (String) -> Unit = {}
|
||||
) {
|
||||
val profileViewModel = LocalContext.current.profileViewModel!!
|
||||
val profileUiState by profileViewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
if (profileUiState is ProfileUiState.NoProfile)
|
||||
return
|
||||
|
||||
val profile = (profileUiState as ProfileUiState.HasProfile).profile
|
||||
|
||||
var teacherName = profile.username
|
||||
|
||||
val uiState by teacherScheduleViewModel.uiState.collectAsStateWithLifecycle()
|
||||
LaunchedEffect(uiState) {
|
||||
delay(120_000)
|
||||
fetch(teacherName)
|
||||
}
|
||||
|
||||
val lifecycleOwner = rememberUpdatedLifecycleOwner()
|
||||
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_RESUME -> {
|
||||
fetch(teacherName)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
|
||||
onDispose {
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
LoadingContent(
|
||||
empty = when (uiState) {
|
||||
is TeacherScheduleUiState.NoData -> uiState.isLoading
|
||||
is TeacherScheduleUiState.HasData -> false
|
||||
},
|
||||
loading = uiState.isLoading,
|
||||
) {
|
||||
when (uiState) {
|
||||
is TeacherScheduleUiState.HasData -> {
|
||||
Column {
|
||||
val hasData = uiState as TeacherScheduleUiState.HasData
|
||||
|
||||
DayPager(hasData.teacher)
|
||||
}
|
||||
}
|
||||
|
||||
is TeacherScheduleUiState.NoData -> {
|
||||
if (!uiState.isLoading) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
text = stringResource(R.string.teacher_not_selected),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.user
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -1,4 +1,4 @@
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.user
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -1,4 +1,4 @@
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher
|
||||
package ru.n08i40k.polytechnic.next.ui.main.schedule.teacher.user
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -39,7 +39,7 @@ private fun rememberUpdatedLifecycleOwner(): LifecycleOwner {
|
||||
|
||||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
fun TeacherScheduleScreen(
|
||||
fun TeacherUserScheduleScreen(
|
||||
teacherScheduleViewModel: TeacherScheduleViewModel = TeacherScheduleViewModel(
|
||||
MockAppContainer(
|
||||
LocalContext.current
|
||||
@@ -27,7 +27,7 @@ import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.network.request.schedule.ScheduleGetGroupNames
|
||||
|
||||
@Composable
|
||||
private fun getGroups(context: Context, onUpdated: (String?) -> Unit): ArrayList<String?> {
|
||||
private fun getTeacherNames(context: Context, onUpdated: (String?) -> Unit): ArrayList<String?> {
|
||||
val groupPlaceholder = stringResource(R.string.loading)
|
||||
|
||||
val groups = remember { arrayListOf(null, groupPlaceholder) }
|
||||
@@ -55,6 +55,7 @@ fun GroupSelector(
|
||||
value: String? = "ИС-214/24",
|
||||
isError: Boolean = false,
|
||||
readOnly: Boolean = false,
|
||||
teacher: Boolean = false,
|
||||
onValueChange: (String?) -> Unit = {},
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
@@ -68,10 +69,10 @@ fun GroupSelector(
|
||||
expanded = !readOnly && !expanded
|
||||
}
|
||||
) {
|
||||
val groups = getGroups(LocalContext.current, onValueChange)
|
||||
val groups = getTeacherNames(LocalContext.current, onValueChange)
|
||||
|
||||
TextField(
|
||||
label = { Text(stringResource(R.string.group)) },
|
||||
label = { Text(stringResource(if (teacher) R.string.supervised_group else R.string.group)) },
|
||||
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryEditable),
|
||||
value = value ?: groups.getOrElse(1) { "TODO" }!!,
|
||||
leadingIcon = {
|
||||
@@ -97,7 +98,7 @@ fun GroupSelector(
|
||||
DropdownMenuItem(
|
||||
text = { Text(it) },
|
||||
onClick = {
|
||||
if (groups.size > 0 && groups[0] != null)
|
||||
if (groups.isNotEmpty() && groups[0] != null)
|
||||
onValueChange(it)
|
||||
expanded = false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package ru.n08i40k.polytechnic.next.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import ru.n08i40k.polytechnic.next.R
|
||||
import ru.n08i40k.polytechnic.next.network.request.schedule.ScheduleGetTeacherNames
|
||||
|
||||
@Composable
|
||||
private fun getTeacherNames(context: Context, onUpdated: (String?) -> Unit): ArrayList<String?> {
|
||||
val groupPlaceholder = stringResource(R.string.loading)
|
||||
|
||||
val names = remember { arrayListOf(null, groupPlaceholder) }
|
||||
|
||||
LaunchedEffect(names) {
|
||||
ScheduleGetTeacherNames(context, {
|
||||
names.clear()
|
||||
names.addAll(it.names)
|
||||
onUpdated(names.getOrElse(0) { "TODO" }!!)
|
||||
}, {
|
||||
names.clear()
|
||||
names.add(null)
|
||||
names.add(context.getString(R.string.failed_to_fetch_teacher_names))
|
||||
onUpdated(names[1]!!)
|
||||
}).send()
|
||||
}
|
||||
|
||||
return names
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun TeacherNameSelector(
|
||||
value: String? = "Фамилия И.О.",
|
||||
isError: Boolean = false,
|
||||
readOnly: Boolean = false,
|
||||
onValueChange: (String?) -> Unit = {},
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
modifier = Modifier.wrapContentSize()
|
||||
) {
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = {
|
||||
expanded = !readOnly && !expanded
|
||||
}
|
||||
) {
|
||||
val names = getTeacherNames(LocalContext.current, onValueChange)
|
||||
|
||||
TextField(
|
||||
label = { Text(stringResource(R.string.username)) },
|
||||
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryEditable),
|
||||
value = value ?: names.getOrElse(1) { "TODO" }!!,
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Filled.Person,
|
||||
contentDescription = "username"
|
||||
)
|
||||
},
|
||||
onValueChange = {},
|
||||
isError = isError,
|
||||
readOnly = true,
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }
|
||||
)
|
||||
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
names.forEach {
|
||||
if (it == null)
|
||||
return@forEach
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text(it) },
|
||||
onClick = {
|
||||
if (names.isNotEmpty() && names[0] != null)
|
||||
onValueChange(it)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,4 +85,6 @@
|
||||
<string name="lesson_type_exam">ЗАЧЁТ</string>
|
||||
<string name="lesson_type_exam_with_grade">ЗАЧЁТ С ОЦЕНКОЙ</string>
|
||||
<string name="lesson_type_exam_default">ЭКЗАМЕН</string>
|
||||
<string name="supervised_group">Курируемая группа</string>
|
||||
<string name="teacher_schedule">Преподаватель</string>
|
||||
</resources>
|
||||
@@ -85,4 +85,6 @@
|
||||
<string name="lesson_type_exam">EXAM*</string>
|
||||
<string name="lesson_type_exam_with_grade">EXAM* WITH GRADE</string>
|
||||
<string name="lesson_type_exam_default">EXAM</string>
|
||||
<string name="supervised_group">Supervised group</string>
|
||||
<string name="teacher_schedule">Teacher</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user