Merge remote-tracking branch 'origin/main'

This commit is contained in:
veronicagtea 2025-02-20 16:08:53 +03:00
commit efd651bd6d
30 changed files with 422 additions and 1186 deletions

View File

@ -48,7 +48,13 @@ dependencies {
implementation(Dependencies.Retrofit.gsonConverter) implementation(Dependencies.Retrofit.gsonConverter)
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0") implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
implementation("com.squareup.picasso:picasso:2.8") // Убираем Picasso
// implementation("com.squareup.picasso:picasso:2.8")
// Добавляем Glide
implementation("com.github.bumptech.glide:glide:4.14.2")
kapt("com.github.bumptech.glide:compiler:4.14.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
implementation("androidx.datastore:datastore-preferences:1.1.2") implementation("androidx.datastore:datastore-preferences:1.1.2")
implementation("com.google.mlkit:barcode-scanning:17.3.0") implementation("com.google.mlkit:barcode-scanning:17.3.0")

View File

@ -6,6 +6,7 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import ru.myitschool.work.api.admin.ApiServiceAdmin
import ru.myitschool.work.api.list.ApiServiceList import ru.myitschool.work.api.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain import ru.myitschool.work.api.main.ApiServiceMain
@ -45,4 +46,10 @@ object NetworkModule {
fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList { fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList {
return retrofitClient.getApiServiceList() return retrofitClient.getApiServiceList()
} }
@Provides
@Singleton
fun provideApiServiceAdmin(retrofitClient: RetrofitClient): ApiServiceAdmin {
return retrofitClient.getApiServiceAdmin()
}
} }

View File

@ -1,11 +1,11 @@
package ru.myitschool.work.api package ru.myitschool.work.api
import android.content.Context import android.content.Context
import com.google.android.datatransport.BuildConfig
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import ru.myitschool.work.api.admin.ApiServiceAdmin
import ru.myitschool.work.api.list.ApiServiceList import ru.myitschool.work.api.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain import ru.myitschool.work.api.main.ApiServiceMain
@ -57,4 +57,9 @@ class RetrofitClient(context: Context) {
fun getApiServiceList(): ApiServiceList { fun getApiServiceList(): ApiServiceList {
return retrofitWithAuth.create(ApiServiceList::class.java) return retrofitWithAuth.create(ApiServiceList::class.java)
} }
fun getApiServiceAdmin(): ApiServiceAdmin {
return retrofitWithAuth.create(ApiServiceAdmin::class.java)
}
} }

View File

@ -0,0 +1,7 @@
package ru.myitschool.work.api.admin
import com.google.gson.annotations.SerializedName
class AdminJson(
@SerializedName("authority") var authority: String? = null,
)

View File

@ -0,0 +1,14 @@
package ru.myitschool.work.api.admin
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.PATCH
import retrofit2.http.Path
interface ApiServiceAdmin {
@PATCH("api/admin/authority/change/{login}")
suspend fun block(
@Path("login") login: String,
@Body data: AdminJson
): Response<Void>
}

View File

@ -5,6 +5,6 @@ import retrofit2.http.GET
import retrofit2.http.Path import retrofit2.http.Path
interface ApiServiceList { interface ApiServiceList {
@GET("api/list/{login}") @GET("api/user/list/{login}")
suspend fun getList(@Path("login") login: String): Response<List<ListInfo>> suspend fun getList(@Path("login") login: String): Response<List<ListInfo>>
} }

View File

@ -1,13 +1,9 @@
package ru.myitschool.work.api.login package ru.myitschool.work.api.login
import retrofit2.Call import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
import ru.myitschool.work.api.main.UserInfo
interface ApiServiceLogin { interface ApiServiceLogin {
@GET("api/login") @GET("api/user/login")
fun authenticate(): Call<Void> fun authenticate(): Call<Void>
} }

View File

