add profile fragment
This commit is contained in:
parent
9ba4ba21db
commit
45a5f9cff5
@ -1,5 +1,5 @@
|
|||||||
package ru.myitschool.work.core
|
package ru.myitschool.work.core
|
||||||
// БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ
|
// БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ
|
||||||
object Constants {
|
object Constants {
|
||||||
const val SERVER_ADDRESS = "http://localhost:8090"
|
const val SERVER_ADDRESS = "http://10.0.2.2:8080"
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package ru.myitschool.work.data.auth
|
package ru.myitschool.work.data.auth
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import io.ktor.client.call.body
|
import io.ktor.client.call.body
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.request.header
|
import io.ktor.client.request.header
|
||||||
@ -17,22 +18,24 @@ import ru.myitschool.work.data.user.UserDto
|
|||||||
|
|
||||||
object AuthNetworkDataSource {
|
object AuthNetworkDataSource {
|
||||||
|
|
||||||
suspend fun isUserExist(login: String): Result<Boolean?> = withContext(Dispatchers.IO) {
|
// suspend fun isUserExist(login: String): Result<Boolean?> = withContext(Dispatchers.IO) {
|
||||||
runCatching {
|
// runCatching {
|
||||||
val result = client.get("$SERVER_ADDRESS/api/login/$login") //10.0.2.2
|
// val result = client.get("$SERVER_ADDRESS/api/login/$login") //10.0.2.2
|
||||||
when (result.status) {
|
// when (result.status) {
|
||||||
HttpStatusCode.OK -> { return@runCatching true }
|
// HttpStatusCode.OK -> { return@runCatching true }
|
||||||
HttpStatusCode.NotFound -> { return@runCatching false }
|
// HttpStatusCode.NotFound -> { return@runCatching false }
|
||||||
else -> {return@runCatching null }
|
// else -> {return@runCatching null }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
suspend fun login(token: String): Result<UserDto> = withContext(Dispatchers.IO) {
|
suspend fun login(token: String): Result<UserDto> = withContext(Dispatchers.IO) {
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
val result = client.get("$SERVER_ADDRESS/api/login") {
|
val result = client.get("$SERVER_ADDRESS/api/login") {
|
||||||
header(HttpHeaders.Authorization, token)
|
header(HttpHeaders.Authorization, token)
|
||||||
}
|
}
|
||||||
|
Log.d("result", "${result.status}")
|
||||||
if (result.status == HttpStatusCode.Unauthorized) {
|
if (result.status == HttpStatusCode.Unauthorized) {
|
||||||
error("Неверный email или пароль")
|
error("Неверный email или пароль")
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ class AuthRepoImpl(
|
|||||||
private val authNetworkDataSource: AuthNetworkDataSource,
|
private val authNetworkDataSource: AuthNetworkDataSource,
|
||||||
private val authStorageDataSource: AuthStorageDataSource
|
private val authStorageDataSource: AuthStorageDataSource
|
||||||
) : AuthRepo {
|
) : AuthRepo {
|
||||||
override suspend fun isUserExist(email: String): Result<Boolean?> {
|
// override suspend fun isUserExist(email: String): Result<Boolean?> {
|
||||||
return authNetworkDataSource.isUserExist(email)
|
// return authNetworkDataSource.isUserExist(email)
|
||||||
}
|
// }
|
||||||
|
|
||||||
override suspend fun login(email: String, password: String): Result<UserDto> {
|
override suspend fun login(email: String, password: String): Result<UserDto> {
|
||||||
val token = authStorageDataSource.updateToken(email, password)
|
val token = authStorageDataSource.updateToken(email, password)
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package ru.myitschool.work.data.user
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
|
||||||
|
data class EntranceDto(
|
||||||
|
@SerialName("login")
|
||||||
|
val login : String,
|
||||||
|
@SerialName("name")
|
||||||
|
var name: String,
|
||||||
|
@SerialName("enterAt")
|
||||||
|
var enterAt: String,
|
||||||
|
@SerialName("enterType")
|
||||||
|
var enterType: String,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
@ -18,8 +18,8 @@ data class UserDto(
|
|||||||
var avatarUrl: String?,
|
var avatarUrl: String?,
|
||||||
@SerialName("position")
|
@SerialName("position")
|
||||||
val position: String,
|
val position: String,
|
||||||
@SerialName("lastEntry")
|
@SerialName("lastEnter")
|
||||||
val lastEntry : String,
|
val lastEntry : String? = null,
|
||||||
@SerialName("authorities")
|
@SerialName("authorities")
|
||||||
val authorities : String
|
val authorities : String
|
||||||
) {
|
) {
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package ru.sicampus.bootcamp2025.data.user
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.request.header
|
||||||
|
import io.ktor.client.request.put
|
||||||
|
import io.ktor.client.request.setBody
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import ru.myitschool.work.core.Constants.SERVER_ADDRESS
|
||||||
|
import ru.myitschool.work.data.auth.AuthStorageDataSource.token
|
||||||
|
import ru.myitschool.work.data.auth.Network.client
|
||||||
|
import ru.myitschool.work.data.user.EntranceDto
|
||||||
|
import ru.myitschool.work.data.user.UserDto
|
||||||
|
|
||||||
|
class UserNetworkDataSource {
|
||||||
|
suspend fun getUser(login : String): Result<UserDto> = withContext(Dispatchers.IO) {
|
||||||
|
runCatching {
|
||||||
|
|
||||||
|
val result = client.get("http://$SERVER_ADDRESS/api/${login}/info") {
|
||||||
|
header(HttpHeaders.Authorization, token)
|
||||||
|
}
|
||||||
|
Log.d("tututuut", "${result.status}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (result.status != HttpStatusCode.OK) {
|
||||||
|
error("Status ${result.status}")
|
||||||
|
}
|
||||||
|
Log.d("result", result.bodyAsText())
|
||||||
|
result.body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getEntrancesList(login : String) : Result<List<EntranceDto>> = withContext(Dispatchers.IO){
|
||||||
|
runCatching {
|
||||||
|
val result = client.get("http://$SERVER_ADDRESS/api/$login/entrances") {
|
||||||
|
header(HttpHeaders.Authorization, token)
|
||||||
|
}
|
||||||
|
Log.d("serverCode", "${result.status}")
|
||||||
|
if (result.status != HttpStatusCode.OK) {
|
||||||
|
error("Status ${result.status}")
|
||||||
|
}
|
||||||
|
result.body()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package ru.sicampus.bootcamp2025.data.user
|
||||||
|
|
||||||
|
import ru.myitschool.work.data.user.EntranceDto
|
||||||
|
import ru.myitschool.work.data.user.UserDto
|
||||||
|
import ru.myitschool.work.domain.user.EntranceEntity
|
||||||
|
import ru.myitschool.work.domain.user.UserEntity
|
||||||
|
import ru.myitschool.work.domain.user.UserRepo
|
||||||
|
|
||||||
|
|
||||||
|
class UserRepoImpl (
|
||||||
|
private val userNetworkDataSource: UserNetworkDataSource
|
||||||
|
) : UserRepo {
|
||||||
|
override suspend fun getUser(login: String): Result<UserEntity> {
|
||||||
|
return userNetworkDataSource.getUser(login).map { dto ->
|
||||||
|
UserEntity(
|
||||||
|
id = dto.id ?: -1,
|
||||||
|
name = dto.name,
|
||||||
|
avatarUrl = dto.avatarUrl ?: "",
|
||||||
|
authorities = dto.authorities,
|
||||||
|
login = login,
|
||||||
|
position = dto.position,
|
||||||
|
lastEntry = dto.lastEntry ?: "",
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override suspend fun getEntrancesList(login : String): Result<List<EntranceEntity>> {
|
||||||
|
return userNetworkDataSource.getEntrancesList(login).map { userList ->
|
||||||
|
userList.map { it.toEntity() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun EntranceDto.toEntity(): EntranceEntity {
|
||||||
|
return EntranceEntity(
|
||||||
|
login = login,
|
||||||
|
name = this.name,
|
||||||
|
enterAt = this.enterAt,
|
||||||
|
enterType = this.enterType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,6 @@ package ru.myitschool.work.domain.auth
|
|||||||
import ru.myitschool.work.data.user.UserDto
|
import ru.myitschool.work.data.user.UserDto
|
||||||
|
|
||||||
interface AuthRepo {
|
interface AuthRepo {
|
||||||
suspend fun isUserExist(email: String): Result<Boolean?>
|
//suspend fun isUserExist(email: String): Result<Boolean?>
|
||||||
suspend fun login(email: String, password: String) : Result <UserDto>
|
suspend fun login(login: String, password: String) : Result <UserDto>
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@ package ru.myitschool.work.domain.auth
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class IsUserExistUseCase (
|
/*class IsUserExistUseCase (
|
||||||
private val authRepo : AuthRepo
|
private val authRepo : AuthRepo
|
||||||
) {
|
) {
|
||||||
suspend operator fun invoke(email : String) : Result<Boolean?> {
|
suspend operator fun invoke(email : String) : Result<Boolean?> {
|
||||||
return authRepo.isUserExist(email)
|
return authRepo.isUserExist(email)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
@ -5,7 +5,7 @@ import ru.myitschool.work.data.user.UserDto
|
|||||||
class LoginUseCase(
|
class LoginUseCase(
|
||||||
private val authRepo : AuthRepo
|
private val authRepo : AuthRepo
|
||||||
){
|
){
|
||||||
suspend operator fun invoke(email : String, password : String) : Result<UserDto> {
|
suspend operator fun invoke(login : String, password : String) : Result<UserDto> {
|
||||||
return authRepo.login(email, password)
|
return authRepo.login(login, password)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +0,0 @@
|
|||||||
package ru.sicampus.bootcamp2025.data
|
|
||||||
|
|
||||||
import io.ktor.client.HttpClient
|
|
||||||
import io.ktor.client.engine.cio.CIO
|
|
||||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
object Network {
|
|
||||||
val client = HttpClient(CIO) {
|
|
||||||
install(ContentNegotiation) {
|
|
||||||
json(Json {
|
|
||||||
isLenient = true
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package ru.myitschool.work.domain.user
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
|
||||||
|
data class EntranceEntity(
|
||||||
|
val login : String,
|
||||||
|
var name: String,
|
||||||
|
var enterAt: String,
|
||||||
|
var enterType: String,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package ru.myitschool.work.domain.user
|
||||||
|
|
||||||
|
import ru.myitschool.work.data.auth.AuthStorageDataSource
|
||||||
|
import ru.myitschool.work.data.user.UserDto
|
||||||
|
|
||||||
|
class GetUserUseCase(
|
||||||
|
private val repo: UserRepo,
|
||||||
|
private val authStorageDataSource: AuthStorageDataSource
|
||||||
|
) {
|
||||||
|
suspend fun getUserFromStorage() : UserDto? {
|
||||||
|
return authStorageDataSource.userInfo
|
||||||
|
}
|
||||||
|
suspend operator fun invoke() = repo.getUser(getUserFromStorage()?.login!!)
|
||||||
|
suspend fun getEntrancesList() = repo.getEntrancesList(getUserFromStorage()?.login!!)
|
||||||
|
|
||||||
|
}
|
@ -8,7 +8,7 @@ data class UserEntity(
|
|||||||
var name: String,
|
var name: String,
|
||||||
var avatarUrl: String?,
|
var avatarUrl: String?,
|
||||||
val position : String,
|
val position : String,
|
||||||
var lastEntry : String,
|
var lastEntry : String?,
|
||||||
val authorities : String
|
val authorities : String
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package ru.myitschool.work.domain.user
|
||||||
|
|
||||||
|
|
||||||
|
interface UserRepo {
|
||||||
|
suspend fun getUser(login: String) : Result<UserEntity>
|
||||||
|
suspend fun getEntrancesList(login : String) : Result<List<EntranceEntity>>
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package ru.myitschool.work.ui
|
package ru.myitschool.work.ui
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@ -17,22 +18,28 @@ import ru.myitschool.work.ui.qr.scan.QrScanFragment
|
|||||||
// НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА!
|
// НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА!
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class RootActivity : AppCompatActivity() {
|
class RootActivity : AppCompatActivity() {
|
||||||
|
@SuppressLint("ResourceType")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_root)
|
setContentView(R.layout.fragment_profile)
|
||||||
|
val userRole = intent.getStringExtra("USER_ROLE")
|
||||||
|
|
||||||
/*val navHostFragment = supportFragmentManager
|
/*val navHostFragment = supportFragmentManager
|
||||||
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
|
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
|
||||||
|
val navController = navHostFragment.navController*/
|
||||||
|
|
||||||
if (navHostFragment != null) {
|
|
||||||
val navController = navHostFragment.navController
|
|
||||||
navController.graph = navController.createGraph(
|
/*if (userRole == "ROLE_ADMIN") {
|
||||||
startDestination = LoginDestination
|
bottomNavigationView.menu.clear()
|
||||||
) {
|
bottomNavigationView.inflateMenu(R.menu.bottom_menu_admin)
|
||||||
fragment<LoginFragment, LoginDestination>()
|
navController.setGraph(R.navigation.main_admin_nav_graph)
|
||||||
fragment<QrScanFragment, QrScanDestination>()
|
|
||||||
}
|
} else {
|
||||||
}
|
bottomNavigationView.menu.clear()
|
||||||
|
bottomNavigationView.inflateMenu(R.menu.bottom_menu)
|
||||||
|
navController.setGraph(R.navigation.main_nav_graph)
|
||||||
|
}*/
|
||||||
|
|
||||||
onBackPressedDispatcher.addCallback(
|
onBackPressedDispatcher.addCallback(
|
||||||
this,
|
this,
|
||||||
@ -44,7 +51,7 @@ class RootActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportNavigateUp(): Boolean {
|
/*override fun onSupportNavigateUp(): Boolean {
|
||||||
val navController = findNavController(R.id.nav_host_fragment)
|
val navController = findNavController(R.id.nav_host_fragment)
|
||||||
val popBackResult = if (navController.previousBackStackEntry != null) {
|
val popBackResult = if (navController.previousBackStackEntry != null) {
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
@ -53,5 +60,5 @@ class RootActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
return popBackResult || super.onSupportNavigateUp()
|
return popBackResult || super.onSupportNavigateUp()
|
||||||
}*/
|
}*/
|
||||||
}
|
|
||||||
}
|
}
|
@ -65,7 +65,7 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
|
|||||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
|
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
|
||||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
|
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
|
||||||
override fun afterTextChanged(p0: Editable?) {
|
override fun afterTextChanged(p0: Editable?) {
|
||||||
|
viewModel.changeLogin()
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -17,14 +17,13 @@ import ru.myitschool.work.R
|
|||||||
import ru.myitschool.work.data.auth.AuthNetworkDataSource
|
import ru.myitschool.work.data.auth.AuthNetworkDataSource
|
||||||
import ru.myitschool.work.data.auth.AuthRepoImpl
|
import ru.myitschool.work.data.auth.AuthRepoImpl
|
||||||
import ru.myitschool.work.data.auth.AuthStorageDataSource
|
import ru.myitschool.work.data.auth.AuthStorageDataSource
|
||||||
import ru.myitschool.work.domain.auth.IsUserExistUseCase
|
//import ru.myitschool.work.domain.auth.IsUserExistUseCase
|
||||||
import ru.myitschool.work.domain.auth.LoginUseCase
|
import ru.myitschool.work.domain.auth.LoginUseCase
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class LoginViewModel constructor(
|
class LoginViewModel constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val isUserExistUseCase: IsUserExistUseCase,
|
|
||||||
private val loginUseCase: LoginUseCase
|
private val loginUseCase: LoginUseCase
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _state = MutableStateFlow<State>(getStateShow())
|
private val _state = MutableStateFlow<State>(getStateShow())
|
||||||
@ -49,44 +48,23 @@ class LoginViewModel constructor(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
when (checkUserExistence(login)) {
|
loginUser(login, password)
|
||||||
true -> {
|
|
||||||
loginUser(login, password)
|
|
||||||
}
|
|
||||||
false -> {
|
|
||||||
updateState(context.getString(R.string.error_invalid_credentials))
|
|
||||||
}
|
|
||||||
null -> updateState(context.getString(R.string.error_unknown))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun checkUserExistence(email: String):Boolean?{
|
|
||||||
return try {
|
|
||||||
val result = isUserExistUseCase(email)
|
|
||||||
result.fold(
|
|
||||||
onSuccess = {isExist -> isExist},
|
|
||||||
onFailure = {
|
|
||||||
Log.e("LoginViewModel", "Error checking user existence", it)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("LoginViewModel", "Error during user existence check", e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private suspend fun loginUser(email: String, password: String) {
|
private suspend fun loginUser(email: String, password: String) {
|
||||||
loginUseCase(email, password).fold(
|
loginUseCase(email, password).fold(
|
||||||
onSuccess = { user ->
|
onSuccess = { user ->
|
||||||
println("Login successful")
|
Log.d("loginViewModel","Login successful")
|
||||||
_userRole.emit(user.authorities)
|
_userRole.emit(user.authorities)
|
||||||
_navigateToMain.emit(user.authorities)
|
_navigateToMain.emit(user.authorities)
|
||||||
},
|
},
|
||||||
onFailure = { error ->
|
onFailure = { error ->
|
||||||
updateState(error.message ?: context.getString(R.string.error_unknown))
|
updateState(error.message ?: context.getString(R.string.error_unknown))
|
||||||
|
Log.d("errorLoginViewModel","${error.message}")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -125,7 +103,6 @@ class LoginViewModel constructor(
|
|||||||
)
|
)
|
||||||
return LoginViewModel(
|
return LoginViewModel(
|
||||||
application,
|
application,
|
||||||
isUserExistUseCase = IsUserExistUseCase(authRepoImpl),
|
|
||||||
loginUseCase = LoginUseCase(authRepoImpl)
|
loginUseCase = LoginUseCase(authRepoImpl)
|
||||||
) as T
|
) as T
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
package ru.myitschool.work.ui.profile
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
import ru.myitschool.work.R
|
||||||
|
import ru.myitschool.work.databinding.FragmentProfileBinding
|
||||||
|
import ru.myitschool.work.ui.login.EntryActivity
|
||||||
|
import ru.myitschool.work.utils.collectWithLifecycle
|
||||||
|
|
||||||
|
class ProfileFragment : Fragment(R.layout.fragment_profile) {
|
||||||
|
private var _viewBinding: FragmentProfileBinding? = null
|
||||||
|
private val viewBinding: FragmentProfileBinding get() = _viewBinding!!
|
||||||
|
|
||||||
|
private val viewModel by viewModels<ProfileViewModel> { ProfileViewModel.Factory }
|
||||||
|
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
_viewBinding = FragmentProfileBinding.bind(view)
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
|
||||||
|
viewBinding.refresh.setOnClickListener { viewModel.clickRefresh() }
|
||||||
|
viewBinding.refreshForProfile.setOnClickListener { viewModel.clickRefresh() }
|
||||||
|
viewBinding.logout.setOnClickListener {
|
||||||
|
val intent = Intent(requireContext(), EntryActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
viewModel.state.collectWithLifecycle(this) { state ->
|
||||||
|
|
||||||
|
viewBinding.error.visibility = if (state is ProfileViewModel.State.Error) View.VISIBLE else View.GONE
|
||||||
|
viewBinding.loading.visibility = if (state is ProfileViewModel.State.Loading) View.VISIBLE else View.GONE
|
||||||
|
viewBinding.profile.visibility = if (state is ProfileViewModel.State.Show) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
|
when(state) {
|
||||||
|
is ProfileViewModel.State.Loading -> Unit
|
||||||
|
is ProfileViewModel.State.Show -> {
|
||||||
|
viewBinding.name.text = state.profileInfo.name
|
||||||
|
viewBinding.position.text = "Должность: ${state.profileInfo.name}"
|
||||||
|
if (state.profileInfo.lastEntry == null) viewBinding.lastEntry.text = "Время последнего входа: Нет данных"
|
||||||
|
else viewBinding.lastEntry.text = "Время последнего входа: ${state.profileInfo.lastEntry}"
|
||||||
|
Picasso.get().load(state.profileInfo.avatarUrl).resize(100, 100).centerCrop().into(viewBinding.imageView)
|
||||||
|
|
||||||
|
//if (state.entrancesList == emptyList())
|
||||||
|
//viewBinding.recyclerView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
is ProfileViewModel.State.Error -> {
|
||||||
|
viewBinding.errorText.text = state.text
|
||||||
|
//viewBinding.noData.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
_viewBinding = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package ru.myitschool.work.ui.profile
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.myitschool.work.data.auth.AuthStorageDataSource
|
||||||
|
import ru.myitschool.work.domain.user.EntranceEntity
|
||||||
|
import ru.myitschool.work.domain.user.GetUserUseCase
|
||||||
|
import ru.myitschool.work.domain.user.UserEntity
|
||||||
|
import ru.sicampus.bootcamp2025.data.user.UserNetworkDataSource
|
||||||
|
import ru.sicampus.bootcamp2025.data.user.UserRepoImpl
|
||||||
|
|
||||||
|
class ProfileViewModel(
|
||||||
|
private val getUserUseCase: GetUserUseCase
|
||||||
|
) : ViewModel() {
|
||||||
|
private val _state = MutableStateFlow<State>(State.Loading)
|
||||||
|
val state = _state.asStateFlow()
|
||||||
|
|
||||||
|
init {
|
||||||
|
updateStateGet()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickRefresh() {
|
||||||
|
updateStateGet()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateStateGet() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_state.emit(State.Loading)
|
||||||
|
val entranceList : List<EntranceEntity> = getUserUseCase.getEntrancesList().fold(
|
||||||
|
onSuccess = { list ->
|
||||||
|
list
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
_state.emit(
|
||||||
|
getUserUseCase.invoke().fold(
|
||||||
|
onSuccess = { data ->
|
||||||
|
Log.d("uraa", "успех успех ${data.toString()}")
|
||||||
|
State.Show(data, entranceList)
|
||||||
|
},
|
||||||
|
onFailure = { error ->
|
||||||
|
Log.d("kaput", error.message.toString())
|
||||||
|
State.Error(error.message.toString())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
//_state.emit(State.Error("о нет ошибка ошибка помогите"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sealed interface State {
|
||||||
|
data object Loading: State
|
||||||
|
data class Show(
|
||||||
|
val profileInfo: UserEntity,
|
||||||
|
val entrancesList : List<EntranceEntity>
|
||||||
|
) : State
|
||||||
|
data class Error(
|
||||||
|
val text: String
|
||||||
|
) : State
|
||||||
|
}
|
||||||
|
companion object {
|
||||||
|
val Factory : ViewModelProvider.Factory = object : ViewModelProvider.Factory {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return ProfileViewModel(
|
||||||
|
getUserUseCase = GetUserUseCase(
|
||||||
|
repo = UserRepoImpl(
|
||||||
|
userNetworkDataSource = UserNetworkDataSource()
|
||||||
|
),
|
||||||
|
authStorageDataSource = AuthStorageDataSource
|
||||||
|
)
|
||||||
|
) as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -106,7 +106,7 @@
|
|||||||
tools:text="Иванова Вера Павловна" />
|
tools:text="Иванова Вера Павловна" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView"
|
android:id="@+id/position"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
@ -118,6 +118,7 @@
|
|||||||
tools:text="Должность: Разработчик" />
|
tools:text="Должность: Разработчик" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/lastEntry"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
@ -125,7 +126,7 @@
|
|||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16dp"
|
android:textSize="16dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView"
|
app:layout_constraintTop_toBottomOf="@+id/position"
|
||||||
tools:text="Время последнего входа: 12:00 16.09" />
|
tools:text="Время последнего входа: 12:00 16.09" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
@ -167,6 +168,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
android:id="@+id/view"
|
||||||
android:layout_width="1dp"
|
android:layout_width="1dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginTop="7dp"
|
android:layout_marginTop="7dp"
|
||||||
@ -189,25 +191,70 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="20dp"
|
android:layout_height="20dp"
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:elevation="10dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/entry_time"
|
android:text="@string/entry_time"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/view2"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/view3"
|
app:layout_constraintEnd_toStartOf="@+id/view3"
|
||||||
app:layout_constraintHorizontal_bias="0.51"
|
app:layout_constraintHorizontal_bias="0.51"
|
||||||
app:layout_constraintStart_toStartOf="@+id/view2"
|
app:layout_constraintStart_toStartOf="@+id/view2"
|
||||||
app:layout_constraintTop_toTopOf="@+id/view2"
|
app:layout_constraintTop_toTopOf="@+id/view2" />
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:elevation="10dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/entry"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/view"
|
||||||
|
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/view3"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/view2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:elevation="10dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/type_of_entrance"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/view"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/view2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_data"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="28dp"
|
||||||
|
android:text="@string/no_data"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.498"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/view2" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
17
app/src/main/res/navigation/main_admin_nav_graph.xml
Normal file
17
app/src/main/res/navigation/main_admin_nav_graph.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/admin_main_nav_graph">
|
||||||
|
|
||||||
|
<!--<fragment
|
||||||
|
android:id="@+id/fragment_profile"
|
||||||
|
android:name=""
|
||||||
|
android:label="Profile"
|
||||||
|
tools:layout="@layout/fragment_profile" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/fragment_user_list"
|
||||||
|
android:name="ru.sicampus.bootcamp2025.ui.userList.FreeVolunteersListFragment"
|
||||||
|
android:label="UserList"
|
||||||
|
tools:layout="@layout/fragment_free_volunteers_list" />-->
|
||||||
|
|
||||||
|
</navigation>
|
@ -10,4 +10,7 @@
|
|||||||
<string name="error_unknown">Непредвиденная ошибка</string>
|
<string name="error_unknown">Непредвиденная ошибка</string>
|
||||||
<string name="entry_history">История входов\n</string>
|
<string name="entry_history">История входов\n</string>
|
||||||
<string name="entry_time">Время входа\n</string>
|
<string name="entry_time">Время входа\n</string>
|
||||||
|
<string name="entry">Вход</string>
|
||||||
|
<string name="type_of_entrance">Тип прохода</string>
|
||||||
|
<string name="no_data">Нет данных\n</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user