final variant

This commit is contained in:
ksenianeva 2023-12-28 13:22:45 +04:00
parent 0d0ffbeb2f
commit f0ce6018a9
21 changed files with 642 additions and 25 deletions

View File

@ -53,6 +53,8 @@ kotlin {
}
dependencies {
implementation("androidx.compose.runtime:runtime-livedata")
//Core
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")

View File

@ -12,22 +12,29 @@ import retrofit2.http.Query
import com.example.myapplication.api.models.UserRemote
import com.example.myapplication.api.models.ChallengeRemote
import com.example.myapplication.api.models.CategoryRemote
import android.util.Log
import com.example.myapplication.api.models.Credentials
import com.example.myapplication.api.models.Token
import retrofit2.http.Body
import retrofit2.http.POST
import java.util.concurrent.TimeUnit
interface MyServerService {
@GET("users")
suspend fun getUsers(
@Query("_page") page: Int,
@Query("page") page: Int,
@Query("_limit") limit: Int,
): List<UserRemote>
@GET("challenges")
suspend fun getChallenges(
@Query("_page") page: Int,
@Query("page") page: Int,
@Query("_limit") limit: Int,
): List<ChallengeRemote>
@GET("categories")
suspend fun getCategories(
@Query("_page") page: Int,
@Query("page") page: Int,
@Query("_limit") limit: Int,
): List<CategoryRemote>
@ -41,8 +48,27 @@ interface MyServerService {
@Path("id") id: Int,
): ChallengeRemote
@POST("login")
suspend fun login(
@Body credentials: Credentials
): Token
@POST("challenges")
suspend fun createChallenge(
@Body challenge: ChallengeRemote,
)
companion object {
private const val BASE_URL = "http://10.0.2.2:8000/api/"
private var _token: String = ""
fun getToken(): String {
return _token
}
fun setToken(token: String) {
_token = token
}
@Volatile
private var INSTANCE: MyServerService? = null
@ -52,7 +78,26 @@ interface MyServerService {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.connectTimeout(1, TimeUnit.DAYS)
.readTimeout(1, TimeUnit.DAYS)
.writeTimeout(1, TimeUnit.DAYS)
.retryOnConnectionFailure(false)
.callTimeout(1, TimeUnit.DAYS)
.addInterceptor(logger)
.addInterceptor {
val originalRequest = it.request()
if (_token.isEmpty()) {
it.proceed(originalRequest)
} else {
it.proceed(
originalRequest
.newBuilder()
.header("Authorization", "Bearer $_token")
.method(originalRequest.method, originalRequest.body)
.build()
)
}
}
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)

View File

@ -70,8 +70,7 @@ import java.io.IOException
nextKey = nextKey
)
}
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.CATEGORY)
dbCategoryRepository.clearCategories()
dbRemoteKeyRepository.createRemoteKeys(keys)
dbCategoryRepository.insertCategories(categories)
}

View File

@ -77,8 +77,6 @@ class ChallengeRemoteMediator(
)
}
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.CHALLENGE)
dbChallengeRepository.clearChallenges()
dbUserRepository.getAll()
dbCategoryRepository.getAll()
dbRemoteKeyRepository.createRemoteKeys(keys)

View File

@ -5,6 +5,7 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.myapplication.api.MyServerService
import com.example.myapplication.api.models.toChallengeRemote
import com.example.myapplication.api.models.toUserWithChallenges
import com.example.myapplication.api.users.UserRemoteMediator
import com.example.myapplication.common.AppDataContainer
@ -49,4 +50,8 @@ class RestChallengeRepository(
pagingSourceFactory = pagingSourceFactory
).flow
}
override suspend fun insert(challenge: Challenge) {
service.createChallenge(challenge.toChallengeRemote())
}
}

View File

@ -19,4 +19,12 @@ fun ChallengeRemote.toChallenge(): Challenge = Challenge(
challenge_status,
category_id,
user_id
)
fun Challenge.toChallengeRemote(): ChallengeRemote = ChallengeRemote(
challenge_id!!,
challenge_name,
challenge_status,
category_id!!,
user_id!!,
)

View File

@ -0,0 +1,9 @@
package com.example.myapplication.api.models
import kotlinx.serialization.Serializable
@Serializable
data class Credentials(
val email: String = "",
val password: String = "",
)

View File

@ -0,0 +1,8 @@
package com.example.myapplication.api.models
import kotlinx.serialization.Serializable
@Serializable
data class Token(
val token: String
)

View File

@ -74,8 +74,7 @@ class UserRemoteMediator (
nextKey = nextKey
)
}
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.USER)
dbUserRepository.clearUsers()
dbRemoteKeyRepository.createRemoteKeys(keys)
dbChallengeRepository.getAll()
dbUserRepository.insertUsers(users)

