Merge remote-tracking branch 'origin/main'

This commit is contained in:
veronicagtea 2025-02-20 10:18:09 +03:00
commit 36004a2ba4
22 changed files with 362 additions and 129 deletions

View File

@ -0,0 +1,82 @@
kotlin version: 2.0.21
error message: Daemon compilation failed: null
java.lang.Exception
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:240)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:195)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:128)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:170)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:136)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:165)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:134)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.nio.file.DirectoryNotEmptyException: C:\Users\User\AppData\Local\Temp\kotlin-backups5267971900938964466
at java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(Unknown Source)
at java.base/sun.nio.fs.AbstractFileSystemProvider.delete(Unknown Source)
at java.base/java.nio.file.Files.delete(Unknown Source)
at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction$cleanupStash$2$1$1.invoke(CompilationTransaction.kt:244)
at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction$cleanupStash$2$1$1.invoke(CompilationTransaction.kt:244)
at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.cleanupStash$lambda$11$lambda$10$lambda$9(CompilationTransaction.kt:244)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
at java.base/java.util.ArrayList.forEach(Unknown Source)
at java.base/java.util.stream.SortedOps$RefSortingSink.end(Unknown Source)
at java.base/java.util.stream.Sink$ChainedReference.end(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.cleanupStash(CompilationTransaction.kt:244)
at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.close(CompilationTransaction.kt:254)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.tryCompileIncrementally(IncrementalCompilerRunner.kt:747)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:120)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
... 3 more

View File

@ -46,6 +46,7 @@ dependencies {
implementation(Dependencies.Retrofit.library)
implementation(Dependencies.Retrofit.gsonConverter)
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
implementation("com.squareup.picasso:picasso:2.8")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")

View File

@ -1,64 +0,0 @@
package ru.myitschool.work;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {@link Fragment} subclass.
* Use the {@link administrator_screen#newInstance} factory method to
* create an instance of this fragment.
*/
public class administrator_screen extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public administrator_screen() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment administrator_screen.
*/
// TODO: Rename and change types and number of parameters
public static administrator_screen newInstance(String param1, String param2) {
administrator_screen fragment = new administrator_screen();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_administrator_screen, container, false);
}
}

View File

@ -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.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain
import ru.myitschool.work.api.scan.ApiServiceScan
@ -38,4 +39,10 @@ object NetworkModule {
fun provideApiServiceScan(retrofitClient: RetrofitClient): ApiServiceScan {
return retrofitClient.getApiServiceScanAuth()
}
@Provides
@Singleton
fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList {
return retrofitClient.getApiServiceList()
}
}

View File

