diff --git a/app/src/main/java/ru/myitschool/work/data/UserDataStoreManager.kt b/app/src/main/java/ru/myitschool/work/data/UserDataStoreManager.kt index 3478ca7..ba5b650 100644 --- a/app/src/main/java/ru/myitschool/work/data/UserDataStoreManager.kt +++ b/app/src/main/java/ru/myitschool/work/data/UserDataStoreManager.kt @@ -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 = context.applicationContext.dataStore.data.map { prefs -> prefs[USERNAME_KEY] ?: "" } + val passwordFlow: Flow = context.applicationContext.dataStore.data.map { prefs -> + prefs[PASSWORD_KEY] ?: "" + } val roleFlow: Flow = 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() } } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/door/DoorNetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/door/DoorNetworkDataSource.kt index 4589597..4384151 100644 --- a/app/src/main/java/ru/myitschool/work/data/door/DoorNetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/door/DoorNetworkDataSource.kt @@ -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 = withContext(Dispatchers.IO){ + suspend fun openDoor(code : String): Result = 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}") diff --git a/app/src/main/java/ru/myitschool/work/data/door/DoorRepoImpl.kt b/app/src/main/java/ru/myitschool/work/data/door/DoorRepoImpl.kt index 510c241..9b627df 100644 --- a/app/src/main/java/ru/myitschool/work/data/door/DoorRepoImpl.kt +++ b/app/src/main/java/ru/myitschool/work/data/door/DoorRepoImpl.kt @@ -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 { - return networkDataSource.openDoor(openEntity.toDto()) + override suspend fun openDoor(code: String): Result { + return networkDataSource.openDoor(code) } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/dto/OpenRequestDTO.kt b/app/src/main/java/ru/myitschool/work/data/dto/OpenRequestDTO.kt deleted file mode 100644 index 159c5a0..0000000 --- a/app/src/main/java/ru/myitschool/work/data/dto/OpenRequestDTO.kt +++ /dev/null @@ -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 -) \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/dto/UserDTO.kt b/app/src/main/java/ru/myitschool/work/data/dto/UserDTO.kt index 3e0e4be..d2a74c4 100644 --- a/app/src/main/java/ru/myitschool/work/data/dto/UserDTO.kt +++ b/app/src/main/java/ru/myitschool/work/data/dto/UserDTO.kt @@ -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? ) diff --git a/app/src/main/java/ru/myitschool/work/data/dto/VisitDTO.kt b/app/src/main/java/ru/myitschool/work/data/dto/VisitDTO.kt index e7b77a2..2dd1e6d 100644 --- a/app/src/main/java/ru/myitschool/work/data/dto/VisitDTO.kt +++ b/app/src/main/java/ru/myitschool/work/data/dto/VisitDTO.kt @@ -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? ) diff --git a/app/src/main/java/ru/myitschool/work/data/info/InfoNetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/info/InfoNetworkDataSource.kt index 1b38515..99eb908 100644 --- a/app/src/main/java/ru/myitschool/work/data/info/InfoNetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/info/InfoNetworkDataSource.kt @@ -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 = 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}") } diff --git a/app/src/main/java/ru/myitschool/work/data/info/InfoRepoImpl.kt b/app/src/main/java/ru/myitschool/work/data/info/InfoRepoImpl.kt index 9c82918..bfb70ff 100644 --- a/app/src/main/java/ru/myitschool/work/data/info/InfoRepoImpl.kt +++ b/app/src/main/java/ru/myitschool/work/data/info/InfoRepoImpl.kt @@ -7,13 +7,16 @@ class InfoRepoImpl( private val networkDataSource: InfoNetworkDataSource ): InfoRepo { override suspend fun getInfo(): Result { - 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 ?: "" ) } + } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/login/LoginNetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/login/LoginNetworkDataSource.kt index a2b5063..40b5e82 100644 --- a/app/src/main/java/ru/myitschool/work/data/login/LoginNetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/login/LoginNetworkDataSource.kt @@ -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 = withContext(Dispatchers.IO){ + suspend fun login(username: String, password: String):Result = 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() } } diff --git a/app/src/main/java/ru/myitschool/work/data/login/LoginRepoImpl.kt b/app/src/main/java/ru/myitschool/work/data/login/LoginRepoImpl.kt index 890931b..ff6d56a 100644 --- a/app/src/main/java/ru/myitschool/work/data/login/LoginRepoImpl.kt +++ b/app/src/main/java/ru/myitschool/work/data/login/LoginRepoImpl.kt @@ -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 { - return networkDataSource.login(username) + override suspend fun login(username: String, password: String): Result { + return networkDataSource.login(username, password) } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/visitsList/VisitListRepoImpl.kt b/app/src/main/java/ru/myitschool/work/data/visitsList/VisitListRepoImpl.kt deleted file mode 100644 index 1accfab..0000000 --- a/app/src/main/java/ru/myitschool/work/data/visitsList/VisitListRepoImpl.kt +++ /dev/null @@ -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> { - 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")) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/visitsList/VisitListNetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/visitsList/employeeEntrances/EmployeeEntranceListNetworkDataSource.kt similarity index 72% rename from app/src/main/java/ru/myitschool/work/data/visitsList/VisitListNetworkDataSource.kt rename to app/src/main/java/ru/myitschool/work/data/visitsList/employeeEntrances/EmployeeEntranceListNetworkDataSource.kt index cbc833b..335f3c9 100644 --- a/app/src/main/java/ru/myitschool/work/data/visitsList/VisitListNetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/visitsList/employeeEntrances/EmployeeEntranceListNetworkDataSource.kt @@ -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 = 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}") diff --git a/app/src/main/java/ru/myitschool/work/data/visitsList/employeeEntrances/EmployeeEntranceListRepoImpl.kt b/app/src/main/java/ru/myitschool/work/data/visitsList/employeeEntrances/EmployeeEntranceListRepoImpl.kt new file mode 100644 index 0000000..0b9ea26 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/visitsList/employeeEntrances/EmployeeEntranceListRepoImpl.kt @@ -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> { + 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")) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/door/DoorRepo.kt b/app/src/main/java/ru/myitschool/work/domain/door/DoorRepo.kt index bd96676..8b5223e 100644 --- a/app/src/main/java/ru/myitschool/work/domain/door/DoorRepo.kt +++ b/app/src/main/java/ru/myitschool/work/domain/door/DoorRepo.kt @@ -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 + suspend fun openDoor(code: String) : Result } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/door/OpenDoorUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/door/OpenDoorUseCase.kt index f968d4a..98c39c0 100644 --- a/app/src/main/java/ru/myitschool/work/domain/door/OpenDoorUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/door/OpenDoorUseCase.kt @@ -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) } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/entities/VisitEntity.kt b/app/src/main/java/ru/myitschool/work/domain/entities/EmployeeEntranceEntity.kt similarity index 64% rename from app/src/main/java/ru/myitschool/work/domain/entities/VisitEntity.kt rename to app/src/main/java/ru/myitschool/work/domain/entities/EmployeeEntranceEntity.kt index 8cce8f6..91b9830 100644 --- a/app/src/main/java/ru/myitschool/work/domain/entities/VisitEntity.kt +++ b/app/src/main/java/ru/myitschool/work/domain/entities/EmployeeEntranceEntity.kt @@ -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 ) diff --git a/app/src/main/java/ru/myitschool/work/domain/entities/OpenEntity.kt b/app/src/main/java/ru/myitschool/work/domain/entities/OpenEntity.kt deleted file mode 100644 index 288b068..0000000 --- a/app/src/main/java/ru/myitschool/work/domain/entities/OpenEntity.kt +++ /dev/null @@ -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 - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/entities/UserEntity.kt b/app/src/main/java/ru/myitschool/work/domain/entities/UserEntity.kt index 4500cb7..1e99a45 100644 --- a/app/src/main/java/ru/myitschool/work/domain/entities/UserEntity.kt +++ b/app/src/main/java/ru/myitschool/work/domain/entities/UserEntity.kt @@ -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 ) \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/login/LoginRepo.kt b/app/src/main/java/ru/myitschool/work/domain/login/LoginRepo.kt index c63ac08..e3392f4 100644 --- a/app/src/main/java/ru/myitschool/work/domain/login/LoginRepo.kt +++ b/app/src/main/java/ru/myitschool/work/domain/login/LoginRepo.kt @@ -1,5 +1,5 @@ package ru.myitschool.work.domain.login interface LoginRepo { - suspend fun login(username: String): Result + suspend fun login(username: String, password: String): Result } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/login/LoginUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/login/LoginUseCase.kt index 5798888..a977b27 100644 --- a/app/src/main/java/ru/myitschool/work/domain/login/LoginUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/login/LoginUseCase.kt @@ -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) } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/visitsList/EmployeeEntranceListRepo.kt b/app/src/main/java/ru/myitschool/work/domain/visitsList/EmployeeEntranceListRepo.kt new file mode 100644 index 0000000..22957cc --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/visitsList/EmployeeEntranceListRepo.kt @@ -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> +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/visitsList/GetVisitListUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/visitsList/GetEmployeeEntranceListUseCase.kt similarity index 63% rename from app/src/main/java/ru/myitschool/work/domain/visitsList/GetVisitListUseCase.kt rename to app/src/main/java/ru/myitschool/work/domain/visitsList/GetEmployeeEntranceListUseCase.kt index 7735f8e..be24827 100644 --- a/app/src/main/java/ru/myitschool/work/domain/visitsList/GetVisitListUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/visitsList/GetEmployeeEntranceListUseCase.kt @@ -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) } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/visitsList/VisitListRepo.kt b/app/src/main/java/ru/myitschool/work/domain/visitsList/VisitListRepo.kt deleted file mode 100644 index 76937fe..0000000 --- a/app/src/main/java/ru/myitschool/work/domain/visitsList/VisitListRepo.kt +++ /dev/null @@ -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> -} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt index 39feb40..bb17210 100644 --- a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt @@ -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 { diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt index e6f1502..75a34cc 100644 --- a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt @@ -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-> diff --git a/app/src/main/java/ru/myitschool/work/ui/main/EmployeeEntranceListAdapter.kt b/app/src/main/java/ru/myitschool/work/ui/main/EmployeeEntranceListAdapter.kt new file mode 100644 index 0000000..8d0cbf3 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/main/EmployeeEntranceListAdapter.kt @@ -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(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() { + override fun areItemsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean { + return oldItem.scanTime == newItem.scanTime + } + override fun areContentsTheSame(oldItem: EmployeeEntranceEntity, newItem: EmployeeEntranceEntity): Boolean { + return oldItem == newItem + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/main/EmployeeEntranceListPagingSource.kt b/app/src/main/java/ru/myitschool/work/ui/main/EmployeeEntranceListPagingSource.kt new file mode 100644 index 0000000..58662c2 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/main/EmployeeEntranceListPagingSource.kt @@ -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> +) : 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 = { e-> + LoadResult.Error(e) + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt b/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt index 69c4b06..25a4f5d 100644 --- a/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt @@ -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 diff --git a/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt index 641f149..9aece66 100644 --- a/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt @@ -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.Loading) val userState: StateFlow 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 create(modelClass: Class, 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 } } diff --git a/app/src/main/java/ru/myitschool/work/ui/main/VisitListPagingSource.kt b/app/src/main/java/ru/myitschool/work/ui/main/VisitListPagingSource.kt deleted file mode 100644 index 04c18b8..0000000 --- a/app/src/main/java/ru/myitschool/work/ui/main/VisitListPagingSource.kt +++ /dev/null @@ -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> -) : 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 { - TODO("Not yet implemented") - } -} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultFragment.kt b/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultFragment.kt index 2ac5b52..a4e0933 100644 --- a/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultFragment.kt @@ -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) diff --git a/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultViewModel.kt index 34308bd..a21a426 100644 --- a/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/qr/result/QrResultViewModel.kt @@ -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 = { _ -> diff --git a/app/src/main/java/ru/myitschool/work/utils/DateConverter.kt b/app/src/main/java/ru/myitschool/work/utils/DateConverter.kt new file mode 100644 index 0000000..b12facb --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/utils/DateConverter.kt @@ -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 "" +} \ No newline at end of file