diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 8c899db..a28d464 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,9 @@
plugins {
kotlinAndroid
androidApplication
+ jetbrainsKotlinSerialization version Version.Kotlin.language
+ kotlinAnnotationProcessor
+ id("com.google.dagger.hilt.android").version("2.51.1")
}
val packageName = "ru.myitschool.work"
@@ -34,4 +37,33 @@ android {
dependencies {
defaultLibrary()
+ implementation(Dependencies.AndroidX.activity)
+ implementation(Dependencies.AndroidX.fragment)
+ implementation(Dependencies.AndroidX.constraintLayout)
+
+ implementation(Dependencies.AndroidX.Navigation.fragment)
+ implementation(Dependencies.AndroidX.Navigation.navigationUi)
+
+ implementation(Dependencies.Retrofit.library)
+ implementation(Dependencies.Retrofit.gsonConverter)
+
+ implementation("com.squareup.picasso:picasso:2.8")
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
+ implementation("androidx.datastore:datastore-preferences:1.1.1")
+ implementation("com.google.mlkit:barcode-scanning:17.3.0")
+
+ val cameraX = "1.3.4"
+ implementation("androidx.camera:camera-core:$cameraX")
+ implementation("androidx.camera:camera-camera2:$cameraX")
+ implementation("androidx.camera:camera-lifecycle:$cameraX")
+ implementation("androidx.camera:camera-view:$cameraX")
+ implementation("androidx.camera:camera-mlkit-vision:1.4.0-rc04")
+
+ val hilt = "2.51.1"
+ implementation("com.google.dagger:hilt-android:$hilt")
+ kapt("com.google.dagger:hilt-android-compiler:$hilt")
+}
+
+kapt {
+ correctErrorTypes = true
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9ee5c40..795af31 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,7 +2,12 @@
+
+
+
+
+ tools:targetApi="31">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/App.kt b/app/src/main/java/ru/myitschool/work/App.kt
new file mode 100644
index 0000000..3085135
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/App.kt
@@ -0,0 +1,7 @@
+package ru.myitschool.work
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class App : Application()
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/core/Constants.kt b/app/src/main/java/ru/myitschool/work/core/Constants.kt
new file mode 100644
index 0000000..5af1798
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/core/Constants.kt
@@ -0,0 +1,5 @@
+package ru.myitschool.work.core
+// НЕ ИЗМЕНЯЙТЕ ЭТОТ ФАЙЛ. В ТЕСТАХ ОН БУДЕМ ВОЗВРАЩЁН В ИСХОДНОЕ СОСТОЯНИЕ
+object Constants {
+ const val SERVER_ADDRESS = "http://localhost:8090"
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt
new file mode 100644
index 0000000..88a796a
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt
@@ -0,0 +1,56 @@
+package ru.myitschool.work.ui
+
+import android.os.Bundle
+import androidx.activity.OnBackPressedCallback
+import androidx.appcompat.app.AppCompatActivity
+import androidx.navigation.createGraph
+import androidx.navigation.findNavController
+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.login.LoginDestination
+import ru.myitschool.work.ui.login.LoginFragment
+import ru.myitschool.work.ui.qr.scan.QrScanDestination
+import ru.myitschool.work.ui.qr.scan.QrScanFragment
+
+// НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА!
+@AndroidEntryPoint
+class RootActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_root)
+
+ val navHostFragment = supportFragmentManager
+ .findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
+
+ if (navHostFragment != null) {
+ val navController = navHostFragment.navController
+ navController.graph = navController.createGraph(
+ startDestination = LoginDestination
+ ) {
+ fragment()
+ fragment()
+ }
+ }
+
+ onBackPressedDispatcher.addCallback(
+ this,
+ object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ onSupportNavigateUp()
+ }
+ }
+ )
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ val navController = findNavController(R.id.nav_host_fragment)
+ val popBackResult = if (navController.previousBackStackEntry != null) {
+ navController.popBackStack()
+ } else {
+ false
+ }
+ return popBackResult || super.onSupportNavigateUp()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginDestination.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginDestination.kt
new file mode 100644
index 0000000..50acfb0
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginDestination.kt
@@ -0,0 +1,6 @@
+package ru.myitschool.work.ui.login
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data object LoginDestination
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt
new file mode 100644
index 0000000..02842ce
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt
@@ -0,0 +1,36 @@
+package ru.myitschool.work.ui.login
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import dagger.hilt.android.AndroidEntryPoint
+import ru.myitschool.work.R
+import ru.myitschool.work.databinding.FragmentLoginBinding
+import ru.myitschool.work.utils.collectWhenStarted
+import ru.myitschool.work.utils.visibleOrGone
+
+@AndroidEntryPoint
+class LoginFragment : Fragment(R.layout.fragment_login) {
+ private var _binding: FragmentLoginBinding? = null
+ private val binding: FragmentLoginBinding get() = _binding!!
+
+ private val viewModel: LoginViewModel by viewModels()
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ _binding = FragmentLoginBinding.bind(view)
+ subscribe()
+ }
+
+ private fun subscribe() {
+ viewModel.state.collectWhenStarted(this) { state ->
+ binding.loading.visibleOrGone(state)
+ }
+ }
+
+ override fun onDestroyView() {
+ _binding = null
+ super.onDestroyView()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt
new file mode 100644
index 0000000..3a53d6c
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt
@@ -0,0 +1,17 @@
+package ru.myitschool.work.ui.login
+
+import android.content.Context
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import javax.inject.Inject
+
+@HiltViewModel
+class LoginViewModel @Inject constructor(
+ @ApplicationContext private val context: Context,
+) : ViewModel() {
+ private val _state = MutableStateFlow(true)
+ val state = _state.asStateFlow()
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanDestination.kt b/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanDestination.kt
new file mode 100644
index 0000000..7e34b28
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanDestination.kt
@@ -0,0 +1,30 @@
+package ru.myitschool.work.ui.qr.scan
+
+import android.os.Bundle
+import androidx.core.os.bundleOf
+import kotlinx.serialization.Serializable
+
+// НЕ ИЗМЕНЯЙТЕ ЭТОТ ФАЙЛ. В ТЕСТАХ ОН БУДЕМ ВОЗВРАЩЁН В ИСХОДНОЕ СОСТОЯНИЕ
+@Serializable
+data object QrScanDestination {
+ const val REQUEST_KEY = "qr_result"
+ private const val KEY_QR_DATA = "key_qr"
+
+ fun newInstance(): QrScanFragment {
+ return QrScanFragment()
+ }
+
+ fun getDataIfExist(bundle: Bundle): String? {
+ return if (bundle.containsKey(KEY_QR_DATA)) {
+ bundle.getString(KEY_QR_DATA)
+ } else {
+ null
+ }
+ }
+
+ internal fun packToBundle(data: String): Bundle {
+ return bundleOf(
+ KEY_QR_DATA to data
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanFragment.kt b/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanFragment.kt
new file mode 100644
index 0000000..a9ddaab
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanFragment.kt
@@ -0,0 +1,139 @@
+package ru.myitschool.work.ui.qr.scan
+
+import android.os.Bundle
+import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.mlkit.vision.MlKitAnalyzer
+import androidx.camera.view.LifecycleCameraController
+import androidx.camera.view.PreviewView
+import androidx.core.content.ContextCompat
+import androidx.core.os.bundleOf
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.setFragmentResult
+import androidx.fragment.app.viewModels
+import androidx.navigation.NavController
+import androidx.navigation.fragment.findNavController
+import com.google.mlkit.vision.barcode.BarcodeScanner
+import com.google.mlkit.vision.barcode.BarcodeScannerOptions
+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.utils.collectWhenStarted
+import ru.myitschool.work.utils.visibleOrGone
+
+// НЕ ИЗМЕНЯЙТЕ ЭТОТ ФАЙЛ. В ТЕСТАХ ОН БУДЕМ ВОЗВРАЩЁН В ИСХОДНОЕ СОСТОЯНИЕ
+class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
+ private var _binding: FragmentQrScanBinding? = null
+ private val binding: FragmentQrScanBinding get() = _binding!!
+
+ private var barcodeScanner: BarcodeScanner? = null
+ private var isCameraInit: Boolean = false
+ private val permissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted -> viewModel.onPermissionResult(isGranted) }
+
+ private val viewModel: QrScanViewModel by viewModels()
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ _binding = FragmentQrScanBinding.bind(view)
+ sendResult(bundleOf())
+ subscribe()
+ initCallback()
+ }
+
+ private fun initCallback() {
+ binding.close.setOnClickListener { viewModel.close() }
+ }
+
+ private fun subscribe() {
+ viewModel.state.collectWhenStarted(this) { state ->
+ binding.loading.visibleOrGone(state is QrScanViewModel.State.Loading)
+ binding.viewFinder.visibleOrGone(state is QrScanViewModel.State.Scan)
+ if (!isCameraInit && state is QrScanViewModel.State.Scan) {
+ startCamera()
+ isCameraInit = true
+ }
+ }
+
+ viewModel.action.collectWhenStarted(this) { action ->
+ when (action) {
+ is QrScanViewModel.Action.RequestPermission -> requestPermission(action.permission)
+ is QrScanViewModel.Action.CloseWithCancel -> {
+ goBack()
+ }
+ is QrScanViewModel.Action.CloseWithResult -> {
+ sendResult(QrScanDestination.packToBundle(action.result))
+ goBack()
+ }
+ }
+ }
+ }
+
+ private fun requestPermission(permission: String) {
+ permissionLauncher.launch(permission)
+ }
+
+ private fun startCamera() {
+ val context = requireContext()
+ val cameraController = LifecycleCameraController(context)
+ val previewView: PreviewView = binding.viewFinder
+ val executor = ContextCompat.getMainExecutor(context)
+
+ val options = BarcodeScannerOptions.Builder()
+ .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
+ .build()
+ val barcodeScanner = BarcodeScanning.getClient(options)
+ this.barcodeScanner = barcodeScanner
+
+ cameraController.setImageAnalysisAnalyzer(
+ executor,
+ MlKitAnalyzer(
+ listOf(barcodeScanner),
+ ImageAnalysis.COORDINATE_SYSTEM_VIEW_REFERENCED,
+ executor
+ ) { result ->
+ result?.getValue(barcodeScanner)?.firstOrNull()?.let { value ->
+ viewModel.findBarcode(value)
+
+ }
+ }
+ )
+
+ cameraController.bindToLifecycle(this)
+ previewView.controller = cameraController
+ }
+
+ override fun onDestroyView() {
+ barcodeScanner?.close()
+ barcodeScanner = null
+ _binding = null
+ super.onDestroyView()
+ }
+
+ private fun goBack() {
+ findNavControllerOrNull()?.popBackStack()
+ ?: requireActivity().onBackPressedDispatcher.onBackPressed()
+ }
+
+ private fun sendResult(bundle: Bundle) {
+ setFragmentResult(
+ QrScanDestination.REQUEST_KEY,
+ bundle
+ )
+ findNavControllerOrNull()
+ ?.previousBackStackEntry
+ ?.savedStateHandle
+ ?.set(QrScanDestination.REQUEST_KEY, bundle)
+ }
+
+ private fun findNavControllerOrNull(): NavController? {
+ return try {
+ findNavController()
+ } catch (_: Throwable) {
+ null
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanViewModel.kt
new file mode 100644
index 0000000..14565ab
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/ui/qr/scan/QrScanViewModel.kt
@@ -0,0 +1,93 @@
+package ru.myitschool.work.ui.qr.scan
+
+import android.Manifest
+import android.app.Application
+import android.content.pm.PackageManager
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.google.mlkit.vision.barcode.common.Barcode
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import ru.myitschool.work.utils.MutablePublishFlow
+
+// НЕ ИЗМЕНЯЙТЕ ЭТОТ ФАЙЛ. В ТЕСТАХ ОН БУДЕМ ВОЗВРАЩЁН В ИСХОДНОЕ СОСТОЯНИЕ
+class QrScanViewModel(
+ application: Application
+) : AndroidViewModel(application) {
+
+ private val _action = MutablePublishFlow()
+ val action = _action.asSharedFlow()
+
+ private val _state = MutableStateFlow(initialState)
+ val state = _state.asStateFlow()
+
+ init {
+ checkPermission()
+ }
+
+ fun onPermissionResult(isGranted: Boolean) {
+ viewModelScope.launch {
+ if (isGranted) {
+ _state.update { State.Scan }
+ } else {
+ _action.emit(Action.CloseWithCancel)
+ }
+ }
+ }
+
+ private fun checkPermission() {
+ viewModelScope.launch {
+ val isPermissionGranted = ContextCompat.checkSelfPermission(
+ getApplication(),
+ CAMERA_PERMISSION
+ ) == PackageManager.PERMISSION_GRANTED
+ if (isPermissionGranted) {
+ _state.update { State.Scan }
+ } else {
+ delay(1000)
+ _action.emit(Action.RequestPermission(CAMERA_PERMISSION))
+ }
+ }
+ }
+
+ fun findBarcode(barcode: Barcode) {
+ viewModelScope.launch {
+ barcode.rawValue?.let { value ->
+ _action.emit(Action.CloseWithResult(value))
+ }
+ }
+ }
+
+ fun close() {
+ viewModelScope.launch {
+ _action.emit(Action.CloseWithCancel)
+ }
+ }
+
+ sealed interface State {
+ data object Loading : State
+
+ data object Scan : State
+ }
+
+ sealed interface Action {
+ data class RequestPermission(
+ val permission: String
+ ) : Action
+ data object CloseWithCancel : Action
+ data class CloseWithResult(
+ val result: String
+ ) : Action
+ }
+
+ private companion object {
+ val initialState = State.Loading
+
+ const val CAMERA_PERMISSION = Manifest.permission.CAMERA
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/utils/FlowExtensions.kt b/app/src/main/java/ru/myitschool/work/utils/FlowExtensions.kt
new file mode 100644
index 0000000..87bccc2
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/utils/FlowExtensions.kt
@@ -0,0 +1,10 @@
+package ru.myitschool.work.utils
+
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+
+fun MutablePublishFlow() = MutableSharedFlow(
+ replay = 0,
+ extraBufferCapacity = 1,
+ BufferOverflow.DROP_OLDEST
+)
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/utils/FragmentExtesions.kt b/app/src/main/java/ru/myitschool/work/utils/FragmentExtesions.kt
new file mode 100644
index 0000000..8c99ef3
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/utils/FragmentExtesions.kt
@@ -0,0 +1,18 @@
+package ru.myitschool.work.utils
+
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.flowWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+
+inline fun Flow.collectWhenStarted(
+ fragment: Fragment,
+ crossinline collector: (T) -> Unit
+) {
+ fragment.viewLifecycleOwner.lifecycleScope.launch {
+ flowWithLifecycle(fragment.viewLifecycleOwner.lifecycle).collect { value ->
+ collector.invoke(value)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/utils/TextChangedListener.kt b/app/src/main/java/ru/myitschool/work/utils/TextChangedListener.kt
new file mode 100644
index 0000000..c81147d
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/utils/TextChangedListener.kt
@@ -0,0 +1,12 @@
+package ru.myitschool.work.utils
+
+import android.text.Editable
+import android.text.TextWatcher
+
+open class TextChangedListener: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
+
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
+
+ override fun afterTextChanged(s: Editable?) = Unit
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/myitschool/work/utils/ViewExtensions.kt b/app/src/main/java/ru/myitschool/work/utils/ViewExtensions.kt
new file mode 100644
index 0000000..5c38f67
--- /dev/null
+++ b/app/src/main/java/ru/myitschool/work/utils/ViewExtensions.kt
@@ -0,0 +1,7 @@
+package ru.myitschool.work.utils
+
+import android.view.View
+
+fun View.visibleOrGone(isVisible: Boolean) {
+ this.visibility = if (isVisible) View.VISIBLE else View.GONE
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml
new file mode 100644
index 0000000..f8ca0c6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_close.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_logout.xml b/app/src/main/res/drawable/ic_logout.xml
new file mode 100644
index 0000000..c22a96f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_logout.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_no_img.xml b/app/src/main/res/drawable/ic_no_img.xml
new file mode 100644
index 0000000..44206c9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_no_img.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_qr_code.xml b/app/src/main/res/drawable/ic_qr_code.xml
new file mode 100644
index 0000000..b03f9ae
--- /dev/null
+++ b/app/src/main/res/drawable/ic_qr_code.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_refresh.xml b/app/src/main/res/drawable/ic_refresh.xml
new file mode 100644
index 0000000..86504d0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_refresh.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_root.xml b/app/src/main/res/layout/activity_root.xml
new file mode 100644
index 0000000..e7cb1a9
--- /dev/null
+++ b/app/src/main/res/layout/activity_root.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml
new file mode 100644
index 0000000..7f3cd66
--- /dev/null
+++ b/app/src/main/res/layout/fragment_login.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_qr_scan.xml b/app/src/main/res/layout/fragment_qr_scan.xml
new file mode 100644
index 0000000..a52eb71
--- /dev/null
+++ b/app/src/main/res/layout/fragment_qr_scan.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
new file mode 100644
index 0000000..ce65075
--- /dev/null
+++ b/app/src/main/res/values/ids.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ 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 96034ac..b183019 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,3 @@
- Work
+ NTO Pass
\ No newline at end of file
diff --git a/app/src/main/res/values/strings_qr.xml b/app/src/main/res/values/strings_qr.xml
new file mode 100644
index 0000000..ce50067
--- /dev/null
+++ b/app/src/main/res/values/strings_qr.xml
@@ -0,0 +1,4 @@
+
+
+ Close
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 64d8748..f83a038 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,4 +2,5 @@
plugins {
androidApplication version Version.agp apply false
kotlinJvm version Version.Kotlin.language apply false
+ id("com.google.dagger.hilt.android") version "2.51.1" apply false
}
\ No newline at end of file
diff --git a/buildSrc b/buildSrc
index d959060..ec48d5f 160000
--- a/buildSrc
+++ b/buildSrc
@@ -1 +1 @@
-Subproject commit d9590600045906edeb852eaa3f0b9bf7d1875813
+Subproject commit ec48d5f6b8c45e8058303282e9ec1c1d0ed02989