View File

@ -7,8 +7,11 @@ import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.myapplication.ChallengeApplication
import com.example.myapplication.ui.category.list.CategoryListViewModel
import com.example.myapplication.ui.challenge.view.AdminChallengeViewModel
import com.example.myapplication.ui.user.list.UserListViewModel
import com.example.myapplication.ui.user.view.UserViewModel
import com.example.myapplication.ui.login.LoginViewModel
import com.example.myapplication.ui.user.view.AdminUserViewModel
object AppViewModelProvider {
val Factory = viewModelFactory {
@ -21,6 +24,15 @@ object AppViewModelProvider {
initializer {
UserViewModel(this.createSavedStateHandle(), challengeApplication().container.userRestRepository)
}
initializer {
LoginViewModel()
}
initializer {
AdminUserViewModel(this.createSavedStateHandle(), challengeApplication().container.userRestRepository)
}
initializer {
AdminChallengeViewModel(this.createSavedStateHandle(), challengeApplication().container.challengeRestRepository)
}
}
}

View File

@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow
interface ChallengeRepository {
fun getAll(): Flow<PagingData<Challenge>>
// fun getByUid(uid: Int): Flow<Challenge?>
// suspend fun insert(challenge: Challenge)
suspend fun insert(challenge: Challenge)
// suspend fun update(challenge: Challenge)
// suspend fun delete(challenge: Challenge)
}

View File

@ -21,7 +21,7 @@ class OfflineChallengeRepository(private val challengeDao: ChallengeDao) : Chall
).flow;
fun getByUid(uid: Int): Flow<Challenge?> = challengeDao.getByUid(uid);
suspend fun insert(challenge: Challenge) = challengeDao.insert(challenge);
override suspend fun insert(challenge: Challenge) = challengeDao.insert(challenge);
suspend fun update(challenge: Challenge) = challengeDao.update(challenge);

View File

@ -0,0 +1,93 @@
package com.example.myapplication.ui.challenge.view
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.example.myapplication.R
import com.example.myapplication.common.AppViewModelProvider
import com.example.myapplication.database.challenge.model.Challenge
import com.example.myapplication.ui.theme.MyApplicationTheme
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AdminChallengeView(
navController: NavController,
viewModel: AdminChallengeViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val coroutineScope = rememberCoroutineScope()
ChallengeEdit(
challengeUiState = viewModel.adminChallengeUiState,
onClick = {
coroutineScope.launch {
viewModel.saveChallenge()
navController.popBackStack()
}
},
onUpdate = viewModel::updateUiState,
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ChallengeEdit(
challengeUiState: AdminChallengeUiState,
onClick: () -> Unit,
onUpdate: (AdminChallengeDetails) -> Unit,
) {
Column(
Modifier
.fillMaxWidth()
.padding(all = 10.dp)
) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = challengeUiState.adminChallengeDetails.challenge_name,
onValueChange = { onUpdate(challengeUiState.adminChallengeDetails.copy(challenge_name = it)) },
label = {Text("Задание")},
singleLine = true
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = challengeUiState.adminChallengeDetails.category_id.toString(),
onValueChange = { onUpdate(challengeUiState.adminChallengeDetails.copy(category_id = it.toInt())) },
label = {Text("Категория")},
singleLine = true
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = challengeUiState.adminChallengeDetails.user_id.toString(),
onValueChange = { onUpdate(challengeUiState.adminChallengeDetails.copy(user_id = it.toInt())) },
label = {Text("Пользователь")},
singleLine = true
)
Button(
onClick = onClick,
shape = MaterialTheme.shapes.small,
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Сохранить")
}
}
}

View File

@ -0,0 +1,69 @@
package com.example.myapplication.ui.challenge.view
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.common.ChallengeRepository
import com.example.myapplication.database.challenge.model.Challenge
import com.example.myapplication.database.user.model.UserWithChallenges
import com.example.myapplication.common.UserRepository
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class AdminChallengeViewModel(
savedStateHandle: SavedStateHandle,
private val challengeRepository: ChallengeRepository
) : ViewModel() {
var adminChallengeUiState by mutableStateOf(AdminChallengeUiState())
private set
init {
}
fun updateUiState(adminChallengeDetails: AdminChallengeDetails) {
adminChallengeUiState = AdminChallengeUiState(
adminChallengeDetails = adminChallengeDetails,
)
}
suspend fun saveChallenge() {
if (validateInput()) {
challengeRepository.insert(
adminChallengeUiState.adminChallengeDetails.toChallenge()
)
}
}
private fun validateInput(uiState: AdminChallengeDetails = adminChallengeUiState.adminChallengeDetails): Boolean {
return with(uiState) {
challenge_name.isNotBlank()
}
}
}
data class AdminChallengeUiState(
val adminChallengeDetails: AdminChallengeDetails = AdminChallengeDetails(),
)
data class AdminChallengeDetails(
val challenge_name: String = "",
val challenge_status: Boolean = false,
val category_id: Int = 0,
val user_id: Int = 0,
)
fun AdminChallengeDetails.toChallenge(uid: Int = 0): Challenge = Challenge(
challenge_id = uid,
challenge_name = challenge_name,
challenge_status = challenge_status,
category_id = category_id,
user_id = user_id,
)