@ -5,6 +5,6 @@ import retrofit2.http.GET
import retrofit2.http.Path import retrofit2.http.Path
interface ApiServiceMain { interface ApiServiceMain {
@GET("api/info/{login}") @GET("api/user/info/{login}")
fun getDataUser(@Path("login") login: String): Call<UserInfo> fun getDataUser(@Path("login") login: String): Call<UserInfo>
} }

View File

@ -9,15 +9,16 @@ data class UserInfo(
@SerializedName("photo") val photoUrl: String, @SerializedName("photo") val photoUrl: String,
@SerializedName("position") val position: String, @SerializedName("position") val position: String,
@SerializedName("lastVisit") val lastVisit: String, @SerializedName("lastVisit") val lastVisit: String,
) { @SerializedName("authority") val authority: List<AuthorityData>
companion object { )
val Initial = UserInfo(
id = 0, data class AuthorityData(
login = "", @SerializedName("id") val id: Int,
name = "", @SerializedName("authority") val authority: String,
photoUrl = "", )
position = "",
lastVisit = "", object Authorities {
) const val ROLE_ADMIN = "ROLE_ADMIN"
} const val ROLE_USER = "ROLE_USER"
const val ROLE_BLOCK = "ROLE_BLOCK"
} }

View File

@ -6,6 +6,6 @@ import retrofit2.http.POST
import retrofit2.http.Path import retrofit2.http.Path
interface ApiServiceScan { interface ApiServiceScan {
@POST("api/add/{login}") @POST("api/user/add/{login}")
fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void> fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void>
} }

View File

@ -9,6 +9,8 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.fragment import androidx.navigation.fragment.fragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.ui.admin.AdminDestination
import ru.myitschool.work.ui.admin.AdminFragment
import ru.myitschool.work.ui.login.LoginDestination import ru.myitschool.work.ui.login.LoginDestination
import ru.myitschool.work.ui.login.LoginFragment import ru.myitschool.work.ui.login.LoginFragment
import ru.myitschool.work.ui.main.MainDestination import ru.myitschool.work.ui.main.MainDestination
@ -36,6 +38,7 @@ class RootActivity : AppCompatActivity() {
fragment<QrScanFragment, QrScanDestination>() fragment<QrScanFragment, QrScanDestination>()
fragment<MainFragment, MainDestination>() fragment<MainFragment, MainDestination>()
fragment<ResultFragment, ResultDestination>() fragment<ResultFragment, ResultDestination>()
fragment<AdminFragment, AdminDestination>()
} }
} }

View File

@ -0,0 +1,6 @@
package ru.myitschool.work.ui.admin
import kotlinx.serialization.Serializable
@Serializable
data object AdminDestination

View File

@ -0,0 +1,101 @@
package ru.myitschool.work.ui.admin
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentAdminBinding
import ru.myitschool.work.ui.main.MainDestination
import ru.myitschool.work.utils.AuthPreferences
import ru.myitschool.work.utils.QrPreferences
import ru.myitschool.work.utils.collectWhenStarted
import ru.myitschool.work.utils.visibleOrGone
@AndroidEntryPoint
class AdminFragment : Fragment(R.layout.fragment_admin) {
private var _binding: FragmentAdminBinding? = null
private val binding: FragmentAdminBinding get() = _binding!!
private val viewModel: AdminViewModel by viewModels()
private lateinit var authPreferences: AuthPreferences
private lateinit var qrPreferences: QrPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
authPreferences = AuthPreferences(requireContext())
qrPreferences = QrPreferences(requireContext())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentAdminBinding.bind(view)
setupOpenComponents()
observeOpenState()
}
private fun setupOpenComponents() {
binding.apply {
block.setOnClickListener {
authPreferences.getLogin().toString().let {
viewModel.block(
it,
true
)
}
}
}
}
private fun observeOpenState() {
viewModel.state.collectWhenStarted(this) { state ->
when (state) {
is AdminViewModel.ResultState.Loading -> {
}
is AdminViewModel.ResultState.Success -> {
}
is AdminViewModel.ResultState.InvalidCredentials -> {
}
is AdminViewModel.ResultState.Error -> {
}
AdminViewModel.ResultState.Initial -> {
}
}
}
}
private fun visibleAll(isVisible: Boolean) {
binding.apply {
}
}
private fun navigateToMainScreen() {
try {
findNavController().apply {
popBackStack(MainDestination, false)
navigate(MainDestination)
}
} catch (e: Exception) {
Log.e("ResultFragment", "Navigation error", e)
Toast.makeText(context, getText(R.string.errorGoText).toString(), Toast.LENGTH_SHORT).show()
}
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}

