Merge remote-tracking branch 'origin/master'
This commit is contained in:
		
						commit
						0ffd6b0ee6
					
				| @ -28,6 +28,7 @@ class MainActivity : AppCompatActivity() { | ||||
| 
 | ||||
|         val toolbar = findViewById<Toolbar>(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) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -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<Unit>{ | ||||
| 
 | ||||
|     suspend fun login(login: String, password: String): Result<Unit> { | ||||
|         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<List<VisitDto>> { | ||||
| //        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<List<VisitDto>> { | ||||
| //        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<Unit> { | ||||
|         return userRepository.changeRightsByLogin(login, tokenManager.authTokenPair!!.accessToken, isACSBlocked) | ||||
|         return userRepository.changeRightsByLogin( | ||||
|             login, | ||||
|             tokenManager.authTokenPair!!.accessToken, | ||||
|             isACSBlocked | ||||
|         ) | ||||
|     } | ||||
|     suspend fun getInfo(): Result<UserDTO>{ | ||||
| 
 | ||||
|     suspend fun getInfo(): Result<UserDTO> { | ||||
|         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<UserDTO>{ | ||||
| 
 | ||||
|     suspend fun getInfoByLogin(login: String): Result<UserDTO> { | ||||
|         if (!tokenManager.hasTokens()) { | ||||
|             throw RuntimeException("access token is null") | ||||
|         } | ||||
|         return userRepository.getInfoByLogin(tokenManager.authTokenPair!!.accessToken, login) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun openDoor(code: String): Result<Int> { | ||||
|         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) | ||||
|     } | ||||
| } | ||||
| @ -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<Boolean> = 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<AuthTokenPair> = 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<LoginResponseDTO> = | ||||
|         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<AuthTokenPair>(result.bodyAsText()) | ||||
|             tokenPair | ||||
|         } | ||||
|     } | ||||
|     suspend fun openDoor(token: String, code: String): Result<Int> = withContext(Dispatchers.IO){ | ||||
|         runCatching{ | ||||
| 
 | ||||
|     suspend fun openDoor(token: String, code: String): Result<Int> = 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<String>()}") | ||||
|             } | ||||
|             Log.d("UserRepository", result.bodyAsText()) | ||||
| 
 | ||||
|             if (result.status != HttpStatusCode.OK) error("Status ${result.status}: ${result.body<String>()}") | ||||
| 
 | ||||
|             result.status.value | ||||
|         } | ||||
|     } | ||||
|     suspend fun getInfo(token: String): Result<UserDTO> = withContext(Dispatchers.IO){ | ||||
| 
 | ||||
|     suspend fun getInfo(token: String): Result<UserDTO> = 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<String>()}") | ||||
|             } | ||||
|             Log.d("UserRepository", result.bodyAsText()) | ||||
|             if (result.status != HttpStatusCode.OK) error("Status ${result.status}: ${result.body<String>()}") | ||||
|             result.body() | ||||
|         } | ||||
|     } | ||||
|     suspend fun getInfoByLogin(token: String, login: String): Result<UserDTO> = 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<UserDTO> = | ||||
|         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<String>()}") | ||||
|                 result.body() | ||||
|             } | ||||
|             if (result.status != HttpStatusCode.OK) { | ||||
|                 error("Status ${result.status}: ${result.body<String>()}") | ||||
|             } | ||||
|             Log.d("UserRepository", result.bodyAsText()) | ||||
|             result.body() | ||||
|         } | ||||
|     } | ||||
|     suspend fun changeRightsByLogin(login: String, token: String, isACSBlocked: Boolean): Result<Unit> = withContext(Dispatchers.IO) { | ||||
| 
 | ||||
|     suspend fun changeRightsByLogin( | ||||
|         login: String, | ||||
|         token: String, | ||||
|         isACSBlocked: Boolean | ||||
|     ): Result<Unit> = 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<String>()}") | ||||
|  | ||||
| @ -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") | ||||
| @ -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, | ||||
| ) | ||||
| @ -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) | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -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<Action>( | ||||
|         capacity = Channel.BUFFERED, | ||||
|         onBufferOverflow = BufferOverflow.DROP_OLDEST, | ||||
| @ -23,7 +21,7 @@ class AuthViewModel(): ViewModel() { | ||||
|     private val _errorState = MutableStateFlow<String?>(null) | ||||
|     val errorState: StateFlow<String?> = _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) | ||||
|  | ||||
| @ -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() | ||||
|  | ||||
| @ -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<Action>( | ||||
|         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>(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 | ||||
|     } | ||||
| } | ||||
| @ -1,35 +1,43 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     xmlns:tools="http://schemas.android.com/tools"> | ||||
|     android:layout_height="match_parent"> | ||||
| 
 | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:orientation="vertical" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent"> | ||||
|         android:layout_height="match_parent" | ||||
|         android:orientation="vertical" | ||||
|         android:gravity="center_horizontal"> | ||||
| 
 | ||||
|         <ImageView | ||||
|             android:visibility="gone" | ||||
|             android:id="@+id/error_image" | ||||
|             android:layout_width="250dp" | ||||
|             android:layout_height="250dp" | ||||
|             android:layout_gravity="center" | ||||
|             android:layout_margin="10dp" | ||||
|             android:layout_height="250dp" | ||||
|             android:src="@drawable/lost_connection"/> | ||||
|             android:src="@drawable/dinosaur" | ||||
|             android:textAlignment="center"/> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:visibility="gone" | ||||
|             android:id="@+id/error" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:gravity="center" | ||||
|             android:textSize="24sp" | ||||
|             android:layout_margin="15dp" | ||||
|             android:letterSpacing="0.05" | ||||
|             android:background="?android:attr/colorBackground" | ||||
|             android:gravity="center" | ||||
|             android:letterSpacing="0.05" | ||||
|             android:textColor="?attr/colorOnBackground" | ||||
|             tools:text="@string/noInternet" | ||||
|             tools:ignore="MissingConstraints" /> | ||||
|         <ImageView | ||||
|             android:layout_width="250dp" | ||||
|             android:layout_gravity="center" | ||||
|             android:layout_margin="10dp" | ||||
|             android:layout_height="250dp" | ||||
|             android:src="@drawable/dinosaur"/> | ||||
|             android:textSize="24sp" | ||||
|             tools:ignore="MissingConstraints" | ||||
|             tools:text="@string/noInternet" /> | ||||
|         <ProgressBar | ||||
|             android:id="@+id/spinner" | ||||
|             style="?android:attr/progressBarStyle" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content"/> | ||||
|     </LinearLayout> | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| @ -6,7 +6,7 @@ | ||||
|     <fragment | ||||
|         android:id="@+id/nav_init" | ||||
|         android:name="com.displaynone.acss.ui.init.InitFragment" | ||||
|         android:label="InitFragment"> | ||||
|         android:label="@string/app_name"> | ||||
|         <action | ||||
|             android:id="@+id/action_nav_init_to_nav_profile" | ||||
|             app:destination="@id/nav_profile" /> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <resources> | ||||
|     <string name="app_name">AS</string> | ||||
|     <string name="app_name">ACSS</string> | ||||
|     <string name="login">Enter Login</string> | ||||
|     <string name="password">Enter password</string> | ||||
|     <string name="hello">Welcome!</string> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|    <string name="app_name">AS</string> | ||||
|    <string name="app_name">ACSS</string> | ||||
|     <string name="login">Введите логин</string> | ||||
|     <string name="password">Введите пароль</string> | ||||
|     <string name="hello">Здравствуйте!</string> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <resources> | ||||
|     <string name="app_name">AS</string> | ||||
|     <string name="app_name">ACSS</string> | ||||
|     <string name="login">Enter Login</string> | ||||
|     <string name="password">Enter password</string> | ||||
|     <string name="hello">Welcome!</string> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user