View File

@ -0,0 +1,116 @@
package com.example.myapplication.ui.login
import androidx.compose.foundation.layout.*
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.*
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.myapplication.R
import com.example.myapplication.common.AppViewModelProvider
import com.example.myapplication.ui.navigation.Screen
@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun Login(
navController: NavHostController,
viewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val success = viewModel.successState.observeAsState().value
val login = remember { mutableStateOf(TextFieldValue(""))}
val password = remember { mutableStateOf(TextFieldValue(""))}
if (success == false) {
AlertDialog(
title = {
Text(
text = "Ошибка авторизации",
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Text(
text = "Неверный логин или пароль",
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
},
onDismissRequest = {
viewModel.calmSuccessState()
},
confirmButton = {
TextButton(
onClick = {
viewModel.calmSuccessState()
}
) {
Text("OK")
}
}
)
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth(0.7f).fillMaxHeight().padding(vertical=100.dp)
) {
Text(
text = "Вход",
style = TextStyle(
fontSize = 40.sp,
fontWeight = FontWeight(400),
),
modifier = Modifier.fillMaxHeight(0.3f)
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth().padding(bottom=30.dp),
value = login.value,
onValueChange = { login.value = it },
label = { Text(stringResource(id = R.string.login)) },
singleLine = true
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth().padding(bottom=30.dp),
value = password.value,
onValueChange = { password.value = it },
label = { Text(stringResource(id = R.string.password)) },
singleLine = true
)
Button(
{
viewModel.login(login.value.text, password.value.text, navController)
},
modifier = Modifier.padding(bottom=20.dp).fillMaxWidth(0.5f)
) {
Text(
text = "Войти",
style = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight(400),
color = Color(0xFFFFFFFF),
)
)
}
}
}
}

View File

@ -0,0 +1,49 @@
package com.example.myapplication.ui.login
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import com.example.myapplication.api.MyServerService
import com.example.myapplication.api.models.Credentials
import com.example.myapplication.ui.navigation.Screen
import kotlinx.coroutines.launch
class LoginViewModel : ViewModel() {
private val _successState = MutableLiveData<Boolean?>()
val successState: LiveData<Boolean?>
get() = _successState
fun calmSuccessState() {
_successState.postValue(null)
}
fun login(login: String, password: String, navController: NavHostController) {
viewModelScope.launch {
val token = MyServerService.getInstance().login(Credentials(login, password))
if (token.token.isEmpty()) {
_successState.postValue(false)
return@launch
}
MyServerService.setToken(token.token)
_successState.setValue(true)
navigate(navController)
}
}
fun navigate(navController: NavHostController) {
Screen.About.route.let {
navController.navigate(it) {
popUpTo(it) {
inclusive = true
}
}
}
}
}

View File

@ -36,6 +36,10 @@ import com.example.myapplication.ui.about.About
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.example.myapplication.ui.user.view.UserView
import com.example.myapplication.ui.user.list.UsersList
import com.example.myapplication.ui.login.Login
import com.example.myapplication.api.MyServerService
import com.example.myapplication.ui.challenge.view.AdminChallengeView
import com.example.myapplication.ui.user.view.AdminUserView
@OptIn(ExperimentalMaterial3Api::class)
@ -77,24 +81,27 @@ fun Navbar(
) {
NavigationBar(modifier) {
Screen.bottomBarItems.forEach { screen ->
NavigationBarItem(
icon = { Icon(screen.icon, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
if (MyServerService.getToken().isBlank() || screen.route !== "login") {
NavigationBarItem(
icon = { Icon(screen.icon, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = false
}
launchSingleTop = true
restoreState = false
}
launchSingleTop = true
restoreState = true
}
}
)
)
}
}
}
}
@Composable
fun Navhost(
navController: NavHostController,
@ -109,11 +116,18 @@ fun Navhost(
composable(Screen.CategoryList.route) { CategoriesList(navController) }
composable(Screen.About.route) { About() }
composable(Screen.UserList.route) { UsersList(navController) }
composable(Screen.Login.route) { Login(navController) }
composable(Screen.AdminChallengeView.route){ AdminChallengeView(navController)}
composable(
Screen.UserView.route,
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
backStackEntry.arguments?.let { UserView() }
if (MyServerService.getToken().isBlank()) {
backStackEntry.arguments?.let { UserView() }
}
else {
backStackEntry.arguments?.let { AdminUserView(navController) }
}
}
}
}

