Merge remote-tracking branch 'origin/master'

This commit is contained in:
senijan 2025-02-19 18:57:33 +03:00
commit 27cdf4b988
22 changed files with 163 additions and 57 deletions

View File

@ -1,5 +1,5 @@
package ru.myitschool.work.core package ru.myitschool.work.core
// БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ // БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ
object Constants { object Constants {
const val SERVER_ADDRESS = "http://192.168.1.145:8080" const val SERVER_ADDRESS = "http://10.6.66.78:8080"
} }

View File

@ -2,8 +2,10 @@ package ru.myitschool.work.data.deleteEmployee
import ru.myitschool.work.domain.deleteEmployee.DeleteEmployeeRepo import ru.myitschool.work.domain.deleteEmployee.DeleteEmployeeRepo
class DeleteEmployeeRepoImpl : DeleteEmployeeRepo { class DeleteEmployeeRepoImpl(
private val networkDataSource: DeleteEmployeeNetworkDataSource
) : DeleteEmployeeRepo {
override suspend fun deleteEmployee(login: String): Result<Unit> { override suspend fun deleteEmployee(login: String): Result<Unit> {
TODO("Not yet implemented") return networkDataSource.deleteEmployee(login)
} }
} }

View File

@ -21,11 +21,11 @@ class EmployeeListNetworkDataSource(
private val client = NetworkModule.httpClient private val client = NetworkModule.httpClient
private val userDataStoreManager = UserDataStoreManager.getInstance(context) private val userDataStoreManager = UserDataStoreManager.getInstance(context)
suspend fun getInfo():Result<EmployeePagingDTO> = withContext(Dispatchers.IO){ suspend fun getList(pageNum: Int, pageSize: Int):Result<EmployeePagingDTO> = withContext(Dispatchers.IO){
runCatching { runCatching {
val username = userDataStoreManager.usernameFlow.first() val username = userDataStoreManager.usernameFlow.first()
val password = userDataStoreManager.passwordFlow.first() val password = userDataStoreManager.passwordFlow.first()
val result = client.get("${Constants.SERVER_ADDRESS}/api/employee/all"){ val result = client.get("${Constants.SERVER_ADDRESS}/api/employee/all?page=$pageNum&size=$pageSize"){
headers{ headers{
basicAuth(username, password) basicAuth(username, password)
} }

View File

@ -3,8 +3,25 @@ package ru.myitschool.work.data.employeeList
import ru.myitschool.work.domain.employeeList.EmployeeListRepo import ru.myitschool.work.domain.employeeList.EmployeeListRepo
import ru.myitschool.work.entities.EmployeeEntity import ru.myitschool.work.entities.EmployeeEntity
class EmployeeListRepoImpl : EmployeeListRepo { class EmployeeListRepoImpl(
override suspend fun getList(): Result<List<EmployeeEntity>> { private val networkDataSource: EmployeeListNetworkDataSource
TODO("Not yet implemented") ) : EmployeeListRepo {
override suspend fun getList(
pageNum: Int,
pageSize: Int
): Result<List<EmployeeEntity>> {
return networkDataSource.getList(pageNum, pageSize ).map { pagingDTO->
pagingDTO.content?.mapNotNull { dto ->
EmployeeEntity(
id = dto.id ?: return@mapNotNull null,
login = dto.login ?: return@mapNotNull null ,
name = dto.name ?: return@mapNotNull null,
authority = dto.authority ?: return@mapNotNull null,
photoUrl = dto.photoUrl,
position = dto.position ?: return@mapNotNull null,
qrEnabled = dto.qrEnabled ?: false
)
} ?: return Result.failure(IllegalStateException("List parse error"))
}
}
} }
}

View File

@ -16,7 +16,8 @@ class AllEntranceListRepoImpl(
id = dto.id ?: return@mapNotNull null, id = dto.id ?: return@mapNotNull null,
scanTime = dto.scanTime ?: return@mapNotNull null, scanTime = dto.scanTime ?: return@mapNotNull null,
readerName = dto.readerName ?: return@mapNotNull null, readerName = dto.readerName ?: return@mapNotNull null,
type = dto.type ?: return@mapNotNull null type = dto.type ?: return@mapNotNull null,
entryType = dto.entryType ?: return@mapNotNull null,
) )
}?: return Result.failure(IllegalStateException("List parse error")) }?: return Result.failure(IllegalStateException("List parse error"))
} }

View File

@ -14,6 +14,7 @@ class EmployeeEntranceListRepoImpl(
scanTime = dto.scanTime ?: return@mapNotNull null, scanTime = dto.scanTime ?: return@mapNotNull null,
readerName = dto.readerName ?: return@mapNotNull null, readerName = dto.readerName ?: return@mapNotNull null,
type = dto.type ?: return@mapNotNull null, type = dto.type ?: return@mapNotNull null,
entryType = dto.entryType ?: return@mapNotNull null
) )
}?: return Result.failure(IllegalStateException("List parse error")) }?: return Result.failure(IllegalStateException("List parse error"))
} }

