feat: Пагинация списка входов и выходов, переименование некоторые классов, изменение эндпоинтов в запросах и добавление новых

This commit is contained in:
yastruckov 2025-02-19 11:30:57 +03:00
parent 5a490f37f4
commit 645c3e5f62
33 changed files with 250 additions and 155 deletions

View File

@ -13,6 +13,7 @@ class UserDataStoreManager(private val context: Context) {
companion object {
private val USERNAME_KEY = stringPreferencesKey("username")
private val ROLE_KEY = stringPreferencesKey("role")
private val PASSWORD_KEY = stringPreferencesKey("password")
fun getInstance(context: Context): UserDataStoreManager {
return UserDataStoreManager(context.applicationContext)
@ -22,12 +23,16 @@ class UserDataStoreManager(private val context: Context) {
val usernameFlow: Flow<String> = context.applicationContext.dataStore.data.map { prefs ->
prefs[USERNAME_KEY] ?: ""
}
val passwordFlow: Flow<String> = context.applicationContext.dataStore.data.map { prefs ->
prefs[PASSWORD_KEY] ?: ""
}
val roleFlow: Flow<String> = context.applicationContext.dataStore.data.map{ prefs ->
prefs[ROLE_KEY] ?: ""
}
suspend fun saveUsername(username: String) {
suspend fun saveCredentials(username: String, password: String) {
context.dataStore.edit { prefs ->
prefs[USERNAME_KEY] = username
prefs[PASSWORD_KEY] = password
}
}
suspend fun saveRole(role: String){
@ -35,7 +40,7 @@ class UserDataStoreManager(private val context: Context) {
prefs[ROLE_KEY] = role
}
}
suspend fun clearUsername() {
suspend fun clearCredentials() {
context.applicationContext.dataStore.edit { it.clear() }
}
}

View File

@ -2,18 +2,16 @@ package ru.myitschool.work.data.door
import android.content.Context
import io.ktor.client.call.body
import io.ktor.client.request.basicAuth
import io.ktor.client.request.patch
import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
import io.ktor.http.headers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
import ru.myitschool.work.core.Constants
import ru.myitschool.work.data.UserDataStoreManager
import ru.myitschool.work.data.dto.OpenRequestDTO
import ru.myitschool.work.utils.NetworkModule
class DoorNetworkDataSource(
@ -21,12 +19,14 @@ class DoorNetworkDataSource(
) {
private val client = NetworkModule.httpClient
private val userDataStoreManager = UserDataStoreManager.getInstance(context)
suspend fun openDoor(openRequestDTO: OpenRequestDTO): Result<Unit> = withContext(Dispatchers.IO){
suspend fun openDoor(code : String): Result<Unit> = withContext(Dispatchers.IO){
runCatching {
val username = userDataStoreManager.usernameFlow.first()
val result = client.patch("${Constants.SERVER_ADDRESS}/api/$username/open"){
contentType(ContentType.Application.Json)
setBody(openRequestDTO)
val password = userDataStoreManager.passwordFlow.first()
val result = client.patch("${Constants.SERVER_ADDRESS}/api/employee/open?code=$code"){
headers{
basicAuth(username, password)
}
}
if (result.status != HttpStatusCode.OK) {
error("Status ${result.status}")

View File

@ -1,12 +1,11 @@
package ru.myitschool.work.data.door
import ru.myitschool.work.domain.door.DoorRepo
import ru.myitschool.work.domain.entities.OpenEntity
class DoorRepoImpl(
private val networkDataSource: DoorNetworkDataSource
) : DoorRepo {
override suspend fun openDoor(openEntity: OpenEntity): Result<Unit> {
return networkDataSource.openDoor(openEntity.toDto())
override suspend fun openDoor(code: String): Result<Unit> {
return networkDataSource.openDoor(code)
}
}

View File

@ -1,9 +0,0 @@
package ru.myitschool.work.data.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class OpenRequestDTO(
@SerialName("value") val value: Long
)

View File

@ -5,11 +5,11 @@ import kotlinx.serialization.Serializable
@Serializable
data class UserDTO(
@SerialName("id") val id: Int,
@SerialName("login") val login: String,
@SerialName("name") val name: String,
@SerialName("photo") val photo: String,
@SerialName("position") val position: String,
@SerialName("lastVisit") val lastVisit: String
@SerialName("id") val id: Long?,
@SerialName("login") val login: String?,
@SerialName("name") val name: String?,
@SerialName("authority") val authority : String?,
@SerialName("photo") val photoUrl: String?,
@SerialName("position") val position: String?
)

View File

@ -7,8 +7,7 @@ import java.util.Date
@Serializable
data class VisitDTO(
@SerialName("scanTime")
@Serializable(with = DateSerializer::class) val scanTime : Date?,
@SerialName("readerId") val readerId: Long?,
@SerialName("scanTime") @Serializable(with = DateSerializer::class) val scanTime : Date?,
@SerialName("readerId") val readerName: String?,
@SerialName("type") val type: String?
)

View File

@ -2,9 +2,11 @@ package ru.myitschool.work.data.info
import android.content.Context
import io.ktor.client.call.body
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import io.ktor.http.headers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
@ -22,8 +24,12 @@ class InfoNetworkDataSource(
suspend fun getInfo():Result<UserDTO> = withContext(Dispatchers.IO){
runCatching {
val username = userDataStoreManager.usernameFlow.first()
val result = client.get("${Constants.SERVER_ADDRESS}/api/$username/info")
val password = userDataStoreManager.passwordFlow.first()
val result = client.get("${Constants.SERVER_ADDRESS}/api/employee/profile"){
headers{
basicAuth(username, password)
}
}
if (result.status != HttpStatusCode.OK) {
error("Status ${result.status}")
}

View File

@ -7,13 +7,16 @@ class InfoRepoImpl(
private val networkDataSource: InfoNetworkDataSource
): InfoRepo {
override suspend fun getInfo(): Result<UserEntity> {
return networkDataSource.getInfo().map { dto ->
return networkDataSource.getInfo().map { dto->
UserEntity(
name = dto.name,
position = dto.position,
lastVisit = dto.lastVisit,
photo = dto.photo
id = dto.id ?: 0,
login = dto.login ?: "",
name = dto.login ?: "",
authority = dto.authority ?: "",
photoUrl = dto.photoUrl,
position = dto.position ?: ""
)
}
}
}

View File

@ -1,9 +1,10 @@
package ru.myitschool.work.data.login
import io.ktor.client.call.body
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import io.ktor.http.headers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import ru.myitschool.work.core.Constants
@ -11,14 +12,16 @@ import ru.myitschool.work.utils.NetworkModule
class LoginNetworkDataSource {
private val client = NetworkModule.httpClient
suspend fun login(username: String):Result<Unit> = withContext(Dispatchers.IO){
suspend fun login(username: String, password: String):Result<Unit> = withContext(Dispatchers.IO){
runCatching {
val result = client.get("${Constants.SERVER_ADDRESS}/api/$username/auth")
val result = client.get("${Constants.SERVER_ADDRESS}/api/employee/login"){
headers{
basicAuth(username, password)
}
}
if (result.status != HttpStatusCode.OK) {
error("Status ${result.status}")
}
println(result.bodyAsText())
result.body()
}
}

View File

@ -5,7 +5,7 @@ import ru.myitschool.work.domain.login.LoginRepo
class LoginRepoImpl(
private val networkDataSource: LoginNetworkDataSource
) : LoginRepo {
override suspend fun login(username: String): Result<Unit> {
return networkDataSource.login(username)
override suspend fun login(username: String, password: String): Result<Unit> {
return networkDataSource.login(username, password)
}
}

View File

@ -1,21 +0,0 @@
package ru.myitschool.work.data.visitsList
import ru.myitschool.work.domain.entities.UserEntity
import ru.myitschool.work.domain.entities.VisitEntity
import ru.myitschool.work.domain.visitsList.VisitListRepo
class VisitListRepoImpl(
private val networkDataSource: VisitListNetworkDataSource
) : VisitListRepo {
override suspend fun getList(pageNum: Int, pageSize: Int): Result<List<VisitEntity>> {
return networkDataSource.getList(pageNum, pageSize).map { pagingDTO ->
pagingDTO.content?.mapNotNull { dto->
VisitEntity(
scanTime = dto.scanTime ?: return@mapNotNull null,
readerId = dto.readerId ?: return@mapNotNull null,
type = dto.type ?: return@mapNotNull null
)
}?: return Result.failure(IllegalStateException("List parse error"))
}
}
}

View File

@ -1,10 +1,11 @@
package ru.myitschool.work.data.visitsList
package ru.myitschool.work.data.visitsList.employeeEntrances
import android.content.Context
import io.ktor.client.call.body
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import io.ktor.http.headers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
@ -13,7 +14,7 @@ import ru.myitschool.work.data.UserDataStoreManager
import ru.myitschool.work.data.dto.VisitListPagingDTO
import ru.myitschool.work.utils.NetworkModule
class VisitListNetworkDataSource(
class EmployeeEntranceListNetworkDataSource(
context: Context
){
private val client = NetworkModule.httpClient
@ -21,7 +22,12 @@ class VisitListNetworkDataSource(
suspend fun getList(pageNum: Int, pageSize: Int):Result<VisitListPagingDTO> = withContext(Dispatchers.IO){
runCatching {
val username = userDataStoreManager.usernameFlow.first()
val result = client.get("${Constants.SERVER_ADDRESS}/api/$username/visits?page=$pageNum&size=$pageSize")
val password = userDataStoreManager.passwordFlow.first()
val result = client.get("${Constants.SERVER_ADDRESS}/api/entrance?page=$pageNum&size=$pageSize"){
headers{
basicAuth(username, password)
}
}
if (result.status != HttpStatusCode.OK) {
error("Status ${result.status}")

View File

@ -0,0 +1,20 @@
package ru.myitschool.work.data.visitsList.employeeEntrances
import ru.myitschool.work.domain.entities.EmployeeEntranceEntity
import ru.myitschool.work.domain.visitsList.EmployeeEntranceListRepo
class EmployeeEntranceListRepoImpl(
private val networkDataSource: EmployeeEntranceListNetworkDataSource
) : EmployeeEntranceListRepo {
override suspend fun getList(pageNum: Int, pageSize: Int): Result<List<EmployeeEntranceEntity>> {
return networkDataSource.getList(pageNum, pageSize).map { pagingDTO ->
pagingDTO.content?.mapNotNull { dto->
EmployeeEntranceEntity(
scanTime = dto.scanTime ?: return@mapNotNull null,
readerName = dto.readerName ?: return@mapNotNull null,
type = dto.type ?: return@mapNotNull null
)
}?: return Result.failure(IllegalStateException("List parse error"))
}
}
}

View File

@ -1,7 +1,5 @@
package ru.myitschool.work.domain.door
import ru.myitschool.work.domain.entities.OpenEntity
interface DoorRepo {
suspend fun openDoor(openEntity: OpenEntity) : Result<Unit>
suspend fun openDoor(code: String) : Result<Unit>
}

View File

@ -1,11 +1,7 @@
package ru.myitschool.work.domain.door
import ru.myitschool.work.domain.entities.OpenEntity
class OpenDoorUseCase(
private val repo: DoorRepo
) {
suspend operator fun invoke(openEntity: OpenEntity) = repo.openDoor(
openEntity = openEntity
)
suspend operator fun invoke(code: String) = repo.openDoor(code)
}

View File

@ -2,8 +2,8 @@ package ru.myitschool.work.domain.entities
import java.util.Date
data class VisitEntity(
data class EmployeeEntranceEntity(
val scanTime : Date,
val readerId: Long,
val readerName: String,
val type: String
)

View File

@ -1,13 +0,0 @@
package ru.myitschool.work.domain.entities
import ru.myitschool.work.data.dto.OpenRequestDTO
data class OpenEntity(
val value: Long
){
fun toDto() : OpenRequestDTO{
return OpenRequestDTO(
value = value
)
}
}

View File

@ -1,8 +1,10 @@
package ru.myitschool.work.domain.entities
data class UserEntity (
data class UserEntity(
val id: Long,
val login: String,
val name: String,
val photo: String,
val position: String,
val lastVisit: String
val authority: String,
val photoUrl: String?,
val position: String
)

View File

@ -1,5 +1,5 @@
package ru.myitschool.work.domain.login
interface LoginRepo {
suspend fun login(username: String): Result<Unit>
suspend fun login(username: String, password: String): Result<Unit>
}

View File

@ -3,5 +3,5 @@ package ru.myitschool.work.domain.login
class LoginUseCase(
private val repo: LoginRepo
) {
suspend operator fun invoke(username : String) = repo.login(username)
suspend operator fun invoke(username: String, password: String) = repo.login(username, password)
}

View File

@ -0,0 +1,7 @@
package ru.myitschool.work.domain.visitsList
import ru.myitschool.work.domain.entities.EmployeeEntranceEntity
interface EmployeeEntranceListRepo {
suspend fun getList(pageNum : Int, pageSize: Int) : Result<List<EmployeeEntranceEntity>>
}

View File

@ -1,7 +1,7 @@
package ru.myitschool.work.domain.visitsList
class GetVisitListUseCase(
private val repo: VisitListRepo
class GetEmployeeEntranceListUseCase(
private val repo: EmployeeEntranceListRepo
) {
suspend operator fun invoke(pageNum : Int, pageSize: Int) = repo.getList(pageNum, pageSize)
}

View File

@ -1,8 +0,0 @@
package ru.myitschool.work.domain.visitsList
import ru.myitschool.work.domain.entities.UserEntity
import ru.myitschool.work.domain.entities.VisitEntity
interface VisitListRepo {
suspend fun getList(pageNum : Int, pageSize: Int) : Result<List<VisitEntity>>
}

View File

@ -29,14 +29,16 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val username = binding.username.text
binding.loginBtn.isEnabled = username.length >= 3 && !username[0].isDigit() && username.matches(Regex("^[a-zA-Z0-9]*$"))
val password = binding.password.text
binding.loginBtn.isEnabled = username.length >= 3 && !username[0].isDigit() && username.matches(Regex("^[a-zA-Z0-9]*$")) &&
password.length >= 6
}
}
binding.username.addTextChangedListener(textWatcher)
binding.loginBtn.isEnabled = false
binding.loginBtn.setOnClickListener{
viewModel.login(binding.username.text.toString())
viewModel.login(binding.username.text.toString(), binding.password.text.toString())
}
lifecycleScope.launch {

View File

@ -27,26 +27,27 @@ class LoginViewModel(
init {
viewModelScope.launch{
val username = dataStoreManager.usernameFlow.first()
if(username != "")
login(username)
val password = dataStoreManager.passwordFlow.first()
if(username != "" && password != "")
login(username, password)
}
}
sealed class State {
object Idle : State()
object Loading : State()
object Success : State()
data object Idle : State()
data object Loading : State()
data object Success : State()
data class Error(val message: String?) : State()
}
fun login(username: String) {
fun login(username: String, password: String) {
_state.value = State.Loading
viewModelScope.launch{
useCase.invoke(username).fold(
onSuccess = { data ->
dataStoreManager.saveUsername(username)
useCase.invoke(username, password).fold(
onSuccess = { _ ->
dataStoreManager.saveCredentials(username, password)
_state.value = State.Success
},
onFailure = {e->

View File

@ -0,0 +1,43 @@
package ru.myitschool.work.ui.main
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.RecyclerView
import ru.myitschool.work.databinding.ItemVisitBinding
import ru.myitschool.work.domain.entities.EmployeeEntranceEntity
import ru.myitschool.work.utils.dateConverter
class EmployeeEntranceListAdapter : PagingDataAdapter<EmployeeEntranceEntity, EmployeeEntranceListAdapter.ViewHolder>(DiffUtil) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : ViewHolder{
return ViewHolder(
ItemVisitBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
if (item != null) {
holder.bind(item)
}
}
inner class ViewHolder(
private val binding: ItemVisitBinding,
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: EmployeeEntranceEntity) {
binding.readerName.text = item.readerName
binding.timeVisit.text = dateConverter(item.scanTime)
}
}
object DiffUtil : androidx.recyclerview.widget.DiffUtil.ItemCallback<EmployeeEntranceEntity>() {
override fun areItemsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean {
return oldItem.scanTime == newItem.scanTime
}
override fun areContentsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean {
return oldItem == newItem
}
}
}

View File

@ -0,0 +1,35 @@
package ru.myitschool.work.ui.main
import androidx.paging.PagingSource
import androidx.paging.PagingState
import ru.myitschool.work.domain.entities.EmployeeEntranceEntity
class EmployeeEntranceListPagingSource(
private val request: suspend(pageNum: Int, pageSize: Int) ->Result<List<EmployeeEntranceEntity>>
) : PagingSource<Int, EmployeeEntranceEntity>() {
override fun getRefreshKey(state: PagingState<Int, EmployeeEntranceEntity>): Int? {
return state.anchorPosition?.let{
state.closestPageToPosition(it)?.prevKey?.plus(1) ?:
state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, EmployeeEntranceEntity> {
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 = { e->
LoadResult.Error(e)
}
)
}
}

View File

@ -8,6 +8,7 @@ import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.squareup.picasso.Picasso
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -57,6 +58,11 @@ class MainFragment : Fragment(R.layout.fragment_main) {
}
}
}
binding.content.layoutManager = LinearLayoutManager(requireContext())
val adapter = EmployeeEntranceListAdapter()
binding.content.adapter = adapter
setFragmentResultListener(QrScanDestination.REQUEST_KEY) { _, bundle ->
val qrData = QrScanDestination.getDataIfExist(bundle)
println(qrData)
@ -82,8 +88,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.apply {
fullname.text = userEntity.name
position.text = userEntity.position
lastEntry.text = viewModel.formatDate(userEntity.lastVisit)
Picasso.get().load(userEntity.photo).into(photo)
Picasso.get().load(userEntity.photoUrl).into(photo)
error.visibility = View.GONE
setViewsVisibility(View.VISIBLE)
@ -98,7 +103,6 @@ class MainFragment : Fragment(R.layout.fragment_main) {
private fun setViewsVisibility(visibility: Int) {
binding.fullname.visibility = visibility
binding.position.visibility = visibility
binding.lastEntry.visibility = visibility
binding.photo.visibility = visibility
binding.logout.visibility = visibility
binding.scan.visibility = visibility

View File

@ -6,6 +6,9 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -14,16 +17,31 @@ import kotlinx.coroutines.withContext
import ru.myitschool.work.data.UserDataStoreManager
import ru.myitschool.work.data.info.InfoNetworkDataSource
import ru.myitschool.work.data.info.InfoRepoImpl
import ru.myitschool.work.data.visitsList.employeeEntrances.EmployeeEntranceListNetworkDataSource
import ru.myitschool.work.data.visitsList.employeeEntrances.EmployeeEntranceListRepoImpl
import ru.myitschool.work.domain.info.GetInfoUseCase
import ru.myitschool.work.domain.visitsList.GetEmployeeEntranceListUseCase
import ru.myitschool.work.utils.UserState
import java.text.SimpleDateFormat
import java.util.Locale
class MainViewModel(
private val useCase: GetInfoUseCase,
private val infoUseCase: GetInfoUseCase,
private val listUseCase: GetEmployeeEntranceListUseCase,
application: Application
) : AndroidViewModel(application) {
val listState = Pager(
config = PagingConfig(
pageSize = 10,
enablePlaceholders = false,
maxSize = 30
)
) {
println("Creating PagingSource")
EmployeeEntranceListPagingSource(listUseCase::invoke)
}.flow.cachedIn(viewModelScope)
private val _userState = MutableStateFlow<UserState>(UserState.Loading)
val userState: StateFlow<UserState> get() = _userState
@ -45,7 +63,7 @@ class MainViewModel(
fun getUserData() {
_userState.value = UserState.Loading
viewModelScope.launch {
useCase.invoke().fold(
infoUseCase.invoke().fold(
onSuccess = { data -> _userState.value = UserState.Success(data) },
onFailure = { _userState.value = UserState.Error }
)
@ -55,7 +73,7 @@ class MainViewModel(
fun clearUsername() {
viewModelScope.launch{
withContext(Dispatchers.IO) {
dataStoreManager.clearUsername()
dataStoreManager.clearCredentials()
}
}
@ -64,16 +82,22 @@ class MainViewModel(
@Suppress("UNCHECKED_CAST")
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
val repoImpl = InfoRepoImpl(
val infoRepoImpl = InfoRepoImpl(
networkDataSource = InfoNetworkDataSource(
context = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
)
)
val listInfoImpl = EmployeeEntranceListRepoImpl(
networkDataSource = EmployeeEntranceListNetworkDataSource(
context = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
)
)
val useCase = GetInfoUseCase(repoImpl)
val infoUseCase = GetInfoUseCase(infoRepoImpl)
val listUseCase = GetEmployeeEntranceListUseCase(listInfoImpl)
return MainViewModel(
useCase, extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
infoUseCase, listUseCase, extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
) as T
}
}

View File

@ -1,20 +0,0 @@
package ru.myitschool.work.ui.main
import androidx.paging.PagingSource
import androidx.paging.PagingState
import ru.myitschool.work.domain.entities.VisitEntity
class VisitListPagingSource(
private val request: suspend(pageNum: Int, pageSize: Int) ->Result<List<VisitEntity>>
) : PagingSource<Int, VisitEntity>() {
override fun getRefreshKey(state: PagingState<Int, VisitEntity>): Int? {
return state.anchorPosition?.let{
state.closestPageToPosition(it)?.prevKey?.plus(1) ?:
state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, VisitEntity> {
TODO("Not yet implemented")
}
}

View File

@ -7,7 +7,6 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentQrResultBinding
import ru.myitschool.work.domain.entities.OpenEntity
import ru.myitschool.work.utils.collectWhenStarted
class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
@ -19,7 +18,7 @@ class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
_binding = FragmentQrResultBinding.bind(view)
var qrData = arguments?.getString("qr_data")
if (qrData != null) {
viewModel.openDoor(OpenEntity(qrData.toLong()))
viewModel.openDoor(qrData)
}
else{
binding.result.text = getString(R.string.result_null_text)

View File

@ -13,7 +13,6 @@ import kotlinx.coroutines.launch
import ru.myitschool.work.data.door.DoorNetworkDataSource
import ru.myitschool.work.data.door.DoorRepoImpl
import ru.myitschool.work.domain.door.OpenDoorUseCase
import ru.myitschool.work.domain.entities.OpenEntity
class QrResultViewModel(
private val useCase: OpenDoorUseCase,
@ -27,11 +26,11 @@ class QrResultViewModel(
data object Loading : State()
data object Error : State()
}
fun openDoor(openEntity: OpenEntity){
fun openDoor(code: String){
_state.value = State.Loading
viewModelScope.launch{
useCase.invoke(openEntity).fold(
onSuccess = { data->
useCase.invoke(code).fold(
onSuccess = { _ ->
_state.value = State.Success
},
onFailure = { _ ->

View File

@ -0,0 +1,15 @@
package ru.myitschool.work.utils
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
fun dateConverter(date: Date?) : String {
if (date != null) {
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
println(dateFormat.format(date).toString())
return dateFormat.format(date).toString()
}
return ""
}