This commit is contained in:
Universall 2025-02-20 11:41:48 +03:00
parent aecbab7cd3
commit 277db36d79
9 changed files with 89 additions and 97 deletions

View File

@ -7,21 +7,25 @@ import androidx.annotation.Nullable;
import androidx.security.crypto.EncryptedSharedPreferences; import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKeys; 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.displaynone.acss.components.auth.models.user.repository.dto.UserDTO;
import com.google.gson.Gson; import com.google.gson.Gson;
import java.io.IOException; import java.io.IOException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.Optional;
public class UserManager { public class UserManager {
// Preferences
private static final String _PREFERENCES_FILENAME = "userData"; private static final String _PREFERENCES_FILENAME = "userData";
private final SharedPreferences _preferences; 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 UserDTO userDTO;
private static final String ACCESS_KEY = "user";
private Gson gson = new Gson();
public UserManager(Context context) { public UserManager(Context context) {
this._preferences = this._createEncryptedPreferences(context); this._preferences = this._createEncryptedPreferences(context);
@ -40,23 +44,24 @@ public class UserManager {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public void saveDto(UserDTO userDTO) { public void saveDto(UserDTO userDTO) {
this.userDTO = userDTO; this.userDTO = userDTO;
_preferences.edit() _preferences.edit()
.putString(ACCESS_KEY,toJson(userDTO)) .putString(_KEY_USER, toJson(userDTO))
.apply(); .apply();
} }
public @Nullable UserDTO getDto() { public @Nullable UserDTO getDto() {
if (this.userDTO != null) return this.userDTO; if (this.userDTO != null) return this.userDTO;
UserDTO userDTO = fromJson( _preferences.getString(ACCESS_KEY, null)); return fromJson(_preferences.getString(_KEY_USER, 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);
} }
private UserDTO fromJson(String userJSON) {
return gson.fromJson(userJSON, UserDTO.class);
}
private String toJson(UserDTO userDTO) {
return gson.toJson(userDTO);
}
} }

View File

@ -1,5 +1,5 @@
package com.displaynone.acss.config package com.displaynone.acss.config
object Constants { object Constants {
const val serverUrl = "http://192.168.136.38:8086" const val serverUrl = "http://192.168.56.1:8086"
} }

View File

@ -46,7 +46,7 @@ class AdminFragment : Fragment(R.layout.fragment_admin) {
} }
if (state is AdminViewModel.State.Error){ if (state is AdminViewModel.State.Error){
val errorMessage = state.errorMessage val errorMessage = state.errorMessage
binding.loginSearch.setError(errorMessage) binding.loginSearch.error = errorMessage
} }
} }
} }

View File

