fixes / feat: some bugs with dto fixed and block / unblock use case done

This commit is contained in:
a1pha 2025-02-20 15:30:21 +03:00
parent f81befe9bd
commit 3aa012adf9
26 changed files with 191 additions and 95 deletions

@ -7,8 +7,12 @@ import ru.myitschool.work.domain.admin.AdminRepository
class AdminRepositoryImpl( class AdminRepositoryImpl(
private val networkDataSource: AdminNetworkDataSource, private val networkDataSource: AdminNetworkDataSource,
private val localCredentialsLocalDataSource: CredentialsLocalDataSource private val localCredentialsLocalDataSource: CredentialsLocalDataSource
): AdminRepository { ) : AdminRepository {
override suspend fun blockUser(login: String): Result<Unit> { override suspend fun blockUser(login: String): Result<Unit> {
return networkDataSource.blockUser(login, localCredentialsLocalDataSource.getToken()) return networkDataSource.blockUser(login, localCredentialsLocalDataSource.getToken())
} }
override suspend fun unblockUser(login: String): Result<Unit> {
return networkDataSource.unblockUser(login, localCredentialsLocalDataSource.getToken())
}
} }

@ -40,8 +40,8 @@ class PassRepositoryImpl(
return listDto.map { successListDto -> return listDto.map { successListDto ->
successListDto.mapNotNull { dto -> successListDto.mapNotNull { dto ->
PassEntity( PassEntity(
type = dto.type ?: return@mapNotNull null, type = dto.terminal?.type ?: return@mapNotNull null,
name = dto.name ?: return@mapNotNull null, name = dto.terminal.name ?: return@mapNotNull null,
time = dto.time ?: return@mapNotNull null time = dto.time ?: return@mapNotNull null
) )
} }

@ -1,6 +1,7 @@
package ru.myitschool.work.data package ru.myitschool.work.data
import ru.myitschool.work.data.local.CredentialsLocalDataSource import ru.myitschool.work.data.local.CredentialsLocalDataSource
import ru.myitschool.work.data.network.QrNetworkDataSource
import ru.myitschool.work.domain.entities.QrEntity import ru.myitschool.work.domain.entities.QrEntity
import ru.myitschool.work.domain.qr.QrRepository import ru.myitschool.work.domain.qr.QrRepository

@ -21,7 +21,9 @@ class UserRepositoryImpl(
.fold( .fold(
onSuccess = { dto -> onSuccess = { dto ->
map(dto).fold( map(dto).fold(
onSuccess = { userLocalDataSource.cacheData(it) }, onSuccess = {
userLocalDataSource.cacheData(it)
},
onFailure = { error(it) } onFailure = { error(it) }
) )
}, },
@ -32,8 +34,13 @@ class UserRepositoryImpl(
override suspend fun authorize(token: String): Result<Unit> { override suspend fun authorize(token: String): Result<Unit> {
return networkDataSource.login(token).fold( return networkDataSource.login(token).fold(
onSuccess = { Result.success(Unit) }, onSuccess = { dto ->
onFailure = { error -> Result.failure(error) } map(dto).fold(
onSuccess = { Result.success(userLocalDataSource.cacheData(it)) },
onFailure = { Result.failure(it) }
)
},
onFailure = { Result.failure(it) }
) )
} }
@ -54,7 +61,7 @@ class UserRepositoryImpl(
return runCatching { return runCatching {
UserEntity( UserEntity(
name = userDto.name ?: error("Null user name"), name = userDto.name ?: error("Null user name"),
lastVisit = userDto.lastVisit ?: error("Null user lastVisit"), lastVisit = userDto.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 -> isAdmin = userDto.roleId?.let { it ->
@ -62,7 +69,8 @@ class UserRepositoryImpl(
it, it,
credentialsLocalDataSource.getToken() credentialsLocalDataSource.getToken()
).fold(onSuccess = { it }, onFailure = { error(it) }) ).fold(onSuccess = { it }, onFailure = { error(it) })
} ?: error("Null user roleId") } ?: error("Null user roleId"),
isCardBlocked = userDto.isCardBlocked ?: error("Null user isCardBlocked")
) )
} }
} }

@ -6,10 +6,16 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
data class PassDto( data class PassDto(
@SerialName("time")
val time: String?,
@SerialName("localDateTime")
val terminal: TerminalDto?
)
@Serializable
data class TerminalDto(
@SerialName("type") @SerialName("type")
val type: String?, val type: String?,
@SerialName("name") @SerialName("name")
val name: String?, val name: String?
@SerialName("time")
val time: String?
) )

@ -5,7 +5,7 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
data class UserDto( data class UserDto(
@SerialName("roleId") @SerialName("authority_id")
val roleId: Int?, val roleId: Int?,
@SerialName("name") @SerialName("name")
val name: String?, val name: String?,
@ -15,7 +15,7 @@ data class UserDto(
val photoUrl: String?, val photoUrl: String?,
@SerialName("position") @SerialName("position")
val position: String?, val position: String?,
@SerialName("login") @SerialName("username")
val login: String?, val login: String?,
@SerialName("isCardBlocked") @SerialName("isCardBlocked")
val isCardBlocked: Boolean? val isCardBlocked: Boolean?

@ -15,7 +15,7 @@ object AdminNetworkDataSource {
suspend fun blockUser(login: String, token: String): Result<Unit> = suspend fun blockUser(login: String, token: String): Result<Unit> =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
runCatching { runCatching {
val response = client.patch("$SERVER_ADDRESS/api/employees/block&login=${login}") { val response = client.patch("$SERVER_ADDRESS/api/employees/block?login=$login") {
headers { headers {
append(HttpHeaders.Authorization, token) append(HttpHeaders.Authorization, token)
} }
@ -27,4 +27,18 @@ object AdminNetworkDataSource {
} }
} }
suspend fun unblockUser(login: String, token: String): Result<Unit> =
withContext(Dispatchers.IO) {
runCatching {
val response = client.patch("$SERVER_ADDRESS/api/employees/unblock?login=$login") {
headers {
append(HttpHeaders.Authorization, token)
}
}
if (response.status != HttpStatusCode.OK)
error("Status ${response.status}")
Unit
}
}
} }

@ -21,7 +21,7 @@ object PassNetworkDataSource {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
runCatching { runCatching {
val response = val response =
client.get("$SERVER_ADDRESS/api/passes?pageNum=$pageNum&pageSize=$pageSize") { client.get("$SERVER_ADDRESS/api/passes/paginated/?page=$pageNum&size=$pageSize") {
headers { headers {
append(HttpHeaders.Authorization, token) append(HttpHeaders.Authorization, token)
} }

@ -1,4 +1,4 @@
package ru.myitschool.work.data package ru.myitschool.work.data.network
import io.ktor.client.request.headers import io.ktor.client.request.headers
import io.ktor.client.request.patch import io.ktor.client.request.patch
@ -11,28 +11,25 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import ru.myitschool.work.core.Constants import ru.myitschool.work.core.Constants
import ru.myitschool.work.data.dto.QrDto import ru.myitschool.work.data.dto.QrDto
import ru.myitschool.work.data.network.KtorClient
import ru.myitschool.work.domain.entities.QrEntity import ru.myitschool.work.domain.entities.QrEntity
object QrNetworkDataSource { object QrNetworkDataSource {
suspend fun pushQr(qrEntity: QrEntity, token: String): Result<Unit> = withContext(Dispatchers.IO) { suspend fun pushQr(qrEntity: QrEntity, token: String): Result<Unit> =
withContext(Dispatchers.IO) {
runCatching { runCatching {
val response = KtorClient.client.patch("${Constants.SERVER_ADDRESS}/api/push_qr") {
headers {
append(HttpHeaders.Authorization, token)
}
contentType(ContentType.Application.Json)
setBody(
QrDto(code = qrEntity.code)
)
val response =
KtorClient.client.patch("${Constants.SERVER_ADDRESS}/api/open") {
headers {
append(HttpHeaders.Authorization, token)
}
contentType(ContentType.Application.Json)
setBody(QrDto(qrEntity.code))
}
if (response.status != HttpStatusCode.OK)
error("Status ${response.status}")
Unit
} }
if (response.status != HttpStatusCode.OK)
error("Status ${response.status}")
Unit
} }
}
} }

@ -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/employees/$login") val result = KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/users/username/$login")
result.status == HttpStatusCode.OK result.status == HttpStatusCode.OK
} }
} }
@ -23,7 +23,7 @@ object UserNetworkDataSource {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
runCatching { runCatching {
val result = val result =
KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/employees/login") { KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/users/login") {
headers { headers {
append(HttpHeaders.Authorization, token) append(HttpHeaders.Authorization, token)
} }
@ -38,7 +38,7 @@ object UserNetworkDataSource {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
runCatching { runCatching {
val response = val response =
KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/roles/info?$roleId") { KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/authority/$roleId") {
headers { headers {
append(HttpHeaders.Authorization, token) append(HttpHeaders.Authorization, token)
} }

@ -2,4 +2,5 @@ package ru.myitschool.work.domain.admin
interface AdminRepository { interface AdminRepository {
suspend fun blockUser(login: String): Result<Unit> suspend fun blockUser(login: String): Result<Unit>
suspend fun unblockUser(login: String): Result<Unit>
} }

@ -0,0 +1,8 @@
package ru.myitschool.work.domain.admin
class UnblockUserUseCase(
private val repository: AdminRepository
) {
suspend operator fun invoke(login: String) = repository.unblockUser(login)
}

@ -6,5 +6,5 @@ data class UserEntity(
val lastVisit: String, val lastVisit: String,
val photoUrl: String, val photoUrl: String,
val position: String, val position: String,
val isCardBlocked: Boolean
) )

@ -21,6 +21,7 @@ import ru.myitschool.work.data.network.AdminNetworkDataSource
import ru.myitschool.work.data.network.PassNetworkDataSource import ru.myitschool.work.data.network.PassNetworkDataSource
import ru.myitschool.work.data.network.UserNetworkDataSource import ru.myitschool.work.data.network.UserNetworkDataSource
import ru.myitschool.work.domain.admin.BlockUserUseCase import ru.myitschool.work.domain.admin.BlockUserUseCase
import ru.myitschool.work.domain.admin.UnblockUserUseCase
import ru.myitschool.work.domain.entities.PassEntity import ru.myitschool.work.domain.entities.PassEntity
import ru.myitschool.work.domain.entities.UserEntity import ru.myitschool.work.domain.entities.UserEntity
import ru.myitschool.work.domain.passes.GetUsersPassesUseCase import ru.myitschool.work.domain.passes.GetUsersPassesUseCase
@ -30,6 +31,7 @@ import ru.myitschool.work.ui.admin.view.UsersPassesPagingSource
class AdminViewModel( class AdminViewModel(
private val getUserByLoginUseCase: GetUserByLoginUseCase, private val getUserByLoginUseCase: GetUserByLoginUseCase,
private val getUsersPassesUseCase: GetUsersPassesUseCase, private val getUsersPassesUseCase: GetUsersPassesUseCase,
private val unBlockUserUseCase: UnblockUserUseCase,
private val blockUserUseCase: BlockUserUseCase private val blockUserUseCase: BlockUserUseCase
) : ViewModel() { ) : ViewModel() {
@ -88,6 +90,12 @@ class AdminViewModel(
} }
} }
fun unblock() {
viewModelScope.launch {
unBlockUserUseCase(currentLogin!!)
}
}
sealed interface State { sealed interface State {
data class Show(val user: UserEntity) : State data class Show(val user: UserEntity) : State
data object Waiting : State data object Waiting : State
@ -100,6 +108,10 @@ class AdminViewModel(
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory { val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T { override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
val adminRepository = AdminRepositoryImpl(
networkDataSource = AdminNetworkDataSource,
localCredentialsLocalDataSource = CredentialsLocalDataSource.getInstance()
)
return AdminViewModel( return AdminViewModel(
getUserByLoginUseCase = GetUserByLoginUseCase( getUserByLoginUseCase = GetUserByLoginUseCase(
repository = UserRepositoryImpl( repository = UserRepositoryImpl(
@ -115,10 +127,10 @@ class AdminViewModel(
) )
), ),
blockUserUseCase = BlockUserUseCase( blockUserUseCase = BlockUserUseCase(
repository = AdminRepositoryImpl( repository = adminRepository
networkDataSource = AdminNetworkDataSource, ),
localCredentialsLocalDataSource = CredentialsLocalDataSource.getInstance() unBlockUserUseCase = UnblockUserUseCase(
) repository = adminRepository
) )
) as T ) as T
} }

@ -26,20 +26,20 @@ class ViewUserAsAdminFragment : Fragment(R.layout.fragment_user) {
binding.findUser.visibleOrGone(false) binding.findUser.visibleOrGone(false)
binding.logout.visibleOrGone(false) binding.logout.visibleOrGone(false)
binding.block.visibleOrGone(true)
val adapter = PassesListAdapter() val adapter = PassesListAdapter()
binding.passes.adapter = adapter binding.passes.adapter = adapter
viewModel.state.collectWithLifecycle(this) { state -> viewModel.state.collectWithLifecycle(this) { state ->
binding.refresh.isRefreshing = state is AdminViewModel.State.Loading binding.refresh.isRefreshing = state is AdminViewModel.State.Loading
binding.content?.visibleOrGone(state is AdminViewModel.State.Show) binding.content.visibleOrGone(state is AdminViewModel.State.Show)
when (state) { when (state) {
is AdminViewModel.State.Loading -> Unit is AdminViewModel.State.Loading -> Unit
is AdminViewModel.State.Show -> { is AdminViewModel.State.Show -> {
val user = state.user val user = state.user
binding.findUser.visibleOrGone(user.isAdmin) binding.block.visibleOrGone(!user.isCardBlocked)
binding.unblock.visibleOrGone(user.isCardBlocked)
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
@ -79,6 +79,10 @@ class ViewUserAsAdminFragment : Fragment(R.layout.fragment_user) {
.show() .show()
} }
binding.unblock.setOnClickListener {
viewModel.unblock()
}
} }
override fun onDestroy() { override fun onDestroy() {

@ -9,14 +9,10 @@ import androidx.navigation.fragment.findNavController
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.core.Constants import ru.myitschool.work.core.Constants
import ru.myitschool.work.data.local.CredentialsLocalDataSource import ru.myitschool.work.data.local.CredentialsLocalDataSource
import ru.myitschool.work.databinding.FragmentSplashBinding
import ru.myitschool.work.utils.collectWithLifecycle import ru.myitschool.work.utils.collectWithLifecycle
class SplashFragment : Fragment(R.layout.fragment_splash) { class SplashFragment : Fragment(R.layout.fragment_splash) {
private var _binding: FragmentSplashBinding? = null
private val binding: FragmentSplashBinding get() = _binding!!
private val viewModel by viewModels<LoginViewModel> { LoginViewModel.Factory } private val viewModel by viewModels<LoginViewModel> { LoginViewModel.Factory }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -30,21 +26,15 @@ class SplashFragment : Fragment(R.layout.fragment_splash) {
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentSplashBinding.bind(view)
viewModel.action.collectWithLifecycle(this) { action -> viewModel.action.collectWithLifecycle(this) { action ->
val navController = findNavController() val navController = findNavController()
when (action) { when (action) {
is LoginViewModel.Action.GoToLogin -> navController.navigate(R.id.loginFragment) is LoginViewModel.Action.GoToLogin -> navController.navigate(R.id.loginFragment)
is LoginViewModel.Action.OpenApp -> is LoginViewModel.Action.OpenApp ->
navController.navigate(R.id.action_loginFragment_to_userFragment) navController.navigate(R.id.action_splashFragment_to_userFragment)
} }
} }
} }
override fun onDestroy() {
_binding = null
super.onDestroy()
}
} }

@ -15,7 +15,7 @@ class PassesPagingSource(
} }
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PassEntity> { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PassEntity> {
val pageNum = params.key ?: 0 val pageNum = params.key ?: 1
return request.invoke(pageNum, params.loadSize).fold( return request.invoke(pageNum, params.loadSize).fold(
onSuccess = { value -> onSuccess = { value ->
LoadResult.Page( LoadResult.Page(

@ -1,6 +1,7 @@
package ru.myitschool.work.ui.profile package ru.myitschool.work.ui.profile
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View import android.view.View
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -10,9 +11,12 @@ 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
import ru.myitschool.work.ui.qr.result.RESPONSE_KEY
import ru.myitschool.work.ui.qr.scan.QrScanDestination
import ru.myitschool.work.utils.collectWithLifecycle import ru.myitschool.work.utils.collectWithLifecycle
import ru.myitschool.work.utils.visibleOrGone import ru.myitschool.work.utils.visibleOrGone
class UserFragment : Fragment(R.layout.fragment_user) { class UserFragment : Fragment(R.layout.fragment_user) {
private var _binding: FragmentUserBinding? = null private var _binding: FragmentUserBinding? = null
@ -28,11 +32,13 @@ class UserFragment : Fragment(R.layout.fragment_user) {
viewModel.state.collectWithLifecycle(this) { state -> viewModel.state.collectWithLifecycle(this) { state ->
binding.refresh.isRefreshing = state is UserViewModel.State.Loading binding.refresh.isRefreshing = state is UserViewModel.State.Loading
binding.content?.visibleOrGone(state is UserViewModel.State.Show) binding.content.visibleOrGone(state is UserViewModel.State.Show)
Log.d("info", state.toString())
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.scan.visibleOrGone(!user.isCardBlocked)
binding.findUser.visibleOrGone(user.isAdmin) 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
@ -65,14 +71,27 @@ class UserFragment : Fragment(R.layout.fragment_user) {
.setTitle("Выход") .setTitle("Выход")
.setMessage("Вы уверены, что хотите выйти из аккаунта?") .setMessage("Вы уверены, что хотите выйти из аккаунта?")
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.onLogout() } .setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.onLogout()
findNavController().navigate(R.id.action_userFragment_to_loginFragment)
}
.show() .show()
findNavController().navigate(R.id.action_userFragment_to_loginFragment)
} }
binding.findUser.setOnClickListener { binding.findUser.setOnClickListener {
findNavController().navigate(R.id.find_user) findNavController().navigate(R.id.find_user)
} }
binding.scan.setOnClickListener {
findNavController().navigate(R.id.action_userFragment_to_qrScanFragment)
}
parentFragmentManager.setFragmentResultListener(
QrScanDestination.REQUEST_KEY, this
) { _, result ->
parentFragmentManager.setFragmentResult(RESPONSE_KEY, result)
findNavController().navigate(R.id.action_userFragment_to_qrResultFragment)
}
} }
} }

@ -47,7 +47,8 @@ class UserViewModel(
private fun updateState() { private fun updateState() {
viewModelScope.launch { viewModelScope.launch {
State.Show(getCurrentUserUseCase()) _state.emit(State.Loading)
_state.emit(State.Show(getCurrentUserUseCase()))
} }
} }

@ -8,7 +8,7 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentQrResultBinding import ru.myitschool.work.databinding.FragmentQrResultBinding
import ru.myitschool.work.ui.qr.scan.QrScanDestination import ru.myitschool.work.domain.entities.QrEntity
import ru.myitschool.work.ui.qr.scan.QrScanDestination.getDataIfExist import ru.myitschool.work.ui.qr.scan.QrScanDestination.getDataIfExist
import ru.myitschool.work.utils.collectWithLifecycle import ru.myitschool.work.utils.collectWithLifecycle
@ -20,25 +20,18 @@ class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
private var _binding: FragmentQrResultBinding? = null private var _binding: FragmentQrResultBinding? = null
private val binding: FragmentQrResultBinding get() = _binding!! private val binding: FragmentQrResultBinding get() = _binding!!
private var _resultQr: String? = null
private val resultQr: String = _resultQr!!
private val viewModel by viewModels<QrResultViewModel> { QrResultViewModel.Factory } private val viewModel by viewModels<QrResultViewModel> { QrResultViewModel.Factory }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentQrResultBinding.bind(view) _binding = FragmentQrResultBinding.bind(view)
if (savedInstanceState != null) {
_resultQr = savedInstanceState.getString(QrScanDestination.REQUEST_KEY)
}
parentFragmentManager.setFragmentResultListener(RESPONSE_KEY, this) { _, result -> parentFragmentManager.setFragmentResultListener(RESPONSE_KEY, this) { _, result ->
_resultQr = getDataIfExist(result) getDataIfExist(result)?.let { viewModel.setQr(QrEntity(it)) }
viewModel.update(resultQr) viewModel.update()
} }
viewModel.state.collectWithLifecycle(this) { state -> viewModel.state.collectWithLifecycle(this) { state ->
if (_resultQr == null) { if (viewModel._qrEntity == null) {
binding.result.setText(R.string.door_closed) binding.result.setText(R.string.door_closed)
binding.close.background = binding.close.background =
ContextCompat.getDrawable(requireContext(), R.drawable.warn_button) ContextCompat.getDrawable(requireContext(), R.drawable.warn_button)
@ -65,12 +58,6 @@ class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
} }
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(QrScanDestination.REQUEST_KEY, resultQr)
}
override fun onDestroy() { override fun onDestroy() {
_binding = null _binding = null
super.onDestroy() super.onDestroy()

@ -7,7 +7,7 @@ import androidx.lifecycle.viewmodel.CreationExtras
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.myitschool.work.data.QrNetworkDataSource import ru.myitschool.work.data.network.QrNetworkDataSource
import ru.myitschool.work.data.QrRepositoryImpl import ru.myitschool.work.data.QrRepositoryImpl
import ru.myitschool.work.data.local.CredentialsLocalDataSource import ru.myitschool.work.data.local.CredentialsLocalDataSource
import ru.myitschool.work.domain.entities.QrEntity import ru.myitschool.work.domain.entities.QrEntity
@ -20,9 +20,16 @@ class QrResultViewModel(
private val _state = MutableStateFlow<State>(State.Loading) private val _state = MutableStateFlow<State>(State.Loading)
val state = _state.asStateFlow() val state = _state.asStateFlow()
fun update(qrValue: String) { var _qrEntity: QrEntity? = null
private val qrEntity: QrEntity get() = _qrEntity!!
fun setQr(qrEntity: QrEntity) {
_qrEntity = qrEntity
}
fun update() {
viewModelScope.launch { viewModelScope.launch {
pushQrUseCase(QrEntity(code = qrValue)).fold( pushQrUseCase(qrEntity).fold(
onSuccess = { _state.emit(State.Show) }, onSuccess = { _state.emit(State.Show) },
onFailure = { _state.emit(State.Error(it.message.toString())) } onFailure = { _state.emit(State.Error(it.message.toString())) }
) )

@ -14,6 +14,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginHorizontal="20dp" android:layout_marginHorizontal="20dp"
@ -132,7 +133,21 @@
android:background="@drawable/warn_button_outline" android:background="@drawable/warn_button_outline"
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:text="@string/block_card_button_text" android:text="@string/block_card_button_text"
android:textColor="@color/warn_button_color" /> android:textColor="@color/warn_button_color"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/unblock"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:background="@drawable/main_button_outline"
android:foreground="?attr/selectableItemBackground"
android:text="@string/unblock_card_button_text"
android:textColor="@color/main_button_color"
android:visibility="gone" />
<ImageButton <ImageButton
android:id="@+id/logout" android:id="@+id/logout"

@ -1,9 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="@color/warn_button_color"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Some error" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refresh" android:id="@+id/refresh"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -95,15 +107,6 @@
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:text="@string/scan_qr_text" android:text="@string/scan_qr_text"
android:textColor="@color/white" /> android:textColor="@color/white" />
<TextView
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="@color/warn_button_color"
android:visibility="gone"
tools:text="Some error" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -123,8 +126,20 @@
android:text="@string/block_card_button_text" android:text="@string/block_card_button_text"
android:textColor="@color/warn_button_color" android:textColor="@color/warn_button_color"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
<Button
android:id="@+id/unblock"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:background="@drawable/main_button_outline"
android:foreground="?attr/selectableItemBackground"
android:text="@string/unblock_card_button_text"
android:textColor="@color/main_button_color"
android:visibility="gone" />
<ImageButton <ImageButton
android:id="@+id/logout" android:id="@+id/logout"
android:layout_width="wrap_content" android:layout_width="wrap_content"

@ -65,6 +65,11 @@
<action <action
android:id="@+id/action_splashFragment_to_loginFragment" android:id="@+id/action_splashFragment_to_loginFragment"
app:destination="@id/loginFragment" /> app:destination="@id/loginFragment" />
<action
android:id="@+id/action_splashFragment_to_userFragment"
app:destination="@id/userFragment"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/adminFragment" android:id="@+id/adminFragment"

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">NTO Pass</string> <string name="app_name">QR Pass</string>
<string name="scan_qr_text">Scan QR</string> <string name="scan_qr_text">Scan QR</string>
<string name="login_hint">Enter login</string> <string name="login_hint">Enter login</string>
<string name="welcome_text">Welcome to NTO Pass app</string> <string name="welcome_text">Welcome to\nQR Pass app</string>
<string name="login">Login</string> <string name="login">Login</string>
<string name="refresh_data">Refresh</string> <string name="refresh_data">Refresh</string>
<string name="to_main_menu">Close</string> <string name="to_main_menu">Close</string>
@ -21,4 +21,5 @@
<string name="offline_error">Seems you are offline...</string> <string name="offline_error">Seems you are offline...</string>
<string name="no_internet_instructions">Check your internet connection\\nand try again</string> <string name="no_internet_instructions">Check your internet connection\\nand try again</string>
<string name="reload_text">" Reload"</string> <string name="reload_text">" Reload"</string>
<string name="unblock_card_button_text">Unblock card</string>
</resources> </resources>

@ -1,8 +1,8 @@
<resources> <resources>
<string name="app_name">NTO Pass</string> <string name="app_name">QR Pass</string>
<string name="scan_qr_text">Сканировать QR-код</string> <string name="scan_qr_text">Сканировать QR-код</string>
<string name="login_hint">Введите логин</string> <string name="login_hint">Введите логин</string>
<string name="welcome_text">Добро пожаловать в NTO Pass</string> <string name="welcome_text">Добро пожаловать в\nQR Pass</string>
<string name="login">Войти</string> <string name="login">Войти</string>
<string name="refresh_data">Обновить данные</string> <string name="refresh_data">Обновить данные</string>
<string name="to_main_menu">Закрыть</string> <string name="to_main_menu">Закрыть</string>
@ -19,4 +19,5 @@
<string name="offline_error">Кажется вы оффлайн...</string> <string name="offline_error">Кажется вы оффлайн...</string>
<string name="no_internet_instructions">Проверьте подключение к сети\nи попробуйте еще раз</string> <string name="no_internet_instructions">Проверьте подключение к сети\nи попробуйте еще раз</string>
<string name="reload_text">Перезагрузить</string> <string name="reload_text">Перезагрузить</string>
<string name="unblock_card_button_text">Разблокировать карту</string>
</resources> </resources>