feat: LoginUseCase done

This commit is contained in:
a1pha 2025-02-19 18:52:20 +03:00
parent 3298dd98b4
commit 16199d485e
8 changed files with 148 additions and 52 deletions

View File

@ -1,6 +1,5 @@
package ru.myitschool.work.data package ru.myitschool.work.data
import android.util.Log
import ru.myitschool.work.data.dto.UserDto import ru.myitschool.work.data.dto.UserDto
import ru.myitschool.work.data.local.CredentialsLocalDataSource import ru.myitschool.work.data.local.CredentialsLocalDataSource
import ru.myitschool.work.data.local.UserLocalDataSource import ru.myitschool.work.data.local.UserLocalDataSource
@ -19,9 +18,15 @@ class UserRepositoryImpl(
return runCatching { return runCatching {
networkDataSource.login(credentialsLocalDataSource.updateToken(login, password)) networkDataSource.login(credentialsLocalDataSource.updateToken(login, password))
.onSuccess { dto -> .fold(
map(dto).onSuccess { userLocalDataSource.cacheData(it) } onSuccess = { dto ->
} map(dto).fold(
onSuccess = { userLocalDataSource.cacheData(it) },
onFailure = { error(it) }
)
},
onFailure = { error(it) }
)
} }
} }
@ -45,15 +50,26 @@ class UserRepositoryImpl(
return userLocalDataSource.getUser()!! return userLocalDataSource.getUser()!!
} }
private fun map(userDto: UserDto): Result<UserEntity> { private suspend fun map(userDto: UserDto): Result<UserEntity> {
return runCatching { return runCatching {
UserEntity( UserEntity(
id = userDto.id ?: error("Null user id"),
name = userDto.name ?: error("Null user name"), name = userDto.name ?: error("Null user name"),
lastVisit = userDto.lastVisit ?: error("Null user lastVisit"), lastVisit = userDto.lastVisit ?: error("Null user lastVisit"),
photoUrl = userDto.photoUrl ?: error("Null user photoUrl"), photoUrl = userDto.photoUrl ?: error("Null user photoUrl"),
position = userDto.position ?: error("Null user position") position = userDto.position ?: error("Null user position"),
isAdmin = userDto.roleId?.let { it ->
networkDataSource.isRoleHasAdminPermissions(
it,
credentialsLocalDataSource.getToken()
).fold(onSuccess = { it }, onFailure = { error(it) })
} ?: error("Null user roleId")
) )
} }
} }
override suspend fun getUserByLogin(login: String): Result<UserEntity> {
return networkDataSource.getUserByLogin(login, credentialsLocalDataSource.getToken()).fold(
onSuccess = { map(it) }, onFailure = { error(it) }
)
}
} }

View File

@ -1,31 +1,22 @@
package ru.myitschool.work.data.dto; package ru.myitschool.work.data.dto
import kotlinx.serialization.SerialName
import androidx.annotation.Nullable; import kotlinx.serialization.Serializable
import com.google.gson.annotations.SerializedName;
import kotlinx.serialization.Serializable;
@Serializable @Serializable
public class UserDto { data class UserDto(
@SerialName("roleId")
@Nullable val roleId: Int?,
@SerializedName("id") @SerialName("name")
public String id; val name: String?,
@Nullable @SerialName("lastVisit")
@SerializedName("name") val lastVisit: String?,
public String name; @SerialName("photo")
@Nullable val photoUrl: String?,
@SerializedName("lastVisit") @SerialName("position")
public String lastVisit; val position: String?,
@Nullable @SerialName("login")
@SerializedName("photo") val login: String?,
public String photoUrl; @SerialName("isCardBlocked")
@Nullable val isCardBlocked: Boolean?
@SerializedName("position") )
public String position;
@Nullable
@SerializedName("login")
public String login;
}

View File

@ -14,7 +14,7 @@ object UserNetworkDataSource {
suspend fun isUserExist(login: String): Result<Boolean> = withContext(Dispatchers.IO) { suspend fun isUserExist(login: String): Result<Boolean> = withContext(Dispatchers.IO) {
runCatching { runCatching {
val result = KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/users/username/$login") val result = KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/employees/$login")
result.status == HttpStatusCode.OK result.status == HttpStatusCode.OK
} }
} }
@ -22,16 +22,45 @@ object UserNetworkDataSource {
suspend fun login(token: String): Result<UserDto> = suspend fun login(token: String): Result<UserDto> =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
runCatching { runCatching {
val result = KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/users/login") { val result =
headers { KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/employees/login") {
append(HttpHeaders.Authorization, token) headers {
append(HttpHeaders.Authorization, token)
}
} }
}
if (result.status != HttpStatusCode.OK) if (result.status != HttpStatusCode.OK)
error("Status ${result.status}") error("Status ${result.status}")
result.body() result.body()
} }
} }
suspend fun getUserByLogin() {} suspend fun isRoleHasAdminPermissions(roleId: Int, token: String): Result<Boolean> =
withContext(Dispatchers.IO) {
runCatching {
val response =
KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/roles/info?$roleId") {
headers {
append(HttpHeaders.Authorization, token)
}
}
response.status == HttpStatusCode.OK
}
}
suspend fun getUserByLogin(login: String, token: String): Result<UserDto> =
withContext(Dispatchers.IO) {
runCatching {
val response =
KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/employees/find?${login}") {
headers {
append(HttpHeaders.Authorization, token)
}
}
if (response.status == HttpStatusCode.OK)
error("Status ${response.status}")
response.body()
}
}
} }