View File

@ -3,8 +3,7 @@ package ru.myitschool.work.data.entrance.lastEntrance
import android.content.Context import android.content.Context
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.request.basicAuth import io.ktor.client.request.basicAuth
import io.ktor.client.request.post import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.http.headers import io.ktor.http.headers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -24,7 +23,7 @@ class LastEntranceNetworkDataSource(
runCatching { runCatching {
val username = userDataStoreManager.usernameFlow.first() val username = userDataStoreManager.usernameFlow.first()
val password = userDataStoreManager.passwordFlow.first() val password = userDataStoreManager.passwordFlow.first()
val result = client.post("${Constants.SERVER_ADDRESS}/api/entrance/last"){ val result = client.get("${Constants.SERVER_ADDRESS}/api/entrance/last"){
headers{ headers{
basicAuth(username, password) basicAuth(username, password)
} }
@ -32,7 +31,6 @@ class LastEntranceNetworkDataSource(
if (result.status != HttpStatusCode.OK) { if (result.status != HttpStatusCode.OK) {
error("Status ${result.status}") error("Status ${result.status}")
} }
println(result.bodyAsText())
result.body() result.body()
} }
} }

View File

@ -12,7 +12,8 @@ class LastEntranceRepoImpl(
id = dto.id ?: 0, id = dto.id ?: 0,
scanTime = dto.scanTime, scanTime = dto.scanTime,
readerName = dto.readerName ?: "", readerName = dto.readerName ?: "",
type = dto.type ?: "" type = dto.type ?: "",
entryType = dto.entryType
) )
} }
} }

View File