View File

@ -8,6 +8,8 @@ import androidx.compose.material.icons.filled.List
import androidx.compose.material.icons.filled.Person
import androidx.compose.ui.graphics.vector.ImageVector
import com.example.myapplication.R
import androidx.compose.material.icons.filled.Face
import com.example.myapplication.api.MyServerService
enum class Screen(
val route: String,
@ -18,6 +20,9 @@ enum class Screen(
CategoryList(
"categories-list", R.string.categories_list, Icons.Filled.List
),
Login(
"login", R.string.login_main_title, Icons.Filled.Face
),
UserList(
"users-list", R.string.user_list, Icons.Filled.Person
),
@ -26,13 +31,17 @@ enum class Screen(
),
UserView(
"user-view/{id}", R.string.user_view_title, showInBottomBar = false
),
AdminChallengeView(
"admin-challenge-view", R.string.admin_challenge,showInBottomBar = false
);
companion object {
val bottomBarItems = listOf(
About,
CategoryList,
UserList,
About,
Login
)
fun getItem(route: String): Screen? {

View File

@ -0,0 +1,124 @@
package com.example.myapplication.ui.user.view
import android.content.res.Configuration
import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
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.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemContentType
import androidx.paging.compose.itemKey
import coil.compose.AsyncImage
import com.example.myapplication.R
import com.example.myapplication.api.MyServerService
import com.example.myapplication.database.user.model.User
import com.example.myapplication.common.AppViewModelProvider
import com.example.myapplication.ui.navigation.Screen
import com.example.myapplication.ui.theme.MyApplicationTheme
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AdminUserView(
navController: NavController,
viewModel: AdminUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val coroutineScope = rememberCoroutineScope()
val userWithChallanges = viewModel.adminUserUiState.adminUserDetails
Scaffold(
topBar = {},
floatingActionButton = {
FloatingActionButton(
onClick = {
val route = Screen.AdminChallengeView.route.replace("{id}", 0.toString())
navController.navigate(route)
},
) {
Icon(Icons.Filled.Add, "Добавить")
}
}
)
{ innerPadding ->
val userWithChallanges = viewModel.adminUserUiState.adminUserDetails;
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = userWithChallanges.login.toString(),
onValueChange = {},
readOnly = true,
label = {
Text(stringResource(id = R.string.user_login))
}
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = userWithChallanges.fio.toString(),
onValueChange = {},
readOnly = true,
label = {
Text(stringResource(id = R.string.user_fio))
}
)
userWithChallanges.challenges?.forEachIndexed() { _, challenge ->
Row {
Text(text = challenge.challenge_name)
if (challenge.challenge_status) {
Text(text = " - Выполнено")
} else {
Text(text = " - В процессе")
}
}
}
}
}
}

View File

@ -0,0 +1,54 @@
package com.example.myapplication.ui.user.view
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.database.challenge.model.Challenge
import com.example.myapplication.database.user.model.UserWithChallenges
import com.example.myapplication.common.UserRepository
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class AdminUserViewModel(
savedStateHandle: SavedStateHandle,
private val userRepository: UserRepository
) : ViewModel() {
var adminUserUiState by mutableStateOf(AdminUserUiState())
private set
private val studentUid: Int = checkNotNull(savedStateHandle["id"])
init {
viewModelScope.launch {
if (studentUid > 0) {
adminUserUiState = userRepository.getByUid(studentUid)
.toAdminUiState()
}
}
}
}
data class AdminUserUiState(
val adminUserDetails: AdminUserDetails = AdminUserDetails(),
)
data class AdminUserDetails(
val login: String = "",
val fio: String = "",
val challenges: List<Challenge> = listOf()
)
fun UserWithChallenges.toAdminDetails(): AdminUserDetails = AdminUserDetails(
login = user.login,
fio = user.fio,
challenges = challenges
)
fun UserWithChallenges.toAdminUiState(): AdminUserUiState = AdminUserUiState(
adminUserDetails = this.toAdminDetails(),
)

View File

@ -10,4 +10,8 @@
<string name="user_login">Логин</string>
<string name="user_fio">ФИО</string>
<string name="user_view_title">Пользователь</string>
<string name="login_main_title">Вход</string>
<string name="login">Логин</string>
<string name="password">Пароль</string>
<string name="admin_challenge">Создание челленджа</string>
</resources>