feat: View profile use case done
This commit is contained in:
parent
16199d485e
commit
f76d744fd7
@ -0,0 +1,51 @@
|
|||||||
|
package ru.myitschool.work.data
|
||||||
|
|
||||||
|
import ru.myitschool.work.data.dto.PassDto
|
||||||
|
import ru.myitschool.work.data.local.CredentialsLocalDataSource
|
||||||
|
import ru.myitschool.work.data.network.PassNetworkDataSource
|
||||||
|
import ru.myitschool.work.domain.entities.PassEntity
|
||||||
|
import ru.myitschool.work.domain.passes.PassRepository
|
||||||
|
|
||||||
|
class PassRepositoryImpl(
|
||||||
|
private val networkDataSource: PassNetworkDataSource,
|
||||||
|
private val credentialsLocalDataSource: CredentialsLocalDataSource
|
||||||
|
) : PassRepository {
|
||||||
|
|
||||||
|
override suspend fun getCurrentPasses(pageNum: Int, pageSize: Int): Result<List<PassEntity>> {
|
||||||
|
return map(
|
||||||
|
networkDataSource.getCurrentPasses(
|
||||||
|
pageNum,
|
||||||
|
pageSize,
|
||||||
|
credentialsLocalDataSource.getToken()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getUsersPasses(
|
||||||
|
pageNum: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
login: String
|
||||||
|
): Result<List<PassEntity>> {
|
||||||
|
return map(
|
||||||
|
networkDataSource.getUsersPasses(
|
||||||
|
login = login,
|
||||||
|
pageNum = pageNum,
|
||||||
|
pageSize = pageSize,
|
||||||
|
token = credentialsLocalDataSource.getToken()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun map(listDto: Result<List<PassDto>>): Result<List<PassEntity>> {
|
||||||
|
return listDto.map { successListDto ->
|
||||||
|
successListDto.mapNotNull { dto ->
|
||||||
|
PassEntity(
|
||||||
|
type = dto.type ?: return@mapNotNull null,
|
||||||
|
name = dto.name ?: return@mapNotNull null,
|
||||||
|
time = dto.time ?: return@mapNotNull null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
app/src/main/java/ru/myitschool/work/data/dto/PassDto.kt
Normal file
15
app/src/main/java/ru/myitschool/work/data/dto/PassDto.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package ru.myitschool.work.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PassDto(
|
||||||
|
@SerialName("type")
|
||||||
|
val type: String?,
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String?,
|
||||||
|
@SerialName("time")
|
||||||
|
val time: String?
|
||||||
|
)
|
@ -0,0 +1,56 @@
|
|||||||
|
package ru.myitschool.work.data.network
|
||||||
|
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.request.headers
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import ru.myitschool.work.core.Constants.SERVER_ADDRESS
|
||||||
|
import ru.myitschool.work.data.dto.PassDto
|
||||||
|
|
||||||
|
object PassNetworkDataSource {
|
||||||
|
private val client = KtorClient.client
|
||||||
|
|
||||||
|
suspend fun getCurrentPasses(
|
||||||
|
pageNum: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
token: String
|
||||||
|
): Result<List<PassDto>> =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
runCatching {
|
||||||
|
val response =
|
||||||
|
client.get("$SERVER_ADDRESS/api/passes?pageNum=$pageNum&pageSize=$pageSize") {
|
||||||
|
headers {
|
||||||
|
append(HttpHeaders.Authorization, token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (response.status != HttpStatusCode.OK)
|
||||||
|
error("${response.status}")
|
||||||
|
response.body()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getUsersPasses(
|
||||||
|
login: String,
|
||||||
|
pageNum: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
token: String
|
||||||
|
): Result<List<PassDto>> = withContext(Dispatchers.IO) {
|
||||||
|
runCatching {
|
||||||
|
|
||||||
|
val response =
|
||||||
|
client.get("$SERVER_ADDRESS/api/passes?login=$login&pageNum=$pageNum&pageSize=$pageSize") {
|
||||||
|
headers {
|
||||||
|
append(HttpHeaders.Authorization, token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (response.status != HttpStatusCode.OK)
|
||||||
|
error("Status ${response.status}")
|
||||||
|
response.body()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package ru.myitschool.work.domain.entities
|
||||||
|
|
||||||
|
data class PassEntity(
|
||||||
|
val type: String,
|
||||||
|
val name: String,
|
||||||
|
val time: String
|
||||||
|
)
|
@ -0,0 +1,11 @@
|
|||||||
|
package ru.myitschool.work.domain.passes
|
||||||
|
|
||||||
|
import ru.myitschool.work.domain.entities.PassEntity
|
||||||
|
|
||||||
|
class GetCurrentPassesUseCase(
|
||||||
|
private val repository: PassRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(pageNum: Int, pageSize: Int): Result<List<PassEntity>> =
|
||||||
|
repository.getCurrentPasses(pageNum, pageSize)
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package ru.myitschool.work.domain.passes
|
||||||
|
|
||||||
|
import ru.myitschool.work.domain.entities.PassEntity
|
||||||
|
|
||||||
|
interface PassRepository {
|
||||||
|
|
||||||
|
suspend fun getCurrentPasses(pageNum: Int, pageSize: Int): Result<List<PassEntity>>
|
||||||
|
suspend fun getUsersPasses(pageNum: Int, pageSize: Int, login: String): Result<List<PassEntity>>
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package ru.myitschool.work.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import ru.myitschool.work.R
|
||||||
|
import ru.myitschool.work.databinding.FragmentNoInternetNotificationBinding
|
||||||
|
import ru.myitschool.work.utils.isOnline
|
||||||
|
|
||||||
|
class NoInternetNotificationFragment: BottomSheetDialogFragment(R.layout.fragment_no_internet_notification) {
|
||||||
|
|
||||||
|
private var _binding: FragmentNoInternetNotificationBinding? = null
|
||||||
|
private val binding: FragmentNoInternetNotificationBinding get() = _binding!!
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
_binding = FragmentNoInternetNotificationBinding.bind(view)
|
||||||
|
|
||||||
|
binding.close.setOnClickListener {
|
||||||
|
if (isOnline(requireActivity())) dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
_binding = null
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package ru.myitschool.work.ui.profile
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.paging.PagingDataAdapter
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
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) {
|
||||||
|
|
||||||
|
class ViewHolder(
|
||||||
|
private val binding: PassItemBinding,
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: PassEntity) {
|
||||||
|
binding.time.text = item.time
|
||||||
|
binding.name.text = item.name
|
||||||
|
binding.type.text = item.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CenterDiff : DiffUtil.ItemCallback<PassEntity>() {
|
||||||
|
override fun areContentsTheSame(oldItem: PassEntity, newItem: PassEntity): Boolean {
|
||||||
|
return oldItem.name == newItem.name
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: PassEntity, newItem: PassEntity): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
return ViewHolder(
|
||||||
|
PassItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(
|
||||||
|
getItem(position) ?: PassEntity(
|
||||||
|
type = "Загрузка ...",
|
||||||
|
name = "Терминал №...",
|
||||||
|
time = "Давным-давно..."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package ru.myitschool.work.ui.profile
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import ru.myitschool.work.domain.entities.PassEntity
|
||||||
|
|
||||||
|
class PassesPagingSource(
|
||||||
|
private val request: suspend (pageNum: Int, pageSize: Int) -> Result<List<PassEntity>>
|
||||||
|
) : PagingSource<Int, PassEntity>() {
|
||||||
|
override fun getRefreshKey(state: PagingState<Int, PassEntity>): 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, PassEntity> {
|
||||||
|
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) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -4,25 +4,43 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.CreationExtras
|
import androidx.lifecycle.viewmodel.CreationExtras
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.cachedIn
|
||||||
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.PassRepositoryImpl
|
||||||
import ru.myitschool.work.data.UserRepositoryImpl
|
import ru.myitschool.work.data.UserRepositoryImpl
|
||||||
import ru.myitschool.work.data.local.CredentialsLocalDataSource
|
import ru.myitschool.work.data.local.CredentialsLocalDataSource
|
||||||
import ru.myitschool.work.data.local.UserLocalDataSource
|
import ru.myitschool.work.data.local.UserLocalDataSource
|
||||||
|
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.entities.UserEntity
|
import ru.myitschool.work.domain.entities.UserEntity
|
||||||
import ru.myitschool.work.domain.login.LogoutUseCase
|
import ru.myitschool.work.domain.login.LogoutUseCase
|
||||||
|
import ru.myitschool.work.domain.passes.GetCurrentPassesUseCase
|
||||||
import ru.myitschool.work.domain.user.GetCurrentUserUseCase
|
import ru.myitschool.work.domain.user.GetCurrentUserUseCase
|
||||||
|
|
||||||
class UserViewModel(
|
class UserViewModel(
|
||||||
private val getCurrentUserUseCase: GetCurrentUserUseCase,
|
private val getCurrentUserUseCase: GetCurrentUserUseCase,
|
||||||
private val logoutUseCase: LogoutUseCase
|
private val logoutUseCase: LogoutUseCase,
|
||||||
|
private val getCurrentPassesUseCase: GetCurrentPassesUseCase
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _state = MutableStateFlow<State>(State.Loading)
|
private val _state = MutableStateFlow<State>(State.Loading)
|
||||||
val state = _state.asStateFlow()
|
val state = _state.asStateFlow()
|
||||||
|
|
||||||
|
val listState = Pager(
|
||||||
|
config = PagingConfig(
|
||||||
|
pageSize = 10,
|
||||||
|
enablePlaceholders = false,
|
||||||
|
maxSize = 50
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
PassesPagingSource(getCurrentPassesUseCase::invoke)
|
||||||
|
}.flow
|
||||||
|
.cachedIn(viewModelScope)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
updateState()
|
updateState()
|
||||||
}
|
}
|
||||||
@ -57,7 +75,13 @@ class UserViewModel(
|
|||||||
)
|
)
|
||||||
return UserViewModel(
|
return UserViewModel(
|
||||||
getCurrentUserUseCase = GetCurrentUserUseCase(repository = repository),
|
getCurrentUserUseCase = GetCurrentUserUseCase(repository = repository),
|
||||||
logoutUseCase = LogoutUseCase(repository = repository)
|
logoutUseCase = LogoutUseCase(repository = repository),
|
||||||
|
getCurrentPassesUseCase = GetCurrentPassesUseCase(
|
||||||
|
repository = PassRepositoryImpl(
|
||||||
|
networkDataSource = PassNetworkDataSource,
|
||||||
|
credentialsLocalDataSource = CredentialsLocalDataSource.getInstance()
|
||||||
|
)
|
||||||
|
)
|
||||||
) as T
|
) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user