Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
efd651bd6d
@ -48,7 +48,13 @@ dependencies {
|
||||
implementation(Dependencies.Retrofit.gsonConverter)
|
||||
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("androidx.datastore:datastore-preferences:1.1.2")
|
||||
implementation("com.google.mlkit:barcode-scanning:17.3.0")
|
||||
|
@ -6,6 +6,7 @@ import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
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.login.ApiServiceLogin
|
||||
import ru.myitschool.work.api.main.ApiServiceMain
|
||||
@ -45,4 +46,10 @@ object NetworkModule {
|
||||
fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList {
|
||||
return retrofitClient.getApiServiceList()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideApiServiceAdmin(retrofitClient: RetrofitClient): ApiServiceAdmin {
|
||||
return retrofitClient.getApiServiceAdmin()
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package ru.myitschool.work.api
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.datatransport.BuildConfig
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import ru.myitschool.work.api.admin.ApiServiceAdmin
|
||||
import ru.myitschool.work.api.list.ApiServiceList
|
||||
import ru.myitschool.work.api.login.ApiServiceLogin
|
||||
import ru.myitschool.work.api.main.ApiServiceMain
|
||||
@ -57,4 +57,9 @@ class RetrofitClient(context: Context) {
|
||||
fun getApiServiceList(): ApiServiceList {
|
||||
return retrofitWithAuth.create(ApiServiceList::class.java)
|
||||
}
|
||||
|
||||
fun getApiServiceAdmin(): ApiServiceAdmin {
|
||||
return retrofitWithAuth.create(ApiServiceAdmin::class.java)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package ru.myitschool.work.api.admin
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class AdminJson(
|
||||
@SerializedName("authority") var authority: String? = null,
|
||||
)
|
@ -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>
|
||||
}
|
@ -5,6 +5,6 @@ import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
|
||||
interface ApiServiceList {
|
||||
@GET("api/list/{login}")
|
||||
@GET("api/user/list/{login}")
|
||||
suspend fun getList(@Path("login") login: String): Response<List<ListInfo>>
|
||||
}
|
@ -1,13 +1,9 @@
|
||||
package ru.myitschool.work.api.login
|
||||
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
import ru.myitschool.work.api.main.UserInfo
|
||||
|
||||
interface ApiServiceLogin {
|
||||
@GET("api/login")
|
||||
@GET("api/user/login")
|
||||
fun authenticate(): Call<Void>
|
||||
}
|
@ -5,6 +5,6 @@ import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
|
||||
interface ApiServiceMain {
|
||||
@GET("api/info/{login}")
|
||||
@GET("api/user/info/{login}")
|
||||
fun getDataUser(@Path("login") login: String): Call<UserInfo>
|
||||
}
|
@ -9,15 +9,16 @@ data class UserInfo(
|
||||
@SerializedName("photo") val photoUrl: String,
|
||||
@SerializedName("position") val position: String,
|
||||
@SerializedName("lastVisit") val lastVisit: String,
|
||||
) {
|
||||
companion object {
|
||||
val Initial = UserInfo(
|
||||
id = 0,
|
||||
login = "",
|
||||
name = "",
|
||||
photoUrl = "",
|
||||
position = "",
|
||||
lastVisit = "",
|
||||
)
|
||||
}
|
||||
@SerializedName("authority") val authority: List<AuthorityData>
|
||||
)
|
||||
|
||||
data class AuthorityData(
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("authority") val authority: String,
|
||||
)
|
||||
|
||||
object Authorities {
|
||||
const val ROLE_ADMIN = "ROLE_ADMIN"
|
||||
const val ROLE_USER = "ROLE_USER"
|
||||
const val ROLE_BLOCK = "ROLE_BLOCK"
|
||||
}
|
@ -6,6 +6,6 @@ import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
|
||||
interface ApiServiceScan {
|
||||
@POST("api/add/{login}")
|
||||
@POST("api/user/add/{login}")
|
||||
fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void>
|
||||
}
|
@ -9,6 +9,8 @@ import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.fragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
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.LoginFragment
|
||||
import ru.myitschool.work.ui.main.MainDestination
|
||||
@ -36,6 +38,7 @@ class RootActivity : AppCompatActivity() {
|
||||
fragment<QrScanFragment, QrScanDestination>()
|
||||
fragment<MainFragment, MainDestination>()
|
||||
fragment<ResultFragment, ResultDestination>()
|
||||
fragment<AdminFragment, AdminDestination>()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package ru.myitschool.work.ui.admin
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data object AdminDestination
|
101
app/src/main/java/ru/myitschool/work/ui/admin/AdminFragment.kt
Normal file
101
app/src/main/java/ru/myitschool/work/ui/admin/AdminFragment.kt
Normal 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()
|
||||
}
|
||||
}
|
135
app/src/main/java/ru/myitschool/work/ui/admin/AdminViewModel.kt
Normal file
135
app/src/main/java/ru/myitschool/work/ui/admin/AdminViewModel.kt
Normal 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()
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
private val binding = ItemRecyclerViewEntrancedataBinding.bind(itemView)
|
||||
|
||||
fun bind(item: ListInfo) {
|
||||
binding.text1.text = item.time
|
||||
binding.text1.text = item.time.replace("T", " ")
|
||||
binding.text2.text = item.value
|
||||
binding.text3.text = item.type
|
||||
}
|
||||
|
@ -103,8 +103,6 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
|
||||
text = "Ошибка авторизации"
|
||||
}
|
||||
|
||||
authPreferences.clearLoginState()
|
||||
|
||||
Log.d("Authentication", "Ошибка авторизации")
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ class LoginViewModel @Inject constructor(
|
||||
_state.value = LoginState.InvalidCredentials
|
||||
}
|
||||
401 -> {
|
||||
_state.value = LoginState.Error
|
||||
_state.value = LoginState.InvalidCredentials
|
||||
}
|
||||
else -> {
|
||||
_state.value = LoginState.Error
|
||||
|
@ -8,10 +8,11 @@ import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.squareup.picasso.Picasso
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.api.main.Authorities
|
||||
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.login.LoginDestination
|
||||
import ru.myitschool.work.ui.scan.qr.QrScanDestination
|
||||
@ -100,6 +101,16 @@ class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
username.text = state.userInfo.name
|
||||
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)
|
||||
|
||||
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 {
|
||||
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) {
|
||||
lastEntry.text = state.userInfo.lastVisit
|
||||
}
|
||||
@ -125,13 +137,13 @@ class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
viewModel.listState.collectWhenStarted(this) { state ->
|
||||
when (state) {
|
||||
is MainViewModel.ListState.Loading -> {
|
||||
//TODO
|
||||
hideAll()
|
||||
}
|
||||
is MainViewModel.ListState.Success -> {
|
||||
listAdapter.submitList(state.data)
|
||||
}
|
||||
is MainViewModel.ListState.Error -> {
|
||||
//TODO
|
||||
hideAll()
|
||||
binding.error.text = state.message
|
||||
}
|
||||
}
|
||||
@ -139,11 +151,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
}
|
||||
|
||||
private fun loadImageFromUrl(url: String) {
|
||||
Picasso
|
||||
.get()
|
||||
.load(url)
|
||||
.error(R.drawable.icon_profile)
|
||||
.into(binding.photo)
|
||||
|
||||
}
|
||||
|
||||
private fun setupMainComponents() {
|
||||
@ -152,6 +160,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
navigateToLogin()
|
||||
}
|
||||
|
||||
binding.admin.setOnClickListener {
|
||||
navigateToAdmin()
|
||||
}
|
||||
|
||||
binding.refresh.setOnClickListener {
|
||||
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() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
|
@ -36,12 +36,15 @@ class MainViewModel @Inject constructor(
|
||||
|
||||
when {
|
||||
response.isSuccessful -> {
|
||||
val userInfo = response.body() ?: UserInfo.Initial
|
||||
_state.value = MainState.Success(userInfo)
|
||||
val userInfo = response.body()
|
||||
_state.value = userInfo?.let { MainState.Success(it) }!!
|
||||
}
|
||||
response.code() == 401 -> {
|
||||
_state.value = MainState.Error("Unauthorized")
|
||||
}
|
||||
response.code() == 403 -> {
|
||||
_state.value = MainState.Error("Block")
|
||||
}
|
||||
else -> {
|
||||
_state.value = MainState.Error("Error")
|
||||
}
|
||||
|
@ -58,7 +58,9 @@ class ResultFragment : Fragment(R.layout.fragment_scan_result) {
|
||||
|
||||
if (qrData != null) {
|
||||
authPreferences.getLogin()?.let { login ->
|
||||
|
||||
val currentTime = getCurrentTime()
|
||||
|
||||
viewModel.open(login, CodeJson(
|
||||
value = qrData.toString(),
|
||||
type = OpenType.QR_TYPE,
|
||||
|
@ -1,6 +0,0 @@
|
||||
package ru.myitschool.work.ui.result
|
||||
|
||||
object TextStatus {
|
||||
const val error = "Вход был отменён/Operation was cancelled"
|
||||
const val success = "Успешно/Success"
|
||||
}
|
@ -22,7 +22,6 @@ import com.google.mlkit.vision.barcode.BarcodeScanning
|
||||
import com.google.mlkit.vision.barcode.common.Barcode
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.databinding.FragmentQrScanBinding
|
||||
import ru.myitschool.work.ui.main.MainDestination
|
||||
import ru.myitschool.work.ui.result.ResultDestination
|
||||
import ru.myitschool.work.utils.QrPreferences
|
||||
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 lateinit var qrPreferences: QrPreferences
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
qrPreferences = QrPreferences(requireContext())
|
||||
}
|
||||
|
||||
@ -77,8 +74,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
|
||||
goBack()
|
||||
}
|
||||
is QrScanViewModel.Action.CloseWithResult -> {
|
||||
sendResult(QrScanDestination.packToBundle(action.result))
|
||||
goResult()
|
||||
// Удаляем этот блок, так как мы будем обрабатывать результат в другом месте
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,8 +104,12 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
|
||||
executor
|
||||
) { result ->
|
||||
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()
|
||||
}
|
||||
|
||||
private fun goBack() {
|
||||
val qrData = arguments?.let { QrScanDestination.getDataIfExist(it) }
|
||||
qrPreferences.saveQr(qrData.toString())
|
||||
|
||||
findNavControllerOrNull()?.popBackStack()
|
||||
?: requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
private fun goResult() {
|
||||
try {
|
||||
val qrData = arguments?.let { QrScanDestination.getDataIfExist(it) }
|
||||
qrPreferences.saveQr(qrData.toString())
|
||||
|
||||
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()
|
||||
findNavController().apply {
|
||||
popBackStack(ResultDestination, false)
|
||||
navigate(ResultDestination)
|
||||
}
|
||||
}
|
||||
|
||||
private fun goBack() {
|
||||
findNavControllerOrNull()?.popBackStack()
|
||||
?: requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
private fun sendResult(bundle: Bundle) {
|
||||
setFragmentResult(
|
||||
|
@ -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>
|
@ -2,7 +2,7 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/white" />
|
||||
<stroke
|
||||
android:width="3dp"
|
||||
android:width="2dp"
|
||||
android:color="@color/beige" />
|
||||
<corners android:radius="8dp"/>
|
||||
</shape>
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,26 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="169dp"
|
||||
android:height="169dp"
|
||||
android:viewportWidth="169"
|
||||
android:viewportHeight="169">
|
||||
android:width="77.53dp"
|
||||
android:height="115.35dp"
|
||||
android:viewportWidth="77.53"
|
||||
android:viewportHeight="115.35">
|
||||
<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:fillColor="#000000"
|
||||
android:strokeColor="#00000000"/>
|
||||
android:pathData="M28.08,43.07h3.94v1h-3.94z"
|
||||
android:fillColor="#E9D4C3"/>
|
||||
<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:fillColor="#000000"
|
||||
android:strokeColor="#00000000"/>
|
||||
android:pathData="M36.1,43.07h12.85v1h-12.85z"
|
||||
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: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>
|
||||
|
9
app/src/main/res/drawable/res_success_ic.xml
Normal file
9
app/src/main/res/drawable/res_success_ic.xml
Normal 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>
|
@ -19,7 +19,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.23" />
|
||||
app:layout_constraintGuide_percent="0.21" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
@ -39,7 +39,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.65" />
|
||||
app:layout_constraintGuide_percent="0.62" />
|
||||
|
||||
<View
|
||||
android:id="@+id/close"
|
||||
@ -54,8 +54,8 @@
|
||||
|
||||
<View
|
||||
android:id="@+id/success_icon"
|
||||
android:layout_width="230dp"
|
||||
android:layout_height="230dp"
|
||||
android:layout_width="190dp"
|
||||
android:layout_height="250dp"
|
||||
android:background="@drawable/res_success"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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_height="80dp"
|
||||
android:orientation="vertical"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">NTO Pass</string>
|
||||
<string name="app_name">DoorRock</string>
|
||||
<string name="loginText">логин</string>
|
||||
<string name="welcomeText">Добро пожаловать!</string>
|
||||
<string name="inputLoginText">Введите свой логин</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user