Compare commits

..

No commits in common. "main" and "TheDevs-front_1.0" have entirely different histories.

22 changed files with 312 additions and 544 deletions

View File

@ -1,82 +0,0 @@
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-backups11164380389062662786
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

@ -1,82 +0,0 @@
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-backups8341820686666786180
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

@ -1,82 +0,0 @@
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-backups1146231745401124119
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

@ -1,9 +1,9 @@
plugins { plugins {
id("com.android.application") kotlinAndroid
id("kotlin-android") androidApplication
id("kotlin-kapt") // Добавлено для KAPT jetbrainsKotlinSerialization version Version.Kotlin.language
id("dagger.hilt.android.plugin") // Используйте этот синтаксис для Hilt kotlinAnnotationProcessor
id("org.jetbrains.kotlin.plugin.serialization") version Version.Kotlin.language // Убедитесь, что версия актуальна id("com.google.dagger.hilt.android").version("2.51.1")
} }
val packageName = "ru.myitschool.work" val packageName = "ru.myitschool.work"
@ -22,9 +22,9 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
buildFeatures { buildFeatures.viewBinding = true
viewBinding = true
}
compileOptions { compileOptions {
sourceCompatibility = Version.Kotlin.javaSource sourceCompatibility = Version.Kotlin.javaSource
@ -37,41 +37,38 @@ android {
} }
dependencies { dependencies {
// Retrofit and OkHttp
implementation ("com.squareup.retrofit2:retrofit:2.9.0") implementation ("com.squareup.retrofit2:retrofit:2.9.0")
implementation ("com.squareup.retrofit2:converter-gson:2.9.0") implementation ("com.squareup.retrofit2:converter-gson:2.9.0")
implementation ("com.squareup.okhttp3:okhttp:4.9.0") implementation ("com.squareup.okhttp3:okhttp:4.9.0")
// Glide
implementation ("com.github.bumptech.glide:glide:4.15.1") implementation ("com.github.bumptech.glide:glide:4.15.1")
kapt("com.github.bumptech.glide:compiler:4.15.1")
// AndroidX Libraries
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.10.0") implementation("com.google.android.material:material:1.10.0")
implementation("androidx.activity:activity:1.10.0") implementation("androidx.activity:activity:1.10.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1") kapt ("com.github.bumptech.glide:compiler:4.15.1")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
// Hilt dependencies defaultLibrary()
implementation("com.google.dagger:hilt-android:2.51.1")
kapt("com.google.dagger:hilt-android-compiler:2.51.1") implementation(Dependencies.AndroidX.activity)
implementation(Dependencies.AndroidX.fragment)
implementation(Dependencies.AndroidX.constraintLayout)
// Navigation
implementation(Dependencies.AndroidX.Navigation.fragment) implementation(Dependencies.AndroidX.Navigation.fragment)
implementation(Dependencies.AndroidX.Navigation.navigationUi) implementation(Dependencies.AndroidX.Navigation.navigationUi)
// DataStore implementation(Dependencies.Retrofit.library)
implementation("androidx.datastore:datastore-preferences:1.1.1") implementation(Dependencies.Retrofit.gsonConverter)
// ML Kit
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") implementation("com.google.mlkit:barcode-scanning:17.3.0")
// CameraX
val cameraX = "1.3.4" val cameraX = "1.3.4"
implementation("androidx.camera:camera-core:$cameraX") implementation("androidx.camera:camera-core:$cameraX")
implementation("androidx.camera:camera-camera2:$cameraX") implementation("androidx.camera:camera-camera2:$cameraX")
@ -79,11 +76,9 @@ dependencies {
implementation("androidx.camera:camera-view:$cameraX") implementation("androidx.camera:camera-view:$cameraX")
implementation("androidx.camera:camera-mlkit-vision:1.4.0-rc04") implementation("androidx.camera:camera-mlkit-vision:1.4.0-rc04")
// Picasso val hilt = "2.51.1"
implementation("com.squareup.picasso:picasso:2.8") implementation("com.google.dagger:hilt-android:$hilt")
kapt("com.google.dagger:hilt-android-compiler:$hilt")
// Kotlin Serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
} }
kapt { kapt {

View File

@ -33,7 +33,6 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>
</manifest> </manifest>

View File

@ -4,9 +4,4 @@ import android.app.Application
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp @HiltAndroidApp
class App : Application() { class App : Application()
override fun onCreate() {
super.onCreate()
SessionManager.init(this) // Инициализация SessionManager
}
}

View File

@ -1,39 +1,10 @@
package ru.myitschool.work package ru.myitschool.work
import android.content.Context
import android.content.SharedPreferences
import java.util.Base64
object SessionManager { object SessionManager {
private const val PREF_NAME = "user_session" var userLogin: String? = null // Логин пользователя
private const val KEY_USER_LOGIN = "user_login" var userRole: String? = null // Роль пользователя
private const val KEY_USER_ROLE = "user_role"
private lateinit var preferences: SharedPreferences
fun init(context: Context) {
preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
}
var userLogin: String?
get() = preferences.getString(KEY_USER_LOGIN, null)
set(value) {
preferences.edit().putString(KEY_USER_LOGIN, value).apply()
}
var userRole: String?
get() = preferences.getString(KEY_USER_ROLE, null)
set(value) {
preferences.edit().putString(KEY_USER_ROLE, value).apply()
}
fun getAuthHeader(): String {
val username = userLogin ?: return ""
val password = "password123" // Замените на ваш пароль
val credential = Base64.getEncoder().encodeToString("$username:$password".toByteArray())
return "Basic $credential"
}
// Метод для очистки данных сессии
fun clearSession() { fun clearSession() {
userLogin = null userLogin = null
userRole = null userRole = null

View File

@ -1,6 +1,5 @@
package ru.myitschool.work.api package ru.myitschool.work.api
import LoggingInterceptor
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -8,6 +7,7 @@ import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import ru.myitschool.work.core.Constants
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@ -16,26 +16,19 @@ object ApiModule {
@Provides @Provides
@Singleton @Singleton
fun provideOkHttpClient(authInterceptor: AuthInterceptor): OkHttpClient { fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(authInterceptor) // Добавляем интерсептор аутентификации
.addInterceptor(LoggingInterceptor()) // Добавляем интерсептор логирования
.build()
}
@Provides
@Singleton
fun provideAuthInterceptor(): AuthInterceptor {
val username = "pivanov" // Замените на ваш логин val username = "pivanov" // Замените на ваш логин
val password = "password123" // Замените на ваш пароль val password = "password123" // Замените на ваш пароль
return AuthInterceptor(username, password) return OkHttpClient.Builder()
.addInterceptor(AuthInterceptor(username, password))
.build()
} }
@Provides @Provides
@Singleton @Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit { fun provideRetrofit(client: OkHttpClient): Retrofit {
return Retrofit.Builder() return Retrofit.Builder()
.baseUrl("http://10.6.66.110:8080/") // Убедитесь, что URL корректен .baseUrl(Constants.SERVER_ADDRESS)
.client(client) .client(client)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()

View File

@ -3,7 +3,6 @@ package ru.myitschool.work.api
import retrofit2.Response import retrofit2.Response
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.PATCH import retrofit2.http.PATCH
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Path import retrofit2.http.Path
@ -11,26 +10,21 @@ import retrofit2.http.Query
interface ApiService { interface ApiService {
// Метод для аутентификации // Метод для аутентификации
@GET("/api/auth") @GET("/api/auth") // Используем GET для аутентификации
suspend fun authenticate( suspend fun authenticate(
@Query("login") login: String, @Query("login") login: String, // Передаем логин как параметр запроса
@Query("password") password: String @Query("password") password: String // Передаем пароль как параметр запроса
): Response<Unit> // Измените Response<String> на Response<Unit> ): Response<UserAuthResponse> // Возвращаем JSON как объект UserAuthResponse
@GET("/api/{login}/info") // Другие методы...
suspend fun getUserInfo( @GET("/api/{login}/info") // Получение информации о пользователе
@Path("login") login: String, suspend fun getUserInfo(@Path("login") login: String): Response<Map<String, Any>>
@Header("Authorization") authHeader: String
): Response<EmployeeData>
@GET("/api/employee/{login}") // Получение информации о сотруднике @GET("/api/employee/{login}") // Получение информации о сотруднике
suspend fun getEmployeeInfo(@Path("login") login: String): Response<EmployeeData> suspend fun getEmployeeInfo(@Path("login") login: String): Response<EmployeeData>
@PATCH("/api/open") // Открыть дверь @PATCH("/api/open") // Открыть дверь
suspend fun openDoor( suspend fun openDoor(@Body request: OpenDoorRequest): Response<String>
@Header("Authorization") authHeader: String,
@Body request: OpenDoorRequest
): Response<Unit> // Измените Response<String> на Response<Unit>
@POST("/api/employee/toggleAccess") // Метод для блокировки/разблокировки доступа @POST("/api/employee/toggleAccess") // Метод для блокировки/разблокировки доступа
suspend fun toggleAccess(@Body request: ToggleAccessRequest): Response<Unit> suspend fun toggleAccess(@Body request: ToggleAccessRequest): Response<Unit>
@ -39,12 +33,16 @@ interface ApiService {
suspend fun getAllWorkers(): Response<List<EmployeeData>> suspend fun getAllWorkers(): Response<List<EmployeeData>>
} }
// Модель данных для ответа аутентификации
data class UserAuthResponse(
val role: String // Добавляем поле для роли
)
// Модель данных для информации о сотруднике // Модель данных для информации о сотруднике
data class EmployeeData( data class EmployeeData(
val name: String, val name: String,
val position: String, val position: String,
val lastVisit: String, val lastVisit: String
val avatarUrl: String? // Добавьте это поле
) )
// Модель данных для запроса блокировки/разблокировки доступа // Модель данных для запроса блокировки/разблокировки доступа
@ -55,5 +53,6 @@ data class ToggleAccessRequest(
// Модель данных для запроса открытия двери // Модель данных для запроса открытия двери
data class OpenDoorRequest( data class OpenDoorRequest(
val login: String, // Логин сотрудника
val value: Long // Код для открытия двери val value: Long // Код для открытия двери
) )

View File

@ -1,15 +0,0 @@
import okhttp3.Interceptor
import okhttp3.Response
import android.util.Log
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
Log.d("LoggingInterceptor", "Sending request to ${request.url} with headers ${request.headers}")
val response = chain.proceed(request)
Log.d("LoggingInterceptor", "Received response for ${response.request.url} with code ${response.code}")
return response
}
}

View File

@ -2,5 +2,4 @@ package ru.myitschool.work.core
// БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ // БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ
object Constants { object Constants {
const val SERVER_ADDRESS = "http://10.6.66.110:8080" const val SERVER_ADDRESS = "http://10.6.66.110:8080"
//,
} }

View File

@ -1,4 +1,4 @@
package ru.myitschool.work.ui.main package ru.myitschool.work.ui.Main
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
@ -10,6 +10,7 @@ import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.api.ApiService import ru.myitschool.work.api.ApiService
import ru.myitschool.work.api.EmployeeData
import ru.myitschool.work.api.ToggleAccessRequest import ru.myitschool.work.api.ToggleAccessRequest
import ru.myitschool.work.core.Constants import ru.myitschool.work.core.Constants
import ru.myitschool.work.databinding.FragmentAdminBinding import ru.myitschool.work.databinding.FragmentAdminBinding
@ -25,7 +26,7 @@ class AdminFragment : Fragment(R.layout.fragment_admin) {
.build() .build()
.create(ApiService::class.java) .create(ApiService::class.java)
} }
//.
private var isAccessBlocked: Boolean = false // Переменная для отслеживания состояния доступа private var isAccessBlocked: Boolean = false // Переменная для отслеживания состояния доступа
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -34,7 +35,7 @@ class AdminFragment : Fragment(R.layout.fragment_admin) {
setupUI() setupUI()
} }
//.
private fun setupUI() { private fun setupUI() {
binding.viewEmployeeInfo.setOnClickListener { binding.viewEmployeeInfo.setOnClickListener {
val login = binding.employeeLogin.text.toString() val login = binding.employeeLogin.text.toString()

View File

@ -1,144 +1,201 @@
package ru.myitschool.work.ui.main package ru.myitschool.work.ui.main
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.squareup.picasso.Picasso import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.myitschool.work.R import kotlinx.coroutines.withContext
import ru.myitschool.work.api.ApiService
import ru.myitschool.work.api.EmployeeData
import ru.myitschool.work.core.Constants
import ru.myitschool.work.databinding.FragmentMainBinding
import ru.myitschool.work.SessionManager
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import ru.myitschool.work.R
import ru.myitschool.work.SessionManager
import ru.myitschool.work.api.AccessLog
import ru.myitschool.work.api.ApiService
import ru.myitschool.work.core.Constants
import ru.myitschool.work.databinding.FragmentMainBinding
import ru.myitschool.work.ui.qr.scan.QrScanDestination import ru.myitschool.work.ui.qr.scan.QrScanDestination
import java.net.HttpURLConnection
import java.net.URL
class MainFragment : Fragment(R.layout.fragment_main) { class MainFragment : Fragment(R.layout.fragment_main) {
private var _binding: FragmentMainBinding? = null private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var apiService: ApiService private val apiService: ApiService by lazy {
Retrofit.Builder()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
apiService = Retrofit.Builder()
.baseUrl(Constants.SERVER_ADDRESS) .baseUrl(Constants.SERVER_ADDRESS)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()
.create(ApiService::class.java) .create(ApiService::class.java)
} }
private lateinit var accessLogAdapter: AccessLogAdapter
private val accessLogs = mutableListOf<AccessLog>() // Список для хранения данных проходов
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
_binding = FragmentMainBinding.bind(view) _binding = FragmentMainBinding.bind(view) // Подключаем binding
setupUI() setupUI()
fetchUserInfo() fetchUserData()
checkAdminAccess() // Проверяем доступ администратора
// Проверяем, есть ли результат QR // Проверяем, есть ли результат QR
checkQrResult() checkQrResult()
} }
private fun checkAdminAccess() {
// Проверяем, является ли пользователь администратором
if (SessionManager.userRole == "admin") {
binding.adminPanel.visibility = View.VISIBLE // Показываем кнопку AdminPanel
binding.adminPanel.setOnClickListener {
findNavController().navigate(R.id.adminFragment) // Переход на экран администратора
}
} else {
binding.adminPanel.visibility = View.GONE // Скрываем кнопку для обычных пользователей
}
}
private fun checkQrResult() { private fun checkQrResult() {
// Слушаем результат QR сканирования // Слушаем результат QR сканирования
setFragmentResultListener(QrScanDestination.REQUEST_KEY) { _, bundle -> setFragmentResultListener(QrScanDestination.REQUEST_KEY) { _, bundle ->
val qrData = QrScanDestination.getDataIfExist(bundle) val qrData = QrScanDestination.getDataIfExist(bundle)
if (qrData != null) { if (qrData != null) {
// Если данные QR есть, переходим на экран с результатом // Если данные QR есть, переходим на экран с результатом
val resultBundle = QrScanDestination.packToBundle(qrData) findNavController().navigate(R.id.qrResultFragment)
findNavController().navigate(R.id.qrResultFragment, resultBundle)
} else {
Toast.makeText(requireContext(), "QR данные не найдены", Toast.LENGTH_SHORT).show()
} }
} }
} }
private fun setupUI() { private fun setupUI() {
binding.refresh.setOnClickListener { // Настройка RecyclerView
fetchUserInfo() binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
} accessLogAdapter = AccessLogAdapter(accessLogs)
binding.recyclerView.adapter = accessLogAdapter
binding.scanQrCode?.setOnClickListener { // Проверяем, что binding не null, прежде чем устанавливать слушателей
// Переход к экрану сканирования QR-кода binding.apply {
findNavController().navigate(R.id.qrScanFragment) // Убедитесь, что у вас есть правильный ID для навигации refresh.setOnClickListener { fetchUserData() }
} logout.setOnClickListener { logout() }
scan.setOnClickListener { navigateToQrScan() }
// Проверяем роль пользователя и показываем кнопку AdminPanel, если роль admin
if (SessionManager.userRole == "admin") {
binding.adminPanelButton?.visibility = View.VISIBLE
binding.adminPanelButton?.setOnClickListener {
findNavController().navigate(R.id.adminFragment) // Переход к экрану администратора
}
} else {
binding.adminPanelButton?.visibility = View.GONE // Скрываем кнопку, если не admin
} }
} }
private fun fetchUserInfo() { private fun fetchUserData() {
lifecycleScope.launch { lifecycleScope.launch {
val login = SessionManager.userLogin ?: run { showError(null) // Скрыть ошибку, если она была
binding.error.text = "Пользователь не авторизован"
binding.error.visibility = View.VISIBLE
return@launch
}
val authHeader = SessionManager.getAuthHeader() ?: run {
binding.error.text = "Ошибка авторизации"
binding.error.visibility = View.VISIBLE
return@launch
}
try { try {
val response = apiService.getUserInfo(login, authHeader) val response =
SessionManager.userLogin?.let { apiService.getUserInfo(it) } // Получаем данные пользователя
// Логируем код ответа if (response != null) {
Log.d("MainFragment", "Response code: ${response.code()}")
if (response.isSuccessful) { if (response.isSuccessful) {
val employeeData = response.body() response.body()?.let { data ->
employeeData?.let { // Извлекаем значения из Map
binding.fullname.text = it.name val fullName = data["name"] as? String ?: "Неизвестно"
binding.position.text = it.position val position = data["position"] as? String ?: "Неизвестно"
binding.lastEntry.text = it.lastVisit val lastVisit = data["lastVisit"] as? String ?: "Неизвестно"
val photoUrl = data["photo"] as? String ?: ""
// Логируем URL аватара // Обновляем UI
Log.d("MainFragment", "Avatar URL: ${it.avatarUrl}") updateUI(fullName, position, lastVisit, photoUrl)
// Загрузка аватара с помощью Picasso // Здесь вы можете добавить данные проходов в список
if (it.avatarUrl != null) { // Пример:
Picasso.get() accessLogs.add(AccessLog("2024-02-31 08:31", "Считыватель 1", "карта"))
.load(it.avatarUrl) accessLogAdapter.notifyDataSetChanged() // Обновляем адаптер
.placeholder(R.drawable.ic_refresh) // Замените на ваш ресурс-заполнитель
.error(R.drawable.ic_close) // Замените на ваш ресурс ошибки
.into(binding.photo)
binding.photo.visibility = View.VISIBLE
} else {
binding.photo.visibility = View.GONE // Скрыть, если URL нет
}
// Показываем кнопку "Сканировать QR-код" после успешного получения данных
binding.scanQrCode?.visibility = View.VISIBLE
} }
} else { } else {
binding.error.text = "Ошибка получения данных: ${response.message()}" showError(getString(R.string.error_loading_data)) // Показываем ошибку, если данные не загрузились
binding.error.visibility = View.VISIBLE }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e("MainFragment", "Error fetching user info", e) showError(e.localizedMessage) // Показываем ошибку при исключении
binding.error.text = "Ошибка сети: ${e.message}"
binding.error.visibility = View.VISIBLE
} }
} }
} }
private fun updateUI(fullName: String, position1: String, lastVisit: String, photoUrl: String) {
// Проверяем, что binding не null, прежде чем обновлять UI
binding?.apply {
fullname.text = fullName
position.text = position1
lastEntry.text = lastVisit
if (photoUrl.isNotEmpty()) {
// Загружаем изображение
lifecycleScope.launch {
val bitmap = loadImageFromUrl(photoUrl)
bitmap?.let { photo.setImageBitmap(it) }
}
}
// Показываем элементы
fullname.visibility = View.VISIBLE
position.visibility = View.VISIBLE
lastEntry.visibility = View.VISIBLE
photo.visibility = View.VISIBLE
logout.visibility = View.VISIBLE
scan.visibility = View.VISIBLE
}
}
private suspend fun loadImageFromUrl(urlString: String): Bitmap? {
return withContext(Dispatchers.IO) {
try {
val url = URL(urlString)
val connection = url.openConnection() as HttpURLConnection
connection.doInput = true
connection.connect()
val inputStream = connection.inputStream
BitmapFactory.decodeStream(inputStream)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}
private fun showError(message: String?) {
// Проверяем, что binding не null, прежде чем обновлять ошибку
binding.apply {
if (message != null) {
error.text = message
error.visibility = View.VISIBLE
// Скрываем остальные элементы, когда возникает ошибка
fullname.visibility = View.GONE
position.visibility = View.GONE
lastEntry.visibility = View.GONE
photo.visibility = View.GONE
logout.visibility = View.GONE
scan.visibility = View.GONE
recyclerView.visibility = View.GONE // Скрываем RecyclerView при ошибке
} else {
error.visibility = View.GONE
recyclerView.visibility = View.VISIBLE // Показываем RecyclerView, если ошибки нет
}
}
}
private fun logout() {
// Очистите данные пользователя
Toast.makeText(requireContext(), getString(R.string.logged_out), Toast.LENGTH_SHORT).show()
findNavController().navigate(R.id.loginFragment) // Переход на экран входа
}
private fun navigateToQrScan() {
findNavController().navigate(R.id.qrScanFragment) // Переход на экран сканирования QR
}
override fun onDestroyView() { override fun onDestroyView() {
_binding = null _binding = null // Освобождаем binding, когда представление уничтожается
super.onDestroyView() super.onDestroyView()
} }
} }

View File

@ -1,39 +1,47 @@
package ru.myitschool.work.ui.main package ru.myitschool.work.ui.main
import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.myitschool.work.SessionManager
import ru.myitschool.work.api.ApiService import ru.myitschool.work.api.ApiService
import ru.myitschool.work.api.EmployeeData
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class MainViewModel @Inject constructor( class MainViewModel @Inject constructor(
private val apiService: ApiService private val apiService: ApiService
) : ViewModel() { ) : ViewModel() {
private val _userInfoState = MutableStateFlow<Map<String, Any>?>(null)
val userInfoState: StateFlow<Map<String, Any>?> = _userInfoState
private val _employeeData = MutableStateFlow<EmployeeData?>(null) init {
val employeeData: StateFlow<EmployeeData?> get() = _employeeData loadUserData()
}
private val _errorMessage = MutableStateFlow<String?>(null) private fun loadUserData() {
val errorMessage: StateFlow<String?> get() = _errorMessage
fun fetchUserInfo(login: String, authHeader: String) {
viewModelScope.launch { viewModelScope.launch {
try { try {
val response = apiService.getUserInfo(login, authHeader) val login = SessionManager.userLogin
if (login != null) {
val response = apiService.getUserInfo(login)
if (response.isSuccessful) { if (response.isSuccessful) {
_employeeData.value = response.body() _userInfoState.value = response.body()
} else { } else {
_errorMessage.value = "Ошибка получения данных: ${response.message()}" // Обработка ошибки, если ответ не успешен
_userInfoState.value = null // Или установите какое-то состояние ошибки
}
} else {
// Логин равен null, обработайте это состояние
_userInfoState.value = null // Или установите какое-то состояние ошибки
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e("MainViewModel", "Error fetching user info", e) // Логирование ошибки
_errorMessage.value = "Ошибка сети: ${e.message}" e.printStackTrace()
// Установите состояние ошибки
_userInfoState.value = null // Или установите какое-то состояние ошибки
} }
} }
} }

View File

@ -1,6 +1,5 @@
package ru.myitschool.work.ui.login package ru.myitschool.work.ui.login
import ru.myitschool.work.api.ApiService
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.InputType import android.text.InputType
@ -16,6 +15,7 @@ import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.SessionManager import ru.myitschool.work.SessionManager
import ru.myitschool.work.api.UserAuthResponse
import ru.myitschool.work.databinding.FragmentLoginBinding import ru.myitschool.work.databinding.FragmentLoginBinding
import ru.myitschool.work.utils.collectWhenStarted import ru.myitschool.work.utils.collectWhenStarted
import ru.myitschool.work.utils.visibleOrGone import ru.myitschool.work.utils.visibleOrGone
@ -40,7 +40,7 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) // Убедитесь, что этот вызов находится здесь super.onViewCreated(view, savedInstanceState)
_binding = FragmentLoginBinding.bind(view) _binding = FragmentLoginBinding.bind(view)
setupUI() setupUI()
@ -96,6 +96,12 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
authPreferences.saveLoginState(true) authPreferences.saveLoginState(true)
authPreferences.saveLogin(binding.username.text.toString()) // Сохраняем логин authPreferences.saveLogin(binding.username.text.toString()) // Сохраняем логин
// Сохраняем роль пользователя в SessionManager
val userAuthResponse: UserAuthResponse? = state.userAuthResponse
userAuthResponse?.let {
SessionManager.userRole = it.role // Сохраняем роль
}
Toast.makeText(context, "Авторизация прошла успешно", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Авторизация прошла успешно", Toast.LENGTH_SHORT).show()
navigateToMainScreen() // Перенаправление на следующий экран navigateToMainScreen() // Перенаправление на следующий экран
} else if (state.error != null) { } else if (state.error != null) {

View File

@ -1,6 +1,5 @@
package ru.myitschool.work.ui.login package ru.myitschool.work.ui.login
import ru.myitschool.work.api.ApiService
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@ -9,6 +8,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.myitschool.work.SessionManager import ru.myitschool.work.SessionManager
import ru.myitschool.work.api.ApiService
import ru.myitschool.work.api.UserAuthResponse
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -20,40 +21,34 @@ class LoginViewModel @Inject constructor(
val state: StateFlow<LoginState> get() = _state val state: StateFlow<LoginState> get() = _state
fun authenticate(username: String, password: String) { fun authenticate(username: String, password: String) {
Log.d("LoginViewModel", "Authenticating user: $username") // Логируем начало аутентификации
if (isValidUsername(username)) { if (isValidUsername(username)) {
viewModelScope.launch { viewModelScope.launch {
try { try {
Log.d("LoginViewModel", "Sending authentication request to server") // Логируем отправку запроса
val response = apiService.authenticate(username, password) val response = apiService.authenticate(username, password)
Log.d("LoginViewModel", "Response code: ${response.code()}") // Логируем код ответа Log.d("LoginViewModel", "Response code: ${response.code()}")
// Проверяем код ответа if (response.isSuccessful) {
when (response.code()) { val userAuthResponse = response.body() // Получаем JSON-ответ
200 -> { Log.d("LoginViewModel", "User Auth Response: $userAuthResponse") // Логируем ответ
// Обработка JSON-ответа
if (userAuthResponse != null) {
SessionManager.userLogin = username SessionManager.userLogin = username
SessionManager.userRole = userAuthResponse.role // Сохраняем роль
_state.value = LoginState(success = true) // Успешная авторизация _state.value = LoginState(success = true) // Успешная авторизация
Log.d("LoginViewModel", "Authentication successful") // Логируем успешную аутентификацию } else {
}
400 -> {
_state.value = LoginState(error = "Ошибка авторизации: Неверные учетные данные.") _state.value = LoginState(error = "Ошибка авторизации: Неверные учетные данные.")
Log.d("LoginViewModel", "Authentication failed: Invalid credentials") // Логируем ошибку
} }
else -> { } else {
_state.value = LoginState(error = "Ошибка авторизации: ${response.message()}") _state.value = LoginState(error = "Ошибка авторизации: ${response.message()}")
Log.d("LoginViewModel", "Authentication failed: ${response.message()}") // Логируем ошибку
}
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
_state.value = LoginState(error = "Ошибка сети. Проверьте подключение к интернету.") _state.value = LoginState(error = "Ошибка сети. Проверьте подключение к интернету.")
Log.e("LoginViewModel", "Network error: ${e.message}") // Логируем ошибку сети
} }
} }
} else { } else {
_state.value = LoginState(error = "Неправильный логин") _state.value = LoginState(error = "Неправильный логин")
Log.d("LoginViewModel", "Invalid username: $username") // Логируем неправильный логин
} }
} }
@ -65,6 +60,7 @@ class LoginViewModel @Inject constructor(
// Состояние аутентификации // Состояние аутентификации
data class LoginState( data class LoginState(
val success: Boolean = false, // Успешность аутентификации val success: Boolean = false, // Успешность аутентификации
val userAuthResponse: UserAuthResponse? = null, // Ответ с информацией о пользователе
val error: String? = null, // Сообщение об ошибке val error: String? = null, // Сообщение об ошибке
val maintenance: Boolean = false // Состояние техобслуживания val maintenance: Boolean = false // Состояние техобслуживания
) )

View File

@ -5,10 +5,8 @@ import androidx.navigation.fragment.findNavController
import ru.myitschool.work.SessionManager import ru.myitschool.work.SessionManager
import ru.myitschool.work.api.OpenDoorRequest import ru.myitschool.work.api.OpenDoorRequest
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.util.Base64
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -21,9 +19,7 @@ import ru.myitschool.work.core.Constants
import ru.myitschool.work.databinding.FragmentQrScanResultBinding import ru.myitschool.work.databinding.FragmentQrScanResultBinding
class QrResult : Fragment(R.layout.fragment_qr_scan_result) { class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
private var _binding: FragmentQrScanResultBinding? = null private lateinit var binding: FragmentQrScanResultBinding
private val binding get() = _binding!!
private lateinit var apiService: ApiService private lateinit var apiService: ApiService
override fun onCreateView( override fun onCreateView(
@ -31,7 +27,7 @@ class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
_binding = FragmentQrScanResultBinding.inflate(inflater, container, false) binding = FragmentQrScanResultBinding.inflate(inflater, container, false)
apiService = Retrofit.Builder() apiService = Retrofit.Builder()
.baseUrl(Constants.SERVER_ADDRESS) .baseUrl(Constants.SERVER_ADDRESS)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
@ -44,12 +40,8 @@ class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// Получаем данные из аргументов
val qrData = QrScanDestination.getDataIfExist(requireArguments()) val qrData = QrScanDestination.getDataIfExist(requireArguments())
Log.d("QrResult", "QR Data: $qrData") // Логируем полученные данные
if (qrData != null) { if (qrData != null) {
binding.result.text = "Результат сканирования: $qrData" // Отображаем результат сканирования
sendRequestToServer(qrData) sendRequestToServer(qrData)
} else { } else {
binding.result.text = "Вход был отменён/Operation was cancelled" binding.result.text = "Вход был отменён/Operation was cancelled"
@ -63,40 +55,23 @@ class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
private fun sendRequestToServer(qrData: String) { private fun sendRequestToServer(qrData: String) {
lifecycleScope.launch { lifecycleScope.launch {
try { try {
val qrValue = qrData.toLong() // Преобразуем данные QR-кода в Long // Проверяем, что userLogin не равен null
val login = SessionManager.userLogin ?: "default_login" // Замените на ваш логин val login = SessionManager.userLogin
val password = "your_password" // Замените на ваш пароль if (login != null) {
val authHeader = "Basic " + Base64.encodeToString("$login:$password".toByteArray(), Base64.NO_WRAP) // Создаем объект OpenDoorRequest с логином и кодом
val openDoorRequest = OpenDoorRequest(login, qrData.toLong()) // Преобразуем qrData в Long, если это необходимо
// Логируем данные перед отправкой val response = apiService.openDoor(openDoorRequest) // Теперь передаем только openDoorRequest
Log.d("QrResult", "Sending request with QR value: $qrValue and authHeader: $authHeader")
// Создаем объект запроса
val request = OpenDoorRequest(qrValue)
// Вызываем метод openDoor с правильными параметрами
val response = apiService.openDoor(authHeader, request)
// Логируем код ответа и тело ответа
Log.d("QrResult", "Response code: ${response.code()}")
Log.d("QrResult", "Response body: ${response.body()}")
if (response.isSuccessful) { if (response.isSuccessful) {
binding.result.text = "Door Opened" // Сообщение о том, что дверь открыта binding.result.text = "Успешно/Success"
} else { } else {
binding.result.text = "Door Closed" // Сообщение о том, что дверь закрыта binding.result.text = "Что-то пошло не так/Something wrong"
}
} else {
binding.result.text = "Пользователь не авторизован/Unauthorized user"
} }
} catch (e: NumberFormatException) {
binding.result.text = "Некорректные данные QR-кода"
} catch (e: Exception) { } catch (e: Exception) {
binding.result.text = "Что-то пошло не так/Something went wrong: ${e.message}" binding.result.text = "Что-то пошло не так/Something wrong"
Log.e("QrResult", "Error sending request to server", e)
} }
} }
} }
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
} }

View File

@ -3,76 +3,108 @@
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:gravity="bottom"
android:padding="16dp"
android:background="@android:color/white">
<!-- Поле для ФИО -->
<TextView <TextView
android:id="@+id/fullname" android:id="@+id/fullname"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="18sp" /> android:text="@string/fullname_label"
android:textSize="18sp"
android:layout_marginBottom="5dp"
android:visibility="gone" />
<!-- Фото пользователя. -->
<ImageView <ImageView
android:id="@+id/photo" android:id="@+id/photo"
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_gravity="center" android:layout_gravity="center"
android:contentDescription="@string/photo_description" /> android:contentDescription="@string/photo_description"
android:layout_marginBottom="5dp"
android:visibility="gone" />
<!-- Поле для должности -->
<TextView <TextView
android:id="@+id/position" android:id="@+id/position"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="16sp" /> android:text="@string/position_label"
android:layout_marginBottom="5dp"
android:visibility="gone" />
<!-- Поле для даты последнего входа -->
<TextView <TextView
android:id="@+id/lastEntry" android:id="@+id/lastEntry"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" /> android:text="2024-02-31 08:31"
android:layout_marginBottom="75dp"
android:visibility="gone" />
<!-- Кнопка обновления -->
<Button <Button
android:id="@+id/refresh" android:id="@+id/refresh"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/refresh"
app:cornerRadius="16dp"
android:backgroundTint="@color/colorPrimary" android:backgroundTint="@color/colorPrimary"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:padding="12dp" android:layout_marginBottom="12dp"
app:cornerRadius="16dp" android:padding="12dp"/>
android:text="@string/refresh" />
<!-- Поле ошибки -->
<TextView <TextView
android:id="@+id/error" android:id="@+id/error"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/error_placeholder"
android:textColor="@android:color/holo_red_dark" android:textColor="@android:color/holo_red_dark"
android:visibility="gone" /> android:visibility="gone" />
<!-- RecyclerView для списка проходов -->
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_weight="1"
android:visibility="gone" />
<!-- Кнопки -->
<Button <Button
android:id="@+id/scan_qr_code" android:id="@+id/scan"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/scan_qr_code"
android:layout_marginBottom="12dp"
android:backgroundTint="@color/colorPrimary" android:backgroundTint="@color/colorPrimary"
android:textColor="@android:color/white"
android:padding="12dp"
app:cornerRadius="16dp" app:cornerRadius="16dp"
android:text="Сканировать QR-код" android:textColor="@android:color/white"
android:visibility="gone" /> android:visibility="gone" />
<Button <Button
android:id="@+id/adminPanelButton" android:id="@+id/logout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/logout"
android:layout_marginBottom="50dp"
app:cornerRadius="16dp"
android:backgroundTint="@color/colorPrimary" android:backgroundTint="@color/colorPrimary"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:padding="12dp" android:visibility="gone" />
<Button
android:id="@+id/admin_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/admin_panel"
app:cornerRadius="16dp" app:cornerRadius="16dp"
android:text="Admin Panel" android:backgroundTint="@color/colorPrimary"
android:layout_marginTop="16dp"
android:visibility="gone" /> android:visibility="gone" />
</LinearLayout> </LinearLayout>

View File

@ -27,4 +27,5 @@
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:padding="12dp" android:padding="12dp"
android:layout_marginTop="24dp" /> android:layout_marginTop="24dp" />
</LinearLayout> </LinearLayout>

View File

@ -1,4 +1,3 @@
<?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:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -9,17 +8,20 @@
android:id="@+id/scan_time" android:id="@+id/scan_time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" /> android:text="Время сканирования"
android:textSize="16sp" />
<TextView <TextView
android:id="@+id/reader_id" android:id="@+id/reader_id"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" /> android:text="Идентификатор считывателя"
android:textSize="16sp" />
<TextView <TextView
android:id="@+id/access_type" android:id="@+id/access_type"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" /> android:text="Тип прохода"
android:textSize="16sp" />
</LinearLayout> </LinearLayout>

View File

@ -24,7 +24,7 @@
<fragment <fragment
android:id="@+id/adminFragment" android:id="@+id/adminFragment"
android:name="ru.myitschool.work.ui.main.AdminFragment" android:name="ru.myitschool.work.ui.admin.AdminFragment"
android:label="Admin Fragment" android:label="Admin Fragment"
tools:layout="@layout/fragment_admin" /> tools:layout="@layout/fragment_admin" />