@ -80,10 +80,6 @@ class InitFragment : Fragment(R.layout.fragment_init) {
return false return false
} }
private fun getCachedUser(): UserDTO? {
return UserServiceST.getInstance().getUserDTO();
}
private fun isUserAuthenticated(): Boolean { private fun isUserAuthenticated(): Boolean {
return UserServiceST.getInstance().hasTokens() return UserServiceST.getInstance().hasTokens()
} }
@ -91,4 +87,9 @@ class InitFragment : Fragment(R.layout.fragment_init) {
private fun handleError(string: Int) { private fun handleError(string: Int) {
binding.error.text = requireContext().getString(string) binding.error.text = requireContext().getString(string)
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
} }

View File

@ -11,8 +11,8 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.displaynone.acss.R 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.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.components.auth.models.user.repository.dto.UserDTO
import com.displaynone.acss.databinding.FragmentProfileBinding import com.displaynone.acss.databinding.FragmentProfileBinding
import com.displaynone.acss.ui.profile.ProfileViewModel.Action 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.collectWithLifecycle
import com.displaynone.acss.util.navigateTo 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 var _binding: FragmentProfileBinding? = null
private val binding: FragmentProfileBinding get() = _binding!! private val binding: FragmentProfileBinding get() = _binding!!
@ -33,29 +33,28 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
checkForAdmin() checkForAdmin()
binding.swipeRefresh.setOnRefreshListener { binding.swipeRefresh.setOnRefreshListener {
if (getIsMe()){ if (getIsMe()) refreshData() else showData(getUserDto()!!);
refreshData()
} else{
showData(getUserDto()!!)
}
} }
binding.logout.setOnClickListener{
binding.logout.setOnClickListener {
logout() logout()
} }
binding.scan.setOnClickListener{
binding.scan.setOnClickListener {
navigateTo(view, R.id.action_profileFragment_to_qrScanFragment) navigateTo(view, R.id.action_profileFragment_to_qrScanFragment)
} }
binding.buttonSearch.setOnClickListener{
binding.buttonSearch.setOnClickListener {
navigateTo(view, R.id.action_profileFragment_to_adminFragment) navigateTo(view, R.id.action_profileFragment_to_adminFragment)
} }
binding.recyclerViewLogs.adapter = adapter binding.recyclerViewLogs.adapter = adapter
if (getIsMe()) { if (getIsMe()) {
refreshData() refreshData()
viewModel.visitListState.collectWithLifecycle(this) { data -> viewModel.visitListState.collectWithLifecycle(this) { data -> adapter.submitData(data) }
adapter.submitData(data)
}
waitForQRScanResult() waitForQRScanResult()
} else{ } else {
showData(getUserDto()!!) showData(getUserDto()!!)
Log.d("ProfileFragment", "set login") Log.d("ProfileFragment", "set login")
viewModel.visitListStateFromLogin.collectWithLifecycle(this) { data -> viewModel.visitListStateFromLogin.collectWithLifecycle(this) { data ->
@ -66,72 +65,66 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
} }
subscribe() subscribe()
binding.recyclerViewLogs.layoutManager = LinearLayoutManager(requireContext()) binding.recyclerViewLogs.layoutManager = LinearLayoutManager(requireContext())
// viewModel.visitListStateFromLogin.collectWithLifecycle(this) { data ->
// adapter.submitData(data)
// }
} }
private fun checkForAdmin() { private fun checkForAdmin() {
Log.d("check", "cheking for roles") val userDTO = UserServiceST.getInstance().getUserDTO() ?: return
val userDTO = UserServiceST.getInstance().getUserDTO() if (userDTO.roles.any { it.name == "ROLE_ADMIN" }) {
if (userDTO != null) { binding.buttonSearch.visibility = View.VISIBLE
if (userDTO.roles.any { it.name == "ROLE_ADMIN" }) { binding.rightsUsingSmartphone.text = "Пропуск действителен"
Log.d("adminlog", "i'm admin") }
binding.buttonSearch.visibility = View.VISIBLE if (userDTO.roles.any { it.name == "ROLE_USER" }) {
binding.rightsUsingSmartphone.text = "Пропуск действителен" binding.rightsUsingSmartphone.text = "Пропуск действителен"
}
if (userDTO.roles.any { it.name == "ROLE_USER" }) {
Log.d("userlog", "i'm user")
binding.rightsUsingSmartphone.text = "Пропуск действителен"
}
} }
} }
private fun hideButtons() { private fun hideButtons() {
binding.logout.visibility = View.GONE binding.logout.visibility = View.GONE
binding.scan.visibility = View.GONE binding.scan.visibility = View.GONE
binding.buttonSearch.visibility = View.GONE binding.buttonSearch.visibility = View.GONE
} }
fun showMyData(userDTO: UserDTO){
private fun showMyData(userDTO: UserDTO) {
binding.fio.text = userDTO.name binding.fio.text = userDTO.name
binding.position.text = userDTO.position binding.position.text = userDTO.position
setAvatar(userDTO.photo) setAvatar(userDTO.photo)
} }
fun showData(userDTO: UserDTO){
private fun showData(userDTO: UserDTO) {
binding.fio.text = userDTO.name binding.fio.text = userDTO.name
binding.position.text = userDTO.position binding.position.text = userDTO.position
viewModel.setLogin(login1 = userDTO.login) viewModel.setLogin(login1 = userDTO.login)
Log.d("ProfileFragment", userDTO.login)
// binding.lastEntry.text = userDTO.lastVisit
setAvatar(userDTO.photo) setAvatar(userDTO.photo)
} }
private fun refreshData() { private fun refreshData() {
Log.d("ProfileFragment", "Refreshed")
viewModel.getInfo() viewModel.getInfo()
subscribeToGetData() subscribeToGetData()
} }
fun subscribe() {
private fun subscribe() {
viewModel.action.collectWithLifecycle(this) { action -> viewModel.action.collectWithLifecycle(this) { action ->
if (action is Action.GoToAuth) { 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) { 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? { private fun getUserDto(): UserDTO? {
return arguments?.getSerializable("user") as? UserDTO return arguments?.getSerializable("user") as? UserDTO
} }
private fun getIsMe(): Boolean { private fun getIsMe(): Boolean {
return arguments?.getBoolean("isMe", true) ?: true return arguments?.getBoolean("isMe", true) ?: true
} }
private fun waitForQRScanResult() { private fun waitForQRScanResult() {
requireActivity().onBackPressedDispatcher.addCallback( requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner, viewLifecycleOwner,
object : OnBackPressedCallback(true) { object : OnBackPressedCallback(true) {
@ -145,20 +138,19 @@ class ProfileFragment: Fragment(R.layout.fragment_profile) {
)?.observe(viewLifecycleOwner) { bundle -> )?.observe(viewLifecycleOwner) { bundle ->
val qrCode = bundle.getString("key_qr") val qrCode = bundle.getString("key_qr")
if (!qrCode.isNullOrEmpty()) view?.let { if (!qrCode.isNullOrEmpty()) view?.let {
val bundle = Bundle().apply { val newBundle = Bundle().apply { putString("qrCode", qrCode) }
putString("qrCode", qrCode) navigateTo(it, R.id.action_profileFragment_to_qrResultFragment, newBundle)
}
navigateTo(it, R.id.action_profileFragment_to_qrResultFragment, bundle)
} }
} }
} }
private fun logout() { private fun logout() {
viewModel.logout() viewModel.logout()
viewModel.openAuth() viewModel.openAuth()
Toast.makeText(activity, "LOGOUT", Toast.LENGTH_SHORT).show() Toast.makeText(activity, "LOGOUT", Toast.LENGTH_SHORT).show()
} }
private fun subscribeToGetData(){ private fun subscribeToGetData() {
viewModel.state.collectWithLifecycle(this) { state -> viewModel.state.collectWithLifecycle(this) { state ->
if (state is ProfileViewModel.State.Show) { if (state is ProfileViewModel.State.Show) {
val userDto: UserDTO = state.item val userDto: UserDTO = state.item

View File

@ -1,13 +1,9 @@
package com.displaynone.acss.ui.result package com.displaynone.acss.ui.result
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.displaynone.acss.R import com.displaynone.acss.R
import com.displaynone.acss.databinding.FragmentQrResultBinding import com.displaynone.acss.databinding.FragmentQrResultBinding
import com.displaynone.acss.util.collectWithLifecycle 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?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Log.d("QrResultFragment", getQrCode())
_binding = FragmentQrResultBinding.bind(view) _binding = FragmentQrResultBinding.bind(view)
binding.close.setOnClickListener(this::closeQrScanFragment) binding.close.setOnClickListener(this::closeQrScanFragment)
this.openDoor() this.openDoor()
viewModel.state.collectWithLifecycle(this){ state -> viewModel.state.collectWithLifecycle(this) { state ->
if (state is QrResultViewModel.State.Result){ if (state is QrResultViewModel.State.Result) {
if (state.resultCode == 200) { when (state.resultCode) {
setResult(getString(R.string.success)) 200 -> {
} else if (state.resultCode == 400) { setResult(getString(R.string.success))
setResult(getString(R.string.wrong)) }
} else if (state.resultCode == 401) {
setResult(getString(R.string.cancel)) 400 -> {
setResult(getString(R.string.wrong))
}
401 -> {
setResult(getString(R.string.cancel))
}
} }
} }
if (state is QrResultViewModel.State.Error){ if (state is QrResultViewModel.State.Error) setResult(state.errorMessage)
setResult(state.errorMessage)
}
} }
} }
private fun openDoor() { private fun openDoor() {
val qrValue = getQrCode() ?: return
val qrCodeValueLong: Long val qrCodeValueLong: Long
try { try {
qrCodeValueLong = getQrCode().toLong() qrCodeValueLong = qrValue.toLong()
} catch (exception: Exception) { } catch (exception: Exception) {
when (exception) { when (exception) {
is NumberFormatException, is IllegalArgumentException -> setResult(getString(R.string.wrong)) is NumberFormatException, is IllegalArgumentException -> setResult(getString(R.string.wrong))
@ -60,8 +59,8 @@ class QrResultFragment : Fragment(R.layout.fragment_qr_result) {
viewModel.openDoor(qrCodeValueLong) viewModel.openDoor(qrCodeValueLong)
} }
private fun getQrCode(): String { private fun getQrCode(): String? {
return arguments?.getString("qrCode") ?: "No QR Code Provided" return arguments?.getString("qrCode")
} }
private fun closeQrScanFragment(view: View) { private fun closeQrScanFragment(view: View) {

View File

@ -61,9 +61,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
viewModel.action.collectWhenStarted(this) { action -> viewModel.action.collectWhenStarted(this) { action ->
when (action) { when (action) {
is QrScanViewModel.Action.RequestPermission -> requestPermission(action.permission) is QrScanViewModel.Action.RequestPermission -> requestPermission(action.permission)
is QrScanViewModel.Action.CloseWithCancel -> { is QrScanViewModel.Action.CloseWithCancel -> goBack()
goBack()
}
is QrScanViewModel.Action.CloseWithResult -> { is QrScanViewModel.Action.CloseWithResult -> {
sendResult(QrScanDestination.packToBundle(action.result)) sendResult(QrScanDestination.packToBundle(action.result))
goBack() goBack()
@ -82,9 +80,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
val previewView: PreviewView = binding.viewFinder val previewView: PreviewView = binding.viewFinder
val executor = ContextCompat.getMainExecutor(context) val executor = ContextCompat.getMainExecutor(context)
val options = BarcodeScannerOptions.Builder() val options = BarcodeScannerOptions.Builder().setBarcodeFormats(Barcode.FORMAT_QR_CODE).build()
.setBarcodeFormats(Barcode.FORMAT_QR_CODE)
.build()
val barcodeScanner = BarcodeScanning.getClient(options) val barcodeScanner = BarcodeScanning.getClient(options)
this.barcodeScanner = barcodeScanner this.barcodeScanner = barcodeScanner

View File

@ -1,7 +1,5 @@
package com.displaynone.acss.ui.scan package com.displaynone.acss.ui.scan
import androidx.lifecycle.ViewModel
import android.Manifest import android.Manifest
import android.app.Application import android.app.Application
import android.content.pm.PackageManager import android.content.pm.PackageManager
@ -80,6 +78,7 @@ class QrScanViewModel(
data class RequestPermission( data class RequestPermission(
val permission: String val permission: String
) : Action ) : Action
data object CloseWithCancel : Action data object CloseWithCancel : Action
data class CloseWithResult( data class CloseWithResult(
val result: String val result: String

View File

@ -17,7 +17,7 @@
<fragment <fragment
android:id="@+id/nav_profile" android:id="@+id/nav_profile"
android:name="com.displaynone.acss.ui.profile.ProfileFragment" android:name="com.displaynone.acss.ui.profile.ProfileFragment"
android:label="@string/profile" android:label="@string/title_profile"
tools:layout="@layout/fragment_profile"> tools:layout="@layout/fragment_profile">
<action <action
android:id="@+id/action_profileFragment_to_authFragment" android:id="@+id/action_profileFragment_to_authFragment"