feat: last commit

This commit is contained in:
a1pha 2025-02-20 16:54:50 +03:00
parent 9d45790735
commit 5297d47340
14 changed files with 171 additions and 103 deletions

View File

@ -1,5 +1,6 @@
package ru.myitschool.work.data
import android.util.Log
import ru.myitschool.work.data.dto.PassDto
import ru.myitschool.work.data.local.CredentialsLocalDataSource
import ru.myitschool.work.data.network.PassNetworkDataSource

View File

@ -77,7 +77,7 @@ class UserRepositoryImpl(
override suspend fun getUserByLogin(login: String): Result<UserEntity> {
return networkDataSource.getUserByLogin(login, credentialsLocalDataSource.getToken()).fold(
onSuccess = { map(it) }, onFailure = { error(it) }
onSuccess = { map(it) }, onFailure = { Result.failure(it) }
)
}
}

View File

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

View File

@ -15,7 +15,7 @@ object AdminNetworkDataSource {
suspend fun blockUser(login: String, token: String): Result<Unit> =
withContext(Dispatchers.IO) {
runCatching {
val response = client.patch("$SERVER_ADDRESS/api/employees/block?login=$login") {
val response = client.patch("$SERVER_ADDRESS/api/users/block?username=$login") {
headers {
append(HttpHeaders.Authorization, token)
}
@ -30,7 +30,7 @@ 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") {
val response = client.patch("$SERVER_ADDRESS/api/users/unblock?username=$login") {
headers {
append(HttpHeaders.Authorization, token)
}

View File

@ -52,13 +52,13 @@ object UserNetworkDataSource {
withContext(Dispatchers.IO) {
runCatching {
val response =
KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/employees/find?${login}") {
KtorClient.client.get("${Constants.SERVER_ADDRESS}/api/users/get?username=${login}") {
headers {
append(HttpHeaders.Authorization, token)
}
}
if (response.status == HttpStatusCode.OK)
if (response.status != HttpStatusCode.OK)
error("Status ${response.status}")
response.body()
}

View File

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentFindEmployeeBinding
import ru.myitschool.work.utils.collectWithLifecycle
@ -23,7 +24,7 @@ class AdminFragment : Fragment(R.layout.fragment_find_employee) {
when (state) {
is AdminViewModel.State.Error -> binding.error.text = state.errorMessage
is AdminViewModel.State.Loading -> Unit
is AdminViewModel.State.Show -> {}
is AdminViewModel.State.Show -> findNavController().navigate(R.id.action_adminFragment_to_viewUserAsAdminFragment)
is AdminViewModel.State.Waiting -> Unit
}
}
@ -31,7 +32,6 @@ class AdminFragment : Fragment(R.layout.fragment_find_employee) {
binding.find.setOnClickListener {
viewModel.onFind(binding.username.text.toString())
}
}
override fun onDestroy() {

View File

@ -38,10 +38,10 @@ class AdminViewModel(
private val _state = MutableStateFlow<State>(State.Waiting)
val state = _state.asStateFlow()
private var _listState: Flow<PagingData<PassEntity>>? = null
val listState: Flow<PagingData<PassEntity>> get() = _listState!!
// private var _listState: Flow<PagingData<PassEntity>>? = null
// val listState: Flow<PagingData<PassEntity>> get() = _listState!!
private var currentLogin: String? = null
private var currentLogin: String = "pivanov"
fun onFind(login: String) {
viewModelScope.launch {
@ -72,16 +72,16 @@ class AdminViewModel(
}
private fun setUpPager(login: String) {
_listState = Pager(
config = PagingConfig(
pageSize = 10,
enablePlaceholders = false,
maxSize = 50
)
) {
UsersPassesPagingSource(getUsersPassesUseCase::invoke, login)
}.flow
.cachedIn(viewModelScope)
// _listState = Pager(
// config = PagingConfig(
// pageSize = 10,
// enablePlaceholders = false,
// maxSize = 50
// )
// ) {
// UsersPassesPagingSource(getUsersPassesUseCase::invoke, login)
// }.flow
// .cachedIn(viewModelScope)
}
fun onBlock() {

View File

@ -49,27 +49,28 @@ class ViewUserAsAdminFragment : Fragment(R.layout.fragment_user) {
is AdminViewModel.State.Error -> binding.error.text = state.errorMessage
is AdminViewModel.State.Waiting -> Unit
}
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()
adapter.refresh()
}
}
// 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()
// adapter.refresh()
}
binding.block.setOnClickListener {
AlertDialog.Builder(requireContext())
.setTitle("Блокировка доступа")

View File

@ -1,15 +1,17 @@
package ru.myitschool.work.ui.profile
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import ru.myitschool.work.databinding.PassItemBinding
import ru.myitschool.work.domain.entities.PassEntity
class PassesListAdapter:
PagingDataAdapter<PassEntity, PassesListAdapter.ViewHolder>(CenterDiff) {
ListAdapter<PassEntity, PassesListAdapter.ViewHolder>(CenterDiff) {
class ViewHolder(
private val binding: PassItemBinding,
@ -38,12 +40,6 @@ class PassesListAdapter:
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(
getItem(position) ?: PassEntity(
type = "Загрузка ...",
name = "Терминал №...",
time = "Давным-давно..."
)
)
holder.bind(getItem(position))
}
}

View File

@ -1,5 +1,6 @@
package ru.myitschool.work.ui.profile
import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import ru.myitschool.work.domain.entities.PassEntity
@ -15,12 +16,12 @@ class PassesPagingSource(
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PassEntity> {
val pageNum = params.key ?: 1
val pageNum = params.key ?: 0
return request.invoke(pageNum, params.loadSize).fold(
onSuccess = { value ->
LoadResult.Page(
data = value,
prevKey = (pageNum - 1).takeIf { it >= 0 },
prevKey = (pageNum - 1).takeIf { it > 0 },
nextKey = (pageNum + 1).takeIf { value.size == params.loadSize }
)
},

View File

@ -7,7 +7,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.paging.LoadState
import com.squareup.picasso.Picasso
import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentUserBinding
@ -33,10 +32,10 @@ class UserFragment : Fragment(R.layout.fragment_user) {
viewModel.state.collectWithLifecycle(this) { state ->
binding.refresh.isRefreshing = state is UserViewModel.State.Loading
binding.content.visibleOrGone(state is UserViewModel.State.Show)
Log.d("info", state.toString())
when (state) {
is UserViewModel.State.Loading -> Unit
is UserViewModel.State.Show -> {
adapter.submitList(state.passes)
val user = state.userEntity
binding.scan.visibleOrGone(!user.isCardBlocked)
binding.findUser.visibleOrGone(user.isAdmin)
@ -46,53 +45,39 @@ class UserFragment : Fragment(R.layout.fragment_user) {
Picasso.get().load(user.photoUrl).into(binding.photo)
}
}
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()
adapter.refresh()
}
binding.logout.setOnClickListener {
AlertDialog.Builder(requireContext())
.setTitle("Выход")
.setMessage("Вы уверены, что хотите выйти из аккаунта?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.onLogout()
findNavController().navigate(R.id.action_userFragment_to_loginFragment)
}
.show()
}
binding.findUser.setOnClickListener {
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)
}
}
binding.refresh.setOnRefreshListener {
viewModel.onRefresh()
}
binding.logout.setOnClickListener {
AlertDialog.Builder(requireContext())
.setTitle("Выход")
.setMessage("Вы уверены, что хотите выйти из аккаунта?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.onLogout()
findNavController().navigate(R.id.action_userFragment_to_loginFragment)
}
.show()
}
binding.findUser.setOnClickListener {
findNavController().navigate(R.id.action_userFragment_to_adminFragment)
}
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)
}
}
override fun onDestroy() {

View File

@ -1,5 +1,6 @@
package ru.myitschool.work.ui.profile
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
@ -16,6 +17,7 @@ import ru.myitschool.work.data.local.CredentialsLocalDataSource
import ru.myitschool.work.data.local.UserLocalDataSource
import ru.myitschool.work.data.network.PassNetworkDataSource
import ru.myitschool.work.data.network.UserNetworkDataSource
import ru.myitschool.work.domain.entities.PassEntity
import ru.myitschool.work.domain.entities.UserEntity
import ru.myitschool.work.domain.login.LogoutUseCase
import ru.myitschool.work.domain.passes.GetCurrentPassesUseCase
@ -48,7 +50,14 @@ class UserViewModel(
private fun updateState() {
viewModelScope.launch {
_state.emit(State.Loading)
_state.emit(State.Show(getCurrentUserUseCase()))
_state.emit(
State.Show(
getCurrentUserUseCase(),
getCurrentPassesUseCase(0, 30).getOrNull()!!
)
)
}
}
@ -62,7 +71,7 @@ class UserViewModel(
sealed interface State {
data object Loading : State
data class Show(val userEntity: UserEntity) : State
data class Show(val userEntity: UserEntity, val passes: List<PassEntity>) : State
}
companion object {

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>