diff --git a/app/src/main/java/com/displaynone/acss/components/auth/internal_utils/UserManager.java b/app/src/main/java/com/displaynone/acss/components/auth/internal_utils/UserManager.java
index 2c9397c..24cdfa1 100644
--- a/app/src/main/java/com/displaynone/acss/components/auth/internal_utils/UserManager.java
+++ b/app/src/main/java/com/displaynone/acss/components/auth/internal_utils/UserManager.java
@@ -7,21 +7,25 @@ import androidx.annotation.Nullable;
import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKeys;
-import com.displaynone.acss.components.auth.models.AuthTokenPair;
import com.displaynone.acss.components.auth.models.user.repository.dto.UserDTO;
import com.google.gson.Gson;
import java.io.IOException;
import java.security.GeneralSecurityException;
-import java.util.Collections;
-import java.util.Optional;
public class UserManager {
+ // Preferences
private static final String _PREFERENCES_FILENAME = "userData";
private final SharedPreferences _preferences;
+
+ // Utils
+ private static final Gson gson = new Gson();
+
+ // Keys
+ private static final String _KEY_USER = "user";
+
+ // Cache
private UserDTO userDTO;
- private static final String ACCESS_KEY = "user";
- private Gson gson = new Gson();
public UserManager(Context context) {
this._preferences = this._createEncryptedPreferences(context);
@@ -40,23 +44,24 @@ public class UserManager {
throw new RuntimeException(e);
}
}
+
public void saveDto(UserDTO userDTO) {
this.userDTO = userDTO;
_preferences.edit()
- .putString(ACCESS_KEY,toJson(userDTO))
+ .putString(_KEY_USER, toJson(userDTO))
.apply();
}
+
public @Nullable UserDTO getDto() {
if (this.userDTO != null) return this.userDTO;
- UserDTO userDTO = fromJson( _preferences.getString(ACCESS_KEY, null));
- return userDTO;
- }
- private UserDTO fromJson(String userJSON){
- UserDTO userDTO = gson.fromJson(userJSON, UserDTO.class);
- return userDTO;
- }
- private String toJson(UserDTO userDTO){
- return gson.toJson(userDTO);
+ return fromJson(_preferences.getString(_KEY_USER, null));
}
+ private UserDTO fromJson(String userJSON) {
+ return gson.fromJson(userJSON, UserDTO.class);
+ }
+
+ private String toJson(UserDTO userDTO) {
+ return gson.toJson(userDTO);
+ }
}
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 5fb94b1..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.136.38:8086"
+ 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
index 8b4db77..b910c1e 100644
--- a/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt
+++ b/app/src/main/java/com/displaynone/acss/ui/admin/AdminFragment.kt
@@ -46,7 +46,7 @@ class AdminFragment : Fragment(R.layout.fragment_admin) {
}
if (state is AdminViewModel.State.Error){
val errorMessage = state.errorMessage
- binding.loginSearch.setError(errorMessage)
+ binding.loginSearch.error = errorMessage
}
}
}
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 8c0dbe2..bf2aef0 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
@@ -56,18 +56,17 @@ class AuthFragment: Fragment(R.layout.fragment_auth) {
@SuppressLint("ResourceAsColor")
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
binding.error.visibility = View.GONE
- val username = s.toString()
- val valid = isUsernameValid(username)
-
- if (valid) {
- binding.hint.visibility = View.INVISIBLE
- }else{
- binding.login.error = getString(R.string.login_hint)
- }
+// val username = s.toString()
+// val valid = isUsernameValid(username)
+//
+// if (valid) {
+// binding.hint.visibility = View.INVISIBLE
+// }else{
+// binding.login.error = getString(R.string.login_hint)
+// }
// binding.hint.visibility = if(valid) View.INVISIBLE else View.VISIBLE
- binding.next.isEnabled = valid
- val color = if (valid) R.color.primary else R.color.secondary
- binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color)
+// binding.next.isEnabled = valid
+
}
override fun afterTextChanged(s: Editable?) {}
@@ -94,37 +93,95 @@ class AuthFragment: Fragment(R.layout.fragment_auth) {
// })
}
private fun getPasswordValidError(password: String): String {
- if (password.length < 8){ return "LenError" }
- val letterRegex = Regex("^(?=.*[A-Z]).+$")
- if(!letterRegex.matches(password)){ return "UpperCaseError"}
- val digitRegex = Regex("^(?=.*\\\\d).+$")
- if(!digitRegex.matches(password)){ return "DigitCaseError"}
-
+ if (password.length < 8) {
+ return "LenError"
+ }
return "NoErrors"
}
- private fun isUsernameValid(username: String): Boolean {
+ private fun validatePasswordAndSetError(password: String) {
+ val errorType = getPasswordValidError(password)
+
+ when (errorType) {
+ "LenError" -> {
+ binding.password.error = getString(R.string.error_password_too_short)
+ }
+
+ "NoErrors" -> {
+ binding.password.error = null
+ }
+ }
+ }
+ private fun getLoginValidError(username: String): String {
val alf = "^[a-zA-Z0-9_]+$".toRegex()
- return username.isNotEmpty() &&
- username.length >= 3 &&
- !username[0].isDigit() &&
- alf.matches(username)
- }
- private fun isPasswordValid(password: String): Boolean {
- return password.isNotEmpty() &&
- password.length >= 8
+ if (username.isEmpty()) {
+ return "EmptyError"
+ }
+ if (username.length < 3) {
+ return "LenError"
+ }
+ if (username[0].isDigit()) {
+ return "StartsWithDigitError"
+ }
+ if (!alf.matches(username)) {
+ return "InvalidCharactersError"
+ }
+ return "NoErrors"
}
+// private fun isPasswordValid(password: String): Boolean {
+// return password.isNotEmpty() &&
+// password.length >= 8
+// }
// private fun subscribe() {
// viewModel.state.collectWhenStarted(this) { state ->
// binding.login.setOnClickListener(this::onLoginButtonClicked)
// }
// }
+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
+ }
+ }
+}
private fun onLoginButtonClicked(view: View) {
val login = binding.login.text.toString()
val password = binding.password.text.toString()
- if (login.isEmpty()) return
+ if (getPasswordValidError(password) != "NoErrors") {
+
+
+ val color = R.color.secondary
+ binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color)
+ validatePasswordAndSetError(password)
+ }else{
+ val color = R.color.primary
+ 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)
+ validateLoginAndSetError(login)
+ }else{
+ val color = R.color.primary
+ binding.next.backgroundTintList = ContextCompat.getColorStateList(requireContext(), color)
+
+ }
viewModel.login(login, password)
}
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 6f7bc43..bb6b8f2 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
@@ -109,4 +109,9 @@ class InitFragment : Fragment(R.layout.fragment_init) {
private fun handleError(errorMessage: String) {
binding.error.text = errorMessage
}
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
}
\ No newline at end of file
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 09e5295..76c2018 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
@@ -11,8 +11,8 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.displaynone.acss.R
-import com.displaynone.acss.components.auth.models.user.UserServiceST
import com.displaynone.acss.components.acs.models.visit.VisitAdapter
+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.FragmentProfileBinding
import com.displaynone.acss.ui.profile.ProfileViewModel.Action
@@ -20,7 +20,7 @@ import com.displaynone.acss.ui.scan.QrScanDestination
import com.displaynone.acss.util.collectWithLifecycle
import com.displaynone.acss.util.navigateTo
-class ProfileFragment: Fragment(R.layout.fragment_profile) {
+class ProfileFragment : Fragment(R.layout.fragment_profile) {
private var _binding: FragmentProfileBinding? = null
private val binding: FragmentProfileBinding get() = _binding!!
@@ -33,29 +33,28 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
checkForAdmin()
binding.swipeRefresh.setOnRefreshListener {
- if (getIsMe()){
- refreshData()
- } else{
- showData(getUserDto()!!)
- }
+ if (getIsMe()) refreshData() else showData(getUserDto()!!);
}
- binding.logout.setOnClickListener{
+
+ binding.logout.setOnClickListener {
logout()
}
- binding.scan.setOnClickListener{
+
+ binding.scan.setOnClickListener {
navigateTo(view, R.id.action_profileFragment_to_qrScanFragment)
}
- binding.buttonSearch.setOnClickListener{
+
+ binding.buttonSearch.setOnClickListener {
navigateTo(view, R.id.action_profileFragment_to_adminFragment)
}
+
binding.recyclerViewLogs.adapter = adapter
+
if (getIsMe()) {
refreshData()
- viewModel.visitListState.collectWithLifecycle(this) { data ->
- adapter.submitData(data)
- }
+ viewModel.visitListState.collectWithLifecycle(this) { data -> adapter.submitData(data) }
waitForQRScanResult()
- } else{
+ } else {
showData(getUserDto()!!)
Log.d("ProfileFragment", "set login")
@@ -67,40 +66,34 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
}
subscribe()
binding.recyclerViewLogs.layoutManager = LinearLayoutManager(requireContext())
-// viewModel.visitListStateFromLogin.collectWithLifecycle(this) { data ->
-// adapter.submitData(data)
-// }
-
}
+
private fun checkForAdmin() {
- Log.d("check", "cheking for roles")
+ val userDTO = UserServiceST.getInstance().getUserDTO() ?: return
- val userDTO = UserServiceST.getInstance().getUserDTO()
- if (userDTO != null) {
- if (userDTO.roles.any { it.name == "ROLE_ADMIN" }) {
- Log.d("adminlog", "i'm admin")
- binding.buttonSearch.visibility = View.VISIBLE
- binding.rightsUsingSmartphone.text = "Пропуск действителен"
- }
- if (userDTO.roles.any { it.name == "ROLE_USER" }) {
- Log.d("userlog", "i'm user")
-
- binding.rightsUsingSmartphone.text = "Пропуск действителен"
- }
+ if (userDTO.roles.any { it.name == "ROLE_ADMIN" }) {
+ binding.buttonSearch.visibility = View.VISIBLE
+ binding.rightsUsingSmartphone.text = "Пропуск действителен"
+ }
+ if (userDTO.roles.any { it.name == "ROLE_USER" }) {
+ binding.rightsUsingSmartphone.text = "Пропуск действителен"
}
}
+
private fun hideButtons() {
binding.logout.visibility = View.GONE
binding.scan.visibility = View.GONE
binding.buttonSearch.visibility = View.GONE
binding.changeRights.visibility = View.VISIBLE
}
- fun showMyData(userDTO: UserDTO){
+
+ private fun showMyData(userDTO: UserDTO) {
binding.fio.text = userDTO.name
binding.position.text = userDTO.position
setAvatar(userDTO.photo)
}
- fun showData(userDTO: UserDTO){
+
+ private fun showData(userDTO: UserDTO) {
binding.fio.text = userDTO.name
binding.position.text = userDTO.position
binding.changeRights.text = if(userDTO.isACSBlocked) "Разблокировать пользователя" else "Заблокировать пользователя"
@@ -114,30 +107,34 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
setAvatar(userDTO.photo)
}
+
private fun refreshData() {
- Log.d("ProfileFragment", "Refreshed")
viewModel.getInfo()
subscribeToGetData()
}
- fun subscribe() {
+
+ private fun subscribe() {
viewModel.action.collectWithLifecycle(this) { action ->
if (action is Action.GoToAuth) {
- view?.let { navigateTo(it, R.id.action_profileFragment_to_authFragment) } ?: throw IllegalStateException("View is null")
+ 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_qrResultFragment) }?: throw IllegalStateException("View is null")
+ view?.let { navigateTo(it, R.id.action_profileFragment_to_qrResultFragment) }
+ ?: throw IllegalStateException("View is null")
}
}
}
+
private fun getUserDto(): UserDTO? {
return arguments?.getSerializable("user") as? UserDTO
}
+
private fun getIsMe(): Boolean {
return arguments?.getBoolean("isMe", true) ?: true
}
private fun waitForQRScanResult() {
-
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
object : OnBackPressedCallback(true) {
@@ -151,20 +148,19 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
)?.observe(viewLifecycleOwner) { bundle ->
val qrCode = bundle.getString("key_qr")
if (!qrCode.isNullOrEmpty()) view?.let {
- val bundle = Bundle().apply {
- putString("qrCode", qrCode)
- }
- navigateTo(it, R.id.action_profileFragment_to_qrResultFragment, bundle)
+ val newBundle = Bundle().apply { putString("qrCode", qrCode) }
+ navigateTo(it, R.id.action_profileFragment_to_qrResultFragment, newBundle)
}
}
}
+
private fun logout() {
viewModel.logout()
viewModel.openAuth()
Toast.makeText(activity, "LOGOUT", Toast.LENGTH_SHORT).show()
}
- private fun subscribeToGetData(){
+ private fun subscribeToGetData() {
viewModel.state.collectWithLifecycle(this) { state ->
if (state is ProfileViewModel.State.Show) {
val userDto: UserDTO = state.item
diff --git a/app/src/main/java/com/displaynone/acss/ui/result/QrResultFragment.kt b/app/src/main/java/com/displaynone/acss/ui/result/QrResultFragment.kt
index 4f47f45..34de52b 100644
--- a/app/src/main/java/com/displaynone/acss/ui/result/QrResultFragment.kt
+++ b/app/src/main/java/com/displaynone/acss/ui/result/QrResultFragment.kt
@@ -1,13 +1,9 @@
package com.displaynone.acss.ui.result
-import android.content.Context
-import android.content.SharedPreferences
import android.os.Bundle
-import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
-import androidx.navigation.fragment.findNavController
import com.displaynone.acss.R
import com.displaynone.acss.databinding.FragmentQrResultBinding
import com.displaynone.acss.util.collectWithLifecycle
@@ -21,34 +17,37 @@ class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- Log.d("QrResultFragment", getQrCode())
_binding = FragmentQrResultBinding.bind(view)
binding.close.setOnClickListener(this::closeQrScanFragment)
this.openDoor()
- viewModel.state.collectWithLifecycle(this){ state ->
- if (state is QrResultViewModel.State.Result){
- if (state.resultCode == 200) {
- setResult(getString(R.string.success))
- } else if (state.resultCode == 400) {
- setResult(getString(R.string.wrong))
- } else if (state.resultCode == 401) {
- setResult(getString(R.string.cancel))
+ viewModel.state.collectWithLifecycle(this) { state ->
+ if (state is QrResultViewModel.State.Result) {
+ when (state.resultCode) {
+ 200 -> {
+ setResult(getString(R.string.success))
+ }
+
+ 400 -> {
+ setResult(getString(R.string.wrong))
+ }
+
+ 401 -> {
+ setResult(getString(R.string.cancel))
+ }
}
}
- if (state is QrResultViewModel.State.Error){
- setResult(state.errorMessage)
- }
+ if (state is QrResultViewModel.State.Error) setResult(state.errorMessage)
}
}
private fun openDoor() {
+ val qrValue = getQrCode() ?: return
val qrCodeValueLong: Long
-
try {
- qrCodeValueLong = getQrCode().toLong()
+ qrCodeValueLong = qrValue.toLong()
} catch (exception: Exception) {
when (exception) {
is NumberFormatException, is IllegalArgumentException -> setResult(getString(R.string.wrong))
@@ -60,8 +59,8 @@ class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
viewModel.openDoor(qrCodeValueLong)
}
- private fun getQrCode(): String {
- return arguments?.getString("qrCode") ?: "No QR Code Provided"
+ private fun getQrCode(): String? {
+ return arguments?.getString("qrCode")
}
private fun closeQrScanFragment(view: View) {
diff --git a/app/src/main/java/com/displaynone/acss/ui/scan/QrScanFragment.kt b/app/src/main/java/com/displaynone/acss/ui/scan/QrScanFragment.kt
index b1f3c2a..ca6d1d0 100644
--- a/app/src/main/java/com/displaynone/acss/ui/scan/QrScanFragment.kt
+++ b/app/src/main/java/com/displaynone/acss/ui/scan/QrScanFragment.kt
@@ -61,9 +61,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
viewModel.action.collectWhenStarted(this) { action ->
when (action) {
is QrScanViewModel.Action.RequestPermission -> requestPermission(action.permission)
- is QrScanViewModel.Action.CloseWithCancel -> {
- goBack()
- }
+ is QrScanViewModel.Action.CloseWithCancel -> goBack()
is QrScanViewModel.Action.CloseWithResult -> {
sendResult(QrScanDestination.packToBundle(action.result))
goBack()
@@ -82,9 +80,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
val previewView: PreviewView = binding.viewFinder
val executor = ContextCompat.getMainExecutor(context)
- val options = BarcodeScannerOptions.Builder()
- .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
- .build()
+ val options = BarcodeScannerOptions.Builder().setBarcodeFormats(Barcode.FORMAT_QR_CODE).build()
val barcodeScanner = BarcodeScanning.getClient(options)
this.barcodeScanner = barcodeScanner
diff --git a/app/src/main/java/com/displaynone/acss/ui/scan/QrScanViewModel.kt b/app/src/main/java/com/displaynone/acss/ui/scan/QrScanViewModel.kt
index 6961085..18537f9 100644
--- a/app/src/main/java/com/displaynone/acss/ui/scan/QrScanViewModel.kt
+++ b/app/src/main/java/com/displaynone/acss/ui/scan/QrScanViewModel.kt
@@ -1,7 +1,5 @@
package com.displaynone.acss.ui.scan
-import androidx.lifecycle.ViewModel
-
import android.Manifest
import android.app.Application
import android.content.pm.PackageManager
@@ -80,6 +78,7 @@ class QrScanViewModel(
data class RequestPermission(
val permission: String
) : Action
+
data object CloseWithCancel : Action
data class CloseWithResult(
val result: String
diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml
index 7be0e0a..ab89cea 100644
--- a/app/src/main/res/layout/fragment_profile.xml
+++ b/app/src/main/res/layout/fragment_profile.xml
@@ -36,19 +36,29 @@
android:orientation="vertical"
android:gravity="center_horizontal"
android:paddingTop="50dp">
+
+
+
Profile
Server is unavailable
Checking the session employee
+ The password must contain at least 8 characters
+ The password must contain at least one uppercase letter
+ The password must contain at least one digit
+ The username cannot be empty
+ Login must contain at least 3 characters
+ Login cannot start with a digit
+ Login can contain only letters, numbers, and underscores
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7e51d96..e7ff264 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -25,7 +25,12 @@
QR code scanning
Scan result
Profile
-
+ The password must contain at least 8 characters
+ The password must contain at least one uppercase letter
+ The password must contain at least one digit
Checking the session employee
-
+ The username cannot be empty
+ Login must contain at least 3 characters
+ Login cannot start with a digit
+ Login can contain only letters, numbers, and underscores
\ No newline at end of file