From 5d31ab0c42ed3e3bc3b7db451f215ed334b515cd Mon Sep 17 00:00:00 2001 From: Universall Date: Thu, 20 Feb 2025 15:07:25 +0300 Subject: [PATCH] User cache fix; Bugfix; Refactor --- .../java/com/displaynone/acss/MainActivity.kt | 6 +- .../auth/models/user/UserServiceST.kt | 59 ++++----- .../models/user/repository/UserRepository.kt | 124 ++++++++---------- .../dto/{UserLoginDto.kt => LoginDTO.kt} | 2 +- .../user/repository/dto/LoginResponseDTO.kt | 13 ++ .../displaynone/acss/ui/auth/AuthFragment.kt | 81 +++++++----- .../displaynone/acss/ui/auth/AuthViewModel.kt | 7 +- .../displaynone/acss/ui/init/InitFragment.kt | 46 ++++--- .../acss/ui/profile/ProfileViewModel.kt | 35 +++-- app/src/main/res/layout/fragment_init.xml | 42 +++--- app/src/main/res/navigation/nav_graph.xml | 2 +- app/src/main/res/values-en/strings-en.xml | 2 +- app/src/main/res/values-ru/strings-ru.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 14 files changed, 228 insertions(+), 195 deletions(-) rename app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/{UserLoginDto.kt => LoginDTO.kt} (91%) create mode 100644 app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginResponseDTO.kt diff --git a/app/src/main/java/com/displaynone/acss/MainActivity.kt b/app/src/main/java/com/displaynone/acss/MainActivity.kt index 177425c..581b3b6 100644 --- a/app/src/main/java/com/displaynone/acss/MainActivity.kt +++ b/app/src/main/java/com/displaynone/acss/MainActivity.kt @@ -28,6 +28,7 @@ class MainActivity : AppCompatActivity() { val toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) + val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment ?: throw IllegalStateException("NavHostFragment is null") @@ -38,6 +39,7 @@ class MainActivity : AppCompatActivity() { ) NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration) NavigationUI.setupWithNavController(navView, navController) + supportActionBar!!.setDisplayHomeAsUpEnabled(false) navController.addOnDestinationChangedListener { _, destination, _ -> Log.d("Navigate", "Navigate to " + destination.label) @@ -45,8 +47,8 @@ class MainActivity : AppCompatActivity() { val userDTO = getCachedUser() if (userDTO != null) { - if (!userDTO.roles.any { it.name == "ROLE_ADMIN" }) navView.menu.findItem(R.id.nav_admin) - .setVisible(false) else navView.menu.findItem(R.id.nav_admin).setVisible(true) + val adminButton = navView.menu.findItem(R.id.nav_admin) + if (!userDTO.roles.any { it.name == "ROLE_ADMIN" }) adminButton.setVisible(false) else adminButton.setVisible(true) } } } 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 c7ab743..ae6641c 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 @@ -1,12 +1,12 @@ package com.displaynone.acss.components.auth.models.user import android.content.Context +import android.util.Log import com.displaynone.acss.components.auth.internal_utils.AuthTokenManager import com.displaynone.acss.components.auth.internal_utils.UserManager import com.displaynone.acss.components.auth.models.AuthTokenPair import com.displaynone.acss.components.auth.models.user.repository.UserRepository import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO -import com.displaynone.acss.components.acs.models.visit.repository.dto.VisitDto class UserServiceST( @@ -34,69 +34,64 @@ class UserServiceST( return instance ?: throw RuntimeException("null instance") } } - suspend fun login(login: String, password:String): Result{ + + suspend fun login(login: String, password: String): Result { return runCatching { userRepository.login(login = login, password).getOrThrow().let { data -> - tokenManager.saveTokens(data) + userManager.saveDto(data.user) + tokenManager.saveTokens(data.tokens) } } } + fun getTokenPair(): AuthTokenPair? { return tokenManager.authTokenPair } + fun hasTokens(): Boolean { return tokenManager.hasTokens() } -// suspend fun getMyLastVisits(pageNum: Int, -// pageSize: Int): Result> { -// if (!tokenManager.hasTokens()) { -// throw RuntimeException("access token is null") -// } -// -// return userRepository.getMyLastVisits( -// pageNum = pageNum, -// pageSize = pageSize, -// token = tokenManager.authTokenPair!!.accessToken -// ).map { pagingDto -> pagingDto.content } -// } -// suspend fun getLastVisitsByLogin(pageNum: Int, -// pageSize: Int, -// login: String): Result> { -// if (!tokenManager.hasTokens()) { -// throw RuntimeException("access token is null") -// } -// return userRepository.getLastVisitsByLogin(pageNum, pageSize, tokenManager.authTokenPair!!.accessToken, login).map { pagingDto -> pagingDto.content } -// } - fun logout(){ + + fun logout() { tokenManager.clear() } + suspend fun changeRights(login: String, isACSBlocked: Boolean): Result { - return userRepository.changeRightsByLogin(login, tokenManager.authTokenPair!!.accessToken, isACSBlocked) + return userRepository.changeRightsByLogin( + login, + tokenManager.authTokenPair!!.accessToken, + isACSBlocked + ) } - suspend fun getInfo(): Result{ + + suspend fun getInfo(): Result { if (!tokenManager.hasTokens()) { throw RuntimeException("access token is null") } + val result = userRepository.getInfo(tokenManager.authTokenPair!!.accessToken) - result.map { dto -> - saveUserDTO(dto) - } + result.map { dto -> saveUserDTO(dto) } return result } - suspend fun getInfoByLogin(login: String): Result{ + + 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) } + fun getUserDTO(): UserDTO? { return userManager.dto } - fun saveUserDTO(userDTO: UserDTO){ - return userManager.saveDto(userDTO) + fun saveUserDTO(userDTO: UserDTO) { + Log.d("USER", "UPDATE USER") + + return userManager.saveDto(userDTO) } } \ No newline at end of file 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 6e482c5..49da595 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 @@ -1,22 +1,18 @@ package com.displaynone.acss.components.auth.models.user.repository import android.util.Log -import com.bumptech.glide.load.HttpException -import com.displaynone.acss.components.auth.models.AuthTokenPair -import com.displaynone.acss.config.Constants.serverUrl -import com.displaynone.acss.config.Network -import com.displaynone.acss.components.auth.models.user.repository.dto.RegisterUserDto +import com.displaynone.acss.components.auth.models.user.repository.dto.LoginDTO +import com.displaynone.acss.components.auth.models.user.repository.dto.LoginResponseDTO import com.displaynone.acss.components.auth.models.user.repository.dto.UpdateUserDTO import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO -import com.displaynone.acss.components.auth.models.user.repository.dto.UserLoginDto +import com.displaynone.acss.config.Constants.serverUrl +import com.displaynone.acss.config.Network import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.headers import io.ktor.client.request.patch import io.ktor.client.request.post import io.ktor.client.request.setBody -import io.ktor.client.statement.bodyAsText - import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.HttpStatusCode @@ -24,40 +20,27 @@ import io.ktor.http.contentType import io.ktor.http.encodeURLPath import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json -class UserRepository( - -) { - suspend fun isUserExist(login: String): Result = withContext(Dispatchers.IO) { - runCatching { - val encodedLogin = login.encodeURLPath() - val result = Network.client.get("$serverUrl/api/$encodedLogin/auth/") - result.status != HttpStatusCode.OK - } - } - suspend fun login(login: String, password: String): Result = withContext(Dispatchers.IO) { - runCatching { - val result = Network.client.post("$serverUrl/api/auth/login") { - headers { - append(HttpHeaders.ContentType, ContentType.Application.Json.toString()) +class UserRepository { + suspend fun login(login: String, password: String): Result = + withContext(Dispatchers.IO) { + runCatching { + val result = Network.client.post("$serverUrl/api/auth/login") { + headers { + append(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + } + contentType(ContentType.Application.Json) + setBody(LoginDTO(login, password)) } - contentType(ContentType.Application.Json) - setBody(UserLoginDto(login, password)) + + if (result.status != HttpStatusCode.OK) error(result.status) + + result.body() } - if (result.status != HttpStatusCode.OK) { - error(result.status) - } -// val gson = Gson() -// val tokenPair = gson.fromJson(result.bodyAsText(), AuthTokenPair::class.java) - Log.d("UserRepository", result.bodyAsText()) -// result.body() - val tokenPair = Json.decodeFromString(result.bodyAsText()) - tokenPair } - } - suspend fun openDoor(token: String, code: String): Result = withContext(Dispatchers.IO){ - runCatching{ + + suspend fun openDoor(token: String, code: String): Result = withContext(Dispatchers.IO) { + runCatching { val result = Network.client.post("$serverUrl/api/acs/open") { headers { append(HttpHeaders.Authorization, "Bearer $token") @@ -65,58 +48,61 @@ class UserRepository( contentType(ContentType.Application.Json) setBody("""{ "code": $code }""") } - if (result.status != HttpStatusCode.OK) { - error("Status ${result.status}: ${result.body()}") - } - Log.d("UserRepository", result.bodyAsText()) + + if (result.status != HttpStatusCode.OK) error("Status ${result.status}: ${result.body()}") + result.status.value } } - suspend fun getInfo(token: String): Result = withContext(Dispatchers.IO){ + + suspend fun getInfo(token: String): Result = withContext(Dispatchers.IO) { runCatching { val result = Network.client.get("$serverUrl/api/users/me") { headers { append(HttpHeaders.Authorization, "Bearer $token") } } - if (result.status != HttpStatusCode.OK) { - error("Status ${result.status}: ${result.body()}") - } - Log.d("UserRepository", result.bodyAsText()) + if (result.status != HttpStatusCode.OK) error("Status ${result.status}: ${result.body()}") 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") + + 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" }""") } - setBody("""{ "code": "$encodedLogin" }""") + if (result.status != HttpStatusCode.OK) error("Status ${result.status}: ${result.body()}") + result.body() } - if (result.status != HttpStatusCode.OK) { - error("Status ${result.status}: ${result.body()}") - } - Log.d("UserRepository", result.bodyAsText()) - result.body() } - } - suspend fun changeRightsByLogin(login: String, token: String, isACSBlocked: Boolean): Result = withContext(Dispatchers.IO) { + + suspend fun changeRightsByLogin( + login: String, + token: String, + isACSBlocked: Boolean + ): Result = withContext(Dispatchers.IO) { runCatching { val encodedLogin = login.encodeURLPath() val result = Network.client.patch("$serverUrl/api/users/login/$encodedLogin") { - headers{ + headers { append(HttpHeaders.Authorization, "Bearer $token") } contentType(ContentType.Application.Json) - setBody(UpdateUserDTO( - password = null, - name = null, - photo = null, - position = null, - isACSBlocked = isACSBlocked - )) + setBody( + UpdateUserDTO( + password = null, + name = null, + photo = null, + position = null, + isACSBlocked = isACSBlocked + ) + ) } if (result.status != HttpStatusCode.OK) { Log.w("UserRepository", "Status: ${result.status}, Body: ${result.body()}") diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginDTO.kt similarity index 91% rename from app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt rename to app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginDTO.kt index 7627b6a..641e4c5 100644 --- a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/UserLoginDto.kt +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginDTO.kt @@ -4,7 +4,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class UserLoginDto( +data class LoginDTO( @SerialName("login") val login: String, @SerialName("password") diff --git a/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginResponseDTO.kt b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginResponseDTO.kt new file mode 100644 index 0000000..35f9b13 --- /dev/null +++ b/app/src/main/java/com/displaynone/acss/components/auth/models/user/repository/dto/LoginResponseDTO.kt @@ -0,0 +1,13 @@ +package com.displaynone.acss.components.auth.models.user.repository.dto + +import com.displaynone.acss.components.auth.models.AuthTokenPair +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class LoginResponseDTO( + @SerialName("tokens") + val tokens: AuthTokenPair, + @SerialName("user") + val user: UserDTO, +) \ 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 71433a5..ce19f67 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 @@ -9,18 +9,17 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import com.displaynone.acss.R import com.displaynone.acss.databinding.FragmentAuthBinding +import com.displaynone.acss.ui.auth.AuthViewModel.Action import com.displaynone.acss.util.collectWithLifecycle import com.displaynone.acss.util.navigateTo -import com.displaynone.acss.ui.auth.AuthViewModel.Action -class AuthFragment: Fragment(R.layout.fragment_auth) { +class AuthFragment : Fragment(R.layout.fragment_auth) { private var _binding: FragmentAuthBinding? = null private val binding: FragmentAuthBinding get() = _binding!! private val viewModel: AuthViewModel by viewModels() - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentAuthBinding.bind(view) @@ -40,22 +39,25 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { binding.errorTitle.visibility = View.VISIBLE } } - binding.next.setOnClickListener{ + binding.next.setOnClickListener { onLoginButtonClicked(view) } } + @SuppressLint("StringFormatMatches") private fun getErrorDescription(errorCode: String): String { return when (errorCode) { - 401.toString()+' ' -> getString(R.string.error_401) - 404.toString()+' ' -> getString(R.string.error_404) - 500.toString()+' ' -> getString(R.string.error_500) + 401.toString() + ' ' -> getString(R.string.error_401) + 404.toString() + ' ' -> getString(R.string.error_404) + 500.toString() + ' ' -> getString(R.string.error_500) else -> getString(R.string.error_unknown, errorCode) } } + private fun blockLoginButton() { binding.next.isEnabled = false } + private fun getPasswordValidError(password: String): String { if (password.length < 8) { return "LenError" @@ -76,6 +78,7 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { } } } + private fun getLoginValidError(username: String): String { val alf = "^[a-zA-Z0-9_]+$".toRegex() if (username.isEmpty()) { @@ -97,53 +100,61 @@ class AuthFragment: Fragment(R.layout.fragment_auth) { // password.length >= 8 // } -// private fun subscribe() { + // private fun subscribe() { // viewModel.state.collectWhenStarted(this) { state -> // binding.login.setOnClickListener(this::onLoginButtonClicked) // } // } -private fun validateLoginAndSetError(username: String) { - val errorType = getLoginValidError(username) + private fun validateLoginAndSetError(username: String) { + val errorType = getLoginValidError(username) - when (errorType) { - "EmptyError" -> { - binding.login.error = getString(R.string.error_login_empty) - } - "LenError" -> { - binding.login.error = getString(R.string.error_login_too_short) - } - "StartsWithDigitError" -> { - binding.login.error = getString(R.string.error_login_starts_with_digit) - } - "InvalidCharactersError" -> { - binding.login.error = getString(R.string.error_login_invalid_characters) - } - "NoErrors" -> { - binding.login.error = null + when (errorType) { + "EmptyError" -> { + binding.login.error = getString(R.string.error_login_empty) + } + + "LenError" -> { + binding.login.error = getString(R.string.error_login_too_short) + } + + "StartsWithDigitError" -> { + binding.login.error = getString(R.string.error_login_starts_with_digit) + } + + "InvalidCharactersError" -> { + binding.login.error = getString(R.string.error_login_invalid_characters) + } + + "NoErrors" -> { + binding.login.error = null + } } } -} + private fun onLoginButtonClicked(view: View) { val login = binding.login.text.toString() val password = binding.password.text.toString() + if (getPasswordValidError(password) != "NoErrors") { - - val color = R.color.secondary - binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color) + binding.next.backgroundTintList = + ContextCompat.getColorStateList(requireContext(), color) validatePasswordAndSetError(password) - }else{ + } else { val color = R.color.primary - binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color) + binding.next.backgroundTintList = + ContextCompat.getColorStateList(requireContext(), color) } -// if (login.isEmpty()) return + if (getLoginValidError(login) != "NoErrors") { val color = R.color.secondary - binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color) + binding.next.backgroundTintList = + ContextCompat.getColorStateList(requireContext(), color) validateLoginAndSetError(login) - }else{ + } else { val color = R.color.primary - binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color) + binding.next.backgroundTintList = + ContextCompat.getColorStateList(requireContext(), color) } diff --git a/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt index b653f2a..b163e75 100644 --- a/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt +++ b/app/src/main/java/com/displaynone/acss/ui/auth/AuthViewModel.kt @@ -4,7 +4,6 @@ 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.RegisterUserDto import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow @@ -12,9 +11,8 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch -import kotlin.reflect.typeOf -class AuthViewModel(): ViewModel() { +class AuthViewModel : ViewModel() { private val _action = Channel( capacity = Channel.BUFFERED, onBufferOverflow = BufferOverflow.DROP_OLDEST, @@ -23,7 +21,7 @@ class AuthViewModel(): ViewModel() { private val _errorState = MutableStateFlow(null) val errorState: StateFlow = _errorState.asStateFlow() - fun login(login: String, password:String){ + fun login(login: String, password: String) { viewModelScope.launch { try { UserServiceST.getInstance().login(login, password).fold( @@ -40,6 +38,7 @@ class AuthViewModel(): ViewModel() { } } } + private fun openProfile() { viewModelScope.launch { _action.send(Action.GotoProfile) diff --git a/app/src/main/java/com/displaynone/acss/ui/init/InitFragment.kt b/app/src/main/java/com/displaynone/acss/ui/init/InitFragment.kt index bb6b8f2..600ad9d 100644 --- a/app/src/main/java/com/displaynone/acss/ui/init/InitFragment.kt +++ b/app/src/main/java/com/displaynone/acss/ui/init/InitFragment.kt @@ -12,7 +12,6 @@ import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.displaynone.acss.R import com.displaynone.acss.components.auth.models.user.UserServiceST -import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO import com.displaynone.acss.databinding.FragmentInitBinding import com.displaynone.acss.util.collectWithLifecycle import com.displaynone.acss.util.navigateTo @@ -29,24 +28,26 @@ class InitFragment : Fragment(R.layout.fragment_init) { _binding = FragmentInitBinding.bind(view) if (!checkInternetConnection()) { + hideSpinner() handleError(R.string.noInternet) return } pingServer() - } private fun pingServer() { viewModel.pingServer() viewModel.state.collectWithLifecycle(this) { state -> - if (state is InitFragmentViewModel.State.Show){ - if(!state.item){ + if (state is InitFragmentViewModel.State.Show) { + if (!state.item) { + hideSpinner() handleError(R.string.serverIsUnabailable) - } else{ + } else { val navController: NavController = findNavController() if (!isUserAuthenticated()) { + hideSpinner() navigateTo(navController, R.id.action_nav_init_to_nav_auth) } else { updateUser(navController) @@ -58,15 +59,14 @@ class InitFragment : Fragment(R.layout.fragment_init) { private fun updateUser(navController: NavController) { viewModel.updateUserInfo() - viewModel.state.collectWithLifecycle(this){ state -> + viewModel.state.collectWithLifecycle(this) { state -> + hideSpinner() + if (state is InitFragmentViewModel.State.Update) { - if (state.item == null) { - navigateTo(navController, R.id.action_nav_init_to_nav_auth) - } else{ - navigateTo(navController, R.id.action_nav_init_to_nav_profile) - } + navigateTo(navController, R.id.action_nav_init_to_nav_profile) } - if (state is InitFragmentViewModel.State.Error){ + + if (state is InitFragmentViewModel.State.Error) { navigateTo(navController, R.id.action_nav_init_to_nav_auth) } } @@ -95,8 +95,22 @@ class InitFragment : Fragment(R.layout.fragment_init) { return false } - private fun getCachedUser(): UserDTO? { - return UserServiceST.getInstance().getUserDTO(); + private fun hideSpinner() { + binding.spinner.visibility = View.GONE + } + + private fun unhideSpinner() { + binding.spinner.visibility = View.VISIBLE + } + + private fun hideError() { + binding.errorImage.visibility = View.GONE + binding.error.visibility = View.GONE + } + + private fun unhideError() { + binding.errorImage.visibility = View.VISIBLE + binding.error.visibility = View.VISIBLE } private fun isUserAuthenticated(): Boolean { @@ -104,11 +118,9 @@ class InitFragment : Fragment(R.layout.fragment_init) { } private fun handleError(string: Int) { + unhideError() binding.error.text = requireContext().getString(string) } - private fun handleError(errorMessage: String) { - binding.error.text = errorMessage - } override fun onDestroyView() { super.onDestroyView() diff --git a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt index bf949a2..be4150c 100644 --- a/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/displaynone/acss/ui/profile/ProfileViewModel.kt @@ -6,11 +6,10 @@ import androidx.lifecycle.viewModelScope import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.cachedIn -import com.displaynone.acss.components.auth.models.user.UserServiceST import com.displaynone.acss.components.acs.models.visit.VisitListPagingSource import com.displaynone.acss.components.acs.models.visit.VisitServiceST +import com.displaynone.acss.components.auth.models.user.UserServiceST import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO -import io.ktor.util.reflect.instanceOf import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow @@ -18,21 +17,24 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch -class ProfileViewModel(): ViewModel() { +class ProfileViewModel() : ViewModel() { private val _action = Channel( capacity = Channel.BUFFERED, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) + private var login: String = "" - fun setLogin(login1: String){ + fun setLogin(login1: String) { login = login1 } + val action = _action.receiveAsFlow() val _state = MutableStateFlow(State.Loading) val state = _state.asStateFlow() val visitListState = Pager( - config = PagingConfig(pageSize = 20, + config = PagingConfig( + pageSize = 20, enablePlaceholders = false, maxSize = 100 ) @@ -45,19 +47,19 @@ class ProfileViewModel(): ViewModel() { config = PagingConfig(pageSize = 20, enablePlaceholders = false, maxSize = 100) ) { VisitListPagingSource { pageNum, pageSize -> - VisitServiceST.getInstance().getLastVisitsByLogin(pageNum,pageSize, login) + VisitServiceST.getInstance().getLastVisitsByLogin(pageNum, pageSize, login) } }.flow.cachedIn(viewModelScope) - fun logout(){ + fun logout() { UserServiceST.getInstance().logout() } - fun getInfo(){ + + fun getInfo() { viewModelScope.launch { UserServiceST.getInstance().getInfo().fold( onSuccess = { data -> _state.emit(State.Show(data)) - UserServiceST.getInstance().saveUserDTO(data) Log.d("Pvm", data.login) }, onFailure = { error -> @@ -67,7 +69,8 @@ class ProfileViewModel(): ViewModel() { ) } } - fun changeRights(login: String, isACSBlocked: Boolean){ + + fun changeRights(login: String, isACSBlocked: Boolean) { viewModelScope.launch { UserServiceST.getInstance().changeRights(login, isACSBlocked).fold( onSuccess = { @@ -80,12 +83,14 @@ class ProfileViewModel(): ViewModel() { ) } } - fun openAuth(){ + + fun openAuth() { viewModelScope.launch { _action.send(Action.GoToAuth) } } - fun openScan(){ + + fun openScan() { viewModelScope.launch { _action.send(Action.GoToScan) } @@ -96,12 +101,14 @@ class ProfileViewModel(): ViewModel() { data class Show( val item: UserDTO ) : State + data class Change( val item: Boolean ) : State } + sealed interface Action { - data object GoToAuth: Action - data object GoToScan: Action + data object GoToAuth : Action + data object GoToScan : Action } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_init.xml b/app/src/main/res/layout/fragment_init.xml index 4edd169..8d02585 100644 --- a/app/src/main/res/layout/fragment_init.xml +++ b/app/src/main/res/layout/fragment_init.xml @@ -1,35 +1,43 @@ + android:layout_height="match_parent"> + + + android:layout_height="match_parent" + android:orientation="vertical" + android:gravity="center_horizontal"> + + android:src="@drawable/dinosaur" + android:textAlignment="center"/> + - + android:textSize="24sp" + tools:ignore="MissingConstraints" + tools:text="@string/noInternet" /> + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 2a2aca1..d610388 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -6,7 +6,7 @@ + android:label="@string/app_name"> diff --git a/app/src/main/res/values-en/strings-en.xml b/app/src/main/res/values-en/strings-en.xml index 72cf469..f979947 100644 --- a/app/src/main/res/values-en/strings-en.xml +++ b/app/src/main/res/values-en/strings-en.xml @@ -1,5 +1,5 @@ - AS + ACSS Enter Login Enter password Welcome! diff --git a/app/src/main/res/values-ru/strings-ru.xml b/app/src/main/res/values-ru/strings-ru.xml index bfb8dc1..e9a5b1c 100644 --- a/app/src/main/res/values-ru/strings-ru.xml +++ b/app/src/main/res/values-ru/strings-ru.xml @@ -1,6 +1,6 @@ - AS + ACSS Введите логин Введите пароль Здравствуйте! diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0a0697..faa86ad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - AS + ACSS Enter Login Enter password Welcome!