View File

@ -0,0 +1,135 @@
package ru.myitschool.work.ui.admin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import ru.myitschool.work.api.admin.AdminJson
import ru.myitschool.work.api.admin.ApiServiceAdmin
import ru.myitschool.work.api.list.ListInfo
import ru.myitschool.work.api.main.ApiServiceMain
import ru.myitschool.work.api.main.Authorities
import ru.myitschool.work.api.main.UserInfo
import ru.myitschool.work.ui.list.ListRepository
import javax.inject.Inject
@HiltViewModel
class AdminViewModel @Inject constructor(
private val apiService: ApiServiceAdmin,
private val apiServiceData: ApiServiceMain,
private val listRepository: ListRepository
) : ViewModel() {
private val _state = MutableStateFlow<ResultState>(ResultState.Initial)
val state = _state.asStateFlow()
private val _stateData = MutableStateFlow<ResultStateData>(ResultStateData.Initial)
val stateData = _stateData.asStateFlow()
fun block(login: String, authority: Boolean) {
viewModelScope.launch {
_state.value = ResultState.Loading
try {
val response = apiService.block(
login = login,
data = AdminJson(
if (authority) Authorities.ROLE_BLOCK
else Authorities.ROLE_USER
)
)
when (response.code()) {
200 -> {
_state.value = ResultState.Success
}
403 -> {
_state.value = ResultState.InvalidCredentials
}
401 -> {
_state.value = ResultState.Error
}
else -> {
_state.value = ResultState.Error
}
}
} catch (t: Throwable) {
_state.value = ResultState.Error
}
}
}
fun getUserData(login: String) {
viewModelScope.launch {
_stateData.value = ResultStateData.Loading
apiServiceData.getDataUser(login).enqueue(object : Callback<UserInfo> {
override fun onResponse(call: Call<UserInfo>, response: Response<UserInfo>) {
when {
response.isSuccessful -> {
val userInfo = response.body()
_stateData.value = userInfo?.let { ResultStateData.Success(it) }!!
}
response.code() == 401 -> {
_stateData.value = ResultStateData.Error("Unauthorized")
}
response.code() == 403 -> {
_stateData.value = ResultStateData.Error("Block")
}
else -> {
_stateData.value = ResultStateData.Error("Error")
}
}
}
override fun onFailure(call: Call<UserInfo>, t: Throwable) {
_stateData.value = ResultStateData.Error("Network Error")
}
})
}
}
private val _listState = MutableStateFlow<ListState>(ListState.Loading)
val listState: StateFlow<ListState> = _listState
sealed class ListState {
data object Loading : ListState()
data class Success(val data: List<ListInfo>) : ListState()
data class Error(val message: String) : ListState()
}
fun loadList(login: String) {
viewModelScope.launch {
_listState.value = ListState.Loading
try {
val list = listRepository.getList(login)
_listState.value = ListState.Success(list)
} catch (e: Exception) {
_listState.value = ListState.Error(e.message ?: "Unknown error")
}
}
}
sealed class ResultState {
data object Initial : ResultState()
data object InvalidCredentials : ResultState()
data object Loading : ResultState()
data object Success : ResultState()
data object Error : ResultState()
}
sealed class ResultStateData {
data object Initial : ResultStateData()
data object Loading : ResultStateData()
data class Success(val userInfo: UserInfo) : ResultStateData()
data class Error(val message: String) : ResultStateData()
}
}

View File

