diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt index a369592..70b2b55 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/UserServiceST.kt @@ -44,6 +44,12 @@ class UserServiceST( } return userRepository.getInfo(tokenManager.authTokenPair!!.accessToken) } + suspend fun getInfoByLogin(login: String): Result{ + if (!tokenManager.hasTokens()) { + throw RuntimeException("access token is null") + } + return userRepository.getInfoByLogin(tokenManager.authTokenPair!!.accessToken, login) + } suspend fun openDoor(code: String): Result { return userRepository.openDoor(tokenManager.authTokenPair!!.accessToken, code = code) } diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt index 39634b5..1f7ab2c 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/UserRepository.kt @@ -83,6 +83,22 @@ class UserRepository( result.body() } } + suspend fun getInfoByLogin(token: String, login: String): Result = withContext(Dispatchers.IO){ + runCatching { + val encodedLogin = login.encodeURLPath() + val result = Network.client.get("$serverUrl/api/users/login/$encodedLogin") { + headers { + append(HttpHeaders.Authorization, "Bearer $token") + } + setBody("""{ "code": "$encodedLogin" }""") + } + if (result.status != HttpStatusCode.OK) { + error("Status ${result.status}: ${result.body()}") + } + Log.d("UserRepository", result.bodyAsText()) + result.body() + } + } suspend fun openDoor(token: String, code: Long): Result = withContext(Dispatchers.IO) { runCatching { val result = Network.client.patch("$serverUrl/api/open") { diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt index a913f59..1b97fdf 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserDTO.kt @@ -23,4 +23,4 @@ data class UserDTO ( @SerialName("lastVisit") val lastVisit: String, -) \ No newline at end of file +) : java.io.Serializable \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/config/Constants.kt b/app/src/main/java/com/displaynone/acss/config/Constants.kt index 43646d9..350a0dc 100644 --- a/app/src/main/java/com/displaynone/acss/config/Constants.kt +++ b/app/src/main/java/com/displaynone/acss/config/Constants.kt @@ -1,5 +1,5 @@ package com.displaynone.acss.config object Constants { - const val serverUrl = "http://192.168.1.107:8080" + const val serverUrl = "http://192.168.56.1:8086" } diff --git a/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt b/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt new file mode 100644 index 0000000..522c287 --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt @@ -0,0 +1,48 @@ +package com.displaynone.acss.ui.admin + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import com.displaynone.acss.R +import com.displaynone.acss.util.collectWithLifecycle +import com.displaynone.acss.util.navigateTo +import com.displaynone.acss.databinding.FragmentAdminBinding +import com.displaynone.acss.databinding.FragmentAuthBinding + +class AdminFragment : Fragment(R.layout.fragment_admin) { + private var _binding: FragmentAdminBinding? = null + private val binding: FragmentAdminBinding get() = _binding!! + + private val viewModel: AdminViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentAdminBinding.bind(view) + + subscribeToState(view) + + binding.buttonSearch.setOnClickListener{ + onSearchButtonClicked() + } + } + + private fun onSearchButtonClicked() { + val login = binding.editTextTextEmailAddress.text.toString() + if (login.isEmpty()) return + + viewModel.getDataByLogin(login) + } + + private fun subscribeToState(view: View){ + viewModel.state.collectWithLifecycle(this){ state -> + if (state is AdminViewModel.State.Show){ + val userDto = state.item + val bundle = Bundle().apply{ + putSerializable("user", userDto) + } + navigateTo(view, R.id.action_adminFragment_to_profileFragment, bundle) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt new file mode 100644 index 0000000..739a0f0 --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/ui/admin/AdminViewModel.kt @@ -0,0 +1,35 @@ +package com.displaynone.acss.ui.admin + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.displaynone.acss.components.auth.models.user.UserServiceST +import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO +import com.displaynone.acss.ui.profile.ProfileViewModel.State +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +class AdminViewModel: ViewModel() { + val _state = MutableStateFlow(State.Loading) + val state = _state.asStateFlow() + fun getDataByLogin(login: String){ + viewModelScope.launch { + UserServiceST.getInstance().getInfoByLogin(login).fold( + onSuccess = { dto -> + _state.emit(State.Show(item = dto)) + }, + onFailure = { error -> + error.message?.let { error(it) } + Log.e("AdminViewModel", error.message.toString()) } + ) + } + } + + sealed interface State { + data class Show( + val item: UserDTO + ): State + data object Loading : State + } +} \ No newline at end of file diff --git a/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt b/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt index 823bc73..7cea88b 100644 --- a/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt +++ b/app/src/main/java/com/displaynone/acss/ui/auth/AuthFragment.kt @@ -22,14 +22,17 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { private val viewModel: AuthViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentAuthBinding.bind(view) setupLoginButton() viewModel.action.collectWithLifecycle(this) { action -> - when (action) { - Action.GotoProfile -> navigateTo(view, R.id.action_authFragment_to_profileFragment) + if (action is Action.GotoProfile) { + blockLoginButton() // FIXME() При двойном нажатии вылетает с ошибкой + navigateTo(view, R.id.action_authFragment_to_profileFragment) } } viewModel.errorState.collectWithLifecycle(this) { errorMessage -> @@ -43,7 +46,9 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { onLoginButtonClicked(view) } } - + private fun blockLoginButton() { + binding.next.isEnabled = false + } private fun setupLoginButton() { binding.login.addTextChangedListener(object : TextWatcher { @@ -79,7 +84,6 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { private fun onLoginButtonClicked(view: View) { val login = binding.login.text.toString() if (login.isEmpty()) return - viewModel.login(login) } diff --git a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt index 0e35309..61cc935 100644 --- a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt +++ b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileFragment.kt @@ -37,11 +37,23 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) { binding.scan.setOnClickListener{ viewModel.openScan() } + val user = getUserDto() + if (user == null) { + refreshData() + waitForQRScanResult() + } else{ + showData(user) // TODO() не показывать кнопки + } subscribe() - refreshData() - waitForQRScanResult() + } + fun showData(userDTO: UserDTO){ + binding.fio.text = userDTO.name + binding.position.text = userDTO.position + binding.lastEntry.text = userDTO.lastVisit + setAvatar(userDTO.photo) + } private fun refreshData() { Log.d("ProfileFragment", "Refreshed") viewModel.getInfo() @@ -53,10 +65,13 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) { view?.let { navigateTo(it, R.id.action_profileFragment_to_authFragment) } ?: throw IllegalStateException("View is null") } if (action is Action.GoToScan) { - view?.let { navigateTo(it, R.id.action_profileFragment_to_qrScanFragment) }?: throw IllegalStateException("View is null") + view?.let { navigateTo(it, R.id.action_profileFragment_to_adminFragment) }?: throw IllegalStateException("View is null") } } } + private fun getUserDto(): UserDTO? { + return arguments?.getSerializable("user") as? UserDTO + } private fun waitForQRScanResult() { requireActivity().onBackPressedDispatcher.addCallback( @@ -89,10 +104,7 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) { viewModel.state.collectWithLifecycle(this) { state -> if (state is ProfileViewModel.State.Show) { val userDto: UserDTO = state.item - binding.fio.text = userDto.name - binding.position.text = userDto.position - binding.lastEntry.text = userDto.lastVisit - setAvatar(userDto.photo) + showData(userDto) } } } diff --git a/app/src/main/res/layout/administrator_search_by_login.xml b/app/src/main/res/layout/fragment_admin.xml similarity index 100% rename from app/src/main/res/layout/administrator_search_by_login.xml rename to app/src/main/res/layout/fragment_admin.xml diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 453aa8f..a01e4ec 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -17,6 +17,9 @@ + + + + \ No newline at end of file