@ -1,5 +1,6 @@
package ru.myitschool.work.data.login package ru.myitschool.work.data.login
import android.content.Context
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.request.basicAuth import io.ktor.client.request.basicAuth
import io.ktor.client.request.post import io.ktor.client.request.post
@ -8,10 +9,13 @@ import io.ktor.http.HttpStatusCode
import io.ktor.http.headers import io.ktor.http.headers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import ru.myitschool.work.R
import ru.myitschool.work.core.Constants import ru.myitschool.work.core.Constants
import ru.myitschool.work.utils.NetworkModule import ru.myitschool.work.utils.NetworkModule
class LoginNetworkDataSource { class LoginNetworkDataSource(
private val context: Context
) {
private val client = NetworkModule.httpClient private val client = NetworkModule.httpClient
suspend fun login(username: String, password: String):Result<Unit> = withContext(Dispatchers.IO){ suspend fun login(username: String, password: String):Result<Unit> = withContext(Dispatchers.IO){
runCatching { runCatching {
@ -21,7 +25,10 @@ class LoginNetworkDataSource {
basicAuth(username, password) basicAuth(username, password)
} }
} }
if (result.status != HttpStatusCode.OK) { if(result.status == HttpStatusCode.Unauthorized){
error(context.getString(R.string.login_unauthorized))
}
else if (result.status != HttpStatusCode.OK) {
error("Status ${result.status}") error("Status ${result.status}")
} }
println(result.bodyAsText()) println(result.bodyAsText())

View File

@ -3,5 +3,7 @@ package ru.myitschool.work.domain.employeeList
import ru.myitschool.work.entities.EmployeeEntity import ru.myitschool.work.entities.EmployeeEntity
interface EmployeeListRepo { interface EmployeeListRepo {
suspend fun getList() : Result<List<EmployeeEntity>> suspend fun getList(
pageNum: Int,
pageSize: Int ) : Result<List<EmployeeEntity>>
} }

View File

@ -3,5 +3,5 @@ package ru.myitschool.work.domain.employeeList
class GetEmployeeListUseCase( class GetEmployeeListUseCase(
private val repo: EmployeeListRepo private val repo: EmployeeListRepo
) { ) {
suspend operator fun invoke() = repo.getList() suspend operator fun invoke(pageNum: Int, pageSize: Int) = repo.getList(pageNum, pageSize)
} }

View File

@ -10,5 +10,6 @@ data class EmployeeEntranceDTO(
@SerialName("id") val id : Int?, @SerialName("id") val id : Int?,
@SerialName("entryTime") @Serializable(with = DateSerializer::class) val scanTime : Date?, @SerialName("entryTime") @Serializable(with = DateSerializer::class) val scanTime : Date?,
@SerialName("readerName") val readerName: String?, @SerialName("readerName") val readerName: String?,
@SerialName("type") val type: String? @SerialName("type") val type: String?,
@SerialName("entryType") val entryType: String?
) )

View File

@ -2,8 +2,9 @@ package ru.myitschool.work.entities
import java.util.Date import java.util.Date
data class EmployeeEntranceEntity( data class EmployeeEntranceEntity(
val id : Int, val id : Int?,
val scanTime : Date?, val scanTime : Date?,
val readerName: String, val readerName: String?,
val type: String val type: String?,
val entryType: String?
) )

View File

@ -49,8 +49,10 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
when(state){ when(state){
is LoginViewModel.State.Error -> { is LoginViewModel.State.Error -> {
error.visibility = View.VISIBLE error.visibility = View.VISIBLE
error.text = state.message
loading.visibility = View.GONE loading.visibility = View.GONE
username.isEnabled = true username.isEnabled = true
} }
is LoginViewModel.State.Idle -> { is LoginViewModel.State.Idle -> {
loading.visibility = View.GONE loading.visibility = View.GONE

View File

@ -31,7 +31,6 @@ class LoginViewModel(
if(username != "" && password != "") if(username != "" && password != "")
login(username, password) login(username, password)
} }
} }
sealed class State { sealed class State {
@ -63,7 +62,9 @@ class LoginViewModel(
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory { val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T { override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
val repoImpl = LoginRepoImpl( val repoImpl = LoginRepoImpl(
networkDataSource = LoginNetworkDataSource() networkDataSource = LoginNetworkDataSource(
context = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
)
) )
val useCase = LoginUseCase(repoImpl) val useCase = LoginUseCase(repoImpl)

View File

@ -4,9 +4,11 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.paging.PagingDataAdapter import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ru.myitschool.work.R
import ru.myitschool.work.databinding.ItemVisitBinding import ru.myitschool.work.databinding.ItemVisitBinding
import ru.myitschool.work.entities.EmployeeEntranceEntity import ru.myitschool.work.entities.EmployeeEntranceEntity
import ru.myitschool.work.utils.dateConverter import ru.myitschool.work.utils.monthConverter
import ru.myitschool.work.utils.timeConverter
class EmployeeEntranceListAdapter : PagingDataAdapter<EmployeeEntranceEntity, EmployeeEntranceListAdapter.ViewHolder>(DiffUtil) { class EmployeeEntranceListAdapter : PagingDataAdapter<EmployeeEntranceEntity, EmployeeEntranceListAdapter.ViewHolder>(DiffUtil) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : ViewHolder{ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : ViewHolder{
@ -27,14 +29,23 @@ class EmployeeEntranceListAdapter : PagingDataAdapter<EmployeeEntranceEntity, Em
private val binding: ItemVisitBinding, private val binding: ItemVisitBinding,
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: EmployeeEntranceEntity) { fun bind(item: EmployeeEntranceEntity) {
binding.readerName.text = item.readerName binding.visitReaderId.text = item.readerName
binding.timeVisit.text = dateConverter(item.scanTime) binding.visitDate.text = monthConverter(item.scanTime)
binding.visitTime.text = timeConverter(item.scanTime)
binding.visitDirection.text = item.entryType
if(item.type == "smartphone"){
binding.visitType.setImageResource(R.drawable.logo_visit_scan)
}
else{
binding.visitType.setImageResource(R.drawable.logo_visit_card)
}
} }
} }
object DiffUtil : androidx.recyclerview.widget.DiffUtil.ItemCallback<EmployeeEntranceEntity>() { object DiffUtil : androidx.recyclerview.widget.DiffUtil.ItemCallback<EmployeeEntranceEntity>() {
override fun areItemsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean { override fun areItemsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean {
return oldItem.scanTime == newItem.scanTime return oldItem.id == newItem.id
} }
override fun areContentsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean { override fun areContentsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean {
return oldItem == newItem return oldItem == newItem

View File

@ -20,6 +20,7 @@ import ru.myitschool.work.ui.qr.scan.QrScanDestination
import ru.myitschool.work.utils.UserState import ru.myitschool.work.utils.UserState
import ru.myitschool.work.utils.collectWhenStarted import ru.myitschool.work.utils.collectWhenStarted
import ru.myitschool.work.utils.collectWithLifecycle import ru.myitschool.work.utils.collectWithLifecycle
import ru.myitschool.work.utils.dateTimeConverter
class MainFragment : Fragment(R.layout.fragment_main) { class MainFragment : Fragment(R.layout.fragment_main) {
@ -34,6 +35,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
_binding = FragmentMainBinding.bind(view) _binding = FragmentMainBinding.bind(view)
viewModel.getUserData() viewModel.getUserData()
viewModel.getLastEntryDate()
binding.logout.setOnClickListener { logout() } binding.logout.setOnClickListener { logout() }
binding.scan.setOnClickListener { onScanClick() } binding.scan.setOnClickListener { onScanClick() }
@ -56,7 +58,30 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.loading.visibility = View.GONE binding.loading.visibility = View.GONE
binding.error.visibility = View.GONE binding.error.visibility = View.GONE
showUserData(state.employeeEntity) showUserData(state.employeeEntity)
}
}
}
viewModel.dateState.collectWhenStarted(this) { state ->
println(state)
when (state) {
is MainViewModel.DateState.Error -> {
binding.error.visibility = View.VISIBLE
binding.error.text = state.message
binding.loading.visibility = View.GONE
binding.content.visibility = View.GONE
}
is MainViewModel.DateState.Loading -> {
binding.error.visibility = View.GONE
binding.loading.visibility = View.VISIBLE
binding.lastEntry.visibility = View.GONE
binding.content.visibility = View.GONE
}
is MainViewModel.DateState.Success -> {
binding.error.visibility = View.GONE
binding.loading.visibility = View.GONE
binding.lastEntry.text = dateTimeConverter(state.data.scanTime)
binding.lastEntry.visibility = View.VISIBLE
binding.content.visibility = View.VISIBLE
} }
} }
} }
@ -65,11 +90,13 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.refresh.setOnClickListener { binding.refresh.setOnClickListener {
viewModel.getUserData() viewModel.getUserData()
adapter.refresh() adapter.refresh()
viewModel.getLastEntryDate()
} }
binding.content.adapter = adapter binding.content.adapter = adapter
viewModel.listState.collectWithLifecycle(this) { data -> viewModel.listState.collectWithLifecycle(this) { data ->
adapter.submitData(data) adapter.submitData(data)
} }
adapter.loadStateFlow.collectWithLifecycle(this) { loadState -> adapter.loadStateFlow.collectWithLifecycle(this) { loadState ->
val state = loadState.refresh val state = loadState.refresh
binding.error.visibility = if (state is LoadState.Error) View.VISIBLE else View.GONE binding.error.visibility = if (state is LoadState.Error) View.VISIBLE else View.GONE
@ -88,10 +115,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
findNavController().navigate(R.id.qrResultFragment, bundleToQrResult) findNavController().navigate(R.id.qrResultFragment, bundleToQrResult)
} }
} }
private fun logout() { private fun logout() {
lifecycleScope.launch { lifecycleScope.launch {
viewModel.clearUsername() viewModel.clearUsername()
@ -100,8 +124,6 @@ class MainFragment : Fragment(R.layout.fragment_main) {
} }
} }
private fun showUserData(employeeEntity: EmployeeEntity) { private fun showUserData(employeeEntity: EmployeeEntity) {
binding.apply { binding.apply {
fullname.text = employeeEntity.name fullname.text = employeeEntity.name

View File

@ -19,15 +19,24 @@ import ru.myitschool.work.data.profile.ProfileNetworkDataSource
import ru.myitschool.work.data.profile.ProfileRepoImpl import ru.myitschool.work.data.profile.ProfileRepoImpl
import ru.myitschool.work.data.entrance.employeeEntrances.EmployeeEntranceListNetworkDataSource import ru.myitschool.work.data.entrance.employeeEntrances.EmployeeEntranceListNetworkDataSource
import ru.myitschool.work.data.entrance.employeeEntrances.EmployeeEntranceListRepoImpl import ru.myitschool.work.data.entrance.employeeEntrances.EmployeeEntranceListRepoImpl
import ru.myitschool.work.data.entrance.lastEntrance.LastEntranceNetworkDataSource
import ru.myitschool.work.data.entrance.lastEntrance.LastEntranceRepoImpl
import ru.myitschool.work.domain.profile.GetProfileUseCase import ru.myitschool.work.domain.profile.GetProfileUseCase
import ru.myitschool.work.domain.employeeEntrance.employeeEntrances.GetEmployeeEntranceListUseCase import ru.myitschool.work.domain.employeeEntrance.employeeEntrances.GetEmployeeEntranceListUseCase
import ru.myitschool.work.domain.employeeEntrance.lastEntrance.GetLastEntranceUseCase
import ru.myitschool.work.entities.EmployeeEntranceEntity
import ru.myitschool.work.utils.UserState import ru.myitschool.work.utils.UserState
class MainViewModel( class MainViewModel(
private val infoUseCase: GetProfileUseCase, private val infoUseCase: GetProfileUseCase,
private val listUseCase: GetEmployeeEntranceListUseCase, private val listUseCase: GetEmployeeEntranceListUseCase,
private val lastEntranceUseCase: GetLastEntranceUseCase,
application: Application application: Application
) : AndroidViewModel(application) { ) : AndroidViewModel(application) {
private val _userState = MutableStateFlow<UserState>(UserState.Loading)
val userState: StateFlow<UserState> get() = _userState
private val _dateState = MutableStateFlow<DateState>(DateState.Loading)
val dateState: StateFlow<DateState> get() = _dateState
val listState = Pager( val listState = Pager(
config = PagingConfig( config = PagingConfig(
@ -36,23 +45,14 @@ class MainViewModel(
maxSize = 30 maxSize = 30
) )
) { ) {
println("Creating PagingSource")
EmployeeEntranceListPagingSource(listUseCase::invoke) EmployeeEntranceListPagingSource(listUseCase::invoke)
}.flow.cachedIn(viewModelScope) }.flow.cachedIn(viewModelScope)
init {
viewModelScope.launch {
listState.collect { pagingData ->
if (pagingData.toString().isEmpty()) {
println("No data in paging data.")
} else {
println("Data received: $pagingData")
}
}
}
}
private val _userState = MutableStateFlow<UserState>(UserState.Loading) sealed class DateState {
val userState: StateFlow<UserState> get() = _userState data object Loading : DateState()
data class Success(val data : EmployeeEntranceEntity) : DateState()
data class Error(val message: String?) : DateState()
}
private val dataStoreManager = UserDataStoreManager(application) private val dataStoreManager = UserDataStoreManager(application)
@ -66,6 +66,19 @@ class MainViewModel(
) )
} }
} }
fun getLastEntryDate(){
_dateState.value = DateState.Loading
viewModelScope.launch {
lastEntranceUseCase.invoke().fold(
onSuccess = { data ->
_dateState.value = DateState.Success(data)
},
onFailure = { e ->
_dateState.value = DateState.Error(e.message)
}
)
}
}
fun clearUsername() { fun clearUsername() {
viewModelScope.launch{ viewModelScope.launch{
@ -89,12 +102,21 @@ class MainViewModel(
context = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application context = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
) )
) )
val lastEntranceRepoImpl = LastEntranceRepoImpl(
networkDataSource = LastEntranceNetworkDataSource(
context = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
)
)
val infoUseCase = GetProfileUseCase(profileRepoImpl) val infoUseCase = GetProfileUseCase(profileRepoImpl)
val listUseCase = GetEmployeeEntranceListUseCase(listInfoImpl) val listUseCase = GetEmployeeEntranceListUseCase(listInfoImpl)
val lastEntranceUseCase = GetLastEntranceUseCase(lastEntranceRepoImpl)
return MainViewModel( return MainViewModel(
infoUseCase, listUseCase, extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application infoUseCase,
listUseCase,
lastEntranceUseCase,
extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
) as T ) as T
} }
} }

View File

@ -1,15 +1,31 @@
package ru.myitschool.work.utils package ru.myitschool.work.utils
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
fun dateConverter(date: Date?) : String { fun dateTimeConverter(date: Date?) : String {
if (date != null) { if (date != null) {
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) val dateFormat = SimpleDateFormat("HH:mm • yyyy-MM-dd", Locale.getDefault())
println(dateFormat.format(date).toString()) return dateFormat.format(date).toString()
}
return ""
}
fun monthConverter(date: Date?) : String {
if (date != null) {
val russianLocale = Locale("ru", "RU", "variant")
val localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
val formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", russianLocale)
return localDate.format(formatter)
}
return ""
}
fun timeConverter(date: Date?) : String {
if (date != null) {
val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
return dateFormat.format(date).toString() return dateFormat.format(date).toString()
} }
return "" return ""
} }

View File

@ -11,7 +11,7 @@ import java.util.Date
import java.util.Locale import java.util.Locale
object DateSerializer : KSerializer<Date> { object DateSerializer : KSerializer<Date> {
private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US) private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm", Locale.US)
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING) override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

View File

@ -16,4 +16,5 @@
<string name="result_null_text">Operation was cancelled</string> <string name="result_null_text">Operation was cancelled</string>
<string name="password_hint">Enter the password</string> <string name="password_hint">Enter the password</string>
<string name="history_title">Visit history</string> <string name="history_title">Visit history</string>
<string name="login_unauthorized">Incorrect login or password</string>
</resources> </resources>

View File

@ -18,7 +18,7 @@
<string name="close_btn">Закрыть</string> <string name="close_btn">Закрыть</string>
<string name="password_hint">Введите пароль</string> <string name="password_hint">Введите пароль</string>
<string name="history_title">История посещений</string> <string name="history_title">История посещений</string>
<!-- TODO: Remove or change this placeholder text --> <string name="login_unauthorized">Неправильное имя пользователя или пароль</string>
</resources> </resources>