@ -9,7 +9,7 @@ class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val binding = ItemRecyclerViewEntrancedataBinding.bind(itemView) private val binding = ItemRecyclerViewEntrancedataBinding.bind(itemView)
fun bind(item: ListInfo) { fun bind(item: ListInfo) {
binding.text1.text = item.time binding.text1.text = item.time.replace("T", " ")
binding.text2.text = item.value binding.text2.text = item.value
binding.text3.text = item.type binding.text3.text = item.type
} }

View File

@ -103,8 +103,6 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
text = "Ошибка авторизации" text = "Ошибка авторизации"
} }
authPreferences.clearLoginState()
Log.d("Authentication", "Ошибка авторизации") Log.d("Authentication", "Ошибка авторизации")
} }

View File

@ -36,7 +36,7 @@ class LoginViewModel @Inject constructor(
_state.value = LoginState.InvalidCredentials _state.value = LoginState.InvalidCredentials
} }
401 -> { 401 -> {
_state.value = LoginState.Error _state.value = LoginState.InvalidCredentials
} }
else -> { else -> {
_state.value = LoginState.Error _state.value = LoginState.Error

View File

@ -8,10 +8,11 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.api.main.Authorities
import ru.myitschool.work.databinding.FragmentMainBinding import ru.myitschool.work.databinding.FragmentMainBinding
import ru.myitschool.work.ui.admin.AdminDestination
import ru.myitschool.work.ui.list.ListAdapter import ru.myitschool.work.ui.list.ListAdapter
import ru.myitschool.work.ui.login.LoginDestination import ru.myitschool.work.ui.login.LoginDestination
import ru.myitschool.work.ui.scan.qr.QrScanDestination import ru.myitschool.work.ui.scan.qr.QrScanDestination
@ -100,6 +101,16 @@ class MainFragment : Fragment(R.layout.fragment_main) {
username.text = state.userInfo.name username.text = state.userInfo.name
position.text = state.userInfo.position position.text = state.userInfo.position
if (state.userInfo.authority[0].authority == Authorities.ROLE_ADMIN) {
admin.visibleOrGone(true)
} else if (state.userInfo.authority[0].authority == Authorities.ROLE_USER) {
admin.visibleOrGone(false)
} else {
admin.visibleOrGone(false)
Log.e("MainFragment", "Unknown role")
}
loadImageFromUrl(state.userInfo.photoUrl) loadImageFromUrl(state.userInfo.photoUrl)
val inputFormat = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()) val inputFormat = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault())
@ -107,7 +118,8 @@ class MainFragment : Fragment(R.layout.fragment_main) {
try { try {
val parsedDate = inputFormat.parse(state.userInfo.lastVisit) val parsedDate = inputFormat.parse(state.userInfo.lastVisit)
lastEntry.text = parsedDate?.let { outputFormat.format(it) } ?: state.userInfo.lastVisit lastEntry.text = parsedDate?.let { outputFormat.format(it) }
?: state.userInfo.lastVisit
} catch (e: Exception) { } catch (e: Exception) {
lastEntry.text = state.userInfo.lastVisit lastEntry.text = state.userInfo.lastVisit
} }
@ -125,13 +137,13 @@ class MainFragment : Fragment(R.layout.fragment_main) {
viewModel.listState.collectWhenStarted(this) { state -> viewModel.listState.collectWhenStarted(this) { state ->
when (state) { when (state) {
is MainViewModel.ListState.Loading -> { is MainViewModel.ListState.Loading -> {
//TODO hideAll()
} }
is MainViewModel.ListState.Success -> { is MainViewModel.ListState.Success -> {
listAdapter.submitList(state.data) listAdapter.submitList(state.data)
} }
is MainViewModel.ListState.Error -> { is MainViewModel.ListState.Error -> {
//TODO hideAll()
binding.error.text = state.message binding.error.text = state.message
} }
} }
@ -139,11 +151,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
} }
private fun loadImageFromUrl(url: String) { private fun loadImageFromUrl(url: String) {
Picasso
.get()
.load(url)
.error(R.drawable.icon_profile)
.into(binding.photo)
} }
private fun setupMainComponents() { private fun setupMainComponents() {
@ -152,6 +160,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
navigateToLogin() navigateToLogin()
} }
binding.admin.setOnClickListener {
navigateToAdmin()
}
binding.refresh.setOnClickListener { binding.refresh.setOnClickListener {
viewModel.getUserData(authPreferences.getLogin() ?: "") viewModel.getUserData(authPreferences.getLogin() ?: "")
} }
@ -173,6 +185,19 @@ class MainFragment : Fragment(R.layout.fragment_main) {
} }
} }
private fun navigateToAdmin() {
try {
authPreferences.clearLoginState()
findNavController().apply {
popBackStack(AdminDestination, false)
navigate(AdminDestination)
}
} catch (e: Exception) {
Log.e("MainFragment", "Error navigating to login", e)
}
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null

View File

@ -36,12 +36,15 @@ class MainViewModel @Inject constructor(
when { when {
response.isSuccessful -> { response.isSuccessful -> {
val userInfo = response.body() ?: UserInfo.Initial val userInfo = response.body()
_state.value = MainState.Success(userInfo) _state.value = userInfo?.let { MainState.Success(it) }!!
} }
response.code() == 401 -> { response.code() == 401 -> {
_state.value = MainState.Error("Unauthorized") _state.value = MainState.Error("Unauthorized")
} }
response.code() == 403 -> {
_state.value = MainState.Error("Block")
}
else -> { else -> {
_state.value = MainState.Error("Error") _state.value = MainState.Error("Error")
} }

View File

@ -58,7 +58,9 @@ class ResultFragment : Fragment(R.layout.fragment_scan_result) {
if (qrData != null) { if (qrData != null) {
authPreferences.getLogin()?.let { login -> authPreferences.getLogin()?.let { login ->
val currentTime = getCurrentTime() val currentTime = getCurrentTime()
viewModel.open(login, CodeJson( viewModel.open(login, CodeJson(
value = qrData.toString(), value = qrData.toString(),
type = OpenType.QR_TYPE, type = OpenType.QR_TYPE,

View File

@ -1,6 +0,0 @@
package ru.myitschool.work.ui.result
object TextStatus {
const val error = "Вход был отменён/Operation was cancelled"
const val success = "Успешно/Success"
}

View File

@ -22,7 +22,6 @@ import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode import com.google.mlkit.vision.barcode.common.Barcode
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentQrScanBinding import ru.myitschool.work.databinding.FragmentQrScanBinding
import ru.myitschool.work.ui.main.MainDestination
import ru.myitschool.work.ui.result.ResultDestination import ru.myitschool.work.ui.result.ResultDestination
import ru.myitschool.work.utils.QrPreferences import ru.myitschool.work.utils.QrPreferences
import ru.myitschool.work.utils.collectWhenStarted import ru.myitschool.work.utils.collectWhenStarted
@ -41,10 +40,8 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
private val viewModel: QrScanViewModel by viewModels() private val viewModel: QrScanViewModel by viewModels()
private lateinit var qrPreferences: QrPreferences private lateinit var qrPreferences: QrPreferences
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
qrPreferences = QrPreferences(requireContext()) qrPreferences = QrPreferences(requireContext())
} }
@ -77,8 +74,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
goBack() goBack()
} }
is QrScanViewModel.Action.CloseWithResult -> { is QrScanViewModel.Action.CloseWithResult -> {
sendResult(QrScanDestination.packToBundle(action.result)) // Удаляем этот блок, так как мы будем обрабатывать результат в другом месте
goResult()
} }
} }
} }
@ -108,8 +104,12 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
executor executor
) { result -> ) { result ->
result?.getValue(barcodeScanner)?.firstOrNull()?.let { value -> result?.getValue(barcodeScanner)?.firstOrNull()?.let { value ->
viewModel.findBarcode(value)
qrPreferences.saveQr(value.displayValue ?: value.rawValue ?: "")
sendResult(QrScanDestination.packToBundle(value.displayValue ?: value.rawValue ?: ""))
goResult()
} }
} }
) )
@ -125,31 +125,17 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
super.onDestroyView() super.onDestroyView()
} }
private fun goBack() {
val qrData = arguments?.let { QrScanDestination.getDataIfExist(it) }
qrPreferences.saveQr(qrData.toString())
findNavControllerOrNull()?.popBackStack()
?: requireActivity().onBackPressedDispatcher.onBackPressed()
}
private fun goResult() { private fun goResult() {
try { findNavController().apply {
val qrData = arguments?.let { QrScanDestination.getDataIfExist(it) } popBackStack(ResultDestination, false)
qrPreferences.saveQr(qrData.toString()) navigate(ResultDestination)
Log.i("ResultFragment", qrData.toString())
findNavController().apply {
popBackStack(ResultDestination, false)
navigate(ResultDestination)
}
} catch (e: Exception) {
Log.e("ResultFragment", "Navigation error", e)
Toast.makeText(context, getText(R.string.errorGoText).toString(), Toast.LENGTH_SHORT).show()
} }
} }
private fun goBack() {
findNavControllerOrNull()?.popBackStack()
?: requireActivity().onBackPressedDispatcher.onBackPressed()
}
private fun sendResult(bundle: Bundle) { private fun sendResult(bundle: Bundle) {
setFragmentResult( setFragmentResult(

View File

@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M17,11c0.34,0 0.67,0.04 1,0.09V6.27L10.5,3L3,6.27v4.91c0,4.54 3.2,8.79 7.5,9.82c0.55,-0.13 1.08,-0.32 1.6,-0.55C11.41,19.47 11,18.28 11,17C11,13.69 13.69,11 17,11z"/>
<path android:fillColor="@android:color/white" android:pathData="M17,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C21,14.79 19.21,13 17,13zM17,14.38c0.62,0 1.12,0.51 1.12,1.12s-0.51,1.12 -1.12,1.12s-1.12,-0.51 -1.12,-1.12S16.38,14.38 17,14.38zM17,19.75c-0.93,0 -1.74,-0.46 -2.24,-1.17c0.05,-0.72 1.51,-1.08 2.24,-1.08s2.19,0.36 2.24,1.08C18.74,19.29 17.93,19.75 17,19.75z"/>
</vector>

View File

@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" /> <solid android:color="@color/white" />
<stroke <stroke
android:width="3dp" android:width="2dp"
android:color="@color/beige" /> android:color="@color/beige" />
<corners android:radius="8dp"/> <corners android:radius="8dp"/>
</shape> </shape>

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="169dp" android:width="77.53dp"
android:height="169dp" android:height="115.35dp"
android:viewportWidth="169" android:viewportWidth="77.53"
android:viewportHeight="169"> android:viewportHeight="115.35">
<path <path
android:pathData="M55.3,3.4c-15.3,5 -24.2,16.8 -25.1,33.2 -0.2,4.4 0.1,10.4 0.7,13.3 1.3,6.3 5.3,15 8.7,19l2.3,2.8 -7.2,3.6c-15.7,7.8 -27.3,22.3 -32.2,40.6 -0.9,3.1 -1.8,10.6 -2.2,16.8 -0.6,11 -0.6,11.2 2,13.5 4.1,3.9 19.6,11.5 30.7,15.2 13.9,4.6 24.4,6 39.4,5.3 13.5,-0.6 23,-2.8 36.5,-8.2 8.3,-3.3 9,-3.4 14.7,-2.4 11.3,2 24.8,-2.5 33.4,-11.1 19.5,-19.5 14,-52 -10.7,-64.2 -8.9,-4.4 -20.1,-5.1 -30.1,-1.9l-6.8,2.2 -5.9,-3.6c-3.3,-2 -7,-3.8 -8.2,-4.1 -2.9,-0.8 -2.9,-1 0.7,-6.4 8.7,-13.1 10.8,-31 5.1,-44.4 -3,-6.8 -10.1,-13.9 -17.4,-17.2 -5,-2.3 -7.9,-2.8 -15.2,-3.1 -5.7,-0.2 -10.5,0.2 -13.2,1.1zM78.1,11.5c9.4,3.2 16.1,11.6 18,22.2 3.4,19.6 -12.9,44.3 -29.2,44.3 -9,-0 -19.9,-9.3 -25.7,-22 -2.9,-6.5 -4.2,-20.5 -2.3,-26.2 3,-9.1 10.1,-16.3 18.2,-18.7 5.3,-1.5 16.1,-1.3 21,0.4zM57.2,84c8,3.6 18.2,2.1 26.6,-3.9 2.7,-1.9 2.8,-1.9 7.7,0.3 2.8,1.2 6.5,3 8.4,4l3.3,1.8 -3.4,3.6c-4.9,5.2 -7.5,9.9 -9.3,16.7 -3.9,15 0.9,30.1 12.8,40.7l4.2,3.7 -3,1.1c-14.4,5.5 -19.6,6.4 -37.5,6.4 -16.1,-0 -18.2,-0.2 -26.5,-2.7 -4.9,-1.5 -14.2,-5.3 -20.5,-8.4l-11.5,-5.8 -0.3,-6.6c-1,-22.2 11.3,-43.2 30.9,-52.8l8.3,-4 2.7,2c1.5,1.1 4.7,2.8 7.1,3.9zM142.5,87.8c6.8,3.3 12.7,9.2 15.9,16.1 3.2,7.1 3,19.9 -0.6,26.6 -3.2,6.2 -10.4,13 -16.6,15.8 -6.5,2.9 -17.9,2.9 -24.4,-0 -6.6,-3 -14.1,-10.4 -16.9,-16.6 -3.2,-7.1 -3.3,-19.1 -0.2,-25.8 3,-6.7 8.6,-12.4 15.5,-15.9 5.2,-2.5 7.3,-3 13.7,-3 6.3,-0 8.6,0.5 13.6,2.8z" android:pathData="M28.08,43.07h3.94v1h-3.94z"
android:fillColor="#000000" android:fillColor="#E9D4C3"/>
android:strokeColor="#00000000"/>
<path <path
android:pathData="M134.5,112l-9.9,9.9 -6.2,-5.9c-3.4,-3.3 -6.7,-6 -7.2,-6 -1.4,-0 -4.2,2.9 -4.2,4.3 0,0.7 3.8,5 8.5,9.7 8.2,8.1 8.5,8.3 11,7 3.4,-1.8 24.5,-23.5 24.5,-25.2 0,-2 -2.1,-3.8 -4.5,-3.8 -1.3,-0 -5.8,3.8 -12,10z" android:pathData="M36.1,43.07h12.85v1h-12.85z"
android:fillColor="#000000" android:fillColor="#E9D4C3"/>
android:strokeColor="#00000000"/> <path
android:pathData="M72.47,26l-2.49,28.5a5.18,5.18 0,0 1,-5.06 4.65,4.2 4.2,0 0,1 -4.25,-4.65L63.14,26a15.08,15.08 0,0 0,-15.24 -16.7L37.74,9.3A18.61,18.61 0,0 0,19.58 26l-1,11.64h-9.3l1,-11.64c1.25,-14.34 13.94,-26 28.27,-26h10.2A23.47,23.47 0,0 1,72.47 26Z"
android:fillColor="#E9D4C3"/>
<path
android:pathData="M72.47,26l-2.49,28.5a5.18,5.18 0,0 1,-5.06 4.65,4.2 4.2,0 0,1 -4.25,-4.65L63.14,26a15.08,15.08 0,0 0,-15.24 -16.7L37.74,9.3A18.61,18.61 0,0 0,19.58 26l-1,11.64h-9.3l1,-11.64c1.25,-14.34 13.94,-26 28.27,-26h10.2A23.47,23.47 0,0 1,72.47 26Z"
android:strokeAlpha="0.5"
android:fillColor="#fff"
android:fillAlpha="0.5"/>
<path
android:pathData="M73.14,53.46 L68.29,109a7.07,7.07 0,0 1,-6.92 6.35L5.83,115.35a5.73,5.73 0,0 1,-5.8 -6.35l4.86,-55.54a7.07,7.07 0,0 1,3.46 -5.39,6.8 6.8,0 0,1 3.46,-1L67.34,47.07a6,6 0,0 1,3.21 0.91A5.76,5.76 0,0 1,73.14 53.46Z"
android:fillColor="#E9D4C3"/>
<path
android:pathData="M15.39,77.72l14.43,22.21 47.59,-47.59a0.48,0.48 0,0 0,-0.63 -0.71l-45.35,35.55 -8.57,-13.81Z"
android:fillColor="#fff"/>
</vector> </vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M17.5,12C20.538,12 23,14.462 23,17.5C23,20.537 20.538,23 17.5,23C14.463,23 12,20.537 12,17.5C12,14.462 14.463,12 17.5,12ZM14.854,17.146C14.658,16.951 14.342,16.951 14.147,17.146C13.951,17.341 13.951,17.658 14.147,17.853L16.147,19.853C16.342,20.049 16.658,20.049 16.854,19.853L20.854,15.853C21.049,15.658 21.049,15.342 20.854,15.146C20.658,14.951 20.342,14.951 20.147,15.146L16.5,18.793L14.854,17.146ZM12.022,13.999C11.726,14.462 11.486,14.966 11.314,15.499L4.253,15.5C3.839,15.5 3.504,15.835 3.504,16.249V16.826C3.504,17.362 3.695,17.88 4.043,18.287C5.296,19.755 7.262,20.501 10,20.501C10.597,20.501 11.156,20.465 11.68,20.395C11.925,20.89 12.233,21.348 12.592,21.761C11.796,21.921 10.932,22.001 10,22.001C6.854,22.001 4.468,21.096 2.902,19.261C2.322,18.583 2.004,17.719 2.004,16.826V16.249C2.004,15.007 3.011,14 4.253,14L12.022,13.999ZM10,2.004C12.762,2.004 15,4.243 15,7.004C15,9.766 12.762,12.004 10,12.004C7.239,12.004 5,9.766 5,7.004C5,4.243 7.239,2.004 10,2.004ZM10,3.504C8.067,3.504 6.5,5.071 6.5,7.004C6.5,8.937 8.067,10.504 10,10.504C11.933,10.504 13.5,8.937 13.5,7.004C13.5,5.071 11.933,3.504 10,3.504Z"
android:fillColor="#212121"/>
</vector>

View File

@ -19,7 +19,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintGuide_percent="0.23" /> app:layout_constraintGuide_percent="0.21" />
<TextView <TextView
android:id="@+id/error" android:id="@+id/error"
@ -39,7 +39,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintGuide_percent="0.65" /> app:layout_constraintGuide_percent="0.62" />
<View <View
android:id="@+id/close" android:id="@+id/close"
@ -54,8 +54,8 @@
<View <View
android:id="@+id/success_icon" android:id="@+id/success_icon"
android:layout_width="230dp" android:layout_width="190dp"
android:layout_height="230dp" android:layout_height="250dp"
android:background="@drawable/res_success" android:background="@drawable/res_success"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/button_beigestroke_whitefill" android:background="@drawable/button_grestroke_whiteback"
android:layout_width="320dp" android:layout_width="320dp"
android:layout_height="80dp" android:layout_height="80dp"
android:orientation="vertical" android:orientation="vertical"

View File

@ -1,5 +1,5 @@
<resources> <resources>
<string name="app_name">NTO Pass</string> <string name="app_name">DoorRock</string>
<string name="loginText">логин</string> <string name="loginText">логин</string>
<string name="welcomeText">Добро пожаловать!</string> <string name="welcomeText">Добро пожаловать!</string>
<string name="inputLoginText">Введите свой логин</string> <string name="inputLoginText">Введите свой логин</string>