From 961c37d2659c6d733a2c82ca0091b30b392d88f9 Mon Sep 17 00:00:00 2001 From: Izlydov Date: Wed, 19 Feb 2025 13:00:08 +0300 Subject: [PATCH] Added start logic for visits pagination, changed visits logic, changed Dto objects, added password in login, bug fixes, --- app/build.gradle.kts | 2 +- .../components/auth/models/user/UserEntity.kt | 2 +- .../components/auth/models/user/UserMapper.kt | 4 +- .../auth/models/user/UserServiceST.kt | 27 ++++++++- .../models/user/repository/UserRepository.kt | 58 ++++++++++++++++++- .../models/user/repository/VisitAdapter.kt | 55 ++++++++++++++++++ .../user/repository/VisitListPagingSource.kt | 35 +++++++++++ .../user/repository/dto/LastVisitsDto.kt | 12 ++++ .../models/user/repository/dto/UserDTO.kt | 4 +- .../user/repository/dto/UserLoginDto.kt | 13 +++++ .../models/user/repository/dto/VisitDto.kt | 17 ++++++ .../acss/ui/admin/AdminFragment.kt | 5 ++ .../acss/ui/admin/AdminViewModel.kt | 7 ++- .../displaynone/acss/ui/auth/AuthFragment.kt | 37 +++++++++++- .../displaynone/acss/ui/auth/AuthViewModel.kt | 4 +- .../acss/ui/profile/ProfileFragment.kt | 48 ++++++++++++--- .../acss/ui/profile/ProfileViewModel.kt | 27 +++++++++ 17 files changed, 334 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitAdapter.kt create mode 100644 app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitListPagingSource.kt create mode 100644 app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LastVisitsDto.kt create mode 100644 app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt create mode 100644 app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/VisitDto.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d042a44..d7fa690 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -39,7 +39,7 @@ android { } dependencies { - + implementation("androidx.paging:paging-runtime:3.3.2") val cameraX = "1.3.4" implementation("androidx.camera:camera-core:$cameraX") implementation("androidx.camera:camera-camera2:$cameraX") diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserEntity.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserEntity.kt index b71e508..ca03eba 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserEntity.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserEntity.kt @@ -6,5 +6,5 @@ data class UserEntity( val name: String, val photo: String, val position: String, - val lastVisit: String, +// val lastVisit: String, ) \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserMapper.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserMapper.kt index 75be2eb..633f8ac 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserMapper.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserMapper.kt @@ -10,7 +10,7 @@ class UserMapper { login = userDTO.login, position = userDTO.position, name = userDTO.name, - lastVisit = userDTO.lastVisit, +// lastVisit = userDTO.lastVisit, photo = userDTO.photo ) return userEntity @@ -22,7 +22,7 @@ class UserMapper { name = userEntity.name, photo = userEntity.photo, position = userEntity.position, - lastVisit = userEntity.lastVisit, +// lastVisit = userEntity.lastVisit, ) return userDto } diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt index 70b2b55..22e5cb1 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt @@ -3,7 +3,9 @@ package com.displaynone.acss.components.auth.models.user import android.content.Context import com.displaynone.acss.components.auth.internal_utils.AuthTokenManager import com.displaynone.acss.components.auth.models.user.repository.UserRepository +import com.displaynone.acss.components.auth.models.user.repository.dto.LastVisitsDto import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO +import com.displaynone.acss.components.auth.models.user.repository.dto.VisitDto class UserServiceST( @@ -28,13 +30,34 @@ class UserServiceST( return instance ?: throw RuntimeException("null instance") } } - suspend fun login(login: String): Result{ + suspend fun login(login: String, password:String): Result{ return runCatching { - userRepository.login(login = login).getOrThrow().let { data -> + userRepository.login(login = login, password).getOrThrow().let { data -> tokenManager.saveTokens(data) } } } + suspend fun getMyLastVisits(pageNum: Int, + pageSize: Int): Result> { + if (!tokenManager.hasTokens()) { + throw RuntimeException("access token is null") + } + + return userRepository.getMyLastVisits( + pageNum = pageNum, + pageSize = pageSize, + token = tokenManager.authTokenPair!!.accessToken + ).map { pagingDto -> pagingDto.content + } + } + suspend fun getLastVisitsByLogin(pageNum: Int, + pageSize: Int, + login: String): Result> { + if (!tokenManager.hasTokens()) { + throw RuntimeException("access token is null") + } + return userRepository.getLastVisitsByLogin(pageNum, pageSize, tokenManager.authTokenPair!!.accessToken, login).map { pagingDto -> pagingDto.content } + } fun logout(){ tokenManager.clear() } diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt index 1f7ab2c..159ea88 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt @@ -2,10 +2,12 @@ package com.displaynone.acss.components.auth.models.user.repository import android.util.Log import com.displaynone.acss.components.auth.models.AuthTokenPair +import com.displaynone.acss.components.auth.models.user.repository.dto.LastVisitsDto import com.displaynone.acss.config.Constants.serverUrl import com.displaynone.acss.config.Network import com.displaynone.acss.components.auth.models.user.repository.dto.RegisterUserDto import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO +import com.displaynone.acss.components.auth.models.user.repository.dto.UserLoginDto import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.headers @@ -33,13 +35,14 @@ class UserRepository( result.status != HttpStatusCode.OK } } - suspend fun login(login: String): Result = withContext(Dispatchers.IO) { + suspend fun login(login: String, password: String): Result = withContext(Dispatchers.IO) { runCatching { val result = Network.client.post("$serverUrl/api/auth/login") { headers { append(HttpHeaders.ContentType, ContentType.Application.Json.toString()) } - setBody("""{ "login": "$login" }""") + contentType(ContentType.Application.Json) + setBody(UserLoginDto(login, password)) } if (result.status != HttpStatusCode.OK) { error("Status ${result.status}: ${result.body()}") @@ -99,6 +102,57 @@ class UserRepository( result.body() } } + suspend fun getMyLastVisits(pageNum: Int, + pageSize: Int, + token: String): Result = withContext(Dispatchers.IO){ + runCatching { + val result = Network.client.get("$serverUrl/api/acs/visits/me?page=$pageNum&size=$pageSize") { + headers { + append(HttpHeaders.Authorization, "Bearer $token") + } + } + Log.d("UserRepository", result.bodyAsText()) + if (result.status != HttpStatusCode.OK) { + error("Status ${result.status}: ${result.body()}") + } + + result.body() + } + } + suspend fun getLastVisitsByLogin(pageNum: Int, + pageSize: Int, + token: String, login: String): Result = withContext(Dispatchers.IO){ + runCatching { + val encodedLogin = login.encodeURLPath() + val result = Network.client.get("$serverUrl/api/acs/login/${encodedLogin}?page=$pageNum&size=$pageSize") { + headers { + append(HttpHeaders.Authorization, "Bearer $token") + } + setBody("""{ "login": "$encodedLogin" }""") + } + if (result.status != HttpStatusCode.OK) { + error("Status ${result.status}: ${result.body()}") + } + Log.d("UserRepository", result.bodyAsText()) + result.body() + } + } + suspend fun getAllLastVisitsAsAdmin(token: String, login: String): Result = withContext(Dispatchers.IO){ + runCatching { + val encodedLogin = login.encodeURLPath() + val result = Network.client.get("$serverUrl/api/users/login/$encodedLogin") { + headers { + append(HttpHeaders.Authorization, "Bearer $token") + } + setBody("""{ "code": "$encodedLogin" }""") + } + if (result.status != HttpStatusCode.OK) { + error("Status ${result.status}: ${result.body()}") + } + Log.d("UserRepository", result.bodyAsText()) + result.body() + } + } suspend fun openDoor(token: String, code: Long): Result = withContext(Dispatchers.IO) { runCatching { val result = Network.client.patch("$serverUrl/api/open") { diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitAdapter.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitAdapter.kt new file mode 100644 index 0000000..4b7241e --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitAdapter.kt @@ -0,0 +1,55 @@ +package com.displaynone.acss.components.auth.models.user.repository + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.paging.PagingDataAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.displaynone.acss.components.auth.models.user.repository.dto.VisitDto +import com.displaynone.acss.databinding.ItemScannerViewBinding + +class VisitAdapter: PagingDataAdapter(VisitDiff) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + ItemScannerViewBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(getItem(position) ?: + VisitDto( + id = -1, + userId = -1, + gateId = -1, + createdAt = "Loading...", + )) + } + + + class ViewHolder( + private val binding: ItemScannerViewBinding + ): RecyclerView.ViewHolder(binding.root) { + fun bind(item: VisitDto){ + binding.scanTime.text = item.createdAt + binding.scannerId.text = item.gateId.toString() + } + } + + object VisitDiff : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: VisitDto, newItem: VisitDto): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: VisitDto, newItem: VisitDto): Boolean { + return oldItem == newItem + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitListPagingSource.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitListPagingSource.kt new file mode 100644 index 0000000..c80f861 --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/VisitListPagingSource.kt @@ -0,0 +1,35 @@ +package com.displaynone.acss.components.auth.models.user.repository + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.displaynone.acss.components.auth.models.user.repository.dto.VisitDto + +class VisitListPagingSource( + private val request: suspend (pageNum: Int, pageSize: Int) -> Result> +) : PagingSource() { + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition?.let { + state.closestPageToPosition(it)?.prevKey?.plus(1) + ?: state.closestPageToPosition(it)?.nextKey?.minus(1) + } + } + + override suspend fun load(params: LoadParams): LoadResult { + val pageNum = params.key ?: 0 + return request.invoke( + pageNum, + params.loadSize + ).fold( + onSuccess = { value -> + LoadResult.Page( + data = value, + prevKey = (pageNum - 1).takeIf { it >= 0 }, + nextKey = (pageNum + 1).takeIf { value.size == params.loadSize } + ) + }, + onFailure = { error -> + LoadResult.Error(error) + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LastVisitsDto.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LastVisitsDto.kt new file mode 100644 index 0000000..dea6502 --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LastVisitsDto.kt @@ -0,0 +1,12 @@ +package com.displaynone.acss.components.auth.models.user.repository.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class LastVisitsDto( + @SerialName("content") + val content: List +) { +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt index 1b97fdf..79a9c32 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt @@ -21,6 +21,6 @@ data class UserDTO ( @SerialName("position") val position: String, - @SerialName("lastVisit") - val lastVisit: String, +// @SerialName("lastVisit") +// val lastVisit: String, ) : java.io.Serializable \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt new file mode 100644 index 0000000..7627b6a --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt @@ -0,0 +1,13 @@ +package com.displaynone.acss.components.auth.models.user.repository.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UserLoginDto( + @SerialName("login") + val login: String, + @SerialName("password") + val password: String, +) { +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/VisitDto.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/VisitDto.kt new file mode 100644 index 0000000..a22dfc7 --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/VisitDto.kt @@ -0,0 +1,17 @@ +package com.displaynone.acss.components.auth.models.user.repository.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class VisitDto( + @SerialName("id") + val id: Long, + @SerialName("userId") + val userId: Long, + @SerialName("gateId") + val gateId: Long, + @SerialName("createdAt") + val createdAt: String, +) { +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt b/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt index 5746869..8b4db77 100644 --- a/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt +++ b/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt @@ -40,9 +40,14 @@ class AdminFragment : Fragment(R.layout.fragment_admin) { val userDto = state.item val bundle = Bundle().apply{ putSerializable("user", userDto) + putBoolean("isMe", false) } navigateTo(view, R.id.action_adminFragment_to_profileFragment, bundle) } + if (state is AdminViewModel.State.Error){ + val errorMessage = state.errorMessage + binding.loginSearch.setError(errorMessage) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt index 739a0f0..7b3651a 100644 --- a/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt +++ b/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt @@ -5,7 +5,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.displaynone.acss.components.auth.models.user.UserServiceST import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO -import com.displaynone.acss.ui.profile.ProfileViewModel.State import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch @@ -20,7 +19,8 @@ class AdminViewModel: ViewModel() { _state.emit(State.Show(item = dto)) }, onFailure = { error -> - error.message?.let { error(it) } +// error.message?.let { error(it) } + _state.emit(State.Error(error.message.toString())) Log.e("AdminViewModel", error.message.toString()) } ) } @@ -30,6 +30,9 @@ class AdminViewModel: ViewModel() { data class Show( val item: UserDTO ): State + data class Error( + val errorMessage: String + ): State data object Loading : State } } \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt b/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt index 86e3855..9b39383 100644 --- a/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt +++ b/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt @@ -59,6 +59,7 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { val username = s.toString() val valid = isUsernameValid(username) + binding.hint.visibility = if(valid) View.INVISIBLE else View.VISIBLE binding.next.isEnabled = valid val color = if (valid) R.color.primary else R.color.secondary @@ -67,6 +68,35 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { override fun afterTextChanged(s: Editable?) {} }) +// binding.password.addTextChangedListener(object : TextWatcher { +// override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} +// @SuppressLint("ResourceAsColor") +// override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { +// binding.error.visibility = View.GONE +// val username = s.toString() +// val valid = isPasswordValid(username) +// +// binding.hint.visibility = if(valid) View.INVISIBLE else View.VISIBLE +// if (!valid){ +// val errorMessage = getPasswordValidError(s.toString()) +// binding.password.setError(errorMessage) +// } +// binding.next.isEnabled = valid +// val color = if (valid) R.color.primary else R.color.secondary +// binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color) +// } +// +// override fun afterTextChanged(s: Editable?) {} +// }) + } + private fun getPasswordValidError(password: String): String { + if (password.length < 8){ return "LenError" } + val letterRegex = Regex("^(?=.*[A-Z]).+$") + if(!letterRegex.matches(password)){ return "UpperCaseError"} + val digitRegex = Regex("^(?=.*\\\\d).+$") + if(!digitRegex.matches(password)){ return "DigitCaseError"} + + return "NoErrors" } private fun isUsernameValid(username: String): Boolean { @@ -76,6 +106,10 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { !username[0].isDigit() && alf.matches(username) } + private fun isPasswordValid(password: String): Boolean { + return password.isNotEmpty() && + password.length >= 8 + } // private fun subscribe() { // viewModel.state.collectWhenStarted(this) { state -> // binding.login.setOnClickListener(this::onLoginButtonClicked) @@ -84,8 +118,9 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { private fun onLoginButtonClicked(view: View) { val login = binding.login.text.toString() + val password = binding.password.text.toString() if (login.isEmpty()) return - viewModel.login(login) + viewModel.login(login, password) } diff --git a/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt index 0426f7e..b7a0433 100644 --- a/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt +++ b/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt @@ -22,10 +22,10 @@ class AuthViewModel(): ViewModel() { private val _errorState = MutableStateFlow(null) val errorState: StateFlow = _errorState.asStateFlow() - fun login(login: String){ + fun login(login: String, password:String){ viewModelScope.launch { try { - UserServiceST.getInstance().login(login).fold( + UserServiceST.getInstance().login(login, password).fold( onSuccess = { openProfile() }, onFailure = { error -> Log.e("AuthViewModel", "Login failed: ${error.message ?: "Unknown error"}") diff --git a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt index 61cc935..7782cb2 100644 --- a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt +++ b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt @@ -10,6 +10,7 @@ import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.bumptech.glide.Glide import com.displaynone.acss.R +import com.displaynone.acss.components.auth.models.user.repository.VisitAdapter import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO import com.displaynone.acss.databinding.FragmentProfileBinding import com.displaynone.acss.ui.profile.ProfileViewModel.Action @@ -27,31 +28,58 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentProfileBinding.bind(view) - - binding.swipeRefresh.setOnRefreshListener { - refreshData() - } +// +// binding.swipeRefresh.setOnRefreshListener { +// if (getIsMe()){ +// refreshData() +// } else{ +// showData(getUserDto()!!) +// } +// } binding.logout.setOnClickListener{ logout() } binding.scan.setOnClickListener{ viewModel.openScan() } - val user = getUserDto() - if (user == null) { + val adapter = VisitAdapter() + binding.recyclerViewLogs.adapter = adapter + if (getIsMe()) { refreshData() +// viewModel.visitListState.collectWithLifecycle(this) { data -> +// adapter.submitData(data) +// } waitForQRScanResult() } else{ - showData(user) // TODO() не показывать кнопки + showData(getUserDto()!!) + hideButtons() + } subscribe() + viewModel.visitListState.collectWithLifecycle(this) { data -> + adapter.submitData(data) + Log.d("ProfileFragment", "submitted data") + } +// viewModel.visitListStateFromLogin.collectWithLifecycle(this) { data -> +// adapter.submitData(data) +// } + + } + + private fun hideButtons() { + binding.logout.visibility = View.INVISIBLE + binding.scan.visibility = View.INVISIBLE } fun showData(userDTO: UserDTO){ binding.fio.text = userDTO.name binding.position.text = userDTO.position - binding.lastEntry.text = userDTO.lastVisit + viewModel.setLogin(login1 = userDTO.login) +// binding.lastEntry.text = userDTO.lastVisit +// viewModel.visitListStateFromLogin.collectWithLifecycle(this){ +// +// } setAvatar(userDTO.photo) } private fun refreshData() { @@ -72,6 +100,10 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) { private fun getUserDto(): UserDTO? { return arguments?.getSerializable("user") as? UserDTO } + private fun getIsMe(): Boolean { + return arguments?.getBoolean("isMe", true) ?: true + } + private fun waitForQRScanResult() { requireActivity().onBackPressedDispatcher.addCallback( diff --git a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt index 573e354..308ca53 100644 --- a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt @@ -3,7 +3,12 @@ package com.displaynone.acss.ui.profile import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.cachedIn +import androidx.paging.log import com.displaynone.acss.components.auth.models.user.UserServiceST +import com.displaynone.acss.components.auth.models.user.repository.VisitListPagingSource import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel @@ -17,10 +22,31 @@ class ProfileViewModel(): ViewModel() { capacity = Channel.BUFFERED, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) + private var login: String = "" // FIXME() + fun setLogin(login1: String){ + login = login1 + } val action = _action.receiveAsFlow() val _state = MutableStateFlow(State.Loading) val state = _state.asStateFlow() + val visitListState = Pager( + config = PagingConfig(pageSize = 20, + enablePlaceholders = false, + maxSize = 100 + ) + ) { + VisitListPagingSource(UserServiceST.getInstance()::getMyLastVisits) + }.flow + .cachedIn(viewModelScope) + + val visitListStateFromLogin = Pager( + config = PagingConfig(pageSize = 20, enablePlaceholders = false, maxSize = 100) + ) { + VisitListPagingSource { pageNum, pageSize -> + UserServiceST.getInstance().getLastVisitsByLogin(pageNum,pageSize, login) + } + }.flow.cachedIn(viewModelScope) fun logout(){ UserServiceST.getInstance().logout() @@ -48,6 +74,7 @@ class ProfileViewModel(): ViewModel() { _action.send(Action.GoToScan) } } + sealed interface State { data object Loading : State data class Show(