@ -1,9 +1,12 @@
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.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain
import ru.myitschool.work.api.scan.ApiServiceScan
@ -16,12 +19,18 @@ class RetrofitClient(context: Context) {
private val serverAddress = SERVER_ADDRESS
private var authPreferences: AuthPreferences = AuthPreferences(context)
private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
private val httpClientWithAuth = OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.addInterceptor(BasicAuthInterceptor(
authPreferences.getLogin() ?: "",
authPreferences.getPassword() ?: ""
))
.addInterceptor(loggingInterceptor)
.readTimeout(5, TimeUnit.SECONDS)
.build()
@ -44,4 +53,8 @@ class RetrofitClient(context: Context) {
fun getApiServiceScanAuth(): ApiServiceScan {
return retrofitWithAuth.create(ApiServiceScan::class.java)
}
fun getApiServiceList(): ApiServiceList {
return retrofitWithAuth.create(ApiServiceList::class.java)
}
}

View File

@ -1,10 +1,10 @@
package ru.myitschool.work.api.list
import retrofit2.Call
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Path
interface ApiServiceList {
@GET("api/auth/{login}")
fun authenticate(@Path("login") login: String): Call<Void>
@GET("api/list/{login}")
suspend fun getList(@Path("login") login: String): Response<List<ListInfo>>
}

View File

@ -0,0 +1,7 @@
package ru.myitschool.work.api.list
data class ListInfo(
val value: String,
val type: String,
val time: String
)

View File

@ -8,6 +8,6 @@ import retrofit2.http.Path
import ru.myitschool.work.api.main.UserInfo
interface ApiServiceLogin {
@GET("api/auth")
@GET("api/login")
fun authenticate(): Call<Void>
}

View File

@ -2,10 +2,10 @@ package ru.myitschool.work.api.scan
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.Path
interface ApiServiceScan {
@PATCH("api/info/{login}")
@POST("api/add/{login}")
fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void>
}

View File

@ -1,9 +1,11 @@
package ru.myitschool.work.api.scan
import com.google.gson.annotations.SerializedName
class CodeJson(
private var value: String? = null,
private var type: String? = null,
private var time: String? = null
@SerializedName("value") var value: String? = null,
@SerializedName("type") var type: String? = null,
@SerializedName("time") var time: String? = null
)
object OpenType {

View File

@ -1,5 +1,5 @@
package ru.myitschool.work.core
object Constants {
const val SERVER_ADDRESS = "http://192.168.1.113:8080"
const val SERVER_ADDRESS = "http://10.6.66.93:8080"
}

View File

@ -13,8 +13,8 @@ import ru.myitschool.work.ui.login.LoginDestination
import ru.myitschool.work.ui.login.LoginFragment
import ru.myitschool.work.ui.main.MainDestination
import ru.myitschool.work.ui.main.MainFragment
import ru.myitschool.work.ui.qr.scan.QrScanDestination
import ru.myitschool.work.ui.qr.scan.QrScanFragment
import ru.myitschool.work.ui.scan.qr.QrScanDestination
import ru.myitschool.work.ui.scan.qr.QrScanFragment
import ru.myitschool.work.ui.result.ResultDestination
import ru.myitschool.work.ui.result.ResultFragment

View File

@ -0,0 +1,35 @@
package ru.myitschool.work.ui.list
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import ru.myitschool.work.R
import ru.myitschool.work.api.list.ListInfo
class ListAdapter : ListAdapter<ListInfo, ListViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_recycler_view_entrancedata, parent, false)
return ListViewHolder(view)
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
}
class DiffCallback : DiffUtil.ItemCallback<ListInfo>() {
override fun areItemsTheSame(oldItem: ListInfo, newItem: ListInfo): Boolean {
return oldItem.time == newItem.time && oldItem.value == newItem.value
}
override fun areContentsTheSame(oldItem: ListInfo, newItem: ListInfo): Boolean {
return oldItem == newItem
}
}
}

View File

@ -0,0 +1,13 @@
package ru.myitschool.work.ui.list
import ru.myitschool.work.api.list.ApiServiceList
import ru.myitschool.work.api.list.ListInfo
import javax.inject.Inject
class ListRepository @Inject constructor(
private val apiService: ApiServiceList
) {
suspend fun getList(login: String): List<ListInfo> {
return apiService.getList(login).body() ?: emptyList()
}
}

View File

@ -0,0 +1,16 @@
package ru.myitschool.work.ui.list
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import ru.myitschool.work.api.list.ListInfo
import ru.myitschool.work.databinding.ItemRecyclerViewEntrancedataBinding
class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val binding = ItemRecyclerViewEntrancedataBinding.bind(itemView)
fun bind(item: ListInfo) {
binding.text1.text = item.time
binding.text2.text = item.value
binding.text3.text = item.type
}
}

View File