View File

@ -1,9 +1,10 @@
package ru.myitschool.work.domain.entities package ru.myitschool.work.domain.entities
data class UserEntity( data class UserEntity(
val id: String, val isAdmin: Boolean,
val name: String, val name: String,
val lastVisit: String, val lastVisit: String,
val photoUrl: String, val photoUrl: String,
val position: String, val position: String,
) )

View File

@ -0,0 +1,10 @@
package ru.myitschool.work.domain.user
import ru.myitschool.work.domain.entities.UserEntity
class GetUserByLoginUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(login: String): Result<UserEntity> = repository.getUserByLogin(login)
}

View File

@ -5,4 +5,5 @@ import ru.myitschool.work.domain.entities.UserEntity
interface UserRepository { interface UserRepository {
suspend fun getCurrentUser(): UserEntity suspend fun getCurrentUser(): UserEntity
suspend fun getUserByLogin(login: String) : Result<UserEntity>
} }

View File

@ -1,8 +1,9 @@
package ru.myitschool.work.ui.login package ru.myitschool.work.ui.login
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
@ -32,11 +33,18 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
binding.error.visibleOrGone(state is LoginViewModel.State.Error) binding.error.visibleOrGone(state is LoginViewModel.State.Error)
when (state) { when (state) {
is LoginViewModel.State.Error -> binding.error.text = state.errorMessage is LoginViewModel.State.Error -> {
is LoginViewModel.State.Loading -> Unit binding.error.text = state.errorMessage
setButtonActive()
}
is LoginViewModel.State.Loading -> setButtonInactive()
is LoginViewModel.State.Waiting -> Unit is LoginViewModel.State.Waiting -> Unit
is LoginViewModel.State.LoginCheckCompleted -> binding.login.isEnabled = is LoginViewModel.State.LoginCheckCompleted -> {
state.isCompleted state.isCompleted.let {
if (it) setButtonActive() else setButtonInactive()
binding.login.isEnabled = it
}
}
} }
} }
@ -57,6 +65,18 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
} }
} }
private fun setButtonInactive() {
binding.login.setTextColor(Color.BLACK)
binding.login.background =
ContextCompat.getDrawable(requireContext(), R.drawable.inactive_button)
}
private fun setButtonActive() {
binding.login.setTextColor(Color.WHITE)
binding.login.background =
ContextCompat.getDrawable(requireContext(), R.drawable.main_button)
}
override fun onDestroy() { override fun onDestroy() {
_binding = null _binding = null
super.onDestroy() super.onDestroy()

View File

@ -2,10 +2,11 @@ package ru.myitschool.work.ui.profile
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.paging.LoadState
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentUserBinding import ru.myitschool.work.databinding.FragmentUserBinding
@ -22,14 +23,17 @@ class UserFragment : Fragment(R.layout.fragment_user) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentUserBinding.bind(view) _binding = FragmentUserBinding.bind(view)
val adapter = PassesListAdapter()
binding.passes.adapter = adapter
viewModel.state.collectWithLifecycle(this) { state -> viewModel.state.collectWithLifecycle(this) { state ->
(binding.refresh as SwipeRefreshLayout).isRefreshing = binding.refresh.isRefreshing = state is UserViewModel.State.Loading
state is UserViewModel.State.Loading
binding.content?.visibleOrGone(state is UserViewModel.State.Show) binding.content?.visibleOrGone(state is UserViewModel.State.Show)
when (state) { when (state) {
is UserViewModel.State.Loading -> Unit is UserViewModel.State.Loading -> Unit
is UserViewModel.State.Show -> { is UserViewModel.State.Show -> {
val user = state.userEntity val user = state.userEntity
binding.findUser.visibleOrGone(user.isAdmin)
binding.fullname.text = user.name binding.fullname.text = user.name
binding.position.text = user.position binding.position.text = user.position
binding.lastEntry.text = user.lastVisit binding.lastEntry.text = user.lastVisit
@ -37,14 +41,38 @@ class UserFragment : Fragment(R.layout.fragment_user) {
} }
} }
(binding.refresh as SwipeRefreshLayout).setOnRefreshListener { viewModel.listState.collectWithLifecycle(this) { listState ->
adapter.submitData(listState)
}
adapter.loadStateFlow.collectWithLifecycle(this) { data ->
val dataState = data.refresh
binding.refresh.isRefreshing = dataState is LoadState.Loading
binding.error.visibleOrGone(dataState is LoadState.Error)
if (dataState is LoadState.Error) {
binding.error.text = dataState.error.toString()
}
}
binding.refresh.setOnRefreshListener {
viewModel.onRefresh() viewModel.onRefresh()
adapter.refresh()
} }
binding.logout.setOnClickListener { binding.logout.setOnClickListener {
viewModel.onLogout() AlertDialog.Builder(requireContext())
.setTitle("Выход")
.setMessage("Вы уверены, что хотите выйти из аккаунта?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.onLogout() }
.show()
findNavController().navigate(R.id.action_userFragment_to_loginFragment) findNavController().navigate(R.id.action_userFragment_to_loginFragment)
} }
binding.findUser.setOnClickListener {
findNavController().navigate(R.id.find_user)
}
} }
} }