Compare commits
1 Commits
main
...
Frontend_E
Author | SHA1 | Date | |
---|---|---|---|
94245f656c |
@ -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-backups14802231755905846813
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
122
README.md
122
README.md
@ -1 +1,121 @@
|
||||
Figma: https://www.figma.com/design/v9YlfUjxz6ChHS5mNWSQPN/TheDevs_Final?node-id=2-3&t=Hnk1mGCVo7joisAC-1
|
||||
[](https://sicampus.ru/gitea/core/docs/src/branch/main/how-upload-project.md)
|
||||
|
||||
# НТО 2024. II отборочный этап. Командные задани — клиентская часть
|
||||
|
||||
## 📖 Предыстория
|
||||
В компании S контроль доступа в офис осуществляется с помощью СКУД (системы контроля управления доступом). На данный момент у каждого сотрудника компании есть карта-пропуск с NFC меткой. А у каждой входной двери есть считыватель с обеих сторон. При поднесении карты к считывателю, дверь открывается, а информация о времени входа или выхода сотрудника фиксируется в базе данных.
|
||||
Администрации компании S требуется мобильное приложение, как для рядовых сотрудников, так и для администрации с возможностью просмотра посещений и работой электронного пропуска как временной замены обычного (при помощи сканировании QR кода, который находится на считывателе). Поскольку в приложении есть возможность использовать телефон как пропуск - то к данному приложению повышенные требования к безопасности всех данных, находящихся внутри него.
|
||||
|
||||
|
||||
|
||||
## 📋 Системные требования
|
||||
|
||||
| **Параметр** | **Требование** |
|
||||
|-----------------------------|---------------------------------------|
|
||||
| **Минимальная версия Android** | 9.0 (API 28) |
|
||||
| **Целевая версия Android** | 14 (API 34) |
|
||||
| **Поддерживаемые устройства** | смартфоны, планшеты |
|
||||
| **Ориентация экранов** | портретная |
|
||||
| **Языки** | русский, английский |
|
||||
| **Разрешения** | доступ к интернету, камера (при необходимости) |
|
||||
|
||||
|
||||
|
||||
## 📱 Техническое задание
|
||||
Требуется разработать нативное мобильное приложение, которое будет содержать следующие экраны.
|
||||
|
||||
|
||||
### 1. Экран авторизации
|
||||
|
||||
> Данный экран должен быть показан при первом входе в приложение, а также в ситуациях, когда пользователь не зарегистрировался в приложении.
|
||||
|
||||
#### Элементы, которые должны присутствовать на экране:
|
||||
- Поле ввода (`id/username`), в котором пользователю необходимо ввести свой логин.
|
||||
- Кнопка входа (`id/login`), по нажатию на которую пользователь авторизуется в системе.
|
||||
- По умолчанию скрытое (`GONE`) текстовое поле с ошибкой (`id/error`).
|
||||
|
||||
#### Требования к компонентам:
|
||||
1. В пустом поле ввода должна отображаться подсказка, что требуется ввести пользователю.
|
||||
2. Если хотя бы одно из условий ниже соблюдено - кнопка должна быть неактивной:
|
||||
- Поле ввода пустое.
|
||||
- Количество символов менее 3х.
|
||||
- Логин начинается с цифры.
|
||||
- Логин содержит символы, отличные от латинского алфавита и цифр.
|
||||
3. Поле ввода и кнопку должно быть видно при раскрытии клавиатуры.
|
||||
4. - При нажатии на кнопку входа необходимо проверить, что данный пользователь существует с помощью запроса `api/<LOGIN>/auth` (подробное описание представлено в техническом задании серверной части).
|
||||
5. В случае отсутствия логина или любой другой неполадки - необходимо вывести ошибку, пока пользователь не изменит текстовое поле или повторно не нажмёт на кнопку.
|
||||
6. После нажатия на кнопку - логин должен быть сохранён и при следующем открытии приложения экран авторизации не должен быть показан.
|
||||
7. После нажатия на кнопку - при нажатии стрелки назад - экран авторизации не должен быть показан повторно.
|
||||
8. Экран авторизации показывается только в случае, если пользователь неавторизован.
|
||||
|
||||
|
||||
|
||||
|
||||
### 2. Главный экран
|
||||
|
||||
> Данный экран содержит общую информацию о пользователе:
|
||||
>- ФИО
|
||||
>- Фото
|
||||
>- Должность
|
||||
>- Время последнего входа
|
||||
|
||||
#### Элементы, которые должны присутствовать на экране:
|
||||
- Текстовое поле (`id/fullname`), в котором написано имя пользователя.
|
||||
- Изображение (`id/photo`), на котором отображено фото пользователя.
|
||||
- Текстовое поле (`id/position`), в котором написана должность пользователя.
|
||||
- Текстовое поле (`id/lastEntry`), в котором написана дата и время последнего входа пользователя.
|
||||
- Кнопка (`id/logout`) для выхода пользователя из аккаунта.
|
||||
- Кнопка (`id/refresh`) для обновления данных.
|
||||
- Кнопка (`id/scan`) для сканирования QR кода.
|
||||
- По умолчанию скрытое текстовое поле с ошибкой (`id/error`).
|
||||
|
||||
#### Требования к компонентам:
|
||||
- В случае любой ошибки необходимо скрыть все элементы, кроме текстового поля с ошибкой и кнопки обновления данных.
|
||||
- Для получения данных необходимо использовать сетевой запрос `/api/<LOGIN>/info`.
|
||||
- Формат даты и времени последнего входа пользователя: `yyyy-MM-dd HH:mm` (например: 2024-02-31 08:31). Время необходимо отображать с сервера, без поправок на часовой пояс или локальное смещение.
|
||||
- При нажатии на кнопку выход все данные (если есть) пользователя должны быть очищены, а приложение должно открыть экран авторизации.
|
||||
- При нажатии кнопки сканирования необходимо открыть экран сканирования QR кода.
|
||||
- При нажатии на кнопку обновления данных - необходимо повторно вызывать сетевой запрос для получения актуальных данных.
|
||||
|
||||
|
||||
|
||||
### 3. Экран сканирования QR-кода
|
||||
|
||||
> Данный экран позволяет отсканировать код на турникете и войти с помощью смартфона. В данном случае данный экран будет уже написан и представлен dам в готовом виде в заготовке. Вам необходимо только подписаться на его результат с помощью **Result API** и обработать считанные данные из QR кода. **Данный экран нельзя модифицировать. Он поставляется как есть.**
|
||||
|
||||
|
||||
|
||||
### 4. Экран с результатом сканирования QR кода
|
||||
|
||||
> На данном экране необходимо вывести успешность или неуспешность входа с помощью метода QR кода.
|
||||
|
||||
#### Элементы, которые должны присутствовать на экране:
|
||||
- Текстовое поле (`id/result`), где содержится текст об успешности или неуспешности входа.
|
||||
- Кнопка (`id/close`) для закрытия данного экрана.
|
||||
|
||||
#### Требования к компонентам:
|
||||
- В случае, если результат пришёл пустым или со статусом “Отмена” - необходимо вывести пользователю текст:
|
||||
*"Вход был отменён/Operation was cancelled"*
|
||||
- В случае, если данные пришли, то необходимо их отправить на сервер с запросом `api/<LOGIN>/open`, добавив данные из результата и получить ответ.
|
||||
- Если сервер ответил успешно - то отображаем текст:
|
||||
*"Успешно/Success"*
|
||||
- Если сервер ответил любой ошибкой - то отображаем текст:
|
||||
*"Что-то пошло не так/Something wrong"*
|
||||
- Кнопка закрытия всегда открывает главный экран.
|
||||
|
||||
|
||||
|
||||
## 🛠 Решение
|
||||
|
||||
Необходимо загрузить свое решение в систему [по ссылке](https://innovationcampus.ru/lms/mod/quiz/view.php?id=2149).
|
||||
|
||||
Отметим, что работу необходимо осуществлять в представленных проектах-заготовках (шаблонах).
|
||||
|
||||
|
||||
|
||||
## ✅ Особенности оценивания
|
||||
|
||||
Оценивание происходит с помощью автоматической системы тестирования, которая в автоматическом режиме находит элементы и взаимодействует с ними (именно для этого у каждого элемента указан уникальный идентификатор, по которому будет производится поиск). Каждый тест происходит с чистой установки приложения.
|
||||
В случае тестирования сервера на него поочередно отправляются команды, описанные в API и ожидаются определенные корректные ответы.
|
||||
Сервер и приложение тестируются независимо.
|
||||
|
||||
|
@ -1,30 +1,30 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("kotlin-kapt") // Добавлено для KAPT
|
||||
id("dagger.hilt.android.plugin") // Используйте этот синтаксис для Hilt
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version Version.Kotlin.language // Убедитесь, что версия актуальна
|
||||
kotlinAndroid
|
||||
androidApplication
|
||||
jetbrainsKotlinSerialization version Version.Kotlin.language
|
||||
kotlinAnnotationProcessor
|
||||
id("com.google.dagger.hilt.android").version("2.51.1")
|
||||
}
|
||||
|
||||
val packageName = "ru.myitschool.work"
|
||||
|
||||
android {
|
||||
namespace = packageName
|
||||
compileSdk = 35 // Обновлено до 35
|
||||
compileSdk = Version.Android.Sdk.compile
|
||||
|
||||
defaultConfig {
|
||||
applicationId = packageName
|
||||
minSdk = Version.Android.Sdk.min
|
||||
targetSdk = 35 // Обновлено до 35
|
||||
targetSdk = Version.Android.Sdk.target
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
buildFeatures.viewBinding = true
|
||||
|
||||
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = Version.Kotlin.javaSource
|
||||
@ -37,41 +37,30 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Retrofit and OkHttp
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.9.0")
|
||||
implementation ("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation ("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||
implementation ("com.squareup.okhttp3:okhttp:4.9.0")
|
||||
implementation ("com.github.bumptech.glide:glide:4.15.1")
|
||||
kapt ("com.github.bumptech.glide:compiler:4.15.1")
|
||||
|
||||
// Glide
|
||||
implementation("com.github.bumptech.glide:glide:4.15.1")
|
||||
kapt("com.github.bumptech.glide:compiler:4.15.1")
|
||||
defaultLibrary()
|
||||
|
||||
// AndroidX Libraries
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.10.0")
|
||||
implementation("androidx.activity:activity:1.10.0")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
|
||||
implementation(Dependencies.AndroidX.activity)
|
||||
implementation(Dependencies.AndroidX.fragment)
|
||||
implementation(Dependencies.AndroidX.constraintLayout)
|
||||
|
||||
// Coroutines
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
||||
|
||||
// Hilt dependencies
|
||||
implementation("com.google.dagger:hilt-android:2.51.1")
|
||||
kapt("com.google.dagger:hilt-android-compiler:2.51.1")
|
||||
|
||||
// Navigation
|
||||
implementation(Dependencies.AndroidX.Navigation.fragment)
|
||||
implementation(Dependencies.AndroidX.Navigation.navigationUi)
|
||||
|
||||
// DataStore
|
||||
implementation("androidx.datastore:datastore-preferences:1.1.1")
|
||||
implementation(Dependencies.Retrofit.library)
|
||||
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")
|
||||
|
||||
// CameraX
|
||||
val cameraX = "1.3.4"
|
||||
implementation("androidx.camera:camera-core:$cameraX")
|
||||
implementation("androidx.camera:camera-camera2:$cameraX")
|
||||
@ -79,13 +68,11 @@ dependencies {
|
||||
implementation("androidx.camera:camera-view:$cameraX")
|
||||
implementation("androidx.camera:camera-mlkit-vision:1.4.0-rc04")
|
||||
|
||||
// Picasso
|
||||
implementation("com.squareup.picasso:picasso:2.8")
|
||||
|
||||
// Kotlin Serialization
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
|
||||
val hilt = "2.51.1"
|
||||
implementation("com.google.dagger:hilt-android:$hilt")
|
||||
kapt("com.google.dagger:hilt-android-compiler:$hilt")
|
||||
}
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Default"
|
||||
tools:targetApi="34">
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".ui.RootActivity"
|
||||
android:exported="true">
|
||||
@ -33,7 +33,6 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -4,9 +4,4 @@ import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class App : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
SessionManager.init(this) // Инициализация SessionManager
|
||||
}
|
||||
}
|
||||
class App : Application()
|
@ -1,41 +1,5 @@
|
||||
package ru.myitschool.work
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import java.util.Base64
|
||||
|
||||
object SessionManager {
|
||||
private const val PREF_NAME = "user_session"
|
||||
private const val KEY_USER_LOGIN = "user_login"
|
||||
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() {
|
||||
userLogin = null
|
||||
userRole = null
|
||||
}
|
||||
var userLogin: String = ""
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package ru.myitschool.work.api
|
||||
|
||||
data class AccessLog(
|
||||
val scanTime: String,
|
||||
val readerId: String,
|
||||
val accessType: String // "карта" или "смартфон"
|
||||
)
|
@ -1,13 +1,13 @@
|
||||
package ru.myitschool.work.api
|
||||
|
||||
import LoggingInterceptor
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import ru.myitschool.work.api.ApiService
|
||||
import ru.myitschool.work.core.Constants
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@ -16,27 +16,9 @@ object ApiModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(authInterceptor: AuthInterceptor): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.addInterceptor(authInterceptor) // Добавляем интерсептор аутентификации
|
||||
.addInterceptor(LoggingInterceptor()) // Добавляем интерсептор логирования
|
||||
.build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthInterceptor(): AuthInterceptor {
|
||||
val username = "pivanov" // Замените на ваш логин
|
||||
val password = "password123" // Замените на ваш пароль
|
||||
return AuthInterceptor(username, password)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRetrofit(client: OkHttpClient): Retrofit {
|
||||
fun provideRetrofit(): Retrofit {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl("http://10.6.66.110:8080/") // Убедитесь, что URL корректен
|
||||
.client(client)
|
||||
.baseUrl(Constants.SERVER_ADDRESS)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
}
|
||||
|
@ -3,57 +3,18 @@ package ru.myitschool.work.api
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.PATCH
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface ApiService {
|
||||
// Метод для аутентификации
|
||||
@GET("/api/auth")
|
||||
suspend fun authenticate(
|
||||
@Query("login") login: String,
|
||||
@Query("password") password: String
|
||||
): Response<Unit> // Измените Response<String> на Response<Unit>
|
||||
@GET("api/{login}/auth")
|
||||
suspend fun authenticate(@Path("login") login: String): Response<Unit>
|
||||
|
||||
@GET("/api/{login}/info")
|
||||
suspend fun getUserInfo(
|
||||
@Path("login") login: String,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Response<EmployeeData>
|
||||
@GET("api/{login}/info")
|
||||
suspend fun getUserInfo(@Path("login") login: String): Response<Map<String, Any>> // Возвращаем Map вместо UserInfo
|
||||
|
||||
@GET("/api/employee/{login}") // Получение информации о сотруднике
|
||||
suspend fun getEmployeeInfo(@Path("login") login: String): Response<EmployeeData>
|
||||
|
||||
@PATCH("/api/open") // Открыть дверь
|
||||
suspend fun openDoor(
|
||||
@Header("Authorization") authHeader: String,
|
||||
@Body request: OpenDoorRequest
|
||||
): Response<Unit> // Измените Response<String> на Response<Unit>
|
||||
|
||||
@POST("/api/employee/toggleAccess") // Метод для блокировки/разблокировки доступа
|
||||
suspend fun toggleAccess(@Body request: ToggleAccessRequest): Response<Unit>
|
||||
|
||||
@GET("/api/workers") // Получить всех сотрудников
|
||||
suspend fun getAllWorkers(): Response<List<EmployeeData>>
|
||||
@PATCH("api/{login}/open")
|
||||
suspend fun openDoor(@Path("login") login: String, @Body body: OpenDoorRequest): Response<Unit>
|
||||
}
|
||||
|
||||
// Модель данных для информации о сотруднике
|
||||
data class EmployeeData(
|
||||
val name: String,
|
||||
val position: String,
|
||||
val lastVisit: String,
|
||||
val avatarUrl: String? // Добавьте это поле
|
||||
)
|
||||
|
||||
// Модель данных для запроса блокировки/разблокировки доступа
|
||||
data class ToggleAccessRequest(
|
||||
val login: String, // Логин сотрудника
|
||||
val action: String // Действие: "block" или "unblock"
|
||||
)
|
||||
|
||||
// Модель данных для запроса открытия двери
|
||||
data class OpenDoorRequest(
|
||||
val value: Long // Код для открытия двери
|
||||
)
|
||||
data class OpenDoorRequest(val value: String)
|
@ -1,16 +0,0 @@
|
||||
package ru.myitschool.work.api
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.util.Base64
|
||||
|
||||
class AuthInterceptor(private val username: String, private val password: String) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val originalRequest = chain.request()
|
||||
val credential = Base64.getEncoder().encodeToString("$username:$password".toByteArray())
|
||||
val newRequest = originalRequest.newBuilder()
|
||||
.addHeader("Authorization", "Basic $credential")
|
||||
.build()
|
||||
return chain.proceed(newRequest)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package ru.myitschool.work.core
|
||||
// БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ
|
||||
object Constants {
|
||||
const val SERVER_ADDRESS = "http://10.6.66.110:8080"
|
||||
//,
|
||||
const val SERVER_ADDRESS = "const val SERVER_ADDRESS = \"http://localhost:8090\"\n"
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package ru.myitschool.work.ui.main
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.api.AccessLog
|
||||
|
||||
class AccessLogAdapter(private val accessLogs: List<AccessLog>) : RecyclerView.Adapter<AccessLogAdapter.AccessLogViewHolder>() {
|
||||
|
||||
class AccessLogViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val scanTime: TextView = itemView.findViewById(R.id.scan_time)
|
||||
val readerId: TextView = itemView.findViewById(R.id.reader_id)
|
||||
val accessType: TextView = itemView.findViewById(R.id.access_type)
|
||||
}
|
||||
//.
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccessLogViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_access_log, parent, false)
|
||||
return AccessLogViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AccessLogViewHolder, position: Int) {
|
||||
val log = accessLogs[position]
|
||||
holder.scanTime.text = log.scanTime
|
||||
holder.readerId.text = log.readerId
|
||||
holder.accessType.text = log.accessType
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return accessLogs.size
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package ru.myitschool.work.ui.main
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.api.ApiService
|
||||
import ru.myitschool.work.api.ToggleAccessRequest
|
||||
import ru.myitschool.work.core.Constants
|
||||
import ru.myitschool.work.databinding.FragmentAdminBinding
|
||||
|
||||
class AdminFragment : Fragment(R.layout.fragment_admin) {
|
||||
private var _binding: FragmentAdminBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val apiService: ApiService by lazy {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(Constants.SERVER_ADDRESS)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(ApiService::class.java)
|
||||
}
|
||||
|
||||
private var isAccessBlocked: Boolean = false // Переменная для отслеживания состояния доступа
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentAdminBinding.bind(view)
|
||||
|
||||
setupUI()
|
||||
}
|
||||
//.
|
||||
private fun setupUI() {
|
||||
binding.viewEmployeeInfo.setOnClickListener {
|
||||
val login = binding.employeeLogin.text.toString()
|
||||
if (login.isNotEmpty()) {
|
||||
fetchEmployeeInfo(login)
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Введите логин сотрудника", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
binding.toggleAccess.setOnClickListener {
|
||||
val login = binding.employeeLogin.text.toString()
|
||||
if (login.isNotEmpty()) {
|
||||
// Определяем действие на основе текущего состояния доступа
|
||||
val action = if (isAccessBlocked) "unblock" else "block"
|
||||
toggleEmployeeAccess(login, action)
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Введите логин сотрудника", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchEmployeeInfo(login: String) {
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val response = apiService.getEmployeeInfo(login)
|
||||
if (response.isSuccessful) {
|
||||
val employeeData = response.body()
|
||||
employeeData?.let {
|
||||
binding.employeeInfo.text = "Имя: ${it.name}, Должность: ${it.position}, Последний визит: ${it.lastVisit}"
|
||||
binding.employeeInfo.visibility = View.VISIBLE
|
||||
binding.toggleAccess.visibility = View.VISIBLE
|
||||
// Здесь можно установить состояние доступа, если оно доступно
|
||||
isAccessBlocked = false // Предположим, что доступ не заблокирован по умолчанию
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Ошибка получения данных", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(requireContext(), "Ошибка сети", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleEmployeeAccess(login: String, action: String) {
|
||||
val request = ToggleAccessRequest(login, action)
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val response = apiService.toggleAccess(request)
|
||||
if (response.isSuccessful) {
|
||||
isAccessBlocked = !isAccessBlocked // Переключаем состояние доступа
|
||||
val message = if (action == "block") "Доступ заблокирован" else "Доступ разблокирован"
|
||||
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Ошибка изменения доступа", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(requireContext(), "Ошибка сети", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
_binding = null // Освобождаем binding, когда представление уничтожается
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -1,34 +1,34 @@
|
||||
package ru.myitschool.work.ui.main
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.myitschool.work.R
|
||||
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 kotlinx.coroutines.withContext
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.SessionManager
|
||||
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 java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
|
||||
class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
private var _binding: FragmentMainBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private val binding get() = _binding
|
||||
|
||||
private lateinit var apiService: ApiService
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
apiService = Retrofit.Builder()
|
||||
private val apiService: ApiService by lazy {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(Constants.SERVER_ADDRESS)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
@ -37,10 +37,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentMainBinding.bind(view)
|
||||
_binding = FragmentMainBinding.bind(view) // Подключаем binding
|
||||
|
||||
setupUI()
|
||||
fetchUserInfo()
|
||||
fetchUserData()
|
||||
|
||||
// Проверяем, есть ли результат QR
|
||||
checkQrResult()
|
||||
@ -52,93 +52,117 @@ class MainFragment : Fragment(R.layout.fragment_main) {
|
||||
val qrData = QrScanDestination.getDataIfExist(bundle)
|
||||
if (qrData != null) {
|
||||
// Если данные QR есть, переходим на экран с результатом
|
||||
val resultBundle = QrScanDestination.packToBundle(qrData)
|
||||
findNavController().navigate(R.id.qrResultFragment, resultBundle)
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "QR данные не найдены", Toast.LENGTH_SHORT).show()
|
||||
findNavController().navigate(R.id.qrResultFragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupUI() {
|
||||
binding.refresh.setOnClickListener {
|
||||
fetchUserInfo()
|
||||
}
|
||||
|
||||
binding.scanQrCode?.setOnClickListener {
|
||||
// Переход к экрану сканирования QR-кода
|
||||
findNavController().navigate(R.id.qrScanFragment) // Убедитесь, что у вас есть правильный ID для навигации
|
||||
}
|
||||
|
||||
// Проверяем роль пользователя и показываем кнопку 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
|
||||
// Проверяем, что binding не null, прежде чем устанавливать слушателей
|
||||
binding?.apply {
|
||||
refresh.setOnClickListener { fetchUserData() }
|
||||
logout.setOnClickListener { logout() }
|
||||
scan.setOnClickListener { navigateToQrScan() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchUserInfo() {
|
||||
private fun fetchUserData() {
|
||||
lifecycleScope.launch {
|
||||
val login = SessionManager.userLogin ?: run {
|
||||
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
|
||||
}
|
||||
|
||||
showError(null) // Скрыть ошибку, если она была
|
||||
try {
|
||||
val response = apiService.getUserInfo(login, authHeader)
|
||||
|
||||
// Логируем код ответа
|
||||
Log.d("MainFragment", "Response code: ${response.code()}")
|
||||
|
||||
val response = apiService.getUserInfo(SessionManager.userLogin) // Получаем данные пользователя
|
||||
if (response.isSuccessful) {
|
||||
val employeeData = response.body()
|
||||
employeeData?.let {
|
||||
binding.fullname.text = it.name
|
||||
binding.position.text = it.position
|
||||
binding.lastEntry.text = it.lastVisit
|
||||
response.body()?.let { data ->
|
||||
// Извлекаем значения из Map
|
||||
val fullName = data["name"] as? String ?: "Неизвестно"
|
||||
val position = data["position"] as? String ?: "Неизвестно"
|
||||
val lastVisit = data["lastVisit"] as? String ?: "Неизвестно"
|
||||
val photoUrl = data["photo"] as? String ?: ""
|
||||
|
||||
// Логируем URL аватара
|
||||
Log.d("MainFragment", "Avatar URL: ${it.avatarUrl}")
|
||||
|
||||
// Загрузка аватара с помощью Picasso
|
||||
if (it.avatarUrl != null) {
|
||||
Picasso.get()
|
||||
.load(it.avatarUrl)
|
||||
.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
|
||||
// Обновляем UI
|
||||
updateUI(fullName, position, lastVisit, photoUrl)
|
||||
}
|
||||
} else {
|
||||
binding.error.text = "Ошибка получения данных: ${response.message()}"
|
||||
binding.error.visibility = View.VISIBLE
|
||||
showError(getString(R.string.error_loading_data)) // Показываем ошибку, если данные не загрузились
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainFragment", "Error fetching user info", e)
|
||||
binding.error.text = "Ошибка сети: ${e.message}"
|
||||
binding.error.visibility = View.VISIBLE
|
||||
showError(e.localizedMessage) // Показываем ошибку при исключении
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
} else {
|
||||
error.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
_binding = null
|
||||
_binding = null // Освобождаем binding, когда представление уничтожается
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -1,40 +1,35 @@
|
||||
package ru.myitschool.work.ui.main
|
||||
|
||||
import android.util.Log
|
||||
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.launch
|
||||
import ru.myitschool.work.SessionManager
|
||||
import ru.myitschool.work.api.ApiService
|
||||
import ru.myitschool.work.api.EmployeeData
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
private val apiService: ApiService
|
||||
) : ViewModel() {
|
||||
private val _userInfoState = MutableStateFlow<Map<String, Any>?>(null)
|
||||
val userInfoState: StateFlow<Map<String, Any>?> = _userInfoState
|
||||
|
||||
private val _employeeData = MutableStateFlow<EmployeeData?>(null)
|
||||
val employeeData: StateFlow<EmployeeData?> get() = _employeeData
|
||||
init {
|
||||
loadUserData()
|
||||
}
|
||||
|
||||
private val _errorMessage = MutableStateFlow<String?>(null)
|
||||
val errorMessage: StateFlow<String?> get() = _errorMessage
|
||||
|
||||
fun fetchUserInfo(login: String, authHeader: String) {
|
||||
private fun loadUserData() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val response = apiService.getUserInfo(login, authHeader)
|
||||
val login = SessionManager.userLogin
|
||||
if (login != null) {
|
||||
val response = apiService.getUserInfo(login)
|
||||
if (response.isSuccessful) {
|
||||
_employeeData.value = response.body()
|
||||
} else {
|
||||
_errorMessage.value = "Ошибка получения данных: ${response.message()}"
|
||||
_userInfoState.value = response.body()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainViewModel", "Error fetching user info", e)
|
||||
_errorMessage.value = "Ошибка сети: ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class RootActivity : AppCompatActivity() {
|
||||
navController.setGraph(R.navigation.nav_graph) // Устанавливаем граф навигации
|
||||
}
|
||||
|
||||
// Настройка кнопки "Назад"
|
||||
// Настраиваем кнопку "Назад"
|
||||
onBackPressedDispatcher.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
@ -44,4 +44,4 @@ class RootActivity : AppCompatActivity() {
|
||||
}
|
||||
return popBackResult || super.onSupportNavigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ru.myitschool.work.ui.login
|
||||
|
||||
import ru.myitschool.work.api.ApiService
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
@ -8,19 +7,17 @@ import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.SessionManager
|
||||
import ru.myitschool.work.databinding.FragmentLoginBinding
|
||||
import ru.myitschool.work.utils.collectWhenStarted
|
||||
import ru.myitschool.work.utils.visibleOrGone
|
||||
import ru.myitschool.work.utils.AuthPreferences
|
||||
import kotlinx.coroutines.launch
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LoginFragment : Fragment(R.layout.fragment_login) {
|
||||
@ -40,7 +37,7 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState) // Убедитесь, что этот вызов находится здесь
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentLoginBinding.bind(view)
|
||||
|
||||
setupUI()
|
||||
@ -55,11 +52,9 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
|
||||
|
||||
binding.login.setOnClickListener {
|
||||
val username = binding.username.text.toString()
|
||||
val password = binding.password.text.toString() // Получаем пароль
|
||||
performLogin(username, password) // Передаем пароль в метод performLogin
|
||||
performLogin(username) // Вызываем метод performLogin
|
||||
}
|
||||
|
||||
// Изначально скрываем индикаторы
|
||||
binding.loading.visibleOrGone(false)
|
||||
binding.error.visibleOrGone(false)
|
||||
}
|
||||
@ -77,44 +72,29 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
|
||||
})
|
||||
}
|
||||
|
||||
private fun performLogin(username: String, password: String) {
|
||||
private fun performLogin(username: String) {
|
||||
lifecycleScope.launch {
|
||||
binding.loading.visibleOrGone(true) // Показываем индикатор загрузки
|
||||
viewModel.authenticate(username, password) // Передаем пароль в метод authenticate
|
||||
viewModel.authenticate(username) // Вызываем метод authenticate из ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribe() {
|
||||
lifecycleScope.launch {
|
||||
viewModel.state.collect { state ->
|
||||
binding.loading.visibleOrGone(false)
|
||||
viewModel.state.collectWhenStarted(this) { state ->
|
||||
binding.loading.visibleOrGone(false)
|
||||
|
||||
if (state.maintenance) {
|
||||
showMaintenanceDialog() // Показываем диалог о техработах
|
||||
} else if (state.success) {
|
||||
binding.error.visibility = View.GONE
|
||||
authPreferences.saveLoginState(true)
|
||||
authPreferences.saveLogin(binding.username.text.toString()) // Сохраняем логин
|
||||
|
||||
Toast.makeText(context, "Авторизация прошла успешно", Toast.LENGTH_SHORT).show()
|
||||
navigateToMainScreen() // Перенаправление на следующий экран
|
||||
} else if (state.error != null) {
|
||||
binding.error.text = state.error
|
||||
binding.error.visibility = View.VISIBLE
|
||||
}
|
||||
if (state.error != null) {
|
||||
binding.error.text = state.error
|
||||
binding.error.visibility = View.VISIBLE
|
||||
} else if (state.success) {
|
||||
binding.error.visibility = View.GONE
|
||||
authPreferences.saveLoginState(true)
|
||||
authPreferences.saveLogin(binding.username.text.toString()) // Сохраняем логин
|
||||
Toast.makeText(context, "Авторизация прошла успешно", Toast.LENGTH_SHORT).show()
|
||||
navigateToMainScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMaintenanceDialog() {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle("Технические работы")
|
||||
.setMessage("Проводятся техработы, пожалуйста, подождите.")
|
||||
.setPositiveButton("ОК ") { dialog, _ -> dialog.dismiss() }
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun navigateToMainScreen() {
|
||||
try {
|
||||
findNavController().apply {
|
||||
@ -122,7 +102,7 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
|
||||
navigate(R.id.mainFragment)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("LoginFragment", "Nav_err", e)
|
||||
Log.e("LF", "Nav_err", e)
|
||||
Toast.makeText(context, "Ошибка перехода", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +1,54 @@
|
||||
package ru.myitschool.work.ui.login
|
||||
|
||||
import ru.myitschool.work.api.ApiService
|
||||
import android.util.Log
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import ru.myitschool.work.SessionManager
|
||||
import ru.myitschool.work.api.ApiService
|
||||
import ru.myitschool.work.core.Constants
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class LoginViewModel @Inject constructor(
|
||||
private val apiService: ApiService
|
||||
@ApplicationContext private val context: Context,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _state = MutableStateFlow(LoginState())
|
||||
val state: StateFlow<LoginState> get() = _state
|
||||
val state = _state.asStateFlow()
|
||||
|
||||
fun authenticate(username: String, password: String) {
|
||||
Log.d("LoginViewModel", "Authenticating user: $username") // Логируем начало аутентификации
|
||||
private val apiService: ApiService by lazy {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(Constants.SERVER_ADDRESS)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(ApiService::class.java)
|
||||
}
|
||||
|
||||
fun authenticate(username: String) {
|
||||
if (isValidUsername(username)) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
Log.d("LoginViewModel", "Sending authentication request to server") // Логируем отправку запроса
|
||||
val response = apiService.authenticate(username, password)
|
||||
Log.d("LoginViewModel", "Response code: ${response.code()}") // Логируем код ответа
|
||||
|
||||
// Проверяем код ответа
|
||||
when (response.code()) {
|
||||
200 -> {
|
||||
SessionManager.userLogin = username
|
||||
_state.value = LoginState(success = true) // Успешная авторизация
|
||||
Log.d("LoginViewModel", "Authentication successful") // Логируем успешную аутентификацию
|
||||
}
|
||||
400 -> {
|
||||
_state.value = LoginState(error = "Ошибка авторизации: Неверные учетные данные.")
|
||||
Log.d("LoginViewModel", "Authentication failed: Invalid credentials") // Логируем ошибку
|
||||
}
|
||||
else -> {
|
||||
_state.value = LoginState(error = "Ошибка авторизации: ${response.message()}")
|
||||
Log.d("LoginViewModel", "Authentication failed: ${response.message()}") // Логируем ошибку
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
_state.value = LoginState(error = "Ошибка сети. Проверьте подключение к интернету.")
|
||||
Log.e("LoginViewModel", "Network error: ${e.message}") // Логируем ошибку сети
|
||||
val response = apiService.authenticate(username)
|
||||
if (response.isSuccessful) {
|
||||
SessionManager.userLogin = username
|
||||
_state.value = LoginState(success = true)
|
||||
} else {
|
||||
_state.value = LoginState(error = "Ошибка авторизации")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_state.value = LoginState(error = "Неправильный логин")
|
||||
Log.d("LoginViewModel", "Invalid username: $username") // Логируем неправильный логин
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidUsername(username: String): Boolean {
|
||||
return username.isNotEmpty() // Пример проверки логина
|
||||
return username.length >= 3 && !username.first().isDigit() && username.all { it.isLetterOrDigit() }
|
||||
}
|
||||
}
|
||||
|
||||
// Состояние аутентификации
|
||||
data class LoginState(
|
||||
val success: Boolean = false, // Успешность аутентификации
|
||||
val error: String? = null, // Сообщение об ошибке
|
||||
val maintenance: Boolean = false // Состояние техобслуживания
|
||||
)
|
||||
data class LoginState(val success: Boolean = false, val error: String? = null)
|
||||
}
|
@ -5,10 +5,8 @@ import androidx.navigation.fragment.findNavController
|
||||
import ru.myitschool.work.SessionManager
|
||||
import ru.myitschool.work.api.OpenDoorRequest
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.util.Base64
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@ -21,9 +19,7 @@ import ru.myitschool.work.core.Constants
|
||||
import ru.myitschool.work.databinding.FragmentQrScanResultBinding
|
||||
|
||||
class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
|
||||
private var _binding: FragmentQrScanResultBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private lateinit var binding: FragmentQrScanResultBinding
|
||||
private lateinit var apiService: ApiService
|
||||
|
||||
override fun onCreateView(
|
||||
@ -31,7 +27,7 @@ class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentQrScanResultBinding.inflate(inflater, container, false)
|
||||
binding = FragmentQrScanResultBinding.inflate(inflater, container, false)
|
||||
apiService = Retrofit.Builder()
|
||||
.baseUrl(Constants.SERVER_ADDRESS)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
@ -44,12 +40,8 @@ class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// Получаем данные из аргументов
|
||||
val qrData = QrScanDestination.getDataIfExist(requireArguments())
|
||||
Log.d("QrResult", "QR Data: $qrData") // Логируем полученные данные
|
||||
|
||||
if (qrData != null) {
|
||||
binding.result.text = "Результат сканирования: $qrData" // Отображаем результат сканирования
|
||||
sendRequestToServer(qrData)
|
||||
} else {
|
||||
binding.result.text = "Вход был отменён/Operation was cancelled"
|
||||
@ -63,40 +55,15 @@ class QrResult : Fragment(R.layout.fragment_qr_scan_result) {
|
||||
private fun sendRequestToServer(qrData: String) {
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val qrValue = qrData.toLong() // Преобразуем данные QR-кода в Long
|
||||
val login = SessionManager.userLogin ?: "default_login" // Замените на ваш логин
|
||||
val password = "your_password" // Замените на ваш пароль
|
||||
val authHeader = "Basic " + Base64.encodeToString("$login:$password".toByteArray(), Base64.NO_WRAP)
|
||||
|
||||
// Логируем данные перед отправкой
|
||||
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()}")
|
||||
|
||||
val response = apiService.openDoor(SessionManager.userLogin, OpenDoorRequest(qrData))
|
||||
if (response.isSuccessful) {
|
||||
binding.result.text = "Door Opened" // Сообщение о том, что дверь открыта
|
||||
binding.result.text = "Успешно/Success"
|
||||
} else {
|
||||
binding.result.text = "Door Closed" // Сообщение о том, что дверь закрыта
|
||||
binding.result.text = "Что-то пошло не так/Something wrong"
|
||||
}
|
||||
} catch (e: NumberFormatException) {
|
||||
binding.result.text = "Некорректные данные QR-кода"
|
||||
} catch (e: Exception) {
|
||||
binding.result.text = "Что-то пошло не так/Something went wrong: ${e.message}"
|
||||
Log.e("QrResult", "Error sending request to server", e)
|
||||
binding.result.text = "Что-то пошло не так/Something wrong"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
_binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package ru.myitschool.work.utils
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
// Функция для сбора данных из Flow, когда жизненный цикл находится в состоянии STARTED
|
||||
fun <T> Flow<T>.collectWhenStarted(lifecycleOwner: LifecycleOwner, collector: (T) -> Unit) {
|
||||
lifecycleOwner.lifecycleScope.launch {
|
||||
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
collect { value -> collector(value) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для управления видимостью View
|
||||
fun View?.visibleOrGone(isVisible: Boolean) {
|
||||
this?.visibility = if (isVisible) View.VISIBLE else View.GONE
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#F0F0F0" />
|
||||
<corners android:radius="16dp" />
|
||||
</shape>
|
@ -1,60 +0,0 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_worker_username"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/employee_login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/worker_username"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/ic_android_black_24dp"
|
||||
android:inputType="text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/view_employee_info"
|
||||
android:layout_width="280dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/watch_info_about_worker"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
app:cornerRadius="16dp"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/employee_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/toggle_access"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/block_or_unblock"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/close"
|
||||
android:layout_width="280dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/back"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
app:cornerRadius="16dp"
|
||||
android:layout_marginTop="0dp" />
|
||||
|
||||
</LinearLayout>
|
@ -1,56 +0,0 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="16dp"
|
||||
android:background="@android:color/white">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/username_hint"
|
||||
android:inputType="text"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/ic_android_black_24dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
android:inputType="textPassword"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/ic_android_black_24dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_button"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
app:cornerRadius="16dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:gravity="center_horizontal"
|
||||
android:textColor="@android:color/holo_red_light"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
@ -1,124 +0,0 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="bottom"
|
||||
android:padding="16dp"
|
||||
android:background="@android:color/white">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<!-- Поле для ФИО -->
|
||||
<TextView
|
||||
android:id="@+id/fullname"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fullname_label"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Фото пользователя. -->
|
||||
<ImageView
|
||||
android:id="@+id/photo"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/photo_description"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Поле для должности -->
|
||||
<TextView
|
||||
android:id="@+id/position"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/position_label"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Поле для даты последнего входа -->
|
||||
<TextView
|
||||
android:id="@+id/lastEntry"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="2024-02-31 08:31"
|
||||
android:layout_marginBottom="75dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- RecyclerView для списка проходов -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<!-- Кнопка обновления -->
|
||||
<Button
|
||||
android:id="@+id/refresh"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/refresh"
|
||||
app:cornerRadius="16dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"/>
|
||||
|
||||
<!-- Поле ошибки -->
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
android:text="@string/error_placeholder"
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Кнопки -->
|
||||
<Button
|
||||
android:id="@+id/scan"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/scan_qr_code"
|
||||
app:cornerRadius="16dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/logout"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/logout"
|
||||
app:cornerRadius="16dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/admin_panel"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/admin_panel"
|
||||
app:cornerRadius="16dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.camera.view.PreviewView
|
||||
android:id="@+id/viewFinder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/close_button"
|
||||
android:src="@drawable/ic_close"
|
||||
app:elevation="0dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/qrScanResultLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/result"
|
||||
android:textSize="18sp"
|
||||
android:gravity="center"
|
||||
android:padding="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/close_button"
|
||||
app:cornerRadius="16dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
android:layout_marginTop="24dp" />
|
||||
|
||||
</LinearLayout>
|
@ -1,61 +0,0 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_worker_username"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/employee_login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/worker_username"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/ic_android_black_24dp"
|
||||
android:inputType="text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/view_employee_info"
|
||||
android:layout_width="280dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/watch_info_about_worker"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
app:cornerRadius="16dp"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/employee_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/toggle_access"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/block_or_unblock"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/close"
|
||||
android:layout_width="280dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/back"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
app:cornerRadius="16dp"
|
||||
android:layout_marginTop="0dp" />
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -1,52 +1,31 @@
|
||||
<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_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="16dp"
|
||||
android:background="@android:color/white">
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/username_hint"
|
||||
android:inputType="text"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/ic_android_black_24dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
android:inputType="textPassword"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/ic_android_black_24dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
android:inputType="text"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_button"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
app:cornerRadius="16dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:gravity="center_horizontal"
|
||||
android:textColor="@android:color/holo_red_light"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
android:textColor="@android:color/holo_red_light" />
|
||||
|
||||
<!-- Добавьте ProgressBar для индикатора загрузки -->
|
||||
<ProgressBar
|
||||
android:id="@+id/loading"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -1,78 +1,72 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Поле для ФИО -->
|
||||
<TextView
|
||||
android:id="@+id/fullname"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp" />
|
||||
android:text="@string/name_and_surname"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Фото пользователя -->
|
||||
<ImageView
|
||||
android:id="@+id/photo"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/photo_description" />
|
||||
android:contentDescription="@string/photo_description"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Поле для должности -->
|
||||
<TextView
|
||||
android:id="@+id/position"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp" />
|
||||
android:text="@string/position_label"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Поле для даты последнего входа -->
|
||||
<TextView
|
||||
android:id="@+id/lastEntry"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp" />
|
||||
android:text="@string/date_and_time"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Кнопки -->
|
||||
<Button
|
||||
android:id="@+id/logout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/logout"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
app:cornerRadius="16dp"
|
||||
android:text="@string/refresh" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/scan"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/scan_qr_code"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Поле ошибки -->
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/error_placeholder"
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/scan_qr_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
app:cornerRadius="16dp"
|
||||
android:text="Сканировать QR-код"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/adminPanelButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
app:cornerRadius="16dp"
|
||||
android:text="Admin Panel"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -30,7 +30,6 @@
|
||||
android:contentDescription="@string/close_button"
|
||||
android:src="@drawable/ic_close"
|
||||
app:elevation="0dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/qrScanResultLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -22,9 +21,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/close_button"
|
||||
app:cornerRadius="16dp"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@android:color/white"
|
||||
android:padding="12dp"
|
||||
android:layout_marginTop="24dp" />
|
||||
|
||||
</LinearLayout>
|
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/scan_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reader_id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/access_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
@ -22,12 +22,6 @@
|
||||
android:label="Main Fragment"
|
||||
tools:layout="@layout/fragment_main" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/adminFragment"
|
||||
android:name="ru.myitschool.work.ui.main.AdminFragment"
|
||||
android:label="Admin Fragment"
|
||||
tools:layout="@layout/fragment_admin" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/qrResultFragment"
|
||||
android:name="ru.myitschool.work.ui.qr.result.QrResult"
|
||||
|
@ -5,16 +5,17 @@
|
||||
<string name="navigate">Go over</string>
|
||||
|
||||
<string name="photo_description">User\'s photo</string>
|
||||
<string name="name_and_surname">Name Surname</string>
|
||||
<string name="logout">Exit</string>
|
||||
<string name="refresh">Update</string>
|
||||
<string name="scan_qr_code">Scan QR Code</string>
|
||||
<string name="error_placeholder">An error has occurred</string>
|
||||
<string name="error_loading_data">Data upload error</string>
|
||||
<string name="logged_out">You have logged out of your account</string>
|
||||
<string name="date_and_time">2024-02-31 08:31</string>
|
||||
|
||||
<!-- Строки для экрана авторизации -->
|
||||
<string name="username_hint">Enter username</string>
|
||||
<string name="password_hint">Enter the password</string>
|
||||
<string name="username_hint">Enter your username</string>
|
||||
<string name="login_button">Enter</string>
|
||||
<string name="error_invalid_username">The login is invalid. Check the entered data.</string>
|
||||
<string name="error_empty_username">The login field must not be empty.</string>
|
||||
@ -32,13 +33,8 @@
|
||||
<string name="qr_scan_success">Successfully</string>
|
||||
<string name="qr_scan_failure">Something went wrong.</string>
|
||||
<string name="qr_scan_cancelled">Operation was cancelled</string>
|
||||
|
||||
<string name="close_button">Close</string>
|
||||
<string name="result">Result</string>
|
||||
|
||||
<!-- Админ панель -->
|
||||
<string name="enter_worker_username">Enter the employee\'s username:</string>
|
||||
<string name="worker_username">Employee\'s login</string>
|
||||
<string name="watch_info_about_worker">View employee information</string>
|
||||
<string name="block_or_unblock">Block/Unblock access</string>
|
||||
<string name="back">Back</string>
|
||||
</resources>
|
@ -7,6 +7,4 @@
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="colorPrimary">#2196F3</color>
|
||||
<color name="light_gray">#F0F0F0</color>
|
||||
</resources>
|
@ -1,45 +1,40 @@
|
||||
<resources>
|
||||
|
||||
<string name="app_name" translatable="false">NTO Pass</string>
|
||||
<string name="welcome_message">Добро пожаловать в приложение!</string>
|
||||
<string name="navigate">Перейти</string>
|
||||
<string name="app_name" translatable="false">NTO Pass</string>
|
||||
<string name="welcome_message">Добро пожаловать в приложение!</string>
|
||||
<string name="navigate">Перейти</string>
|
||||
|
||||
<string name="photo_description">Фото пользователя</string>
|
||||
<string name="logout">Выйти</string>
|
||||
<string name="refresh">Обновить</string>
|
||||
<string name="scan_qr_code">Сканировать QR</string>
|
||||
<string name="error_placeholder">Произошла ошибка</string>
|
||||
<string name="error_loading_data">Ошибка загрузки данных</string>
|
||||
<string name="logged_out">Вы вышли из аккаунта</string>
|
||||
<string name="photo_description">Фото пользователя</string>
|
||||
<string name="name_and_surname">Имя Фамилия</string>
|
||||
<string name="logout">Выйти</string>
|
||||
<string name="refresh">Обновить</string>
|
||||
<string name="scan_qr_code">Сканировать QR</string>
|
||||
<string name="error_placeholder">Произошла ошибка</string>
|
||||
<string name="error_loading_data">Ошибка загрузки данных</string>
|
||||
<string name="logged_out">Вы вышли из аккаунта</string>
|
||||
<string name="date_and_time">2024-02-31 08:31</string>
|
||||
|
||||
<!-- Строки для экрана авторизации -->
|
||||
<string name="username_hint">Введите логин</string>
|
||||
<string name="password_hint">Введите пароль</string>
|
||||
<string name="login_button">Войти</string>
|
||||
<string name="error_invalid_username">Логин недействителен. Проверьте введенные данные.</string>
|
||||
<string name="error_empty_username">Поле логина не должно быть пустым.</string>
|
||||
<string name="error_username_too_short">Логин должен содержать не менее 3 символов.</string>
|
||||
<string name="error_username_starts_with_digit">Логин не должен начинаться с цифры.</string>
|
||||
<string name="error_username_invalid_characters">Логин может содержать только латинские буквы и цифры.</string>
|
||||
<!-- Строки для экрана авторизации -->
|
||||
<string name="username_hint">Введите логин</string>
|
||||
<string name="login_button">Войти</string>
|
||||
<string name="error_invalid_username">Логин недействителен. Проверьте введенные данные.</string>
|
||||
<string name="error_empty_username">Поле логина не должно быть пустым.</string>
|
||||
<string name="error_username_too_short">Логин должен содержать не менее 3 символов.</string>
|
||||
<string name="error_username_starts_with_digit">Логин не должен начинаться с цифры.</string>
|
||||
<string name="error_username_invalid_characters">Логин может содержать только латинские буквы и цифры.</string>
|
||||
|
||||
<!-- Строки для главного экрана -->
|
||||
<string name="fullname_label">ФИО</string>
|
||||
<string name="position_label">Должность</string>
|
||||
<string name="last_entry_label">Время последнего входа</string>
|
||||
<string name="error_no_user_data">Нет данных о пользователе.</string>
|
||||
<string name="admin_panel" translatable="false">Admin Panel</string>
|
||||
<!-- Строки для главного экрана -->
|
||||
<string name="fullname_label">ФИО</string>
|
||||
<string name="position_label">Должность</string>
|
||||
<string name="last_entry_label">Время последнего входа</string>
|
||||
<string name="error_no_user_data">Нет данных о пользователе.</string>
|
||||
|
||||
<!-- Строки для экрана сканирования QR-кода -->
|
||||
<string name="qr_scan_success">Успешно</string>
|
||||
<string name="qr_scan_failure">Что-то пошло не так</string>
|
||||
<string name="qr_scan_cancelled">Вход был отменён / Operation was cancelled</string>
|
||||
<string name="close_button">Закрыть</string>
|
||||
<string name="result">Результат</string>
|
||||
<!-- Строки для экрана сканирования QR-кода -->
|
||||
<string name="qr_scan_success">Успешно</string>
|
||||
<string name="qr_scan_failure">Что-то пошло не так</string>
|
||||
<string name="qr_scan_cancelled">Вход был отменён/Operation was cancelled</string>
|
||||
|
||||
<string name="close_button">Закрыть</string>
|
||||
<string name="result">Результат</string>
|
||||
|
||||
<!-- Админ панель -->
|
||||
<string name="enter_worker_username">Введите логин сотрудника:</string>
|
||||
<string name="worker_username">Логин сотрудника</string>
|
||||
<string name="watch_info_about_worker">Просмотреть информацию о сотруднике</string>
|
||||
<string name="block_or_unblock">Блокировать/Разблокировать доступ</string>
|
||||
<string name="back">Назад</string>
|
||||
</resources>
|
@ -4,6 +4,5 @@ plugins {
|
||||
kotlinJvm version Version.Kotlin.language apply false
|
||||
kotlinAnnotationProcessor version Version.Kotlin.language apply false
|
||||
id("com.google.dagger.hilt.android") version "2.51.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.9.24" apply false
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user