@ -1,24 +1,23 @@
package ru.myitschool.work.ui.main
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentMainBinding
import ru.myitschool.work.ui.list.ListAdapter
import ru.myitschool.work.ui.login.LoginDestination
import ru.myitschool.work.ui.qr.scan.QrScanDestination
import ru.myitschool.work.ui.scan.qr.QrScanDestination
import ru.myitschool.work.utils.AuthPreferences
import ru.myitschool.work.utils.collectWhenStarted
import java.net.URL
import ru.myitschool.work.utils.visibleOrGone
import java.util.Locale
@AndroidEntryPoint
@ -27,6 +26,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
private val binding: FragmentMainBinding get() = _binding!!
private lateinit var authPreferences: AuthPreferences
private val viewModel: MainViewModel by viewModels()
private lateinit var listAdapter: ListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -41,23 +41,41 @@ class MainFragment : Fragment(R.layout.fragment_main) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentMainBinding.bind(view)
setupRecyclerView()
if (authPreferences.isLoggedIn()) {
setupMainComponents()
observeUserState()
observeListState()
viewModel.getUserData(authPreferences.getLogin() ?: "")
val login = authPreferences.getLogin().toString()
viewModel.loadList(login)
}
}
private fun hideAll() {
binding.apply {
username.visibility = View.GONE
position.visibility = View.GONE
lastEntry.visibility = View.GONE
scan.visibility = View.GONE
logout.visibility = View.GONE
username.visibleOrGone(false)
position.visibleOrGone(false)
lastEntry.visibleOrGone(false)
scan.visibleOrGone(false)
logout.visibleOrGone(false)
error.visibility = View.VISIBLE
refresh.visibility = View.VISIBLE
error.visibleOrGone(true)
refresh.visibleOrGone(true)
}
}
private fun setupRecyclerView() {
listAdapter = ListAdapter()
binding.entranceData.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = listAdapter
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
}
}
@ -65,19 +83,19 @@ class MainFragment : Fragment(R.layout.fragment_main) {
viewModel.state.collectWhenStarted(this) { state ->
when (state) {
is MainViewModel.MainState.Initial -> {
binding.error.visibility = View.GONE
binding.error.visibleOrGone(false)
}
is MainViewModel.MainState.Loading -> {
binding.error.visibility = View.GONE
binding.error.visibleOrGone(false)
}
is MainViewModel.MainState.Success -> {
binding.apply {
username.visibility = View.VISIBLE
position.visibility = View.VISIBLE
lastEntry.visibility = View.VISIBLE
scan.visibility = View.VISIBLE
logout.visibility = View.VISIBLE
error.visibility = View.GONE
username.visibleOrGone(true)
position.visibleOrGone(true)
lastEntry.visibleOrGone(true)
scan.visibleOrGone(true)
logout.visibleOrGone(true)
error.visibleOrGone(false)
username.text = state.userInfo.name
position.text = state.userInfo.position
@ -103,26 +121,31 @@ class MainFragment : Fragment(R.layout.fragment_main) {
}
}
private fun loadImageFromUrl(url: String) {
CoroutineScope(Dispatchers.IO).launch {
val bitmap = try {
val input = URL(url).openStream()
BitmapFactory.decodeStream(input)
} catch (e: Exception) {
Log.e("MainFragment", "Error loading image", e)
null
}
withContext(Dispatchers.Main) {
if (bitmap != null) {
binding.photo.setImageBitmap(bitmap)
} else {
binding.photo.setImageResource(R.drawable.ic_no_img)
private fun observeListState() {
viewModel.listState.collectWhenStarted(this) { state ->
when (state) {
is MainViewModel.ListState.Loading -> {
//TODO
}
is MainViewModel.ListState.Success -> {
listAdapter.submitList(state.data)
}
is MainViewModel.ListState.Error -> {
//TODO
binding.error.text = state.message
}
}
}
}
private fun loadImageFromUrl(url: String) {
Picasso
.get()
.load(url)
.error(R.drawable.icon_profile)
.into(binding.photo)
}
private fun setupMainComponents() {
binding.logout.setOnClickListener {
authPreferences.clearLoginState()

View File

@ -5,18 +5,22 @@ 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.list.ListInfo
import ru.myitschool.work.api.main.ApiServiceMain
import ru.myitschool.work.api.main.UserInfo
import ru.myitschool.work.ui.list.ListRepository
import javax.inject.Inject
@HiltViewModel
class MainViewModel @Inject constructor(
private val apiService: ApiServiceMain
private val apiService: ApiServiceMain,
private val listRepository: ListRepository
) : ViewModel() {
private val _state = MutableStateFlow<MainState>(MainState.Initial)
@ -52,6 +56,27 @@ class MainViewModel @Inject constructor(
}
}
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 MainState {
data object Initial : MainState()
data object Loading : MainState()

View File

@ -13,8 +13,8 @@ import ru.myitschool.work.api.scan.CodeJson
import ru.myitschool.work.api.scan.OpenType
import ru.myitschool.work.databinding.FragmentScanResultBinding
import ru.myitschool.work.ui.main.MainDestination
import ru.myitschool.work.ui.qr.scan.QrScanDestination
import ru.myitschool.work.utils.AuthPreferences
import ru.myitschool.work.utils.QrPreferences
import ru.myitschool.work.utils.collectWhenStarted
import ru.myitschool.work.utils.getCurrentTime
import ru.myitschool.work.utils.visibleOrGone
@ -24,11 +24,16 @@ class ResultFragment : Fragment(R.layout.fragment_scan_result) {
private var _binding: FragmentScanResultBinding? = null
private val binding: FragmentScanResultBinding get() = _binding!!
private val viewModel: ResultViewModel 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?) {
@ -45,18 +50,24 @@ class ResultFragment : Fragment(R.layout.fragment_scan_result) {
successIcon.visibleOrGone(false)
close.setOnClickListener {
navigateToMainScreen()
navigateToResultScreen()
}
}
val qrData = QrScanDestination.getDataIfExist(arguments ?: Bundle())
authPreferences.getLogin()?.let { login ->
val currentTime = getCurrentTime()
viewModel.open(login, CodeJson(
value = qrData,
type = OpenType.QR_TYPE,
time = currentTime
))
val qrData = qrPreferences.getQr()
if (qrData != null) {
authPreferences.getLogin()?.let { login ->
val currentTime = getCurrentTime()
viewModel.open(login, CodeJson(
value = qrData.toString(),
type = OpenType.QR_TYPE,
time = currentTime
))
}
} else {
Log.e("ResultFragment", "QR data is null")
Toast.makeText(context, getString(R.string.error), Toast.LENGTH_SHORT).show()
}
}
@ -94,7 +105,7 @@ class ResultFragment : Fragment(R.layout.fragment_scan_result) {
}
}
private fun navigateToMainScreen() {
private fun navigateToResultScreen() {
try {
findNavController().apply {
popBackStack(MainDestination, false)

View File

@ -1,6 +1,7 @@
package ru.myitschool.work.ui.qr.scan
package ru.myitschool.work.ui.scan.qr
import android.os.Bundle
import android.util.Log
import androidx.core.os.bundleOf
import kotlinx.serialization.Serializable

View File

@ -1,7 +1,9 @@
package ru.myitschool.work.ui.qr.scan
package ru.myitschool.work.ui.scan.qr
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.core.ImageAnalysis
import androidx.camera.mlkit.vision.MlKitAnalyzer
@ -20,6 +22,9 @@ 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
import ru.myitschool.work.utils.visibleOrGone
@ -34,6 +39,14 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
) { isGranted -> viewModel.onPermissionResult(isGranted) }
private val viewModel: QrScanViewModel by viewModels()
private lateinit var qrPreferences: QrPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
qrPreferences = QrPreferences(requireContext())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -65,7 +78,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
}
is QrScanViewModel.Action.CloseWithResult -> {
sendResult(QrScanDestination.packToBundle(action.result))
goBack()
goResult()
}
}
}
@ -113,10 +126,31 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) {
}
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()
}
}
private fun sendResult(bundle: Bundle) {
setFragmentResult(
QrScanDestination.REQUEST_KEY,

View File

@ -1,4 +1,4 @@
package ru.myitschool.work.ui.qr.scan
package ru.myitschool.work.ui.scan.qr
import android.Manifest
import android.app.Application

View File

@ -0,0 +1,27 @@
package ru.myitschool.work.utils
import android.content.Context
import android.content.SharedPreferences
class QrPreferences(context: Context) {
private val sharedPreferences: SharedPreferences = context.getSharedPreferences(
PREFS_NAME,
Context.MODE_PRIVATE
)
fun saveQr(login: String) {
sharedPreferences.edit().apply {
putString("qr", login)
apply()
}
}
fun getQr(): String? {
return sharedPreferences.getString("qr", null)
}
companion object {
private const val PREFS_NAME = "ArPreferences"
}
}