diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..f866a66
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+PolytecnicNext
\ No newline at end of file
diff --git a/.idea/dictionaries/n08i40k.xml b/.idea/dictionaries/n08i40k.xml
new file mode 100644
index 0000000..24d5649
--- /dev/null
+++ b/.idea/dictionaries/n08i40k.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5072a76..414f30a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -33,8 +33,8 @@ android {
applicationId = "ru.n08i40k.polytechnic.next"
minSdk = 26
targetSdk = 35
- versionCode = 22
- versionName = "2.2.1"
+ versionCode = 23
+ versionName = "2.3.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/auth/SignUpForm.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/auth/SignUpForm.kt
index 76ccc02..f1c84b1 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/auth/SignUpForm.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/auth/SignUpForm.kt
@@ -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
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/Constants.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/Constants.kt
index 1911aa9..8e06b81 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/Constants.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/Constants.kt
@@ -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
+ )
)
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt
index a7b68d0..4db7d5c 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt
@@ -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
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ChangeGroupDialog.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ChangeGroupDialog.kt
index a8cbcbb..ada7752 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ChangeGroupDialog.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ChangeGroupDialog.kt
@@ -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(
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt
index 419f770..8a3ea80 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt
@@ -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)
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/main/TeacherMainScheduleScreen.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/main/TeacherMainScheduleScreen.kt
new file mode 100644
index 0000000..1bed1ff
--- /dev/null
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/main/TeacherMainScheduleScreen.kt
@@ -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
+ )
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/SearchBox.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/SearchBox.kt
similarity index 97%
rename from app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/SearchBox.kt
rename to app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/SearchBox.kt
index 4eeaad7..84814d2 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/SearchBox.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/SearchBox.kt
@@ -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
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/TeacherSearchBox.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/TeacherSearchBox.kt
similarity index 95%
rename from app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/TeacherSearchBox.kt
rename to app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/TeacherSearchBox.kt
index 0c34c91..5638c9c 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/TeacherSearchBox.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/TeacherSearchBox.kt
@@ -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
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/TeacherScheduleScreen.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/TeacherUserScheduleScreen.kt
similarity index 97%
rename from app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/TeacherScheduleScreen.kt
rename to app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/TeacherUserScheduleScreen.kt
index 6419ac9..dda37b2 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/TeacherScheduleScreen.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/teacher/user/TeacherUserScheduleScreen.kt
@@ -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
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/GroupSelector.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/GroupSelector.kt
index 3f06d4c..abd409e 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/GroupSelector.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/GroupSelector.kt
@@ -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 {
+private fun getTeacherNames(context: Context, onUpdated: (String?) -> Unit): ArrayList {
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
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/TeacherNameSelector.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/TeacherNameSelector.kt
new file mode 100644
index 0000000..62a7c35
--- /dev/null
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/widgets/TeacherNameSelector.kt
@@ -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 {
+ 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
+ }
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index b23dfe2..d287c2a 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -85,4 +85,6 @@
ЗАЧЁТ
ЗАЧЁТ С ОЦЕНКОЙ
ЭКЗАМЕН
+ Курируемая группа
+ Преподаватель
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 06c22d3..24b4c3d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -85,4 +85,6 @@
EXAM*
EXAM* WITH GRADE
EXAM
+ Supervised group
+ Teacher
\ No newline at end of file