diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 1afa7f2..254a1fc 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 7146cb1..d852bbf 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/.idea/studiobot.xml b/.idea/studiobot.xml new file mode 100644 index 0000000..539e3b8 --- /dev/null +++ b/.idea/studiobot.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.kotlin/errors/errors-1768372341802.log b/.kotlin/errors/errors-1768372341802.log new file mode 100644 index 0000000..c35eeee --- /dev/null +++ b/.kotlin/errors/errors-1768372341802.log @@ -0,0 +1,114 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt:20:29: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl.acceptChildren(FirAnonymousFunctionImpl.kt:70) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunction(AbstractDiagnosticCollectorVisitor.kt:141) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:134) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression.accept(FirAnonymousFunctionExpression.kt:30) + at org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList.acceptChildren(FirResolvedArgumentList.kt:35) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirVisitor.visitArgumentList(FirVisitor.kt:81) + at org.jetbrains.kotlin.fir.expressions.FirArgumentList.accept(FirArgumentList.kt:25) + at org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl.acceptChildren(FirFunctionCallImpl.kt:55) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:49) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithCallOrAssignment(AbstractDiagnosticCollectorVisitor.kt:346) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:255) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirFunctionCall.accept(FirFunctionCall.kt:41) + at org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl.acceptChildren(FirReturnExpressionImpl.kt:41) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitJump(FirDefaultVisitor.kt:54) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitReturnExpression(FirDefaultVisitor.kt:66) + at org.jetbrains.kotlin.fir.expressions.FirReturnExpression.accept(FirReturnExpression.kt:31) + at org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl.acceptChildren(FirBlockImpl.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:209) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirBlock.accept(FirBlock.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:68) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372341807.log b/.kotlin/errors/errors-1768372341807.log new file mode 100644 index 0000000..c53ba2e --- /dev/null +++ b/.kotlin/errors/errors-1768372341807.log @@ -0,0 +1,69 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/presentation/src/main/java/com/example/presentation/NoteMarkDefaultScreen.kt:16:1: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372341810.log b/.kotlin/errors/errors-1768372341810.log new file mode 100644 index 0000000..6b923b1 --- /dev/null +++ b/.kotlin/errors/errors-1768372341810.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt:10:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372341816.log b/.kotlin/errors/errors-1768372341816.log new file mode 100644 index 0000000..b01bbfd --- /dev/null +++ b/.kotlin/errors/errors-1768372341816.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/releases/data/src/main/java/com/example/data/ReleasesService.kt:5:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372402078.log b/.kotlin/errors/errors-1768372402078.log new file mode 100644 index 0000000..c35eeee --- /dev/null +++ b/.kotlin/errors/errors-1768372402078.log @@ -0,0 +1,114 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt:20:29: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl.acceptChildren(FirAnonymousFunctionImpl.kt:70) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunction(AbstractDiagnosticCollectorVisitor.kt:141) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:134) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression.accept(FirAnonymousFunctionExpression.kt:30) + at org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList.acceptChildren(FirResolvedArgumentList.kt:35) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirVisitor.visitArgumentList(FirVisitor.kt:81) + at org.jetbrains.kotlin.fir.expressions.FirArgumentList.accept(FirArgumentList.kt:25) + at org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl.acceptChildren(FirFunctionCallImpl.kt:55) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:49) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithCallOrAssignment(AbstractDiagnosticCollectorVisitor.kt:346) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:255) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirFunctionCall.accept(FirFunctionCall.kt:41) + at org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl.acceptChildren(FirReturnExpressionImpl.kt:41) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitJump(FirDefaultVisitor.kt:54) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitReturnExpression(FirDefaultVisitor.kt:66) + at org.jetbrains.kotlin.fir.expressions.FirReturnExpression.accept(FirReturnExpression.kt:31) + at org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl.acceptChildren(FirBlockImpl.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:209) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirBlock.accept(FirBlock.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:68) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372402083.log b/.kotlin/errors/errors-1768372402083.log new file mode 100644 index 0000000..c53ba2e --- /dev/null +++ b/.kotlin/errors/errors-1768372402083.log @@ -0,0 +1,69 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/presentation/src/main/java/com/example/presentation/NoteMarkDefaultScreen.kt:16:1: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372402085.log b/.kotlin/errors/errors-1768372402085.log new file mode 100644 index 0000000..6b923b1 --- /dev/null +++ b/.kotlin/errors/errors-1768372402085.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt:10:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372402089.log b/.kotlin/errors/errors-1768372402089.log new file mode 100644 index 0000000..b01bbfd --- /dev/null +++ b/.kotlin/errors/errors-1768372402089.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/releases/data/src/main/java/com/example/data/ReleasesService.kt:5:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372523043.log b/.kotlin/errors/errors-1768372523043.log new file mode 100644 index 0000000..c35eeee --- /dev/null +++ b/.kotlin/errors/errors-1768372523043.log @@ -0,0 +1,114 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt:20:29: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl.acceptChildren(FirAnonymousFunctionImpl.kt:70) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunction(AbstractDiagnosticCollectorVisitor.kt:141) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:134) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression.accept(FirAnonymousFunctionExpression.kt:30) + at org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList.acceptChildren(FirResolvedArgumentList.kt:35) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirVisitor.visitArgumentList(FirVisitor.kt:81) + at org.jetbrains.kotlin.fir.expressions.FirArgumentList.accept(FirArgumentList.kt:25) + at org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl.acceptChildren(FirFunctionCallImpl.kt:55) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:49) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithCallOrAssignment(AbstractDiagnosticCollectorVisitor.kt:346) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:255) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirFunctionCall.accept(FirFunctionCall.kt:41) + at org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl.acceptChildren(FirReturnExpressionImpl.kt:41) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitJump(FirDefaultVisitor.kt:54) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitReturnExpression(FirDefaultVisitor.kt:66) + at org.jetbrains.kotlin.fir.expressions.FirReturnExpression.accept(FirReturnExpression.kt:31) + at org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl.acceptChildren(FirBlockImpl.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:209) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirBlock.accept(FirBlock.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:68) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372523046.log b/.kotlin/errors/errors-1768372523046.log new file mode 100644 index 0000000..c53ba2e --- /dev/null +++ b/.kotlin/errors/errors-1768372523046.log @@ -0,0 +1,69 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/presentation/src/main/java/com/example/presentation/NoteMarkDefaultScreen.kt:16:1: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372523047.log b/.kotlin/errors/errors-1768372523047.log new file mode 100644 index 0000000..6b923b1 --- /dev/null +++ b/.kotlin/errors/errors-1768372523047.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt:10:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372523050.log b/.kotlin/errors/errors-1768372523050.log new file mode 100644 index 0000000..b01bbfd --- /dev/null +++ b/.kotlin/errors/errors-1768372523050.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/releases/data/src/main/java/com/example/data/ReleasesService.kt:5:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372649411.log b/.kotlin/errors/errors-1768372649411.log new file mode 100644 index 0000000..c35eeee --- /dev/null +++ b/.kotlin/errors/errors-1768372649411.log @@ -0,0 +1,114 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt:20:29: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl.acceptChildren(FirAnonymousFunctionImpl.kt:70) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunction(AbstractDiagnosticCollectorVisitor.kt:141) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:134) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression.accept(FirAnonymousFunctionExpression.kt:30) + at org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList.acceptChildren(FirResolvedArgumentList.kt:35) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirVisitor.visitArgumentList(FirVisitor.kt:81) + at org.jetbrains.kotlin.fir.expressions.FirArgumentList.accept(FirArgumentList.kt:25) + at org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl.acceptChildren(FirFunctionCallImpl.kt:55) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:49) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithCallOrAssignment(AbstractDiagnosticCollectorVisitor.kt:346) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:255) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirFunctionCall.accept(FirFunctionCall.kt:41) + at org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl.acceptChildren(FirReturnExpressionImpl.kt:41) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitJump(FirDefaultVisitor.kt:54) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitReturnExpression(FirDefaultVisitor.kt:66) + at org.jetbrains.kotlin.fir.expressions.FirReturnExpression.accept(FirReturnExpression.kt:31) + at org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl.acceptChildren(FirBlockImpl.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:209) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirBlock.accept(FirBlock.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:68) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372649416.log b/.kotlin/errors/errors-1768372649416.log new file mode 100644 index 0000000..6b923b1 --- /dev/null +++ b/.kotlin/errors/errors-1768372649416.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt:10:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372649421.log b/.kotlin/errors/errors-1768372649421.log new file mode 100644 index 0000000..b01bbfd --- /dev/null +++ b/.kotlin/errors/errors-1768372649421.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/releases/data/src/main/java/com/example/data/ReleasesService.kt:5:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372886661.log b/.kotlin/errors/errors-1768372886661.log new file mode 100644 index 0000000..c35eeee --- /dev/null +++ b/.kotlin/errors/errors-1768372886661.log @@ -0,0 +1,114 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt:20:29: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl.acceptChildren(FirAnonymousFunctionImpl.kt:70) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunction(AbstractDiagnosticCollectorVisitor.kt:141) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:134) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression.accept(FirAnonymousFunctionExpression.kt:30) + at org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList.acceptChildren(FirResolvedArgumentList.kt:35) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirVisitor.visitArgumentList(FirVisitor.kt:81) + at org.jetbrains.kotlin.fir.expressions.FirArgumentList.accept(FirArgumentList.kt:25) + at org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl.acceptChildren(FirFunctionCallImpl.kt:55) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:49) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithCallOrAssignment(AbstractDiagnosticCollectorVisitor.kt:346) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:255) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirFunctionCall.accept(FirFunctionCall.kt:41) + at org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl.acceptChildren(FirReturnExpressionImpl.kt:41) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitJump(FirDefaultVisitor.kt:54) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitReturnExpression(FirDefaultVisitor.kt:66) + at org.jetbrains.kotlin.fir.expressions.FirReturnExpression.accept(FirReturnExpression.kt:31) + at org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl.acceptChildren(FirBlockImpl.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:209) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirBlock.accept(FirBlock.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:68) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372886667.log b/.kotlin/errors/errors-1768372886667.log new file mode 100644 index 0000000..6b923b1 --- /dev/null +++ b/.kotlin/errors/errors-1768372886667.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt:10:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372895329.log b/.kotlin/errors/errors-1768372895329.log new file mode 100644 index 0000000..c35eeee --- /dev/null +++ b/.kotlin/errors/errors-1768372895329.log @@ -0,0 +1,114 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt:20:29: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl.acceptChildren(FirAnonymousFunctionImpl.kt:70) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunction(AbstractDiagnosticCollectorVisitor.kt:141) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:134) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnonymousFunctionExpression(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression.accept(FirAnonymousFunctionExpression.kt:30) + at org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList.acceptChildren(FirResolvedArgumentList.kt:35) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirVisitor.visitArgumentList(FirVisitor.kt:81) + at org.jetbrains.kotlin.fir.expressions.FirArgumentList.accept(FirArgumentList.kt:25) + at org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl.acceptChildren(FirFunctionCallImpl.kt:55) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitElement(AbstractDiagnosticCollectorVisitor.kt:49) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithCallOrAssignment(AbstractDiagnosticCollectorVisitor.kt:346) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:255) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFunctionCall(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirFunctionCall.accept(FirFunctionCall.kt:41) + at org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl.acceptChildren(FirReturnExpressionImpl.kt:41) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitJump(FirDefaultVisitor.kt:54) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitReturnExpression(FirDefaultVisitor.kt:66) + at org.jetbrains.kotlin.fir.expressions.FirReturnExpression.accept(FirReturnExpression.kt:31) + at org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl.acceptChildren(FirBlockImpl.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:61) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitAnnotationContainer(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitStatement(FirDefaultVisitor.kt:33) + at org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor.visitExpression(FirDefaultVisitor.kt:36) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:209) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitBlock(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.expressions.FirBlock.accept(FirBlock.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:68) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/.kotlin/errors/errors-1768372895334.log b/.kotlin/errors/errors-1768372895334.log new file mode 100644 index 0000000..6b923b1 --- /dev/null +++ b/.kotlin/errors/errors-1768372895334.log @@ -0,0 +1,76 @@ +kotlin version: 2.0.21 +error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /Users/invoke/AndroidStudioProjects/NoteMark/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt:10:5: java.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57) + at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77) + at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319) + at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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) + 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.lang.IllegalArgumentException: source must not be null + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39) + at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50) + at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42) + at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53) + at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28) + at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51) + at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48) + at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30) + at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42) + at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36) + at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34) + ... 33 more + + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 57efd81..e2c6014 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,68 +1,77 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.kotlin.compose) - id("com.google.devtools.ksp") version "2.2.10-2.0.2" - id("dagger.hilt.android.plugin") - id("kotlinx-serialization") + alias(libs.plugins.notemark.android.application) + id("com.google.dagger.hilt.android") + alias(libs.plugins.ksp) } android { namespace = "com.example.notemark" - compileSdk = 35 defaultConfig { - applicationId = "com.example.notemark" - minSdk = 30 - targetSdk = 35 - versionCode = 1 - versionName = "1.0" - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } - - - - buildTypes { - debug { - buildConfigField ("String", "BASE_URL", "\"https://notemark.pl-coding.com/\"") - } - release { - isMinifyEnabled = false - buildConfigField ("String", "BASE_URL", "\"https://notemark.pl-coding.com/\"") - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" - ) - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - kotlin { - compilerOptions { - jvmTarget = JvmTarget.fromTarget("17") - } - } - buildFeatures { - compose = true - buildConfig = true - } } dependencies { - + // --- Android Core & Lifecycle --- implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.lifecycle.viewmodel.compose) + implementation(libs.androidx.core.splashscreen) + + // --- Compose UI Layer --- implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) + implementation(libs.material3.adaptive) + implementation(libs.lottie.compose) + + // --- Internal Modules (Modularized Architecture) --- + // Auth + implementation(projects.auth.data) + implementation(projects.auth.domain) + implementation(projects.auth.presentation) + // Core + implementation(projects.core.data) + implementation(projects.core.domain) + implementation(projects.core.presentation) + // Note + implementation(projects.note.data) + implementation(projects.note.domain) + implementation(projects.note.presentation) + // Releases + implementation(projects.releases.data) + implementation(projects.releases.domain) + implementation(projects.releases.presentation) + + // --- Navigation --- + implementation(libs.navigation.compose) + implementation(libs.kotlinx.serialization.json) + + // --- Dependency Injection (Hilt) --- + implementation(libs.hilt.android) + implementation(libs.hilt.navigation.compose) + ksp(libs.hilt.android.compiler) + ksp(libs.hilt.compiler) + + // --- Networking (Ktor) --- + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.android) + implementation(libs.ktor.client.cio) + implementation(libs.ktor.client.auth) + implementation(libs.ktor.client.logging) + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.serialization) + + // --- Paging & Persistence --- + implementation(libs.androidx.paging.compose) + implementation(libs.androidx.room.paging) + + // --- Testing --- testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) @@ -70,6 +79,7 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) + with(projects) { with(auth) { implementation(data) @@ -92,45 +102,4 @@ dependencies { implementation(presentation) } } - - // splash screen - implementation(libs.androidx.core.splashscreen) - - // icons extension - implementation(libs.androidx.material.icons.extended) - - // type-safe navigation - implementation(libs.navigation.compose) - implementation(libs.kotlinx.serialization.json) - - // adaptive-layout - implementation(libs.material3.adaptive) - - // ktor - implementation (libs.ktor.client.core) - implementation (libs.ktor.client.android) - implementation (libs.ktor.serialization) - implementation(libs.ktor.client.auth) - implementation(libs.ktor.client.content.negotiation) - implementation(libs.ktor.client.core) - implementation(libs.ktor.client.cio) - implementation(libs.ktor.client.logging) - - // hilt - implementation(libs.hilt.android) - ksp(libs.hilt.android.compiler) - ksp(libs.hilt.compiler) - - // paging - implementation(libs.androidx.paging.runtime.ktx) - implementation(libs.androidx.paging.compose) - - // room - implementation (libs.androidx.room.paging) - - // lottie files - implementation(libs.lottie.compose) - - implementation(libs.androidx.lifecycle.runtime.compose) - implementation(libs.androidx.lifecycle.viewmodel.compose) } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/MainActivity.kt b/app/src/main/java/com/example/notemark/MainActivity.kt index c6fbb72..d08073a 100644 --- a/app/src/main/java/com/example/notemark/MainActivity.kt +++ b/app/src/main/java/com/example/notemark/MainActivity.kt @@ -2,13 +2,8 @@ package com.example.notemark import android.os.Bundle import androidx.activity.ComponentActivity -import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import androidx.navigation.NavHostController @@ -24,13 +19,7 @@ class MainActivity : ComponentActivity() { installSplashScreen() super.onCreate(savedInstanceState) - enableEdgeToEdge( - statusBarStyle = SystemBarStyle.light( - Color.Black.hashCode(), - Color.Black.hashCode() - ) - ) - + enableEdgeToEdge() WindowCompat.setDecorFitsSystemWindows(window, false) setContent { diff --git a/app/src/main/java/com/example/notemark/auth/data/remote/api/LoginService.kt b/app/src/main/java/com/example/notemark/auth/data/remote/api/LoginService.kt deleted file mode 100644 index c6a075f..0000000 --- a/app/src/main/java/com/example/notemark/auth/data/remote/api/LoginService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.notemark.auth.data.remote.api - -import com.example.notemark.auth.domain.model.LoginModel -import com.example.notemark.auth.domain.model.LoginResponse - -interface LoginService { - - suspend fun login(body: LoginModel): LoginResponse? - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/data/remote/api/LogoutService.kt b/app/src/main/java/com/example/notemark/auth/data/remote/api/LogoutService.kt deleted file mode 100644 index def0d23..0000000 --- a/app/src/main/java/com/example/notemark/auth/data/remote/api/LogoutService.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.notemark.auth.data.remote.api - -import com.example.notemark.core.factory.AccessTokenResponse - -interface LogoutService { - - suspend fun logout(refreshToken: String): AccessTokenResponse? - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/data/remote/api/RegistrationService.kt b/app/src/main/java/com/example/notemark/auth/data/remote/api/RegistrationService.kt deleted file mode 100644 index 64b43ee..0000000 --- a/app/src/main/java/com/example/notemark/auth/data/remote/api/RegistrationService.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.notemark.auth.data.remote.api - -import com.example.notemark.auth.domain.model.RegistrationModel - -interface RegistrationService { - - suspend fun register(body: RegistrationModel): RegistrationModel? - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/domain/Error.kt b/app/src/main/java/com/example/notemark/auth/domain/Error.kt deleted file mode 100644 index 9679a1f..0000000 --- a/app/src/main/java/com/example/notemark/auth/domain/Error.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.example.notemark.auth.domain - -sealed interface Error \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/domain/UserDataValidator.kt b/app/src/main/java/com/example/notemark/auth/domain/UserDataValidator.kt deleted file mode 100644 index 2ae252e..0000000 --- a/app/src/main/java/com/example/notemark/auth/domain/UserDataValidator.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.example.notemark.auth.domain - -import android.util.Patterns -import com.example.notemark.auth.presentation.util.FormValidation -import com.example.notemark.auth.presentation.util.ValidationResult - -class UserDataValidator { - - fun validatePassword(password: String): Result { - if(password.length < 9) { - return Result.Error(PasswordError.TOO_SHORT) - } - - val hasUppercaseChar = password.any { it.isUpperCase() } - if(!hasUppercaseChar) { - return Result.Error(PasswordError.NO_UPPERCASE) - } - - val hasDigit = password.any { it.isDigit() } - if(!hasDigit) { - return Result.Error(PasswordError.NO_DIGIT) - } - - return Result.Success(Unit) - } - - fun validateEmail(email: String): Result { - val emailPattern = Patterns.EMAIL_ADDRESS.matcher(email).matches() - return if (emailPattern) { - Result.Success(Unit) - } else { - Result.Error(EmailError.INVALID_FORMAT) - } - } - - fun validateUsername(username: String): Result { - if(username.length < 3) { - return Result.Error(UsernameError.TOO_SHORT) - } - if(username.length > 20) { - return Result.Error(UsernameError.TOO_LONG) - } - return Result.Success(Unit) - } - - fun validateRepeatPassword(password: String, repeatPassword: String): Result { - if(password != repeatPassword) { - return Result.Error(PasswordMatchError.PASSWORDS_DO_NOT_MATCH) - } - return Result.Success(Unit) - } - - fun isFormValid( - username: String, - email: String, - password: String, - repeatPassword: String - ): Boolean { - return FormValidation.validateUsername(username) is ValidationResult.Valid && - FormValidation.validateEmail(email) is ValidationResult.Valid && - FormValidation.validatePassword(password) is ValidationResult.Valid && - FormValidation.validateRepeatPassword(password, repeatPassword) is ValidationResult.Valid - } - - enum class PasswordError: Error { - TOO_SHORT, - NO_UPPERCASE, - NO_DIGIT - } - - enum class EmailError: Error { - INVALID_FORMAT, - } - - enum class UsernameError: Error { - TOO_SHORT, - TOO_LONG - } - - enum class PasswordMatchError : Error { - PASSWORDS_DO_NOT_MATCH - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/domain/model/LoginModel.kt b/app/src/main/java/com/example/notemark/auth/domain/model/LoginModel.kt deleted file mode 100644 index 4e9c51c..0000000 --- a/app/src/main/java/com/example/notemark/auth/domain/model/LoginModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.notemark.auth.domain.model - -import kotlinx.serialization.Serializable - -@Serializable -data class LoginModel( - val email: String, - val password: String -) \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/asUiText.kt b/app/src/main/java/com/example/notemark/auth/presentation/asUiText.kt deleted file mode 100644 index a4f4382..0000000 --- a/app/src/main/java/com/example/notemark/auth/presentation/asUiText.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.example.notemark.auth.presentation - -import androidx.annotation.StringRes -import com.example.notemark.R -import com.example.notemark.auth.domain.DataError -import com.example.notemark.auth.domain.Result -import com.example.notemark.auth.presentation.UiText.StringResource - -fun DataError.asUiText(): UiText { - return when (this) { - DataError.Network.REQUEST_TIMEOUT -> StringResource( - R.string.the_request_timed_out - ) - - DataError.Network.TOO_MANY_REQUESTS -> StringResource( - R.string.youve_hit_your_rate_limit - ) - - DataError.Network.NO_INTERNET -> StringResource( - R.string.no_internet - ) - - DataError.Network.SERVER_ERROR -> StringResource( - R.string.server_error - ) - - DataError.Network.UNKNOWN -> StringResource( - R.string.unknown_error - ) - - DataError.Local.DISK_FULL -> StringResource( - R.string.disk_full - ) - - DataError.ValidationErrors.INVALID_FORMAT -> StringResource( - R.string.invalid_format - ) - - DataError.Note.NOTE_IS_NOT_DELETED -> StringResource( - R.string.note_is_not_deleted - ) - } -} - -fun Result.Error<*, DataError>.asErrorUiText(): UiText { - return error.asUiText() -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/login/screens/LoginScreen.kt b/app/src/main/java/com/example/notemark/auth/presentation/login/screens/LoginScreen.kt deleted file mode 100644 index 8f4dda7..0000000 --- a/app/src/main/java/com/example/notemark/auth/presentation/login/screens/LoginScreen.kt +++ /dev/null @@ -1,292 +0,0 @@ -package com.example.notemark.auth.presentation.login.screens - -import android.util.Log -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarDuration -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.SnackbarResult -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.focus.FocusDirection -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import com.example.notemark.auth.presentation.login.vm.LoginState -import com.example.notemark.auth.presentation.login.vm.LoginViewModel -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.auth.presentation.util.isValidEmail -import com.example.notemark.auth.presentation.vm.AuthViewModel -import com.example.notemark.core.components.NoteMarkButton -import com.example.notemark.core.components.NoteMarkLink -import com.example.notemark.core.components.NoteMarkTextField -import com.example.notemark.core.manager.SessionManager -import com.example.notemark.navigation.screens.AuthScreens -import com.example.notemark.navigation.screens.HomeScreens -import kotlinx.coroutines.launch - -@Composable -fun LoginScreen( - navController: NavHostController = rememberNavController(), -) { - val snackbarHostState = remember { SnackbarHostState() } - - Scaffold( - snackbarHost = { - SnackbarHost(hostState = snackbarHostState) - }, - modifier = Modifier.fillMaxSize(), - contentWindowInsets = WindowInsets.statusBars - ) { innerPadding -> - - val rootModifier = Modifier - .fillMaxSize() - .padding(innerPadding) - .clip( - RoundedCornerShape( - topStart = 15.dp, - topEnd = 15.dp - ) - ) - .background(MaterialTheme.colorScheme.surfaceContainerLowest) - .padding( - horizontal = 16.dp, - vertical = 24.dp - ) - .consumeWindowInsets(WindowInsets.navigationBars) - - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) - - when(deviceConfiguration) { - DeviceConfiguration.MOBILE_PORTRAIT -> { - Column( - modifier = rootModifier, - ) { - LoginHeaderSection( - modifier = Modifier.fillMaxWidth() - ) - LoginSheet( - navController = navController, - modifier = Modifier - .fillMaxWidth() - .padding(top = 32.dp), - snackbarHostState = snackbarHostState - ) - } - } - DeviceConfiguration.MOBILE_LANDSCAPE -> { - Row( - modifier = rootModifier - .windowInsetsPadding(WindowInsets.displayCutout) - .padding( - horizontal = 32.dp - ), - horizontalArrangement = Arrangement.spacedBy(32.dp) - ) { - LoginHeaderSection( - modifier = Modifier - .weight(1f) - ) - LoginSheet( - navController = navController, - modifier = Modifier - .weight(1f) - .verticalScroll(rememberScrollState()), - snackbarHostState = snackbarHostState - ) - } - } - DeviceConfiguration.TABLET_PORTRAIT, - DeviceConfiguration.TABLET_LANDSCAPE, - DeviceConfiguration.DESKTOP -> { - Column( - modifier = rootModifier - .verticalScroll(rememberScrollState()) - .padding(top = 48.dp), - verticalArrangement = Arrangement.spacedBy(32.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - LoginHeaderSection( - modifier = Modifier - .widthIn(max = 540.dp), - alignment = Alignment.CenterHorizontally - ) - LoginSheet( - navController = navController, - modifier = Modifier - .widthIn(max = 540.dp), - snackbarHostState = snackbarHostState - ) - } - } - } - } -} - -@Composable -fun LoginHeaderSection( - alignment: Alignment.Horizontal = Alignment.Start, - modifier: Modifier -) { - Column( - modifier = modifier, - horizontalAlignment = alignment - ) { - Text( - text = "Log In", - style = MaterialTheme.typography.titleLarge - ) - Text( - text = "Capture your thoughts and ideas.", - style = MaterialTheme.typography.bodyLarge - ) - } -} - -@Composable -fun LoginSheet( - navController: NavHostController, - modifier: Modifier = Modifier, - snackbarHostState : SnackbarHostState -) { - - val context = LocalContext.current - val sessionManager = SessionManager(context) - val scope = rememberCoroutineScope() - val loginViewModel: LoginViewModel = hiltViewModel() - val authViewModel: AuthViewModel = hiltViewModel() - val state by loginViewModel.loginState.collectAsStateWithLifecycle() - - LaunchedEffect(state) { - when (state) { - is LoginState.Success -> { - authViewModel.refreshAuthState() - navController.navigate(HomeScreens.Home.route) { - popUpTo(0) { - inclusive = true - } - } - loginViewModel.clearState() - } - is LoginState.Error -> { - scope.launch { - val result = snackbarHostState - .showSnackbar( - message = "Invalid login credentials", - actionLabel = "", - duration = SnackbarDuration.Short - ) - when (result) { - SnackbarResult.ActionPerformed -> {} - SnackbarResult.Dismissed -> {} - } - } - } - is LoginState.Idle -> {} - is LoginState.Loading -> {} - } - } - - var email by remember { mutableStateOf("") } - var password by remember { mutableStateOf("") } - var isDisabled by remember { mutableStateOf(true) } - val focusManager = LocalFocusManager.current - - isDisabled = email.isBlank() || password.isBlank() || !isValidEmail(email) - LaunchedEffect(Unit) { - Log.d("sessionManager login", "access token: ${sessionManager.getAccessToken()}") - Log.d("sessionManager login", "refresh token: ${sessionManager.getRefreshToken()}") - } - - Column( - modifier = modifier - ) { - NoteMarkTextField( - text = email, - onValueChange = { email = it }, - label = "Email", - hint = "john.doe@example.com", - isInputSecret = false, - modifier = Modifier.fillMaxWidth(), - focusManager = focusManager, - focusDirection = FocusDirection.Down, - imeAction = ImeAction.Next, - ) - - Spacer(modifier = Modifier.height(16.dp)) - - NoteMarkTextField( - text = password, - onValueChange = { password = it }, - label = "Password", - hint = "Password", - isInputSecret = true, - modifier = Modifier.fillMaxWidth(), - focusManager = focusManager, - focusDirection = FocusDirection.Down, - imeAction = ImeAction.Done, - ) - - Spacer(modifier = Modifier.height(24.dp)) - - NoteMarkButton( - text = if (state is LoginState.Loading) "" else "Log in", - onClick = { - loginViewModel.loginUser(email, password) - }, - modifier = Modifier.fillMaxWidth(), - enabled = !isDisabled, - isLoading = state is LoginState.Loading - ) - - Spacer(modifier = Modifier.height(24.dp)) - - NoteMarkLink( - text = "Don't have an account?", - onClick = { - navController.navigate(AuthScreens.Registration.route) { - popUpTo(AuthScreens.LogIn.route) { - inclusive = true - } - } - }, - modifier = Modifier.fillMaxWidth() - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/registration/screens/RegistrationScreen.kt b/app/src/main/java/com/example/notemark/auth/presentation/registration/screens/RegistrationScreen.kt deleted file mode 100644 index 02d0afc..0000000 --- a/app/src/main/java/com/example/notemark/auth/presentation/registration/screens/RegistrationScreen.kt +++ /dev/null @@ -1,319 +0,0 @@ -package com.example.notemark.auth.presentation.registration.screens - -import android.util.Log -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarDuration -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.SnackbarResult -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusDirection -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import com.example.notemark.auth.presentation.registration.vm.RegistrationState -import com.example.notemark.auth.presentation.registration.vm.RegistrationViewModel -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.auth.presentation.util.FormValidation -import com.example.notemark.auth.presentation.util.ValidationResult -import com.example.notemark.core.components.NoteMarkButton -import com.example.notemark.core.components.NoteMarkLink -import com.example.notemark.core.components.NoteMarkTextField -import com.example.notemark.navigation.screens.AuthScreens -import kotlinx.coroutines.launch - -@Composable -fun RegistrationScreen( - navController: NavHostController = rememberNavController(), -) { - val snackbarHostState = remember { SnackbarHostState() } - - Scaffold( - modifier = Modifier.fillMaxSize(), - contentWindowInsets = WindowInsets.statusBars, - snackbarHost = { - SnackbarHost(hostState = snackbarHostState) - }, - ) { innerPadding -> - - val rootModifier = Modifier - .fillMaxSize() - .padding(innerPadding) - .background( - color = MaterialTheme.colorScheme.surfaceContainerLowest, - shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) - ) - .padding(horizontal = 16.dp, vertical = 24.dp) - .consumeWindowInsets(WindowInsets.navigationBars) - - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) - - when(deviceConfiguration) { - DeviceConfiguration.MOBILE_PORTRAIT -> { - Column( - modifier = rootModifier, - ) { - RegistrationHeader( - modifier = Modifier.fillMaxWidth() - ) - RegistrationSheet( - navController = navController, - modifier = Modifier - .fillMaxWidth() - .padding(top = 32.dp), - snackbarHostState = snackbarHostState - ) - } - } - DeviceConfiguration.MOBILE_LANDSCAPE -> { - Row( - modifier = rootModifier - .windowInsetsPadding(WindowInsets.displayCutout) - .padding( - horizontal = 32.dp - ), - horizontalArrangement = Arrangement.spacedBy(32.dp) - ) { - RegistrationHeader( - modifier = Modifier - .weight(1f) - ) - RegistrationSheet( - navController = navController, - modifier = Modifier - .weight(1f) - .verticalScroll(rememberScrollState()), - snackbarHostState = snackbarHostState - ) - } - } - DeviceConfiguration.TABLET_PORTRAIT, - DeviceConfiguration.TABLET_LANDSCAPE, - DeviceConfiguration.DESKTOP -> { - Column( - modifier = rootModifier - .verticalScroll(rememberScrollState()) - .padding(top = 48.dp), - verticalArrangement = Arrangement.spacedBy(32.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - RegistrationHeader( - modifier = Modifier - .widthIn(max = 540.dp), - alignment = Alignment.CenterHorizontally - ) - RegistrationSheet( - navController = navController, - modifier = Modifier - .widthIn(max = 540.dp), - snackbarHostState = snackbarHostState - ) - } - } - } - } -} - -@Composable -private fun RegistrationHeader( - modifier: Modifier = Modifier, - alignment: Alignment.Horizontal = Alignment.Start -) { - Column( - modifier = modifier, - horizontalAlignment = alignment - ) { - Text( - text = "Create account", - style = MaterialTheme.typography.titleLarge - ) - - Spacer(modifier = Modifier.height(8.dp)) - - Text( - text = "Capture your thoughts and ideas.", - style = MaterialTheme.typography.bodyLarge - ) - } -} - -@Composable -fun RegistrationSheet( - navController: NavHostController, - modifier: Modifier = Modifier, - snackbarHostState : SnackbarHostState -) { - val scope = rememberCoroutineScope() - val registrationViewModel: RegistrationViewModel = hiltViewModel() - val registrationState by registrationViewModel.registrationState - - var username by remember { mutableStateOf("") } - var email by remember { mutableStateOf("") } - var password by remember { mutableStateOf("") } - var repeatPassword by remember { mutableStateOf("") } - val focusManager = LocalFocusManager.current - - LaunchedEffect(registrationState) { - when(registrationState) { - is RegistrationState.Success -> { - navController.navigate(AuthScreens.LogIn.route) { - popUpTo(AuthScreens.Registration.route) { - inclusive = true - } - } - registrationViewModel.clearState() - } - is RegistrationState.Error -> { - Log.e("RegistrationScreen", "Registration failed: ${(registrationState as RegistrationState.Error).message}") - scope.launch { - val result = snackbarHostState - .showSnackbar( - message = "Invalid registration credentials: ${(registrationState as RegistrationState.Error).message}", - actionLabel = "", - duration = SnackbarDuration.Short - ) - when (result) { - SnackbarResult.ActionPerformed -> {} - SnackbarResult.Dismissed -> {} - } - } - } - RegistrationState.Idle -> {} - RegistrationState.Loading -> {} - } - } - - - - val usernameValidation = FormValidation.validateUsername(username) - val emailValidation = FormValidation.validateEmail(email) - val passwordValidation = FormValidation.validatePassword(password) - val repeatPasswordValidation = FormValidation.validateRepeatPassword(password, repeatPassword) - - val isFormValid = FormValidation.isFormValid(username, email, password, repeatPassword) - - Column( - modifier = modifier - .fillMaxSize() - .padding(top = 24.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - NoteMarkTextField( - text = username, - onValueChange = { username = it }, - label = "Username", - hint = "Enter username", - isInputSecret = false, - focusManager = focusManager, - focusDirection = FocusDirection.Down, - imeAction = ImeAction.Next, - errorText = if (usernameValidation is ValidationResult.Error) usernameValidation.message else null, - isError = usernameValidation is ValidationResult.Error, - showFocusText = "Use between 3 and 20 characters for your username." - ) - - NoteMarkTextField( - text = email, - onValueChange = { email = it }, - label = "Email", - hint = "Enter email", - isInputSecret = false, - focusManager = focusManager, - focusDirection = FocusDirection.Down, - imeAction = ImeAction.Next, - errorText = if (emailValidation is ValidationResult.Error) emailValidation.message else null, - isError = emailValidation is ValidationResult.Error - ) - - NoteMarkTextField( - text = password, - onValueChange = { password = it }, - label = "Password", - hint = "Enter password", - isInputSecret = true, - focusManager = focusManager, - focusDirection = FocusDirection.Down, - imeAction = ImeAction.Next, - errorText = if (passwordValidation is ValidationResult.Error) passwordValidation.message else null, - isError = passwordValidation is ValidationResult.Error, - showFocusText = "Use 8+ characters with a number or symbol for better security." - ) - - NoteMarkTextField( - text = repeatPassword, - onValueChange = { repeatPassword = it }, - label = "Repeat Password", - hint = "Repeat password", - isInputSecret = true, - focusManager = focusManager, - focusDirection = FocusDirection.Down, - imeAction = ImeAction.Done, - errorText = if (repeatPasswordValidation is ValidationResult.Error) repeatPasswordValidation.message else null, - isError = repeatPasswordValidation is ValidationResult.Error - ) - - Spacer(modifier = Modifier.height(16.dp)) - - NoteMarkButton( - text = if (registrationState is RegistrationState.Loading) "" else "Create account", - onClick = { - registrationViewModel.registerUser( - username = username, - email = email, - password = password - ) - }, - enabled = isFormValid, - modifier = Modifier.fillMaxWidth(), - isLoading = registrationState is RegistrationState.Loading - ) - - Spacer(modifier = Modifier.height(8.dp)) - - NoteMarkLink( - text = "Already have an account?", - onClick = { - navController.navigate(AuthScreens.LogIn.route) { - popUpTo(AuthScreens.Registration.route) { - inclusive = true - } - } - }, - modifier = Modifier.fillMaxWidth() - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/util/DeviceConfiguration.kt b/app/src/main/java/com/example/notemark/auth/presentation/util/DeviceConfiguration.kt deleted file mode 100644 index 3ce6688..0000000 --- a/app/src/main/java/com/example/notemark/auth/presentation/util/DeviceConfiguration.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.notemark.auth.presentation.util - -import androidx.window.core.layout.WindowHeightSizeClass -import androidx.window.core.layout.WindowSizeClass -import androidx.window.core.layout.WindowWidthSizeClass - -enum class DeviceConfiguration { - MOBILE_PORTRAIT, - MOBILE_LANDSCAPE, - TABLET_PORTRAIT, - TABLET_LANDSCAPE, - DESKTOP; - - companion object { - fun fromWindowSizeClass(windowSizeClass: WindowSizeClass): DeviceConfiguration { - val widthClass = windowSizeClass.windowWidthSizeClass - val heightClass = windowSizeClass.windowHeightSizeClass - - return when { - widthClass == WindowWidthSizeClass.COMPACT && - heightClass == WindowHeightSizeClass.MEDIUM -> MOBILE_PORTRAIT - widthClass == WindowWidthSizeClass.COMPACT && - heightClass == WindowHeightSizeClass.EXPANDED -> MOBILE_PORTRAIT - widthClass == WindowWidthSizeClass.EXPANDED && - heightClass == WindowHeightSizeClass.COMPACT -> MOBILE_LANDSCAPE - widthClass == WindowWidthSizeClass.MEDIUM && - heightClass == WindowHeightSizeClass.EXPANDED -> TABLET_PORTRAIT - widthClass == WindowWidthSizeClass.EXPANDED && - heightClass == WindowHeightSizeClass.MEDIUM -> TABLET_LANDSCAPE - else -> DESKTOP - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/util/isValidEmail.kt b/app/src/main/java/com/example/notemark/auth/presentation/util/isValidEmail.kt deleted file mode 100644 index 224a495..0000000 --- a/app/src/main/java/com/example/notemark/auth/presentation/util/isValidEmail.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.example.notemark.auth.presentation.util - -fun isValidEmail(email: String): Boolean = android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/di/AuthModule.kt b/app/src/main/java/com/example/notemark/core/di/AuthModule.kt deleted file mode 100644 index d837689..0000000 --- a/app/src/main/java/com/example/notemark/core/di/AuthModule.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.example.notemark.core.di - -import android.content.Context -import com.example.notemark.auth.data.remote.api.LoginService -import com.example.notemark.auth.data.remote.api.LogoutService -import com.example.notemark.auth.data.remote.repositoryImpl.LogoutServiceImpl -import com.example.notemark.auth.data.remote.api.RegistrationService -import com.example.notemark.auth.data.remote.repositoryImpl.LoginServiceImpl -import com.example.notemark.auth.data.remote.repositoryImpl.RegistrationServiceImpl -import com.example.notemark.auth.domain.UserDataValidator -import com.example.notemark.core.manager.SessionManager -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import io.ktor.client.HttpClient -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object AuthModule { - - @Provides - @Singleton - fun provideSessionManager(@ApplicationContext context: Context): SessionManager = SessionManager(context) - - - @Provides - @Singleton - fun provideRegistrationService(client: HttpClient): RegistrationService = RegistrationServiceImpl(client) - - @Provides - @Singleton - fun provideLoginService(client: HttpClient): LoginService = LoginServiceImpl(client) - - @Provides - @Singleton - fun provideLogoutService(client: HttpClient): LogoutService = LogoutServiceImpl(client) - - @Provides - @Singleton - fun provideUserDataValidator(): UserDataValidator = UserDataValidator() -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/manager/SessionManager.kt b/app/src/main/java/com/example/notemark/core/manager/SessionManager.kt deleted file mode 100644 index 1343daf..0000000 --- a/app/src/main/java/com/example/notemark/core/manager/SessionManager.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.example.notemark.core.manager - -import android.content.Context -import android.content.SharedPreferences - -class SessionManager( - private val context: Context -) { - - companion object { - const val PREF_NAME = "NoteMarkPrefs" - const val ACCESS_TOKEN = "access_token" - const val REFRESH_TOKEN = "refresh_token" - const val USER_NAME = "user_name" - } - - private val sharedPrefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - private val editor: SharedPreferences.Editor = sharedPrefs.edit() - - - // we are not using commit() because it's synchronous, so we don't need to wait for the result - // we use apply() because it's asynchronous and saves the data asynchronously - fun saveTokens(accessToken: String, refreshToken: String) { - sharedPrefs.edit().apply { - putString(ACCESS_TOKEN, accessToken) - putString(REFRESH_TOKEN, refreshToken) - apply() - } - } - - fun saveUserName(userName: String) { - sharedPrefs.edit().apply { - putString(USER_NAME, userName) - apply() - } - } - - fun getUserName(): String? = sharedPrefs.getString(USER_NAME, null) - - fun clearUserName() { - editor.apply { - remove(USER_NAME) - apply() - } - } - - fun getAccessToken(): String? = sharedPrefs.getString(ACCESS_TOKEN, null) - - fun getRefreshToken(): String? = sharedPrefs.getString(REFRESH_TOKEN, null) - - fun clearTokens() { - sharedPrefs.edit().apply { - remove(ACCESS_TOKEN) - remove(REFRESH_TOKEN) - apply() - } - } - - fun isLoggedIn(): Boolean = !getAccessToken().isNullOrEmpty() -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/local/NoteDatabase.kt b/app/src/main/java/com/example/notemark/main/data/local/NoteDatabase.kt deleted file mode 100644 index 9a9b9c7..0000000 --- a/app/src/main/java/com/example/notemark/main/data/local/NoteDatabase.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.notemark.main.data.local - -import androidx.room.Database -import androidx.room.RoomDatabase -import com.example.notemark.main.presentation.screens.note.SyncRecord - -@Database( - entities = [NoteEntity::class, SyncRecord::class], - version = 3 -) -abstract class NoteDatabase: RoomDatabase() { - abstract val dao: NoteDao - abstract val syncDao: SyncDao -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/local/SyncDao.kt b/app/src/main/java/com/example/notemark/main/data/local/SyncDao.kt deleted file mode 100644 index a41c361..0000000 --- a/app/src/main/java/com/example/notemark/main/data/local/SyncDao.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.example.notemark.main.data.local - -import androidx.room.Dao -import androidx.room.Query -import androidx.room.Upsert -import com.example.notemark.main.presentation.screens.note.SyncRecord - -@Dao -interface SyncDao { - @Upsert - suspend fun insertSyncRecord(record: SyncRecord) - - @Query("DELETE FROM syncrecord WHERE id = :id") - suspend fun deleteSyncRecord(id: String) - - @Query("SELECT * FROM syncrecord WHERE userId = :userId") - suspend fun getAllSyncRecords(userId: String): List -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/remote/NoteMappers.kt b/app/src/main/java/com/example/notemark/main/data/remote/NoteMappers.kt deleted file mode 100644 index 7d41674..0000000 --- a/app/src/main/java/com/example/notemark/main/data/remote/NoteMappers.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.example.notemark.main.data.remote - -import com.example.notemark.main.data.local.NoteEntity -import com.example.notemark.main.domain.model.Note -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.domain.model.NotesResponse - -fun NoteDTO.toNoteEntity(): NoteEntity { - return NoteEntity( - id = id, - title = title, - content = content, - createdAt = createdAt, - updatedAt = updatedAt - ) -} - - -fun NoteEntity.toNote(): Note { - return Note( - id = id, - title = title, - content = content, - createdAt = createdAt, - updatedAt = updatedAt - ) -} - -fun NoteEntity.toNoteDTO(): NoteDTO { - return NoteDTO( - id = id, - title = title, - content = content, - createdAt = createdAt, - updatedAt = updatedAt - ) -} - -fun NoteRequest.toNotEntity(): NoteEntity { - return NoteEntity( - id = id, - title = title, - content = content, - createdAt = createdAt, - updatedAt = updatedAt - ) -} - -fun NotesResponse.toNoteEntityList(): List { - return this.notes.map { it.toNoteEntity() } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/remote/api/NoteService.kt b/app/src/main/java/com/example/notemark/main/data/remote/api/NoteService.kt deleted file mode 100644 index f94071f..0000000 --- a/app/src/main/java/com/example/notemark/main/data/remote/api/NoteService.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.example.notemark.main.data.remote.api - -import com.example.notemark.main.data.remote.NoteDTO -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.domain.model.NotesResponse - -interface NoteService { - - suspend fun getNotes( - page: Int, - size: Int, - ): NotesResponse - - suspend fun createNote( - body: NoteRequest - ): Result - - suspend fun updateNote( - body: NoteRequest - ): Result - - suspend fun deleteNote( - id: String - ): Result -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/domain/model/Note.kt b/app/src/main/java/com/example/notemark/main/domain/model/Note.kt deleted file mode 100644 index f098b7d..0000000 --- a/app/src/main/java/com/example/notemark/main/domain/model/Note.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.example.notemark.main.domain.model - -import com.example.notemark.main.formatAsDetailsDate -import com.example.notemark.main.formatAsNoteDate -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class Note( - val id: String, - val title: String, - val content: String, - val createdAt: String, - @SerialName("lastEditedAt") - val updatedAt: String? = "" -) - -fun Note.getFormattedCreatedAt(): String = createdAt.formatAsNoteDate() -fun Note.getFormattedUpdatedAt(): String = updatedAt?.formatAsDetailsDate() ?: "" \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/domain/model/NoteRequest.kt b/app/src/main/java/com/example/notemark/main/domain/model/NoteRequest.kt deleted file mode 100644 index d5b51ad..0000000 --- a/app/src/main/java/com/example/notemark/main/domain/model/NoteRequest.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.example.notemark.main.domain.model - -import com.example.notemark.main.DateFormatter -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class NoteRequest( - val id: String, - val title: String, - val content: String, - val createdAt: String = DateFormatter.getCurrentIsoString(), - @SerialName("lastEditedAt") - val updatedAt: String? = DateFormatter.getCurrentIsoString() -) \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/domain/repository/NotesRepository.kt b/app/src/main/java/com/example/notemark/main/domain/repository/NotesRepository.kt deleted file mode 100644 index f3b8dc4..0000000 --- a/app/src/main/java/com/example/notemark/main/domain/repository/NotesRepository.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.example.notemark.main.domain.repository - -import com.example.notemark.main.data.remote.NoteDTO -import com.example.notemark.main.data.remote.repositoryImpl.NoteServiceImpl -import com.example.notemark.main.domain.model.NoteRequest -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow - -class NotesRepository( - private val api: NoteServiceImpl -) { - - fun createNote( - body: NoteRequest - ) : Flow> = flow { - emit(api.createNote(body)) - } - - fun updateNote( - body: NoteRequest - ) : Flow> = flow { - emit(api.updateNote(body)) - } - - suspend fun deleteNote(noteId: String): Result { - return api.deleteNote(noteId) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/Profile.kt b/app/src/main/java/com/example/notemark/main/presentation/screens/Profile.kt deleted file mode 100644 index 66aaee8..0000000 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/Profile.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.notemark.main.presentation.screens - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController - -@Composable -fun ProfileScreen( - navController: NavHostController = rememberNavController() -) { - Scaffold( - topBar = {} - ) { innerPadding -> - Column( - modifier = Modifier.padding(innerPadding) - ) { - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/Settings.kt b/app/src/main/java/com/example/notemark/main/presentation/screens/Settings.kt deleted file mode 100644 index 90e77da..0000000 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/Settings.kt +++ /dev/null @@ -1,408 +0,0 @@ -package com.example.notemark.main.presentation.screens - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import com.example.notemark.R -import com.example.notemark.auth.presentation.login.vm.LoginViewModel -import com.example.notemark.auth.presentation.login.vm.LogoutState -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.core.manager.SessionManager -import com.example.notemark.main.presentation.vm.NotesViewModel -import com.example.notemark.navigation.screens.AuthScreens - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun SettingsScreen( - navController: NavHostController = rememberNavController() -) { - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) - - when(deviceConfiguration) { - DeviceConfiguration.MOBILE_PORTRAIT -> { - SettingsItem( - navController, - - ) - } - DeviceConfiguration.MOBILE_LANDSCAPE -> { - SettingsItem( - navController, - - ) - } - DeviceConfiguration.TABLET_PORTRAIT, - DeviceConfiguration.TABLET_LANDSCAPE, - DeviceConfiguration.DESKTOP -> { - SettingsItem( - navController, - ) - } - } -} - -@Composable -@OptIn(ExperimentalMaterial3Api::class) -private fun SettingsItem( - navController: NavHostController, -) { - val context = LocalContext.current - val sessionManager = SessionManager(context) - val refreshToken = sessionManager.getRefreshToken() - val loginViewModel: LoginViewModel = hiltViewModel() - val notesViewModel: NotesViewModel = hiltViewModel() - var showSyncIntervalDropdown by remember { mutableStateOf(false) } - val logoutState by loginViewModel.logoutState.collectAsStateWithLifecycle() - var selectedSyncInterval by remember { mutableStateOf(SyncInterval.MANUAL_ONLY) } - - LaunchedEffect(logoutState) { - when (logoutState) { - is LogoutState.Error -> { - Toast.makeText( - context, - (logoutState as LogoutState.Error).message, - Toast.LENGTH_SHORT - ).show() - loginViewModel.clearState() - } - - is LogoutState.Success -> { - notesViewModel.clear() - navController.navigate(AuthScreens.Landing.route) { - popUpTo(0) { - inclusive = true - } - } - loginViewModel.clearState() - } - LogoutState.Loading, - LogoutState.Idle -> {} - } - } - - Scaffold( - topBar = { - TopAppBar( - title = { - Text( - text = stringResource(R.string.settings).uppercase(), - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 1.0.sp, - fontFamily = FontFamily(Font(R.font.space_grotesk_regular)), - ) - }, - navigationIcon = { - IconButton( - onClick = { navController.navigateUp() } - ) { - Icon( - tint = MaterialTheme.colorScheme.onSurfaceVariant, - imageVector = ImageVector.vectorResource(R.drawable.ios_arrow_left), - contentDescription = "Navigate up" - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.surface - ) - ) - } - ) { innerPadding -> - Column( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) - .padding(innerPadding) - ) { - - if (logoutState is LogoutState.Loading) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator() - } - } else { - SettingsContent( - onLogoutClick = { - loginViewModel.logoutUser(refreshToken = refreshToken ?: "") - }, - onSyncClick = { - Toast.makeText( - context, - "This page is not available yet!", - Toast.LENGTH_SHORT - ).show() - }, - onSyncIntervalClick = { - showSyncIntervalDropdown = true - }, - showSyncIntervalDropdown = showSyncIntervalDropdown, - onDismissSyncIntervalDropdown = { - showSyncIntervalDropdown = false - }, - selectedSyncInterval = selectedSyncInterval, - onSyncIntervalSelected = { interval -> - selectedSyncInterval = interval - showSyncIntervalDropdown = false - } - ) - } - } - } -} - -// Enum for sync intervals -enum class SyncInterval(val displayName: String) { - MANUAL_ONLY("Manual Only"), - EVERY_15_MINUTES("15 minutes"), - EVERY_30_MINUTES("30 minutes"), - EVERY_HOUR("1 hour") -} - -@Composable -private fun SettingsContent( - onLogoutClick: () -> Unit, - onSyncClick: () -> Unit, - onSyncIntervalClick: () -> Unit, - showSyncIntervalDropdown: Boolean, - onDismissSyncIntervalDropdown: () -> Unit, - selectedSyncInterval: SyncInterval, - onSyncIntervalSelected: (SyncInterval) -> Unit -) { - SingleItem( - onEndIconAndTextClick = onSyncIntervalClick, - supportingText = null, - headline = stringResource(R.string.sync_interval), - headlineTextColor = MaterialTheme.colorScheme.onSurface, - leadingIcon = ImageVector.vectorResource(R.drawable.clock), - iconTint = MaterialTheme.colorScheme.onSurfaceVariant, - endIcon = ImageVector.vectorResource(R.drawable.chevron_right), - endIconTint = MaterialTheme.colorScheme.onSurfaceVariant, - endText = selectedSyncInterval.displayName, - endTextColor = MaterialTheme.colorScheme.onSurfaceVariant, - showDropdown = showSyncIntervalDropdown, - onDismissDropdown = onDismissSyncIntervalDropdown, - dropdownContent = { - SyncInterval.entries.forEach { interval -> - DropdownMenuItem( - modifier = Modifier - .width(190.dp) - .background( - color = MaterialTheme.colorScheme.surface, - shape = RoundedCornerShape(16.dp) - ), - text = { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = interval.displayName - ) - - if (interval == selectedSyncInterval) { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.check), - contentDescription = null, - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(20.dp) - ) - } - } - }, - onClick = { - onSyncIntervalSelected(interval) - } - ) - } - } - ) - - SingleItem( - onClick = onSyncClick, - supportingText = stringResource(R.string.last_sync), - headline = stringResource(R.string.sync_data), - headlineTextColor = MaterialTheme.colorScheme.onSurface, - supportingTextColor = MaterialTheme.colorScheme.onSurfaceVariant, - leadingIcon = ImageVector.vectorResource(R.drawable.sync_icon), - iconTint = MaterialTheme.colorScheme.onSurfaceVariant, - endIcon = null, - endIconTint = null, - endText = null, - endTextColor = null - ) - - SingleItem( - onClick = onLogoutClick, - headline = stringResource(R.string.logout), - supportingText = null, - headlineTextColor = MaterialTheme.colorScheme.error, - supportingTextColor = null, - leadingIcon = ImageVector.vectorResource(R.drawable.logout), - iconTint = MaterialTheme.colorScheme.error, - endIcon = null, - endIconTint = null, - endText = null, - endTextColor = null - ) -} - -@Composable -private fun SingleItem( - modifier: Modifier = Modifier, - onEndIconAndTextClick: (() -> Unit)? = null, - onClick: (() -> Unit)? = null, - supportingText: String? = null, - supportingTextColor: Color? = null, - headline: String, - headlineTextColor: Color, - leadingIcon: ImageVector? = null, - iconTint: Color? = null, - endIcon: ImageVector? = null, - endIconTint: Color? = null, - endText: String? = null, - endTextColor: Color? = null, - showDropdown: Boolean = false, - onDismissDropdown: (() -> Unit)? = null, - dropdownContent: (@Composable ColumnScope.() -> Unit)? = null, -) { - Row( - modifier = modifier - .fillMaxWidth() - .heightIn(min = 56.dp) - .padding(horizontal = 16.dp, vertical = 8.dp) - .then( - if (onClick != null) { - Modifier.clickable { onClick() } - } else { - Modifier - } - ), - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - - leadingIcon?.let { icon -> - Icon( - imageVector = icon, - contentDescription = null, - tint = iconTint ?: MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - - Column( - modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.Start - ) { - Text( - text = headline, - style = MaterialTheme.typography.titleSmall.copy( - color = headlineTextColor - ) - ) - - if (!supportingText.isNullOrBlank()) { - Text( - text = supportingText, - style = MaterialTheme.typography.bodySmall.copy( - color = supportingTextColor ?: MaterialTheme.colorScheme.onSurfaceVariant - ) - ) - } - } - - val hasEndContent = !endText.isNullOrBlank() || endIcon != null - if (hasEndContent) { - Box { - Row( - modifier = Modifier.then( - if (onEndIconAndTextClick != null) { - Modifier.clickable { onEndIconAndTextClick() } - } else { - Modifier - } - ), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - if (!endText.isNullOrBlank()) { - Text( - text = endText, - style = MaterialTheme.typography.bodySmall.copy( - color = endTextColor ?: MaterialTheme.colorScheme.onSurfaceVariant - ) - ) - } - - endIcon?.let { icon -> - Icon( - imageVector = icon, - contentDescription = null, - tint = endIconTint ?: MaterialTheme.colorScheme.onSurfaceVariant - ) - } - } - - if (dropdownContent != null) { - DropdownMenu( - expanded = showDropdown, - onDismissRequest = onDismissDropdown ?: {} - ) { - dropdownContent() - } - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/note/Details.kt b/app/src/main/java/com/example/notemark/main/presentation/screens/note/Details.kt deleted file mode 100644 index a3b0578..0000000 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/note/Details.kt +++ /dev/null @@ -1,600 +0,0 @@ -package com.example.notemark.main.presentation.screens.note - -import android.app.Activity -import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import androidx.paging.compose.LazyPagingItems -import com.example.notemark.R -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.main.domain.model.Note -import com.example.notemark.main.domain.model.getFormattedUpdatedAt -import com.example.notemark.main.presentation.vm.DetailsViewModel -import com.example.notemark.navigation.screens.HomeScreens - - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun DetailsScreen( - navController: NavHostController = rememberNavController(), - noteId: String? = null, - notes: LazyPagingItems -) { - val note = notes.itemSnapshotList.items.find { it.id == noteId } - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) - - when(deviceConfiguration) { - DeviceConfiguration.MOBILE_PORTRAIT -> { - DetailsContent( - modifier = Modifier, - navController = navController, - note = note, - noteId = noteId, - ) - } - DeviceConfiguration.MOBILE_LANDSCAPE -> { - LandscapeDetailsScreenContent( - modifier = Modifier - .windowInsetsPadding(WindowInsets.displayCutout) - .consumeWindowInsets(WindowInsets.navigationBars), - navController = navController, - note = note, - noteId = noteId, - ) - } - DeviceConfiguration.TABLET_PORTRAIT, - DeviceConfiguration.TABLET_LANDSCAPE -> { - LandscapeDetailsScreenContent( - modifier = Modifier - .windowInsetsPadding(WindowInsets.displayCutout) - .consumeWindowInsets(WindowInsets.navigationBars), - navController = navController, - note = note, - noteId = noteId, - ) - } - DeviceConfiguration.DESKTOP -> { - DetailsContent( - modifier = Modifier, - navController = navController, - note = note, - noteId = noteId, - ) - } - } -} - -@Composable -fun LandscapeDetailsScreenContent( - modifier: Modifier, - navController: NavHostController, - note: Note?, - noteId: String? -) { - val context = LocalContext.current - val activity = context as Activity - val scrollState = rememberScrollState() - val viewModel: DetailsViewModel = viewModel() - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - LaunchedEffect(uiState.requestedOrientation) { - uiState.requestedOrientation?.let { orientation -> - activity.requestedOrientation = orientation - viewModel.onOrientationHandled() - } - } - - LaunchedEffect(Unit) { - viewModel.setOriginalOrientation(activity.requestedOrientation) - } - - BackHandler(enabled = uiState.isReaderMode) { - viewModel.toggleReaderMode() - } - - LaunchedEffect(scrollState.value) { - if (scrollState.isScrollInProgress) { - viewModel.onScrollDetected() - } - } - - Box( - modifier = modifier.fillMaxSize() - ) { - // Main content - this stays in place - Row( - modifier = Modifier - .fillMaxSize() - .padding(start = 80.dp) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - viewModel.onScreenTap() - } - ) { - // Left spacer to account for back button (keep content centered) - Spacer(modifier = Modifier.width(64.dp)) // Adjust based on your back button width - - // Content area - Box( - modifier = Modifier - .fillMaxSize() - .padding(top = 24.dp, bottom = 80.dp) // Add bottom padding for FAB - ) { - if (note != null && note.id == noteId) { - Column( - modifier = Modifier.verticalScroll(scrollState) - ) { - Text( - text = note.title, - style = MaterialTheme.typography.titleLarge.copy( - color = MaterialTheme.colorScheme.onSurface, - ), - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - ) - - HorizontalDivider() - - Row( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - ) { - Column( - modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Text( - text = stringResource(R.string.date_created), - style = MaterialTheme.typography.bodySmall.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - ) - Text( - text = note.getFormattedUpdatedAt(), - style = MaterialTheme.typography.titleSmall.copy( - color = MaterialTheme.colorScheme.onSurface, - fontWeight = FontWeight.Bold - ) - ) - } - if (!note.getFormattedUpdatedAt().isEmpty()) { - Column( - modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Text( - text = stringResource(R.string.last_edited), - style = MaterialTheme.typography.bodySmall.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - ) - Text( - text = note.getFormattedUpdatedAt(), - style = MaterialTheme.typography.titleSmall.copy( - color = MaterialTheme.colorScheme.onSurface, - fontWeight = FontWeight.Bold - ) - ) - } - } - } - - HorizontalDivider() - - Text( - text = note.content, - style = MaterialTheme.typography.bodyLarge.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - ), - modifier = Modifier - .fillMaxWidth() - .padding( - if (uiState.isReaderMode && !uiState.isUiVisible) { - PaddingValues(horizontal = 16.dp, vertical = 32.dp) - } else { - PaddingValues(horizontal = 16.dp, vertical = 32.dp) - } - ) - ) - } - } else { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator() - } - } - } - } - - // Back button overlay - positioned absolutely at top-left - AnimatedVisibility( - visible = !uiState.isReaderMode || uiState.isUiVisible, - enter = fadeIn(animationSpec = tween(300)) + slideInVertically( - animationSpec = tween(300) - ) { -it }, - exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( - animationSpec = tween(300) - ) { -it }, - modifier = Modifier - .align(Alignment.TopStart) - .padding(top = 24.dp) - ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - IconButton( - onClick = { - if (uiState.isReaderMode) viewModel.toggleReaderMode() else navController.popBackStack() - } - ) { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.ios_arrow_left), - contentDescription = "Navigate up", - tint = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - - Spacer(modifier = Modifier.width(8.dp)) - - Text( - text = stringResource(R.string.all_notes).uppercase(), - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 1.0.sp, - fontFamily = FontFamily(Font(R.font.space_grotesk_regular)), - ) - } - } - - // FAB overlay - positioned absolutely at bottom-center - AnimatedVisibility( - visible = !uiState.isReaderMode || uiState.isUiVisible, - enter = fadeIn(animationSpec = tween(300)) + slideInVertically( - animationSpec = tween(300) - ) { it }, - exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( - animationSpec = tween(300) - ) { it }, - modifier = Modifier.align(Alignment.BottomCenter) - ) { - ExtendedFabFSheet( - onEditClick = { - navController.navigate( - HomeScreens.EditNote( - noteId = noteId ?: "" - ) - ) - }, - onReaderModeClick = { viewModel.toggleReaderMode() }, - isReaderMode = uiState.isReaderMode - ) - } - } -} - -@Composable -@OptIn(ExperimentalMaterial3Api::class) -private fun DetailsContent( - modifier: Modifier, - navController: NavHostController, - note: Note?, - noteId: String?, -) { - val context = LocalContext.current - val activity = context as Activity - - val scrollState = rememberScrollState() - val viewModel: DetailsViewModel = viewModel() - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - LaunchedEffect(uiState.requestedOrientation) { - uiState.requestedOrientation?.let { orientation -> - activity.requestedOrientation = orientation - viewModel.onOrientationHandled() - } - } - - LaunchedEffect(Unit) { - viewModel.setOriginalOrientation(activity.requestedOrientation) - } - - BackHandler(enabled = uiState.isReaderMode) { - viewModel.toggleReaderMode() - } - - LaunchedEffect(scrollState.value) { - if (scrollState.isScrollInProgress) { - viewModel.onScrollDetected() - } - } - - Scaffold( - topBar = { - AnimatedVisibility( - visible = !uiState.isReaderMode || uiState.isUiVisible, - enter = fadeIn(animationSpec = tween(300)) + slideInVertically( - animationSpec = tween(300) - ) { -it }, - exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( - animationSpec = tween(300) - ) { -it } - ) { - TopAppBar( - title = { - Text( - text = stringResource(R.string.all_notes).uppercase(), - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 1.0.sp, - fontFamily = FontFamily(Font(R.font.space_grotesk_regular)), - ) - }, - navigationIcon = { - IconButton( - onClick = { - if (uiState.isReaderMode) viewModel.toggleReaderMode() else navController.popBackStack() - } - ) { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.ios_arrow_left), - contentDescription = "Navigate up", - tint = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.onPrimary - ) - ) - } - } - ) { innerPadding -> - Box( - modifier = modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.onPrimary) - .padding( - if (!uiState.isReaderMode || uiState.isUiVisible) innerPadding else PaddingValues( - 0.dp - ) - ) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - viewModel.onScreenTap() - }, - ) { - if (note != null && note.id == noteId) { - Column( - modifier = Modifier.verticalScroll(scrollState) - ) { - Text( - text = note.title, - style = MaterialTheme.typography.titleLarge.copy( - color = MaterialTheme.colorScheme.onSurface, - ), - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - ) - - HorizontalDivider() - - Row( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - ) { - Column( - modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Text( - text = stringResource(R.string.date_created), - style = MaterialTheme.typography.bodySmall.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - ) - Text( - text = note.getFormattedUpdatedAt(), - style = MaterialTheme.typography.titleSmall.copy( - color = MaterialTheme.colorScheme.onSurface, - fontWeight = FontWeight.Bold - ) - ) - } - if (!note.getFormattedUpdatedAt().isEmpty()){ - Column( - modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Text( - text = stringResource(R.string.last_edited), - style = MaterialTheme.typography.bodySmall.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - ) - Text( - text = note.getFormattedUpdatedAt(), - style = MaterialTheme.typography.titleSmall.copy( - color = MaterialTheme.colorScheme.onSurface, - fontWeight = FontWeight.Bold - ) - ) - } - } - } - - HorizontalDivider() - - Text( - text = note.content, - style = MaterialTheme.typography.bodyLarge.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - ), - modifier = Modifier - .fillMaxWidth() - .padding( - if (uiState.isReaderMode && !uiState.isUiVisible) { - PaddingValues(horizontal = 24.dp, vertical = 32.dp) - } else { - PaddingValues(16.dp) - } - ) - ) - } - } else { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator() - } - } - - AnimatedVisibility( - visible = !uiState.isReaderMode || uiState.isUiVisible, - enter = fadeIn(animationSpec = tween(300)) + slideInVertically( - animationSpec = tween(300) - ) { it }, - exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( - animationSpec = tween(300) - ) { it }, - modifier = Modifier.align(Alignment.BottomCenter) - ) { - ExtendedFabFSheet( - onEditClick = { - // if we are in reader mode, first exit reader mode then handle the navigation - navController.navigate( - HomeScreens.EditNote( - noteId = noteId ?: "" - ) - ) - }, - onReaderModeClick = { - viewModel.toggleReaderMode() - }, - isReaderMode = uiState.isReaderMode - ) - } - } - } -} - -@Composable -internal fun ExtendedFabFSheet( - modifier: Modifier = Modifier, - onEditClick: () -> Unit, - onReaderModeClick: () -> Unit, - isReaderMode: Boolean = false -) { - Row( - modifier = modifier - .padding(16.dp) - .background( - MaterialTheme.colorScheme.surface, - shape = MaterialTheme.shapes.medium - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - IconButton( - onClick = onEditClick - ) { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.edit), - contentDescription = null - ) - } - - IconButton( - onClick = onReaderModeClick, - modifier = Modifier - .then( - if (isReaderMode) { - Modifier - .padding(4.dp) - .background( - color = Color(0x1A5977F7), - shape = MaterialTheme.shapes.medium - ) - } else { - Modifier - } - ) - ) { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.book_open), - contentDescription = null, - tint = if (isReaderMode) MaterialTheme.colorScheme.primary else LocalContentColor.current - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/note/Home.kt b/app/src/main/java/com/example/notemark/main/presentation/screens/note/Home.kt deleted file mode 100644 index d546f1e..0000000 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/note/Home.kt +++ /dev/null @@ -1,656 +0,0 @@ -package com.example.notemark.main.presentation.screens.note - -import android.util.Log -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid -import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells -import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan -import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.DeleteOutline -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.FloatingActionButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.ListItem -import androidx.compose.material3.ListItemDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.State -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.hapticfeedback.HapticFeedbackType -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalHapticFeedback -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import androidx.paging.LoadState -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.itemKey -import com.airbnb.lottie.compose.LottieAnimation -import com.airbnb.lottie.compose.LottieCompositionSpec -import com.airbnb.lottie.compose.rememberLottieAnimatable -import com.airbnb.lottie.compose.rememberLottieComposition -import com.example.notemark.R -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.core.getInitials -import com.example.notemark.core.manager.SessionManager -import com.example.notemark.core.truncateAtWord -import com.example.notemark.main.DateFormatter -import com.example.notemark.main.domain.model.Note -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.domain.model.getFormattedCreatedAt -import com.example.notemark.main.presentation.vm.DeleteNoteUiState -import com.example.notemark.main.presentation.vm.NoteUiState -import com.example.notemark.main.presentation.vm.NotesViewModel -import com.example.notemark.navigation.screens.AuthScreens -import com.example.notemark.navigation.screens.HomeScreens -import kotlinx.coroutines.delay -import java.util.UUID - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun HomeScreen( - navController: NavHostController = rememberNavController(), - connectivityState: State, - notesList: LazyPagingItems, - noteUiState: State, - -) { - val context = LocalContext.current - val sessionManager = SessionManager(context) - val username = sessionManager.getUserName() - val accessToken = sessionManager.getAccessToken() - val refreshToken = sessionManager.getRefreshToken() - - LaunchedEffect(Unit) { - Log.d("HomeScreen", "Username: ${sessionManager.getUserName()}") - Log.d("HomeScreen", "Access Token: ${sessionManager.getAccessToken()}") - Log.d("HomeScreen", "Refresh Token: ${sessionManager.getRefreshToken()}") - } - - LaunchedEffect(Unit) { - if (accessToken.isNullOrEmpty() && refreshToken.isNullOrEmpty()) { - navController.navigate(AuthScreens.LogIn.route) { - popUpTo(0) { - inclusive - } - } - } - } - - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) - - when(deviceConfiguration) { - DeviceConfiguration.MOBILE_PORTRAIT -> { - MainContent( - modifier = Modifier, - navController = navController, - username = username, - notes = notesList, - connectivityState = connectivityState, - columnCount = 2 - ) - } - DeviceConfiguration.MOBILE_LANDSCAPE -> { - MainContent( - modifier = Modifier - .background( - MaterialTheme.colorScheme.surface - ) - .windowInsetsPadding(WindowInsets.displayCutout) - .fillMaxSize() - .consumeWindowInsets(WindowInsets.navigationBars), - navController = navController, - username = username, - notes = notesList, - connectivityState = connectivityState, - columnCount = 3 - ) - } - DeviceConfiguration.TABLET_PORTRAIT, - DeviceConfiguration.TABLET_LANDSCAPE, - DeviceConfiguration.DESKTOP -> { - MainContent( - modifier = Modifier, - navController = navController, - username = username, - notes = notesList, - connectivityState = connectivityState, - columnCount = 3 - ) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun MainContent( - modifier: Modifier, - navController: NavHostController, - username: String?, - notes: LazyPagingItems, - connectivityState: State, - columnCount: Int, -) { - val context = LocalContext.current - val uuid = remember { UUID.randomUUID() } - val noteViewModel = hiltViewModel() - val noteState by noteViewModel.createNoteState.collectAsStateWithLifecycle() - val creationTime by remember { mutableStateOf(DateFormatter.getCurrentIsoString()) } - - LaunchedEffect(notes.loadState) { - when { - notes.loadState.refresh is LoadState.Error -> { - val error = (notes.loadState.refresh as LoadState.Error).error - Log.e("Home", "Refresh error: ${error.message}") - if (notes.itemCount == 0) { - Toast.makeText( - context, - "Unable to load notes. Showing cached data.", - Toast.LENGTH_SHORT - ).show() - } - } - notes.loadState.append is LoadState.Error -> { - val error = (notes.loadState.append as LoadState.Error).error - Log.e("Home", "Append error: ${error.message}") - } - } - } - - val initials = getInitials(username ?: "U") - - LaunchedEffect(noteState) { - if (noteState.isSuccess) { - navController.navigate(HomeScreens.Home.route) { - popUpTo(HomeScreens.Home.route) { - inclusive = true - } - } - } - } - - LaunchedEffect(noteState.error) { - noteState.error?.let { error -> - Toast.makeText(context, error, Toast.LENGTH_LONG).show() - Log.d( - "CreateNoteScreen", - "CreateNoteScreen: ${noteState.error}" - ) - } - } - - Scaffold( - topBar = { - TopAppBar( - title = { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(R.string.app_name), - style = MaterialTheme.typography.titleMedium, - modifier = Modifier.padding(end = 4.dp) - ) - if (!connectivityState.value) { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.cloud_off), - contentDescription = "Offline", - tint = Color(0x66535364), - ) - } - } - }, - actions = { - Icon( - imageVector = ImageVector.vectorResource(R.drawable.settings), - contentDescription = "Settings", - modifier = Modifier - .clickable { - navController.navigate(HomeScreens.Settings.route) - } - .padding(end = 16.dp) - ) - Text( - modifier = Modifier - .padding(end = 16.dp) - .size(40.dp) - .clip(RoundedCornerShape(12.dp)) - .background(MaterialTheme.colorScheme.primary) - .padding(10.dp), - text = initials, - style = MaterialTheme.typography.titleSmall.copy( - color = MaterialTheme.colorScheme.onPrimary, - textAlign = TextAlign.Center - ) - ) - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.onPrimary - ) - ) - }, - - floatingActionButton = { - FloatingActionButton( - onClick = { - noteViewModel.createNote( - NoteRequest( - id = uuid.toString(), - title = "Note Title", - content = "", - createdAt = creationTime, - updatedAt = creationTime, - ) - ) - navController.navigate(HomeScreens.CreateNote.route) - }, - modifier = Modifier - .size(64.dp) - .background( - brush = Brush.verticalGradient( - colors = listOf( - Color(0xFF58A1F8), - Color(0xFF5A4CF7) - ) - ), - shape = RoundedCornerShape(20.dp) - ), - containerColor = Color.Transparent, - elevation = FloatingActionButtonDefaults.elevation(0.dp) - ) { - Icon( - tint = MaterialTheme.colorScheme.onPrimary, - imageVector = Icons.Default.Add, - contentDescription = "Add icon" - ) - } - }, - contentWindowInsets = WindowInsets.statusBars - ) { innerPadding -> - Column( - modifier = modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) - .padding(innerPadding) - ) { - if (notes.loadState.refresh is LoadState.Loading) { - CircularProgressIndicator( - modifier = Modifier - .size(24.dp) - .align(Alignment.CenterHorizontally) - ) - } else { - LazyVerticalStaggeredGrid( - columns = StaggeredGridCells.Fixed(columnCount), - state = rememberLazyStaggeredGridState(), - modifier = Modifier.weight(1f), - contentPadding = PaddingValues(16.dp), - verticalItemSpacing = 8.dp, - horizontalArrangement = Arrangement.spacedBy(8.dp), - content = { - items( - notes.itemCount, - key = notes.itemKey { it.id } - ) { index -> - notes[index]?.let { - NoteItem( - modifier = Modifier, - navController = navController, - note = it, - notes = notes - ) - } - } - if (notes.loadState.append is LoadState.Loading) { - item(span = StaggeredGridItemSpan.FullLine) { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator( - modifier = Modifier.size(24.dp) - ) - } - } - } - } - ) - } - EmptyState(notes) - } - } -} - -@Composable -private fun EmptyState(notes: LazyPagingItems) { - - if (notes.loadState.refresh !is LoadState.Loading && notes.itemSnapshotList.items.isEmpty() && !notes.loadState.hasError) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(top = 48.dp), - contentAlignment = Alignment.TopCenter - ) { - Text( - text = stringResource(R.string.empty_container_text), - style = MaterialTheme.typography.titleSmall.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - textAlign = TextAlign.Center - ) - ) - } - } -} - -@Composable -fun NoteItem( - modifier: Modifier, - navController: NavHostController = rememberNavController(), - note: Note, - notes: LazyPagingItems -) { - - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) - val isPhone = deviceConfiguration == DeviceConfiguration.MOBILE_PORTRAIT - - var contextMenuNoteId by rememberSaveable { mutableStateOf(null) } - val haptics = LocalHapticFeedback.current - - Column( - modifier = modifier - .combinedClickable( - onClick = { - navController.navigate( - route = HomeScreens.Details( - noteId = note.id - ) - ) - }, - onLongClick = { - haptics.performHapticFeedback(HapticFeedbackType.LongPress) - contextMenuNoteId = note.id - }, - ) - .background( - MaterialTheme.colorScheme.surfaceContainerLowest, - RoundedCornerShape(16.dp) - ) - .padding(16.dp), - horizontalAlignment = Alignment.Start, - ) { - - Text( - text = note.getFormattedCreatedAt(), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.primary - ) - - Spacer(modifier = Modifier.height(8.dp)) - - Text( - text = note.title, - style = MaterialTheme.typography.titleMedium.copy( - color = MaterialTheme.colorScheme.onSurface - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - - Text( - text = note.content.truncateAtWord(if (isPhone) 150 else 250), - style = MaterialTheme.typography.bodySmall, - maxLines = 3, - overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - if (contextMenuNoteId != null) { - NoteActionSheet( - isVisible = note.id == contextMenuNoteId, - onDismissSheet = { contextMenuNoteId = null }, - - noteId = contextMenuNoteId ?: "", - notes = notes - ) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun NoteActionSheet( - isVisible: Boolean, - onDismissSheet: () -> Unit, - noteId: String, - notes: LazyPagingItems -) { - val context = LocalContext.current - val viewModel: NotesViewModel = hiltViewModel() - val deleteNoteState by viewModel.deleteNoteState.collectAsStateWithLifecycle() - val onDeleteClick = { viewModel.deleteNote(noteId = noteId) } - - LaunchedEffect(deleteNoteState) { - when (deleteNoteState) { - is DeleteNoteUiState.Success -> { - delay(2_000L) - notes.refresh() - viewModel.resetDeleteState() - onDismissSheet() - } - is DeleteNoteUiState.Error -> { - Toast.makeText( - context, - (deleteNoteState as DeleteNoteUiState.Error).message, - Toast.LENGTH_SHORT - ).show() - viewModel.resetDeleteState() - } - else -> {} - } - } - - if (isVisible) { - ModalBottomSheet( - onDismissRequest = { - onDismissSheet() - }, - containerColor = MaterialTheme.colorScheme.surfaceContainerLowest, - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - ActionContent( - deleteNoteState = deleteNoteState, - onDeleteClick = onDeleteClick, - ) - } - } - } -} - -@Composable -private fun SuccessContent() { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 24.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - val animationState = rememberLottieAnimatable() - val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.success)) - - - LaunchedEffect(composition) { - composition?.let { - animationState.animate( - composition = it, - iterations = 1 - ) - } - } - - Box( - modifier = Modifier.size(120.dp), - contentAlignment = Alignment.Center - ) { - if (composition != null) { - LottieAnimation( - composition = composition, - progress = { animationState.progress }, - modifier = Modifier.size(120.dp) - ) - } else { - CircularProgressIndicator( - modifier = Modifier.size(24.dp), - strokeWidth = 2.dp - ) - } - } - - Spacer(modifier = Modifier.height(16.dp)) - - Text( - text = "Note deleted successfully!", - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onSurface, - textAlign = TextAlign.Center - ) - } -} - -@Composable -private fun ActionContent( - deleteNoteState: DeleteNoteUiState, - onDeleteClick: () -> Unit, -) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - if (deleteNoteState is DeleteNoteUiState.Success) { - SuccessContent() - } else { - Card( - modifier = Modifier - .fillMaxWidth() - .clip(MaterialTheme.shapes.medium) - .clickable( - enabled = deleteNoteState !is DeleteNoteUiState.Loading - ) { - onDeleteClick() - }, - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surface - ), - elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) - ) { - ListItem( - colors = ListItemDefaults.colors( - containerColor = Color.Transparent - ), - headlineContent = { - Text( - text = when (deleteNoteState) { - is DeleteNoteUiState.Loading -> "Deleting..." - else -> "Delete Note?" - }, - style = MaterialTheme.typography.bodyLarge.copy( - color = if (deleteNoteState is DeleteNoteUiState.Loading) { - MaterialTheme.colorScheme.onSurfaceVariant - } else { - MaterialTheme.colorScheme.error - } - ) - ) - }, - supportingContent = { - Text( - text = "Are you sure you want to delete this note? This action cannot be undone.", - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - }, - leadingContent = { - Box( - modifier = Modifier.size(40.dp), - contentAlignment = Alignment.Center - ) { - if (deleteNoteState is DeleteNoteUiState.Loading) { - CircularProgressIndicator( - modifier = Modifier.size(20.dp), - strokeWidth = 2.dp, - color = MaterialTheme.colorScheme.primary - ) - } else { - Icon( - imageVector = Icons.Default.DeleteOutline, - contentDescription = "Delete", - tint = MaterialTheme.colorScheme.error, - modifier = Modifier.size(24.dp) - ) - } - } - } - ) - } - Spacer(modifier = Modifier.height(16.dp)) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/note/SyncRecord.kt b/app/src/main/java/com/example/notemark/main/presentation/screens/note/SyncRecord.kt deleted file mode 100644 index 4699caf..0000000 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/note/SyncRecord.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.example.notemark.main.presentation.screens.note - -import androidx.room.Entity -import androidx.room.PrimaryKey -import java.util.UUID - -@Entity -data class SyncRecord( - @PrimaryKey - val id: UUID, - val userId: String, - val noteId: String, - val operation: SyncOperation, - val payload: String, - val timeStamp: String -) - -enum class SyncOperation { - CREATE, - UPDATE, - DELETE -} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/navigation/navs/AppNavigation.kt b/app/src/main/java/com/example/notemark/navigation/navs/AppNavigation.kt index a060e91..cbedd14 100644 --- a/app/src/main/java/com/example/notemark/navigation/navs/AppNavigation.kt +++ b/app/src/main/java/com/example/notemark/navigation/navs/AppNavigation.kt @@ -3,6 +3,7 @@ package com.example.notemark.navigation.navs import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -12,45 +13,55 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController -import com.example.notemark.auth.presentation.vm.AuthState -import com.example.notemark.auth.presentation.vm.AuthViewModel import com.example.notemark.navigation.graphs.Graph +import com.example.presentation.NoteMarkDefaultScreen +import com.example.presentation.vm.AuthState +import com.example.presentation.vm.AuthViewModel @Composable fun AppNavigation( navController: NavHostController = rememberNavController(), ) { - - val authViewModel: AuthViewModel = hiltViewModel() + val authViewModel: AuthViewModel = androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel() val authState by authViewModel.authState.collectAsStateWithLifecycle() when (authState) { AuthState.Loading -> { - Box( + NoteMarkDefaultScreen( modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator() - } + containerColor = MaterialTheme.colorScheme.background, + content = { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + } + ) } AuthState.Authenticated -> { - NavHost( - navController = navController, - startDestination = Graph.HOME - ) { - homeNavGraph(navController = navController) - authNavGraph(navController = navController) + NoteMarkDefaultScreen { + NavHost( + navController = navController, + startDestination = Graph.HOME + ) { + homeNavGraph(navController = navController) + authNavGraph(navController = navController) + } } } AuthState.Unauthenticated -> { - NavHost( - navController = navController, - startDestination = Graph.AUTH - ) { - authNavGraph(navController = navController) - homeNavGraph(navController = navController) + NoteMarkDefaultScreen { + NavHost( + navController = navController, + startDestination = Graph.AUTH + ) { + authNavGraph(navController = navController) + homeNavGraph(navController = navController) + } } } } diff --git a/app/src/main/java/com/example/notemark/navigation/navs/authNavGraph.kt b/app/src/main/java/com/example/notemark/navigation/navs/authNavGraph.kt index fa69cc3..fb5c1b2 100644 --- a/app/src/main/java/com/example/notemark/navigation/navs/authNavGraph.kt +++ b/app/src/main/java/com/example/notemark/navigation/navs/authNavGraph.kt @@ -4,38 +4,65 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import androidx.navigation.navigation -import com.example.notemark.auth.presentation.landing.screens.LandingScreen -import com.example.notemark.auth.presentation.login.screens.LoginScreen -import com.example.notemark.auth.presentation.registration.screens.RegistrationScreen import com.example.notemark.navigation.graphs.Graph import com.example.notemark.navigation.screens.AuthScreens +import com.example.notemark.navigation.screens.HomeScreens +import com.example.presentation.landing.screens.LandingScreen +import com.example.presentation.login.LoginScreen +import com.example.presentation.registration.RegistrationScreen internal fun NavGraphBuilder.authNavGraph( navController: NavHostController, ) { navigation( route = Graph.AUTH, - startDestination = AuthScreens.Landing.route + startDestination = AuthScreens.Landing::class.qualifiedName ?: "" ) { - composable( - route = AuthScreens.Landing.route - ) { + composable { LandingScreen( - navController = navController, + onNavigateToRegistration = { + navController.navigate(AuthScreens.Registration) { + popUpTo(AuthScreens.Landing) { + inclusive = true + } + } + }, + onNavigateToLogIn = { + navController.navigate(AuthScreens.LogIn){ + popUpTo(AuthScreens.Landing) { + inclusive = true + } + } + } ) } - composable( - route = AuthScreens.LogIn.route - ) { + composable { LoginScreen( - navController = navController, + onNavigateToRegistration = { + navController.navigate(AuthScreens.Registration) { + popUpTo(AuthScreens.LogIn) { + inclusive = true + } + } + }, + onNavigateToHome = { + navController.navigate(HomeScreens.Home) { + popUpTo(0) { + inclusive = true + } + } + } ) } - composable( - route = AuthScreens.Registration.route - ) { + composable { RegistrationScreen( - navController = navController, + onNavigateToLogIn = { + navController.navigate(AuthScreens.LogIn) { + popUpTo(AuthScreens.Registration) { + inclusive = true + } + } + }, ) } } diff --git a/app/src/main/java/com/example/notemark/navigation/navs/homeNavGraph.kt b/app/src/main/java/com/example/notemark/navigation/navs/homeNavGraph.kt index 7c0897b..fbcd1e4 100644 --- a/app/src/main/java/com/example/notemark/navigation/navs/homeNavGraph.kt +++ b/app/src/main/java/com/example/notemark/navigation/navs/homeNavGraph.kt @@ -10,17 +10,17 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.navigation import androidx.navigation.toRoute import androidx.paging.compose.collectAsLazyPagingItems -import com.example.notemark.AndroidConnectivityObserver -import com.example.notemark.ConnectivityViewModel -import com.example.notemark.main.presentation.screens.ProfileScreen -import com.example.notemark.main.presentation.screens.SettingsScreen -import com.example.notemark.main.presentation.screens.note.CreateNoteScreen -import com.example.notemark.main.presentation.screens.note.DetailsScreen -import com.example.notemark.main.presentation.screens.note.EditNoteScreen -import com.example.notemark.main.presentation.screens.note.HomeScreen -import com.example.notemark.main.presentation.vm.NotesViewModel +import com.example.data.AndroidConnectivityObserver import com.example.notemark.navigation.graphs.Graph +import com.example.notemark.navigation.screens.AuthScreens import com.example.notemark.navigation.screens.HomeScreens +import com.example.presentation.ConnectivityViewModel +import com.example.presentation.NotesViewModel +import com.example.presentation.edit_note.CreateNoteScreen +import com.example.presentation.edit_note.EditNoteScreen +import com.example.presentation.home.HomeScreen +import com.example.presentation.note_details.DetailsScreen +import com.example.presentation.settings.SettingsScreen internal fun NavGraphBuilder.homeNavGraph( navController: NavHostController @@ -28,10 +28,10 @@ internal fun NavGraphBuilder.homeNavGraph( navigation( route = Graph.HOME, - startDestination = HomeScreens.Home.route + startDestination = HomeScreens.Home::class.qualifiedName ?: "" ) { - composable(route = HomeScreens.Home.route) { + composable { val context = LocalContext.current val connectivityViewModel = viewModel { ConnectivityViewModel( @@ -41,14 +41,42 @@ internal fun NavGraphBuilder.homeNavGraph( ) } val viewModel: NotesViewModel = hiltViewModel() + val username = viewModel.username.collectAsStateWithLifecycle() + val accessToken = viewModel.accessToken.collectAsStateWithLifecycle() + val refreshToken = viewModel.refreshToken.collectAsStateWithLifecycle() val notesList = viewModel.notePagingFlow.collectAsLazyPagingItems() val noteUiState = viewModel.createNoteState.collectAsStateWithLifecycle() val connectivityState = connectivityViewModel.isConnected.collectAsStateWithLifecycle() HomeScreen( - navController = navController, + onNavigateToHome = { + navController.navigate(HomeScreens.Home) { + popUpTo(HomeScreens.Home) { + inclusive = true + } + } + }, + onNavigateToLogin = { + navController.navigate(AuthScreens.LogIn) { + popUpTo(0) { + inclusive + } + } + }, + onNavigateToSettings = { navController.navigate(HomeScreens.Settings) }, + onNavigateToCreateNote = { navController.navigate(HomeScreens.CreateNote) }, + onNavigateToDetailsWithId = { + navController.navigate( + HomeScreens.Details( + noteId = it + ) + ) + }, connectivityState = connectivityState, notesList = notesList, - noteUiState = noteUiState + noteUiState = noteUiState, + username = username.value, + accessToken = accessToken.value, + refreshToken = refreshToken.value ) } @@ -66,21 +94,37 @@ internal fun NavGraphBuilder.homeNavGraph( composable { val argument = it.toRoute() EditNoteScreen( - navController = navController, + onNavigateHome = { + navController.navigate(HomeScreens.Home) { + popUpTo(HomeScreens.Home) { + inclusive = true + } + } + }, + onNavigateUp = { + navController.navigateUp() + }, noteId = argument.noteId, ) } - composable(route = HomeScreens.CreateNote.route) { + composable { CreateNoteScreen(navController = navController) } - composable(route = HomeScreens.Profile.route) { - ProfileScreen(navController = navController) - } - - composable(route = HomeScreens.Settings.route) { - SettingsScreen(navController = navController) + composable { + SettingsScreen( + onNavigateToLanding = { + navController.navigate(AuthScreens.Landing) { + popUpTo(0) { + inclusive = true + } + } + }, + onNavigateUp = { + navController.navigateUp() + } + ) } } } diff --git a/app/src/main/java/com/example/notemark/navigation/screens/AuthScreens.kt b/app/src/main/java/com/example/notemark/navigation/screens/AuthScreens.kt index 6b788d7..3311659 100644 --- a/app/src/main/java/com/example/notemark/navigation/screens/AuthScreens.kt +++ b/app/src/main/java/com/example/notemark/navigation/screens/AuthScreens.kt @@ -3,15 +3,15 @@ package com.example.notemark.navigation.screens import kotlinx.serialization.Serializable @Serializable -sealed class AuthScreens(val route: String) { +sealed interface AuthScreens { @Serializable - object Landing: AuthScreens("landing_screen") + object Landing: AuthScreens @Serializable - object LogIn : AuthScreens("sign_in") + object LogIn : AuthScreens @Serializable - object Registration : AuthScreens("sign_up") + object Registration : AuthScreens } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/navigation/screens/HomeScreens.kt b/app/src/main/java/com/example/notemark/navigation/screens/HomeScreens.kt index 8511db9..0e90457 100644 --- a/app/src/main/java/com/example/notemark/navigation/screens/HomeScreens.kt +++ b/app/src/main/java/com/example/notemark/navigation/screens/HomeScreens.kt @@ -3,28 +3,27 @@ package com.example.notemark.navigation.screens import kotlinx.serialization.Serializable @Serializable -sealed class HomeScreens(val route: String) { +sealed interface HomeScreens { @Serializable - object Home : HomeScreens("home") + data object Home : HomeScreens @Serializable - object Profile : HomeScreens("profile") + object Profile : HomeScreens @Serializable - object CreateNote : HomeScreens("create_note") + object CreateNote : HomeScreens @Serializable data class EditNote( val noteId: String - ): HomeScreens("edit_note") + ): HomeScreens @Serializable - object Settings : HomeScreens("settings") + object Settings : HomeScreens @Serializable data class Details( val noteId: String - ): HomeScreens("details") - + ): HomeScreens } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/ui/theme/Type.kt b/app/src/main/java/com/example/notemark/ui/theme/Type.kt index 8b66275..64a611b 100644 --- a/app/src/main/java/com/example/notemark/ui/theme/Type.kt +++ b/app/src/main/java/com/example/notemark/ui/theme/Type.kt @@ -6,7 +6,7 @@ import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -import com.example.notemark.R +import com.example.notemark.core.presentation.R val Typography = Typography( titleLarge = TextStyle( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 79d4a8e..c5b85e7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,29 +1,3 @@ NoteMark - Request time out - Too many request - no internet - Server error occur. - Unknown error, please reach the support center. - Disk full, please clean the cache. - Invalid email - For some reason note is not deleted, please try again or contact support! - Log out - Last sync: - Sync Data - Sync interval - settings - Manual Only - 15 minutes - 30 minutes - 1 hour - You’ve got an empty board,\n let’s place your first note on it! - all notes - Date created - Last edited - update note - Discard Changes? - You have unsaved changes. If you discard now, all changes will be lost. - Discard - Keep Editing \ No newline at end of file diff --git a/auth/data/build.gradle.kts b/auth/data/build.gradle.kts index af42db5..f910a75 100644 --- a/auth/data/build.gradle.kts +++ b/auth/data/build.gradle.kts @@ -1,17 +1,22 @@ plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) + alias(libs.plugins.notemark.android.library) + alias(libs.plugins.ktor.client.convention) + alias(libs.plugins.compose.compiler) + id("com.google.dagger.hilt.android") // ✅ ADD THIS + alias(libs.plugins.ksp) // ✅ ADD THIS } android { - namespace = "com.example.data" + namespace = "com.example.notemark.auth.data" } dependencies { - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.appcompat) - implementation(libs.material) - testImplementation(libs.junit) - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) + // ✅ ADD HILT DEPENDENCIES + implementation(libs.hilt.android) + ksp(libs.hilt.android.compiler) + with(projects) { + implementation(auth.domain) + implementation(core.data) + implementation(core.domain) + } } \ No newline at end of file diff --git a/auth/data/src/main/java/com/example/data/di/AuthModule.kt b/auth/data/src/main/java/com/example/data/di/AuthModule.kt new file mode 100644 index 0000000..0e36a77 --- /dev/null +++ b/auth/data/src/main/java/com/example/data/di/AuthModule.kt @@ -0,0 +1,66 @@ +package com.example.data.di + +import com.example.data.SessionManager +import com.example.data.remote.LoginServiceImpl +import com.example.data.remote.LogoutServiceImpl +import com.example.data.remote.RegistrationServiceImpl +import com.example.domain.LoginService +import com.example.domain.LogoutService +import com.example.domain.RegistrationService +import com.example.domain.SessionRepository +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import io.ktor.client.HttpClient +import io.ktor.client.engine.android.Android +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class AuthModule { + + @Binds + @Singleton + abstract fun bindSessionRepository( + sessionManager: SessionManager + ): SessionRepository + + companion object { + + @Provides + @Singleton + fun provideHttpClient(): HttpClient = HttpClient(Android) { + install(ContentNegotiation) { + json(Json { + ignoreUnknownKeys = true + isLenient = true + }) + } + install(Logging) { + level = LogLevel.ALL + } + } + + @Provides + @Singleton + fun provideRegistrationService(client: HttpClient): RegistrationService = + RegistrationServiceImpl(client) + + @Provides + @Singleton + fun provideLoginService(client: HttpClient): LoginService = + LoginServiceImpl(client) + + @Provides + @Singleton + fun provideLogoutService(client: HttpClient): LogoutService = + LogoutServiceImpl(client) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/LoginServiceImpl.kt b/auth/data/src/main/java/com/example/data/remote/LoginServiceImpl.kt similarity index 76% rename from app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/LoginServiceImpl.kt rename to auth/data/src/main/java/com/example/data/remote/LoginServiceImpl.kt index ce6f42e..c48e629 100644 --- a/app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/LoginServiceImpl.kt +++ b/auth/data/src/main/java/com/example/data/remote/LoginServiceImpl.kt @@ -1,9 +1,9 @@ -package com.example.notemark.auth.data.remote.repositoryImpl +package com.example.data.remote -import com.example.notemark.core.HttpRoutes -import com.example.notemark.auth.data.remote.api.LoginService -import com.example.notemark.auth.domain.model.LoginModel -import com.example.notemark.auth.domain.model.LoginResponse +import com.example.domain.HttpRoutes +import com.example.domain.LoginService +import com.example.domain.model.LoginModel +import com.example.domain.model.LoginResponse import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.header @@ -33,6 +33,7 @@ class LoginServiceImpl( null } } catch (e: Exception) { + e.printStackTrace() null } } diff --git a/app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/LogoutServiceImpl.kt b/auth/data/src/main/java/com/example/data/remote/LogoutServiceImpl.kt similarity index 76% rename from app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/LogoutServiceImpl.kt rename to auth/data/src/main/java/com/example/data/remote/LogoutServiceImpl.kt index cdb55fc..a1d9a13 100644 --- a/app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/LogoutServiceImpl.kt +++ b/auth/data/src/main/java/com/example/data/remote/LogoutServiceImpl.kt @@ -1,8 +1,8 @@ -package com.example.notemark.auth.data.remote.repositoryImpl +package com.example.data.remote -import com.example.notemark.auth.data.remote.api.LogoutService -import com.example.notemark.core.HttpRoutes -import com.example.notemark.core.factory.AccessTokenResponse +import com.example.domain.HttpRoutes +import com.example.domain.LogoutService +import com.example.domain.model.AccessTokenResponse import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.header @@ -28,7 +28,8 @@ class LogoutServiceImpl( } else { null } - } catch (e: Exception){ + } catch (e: Exception) { + e.printStackTrace() null } } diff --git a/app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/RegistrationServiceImpl.kt b/auth/data/src/main/java/com/example/data/remote/RegistrationServiceImpl.kt similarity index 86% rename from app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/RegistrationServiceImpl.kt rename to auth/data/src/main/java/com/example/data/remote/RegistrationServiceImpl.kt index c14a890..cafa52a 100644 --- a/app/src/main/java/com/example/notemark/auth/data/remote/repositoryImpl/RegistrationServiceImpl.kt +++ b/auth/data/src/main/java/com/example/data/remote/RegistrationServiceImpl.kt @@ -1,8 +1,8 @@ -package com.example.notemark.auth.data.remote.repositoryImpl +package com.example.data.remote -import com.example.notemark.auth.data.remote.api.RegistrationService -import com.example.notemark.auth.domain.model.RegistrationModel -import com.example.notemark.core.HttpRoutes +import com.example.domain.model.RegistrationModel +import com.example.domain.RegistrationService +import com.example.domain.HttpRoutes import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.header diff --git a/auth/domain/build.gradle.kts b/auth/domain/build.gradle.kts index 1870010..28db768 100644 --- a/auth/domain/build.gradle.kts +++ b/auth/domain/build.gradle.kts @@ -1,13 +1,7 @@ plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) + alias(libs.plugins.notemark.jvm.library) } dependencies { - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.appcompat) - implementation(libs.material) - testImplementation(libs.junit) - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) + } \ No newline at end of file diff --git a/auth/domain/src/main/java/com/example/domain/LoginService.kt b/auth/domain/src/main/java/com/example/domain/LoginService.kt new file mode 100644 index 0000000..1c6a3ac --- /dev/null +++ b/auth/domain/src/main/java/com/example/domain/LoginService.kt @@ -0,0 +1,10 @@ +package com.example.domain + +import com.example.domain.model.LoginModel +import com.example.domain.model.LoginResponse + +interface LoginService { + + suspend fun login(body: LoginModel): LoginResponse? + +} \ No newline at end of file diff --git a/auth/domain/src/main/java/com/example/domain/LogoutService.kt b/auth/domain/src/main/java/com/example/domain/LogoutService.kt new file mode 100644 index 0000000..9d9c031 --- /dev/null +++ b/auth/domain/src/main/java/com/example/domain/LogoutService.kt @@ -0,0 +1,9 @@ +package com.example.domain + +import com.example.domain.model.AccessTokenResponse + +interface LogoutService { + + suspend fun logout(refreshToken: String): AccessTokenResponse? + +} \ No newline at end of file diff --git a/auth/domain/src/main/java/com/example/domain/RegistrationService.kt b/auth/domain/src/main/java/com/example/domain/RegistrationService.kt new file mode 100644 index 0000000..cf4c454 --- /dev/null +++ b/auth/domain/src/main/java/com/example/domain/RegistrationService.kt @@ -0,0 +1,9 @@ +package com.example.domain + +import com.example.domain.model.RegistrationModel + +interface RegistrationService { + + suspend fun register(body: RegistrationModel): RegistrationModel? + +} \ No newline at end of file diff --git a/auth/domain/src/main/java/com/example/domain/model/AccessTokenRequest.kt b/auth/domain/src/main/java/com/example/domain/model/AccessTokenRequest.kt new file mode 100644 index 0000000..997f46a --- /dev/null +++ b/auth/domain/src/main/java/com/example/domain/model/AccessTokenRequest.kt @@ -0,0 +1,6 @@ +package com.example.domain.model + +data class AccessTokenRequest( + val refreshToken: String +) + diff --git a/auth/domain/src/main/java/com/example/domain/model/AccessTokenResponse.kt b/auth/domain/src/main/java/com/example/domain/model/AccessTokenResponse.kt new file mode 100644 index 0000000..49a1cb2 --- /dev/null +++ b/auth/domain/src/main/java/com/example/domain/model/AccessTokenResponse.kt @@ -0,0 +1,6 @@ +package com.example.domain.model + +data class AccessTokenResponse( + val accessToken: String, + val refreshToken: String, +) \ No newline at end of file diff --git a/auth/domain/src/main/java/com/example/domain/model/LoginModel.kt b/auth/domain/src/main/java/com/example/domain/model/LoginModel.kt new file mode 100644 index 0000000..627d2f0 --- /dev/null +++ b/auth/domain/src/main/java/com/example/domain/model/LoginModel.kt @@ -0,0 +1,6 @@ +package com.example.domain.model + +data class LoginModel( + val email: String, + val password: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/domain/model/LoginResponse.kt b/auth/domain/src/main/java/com/example/domain/model/LoginResponse.kt similarity index 52% rename from app/src/main/java/com/example/notemark/auth/domain/model/LoginResponse.kt rename to auth/domain/src/main/java/com/example/domain/model/LoginResponse.kt index ac2b8c4..f231fd4 100644 --- a/app/src/main/java/com/example/notemark/auth/domain/model/LoginResponse.kt +++ b/auth/domain/src/main/java/com/example/domain/model/LoginResponse.kt @@ -1,8 +1,5 @@ -package com.example.notemark.auth.domain.model +package com.example.domain.model -import kotlinx.serialization.Serializable - -@Serializable data class LoginResponse( val accessToken: String, val refreshToken: String, diff --git a/app/src/main/java/com/example/notemark/auth/domain/model/RegistrationModel.kt b/auth/domain/src/main/java/com/example/domain/model/RegistrationModel.kt similarity index 51% rename from app/src/main/java/com/example/notemark/auth/domain/model/RegistrationModel.kt rename to auth/domain/src/main/java/com/example/domain/model/RegistrationModel.kt index e6908cd..d3d8d6e 100644 --- a/app/src/main/java/com/example/notemark/auth/domain/model/RegistrationModel.kt +++ b/auth/domain/src/main/java/com/example/domain/model/RegistrationModel.kt @@ -1,8 +1,6 @@ -package com.example.notemark.auth.domain.model +package com.example.domain.model -import kotlinx.serialization.Serializable -@Serializable data class RegistrationModel( val username: String, val email: String, diff --git a/app/src/main/java/com/example/notemark/auth/domain/model/SuccessfulLogin.kt b/auth/domain/src/main/java/com/example/domain/model/SuccessfulLogin.kt similarity index 65% rename from app/src/main/java/com/example/notemark/auth/domain/model/SuccessfulLogin.kt rename to auth/domain/src/main/java/com/example/domain/model/SuccessfulLogin.kt index 386a0db..1f0b1eb 100644 --- a/app/src/main/java/com/example/notemark/auth/domain/model/SuccessfulLogin.kt +++ b/auth/domain/src/main/java/com/example/domain/model/SuccessfulLogin.kt @@ -1,4 +1,4 @@ -package com.example.notemark.auth.domain.model +package com.example.domain.model data class SuccessfulLogin( val accessToken: String, diff --git a/auth/presentation/build.gradle.kts b/auth/presentation/build.gradle.kts index fc0e43d..e5b6d50 100644 --- a/auth/presentation/build.gradle.kts +++ b/auth/presentation/build.gradle.kts @@ -1,17 +1,21 @@ plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) + alias(libs.plugins.notemark.android.library.compose) + id("com.google.dagger.hilt.android") + alias(libs.plugins.ksp) } android { - namespace = "com.example.presentation" + namespace = "com.example.notemark.auth.presentation" } dependencies { - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.appcompat) - implementation(libs.material) - testImplementation(libs.junit) - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) + with(projects) { + implementation(core.domain) + implementation(auth.domain) + implementation(auth.data) + implementation(core.presentation) + } + + implementation(libs.hilt.android) + ksp(libs.hilt.android.compiler) } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/landing/screens/LandingScreen.kt b/auth/presentation/src/main/java/com/example/presentation/landing/screens/LandingScreen.kt similarity index 80% rename from app/src/main/java/com/example/notemark/auth/presentation/landing/screens/LandingScreen.kt rename to auth/presentation/src/main/java/com/example/presentation/landing/screens/LandingScreen.kt index 4a66722..3451007 100644 --- a/app/src/main/java/com/example/notemark/auth/presentation/landing/screens/LandingScreen.kt +++ b/auth/presentation/src/main/java/com/example/presentation/landing/screens/LandingScreen.kt @@ -1,20 +1,16 @@ -package com.example.notemark.auth.presentation.landing.screens +package com.example.presentation.landing.screens import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -22,7 +18,6 @@ import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable @@ -33,15 +28,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import com.example.notemark.R -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.navigation.screens.AuthScreens +import com.example.notemark.core.presentation.R +import com.example.presentation.DeviceConfiguration @Composable fun LandingScreen( - navController: NavHostController = rememberNavController(), + onNavigateToRegistration: () -> Unit = {}, + onNavigateToLogIn: () -> Unit = {}, ) { val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) @@ -60,7 +53,8 @@ fun LandingScreen( ) LandingSheet( - navController = navController, + onNavigateToLogIn = onNavigateToLogIn, + onNavigateToRegistration = onNavigateToRegistration, modifier = Modifier .align(Alignment.BottomCenter) .clip(shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp)) @@ -83,7 +77,8 @@ fun LandingScreen( ) LandingSheet( - navController = navController, + onNavigateToLogIn = onNavigateToLogIn, + onNavigateToRegistration = onNavigateToRegistration, modifier = Modifier .weight(1.2f) .clip(shape = RoundedCornerShape(topStart = 24.dp, bottomStart = 24.dp)), @@ -107,7 +102,8 @@ fun LandingScreen( ) LandingSheet( - navController = navController, + onNavigateToLogIn = onNavigateToLogIn, + onNavigateToRegistration = onNavigateToRegistration, modifier = Modifier .padding(horizontal = 48.dp) .clip(shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp)) @@ -120,8 +116,9 @@ fun LandingScreen( @Composable fun LandingSheet( - navController: NavHostController, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + onNavigateToLogIn: () -> Unit = {}, + onNavigateToRegistration: () -> Unit = {}, ) { Column( modifier = modifier @@ -146,13 +143,7 @@ fun LandingSheet( Spacer(modifier = Modifier.height(32.dp)) Button( - onClick = { - navController.navigate(AuthScreens.Registration.route) { - popUpTo(AuthScreens.Landing.route) { - inclusive = true - } - } - }, + onClick = { onNavigateToRegistration() }, modifier = Modifier .fillMaxWidth() .height(56.dp), @@ -171,13 +162,7 @@ fun LandingSheet( Spacer(modifier = Modifier.height(8.dp)) OutlinedButton( - onClick = { - navController.navigate(AuthScreens.LogIn.route){ - popUpTo(AuthScreens.Landing.route) { - inclusive = true - } - } - }, + onClick = { onNavigateToLogIn() }, modifier = Modifier .fillMaxWidth() .height(56.dp), diff --git a/auth/presentation/src/main/java/com/example/presentation/login/LoginScreen.kt b/auth/presentation/src/main/java/com/example/presentation/login/LoginScreen.kt new file mode 100644 index 0000000..8e559e5 --- /dev/null +++ b/auth/presentation/src/main/java/com/example/presentation/login/LoginScreen.kt @@ -0,0 +1,136 @@ +package com.example.presentation.login + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import com.example.presentation.login.components.LoginHeaderSection +import com.example.presentation.login.components.LoginSheet +import com.example.presentation.DeviceConfiguration + +@Composable +fun LoginScreen( + onNavigateToHome: () -> Unit = {}, + onNavigateToRegistration: () -> Unit = {}, +) { + val snackbarHostState = remember { SnackbarHostState() } + + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + modifier = Modifier.fillMaxSize(), + contentWindowInsets = WindowInsets.statusBars + ) { innerPadding -> + + val rootModifier = Modifier + .fillMaxSize() + .padding(innerPadding) + .clip( + RoundedCornerShape( + topStart = 15.dp, + topEnd = 15.dp + ) + ) + .background(MaterialTheme.colorScheme.surfaceContainerLowest) + .padding( + horizontal = 16.dp, + vertical = 24.dp + ) + .consumeWindowInsets(WindowInsets.navigationBars) + + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) + + when(deviceConfiguration) { + DeviceConfiguration.MOBILE_PORTRAIT -> { + Column( + modifier = rootModifier, + ) { + LoginHeaderSection( + modifier = Modifier.fillMaxWidth() + ) + LoginSheet( + onNavigateToHome = onNavigateToHome, + onNavigateToRegistration = onNavigateToRegistration, + modifier = Modifier + .fillMaxWidth() + .padding(top = 32.dp), + snackbarHostState = snackbarHostState + ) + } + } + DeviceConfiguration.MOBILE_LANDSCAPE -> { + Row( + modifier = rootModifier + .windowInsetsPadding(WindowInsets.displayCutout) + .padding( + horizontal = 32.dp + ), + horizontalArrangement = Arrangement.spacedBy(32.dp) + ) { + LoginHeaderSection( + modifier = Modifier + .weight(1f) + ) + LoginSheet( + onNavigateToHome = onNavigateToHome, + onNavigateToRegistration = onNavigateToRegistration, + modifier = Modifier + .weight(1f) + .verticalScroll(rememberScrollState()), + snackbarHostState = snackbarHostState + ) + } + } + DeviceConfiguration.TABLET_PORTRAIT, + DeviceConfiguration.TABLET_LANDSCAPE, + DeviceConfiguration.DESKTOP -> { + Column( + modifier = rootModifier + .verticalScroll(rememberScrollState()) + .padding(top = 48.dp), + verticalArrangement = Arrangement.spacedBy(32.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + LoginHeaderSection( + modifier = Modifier + .widthIn(max = 540.dp), + alignment = Alignment.CenterHorizontally + ) + LoginSheet( + onNavigateToHome = onNavigateToHome, + onNavigateToRegistration = onNavigateToRegistration, + modifier = Modifier + .widthIn(max = 540.dp), + snackbarHostState = snackbarHostState + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/login/vm/LoginViewModel.kt b/auth/presentation/src/main/java/com/example/presentation/login/LoginViewModel.kt similarity index 87% rename from app/src/main/java/com/example/notemark/auth/presentation/login/vm/LoginViewModel.kt rename to auth/presentation/src/main/java/com/example/presentation/login/LoginViewModel.kt index c25c9da..3ed146f 100644 --- a/app/src/main/java/com/example/notemark/auth/presentation/login/vm/LoginViewModel.kt +++ b/auth/presentation/src/main/java/com/example/presentation/login/LoginViewModel.kt @@ -1,14 +1,14 @@ -package com.example.notemark.auth.presentation.login.vm +package com.example.presentation.login import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.notemark.auth.data.remote.api.LoginService -import com.example.notemark.auth.data.remote.api.LogoutService -import com.example.notemark.auth.domain.model.LoginModel -import com.example.notemark.auth.domain.model.LoginResponse -import com.example.notemark.core.manager.SessionManager +import com.example.domain.LoginService +import com.example.domain.LogoutService +import com.example.domain.SessionRepository +import com.example.domain.model.LoginModel +import com.example.domain.model.LoginResponse import dagger.hilt.android.lifecycle.HiltViewModel -import jakarta.inject.Inject +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -19,7 +19,7 @@ import kotlinx.coroutines.launch class LoginViewModel @Inject constructor( private val loginService: LoginService, private val logoutService: LogoutService, - private val sessionManager: SessionManager + private val sessionManager: SessionRepository ): ViewModel() { private val _loginState = MutableStateFlow(LoginState.Idle) diff --git a/auth/presentation/src/main/java/com/example/presentation/login/components/LoginHeaderSection.kt b/auth/presentation/src/main/java/com/example/presentation/login/components/LoginHeaderSection.kt new file mode 100644 index 0000000..c4b0b56 --- /dev/null +++ b/auth/presentation/src/main/java/com/example/presentation/login/components/LoginHeaderSection.kt @@ -0,0 +1,28 @@ +package com.example.presentation.login.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier + +@Composable +internal fun LoginHeaderSection( + alignment: Alignment.Horizontal = Alignment.Start, + modifier: Modifier +) { + Column( + modifier = modifier, + horizontalAlignment = alignment + ) { + Text( + text = "Log In", + style = MaterialTheme.typography.titleLarge + ) + Text( + text = "Capture your thoughts and ideas.", + style = MaterialTheme.typography.bodyLarge + ) + } +} \ No newline at end of file diff --git a/auth/presentation/src/main/java/com/example/presentation/login/components/LoginSheet.kt b/auth/presentation/src/main/java/com/example/presentation/login/components/LoginSheet.kt new file mode 100644 index 0000000..adba060 --- /dev/null +++ b/auth/presentation/src/main/java/com/example/presentation/login/components/LoginSheet.kt @@ -0,0 +1,129 @@ +package com.example.presentation.login.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.dp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.example.presentation.components.NoteMarkButton +import com.example.presentation.components.NoteMarkLink +import com.example.presentation.components.NoteMarkTextField +import com.example.presentation.login.LoginState +import com.example.presentation.login.LoginViewModel +import com.example.presentation.isValidEmail +import com.example.presentation.vm.AuthViewModel +import kotlinx.coroutines.launch + +@Composable +fun LoginSheet( + modifier: Modifier = Modifier, + onNavigateToHome: () -> Unit = {}, + snackbarHostState : SnackbarHostState, + onNavigateToRegistration: () -> Unit = {}, +) { + + val scope = rememberCoroutineScope() + val loginViewModel: LoginViewModel = hiltViewModel() + val authViewModel: AuthViewModel = hiltViewModel() + val state by loginViewModel.loginState.collectAsStateWithLifecycle() + + LaunchedEffect(state) { + when (state) { + is LoginState.Success -> { + authViewModel.refreshAuthState() + onNavigateToHome() + + loginViewModel.clearState() + } + is LoginState.Error -> { + scope.launch { + val result = snackbarHostState + .showSnackbar( + message = "Invalid login credentials", + actionLabel = "", + duration = SnackbarDuration.Short + ) + when (result) { + SnackbarResult.ActionPerformed -> {} + SnackbarResult.Dismissed -> {} + } + } + } + is LoginState.Idle -> {} + is LoginState.Loading -> {} + } + } + + var email by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + var isDisabled by remember { mutableStateOf(true) } + val focusManager = LocalFocusManager.current + + isDisabled = email.isBlank() || password.isBlank() || !isValidEmail(email) + + Column( + modifier = modifier + ) { + NoteMarkTextField( + text = email, + onValueChange = { email = it }, + label = "Email", + hint = "john.doe@example.com", + isInputSecret = false, + modifier = Modifier.fillMaxWidth(), + focusManager = focusManager, + focusDirection = FocusDirection.Down, + imeAction = ImeAction.Next, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + NoteMarkTextField( + text = password, + onValueChange = { password = it }, + label = "Password", + hint = "Password", + isInputSecret = true, + modifier = Modifier.fillMaxWidth(), + focusManager = focusManager, + focusDirection = FocusDirection.Down, + imeAction = ImeAction.Done, + ) + + Spacer(modifier = Modifier.height(24.dp)) + + NoteMarkButton( + text = if (state is LoginState.Loading) "" else "Log in", + onClick = { + loginViewModel.loginUser(email, password) + }, + modifier = Modifier.fillMaxWidth(), + enabled = !isDisabled, + isLoading = state is LoginState.Loading + ) + + Spacer(modifier = Modifier.height(24.dp)) + + NoteMarkLink( + text = "Don't have an account?", + onClick = { onNavigateToRegistration() }, + modifier = Modifier.fillMaxWidth() + ) + } +} \ No newline at end of file diff --git a/auth/presentation/src/main/java/com/example/presentation/registration/RegistrationScreen.kt b/auth/presentation/src/main/java/com/example/presentation/registration/RegistrationScreen.kt new file mode 100644 index 0000000..5d54d88 --- /dev/null +++ b/auth/presentation/src/main/java/com/example/presentation/registration/RegistrationScreen.kt @@ -0,0 +1,125 @@ +package com.example.presentation.registration + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.example.presentation.registration.components.RegistrationHeader +import com.example.presentation.registration.components.RegistrationSheet +import com.example.presentation.DeviceConfiguration + +@Composable +fun RegistrationScreen( + onNavigateToLogIn: () -> Unit = {}, +) { + val snackbarHostState = remember { SnackbarHostState() } + + Scaffold( + modifier = Modifier.fillMaxSize(), + contentWindowInsets = WindowInsets.statusBars, + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + ) { innerPadding -> + + val rootModifier = Modifier + .fillMaxSize() + .padding(innerPadding) + .background( + color = MaterialTheme.colorScheme.surfaceContainerLowest, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) + .padding(horizontal = 16.dp, vertical = 24.dp) + .consumeWindowInsets(WindowInsets.navigationBars) + + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val deviceConfiguration = DeviceConfiguration.Companion.fromWindowSizeClass(windowSizeClass) + + when(deviceConfiguration) { + DeviceConfiguration.MOBILE_PORTRAIT -> { + Column( + modifier = rootModifier, + ) { + RegistrationHeader( + modifier = Modifier.fillMaxWidth() + ) + RegistrationSheet( + onNavigateToLogIn = onNavigateToLogIn, + modifier = Modifier + .fillMaxWidth() + .padding(top = 32.dp), + snackbarHostState = snackbarHostState + ) + } + } + DeviceConfiguration.MOBILE_LANDSCAPE -> { + Row( + modifier = rootModifier + .windowInsetsPadding(WindowInsets.displayCutout) + .padding( + horizontal = 32.dp + ), + horizontalArrangement = Arrangement.spacedBy(32.dp) + ) { + RegistrationHeader( + modifier = Modifier + .weight(1f) + ) + RegistrationSheet( + onNavigateToLogIn = onNavigateToLogIn, + modifier = Modifier + .weight(1f) + .verticalScroll(rememberScrollState()), + snackbarHostState = snackbarHostState + ) + } + } + DeviceConfiguration.TABLET_PORTRAIT, + DeviceConfiguration.TABLET_LANDSCAPE, + DeviceConfiguration.DESKTOP -> { + Column( + modifier = rootModifier + .verticalScroll(rememberScrollState()) + .padding(top = 48.dp), + verticalArrangement = Arrangement.spacedBy(32.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + RegistrationHeader( + modifier = Modifier + .widthIn(max = 540.dp), + alignment = Alignment.CenterHorizontally + ) + RegistrationSheet( + onNavigateToLogIn = onNavigateToLogIn, + modifier = Modifier + .widthIn(max = 540.dp), + snackbarHostState = snackbarHostState + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/registration/vm/RegistrationViewModel.kt b/auth/presentation/src/main/java/com/example/presentation/registration/RegistrationViewModel.kt similarity index 90% rename from app/src/main/java/com/example/notemark/auth/presentation/registration/vm/RegistrationViewModel.kt rename to auth/presentation/src/main/java/com/example/presentation/registration/RegistrationViewModel.kt index 37dbace..03c7f02 100644 --- a/app/src/main/java/com/example/notemark/auth/presentation/registration/vm/RegistrationViewModel.kt +++ b/auth/presentation/src/main/java/com/example/presentation/registration/RegistrationViewModel.kt @@ -1,11 +1,11 @@ -package com.example.notemark.auth.presentation.registration.vm +package com.example.presentation.registration import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.notemark.auth.data.remote.api.RegistrationService -import com.example.notemark.auth.domain.model.RegistrationModel +import com.example.domain.RegistrationService +import com.example.domain.model.RegistrationModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject diff --git a/auth/presentation/src/main/java/com/example/presentation/registration/components/RegistrationHeader.kt b/auth/presentation/src/main/java/com/example/presentation/registration/components/RegistrationHeader.kt new file mode 100644 index 0000000..268d0ca --- /dev/null +++ b/auth/presentation/src/main/java/com/example/presentation/registration/components/RegistrationHeader.kt @@ -0,0 +1,34 @@ +package com.example.presentation.registration.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +internal fun RegistrationHeader( + modifier: Modifier = Modifier, + alignment: Alignment.Horizontal = Alignment.Start +) { + Column( + modifier = modifier, + horizontalAlignment = alignment + ) { + Text( + text = "Create account", + style = MaterialTheme.typography.titleLarge + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Capture your thoughts and ideas.", + style = MaterialTheme.typography.bodyLarge + ) + } +} \ No newline at end of file diff --git a/auth/presentation/src/main/java/com/example/presentation/registration/components/RegistrationSheet.kt b/auth/presentation/src/main/java/com/example/presentation/registration/components/RegistrationSheet.kt new file mode 100644 index 0000000..26d4af5 --- /dev/null +++ b/auth/presentation/src/main/java/com/example/presentation/registration/components/RegistrationSheet.kt @@ -0,0 +1,169 @@ +package com.example.presentation.registration.components + +import android.util.Log +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.dp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import com.example.presentation.components.NoteMarkButton +import com.example.presentation.components.NoteMarkLink +import com.example.presentation.components.NoteMarkTextField +import com.example.presentation.registration.RegistrationState +import com.example.presentation.registration.RegistrationViewModel +import com.example.presentation.FormValidation +import com.example.presentation.ValidationResult +import kotlinx.coroutines.launch + +@Composable +internal fun RegistrationSheet( + modifier: Modifier = Modifier, + onNavigateToLogIn: () -> Unit = {}, + snackbarHostState : SnackbarHostState +) { + val scope = rememberCoroutineScope() + val registrationViewModel: RegistrationViewModel = hiltViewModel() + val registrationState by registrationViewModel.registrationState + + var username by remember { mutableStateOf("") } + var email by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + var repeatPassword by remember { mutableStateOf("") } + val focusManager = LocalFocusManager.current + + LaunchedEffect(registrationState) { + when(registrationState) { + is RegistrationState.Success -> { + onNavigateToLogIn() + registrationViewModel.clearState() + } + is RegistrationState.Error -> { + Log.e("RegistrationScreen", "Registration failed: ${(registrationState as RegistrationState.Error).message}") + scope.launch { + val result = snackbarHostState + .showSnackbar( + message = "Invalid registration credentials: ${(registrationState as RegistrationState.Error).message}", + actionLabel = "", + duration = SnackbarDuration.Short + ) + when (result) { + SnackbarResult.ActionPerformed -> {} + SnackbarResult.Dismissed -> {} + } + } + } + RegistrationState.Idle -> {} + RegistrationState.Loading -> {} + } + } + + val usernameValidation = FormValidation.validateUsername(username) + val emailValidation = FormValidation.validateEmail(email) + val passwordValidation = FormValidation.validatePassword(password) + val repeatPasswordValidation = FormValidation.validateRepeatPassword(password, repeatPassword) + + val isFormValid = FormValidation.isFormValid(username, email, password, repeatPassword) + + Column( + modifier = modifier + .fillMaxSize() + .padding(top = 24.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + NoteMarkTextField( + text = username, + onValueChange = { username = it }, + label = "Username", + hint = "Enter username", + isInputSecret = false, + focusManager = focusManager, + focusDirection = FocusDirection.Down, + imeAction = ImeAction.Next, + errorText = if (usernameValidation is ValidationResult.Error) usernameValidation.message else null, + isError = usernameValidation is ValidationResult.Error, + showFocusText = "Use between 3 and 20 characters for your username." + ) + + NoteMarkTextField( + text = email, + onValueChange = { email = it }, + label = "Email", + hint = "Enter email", + isInputSecret = false, + focusManager = focusManager, + focusDirection = FocusDirection.Down, + imeAction = ImeAction.Next, + errorText = if (emailValidation is ValidationResult.Error) emailValidation.message else null, + isError = emailValidation is ValidationResult.Error + ) + + NoteMarkTextField( + text = password, + onValueChange = { password = it }, + label = "Password", + hint = "Enter password", + isInputSecret = true, + focusManager = focusManager, + focusDirection = FocusDirection.Down, + imeAction = ImeAction.Next, + errorText = if (passwordValidation is ValidationResult.Error) passwordValidation.message else null, + isError = passwordValidation is ValidationResult.Error, + showFocusText = "Use 8+ characters with a number or symbol for better security." + ) + + NoteMarkTextField( + text = repeatPassword, + onValueChange = { repeatPassword = it }, + label = "Repeat Password", + hint = "Repeat password", + isInputSecret = true, + focusManager = focusManager, + focusDirection = FocusDirection.Down, + imeAction = ImeAction.Done, + errorText = if (repeatPasswordValidation is ValidationResult.Error) repeatPasswordValidation.message else null, + isError = repeatPasswordValidation is ValidationResult.Error + ) + + Spacer(modifier = Modifier.height(16.dp)) + + NoteMarkButton( + text = if (registrationState is RegistrationState.Loading) "" else "Create account", + onClick = { + registrationViewModel.registerUser( + username = username, + email = email, + password = password + ) + }, + enabled = isFormValid, + modifier = Modifier.fillMaxWidth(), + isLoading = registrationState is RegistrationState.Loading + ) + + Spacer(modifier = Modifier.height(8.dp)) + + NoteMarkLink( + text = "Already have an account?", + onClick = { onNavigateToLogIn() }, + modifier = Modifier.fillMaxWidth() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/vm/AuthViewModel.kt b/auth/presentation/src/main/java/com/example/presentation/vm/AuthViewModel.kt similarity index 81% rename from app/src/main/java/com/example/notemark/auth/presentation/vm/AuthViewModel.kt rename to auth/presentation/src/main/java/com/example/presentation/vm/AuthViewModel.kt index 4b42dd9..abe40c0 100644 --- a/app/src/main/java/com/example/notemark/auth/presentation/vm/AuthViewModel.kt +++ b/auth/presentation/src/main/java/com/example/presentation/vm/AuthViewModel.kt @@ -1,7 +1,7 @@ -package com.example.notemark.auth.presentation.vm +package com.example.presentation.vm import androidx.lifecycle.ViewModel -import com.example.notemark.core.manager.SessionManager +import com.example.domain.SessionRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -10,15 +10,13 @@ import javax.inject.Inject @HiltViewModel class AuthViewModel @Inject constructor( - private val sessionManager: SessionManager + private val sessionManager: SessionRepository ) : ViewModel() { private val _authState = MutableStateFlow(AuthState.Loading) val authState: StateFlow = _authState.asStateFlow() - init { - checkAuthenticationStatus() - } + init { checkAuthenticationStatus() } private fun checkAuthenticationStatus() { diff --git a/app/src/main/res/drawable/image.png b/auth/presentation/src/main/res/drawable/image.png similarity index 100% rename from app/src/main/res/drawable/image.png rename to auth/presentation/src/main/res/drawable/image.png diff --git a/build-logic/.kotlin/errors/errors-1768472990915.log b/build-logic/.kotlin/errors/errors-1768472990915.log new file mode 100644 index 0000000..d05de87 --- /dev/null +++ b/build-logic/.kotlin/errors/errors-1768472990915.log @@ -0,0 +1,73 @@ +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:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + 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:194) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169) + at org.gradle.internal.Factories$1.create(Factories.java:31) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133) + 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.io.FileNotFoundException: /Users/invoke/AndroidStudioProjects/NoteMark/build-logic/convention/build/kotlin/compileKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin (No such file or directory) + at java.base/java.io.FileOutputStream.open0(Native Method) + at java.base/java.io.FileOutputStream.open(Unknown Source) + at java.base/java.io.FileOutputStream.(Unknown Source) + at java.base/java.io.FileOutputStream.(Unknown Source) + at org.jetbrains.kotlin.incremental.storage.ExternalizersKt.saveToFile(externalizers.kt:178) + at org.jetbrains.kotlin.incremental.classpathDiff.ClasspathSnapshotShrinkerKt.shrinkAndSaveClasspathSnapshot(ClasspathSnapshotShrinker.kt:299) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.performWorkAfterCompilation(IncrementalJvmCompilerRunner.kt:476) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.performWorkAfterCompilation(IncrementalJvmCompilerRunner.kt:73) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:425) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + 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 + + diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 67ee423..9cd3357 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -19,6 +19,10 @@ dependencies { gradlePlugin { plugins { + register("ktorClientConvention") { + id = "notemark.convention.ktor.client" + implementationClass = "KtorClientConventionPlugin" + } register("androidApp") { id = "notemark.android.application" implementationClass = "AndroidAppConventionPlugin" diff --git a/build-logic/convention/src/main/java/AndroidAppConventionPlugin.kt b/build-logic/convention/src/main/java/AndroidAppConventionPlugin.kt index 1334200..16aa792 100644 --- a/build-logic/convention/src/main/java/AndroidAppConventionPlugin.kt +++ b/build-logic/convention/src/main/java/AndroidAppConventionPlugin.kt @@ -16,9 +16,9 @@ class AndroidAppConventionPlugin : Plugin { pluginManager.run { apply(libs.findPlugin("android.application").get().get().pluginId) apply(libs.findPlugin("kotlin.android").get().get().pluginId) - apply(libs.findPlugin("kotlin.compose").get().get().pluginId) apply(libs.findPlugin("kotlin.serialization").get().get().pluginId) - apply(libs.findPlugin("room").get().get().pluginId) + apply("androidx.room") + apply("org.jetbrains.kotlin.plugin.compose") } extensions.configure { diff --git a/build-logic/convention/src/main/java/AndroidLibComposeConventionPlugin.kt b/build-logic/convention/src/main/java/AndroidLibComposeConventionPlugin.kt index 2542d0d..46a08b9 100644 --- a/build-logic/convention/src/main/java/AndroidLibComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/java/AndroidLibComposeConventionPlugin.kt @@ -11,7 +11,7 @@ class AndroidLibComposeConventionPlugin : Plugin { target.run { pluginManager.run { apply(libs.findPlugin("notemark.android.library").get().get().pluginId) - apply(libs.findPlugin("kotlin.compose").get().get().pluginId) + apply(libs.findPlugin("compose.compiler").get().get().pluginId) } val extension = extensions.getByType() diff --git a/build-logic/convention/src/main/java/KtorClientConventionPlugin.kt b/build-logic/convention/src/main/java/KtorClientConventionPlugin.kt new file mode 100644 index 0000000..9a6f142 --- /dev/null +++ b/build-logic/convention/src/main/java/KtorClientConventionPlugin.kt @@ -0,0 +1,27 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.getByType + +class KtorClientConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + // 1. Apply the serialization plugin required by Ktor for JSON processing + pluginManager.apply("org.jetbrains.kotlin.plugin.serialization") + + val libs = extensions.getByType().named("libs") + + // 2. Add Ktor libraries as dependencies + dependencies { + "implementation"(libs.findLibrary("ktor-client-auth").get()) + "implementation"(libs.findLibrary("ktor-client-core").get()) + "implementation"(libs.findLibrary("ktor-client-android").get()) + "implementation"(libs.findLibrary("ktor-client-cio").get()) + "implementation"(libs.findLibrary("ktor-client-content-negotiation").get()) + "implementation"(libs.findLibrary("ktor-serialization").get()) + "implementation"(libs.findLibrary("ktor-client-logging").get()) + } + } + } +} diff --git a/build-logic/convention/src/main/java/com/example/convention/BuildType.kt b/build-logic/convention/src/main/java/com/example/convention/BuildType.kt index fa8dbc3..cf883ee 100644 --- a/build-logic/convention/src/main/java/com/example/convention/BuildType.kt +++ b/build-logic/convention/src/main/java/com/example/convention/BuildType.kt @@ -19,6 +19,7 @@ internal fun Project.configureBuildTypes( commonExtension.run { buildFeatures { buildConfig = true + compose = true } when (extensionType) { @@ -26,6 +27,7 @@ internal fun Project.configureBuildTypes( extensions.configure { buildTypes { debug { + buildConfigField ("String", "BASE_URL", "\"https://notemark.pl-coding.com/\"") isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), @@ -33,6 +35,7 @@ internal fun Project.configureBuildTypes( ) } release { + buildConfigField ("String", "BASE_URL", "\"https://notemark.pl-coding.com/\"") isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), @@ -47,6 +50,7 @@ internal fun Project.configureBuildTypes( extensions.configure { buildTypes { debug { + buildConfigField ("String", "BASE_URL", "\"https://notemark.pl-coding.com/\"") isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), @@ -54,6 +58,7 @@ internal fun Project.configureBuildTypes( ) } release { + buildConfigField ("String", "BASE_URL", "\"https://notemark.pl-coding.com/\"") isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), diff --git a/build.gradle.kts b/build.gradle.kts index f80232c..dc71206 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,9 +2,10 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false - alias(libs.plugins.kotlin.compose) apply false - id("com.google.dagger.hilt.android") version "2.56.2" apply false - id("com.google.devtools.ksp") version "2.2.10-2.0.2" - id("org.jetbrains.kotlin.plugin.serialization") version "2.2.0" apply false + alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.room) apply false + id("com.google.dagger.hilt.android") version "2.54" apply false + alias(libs.plugins.ksp) apply false + alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.android.library) apply false } \ No newline at end of file diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index a44a841..416ba4e 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -1,12 +1,15 @@ plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) + alias(libs.plugins.notemark.android.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.ktor.client.convention) } android { - namespace = "com.example.data" + namespace = "com.example.notemark.core.data" } dependencies { + implementation(libs.kotlinx.coroutines.core) implementation(projects.core.domain) + implementation(projects.auth.domain) } \ No newline at end of file diff --git a/core/data/src/main/AndroidManifest.xml b/core/data/src/main/AndroidManifest.xml index a5918e6..8c4c982 100644 --- a/core/data/src/main/AndroidManifest.xml +++ b/core/data/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/AndroidConnectivityObserver.kt b/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt similarity index 96% rename from app/src/main/java/com/example/notemark/AndroidConnectivityObserver.kt rename to core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt index 6ed99e8..57f2a33 100644 --- a/app/src/main/java/com/example/notemark/AndroidConnectivityObserver.kt +++ b/core/data/src/main/java/com/example/data/AndroidConnectivityObserver.kt @@ -1,11 +1,11 @@ -package com.example.notemark +package com.example.data import android.content.Context import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities -import android.util.Log import androidx.core.content.getSystemService +import com.example.domain.ConnectivityObserver import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow diff --git a/core/data/src/main/java/com/example/data/AppModule.kt b/core/data/src/main/java/com/example/data/AppModule.kt new file mode 100644 index 0000000..6875364 --- /dev/null +++ b/core/data/src/main/java/com/example/data/AppModule.kt @@ -0,0 +1,21 @@ +package com.example.data + +import android.content.Context +import com.example.domain.ConnectivityObserver +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object AppModule { + + @Provides + @Singleton + fun provideConnectivityObserver( + @ApplicationContext context: Context + ): ConnectivityObserver = AndroidConnectivityObserver(context) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/factory/ClientFactory.kt b/core/data/src/main/java/com/example/data/ClientFactory.kt similarity index 91% rename from app/src/main/java/com/example/notemark/core/factory/ClientFactory.kt rename to core/data/src/main/java/com/example/data/ClientFactory.kt index 7951405..9e9c777 100644 --- a/app/src/main/java/com/example/notemark/core/factory/ClientFactory.kt +++ b/core/data/src/main/java/com/example/data/ClientFactory.kt @@ -1,7 +1,8 @@ -package com.example.notemark.core.factory +package com.example.data -import com.example.notemark.core.HttpRoutes -import com.example.notemark.core.manager.SessionManager +import com.example.domain.HttpRoutes +import com.example.domain.model.AccessTokenRequest +import com.example.domain.model.AccessTokenResponse import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.engine.cio.CIO @@ -19,7 +20,7 @@ import io.ktor.http.ContentType import io.ktor.http.contentType import io.ktor.http.isSuccess import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.Serializable +import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.json.Json import javax.inject.Inject @@ -47,6 +48,7 @@ class HttpClientFactory @Inject constructor( } } + @OptIn(InternalSerializationApi::class) fun build(): HttpClient { return HttpClient(CIO) { install(ContentNegotiation) { @@ -107,6 +109,7 @@ class HttpClientFactory @Inject constructor( BearerTokens(accessToken = "", refreshToken = "") } } catch (e: Exception) { + e.printStackTrace() sessionManager.clearTokens() BearerTokens(accessToken = "", refreshToken = "") } @@ -115,15 +118,4 @@ class HttpClientFactory @Inject constructor( } } } -} - -@Serializable -data class AccessTokenRequest( - val refreshToken: String -) - -@Serializable -data class AccessTokenResponse( - val accessToken: String, - val refreshToken: String, -) \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/di/NetworkModule.kt b/core/data/src/main/java/com/example/data/NetworkModule.kt similarity index 79% rename from app/src/main/java/com/example/notemark/core/di/NetworkModule.kt rename to core/data/src/main/java/com/example/data/NetworkModule.kt index 3e60ca4..4169a32 100644 --- a/app/src/main/java/com/example/notemark/core/di/NetworkModule.kt +++ b/core/data/src/main/java/com/example/data/NetworkModule.kt @@ -1,7 +1,5 @@ -package com.example.notemark.core.di +package com.example.data -import com.example.notemark.core.factory.HttpClientFactory -import com.example.notemark.core.manager.SessionManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/core/data/src/main/java/com/example/data/SessionManager.kt b/core/data/src/main/java/com/example/data/SessionManager.kt new file mode 100644 index 0000000..4b19ec4 --- /dev/null +++ b/core/data/src/main/java/com/example/data/SessionManager.kt @@ -0,0 +1,169 @@ +package com.example.data + +import android.content.Context +import android.content.SharedPreferences +import android.util.Log +import com.example.domain.SessionRepository +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject + +class SessionManager @Inject constructor( + @ApplicationContext context: Context // ✅ Add @ApplicationContext +): SessionRepository { + + companion object { + private const val TAG = "SessionManager" + const val PREF_NAME = "NoteMarkPrefs" + const val ACCESS_TOKEN = "access_token" + const val REFRESH_TOKEN = "refresh_token" + const val USER_NAME = "user_name" + const val USER_EMAIL = "user_email" + const val IS_LOGGED_IN = "is_logged_in" + } + + private val sharedPrefs: SharedPreferences = + context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + + override fun saveTokens(accessToken: String, refreshToken: String) { + try { + sharedPrefs.edit().apply { + putString(ACCESS_TOKEN, accessToken) + putString(REFRESH_TOKEN, refreshToken) + putBoolean(IS_LOGGED_IN, true) + apply() + } + Log.d(TAG, "Tokens saved successfully") + } catch (e: Exception) { + Log.e(TAG, "Error saving tokens: ${e.message}") + } + } + + override fun saveUserName(userName: String) { + try { + sharedPrefs.edit().apply { + putString(USER_NAME, userName) + apply() + } + Log.d(TAG, "Username saved successfully") + } catch (e: Exception) { + Log.e(TAG, "Error saving username: ${e.message}") + } + } + + fun saveUserEmail(email: String) { + try { + sharedPrefs.edit().apply { + putString(USER_EMAIL, email) + apply() + } + Log.d(TAG, "Email saved successfully") + } catch (e: Exception) { + Log.e(TAG, "Error saving email: ${e.message}") + } + } + + override fun getUserName(): String? { + return try { + sharedPrefs.getString(USER_NAME, null) + } catch (e: Exception) { + Log.e(TAG, "Error getting username: ${e.message}") + null + } + } + + fun getUserEmail(): String? { + return try { + sharedPrefs.getString(USER_EMAIL, null) + } catch (e: Exception) { + Log.e(TAG, "Error getting email: ${e.message}") + null + } + } + + override fun getAccessToken(): String? { + return try { + sharedPrefs.getString(ACCESS_TOKEN, null) + } catch (e: Exception) { + Log.e(TAG, "Error getting access token: ${e.message}") + null + } + } + + override fun getRefreshToken(): String? { + return try { + sharedPrefs.getString(REFRESH_TOKEN, null) + } catch (e: Exception) { + Log.e(TAG, "Error getting refresh token: ${e.message}") + null + } + } + + override fun clearUserName() { + try { + sharedPrefs.edit().apply { + remove(USER_NAME) + apply() + } + Log.d(TAG, "Username cleared successfully") + } catch (e: Exception) { + Log.e(TAG, "Error clearing username: ${e.message}") + } + } + + + fun clearUserEmail() { + try { + sharedPrefs.edit().apply { + remove(USER_EMAIL) + apply() + } + Log.d(TAG, "Email cleared successfully") + } catch (e: Exception) { + Log.e(TAG, "Error clearing email: ${e.message}") + } + } + + override fun clearTokens() { + try { + sharedPrefs.edit().apply { + remove(ACCESS_TOKEN) + remove(REFRESH_TOKEN) + putBoolean(IS_LOGGED_IN, false) + apply() + } + Log.d(TAG, "Tokens cleared successfully") + } catch (e: Exception) { + Log.e(TAG, "Error clearing tokens: ${e.message}") + } + } + + override fun clearAllData() { + try { + sharedPrefs.edit().clear().apply() + Log.d(TAG, "All session data cleared successfully") + } catch (e: Exception) { + Log.e(TAG, "Error clearing all data: ${e.message}") + } + } + + override fun isLoggedIn(): Boolean { + return try { + val hasToken = !getAccessToken().isNullOrEmpty() + val isLoggedIn = sharedPrefs.getBoolean(IS_LOGGED_IN, false) + hasToken && isLoggedIn + } catch (e: Exception) { + Log.e(TAG, "Error checking login status: ${e.message}") + false + } + } + + fun getAllSessionData(): Map { + return mapOf( + "userName" to getUserName(), + "userEmail" to getUserEmail(), + "accessToken" to getAccessToken()?.take(10) + "...", // Don't log full token + "refreshToken" to getRefreshToken()?.take(10) + "...", // Don't log full token + "isLoggedIn" to isLoggedIn().toString() + ) + } +} \ No newline at end of file diff --git a/core/data/src/main/java/com/example/data/SessionModule.kt b/core/data/src/main/java/com/example/data/SessionModule.kt new file mode 100644 index 0000000..7d95ed1 --- /dev/null +++ b/core/data/src/main/java/com/example/data/SessionModule.kt @@ -0,0 +1,22 @@ +package com.example.data + +import android.content.Context +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object SessionModule { + + @Provides + @Singleton + fun provideSessionManager( + @ApplicationContext context: Context + ): SessionManager { + return SessionManager(context) + } +} \ No newline at end of file diff --git a/core/domain/build.gradle.kts b/core/domain/build.gradle.kts index 28db768..977bb8e 100644 --- a/core/domain/build.gradle.kts +++ b/core/domain/build.gradle.kts @@ -3,5 +3,5 @@ plugins { } dependencies { - + implementation(libs.kotlinx.coroutines.core) } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/ConnectivityObserver.kt b/core/domain/src/main/java/com/example/domain/ConnectivityObserver.kt similarity index 93% rename from app/src/main/java/com/example/notemark/ConnectivityObserver.kt rename to core/domain/src/main/java/com/example/domain/ConnectivityObserver.kt index 8758a75..d9c201a 100644 --- a/app/src/main/java/com/example/notemark/ConnectivityObserver.kt +++ b/core/domain/src/main/java/com/example/domain/ConnectivityObserver.kt @@ -1,4 +1,4 @@ -package com.example.notemark +package com.example.domain import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first diff --git a/app/src/main/java/com/example/notemark/auth/domain/DataError.kt b/core/domain/src/main/java/com/example/domain/DataError.kt similarity index 91% rename from app/src/main/java/com/example/notemark/auth/domain/DataError.kt rename to core/domain/src/main/java/com/example/domain/DataError.kt index 27fb6ca..28536e1 100644 --- a/app/src/main/java/com/example/notemark/auth/domain/DataError.kt +++ b/core/domain/src/main/java/com/example/domain/DataError.kt @@ -1,4 +1,4 @@ -package com.example.notemark.auth.domain +package com.example.domain sealed interface DataError: Error { diff --git a/core/domain/src/main/java/com/example/domain/Error.kt b/core/domain/src/main/java/com/example/domain/Error.kt new file mode 100644 index 0000000..d5b7a4d --- /dev/null +++ b/core/domain/src/main/java/com/example/domain/Error.kt @@ -0,0 +1,3 @@ +package com.example.domain + +sealed interface Error \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/HttpRoutes.kt b/core/domain/src/main/java/com/example/domain/HttpRoutes.kt similarity index 92% rename from app/src/main/java/com/example/notemark/core/HttpRoutes.kt rename to core/domain/src/main/java/com/example/domain/HttpRoutes.kt index 2ef7cb7..c734505 100644 --- a/app/src/main/java/com/example/notemark/core/HttpRoutes.kt +++ b/core/domain/src/main/java/com/example/domain/HttpRoutes.kt @@ -1,4 +1,4 @@ -package com.example.notemark.core +package com.example.domain object HttpRoutes { diff --git a/core/domain/src/main/java/com/example/domain/Note.kt b/core/domain/src/main/java/com/example/domain/Note.kt new file mode 100644 index 0000000..762c55e --- /dev/null +++ b/core/domain/src/main/java/com/example/domain/Note.kt @@ -0,0 +1,9 @@ +package com.example.domain + +data class Note( + val id: String, + val title: String, + val content: String, + val createdAt: String, + val updatedAt: String? = "" +) \ No newline at end of file diff --git a/core/domain/src/main/java/com/example/domain/NoteRequest.kt b/core/domain/src/main/java/com/example/domain/NoteRequest.kt new file mode 100644 index 0000000..ce131a2 --- /dev/null +++ b/core/domain/src/main/java/com/example/domain/NoteRequest.kt @@ -0,0 +1,9 @@ +package com.example.domain + +data class NoteRequest( + val id: String, + val title: String, + val content: String, + val createdAt: String, + val updatedAt: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/domain/Resource.kt b/core/domain/src/main/java/com/example/domain/Resource.kt similarity index 83% rename from app/src/main/java/com/example/notemark/auth/domain/Resource.kt rename to core/domain/src/main/java/com/example/domain/Resource.kt index c9bbf28..3d8c5b4 100644 --- a/app/src/main/java/com/example/notemark/auth/domain/Resource.kt +++ b/core/domain/src/main/java/com/example/domain/Resource.kt @@ -1,4 +1,4 @@ -package com.example.notemark.auth.domain +package com.example.domain sealed class Resource(val data: T? = null, val message: String? = null) { class Success(data: T?): Resource(data) diff --git a/app/src/main/java/com/example/notemark/auth/domain/RootError.kt b/core/domain/src/main/java/com/example/domain/RootError.kt similarity index 84% rename from app/src/main/java/com/example/notemark/auth/domain/RootError.kt rename to core/domain/src/main/java/com/example/domain/RootError.kt index 2b55048..b6506d5 100644 --- a/app/src/main/java/com/example/notemark/auth/domain/RootError.kt +++ b/core/domain/src/main/java/com/example/domain/RootError.kt @@ -1,4 +1,4 @@ -package com.example.notemark.auth.domain +package com.example.domain typealias RootError = Error diff --git a/core/domain/src/main/java/com/example/domain/SessionRepository.kt b/core/domain/src/main/java/com/example/domain/SessionRepository.kt new file mode 100644 index 0000000..026c98e --- /dev/null +++ b/core/domain/src/main/java/com/example/domain/SessionRepository.kt @@ -0,0 +1,22 @@ +package com.example.domain + +interface SessionRepository { + + fun saveTokens(accessToken: String, refreshToken: String) + + fun saveUserName(userName: String) + + fun getUserName(): String? + + fun getAccessToken(): String? + + fun getRefreshToken(): String? + + fun clearUserName() + + fun clearTokens() + + fun isLoggedIn(): Boolean + + fun clearAllData() +} \ No newline at end of file diff --git a/core/presentation/build.gradle.kts b/core/presentation/build.gradle.kts index eba01ce..7599737 100644 --- a/core/presentation/build.gradle.kts +++ b/core/presentation/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } android { - namespace = "com.example.presentation" + namespace = "com.example.notemark.core.presentation" } dependencies { diff --git a/app/src/main/java/com/example/notemark/ConnectivityViewModel.kt b/core/presentation/src/main/java/com/example/presentation/ConnectivityViewModel.kt similarity index 85% rename from app/src/main/java/com/example/notemark/ConnectivityViewModel.kt rename to core/presentation/src/main/java/com/example/presentation/ConnectivityViewModel.kt index 2ce9f17..2dab206 100644 --- a/app/src/main/java/com/example/notemark/ConnectivityViewModel.kt +++ b/core/presentation/src/main/java/com/example/presentation/ConnectivityViewModel.kt @@ -1,7 +1,8 @@ -package com.example.notemark +package com.example.presentation import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.example.domain.ConnectivityObserver import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn diff --git a/app/src/main/java/com/example/notemark/main/DateFormatter.kt b/core/presentation/src/main/java/com/example/presentation/DateFormatter.kt similarity index 98% rename from app/src/main/java/com/example/notemark/main/DateFormatter.kt rename to core/presentation/src/main/java/com/example/presentation/DateFormatter.kt index 052049d..0603634 100644 --- a/app/src/main/java/com/example/notemark/main/DateFormatter.kt +++ b/core/presentation/src/main/java/com/example/presentation/DateFormatter.kt @@ -1,4 +1,4 @@ -package com.example.notemark.main +package com.example.presentation import java.time.Instant import java.time.LocalDateTime diff --git a/core/presentation/src/main/java/com/example/presentation/DeviceConfiguration.kt b/core/presentation/src/main/java/com/example/presentation/DeviceConfiguration.kt new file mode 100644 index 0000000..8354634 --- /dev/null +++ b/core/presentation/src/main/java/com/example/presentation/DeviceConfiguration.kt @@ -0,0 +1,29 @@ +package com.example.presentation + +import androidx.window.core.layout.WindowHeightSizeClass +import androidx.window.core.layout.WindowSizeClass +import androidx.window.core.layout.WindowWidthSizeClass + +enum class DeviceConfiguration { + MOBILE_PORTRAIT, + MOBILE_LANDSCAPE, + TABLET_PORTRAIT, + TABLET_LANDSCAPE, + DESKTOP; + + companion object { + fun fromWindowSizeClass(windowSizeClass: WindowSizeClass): DeviceConfiguration { + val widthClass = windowSizeClass.windowWidthSizeClass + val heightClass = windowSizeClass.windowHeightSizeClass + + return when (widthClass) { + WindowWidthSizeClass.COMPACT if heightClass == WindowHeightSizeClass.MEDIUM -> MOBILE_PORTRAIT + WindowWidthSizeClass.COMPACT if heightClass == WindowHeightSizeClass.EXPANDED -> MOBILE_PORTRAIT + WindowWidthSizeClass.EXPANDED if heightClass == WindowHeightSizeClass.COMPACT -> MOBILE_LANDSCAPE + WindowWidthSizeClass.MEDIUM if heightClass == WindowHeightSizeClass.EXPANDED -> TABLET_PORTRAIT + WindowWidthSizeClass.EXPANDED if heightClass == WindowHeightSizeClass.MEDIUM -> TABLET_LANDSCAPE + else -> DESKTOP + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/util/FormValidation.kt b/core/presentation/src/main/java/com/example/presentation/FormValidation.kt similarity index 97% rename from app/src/main/java/com/example/notemark/auth/presentation/util/FormValidation.kt rename to core/presentation/src/main/java/com/example/presentation/FormValidation.kt index 8eedaea..977d786 100644 --- a/app/src/main/java/com/example/notemark/auth/presentation/util/FormValidation.kt +++ b/core/presentation/src/main/java/com/example/presentation/FormValidation.kt @@ -1,4 +1,4 @@ -package com.example.notemark.auth.presentation.util +package com.example.presentation import android.util.Patterns diff --git a/core/presentation/src/main/java/com/example/presentation/NoteMarkDefaultScreen.kt b/core/presentation/src/main/java/com/example/presentation/NoteMarkDefaultScreen.kt new file mode 100644 index 0000000..dd607e5 --- /dev/null +++ b/core/presentation/src/main/java/com/example/presentation/NoteMarkDefaultScreen.kt @@ -0,0 +1,48 @@ +package com.example.presentation + +import android.app.Activity +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowInsetsControllerCompat + +@Composable +fun NoteMarkDefaultScreen( + modifier: Modifier = Modifier, + containerColor: Color = MaterialTheme.colorScheme.background, + bottomBar: @Composable () -> Unit = {}, + content: @Composable () -> Unit = {}, +) { + Scaffold( + bottomBar = { bottomBar() }, + modifier = modifier, + containerColor = containerColor, + ) { innerPadding -> + val view = LocalView.current + Box( + modifier = + Modifier + .padding(innerPadding), + ) { + content() + } + + SideEffect { + val window = (view.context as? Activity)?.window + if (!view.isInEditMode && window != null) { + val isLightBackground = containerColor.luminance() > 0.5f + + WindowInsetsControllerCompat(window, window.decorView).apply { + isAppearanceLightStatusBars = isLightBackground + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/auth/presentation/UiText.kt b/core/presentation/src/main/java/com/example/presentation/UiText.kt similarity index 94% rename from app/src/main/java/com/example/notemark/auth/presentation/UiText.kt rename to core/presentation/src/main/java/com/example/presentation/UiText.kt index cf1b64a..f7447d3 100644 --- a/app/src/main/java/com/example/notemark/auth/presentation/UiText.kt +++ b/core/presentation/src/main/java/com/example/presentation/UiText.kt @@ -1,4 +1,4 @@ -package com.example.notemark.auth.presentation +package com.example.presentation import android.content.Context import androidx.annotation.StringRes diff --git a/core/presentation/src/main/java/com/example/presentation/asUiText.kt b/core/presentation/src/main/java/com/example/presentation/asUiText.kt new file mode 100644 index 0000000..9682f6e --- /dev/null +++ b/core/presentation/src/main/java/com/example/presentation/asUiText.kt @@ -0,0 +1,44 @@ +package com.example.presentation + +import com.example.notemark.core.presentation.R +import com.example.domain.DataError + +fun DataError.asUiText(): UiText { + return when (this) { + DataError.Network.REQUEST_TIMEOUT -> UiText.StringResource( + R.string.the_request_timed_out + ) + + DataError.Network.TOO_MANY_REQUESTS -> UiText.StringResource( + R.string.youve_hit_your_rate_limit + ) + + DataError.Network.NO_INTERNET -> UiText.StringResource( + R.string.no_internet + ) + + DataError.Network.SERVER_ERROR -> UiText.StringResource( + R.string.server_error + ) + + DataError.Network.UNKNOWN -> UiText.StringResource( + R.string.unknown_error + ) + + DataError.Local.DISK_FULL -> UiText.StringResource( + R.string.disk_full + ) + + DataError.ValidationErrors.INVALID_FORMAT -> UiText.StringResource( + R.string.invalid_format + ) + + DataError.Note.NOTE_IS_NOT_DELETED -> UiText.StringResource( + R.string.note_is_not_deleted + ) + } +} + +//fun Result.Error<*, DataError>.asErrorUiText(): UiText { +// return error.asUiText() +//} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/components/NoteMarkButton.kt b/core/presentation/src/main/java/com/example/presentation/components/NoteMarkButton.kt similarity index 96% rename from app/src/main/java/com/example/notemark/core/components/NoteMarkButton.kt rename to core/presentation/src/main/java/com/example/presentation/components/NoteMarkButton.kt index 4dbfbe4..559c577 100644 --- a/app/src/main/java/com/example/notemark/core/components/NoteMarkButton.kt +++ b/core/presentation/src/main/java/com/example/presentation/components/NoteMarkButton.kt @@ -1,4 +1,4 @@ -package com.example.notemark.core.components +package com.example.presentation.components import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.size diff --git a/app/src/main/java/com/example/notemark/core/components/NoteMarkLink.kt b/core/presentation/src/main/java/com/example/presentation/components/NoteMarkLink.kt similarity index 93% rename from app/src/main/java/com/example/notemark/core/components/NoteMarkLink.kt rename to core/presentation/src/main/java/com/example/presentation/components/NoteMarkLink.kt index 0fe8919..ee272b8 100644 --- a/app/src/main/java/com/example/notemark/core/components/NoteMarkLink.kt +++ b/core/presentation/src/main/java/com/example/presentation/components/NoteMarkLink.kt @@ -1,4 +1,4 @@ -package com.example.notemark.core.components +package com.example.presentation.components import androidx.compose.foundation.clickable import androidx.compose.material3.MaterialTheme diff --git a/app/src/main/java/com/example/notemark/core/components/NoteMarkTextField.kt b/core/presentation/src/main/java/com/example/presentation/components/NoteMarkTextField.kt similarity index 98% rename from app/src/main/java/com/example/notemark/core/components/NoteMarkTextField.kt rename to core/presentation/src/main/java/com/example/presentation/components/NoteMarkTextField.kt index 0e7152a..2ac2f45 100644 --- a/app/src/main/java/com/example/notemark/core/components/NoteMarkTextField.kt +++ b/core/presentation/src/main/java/com/example/presentation/components/NoteMarkTextField.kt @@ -1,4 +1,4 @@ -package com.example.notemark.core.components +package com.example.presentation.components import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -30,7 +30,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp -import com.example.notemark.R +import com.example.notemark.core.presentation.R @Composable fun NoteMarkTextField( diff --git a/core/presentation/src/main/java/com/example/presentation/getFormattedCreatedAt.kt b/core/presentation/src/main/java/com/example/presentation/getFormattedCreatedAt.kt new file mode 100644 index 0000000..79c7b98 --- /dev/null +++ b/core/presentation/src/main/java/com/example/presentation/getFormattedCreatedAt.kt @@ -0,0 +1,6 @@ +package com.example.presentation + +import com.example.domain.Note + +fun Note.getFormattedCreatedAt(): String = createdAt.formatAsNoteDate() +fun Note.getFormattedUpdatedAt(): String = updatedAt?.formatAsDetailsDate() ?: "" \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/getInitials.kt b/core/presentation/src/main/java/com/example/presentation/getInitials.kt similarity index 85% rename from app/src/main/java/com/example/notemark/core/getInitials.kt rename to core/presentation/src/main/java/com/example/presentation/getInitials.kt index 88fdb7b..86caa97 100644 --- a/app/src/main/java/com/example/notemark/core/getInitials.kt +++ b/core/presentation/src/main/java/com/example/presentation/getInitials.kt @@ -1,4 +1,4 @@ -package com.example.notemark.core +package com.example.presentation fun getInitials(username: String): String { val trimmedName = username.trim() @@ -11,7 +11,7 @@ fun getInitials(username: String): String { words.size == 1 -> { val word = words[0].uppercase() - if (word.length >= 2) word.substring(0, 2) else word + if (word.length >= 2) word.take(2) else word } else -> { diff --git a/core/presentation/src/main/java/com/example/presentation/isValidEmail.kt b/core/presentation/src/main/java/com/example/presentation/isValidEmail.kt new file mode 100644 index 0000000..5ed6c85 --- /dev/null +++ b/core/presentation/src/main/java/com/example/presentation/isValidEmail.kt @@ -0,0 +1,5 @@ +package com.example.presentation + +import android.util.Patterns + +fun isValidEmail(email: String): Boolean = Patterns.EMAIL_ADDRESS.matcher(email).matches() \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/truncateAtWord.kt b/core/presentation/src/main/java/com/example/presentation/truncateAtWord.kt similarity index 90% rename from app/src/main/java/com/example/notemark/core/truncateAtWord.kt rename to core/presentation/src/main/java/com/example/presentation/truncateAtWord.kt index 3e29441..3009f89 100644 --- a/app/src/main/java/com/example/notemark/core/truncateAtWord.kt +++ b/core/presentation/src/main/java/com/example/presentation/truncateAtWord.kt @@ -1,4 +1,4 @@ -package com.example.notemark.core +package com.example.presentation fun String.truncateAtWord(maxLength: Int): String { if (this.length <= maxLength) return this diff --git a/app/src/main/res/drawable/book_open.xml b/core/presentation/src/main/res/drawable/book_open.xml similarity index 100% rename from app/src/main/res/drawable/book_open.xml rename to core/presentation/src/main/res/drawable/book_open.xml diff --git a/app/src/main/res/drawable/check.xml b/core/presentation/src/main/res/drawable/check.xml similarity index 100% rename from app/src/main/res/drawable/check.xml rename to core/presentation/src/main/res/drawable/check.xml diff --git a/app/src/main/res/drawable/chevron_right.xml b/core/presentation/src/main/res/drawable/chevron_right.xml similarity index 100% rename from app/src/main/res/drawable/chevron_right.xml rename to core/presentation/src/main/res/drawable/chevron_right.xml diff --git a/app/src/main/res/drawable/clock.xml b/core/presentation/src/main/res/drawable/clock.xml similarity index 100% rename from app/src/main/res/drawable/clock.xml rename to core/presentation/src/main/res/drawable/clock.xml diff --git a/app/src/main/res/drawable/cloud_off.xml b/core/presentation/src/main/res/drawable/cloud_off.xml similarity index 100% rename from app/src/main/res/drawable/cloud_off.xml rename to core/presentation/src/main/res/drawable/cloud_off.xml diff --git a/app/src/main/res/drawable/copy.xml b/core/presentation/src/main/res/drawable/copy.xml similarity index 100% rename from app/src/main/res/drawable/copy.xml rename to core/presentation/src/main/res/drawable/copy.xml diff --git a/app/src/main/res/drawable/edit.xml b/core/presentation/src/main/res/drawable/edit.xml similarity index 100% rename from app/src/main/res/drawable/edit.xml rename to core/presentation/src/main/res/drawable/edit.xml diff --git a/app/src/main/res/drawable/eye.xml b/core/presentation/src/main/res/drawable/eye.xml similarity index 100% rename from app/src/main/res/drawable/eye.xml rename to core/presentation/src/main/res/drawable/eye.xml diff --git a/app/src/main/res/drawable/eye_off.xml b/core/presentation/src/main/res/drawable/eye_off.xml similarity index 100% rename from app/src/main/res/drawable/eye_off.xml rename to core/presentation/src/main/res/drawable/eye_off.xml diff --git a/core/presentation/src/main/res/drawable/image.png b/core/presentation/src/main/res/drawable/image.png new file mode 100644 index 0000000..40331ec Binary files /dev/null and b/core/presentation/src/main/res/drawable/image.png differ diff --git a/app/src/main/res/drawable/ios_arrow_left.xml b/core/presentation/src/main/res/drawable/ios_arrow_left.xml similarity index 100% rename from app/src/main/res/drawable/ios_arrow_left.xml rename to core/presentation/src/main/res/drawable/ios_arrow_left.xml diff --git a/app/src/main/res/drawable/logo.xml b/core/presentation/src/main/res/drawable/logo.xml similarity index 100% rename from app/src/main/res/drawable/logo.xml rename to core/presentation/src/main/res/drawable/logo.xml diff --git a/app/src/main/res/drawable/logout.xml b/core/presentation/src/main/res/drawable/logout.xml similarity index 100% rename from app/src/main/res/drawable/logout.xml rename to core/presentation/src/main/res/drawable/logout.xml diff --git a/core/presentation/src/main/res/drawable/outline_delete_outline_24.xml b/core/presentation/src/main/res/drawable/outline_delete_outline_24.xml new file mode 100644 index 0000000..2e1bb74 --- /dev/null +++ b/core/presentation/src/main/res/drawable/outline_delete_outline_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/plus.xml b/core/presentation/src/main/res/drawable/plus.xml similarity index 100% rename from app/src/main/res/drawable/plus.xml rename to core/presentation/src/main/res/drawable/plus.xml diff --git a/app/src/main/res/drawable/settings.xml b/core/presentation/src/main/res/drawable/settings.xml similarity index 100% rename from app/src/main/res/drawable/settings.xml rename to core/presentation/src/main/res/drawable/settings.xml diff --git a/app/src/main/res/drawable/sync_icon.xml b/core/presentation/src/main/res/drawable/sync_icon.xml similarity index 100% rename from app/src/main/res/drawable/sync_icon.xml rename to core/presentation/src/main/res/drawable/sync_icon.xml diff --git a/app/src/main/res/drawable/x.xml b/core/presentation/src/main/res/drawable/x.xml similarity index 100% rename from app/src/main/res/drawable/x.xml rename to core/presentation/src/main/res/drawable/x.xml diff --git a/app/src/main/res/font/inter_18pt_medium.ttf b/core/presentation/src/main/res/font/inter_18pt_medium.ttf similarity index 100% rename from app/src/main/res/font/inter_18pt_medium.ttf rename to core/presentation/src/main/res/font/inter_18pt_medium.ttf diff --git a/app/src/main/res/font/inter_18pt_regular.ttf b/core/presentation/src/main/res/font/inter_18pt_regular.ttf similarity index 100% rename from app/src/main/res/font/inter_18pt_regular.ttf rename to core/presentation/src/main/res/font/inter_18pt_regular.ttf diff --git a/app/src/main/res/font/space_grotesk_regular.ttf b/core/presentation/src/main/res/font/space_grotesk_regular.ttf similarity index 100% rename from app/src/main/res/font/space_grotesk_regular.ttf rename to core/presentation/src/main/res/font/space_grotesk_regular.ttf diff --git a/app/src/main/res/raw/success.json b/core/presentation/src/main/res/raw/success.json similarity index 100% rename from app/src/main/res/raw/success.json rename to core/presentation/src/main/res/raw/success.json diff --git a/core/presentation/src/main/res/values/strings.xml b/core/presentation/src/main/res/values/strings.xml new file mode 100644 index 0000000..649be7e --- /dev/null +++ b/core/presentation/src/main/res/values/strings.xml @@ -0,0 +1,30 @@ + + + NoteMark + Request time out + Too many request + no internet + Server error occur. + Unknown error, please reach the support center. + Disk full, please clean the cache. + Invalid email + For some reason note is not deleted, please try again or contact support! + Log out + Last sync: + Sync Data + Sync interval + settings + Manual Only + 15 minutes + 30 minutes + 1 hour + You’ve got an empty board,\n let’s place your first note on it! + all notes + Date created + Last edited + update note + Discard Changes? + You have unsaved changes. If you discard now, all changes will be lost. + Discard + Keep Editing + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8a5390a..34fdf4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,55 +1,56 @@ [versions] agp = "8.13.2" -kotlin = "2.3.0" -coreKtx = "1.16.0" +kotlin = "2.2.10" +coreKtx = "1.17.0" junit = "4.13.2" -junitVersion = "1.2.1" -espressoCore = "3.6.1" +junitVersion = "1.3.0" +espressoCore = "3.7.0" # ktor -ktor = "3.2.0" -ktorClientAndroid = "3.2.0" -ktorClientCio = "3.2.0" -ktorClientCore = "3.2.0" -ktorClientLogging = "3.2.0" -ktorClientSerialization = "3.2.0" -ktorClientContentNegotiation = "3.2.0" - -lifecycleRuntimeKtx = "2.9.1" -activityCompose = "1.10.1" -composeBom = "2025.07.00" -composeNavigation = "2.9.0" -lottieCompose = "6.6.7" +ktor = "3.3.3" +ktorClientAndroid = "3.3.3" +ktorClientCio = "3.3.3" +ktorClientCore = "3.3.3" +ktorClientLogging = "3.3.3" +ktorClientSerialization = "3.3.3" +ktorClientContentNegotiation = "3.3.3" + +lifecycleRuntimeKtx = "2.10.0" +activityCompose = "1.12.2" +composeBom = "2025.12.01" +composeNavigation = "2.9.6" +lottieCompose = "6.7.1" pagingRuntimeKtx = "3.3.6" -roomKtx = "2.7.2" +roomKtx = "2.6.1" serialization = "1.9.0" -coreSplashscreen = "1.0.1" +coreSplashscreen = "1.2.0" iconExtend = "1.7.8" -adaptive = "1.1.2" +adaptive = "1.2.0" +coroutines = "1.10.2" androidTools = "31.12.0" # hilt -hiltAndroidCompiler = "2.56.2" -hiltCompiler = "1.2.0" +hiltAndroidCompiler = "2.54" +hiltCompiler = "1.3.0" -lifecycle = "2.9.2" +lifecycle = "2.10.0" appcompat = "1.7.1" material = "1.13.0" -animation = "1.8.1" -material3Adaptive = "1.1.0" +animation = "1.10.0" +material3Adaptive = "1.2.0" # room -room = "2.7.2" +room = "2.8.4" ksp = "2.2.10-2.0.2" # Project Info projectAppId = "com.example.notemark" projectVersionName = "1.0.0" projectVersionCode = "1" projectMinSdkVersion = "30" -projectTargetSdkVersion = "35" -projectCompileSdkVersion = "35" +projectTargetSdkVersion = "36" +projectCompileSdkVersion = "36" navigationRuntimeKtx = "2.9.3" [libraries] @@ -71,6 +72,7 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } # ktor ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktorClientAndroid" } ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktorClientCio" } @@ -114,7 +116,6 @@ material = { group = "com.google.android.material", name = "material", version.r # Room room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } -room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } # Gradle android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } @@ -128,13 +129,15 @@ room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", vers android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } room = { id = "androidx.room", version.ref = "room" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } + notemark-android-application = { id = "notemark.android.application", version = "unspesified" } +ktor-client-convention = { id = "notemark.convention.ktor.client", version = "unspecified" } notemark-jvm-library = { id = "notemark.jvm.library", version = "unspesified" } notemark-android-library = { id = "notemark.android.library", version = "unspesified" } notemark-android-library-compose = { id = "notemark.android.library.compose", version = "unspesified" } diff --git a/note/data/build.gradle.kts b/note/data/build.gradle.kts index d4f105d..196bf28 100644 --- a/note/data/build.gradle.kts +++ b/note/data/build.gradle.kts @@ -1,11 +1,18 @@ plugins { alias(libs.plugins.notemark.android.library) + alias(libs.plugins.ktor.client.convention) + alias(libs.plugins.ksp) + alias(libs.plugins.compose.compiler) + } android { - namespace = "com.example.data" + namespace = "com.example.notemark.note.data" } dependencies { implementation(projects.note.domain) + implementation(libs.bundles.room) + implementation(libs.androidx.paging.runtime.ktx) + implementation(projects.core.domain) } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/core/di/AppModule.kt b/note/data/src/main/java/com/example/data/di/NoteModule.kt similarity index 65% rename from app/src/main/java/com/example/notemark/core/di/AppModule.kt rename to note/data/src/main/java/com/example/data/di/NoteModule.kt index b15f8d2..55d1b76 100644 --- a/app/src/main/java/com/example/notemark/core/di/AppModule.kt +++ b/note/data/src/main/java/com/example/data/di/NoteModule.kt @@ -1,20 +1,19 @@ -package com.example.notemark.core.di +package com.example.data.di +import NoteRemoteMediator import android.content.Context import androidx.paging.ExperimentalPagingApi import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.room.Room -import com.example.notemark.AndroidConnectivityObserver -import com.example.notemark.ConnectivityObserver -import com.example.notemark.ConnectivityViewModel -import com.example.notemark.core.manager.SessionManager -import com.example.notemark.main.data.local.NoteDatabase -import com.example.notemark.main.data.local.NoteEntity -import com.example.notemark.main.data.remote.NoteRemoteMediator -import com.example.notemark.main.data.remote.api.NoteService -import com.example.notemark.main.data.remote.repositoryImpl.NoteServiceImpl -import com.example.notemark.main.domain.repository.NotesRepository +import com.example.data.local.LocalNoteDataSourceImpl +import com.example.data.local.NoteDatabase +import com.example.data.local.NoteEntity +import com.example.data.remote.NoteServiceImpl +import com.example.domain.ConnectivityObserver +import com.example.domain.LocalNoteDataSource +import com.example.domain.NoteService +import com.example.domain.SessionRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -23,10 +22,9 @@ import dagger.hilt.components.SingletonComponent import io.ktor.client.HttpClient import javax.inject.Singleton -@OptIn(ExperimentalPagingApi::class) @Module @InstallIn(SingletonComponent::class) -object AppModule { +object NoteModule { @Provides @Singleton @@ -43,7 +41,16 @@ object AppModule { @Provides @Singleton - fun provideNotesPager(notesDb: NoteDatabase, noteService: NoteService): Pager { + fun provideLocalNoteDataSource( + noteDatabase: NoteDatabase + ): LocalNoteDataSource { + return LocalNoteDataSourceImpl(noteDatabase) + } + + @OptIn(ExperimentalPagingApi::class) + @Provides + @Singleton + fun provideNotesPager(notesDb: NoteDatabase, noteService: NoteService): Pager { return Pager( config = PagingConfig(pageSize = 20), remoteMediator = NoteRemoteMediator( @@ -56,17 +63,11 @@ object AppModule { ) } - @Provides - @Singleton - fun provideConnectivityObserver( - @ApplicationContext context: Context - ): ConnectivityObserver = AndroidConnectivityObserver(context) - @Provides @Singleton fun provideNoteService( client: HttpClient, - sessionManager: SessionManager, + sessionManager: SessionRepository, @ApplicationContext applicationContext: Context, connectivityObserver: ConnectivityObserver ): NoteService { @@ -78,17 +79,11 @@ object AppModule { ) } - @Provides - @Singleton - fun provideNoteRepository(api: NoteServiceImpl): NotesRepository { - return NotesRepository(api) - } - @Provides @Singleton fun provideNoteServiceImpl( api: HttpClient, - sessionManager: SessionManager, + sessionManager: SessionRepository, @ApplicationContext applicationContext: Context, connectivityObserver: ConnectivityObserver ): NoteServiceImpl { diff --git a/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt b/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt new file mode 100644 index 0000000..c37d412 --- /dev/null +++ b/note/data/src/main/java/com/example/data/local/LocalNoteDataSourceImpl.kt @@ -0,0 +1,17 @@ +package com.example.data.local + +import com.example.domain.LocalNoteDataSource +import javax.inject.Inject + +class LocalNoteDataSourceImpl @Inject constructor( + private val noteDatabase: NoteDatabase +) : LocalNoteDataSource { + + override suspend fun clearAllNotes() { + noteDatabase.dao.clearAll() + } + + override suspend fun getNotesCount(): Int { + return noteDatabase.dao.getNotesCount() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/local/NoteDao.kt b/note/data/src/main/java/com/example/data/local/NoteDao.kt similarity index 76% rename from app/src/main/java/com/example/notemark/main/data/local/NoteDao.kt rename to note/data/src/main/java/com/example/data/local/NoteDao.kt index 4fe7e4c..ec6b8e8 100644 --- a/app/src/main/java/com/example/notemark/main/data/local/NoteDao.kt +++ b/note/data/src/main/java/com/example/data/local/NoteDao.kt @@ -1,10 +1,9 @@ -package com.example.notemark.main.data.local +package com.example.data.local import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Query import androidx.room.Upsert -import com.example.notemark.main.presentation.screens.note.SyncRecord @Dao interface NoteDao { @@ -22,7 +21,7 @@ interface NoteDao { suspend fun deleteNoteById(noteId: String) @Query("SELECT * FROM noteentity") - fun pagingSource(): PagingSource + fun pagingSource(): PagingSource @Query("DELETE FROM noteentity") suspend fun clearAll() diff --git a/note/data/src/main/java/com/example/data/local/NoteDatabase.kt b/note/data/src/main/java/com/example/data/local/NoteDatabase.kt new file mode 100644 index 0000000..76a611b --- /dev/null +++ b/note/data/src/main/java/com/example/data/local/NoteDatabase.kt @@ -0,0 +1,12 @@ +package com.example.data.local + +import androidx.room.Database +import androidx.room.RoomDatabase + +@Database( + entities = [NoteEntity::class], + version = 3 +) +abstract class NoteDatabase: RoomDatabase() { + abstract val dao: NoteDao +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/local/NoteEntity.kt b/note/data/src/main/java/com/example/data/local/NoteEntity.kt similarity index 89% rename from app/src/main/java/com/example/notemark/main/data/local/NoteEntity.kt rename to note/data/src/main/java/com/example/data/local/NoteEntity.kt index c6c82b8..29189c5 100644 --- a/app/src/main/java/com/example/notemark/main/data/local/NoteEntity.kt +++ b/note/data/src/main/java/com/example/data/local/NoteEntity.kt @@ -1,4 +1,4 @@ -package com.example.notemark.main.data.local +package com.example.data.local import androidx.room.Entity import androidx.room.PrimaryKey diff --git a/app/src/main/java/com/example/notemark/main/data/remote/NoteDTO.kt b/note/data/src/main/java/com/example/data/remote/NoteDTO.kt similarity index 85% rename from app/src/main/java/com/example/notemark/main/data/remote/NoteDTO.kt rename to note/data/src/main/java/com/example/data/remote/NoteDTO.kt index 51590c8..91099a6 100644 --- a/app/src/main/java/com/example/notemark/main/data/remote/NoteDTO.kt +++ b/note/data/src/main/java/com/example/data/remote/NoteDTO.kt @@ -1,4 +1,4 @@ -package com.example.notemark.main.data.remote +package com.example.data.remote import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/note/data/src/main/java/com/example/data/remote/NoteMappers.kt b/note/data/src/main/java/com/example/data/remote/NoteMappers.kt new file mode 100644 index 0000000..d0cbf3e --- /dev/null +++ b/note/data/src/main/java/com/example/data/remote/NoteMappers.kt @@ -0,0 +1,101 @@ +package com.example.data.remote + +import com.example.data.local.NoteEntity +import com.example.domain.Note +import com.example.domain.NoteRequest +import com.example.domain.NotesResponse as DomainNotesResponse + +// DTO <-> Domain Note +fun NoteDTO.toDomain(): Note { + return Note( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +fun Note.toDTO(): NoteDTO { + return NoteDTO( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +// DTO <-> NoteEntity +fun NoteDTO.toEntity(): NoteEntity { + return NoteEntity( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +fun NoteEntity.toDTO(): NoteDTO { + return NoteDTO( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +// NoteEntity <-> Domain Note +fun NoteEntity.toDomain(): Note { + return Note( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt ?: "" + ) +} + +fun Note.toEntity(): NoteEntity { + return NoteEntity( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +// NoteRequest -> DTO +fun NoteRequest.toDTO(): NoteRequestDTO { + return NoteRequestDTO( + id = id, + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +// NoteRequest -> DTO +fun NoteRequestDTO.toNote(): Note { + return Note( + id = id ?: "", + title = title, + content = content, + createdAt = createdAt, + updatedAt = updatedAt + ) +} + +// NotesResponse (data) <-> NotesResponse (domain) +fun NotesResponse.toDomain(): DomainNotesResponse { + return DomainNotesResponse( + notes = this.notes.map { it.toDomain() }, + totalPages = this.totalPages, + currentPage = this.currentPage, + totalNotes = this.totalCount + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/remote/NoteRemoteMediator.kt b/note/data/src/main/java/com/example/data/remote/NoteRemoteMediator.kt similarity index 81% rename from app/src/main/java/com/example/notemark/main/data/remote/NoteRemoteMediator.kt rename to note/data/src/main/java/com/example/data/remote/NoteRemoteMediator.kt index 8475cc2..7b69cf8 100644 --- a/app/src/main/java/com/example/notemark/main/data/remote/NoteRemoteMediator.kt +++ b/note/data/src/main/java/com/example/data/remote/NoteRemoteMediator.kt @@ -1,5 +1,3 @@ -package com.example.notemark.main.data.remote - import android.net.http.HttpException import android.os.Build import android.util.Log @@ -10,9 +8,10 @@ import androidx.paging.LoadType import androidx.paging.PagingState import androidx.paging.RemoteMediator import androidx.room.withTransaction -import com.example.notemark.main.data.local.NoteDatabase -import com.example.notemark.main.data.local.NoteEntity -import com.example.notemark.main.data.remote.api.NoteService +import com.example.data.local.NoteDatabase +import com.example.data.remote.toEntity +import com.example.domain.NoteEntity +import com.example.domain.NoteService import kotlinx.io.IOException @OptIn(ExperimentalPagingApi::class) @@ -31,11 +30,11 @@ class NoteRemoteMediator( LoadType.REFRESH -> 1 LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true) LoadType.APPEND -> { - val lastItem = state.lastItemOrNull() - if(lastItem == null) { - return MediatorResult.Success(endOfPaginationReached = true) - } - noteDatabase.dao.getNotesCount() + state.lastItemOrNull() ?: return MediatorResult.Success( + endOfPaginationReached = true + ) + // Calculate the next page based on current items count + (noteDatabase.dao.getNotesCount() / state.config.pageSize) + 1 } } val notesResponses = noteApi.getNotes( @@ -47,7 +46,8 @@ class NoteRemoteMediator( if (loadType == LoadType.REFRESH) { noteDatabase.dao.clearAll() } - val noteEntities = notesResponses.toNoteEntityList() + // Convert NotesResponse to List + val noteEntities = notesResponses.notes.map { it.toEntity() } noteDatabase.dao.upsertAll(noteEntities) } diff --git a/note/data/src/main/java/com/example/data/remote/NoteRequestDTO.kt b/note/data/src/main/java/com/example/data/remote/NoteRequestDTO.kt new file mode 100644 index 0000000..c5fc977 --- /dev/null +++ b/note/data/src/main/java/com/example/data/remote/NoteRequestDTO.kt @@ -0,0 +1,12 @@ +package com.example.data.remote + +import kotlinx.serialization.Serializable + +@Serializable +data class NoteRequestDTO( + val id: String? = null, + val title: String, + val content: String, + val createdAt: String, + val updatedAt: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/data/remote/repositoryImpl/NoteServiceImpl.kt b/note/data/src/main/java/com/example/data/remote/NoteServiceImpl.kt similarity index 55% rename from app/src/main/java/com/example/notemark/main/data/remote/repositoryImpl/NoteServiceImpl.kt rename to note/data/src/main/java/com/example/data/remote/NoteServiceImpl.kt index 1031d48..2d948a6 100644 --- a/app/src/main/java/com/example/notemark/main/data/remote/repositoryImpl/NoteServiceImpl.kt +++ b/note/data/src/main/java/com/example/data/remote/NoteServiceImpl.kt @@ -1,20 +1,14 @@ -package com.example.notemark.main.data.remote.repositoryImpl +package com.example.data.remote -import com.example.notemark.ConnectivityObserver -import com.example.notemark.ConnectivityViewModel -import com.example.notemark.core.HttpRoutes -import com.example.notemark.core.manager.SessionManager -import com.example.notemark.main.data.local.NoteDatabase -import com.example.notemark.main.data.local.SyncDao -import com.example.notemark.main.data.remote.NoteDTO -import com.example.notemark.main.data.remote.api.NoteService -import com.example.notemark.main.data.remote.toNotEntity -import com.example.notemark.main.data.remote.toNoteDTO -import com.example.notemark.main.data.remote.toNoteEntity -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.domain.model.NotesResponse -import com.example.notemark.main.presentation.screens.note.SyncOperation -import com.example.notemark.main.presentation.screens.note.SyncRecord +import com.example.data.local.NoteDatabase +import com.example.domain.ConnectivityObserver +import com.example.domain.HttpRoutes +import com.example.domain.Note +import com.example.domain.NoteRequest +import com.example.domain.NoteService +import com.example.domain.Result +import com.example.domain.RootError +import com.example.domain.SessionRepository import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete @@ -26,17 +20,16 @@ import io.ktor.client.request.setBody import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.contentType -import kotlinx.serialization.json.Json import java.util.UUID class NoteServiceImpl( private val client: HttpClient, - private val sessionManager: SessionManager, + private val sessionManager: SessionRepository, private val noteDatabase: NoteDatabase, private val connectivityObserver: ConnectivityObserver, ): NoteService { - override suspend fun getNotes(page: Int, size: Int): NotesResponse { + override suspend fun getNotes(page: Int, size: Int): com.example.domain.NotesResponse { return try { val accessToken = sessionManager.getAccessToken() @@ -45,33 +38,22 @@ class NoteServiceImpl( header("Authorization", "Bearer $accessToken") header("X-User-Email", HttpRoutes.EMAIL) } - response.body() + response.body() } catch (e: Exception) { throw e } } - override suspend fun createNote(body: NoteRequest): Result { + override suspend fun createNote(body: NoteRequest): Result { return try { // 1. Always save locally first (offline-first principle) - val noteEntity = body.toNotEntity() - val localResult = noteDatabase.dao.upsertNote(note = noteEntity) + val noteEntity = body.toDTO() val username = sessionManager.getUserName() val userId = UUID.nameUUIDFromBytes(username?.toByteArray()) val isOnline = connectivityObserver.getCurrentNetworkState() - // 2. Add to sync queue for later synchronization - val syncRecord = SyncRecord( - id = UUID.randomUUID(), - userId = userId.toString(), // Internal user ID - noteId = noteEntity.id, // Assuming noteEntity has an ID - operation = SyncOperation.CREATE, - payload = Json.encodeToString(body), // JSON representation - timeStamp = System.currentTimeMillis().toString() - ) - noteDatabase.syncDao.insertSyncRecord(syncRecord) // 3. Try to sync immediately if online - return if (isOnline) { + if (isOnline) { try { val accessToken = sessionManager.getAccessToken() val response = client.post( @@ -83,30 +65,28 @@ class NoteServiceImpl( header("X-User-Email", HttpRoutes.EMAIL) } - // 4. If sync successful, remove from sync queue - noteDatabase.syncDao.deleteSyncRecord(syncRecord.noteId) - // 5. Update local record with server response if needed val serverNote = response.body() - noteDatabase.dao.upsertNote(serverNote.toNoteEntity()) + noteDatabase.dao.upsertNote(serverNote.toEntity()) - Result.success(serverNote) + Result.Success(serverNote.toDomain()) } catch (e: Exception) { // Network failed, but local save succeeded // SyncRecord remains in queue for background sync - Result.success(noteEntity.toNoteDTO()) // Return local version + Result.Success(noteEntity.toNote()) // Return local version } } else { // Offline - return local result - Result.success(noteEntity.toNoteDTO()) + Result.Success(noteEntity.toNote()) } } catch (e: Exception) { - Result.failure(e) + Result.Error(e as RootError) } } - override suspend fun updateNote(body: NoteRequest): Result { + + override suspend fun updateNote(body: NoteRequest): Result { return try { val accessToken = sessionManager.getAccessToken() val response = client.put( @@ -117,24 +97,24 @@ class NoteServiceImpl( header("Authorization", "Bearer $accessToken") header("X-User-Email", HttpRoutes.EMAIL) } - Result.success(response.body()) + Result.Success(response.body().toDomain()) } catch (e: Exception) { - Result.failure(e) + Result.Error(e as RootError) } } - override suspend fun deleteNote(id: String): Result { - noteDatabase.dao.deleteNoteById(id) + override suspend fun deleteNote(id: String): Result { return try { + noteDatabase.dao.deleteNoteById(id) val response = client.delete( urlString = "${HttpRoutes.NOTES}/$id" ) { header(HttpHeaders.Accept, "application/json") header("X-User-Email", HttpRoutes.EMAIL) } - Result.success(response.body()) + Result.Success(Unit) } catch (e: Exception) { - Result.failure(e) + Result.Error(e as RootError) } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/domain/model/NotesResponse.kt b/note/data/src/main/java/com/example/data/remote/NotesResponse.kt similarity index 68% rename from app/src/main/java/com/example/notemark/main/domain/model/NotesResponse.kt rename to note/data/src/main/java/com/example/data/remote/NotesResponse.kt index 57db901..3f13895 100644 --- a/app/src/main/java/com/example/notemark/main/domain/model/NotesResponse.kt +++ b/note/data/src/main/java/com/example/data/remote/NotesResponse.kt @@ -1,6 +1,5 @@ -package com.example.notemark.main.domain.model +package com.example.data.remote -import com.example.notemark.main.data.remote.NoteDTO import kotlinx.serialization.Serializable @Serializable diff --git a/note/domain/build.gradle.kts b/note/domain/build.gradle.kts index 28db768..89bdc9c 100644 --- a/note/domain/build.gradle.kts +++ b/note/domain/build.gradle.kts @@ -3,5 +3,6 @@ plugins { } dependencies { - + implementation(libs.kotlinx.coroutines.core) + implementation(projects.core.domain) } \ No newline at end of file diff --git a/note/domain/src/main/java/com/example/domain/LocalNoteDataSource.kt b/note/domain/src/main/java/com/example/domain/LocalNoteDataSource.kt new file mode 100644 index 0000000..77a8578 --- /dev/null +++ b/note/domain/src/main/java/com/example/domain/LocalNoteDataSource.kt @@ -0,0 +1,6 @@ +package com.example.domain + +interface LocalNoteDataSource { + suspend fun clearAllNotes() + suspend fun getNotesCount(): Int +} \ No newline at end of file diff --git a/note/domain/src/main/java/com/example/domain/NoteEntity.kt b/note/domain/src/main/java/com/example/domain/NoteEntity.kt new file mode 100644 index 0000000..a83a46f --- /dev/null +++ b/note/domain/src/main/java/com/example/domain/NoteEntity.kt @@ -0,0 +1,9 @@ +package com.example.domain + +data class NoteEntity( + val id: String, + val title: String, + val content: String, + val createdAt: String, + val updatedAt: String? = "" +) \ No newline at end of file diff --git a/note/domain/src/main/java/com/example/domain/NoteService.kt b/note/domain/src/main/java/com/example/domain/NoteService.kt new file mode 100644 index 0000000..ea94af1 --- /dev/null +++ b/note/domain/src/main/java/com/example/domain/NoteService.kt @@ -0,0 +1,21 @@ +package com.example.domain + +interface NoteService { + + suspend fun getNotes( + page: Int, + size: Int, + ): NotesResponse + + suspend fun createNote( + body: NoteRequest + ): Result + + suspend fun updateNote( + body: NoteRequest + ): Result + + suspend fun deleteNote( + id: String + ): Result +} diff --git a/note/domain/src/main/java/com/example/domain/NotesResponse.kt b/note/domain/src/main/java/com/example/domain/NotesResponse.kt new file mode 100644 index 0000000..8be9d5a --- /dev/null +++ b/note/domain/src/main/java/com/example/domain/NotesResponse.kt @@ -0,0 +1,8 @@ +package com.example.domain + +data class NotesResponse( + val notes: List, + val totalPages: Int? = null, + val currentPage: Int? = null, + val totalNotes: Int? = null +) \ No newline at end of file diff --git a/note/presentation/build.gradle.kts b/note/presentation/build.gradle.kts index e40d2c6..393e151 100644 --- a/note/presentation/build.gradle.kts +++ b/note/presentation/build.gradle.kts @@ -3,13 +3,17 @@ plugins { } android { - namespace = "com.example.presentation" + namespace = "com.example.notemark.note.presentation" } dependencies { + implementation(libs.androidx.paging.compose) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.lottie.compose) with(projects) { - implementation(core.domain) implementation(note.domain) + implementation(core.domain) implementation(core.presentation) + implementation(auth.presentation) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/vm/NoteViewModel.kt b/note/presentation/src/main/java/com/example/presentation/NoteViewModel.kt similarity index 57% rename from app/src/main/java/com/example/notemark/main/presentation/vm/NoteViewModel.kt rename to note/presentation/src/main/java/com/example/presentation/NoteViewModel.kt index 4f4480e..e2f668a 100644 --- a/app/src/main/java/com/example/notemark/main/presentation/vm/NoteViewModel.kt +++ b/note/presentation/src/main/java/com/example/presentation/NoteViewModel.kt @@ -1,17 +1,16 @@ -package com.example.notemark.main.presentation.vm +package com.example.presentation import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.Pager import androidx.paging.cachedIn -import androidx.paging.map -import com.example.notemark.main.data.local.NoteDatabase -import com.example.notemark.main.data.local.NoteEntity -import com.example.notemark.main.data.remote.NoteDTO -import com.example.notemark.main.data.remote.toNote -import com.example.notemark.main.domain.model.Note -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.domain.repository.NotesRepository +import com.example.domain.LocalNoteDataSource +import com.example.domain.Note +import com.example.domain.NoteRequest +import com.example.domain.NoteService +import com.example.domain.Result +import com.example.domain.RootError +import com.example.domain.SessionRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -19,24 +18,19 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class NotesViewModel @Inject constructor( - private val repository: NotesRepository, - private val noteDatabase: NoteDatabase, - pager: Pager + private val service: NoteService, + private val sessionManager: SessionRepository, + private val localDataSource: LocalNoteDataSource, + pager: Pager ) : ViewModel() { val notePagingFlow = pager .flow - .map { pagingData -> - pagingData.map { - it.toNote() - } - } .cachedIn(viewModelScope) private val _createNoteState = MutableStateFlow(NoteUiState()) @@ -48,20 +42,17 @@ class NotesViewModel @Inject constructor( private val _deleteNoteState = MutableStateFlow(DeleteNoteUiState.Idle) val deleteNoteState: StateFlow = _deleteNoteState.asStateFlow() - // Current note being edited (only for edit mode) - private val _currentNote = MutableStateFlow(null) - val currentNote: StateFlow = _currentNote.asStateFlow() + private val _currentNote = MutableStateFlow(null) + val currentNote: StateFlow = _currentNote.asStateFlow() - // Auto-save status (only for edit mode) private val _autoSaveStatus = MutableStateFlow(AutoSaveStatus.Saved) val autoSaveStatus: StateFlow = _autoSaveStatus.asStateFlow() - // Track current mode private val _isEditMode = MutableStateFlow(false) val isEditMode: StateFlow = _isEditMode.asStateFlow() private var autoSaveJob: Job? = null - private val autoSaveDelay = 500L // 500ms debounce + private val autoSaveDelay = 500L sealed class AutoSaveStatus { object Saved : AutoSaveStatus() @@ -69,42 +60,51 @@ class NotesViewModel @Inject constructor( object Error : AutoSaveStatus() } + private val _username = MutableStateFlow(null) + val username: StateFlow = _username.asStateFlow() + + fun getUsername(): String? = sessionManager.getUserName() + + private val _accessToken = MutableStateFlow(null) + val accessToken: StateFlow = _accessToken.asStateFlow() + + fun getAccessToken(): String? = sessionManager.getAccessToken() + + private val _refreshToken = MutableStateFlow(null) + val refreshToken: StateFlow = _refreshToken.asStateFlow() + + fun getRefreshToken(): String? = sessionManager.getRefreshToken() + // CREATE MODE FUNCTIONS fun createNote(noteRequest: NoteRequest) { viewModelScope.launch { _createNoteState.value = _createNoteState.value.copy(isLoading = true, error = null) - val result = repository.createNote(noteRequest) + when (val result = service.createNote(noteRequest)) { + is Result.Success -> { + _createNoteState.value = _createNoteState.value.copy( + isLoading = false, + isSuccess = true, + createdNote = result.data + ) + _currentNote.value = result.data + } + is Result.Error -> { + _createNoteState.value = _createNoteState.value.copy( + isLoading = false, + error = result.error.toString() + ) + } - result.collect { result -> - result.fold( - onSuccess = { data -> - _createNoteState.value = _createNoteState.value.copy( - isLoading = false, - isSuccess = true, - createdNote = data - ) - // Set the created note as current note for tracking - _currentNote.value = data - }, - onFailure = { error -> - _createNoteState.value = _createNoteState.value.copy( - isLoading = false, - error = error.message ?: "Unknown error occurred while creating note." - ) - } - ) } } } - // Function to check if current note is empty (for deletion when user cancels) fun isCurrentNoteEmpty(): Boolean { val note = _currentNote.value ?: return true return note.title.isBlank() || note.title == "Note Title" && note.content.isBlank() } - // Function to delete current note if empty fun deleteCurrentNoteIfEmpty() { val note = _currentNote.value ?: return if (isCurrentNoteEmpty()) { @@ -112,14 +112,13 @@ class NotesViewModel @Inject constructor( } } - // Clear current note when leaving screen fun clearCurrentNote() { _currentNote.value = null autoSaveJob?.cancel() } // EDIT MODE FUNCTIONS - fun enterEditMode(note: NoteDTO) { + fun enterEditMode(note: Note) { _isEditMode.value = true _currentNote.value = note _autoSaveStatus.value = AutoSaveStatus.Saved @@ -132,9 +131,8 @@ class NotesViewModel @Inject constructor( _autoSaveStatus.value = AutoSaveStatus.Saved } - // Auto-save functions (only work in edit mode) fun updateNoteTitle(newTitle: String) { - if (!_isEditMode.value) return // Only work in edit mode + if (!_isEditMode.value) return val current = _currentNote.value ?: return val updatedNote = current.copy(title = newTitle) @@ -143,7 +141,7 @@ class NotesViewModel @Inject constructor( } fun updateNoteContent(newContent: String) { - if (!_isEditMode.value) return // Only work in edit mode + if (!_isEditMode.value) return val current = _currentNote.value ?: return val updatedNote = current.copy(content = newContent) @@ -152,15 +150,11 @@ class NotesViewModel @Inject constructor( } private fun scheduleAutoSave() { - if (!_isEditMode.value) return // Only work in edit mode + if (!_isEditMode.value) return - // Cancel previous auto-save job autoSaveJob?.cancel() - - // Set status to saving _autoSaveStatus.value = AutoSaveStatus.Saving - // Schedule new auto-save job with debounce autoSaveJob = viewModelScope.launch { delay(autoSaveDelay) performAutoSave() @@ -168,7 +162,7 @@ class NotesViewModel @Inject constructor( } private suspend fun performAutoSave() { - if (!_isEditMode.value) return // Only work in edit mode + if (!_isEditMode.value) return val noteToSave = _currentNote.value ?: return @@ -178,35 +172,29 @@ class NotesViewModel @Inject constructor( title = noteToSave.title, content = noteToSave.content, createdAt = noteToSave.createdAt, - updatedAt = System.currentTimeMillis().toString() // Update lastEditedAt + updatedAt = System.currentTimeMillis().toString() ) - val result = repository.updateNote(noteRequest) - - result.collect { result -> - result.fold( - onSuccess = { data -> - _currentNote.value = data - _autoSaveStatus.value = AutoSaveStatus.Saved - }, - onFailure = { error -> - _autoSaveStatus.value = AutoSaveStatus.Error - } - ) + when (val result = service.updateNote(noteRequest)) { + is Result.Success -> { + _currentNote.value = result.data + _autoSaveStatus.value = AutoSaveStatus.Saved + } + is Result.Error -> { + _autoSaveStatus.value = AutoSaveStatus.Error + } } } catch (e: Exception) { _autoSaveStatus.value = AutoSaveStatus.Error } } - // Force save for edit mode (when user finishes editing) fun finishEditing() { if (!_isEditMode.value) return autoSaveJob?.cancel() viewModelScope.launch { performAutoSave() - // Update lastEditedAt to current time when finishing editing _currentNote.value?.let { note -> val updatedNote = note.copy( updatedAt = System.currentTimeMillis().toString() @@ -217,29 +205,26 @@ class NotesViewModel @Inject constructor( } } - // Regular update function (for manual saves, not auto-save) fun updateNote(noteRequest: NoteRequest) { viewModelScope.launch { _updateNoteState.value = _updateNoteState.value.copy(isLoading = true, error = null) - val result = repository.updateNote(noteRequest) - - result.collect { result -> - result.fold( - onSuccess = { data -> - _updateNoteState.value = _updateNoteState.value.copy( - isLoading = false, - isSuccess = true, - createdNote = data - ) - }, - onFailure = { error -> - _updateNoteState.value = _updateNoteState.value.copy( - isLoading = false, - error = error.message ?: "Unknown error occurred while updating note." - ) - } - ) + val result = service.updateNote(noteRequest) + + when (result) { + is com.example.domain.Result.Success -> { + _updateNoteState.value = _updateNoteState.value.copy( + isLoading = false, + isSuccess = true, + createdNote = result.data + ) + } + is com.example.domain.Result.Error -> { + _updateNoteState.value = _updateNoteState.value.copy( + isLoading = false, + error = result.error.toString() + ) + } } } } @@ -249,22 +234,24 @@ class NotesViewModel @Inject constructor( _deleteNoteState.value = DeleteNoteUiState.Loading try { - val result = repository.deleteNote(noteId) - result.fold( - onSuccess = { + when (val result = service.deleteNote(noteId)) { + is Result.Success -> { _deleteNoteState.value = DeleteNoteUiState.Success - }, - onFailure = { error -> - _deleteNoteState.value = DeleteNoteUiState.Error(error.message ?: "Unknown error occurred") } - ) + is Result.Error -> { + _deleteNoteState.value = DeleteNoteUiState.Error( + result.error.toString() + ) + } + } } catch (e: Exception) { - _deleteNoteState.value = DeleteNoteUiState.Error(e.message ?: "Unknown error occurred") + _deleteNoteState.value = DeleteNoteUiState.Error( + e.message ?: "Unknown error occurred" + ) } } } - // Utility functions fun resetDeleteState() { _deleteNoteState.value = DeleteNoteUiState.Idle } @@ -277,10 +264,9 @@ class NotesViewModel @Inject constructor( _updateNoteState.value = NoteUiState() } - // Clear all saved notes locally fun clear() { viewModelScope.launch(Dispatchers.IO) { - noteDatabase.dao.clearAll() + localDataSource.clearAllNotes() } } @@ -300,6 +286,6 @@ sealed class DeleteNoteUiState { data class NoteUiState( val isLoading: Boolean = false, val isSuccess: Boolean = false, - val createdNote: NoteDTO? = null, + val createdNote: Note? = null, val error: String? = null ) \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/domain/model/NotesUiState.kt b/note/presentation/src/main/java/com/example/presentation/NotesUiState.kt similarity index 75% rename from app/src/main/java/com/example/notemark/main/domain/model/NotesUiState.kt rename to note/presentation/src/main/java/com/example/presentation/NotesUiState.kt index 0d8ecd8..a71ba43 100644 --- a/app/src/main/java/com/example/notemark/main/domain/model/NotesUiState.kt +++ b/note/presentation/src/main/java/com/example/presentation/NotesUiState.kt @@ -1,4 +1,6 @@ -package com.example.notemark.main.domain.model +package com.example.presentation + +import com.example.domain.Note data class NotesUiState( val notes: List = emptyList(), diff --git a/note/presentation/src/main/java/com/example/presentation/SyncInterval.kt b/note/presentation/src/main/java/com/example/presentation/SyncInterval.kt new file mode 100644 index 0000000..0aa27ad --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/SyncInterval.kt @@ -0,0 +1,8 @@ +package com.example.presentation + +enum class SyncInterval(val displayName: String) { + MANUAL_ONLY("Manual Only"), + EVERY_15_MINUTES("15 minutes"), + EVERY_30_MINUTES("30 minutes"), + EVERY_HOUR("1 hour") +} \ No newline at end of file diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/note/CreateNote.kt b/note/presentation/src/main/java/com/example/presentation/edit_note/CreateNote.kt similarity index 86% rename from app/src/main/java/com/example/notemark/main/presentation/screens/note/CreateNote.kt rename to note/presentation/src/main/java/com/example/presentation/edit_note/CreateNote.kt index 7151e03..9223c0f 100644 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/note/CreateNote.kt +++ b/note/presentation/src/main/java/com/example/presentation/edit_note/CreateNote.kt @@ -1,12 +1,12 @@ -package com.example.notemark.main.presentation.screens.note +package com.example.presentation.edit_note +import android.util.Log import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars @@ -48,13 +48,14 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController -import com.example.notemark.R -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.presentation.vm.NotesViewModel +import com.example.presentation.DateFormatter +import com.example.presentation.DeviceConfiguration +import com.example.presentation.NotesViewModel +import com.example.notemark.core.presentation.R +import com.example.domain.NoteRequest +import java.util.UUID @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -63,7 +64,7 @@ fun CreateNoteScreen( ) { val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) + val deviceConfiguration = DeviceConfiguration.Companion.fromWindowSizeClass(windowSizeClass) when(deviceConfiguration) { DeviceConfiguration.MOBILE_PORTRAIT -> { @@ -112,7 +113,7 @@ fun CreateNoteBody( // Log current note changes LaunchedEffect(currentNote) { - android.util.Log.d("CreateNote", "Current note changed: ${currentNote?.id}") + Log.d("CreateNote", "Current note changed: ${currentNote?.id}") currentNote?.let { note -> if (title.isEmpty() || title == "Note Title") title = note.title if (content.isEmpty()) content = note.content @@ -122,11 +123,11 @@ fun CreateNoteBody( // In your CreateNoteBody, modify the LaunchedEffect for creating the note: // Create initial note when screen opens LaunchedEffect(Unit) { - android.util.Log.d("CreateNote", "Screen opened, creating initial note") + Log.d("CreateNote", "Screen opened, creating initial note") focusRequester.requestFocus() // Generate a unique ID for the note - val noteId = java.util.UUID.randomUUID().toString() + val noteId = UUID.randomUUID().toString() val initialNoteRequest = NoteRequest( id = noteId, // Use generated UUID instead of empty string @@ -140,7 +141,7 @@ fun CreateNoteBody( // Navigate after successful CREATE LaunchedEffect(createNoteState.isSuccess) { if (createNoteState.isSuccess) { - android.util.Log.d("CreateNote", "Note created successfully: ${createNoteState.createdNote?.id}") + Log.d("CreateNote", "Note created successfully: ${createNoteState.createdNote?.id}") viewModel.resetCreateNoteState() } } @@ -148,7 +149,7 @@ fun CreateNoteBody( // Navigate after successful UPDATE LaunchedEffect(noteState.isSuccess) { if (noteState.isSuccess) { - android.util.Log.d("CreateNote", "Note updated successfully, navigating back") + Log.d("CreateNote", "Note updated successfully, navigating back") viewModel.resetUpdateNoteState() viewModel.clearCurrentNote() navController.navigateUp() @@ -157,7 +158,7 @@ fun CreateNoteBody( // Handle back navigation BackHandler { - android.util.Log.d("CreateNote", "Back pressed") + Log.d("CreateNote", "Back pressed") handleCreateModeBackNavigation(viewModel, navController) } @@ -168,7 +169,7 @@ fun CreateNoteBody( navigationIcon = { IconButton( onClick = { - android.util.Log.d("CreateNote", "X button clicked") + Log.d("CreateNote", "X button clicked") handleCreateModeBackNavigation(viewModel, navController) } ) { @@ -181,26 +182,26 @@ fun CreateNoteBody( actions = { TextButton( onClick = { - android.util.Log.d("CreateNote", "Save button clicked") - android.util.Log.d("CreateNote", "Title: '$title'") - android.util.Log.d("CreateNote", "Content: '$content'") - android.util.Log.d("CreateNote", "CurrentNote: ${currentNote?.id}") - android.util.Log.d("CreateNote", "isLoading: ${noteState.isLoading}") + Log.d("CreateNote", "Save button clicked") + Log.d("CreateNote", "Title: '$title'") + Log.d("CreateNote", "Content: '$content'") + Log.d("CreateNote", "CurrentNote: ${currentNote?.id}") + Log.d("CreateNote", "isLoading: ${noteState.isLoading}") if (title.isNotBlank() || content.isNotBlank()) { currentNote?.let { note -> - android.util.Log.d("CreateNote", "Updating note with id: ${note.id}") + Log.d("CreateNote", "Updating note with id: ${note.id}") val noteRequest = NoteRequest( id = note.id, title = title.trim(), content = content.trim(), createdAt = note.createdAt, - updatedAt = System.currentTimeMillis().toString() + updatedAt = DateFormatter.getCurrentIsoString() ) viewModel.updateNote(noteRequest) - } ?: android.util.Log.e("CreateNote", "CurrentNote is NULL!") + } ?: Log.e("CreateNote", "CurrentNote is NULL!") } else { - android.util.Log.d("CreateNote", "Note is empty, navigating back") + Log.d("CreateNote", "Note is empty, navigating back") handleCreateModeBackNavigation(viewModel, navController) } }, diff --git a/app/src/main/java/com/example/notemark/main/presentation/screens/note/EditNote.kt b/note/presentation/src/main/java/com/example/presentation/edit_note/EditNote.kt similarity index 90% rename from app/src/main/java/com/example/notemark/main/presentation/screens/note/EditNote.kt rename to note/presentation/src/main/java/com/example/presentation/edit_note/EditNote.kt index fac6cf8..2c6d864 100644 --- a/app/src/main/java/com/example/notemark/main/presentation/screens/note/EditNote.kt +++ b/note/presentation/src/main/java/com/example/presentation/edit_note/EditNote.kt @@ -1,4 +1,4 @@ -package com.example.notemark.main.presentation.screens.note +package com.example.presentation.edit_note import android.widget.Toast import androidx.activity.compose.BackHandler @@ -46,21 +46,19 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavController -import androidx.navigation.compose.rememberNavController import androidx.paging.compose.collectAsLazyPagingItems -import com.example.notemark.R -import com.example.notemark.auth.presentation.util.DeviceConfiguration -import com.example.notemark.main.DateFormatter -import com.example.notemark.main.domain.model.NoteRequest -import com.example.notemark.main.domain.model.getFormattedCreatedAt -import com.example.notemark.main.presentation.vm.NotesViewModel -import com.example.notemark.navigation.screens.HomeScreens +import com.example.presentation.DateFormatter +import com.example.presentation.DeviceConfiguration +import com.example.presentation.NotesViewModel +import com.example.notemark.core.presentation.R +import com.example.domain.NoteRequest +import com.example.presentation.getFormattedCreatedAt @OptIn(ExperimentalMaterial3Api::class) @Composable fun EditNoteScreen( - navController: NavController = rememberNavController(), + onNavigateHome: () -> Unit = {}, + onNavigateUp: () -> Unit = {}, noteId: String, ) { @@ -71,7 +69,8 @@ fun EditNoteScreen( DeviceConfiguration.MOBILE_PORTRAIT -> { EditNoteScreenBody( modifier = Modifier, - navController = navController, + onNavigateToHome = onNavigateHome, + onNavigateUp = onNavigateUp, noteId = noteId ) } @@ -84,7 +83,8 @@ fun EditNoteScreen( .windowInsetsPadding(WindowInsets.displayCutout) .fillMaxSize() .consumeWindowInsets(WindowInsets.navigationBars), - navController = navController, + onNavigateToHome = onNavigateHome, + onNavigateUp = onNavigateUp, noteId = noteId ) } @@ -93,7 +93,8 @@ fun EditNoteScreen( DeviceConfiguration.DESKTOP -> { EditNoteScreenBody( modifier = Modifier, - navController = navController, + onNavigateToHome = onNavigateHome, + onNavigateUp = onNavigateUp, noteId = noteId ) } @@ -104,7 +105,8 @@ fun EditNoteScreen( @OptIn(ExperimentalMaterial3Api::class) private fun EditNoteScreenBody( modifier: Modifier, - navController: NavController, + onNavigateToHome: () -> Unit = {}, + onNavigateUp: () -> Unit = {}, noteId: String, ) { @@ -116,15 +118,7 @@ private fun EditNoteScreenBody( val notes = viewModel.notePagingFlow.collectAsLazyPagingItems() val note = notes.itemSnapshotList.items.find { it.id == noteId } - LaunchedEffect(noteState) { - if (noteState.isSuccess) { - navController.navigate(HomeScreens.Home.route) { - popUpTo(HomeScreens.Home.route) { - inclusive = true - } - } - } - } + LaunchedEffect(noteState) { if (noteState.isSuccess) { onNavigateToHome() } } LaunchedEffect(noteState.error) { noteState.error?.let { error -> @@ -146,7 +140,7 @@ private fun EditNoteScreenBody( if (hasChanges) { showExitDialog = true } else { - navController.popBackStack() + onNavigateUp() } } @@ -164,7 +158,7 @@ private fun EditNoteScreenBody( if (hasChanges) { showExitDialog = true } else { - navController.popBackStack() + onNavigateUp() } } ) { @@ -295,7 +289,7 @@ private fun EditNoteScreenBody( TextButton( onClick = { showExitDialog = false - navController.navigateUp() + onNavigateUp() } ) { Text( diff --git a/note/presentation/src/main/java/com/example/presentation/home/Home.kt b/note/presentation/src/main/java/com/example/presentation/home/Home.kt new file mode 100644 index 0000000..f327d3e --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/home/Home.kt @@ -0,0 +1,340 @@ +package com.example.presentation.home + +import android.util.Log +import android.widget.Toast +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid +import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells +import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan +import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.FloatingActionButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.paging.LoadState +import androidx.paging.compose.LazyPagingItems +import androidx.paging.compose.itemKey +import com.example.presentation.DateFormatter +import com.example.presentation.DeviceConfiguration +import com.example.presentation.NoteUiState +import com.example.presentation.NotesViewModel +import com.example.notemark.core.presentation.R +import com.example.domain.Note +import com.example.domain.NoteRequest +import com.example.presentation.getInitials +import com.example.presentation.home.components.EmptyState +import com.example.presentation.home.components.NoteItem +import java.util.UUID + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeScreen( + connectivityState: State, + notesList: LazyPagingItems, + noteUiState: State, + onNavigateToDetailsWithId: (String) -> Unit, + onNavigateToCreateNote: () -> Unit, + onNavigateToLogin: () -> Unit, + onNavigateToSettings: () -> Unit, + onNavigateToHome: () -> Unit, + username: String?, + accessToken: String?, + refreshToken: String? + ) { + + LaunchedEffect(Unit) { if (accessToken.isNullOrEmpty() && refreshToken.isNullOrEmpty()) { onNavigateToLogin() } } + + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) + + when(deviceConfiguration) { + DeviceConfiguration.MOBILE_PORTRAIT -> { + MainContent( + modifier = Modifier, + onNavigateToDetailsWithId = onNavigateToDetailsWithId, + onNavigateToCreateNote = onNavigateToCreateNote, + onNavigateToSettings = onNavigateToSettings, + onNavigateToHome = onNavigateToHome, + username = username, + notes = notesList, + connectivityState = connectivityState, + columnCount = 2 + ) + } + DeviceConfiguration.MOBILE_LANDSCAPE -> { + MainContent( + modifier = Modifier + .background( + MaterialTheme.colorScheme.surface + ) + .windowInsetsPadding(WindowInsets.displayCutout) + .fillMaxSize() + .consumeWindowInsets(WindowInsets.navigationBars), + onNavigateToDetailsWithId = onNavigateToDetailsWithId, + onNavigateToCreateNote = onNavigateToCreateNote, + onNavigateToSettings = onNavigateToSettings, + onNavigateToHome = onNavigateToHome, + username = username, + notes = notesList, + connectivityState = connectivityState, + columnCount = 3 + ) + } + DeviceConfiguration.TABLET_PORTRAIT, + DeviceConfiguration.TABLET_LANDSCAPE, + DeviceConfiguration.DESKTOP -> { + MainContent( + modifier = Modifier, + onNavigateToDetailsWithId = onNavigateToDetailsWithId, + onNavigateToCreateNote = onNavigateToCreateNote, + onNavigateToSettings = onNavigateToSettings, + onNavigateToHome = onNavigateToHome, + username = username, + notes = notesList, + connectivityState = connectivityState, + columnCount = 3 + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun MainContent( + modifier: Modifier, + onNavigateToDetailsWithId: (String) -> Unit = {}, + onNavigateToCreateNote: () -> Unit = {}, + onNavigateToSettings: () -> Unit = {}, + onNavigateToHome: () -> Unit = {}, + username: String?, + notes: LazyPagingItems, + connectivityState: State, + columnCount: Int, +) { + val context = LocalContext.current + val uuid = remember { UUID.randomUUID() } + val noteViewModel = hiltViewModel() + val noteState by noteViewModel.createNoteState.collectAsStateWithLifecycle() + val creationTime by remember { mutableStateOf(DateFormatter.getCurrentIsoString()) } + + LaunchedEffect(notes.loadState) { + when { + notes.loadState.refresh is LoadState.Error -> { + val error = (notes.loadState.refresh as LoadState.Error).error + Log.e("Home", "Refresh error: ${error.message}") + if (notes.itemCount == 0) { + Toast.makeText( + context, + "Unable to load notes. Showing cached data.", + Toast.LENGTH_SHORT + ).show() + } + } + notes.loadState.append is LoadState.Error -> { + val error = (notes.loadState.append as LoadState.Error).error + Log.e("Home", "Append error: ${error.message}") + } + } + } + + val initials = getInitials(username ?: "U") + + LaunchedEffect(noteState) { if (noteState.isSuccess) onNavigateToHome() } + + LaunchedEffect(noteState.error) { + noteState.error?.let { error -> + Toast.makeText(context, error, Toast.LENGTH_LONG).show() + Log.d( + "CreateNoteScreen", + "CreateNoteScreen: ${noteState.error}" + ) + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = stringResource(R.string.app_name), + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(end = 4.dp) + ) + if (!connectivityState.value) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.cloud_off), + contentDescription = "Offline", + tint = Color(0x66535364), + ) + } + } + }, + actions = { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.settings), + contentDescription = "Settings", + modifier = Modifier + .clickable { onNavigateToSettings() } + .padding(end = 16.dp) + ) + Text( + modifier = Modifier + .padding(end = 16.dp) + .size(40.dp) + .clip(RoundedCornerShape(12.dp)) + .background(MaterialTheme.colorScheme.primary) + .padding(10.dp), + text = initials, + style = MaterialTheme.typography.titleSmall.copy( + color = MaterialTheme.colorScheme.onPrimary, + textAlign = TextAlign.Center + ) + ) + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.onPrimary + ) + ) + }, + + floatingActionButton = { + FloatingActionButton( + onClick = { + noteViewModel.createNote( + NoteRequest( + id = uuid.toString(), + title = "Note Title", + content = "", + createdAt = creationTime, + updatedAt = creationTime, + ) + ) + onNavigateToCreateNote() + }, + modifier = Modifier + .size(64.dp) + .background( + brush = Brush.verticalGradient( + colors = listOf( + Color(0xFF58A1F8), + Color(0xFF5A4CF7) + ) + ), + shape = RoundedCornerShape(20.dp) + ), + containerColor = Color.Transparent, + elevation = FloatingActionButtonDefaults.elevation(0.dp) + ) { + Icon( + tint = MaterialTheme.colorScheme.onPrimary, + painter = painterResource(R.drawable.plus), + contentDescription = null + ) + } + }, + contentWindowInsets = WindowInsets.statusBars + ) { innerPadding -> + Column( + modifier = modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.surface) + .padding(innerPadding) + ) { + if (notes.loadState.refresh is LoadState.Loading) { + CircularProgressIndicator( + modifier = Modifier + .size(24.dp) + .align(Alignment.CenterHorizontally) + ) + } else { + LazyVerticalStaggeredGrid( + columns = StaggeredGridCells.Fixed(columnCount), + state = rememberLazyStaggeredGridState(), + modifier = Modifier.weight(1f), + contentPadding = PaddingValues(16.dp), + verticalItemSpacing = 8.dp, + horizontalArrangement = Arrangement.spacedBy(8.dp), + content = { + items( + notes.itemCount, + key = notes.itemKey { it.id } + ) { index -> + notes[index]?.let { + NoteItem( + modifier = Modifier, + onNavigateToDetailsWithId = { noteId -> + onNavigateToDetailsWithId(noteId) + }, + note = it, + notes = notes + ) + } + } + if (notes.loadState.append is LoadState.Loading) { + item(span = StaggeredGridItemSpan.FullLine) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp) + ) + } + } + } + } + ) + } + EmptyState(notes) + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/home/components/ActionContent.kt b/note/presentation/src/main/java/com/example/presentation/home/components/ActionContent.kt new file mode 100644 index 0000000..52b3ef3 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/home/components/ActionContent.kt @@ -0,0 +1,106 @@ +package com.example.presentation.home.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.example.presentation.DeleteNoteUiState +import com.example.notemark.core.presentation.R + +@Composable +internal fun ActionContent( + deleteNoteState: DeleteNoteUiState, + onDeleteClick: () -> Unit, +) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (deleteNoteState is DeleteNoteUiState.Success) { + SuccessContent() + } else { + Card( + modifier = Modifier + .fillMaxWidth() + .clip(MaterialTheme.shapes.medium) + .clickable( + enabled = deleteNoteState !is DeleteNoteUiState.Loading + ) { + onDeleteClick() + }, + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface + ), + elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) + ) { + ListItem( + colors = ListItemDefaults.colors( + containerColor = Color.Transparent + ), + headlineContent = { + Text( + text = when (deleteNoteState) { + is DeleteNoteUiState.Loading -> "Deleting..." + else -> "Delete Note?" + }, + style = MaterialTheme.typography.bodyLarge.copy( + color = if (deleteNoteState is DeleteNoteUiState.Loading) { + MaterialTheme.colorScheme.onSurfaceVariant + } else { + MaterialTheme.colorScheme.error + } + ) + ) + }, + supportingContent = { + Text( + text = "Are you sure you want to delete this note? This action cannot be undone.", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + }, + leadingContent = { + Box( + modifier = Modifier.size(40.dp), + contentAlignment = Alignment.Center + ) { + if (deleteNoteState is DeleteNoteUiState.Loading) { + CircularProgressIndicator( + modifier = Modifier.size(20.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.primary + ) + } else { + Icon( + painter = painterResource(R.drawable.outline_delete_outline_24), + contentDescription = "Delete", + tint = MaterialTheme.colorScheme.error, + modifier = Modifier.size(24.dp) + ) + } + } + } + ) + } + Spacer(modifier = Modifier.height(16.dp)) + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/home/components/EmptyState.kt b/note/presentation/src/main/java/com/example/presentation/home/components/EmptyState.kt new file mode 100644 index 0000000..559fb29 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/home/components/EmptyState.kt @@ -0,0 +1,38 @@ +package com.example.presentation.home.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.paging.LoadState +import androidx.paging.compose.LazyPagingItems +import com.example.notemark.core.presentation.R +import com.example.domain.Note + +@Composable +internal fun EmptyState(notes: LazyPagingItems) { + + if (notes.loadState.refresh !is LoadState.Loading && notes.itemSnapshotList.items.isEmpty() && !notes.loadState.hasError) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(top = 48.dp), + contentAlignment = Alignment.TopCenter + ) { + Text( + text = stringResource(R.string.empty_container_text), + style = MaterialTheme.typography.titleSmall.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + ) + } + } +} diff --git a/note/presentation/src/main/java/com/example/presentation/home/components/NoteActionSheet.kt b/note/presentation/src/main/java/com/example/presentation/home/components/NoteActionSheet.kt new file mode 100644 index 0000000..03e1b40 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/home/components/NoteActionSheet.kt @@ -0,0 +1,78 @@ +package com.example.presentation.home.components + +import android.widget.Toast +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.paging.compose.LazyPagingItems +import com.example.domain.Note +import com.example.presentation.DeleteNoteUiState +import com.example.presentation.NotesViewModel +import kotlinx.coroutines.delay + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun NoteActionSheet( + isVisible: Boolean, + onDismissSheet: () -> Unit, + noteId: String, + notes: LazyPagingItems +) { + val context = LocalContext.current + val viewModel: NotesViewModel = hiltViewModel() + val deleteNoteState by viewModel.deleteNoteState.collectAsStateWithLifecycle() + val onDeleteClick = { viewModel.deleteNote(noteId = noteId) } + + LaunchedEffect(deleteNoteState) { + when (deleteNoteState) { + is DeleteNoteUiState.Success -> { + delay(2_000L) + notes.refresh() + viewModel.resetDeleteState() + onDismissSheet() + } + is DeleteNoteUiState.Error -> { + Toast.makeText( + context, + (deleteNoteState as DeleteNoteUiState.Error).message, + Toast.LENGTH_SHORT + ).show() + viewModel.resetDeleteState() + } + else -> {} + } + } + + if (isVisible) { + ModalBottomSheet( + onDismissRequest = { + onDismissSheet() + }, + containerColor = MaterialTheme.colorScheme.surfaceContainerLowest, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + ActionContent( + deleteNoteState = deleteNoteState, + onDeleteClick = onDeleteClick, + ) + } + } + } +} diff --git a/note/presentation/src/main/java/com/example/presentation/home/components/NoteItem.kt b/note/presentation/src/main/java/com/example/presentation/home/components/NoteItem.kt new file mode 100644 index 0000000..a04c50e --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/home/components/NoteItem.kt @@ -0,0 +1,96 @@ +package com.example.presentation.home.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.paging.compose.LazyPagingItems +import com.example.domain.Note +import com.example.presentation.DeviceConfiguration +import com.example.presentation.getFormattedCreatedAt +import com.example.presentation.truncateAtWord + +@Composable +internal fun NoteItem( + modifier: Modifier, + onNavigateToDetailsWithId: (String) -> Unit, + note: Note, + notes: LazyPagingItems +) { + + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val deviceConfiguration = DeviceConfiguration.Companion.fromWindowSizeClass(windowSizeClass) + val isPhone = deviceConfiguration == DeviceConfiguration.MOBILE_PORTRAIT + + var contextMenuNoteId by rememberSaveable { mutableStateOf(null) } + val haptics = LocalHapticFeedback.current + + Column( + modifier = modifier + .combinedClickable( + onClick = { onNavigateToDetailsWithId(note.id) }, + onLongClick = { + haptics.performHapticFeedback(HapticFeedbackType.LongPress) + contextMenuNoteId = note.id + }, + ) + .background( + MaterialTheme.colorScheme.surfaceContainerLowest, + RoundedCornerShape(16.dp) + ) + .padding(16.dp), + horizontalAlignment = Alignment.Start, + ) { + + Text( + text = note.getFormattedCreatedAt(), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = note.title, + style = MaterialTheme.typography.titleMedium.copy( + color = MaterialTheme.colorScheme.onSurface + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + + Text( + text = note.content.truncateAtWord(if (isPhone) 150 else 250), + style = MaterialTheme.typography.bodySmall, + maxLines = 3, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + if (contextMenuNoteId != null) { + NoteActionSheet( + isVisible = note.id == contextMenuNoteId, + onDismissSheet = { contextMenuNoteId = null }, + + noteId = contextMenuNoteId ?: "", + notes = notes + ) + } +} diff --git a/note/presentation/src/main/java/com/example/presentation/home/components/SuccessContent.kt b/note/presentation/src/main/java/com/example/presentation/home/components/SuccessContent.kt new file mode 100644 index 0000000..b35fde9 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/home/components/SuccessContent.kt @@ -0,0 +1,74 @@ +package com.example.presentation.home.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.rememberLottieAnimatable +import com.airbnb.lottie.compose.rememberLottieComposition +import com.example.notemark.core.presentation.R + +@Composable +internal fun SuccessContent() { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + val animationState = rememberLottieAnimatable() + val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.success)) + + + LaunchedEffect(composition) { + composition?.let { + animationState.animate( + composition = it, + iterations = 1 + ) + } + } + + Box( + modifier = Modifier.size(120.dp), + contentAlignment = Alignment.Center + ) { + if (composition != null) { + LottieAnimation( + composition = composition, + progress = { animationState.progress }, + modifier = Modifier.size(120.dp) + ) + } else { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "Note deleted successfully!", + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.Center + ) + } +} diff --git a/app/src/main/java/com/example/notemark/main/presentation/vm/DetailsViewModel.kt b/note/presentation/src/main/java/com/example/presentation/note_details/DetailsViewModel.kt similarity index 98% rename from app/src/main/java/com/example/notemark/main/presentation/vm/DetailsViewModel.kt rename to note/presentation/src/main/java/com/example/presentation/note_details/DetailsViewModel.kt index 8748606..73e7a67 100644 --- a/app/src/main/java/com/example/notemark/main/presentation/vm/DetailsViewModel.kt +++ b/note/presentation/src/main/java/com/example/presentation/note_details/DetailsViewModel.kt @@ -1,4 +1,4 @@ -package com.example.notemark.main.presentation.vm +package com.example.presentation.note_details import android.content.pm.ActivityInfo import androidx.lifecycle.ViewModel diff --git a/note/presentation/src/main/java/com/example/presentation/note_details/NoteDetails.kt b/note/presentation/src/main/java/com/example/presentation/note_details/NoteDetails.kt new file mode 100644 index 0000000..2d671ba --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/note_details/NoteDetails.kt @@ -0,0 +1,71 @@ +package com.example.presentation.note_details + +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import androidx.paging.compose.LazyPagingItems +import com.example.domain.Note +import com.example.presentation.DeviceConfiguration +import com.example.presentation.note_details.components.DetailsContent +import com.example.presentation.note_details.components.LandscapeDetailsScreenContent +import kotlin.collections.find + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailsScreen( + navController: NavHostController = rememberNavController(), + noteId: String? = null, + notes: LazyPagingItems +) { + val note = notes.itemSnapshotList.items.find { it.id == noteId } + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) + + when(deviceConfiguration) { + DeviceConfiguration.MOBILE_PORTRAIT -> { + DetailsContent( + modifier = Modifier, + navController = navController, + note = note, + noteId = noteId, + ) + } + DeviceConfiguration.MOBILE_LANDSCAPE -> { + LandscapeDetailsScreenContent( + modifier = Modifier + .windowInsetsPadding(WindowInsets.displayCutout) + .consumeWindowInsets(WindowInsets.navigationBars), + navController = navController, + note = note, + noteId = noteId, + ) + } + DeviceConfiguration.TABLET_PORTRAIT, + DeviceConfiguration.TABLET_LANDSCAPE -> { + LandscapeDetailsScreenContent( + modifier = Modifier + .windowInsetsPadding(WindowInsets.displayCutout) + .consumeWindowInsets(WindowInsets.navigationBars), + navController = navController, + note = note, + noteId = noteId, + ) + } + DeviceConfiguration.DESKTOP -> { + DetailsContent( + modifier = Modifier, + navController = navController, + note = note, + noteId = noteId, + ) + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/note_details/components/DetailsContent.kt b/note/presentation/src/main/java/com/example/presentation/note_details/components/DetailsContent.kt new file mode 100644 index 0000000..eebfda2 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/note_details/components/DetailsContent.kt @@ -0,0 +1,266 @@ +package com.example.presentation.note_details.components + +import android.app.Activity +import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import com.example.notemark.core.presentation.R +import com.example.domain.Note +import com.example.presentation.getFormattedUpdatedAt +import com.example.presentation.note_details.DetailsViewModel + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +internal fun DetailsContent( + modifier: Modifier, + navController: NavHostController, + note: Note?, + noteId: String?, +) { + val context = LocalContext.current + val activity = context as Activity + + val scrollState = rememberScrollState() + val viewModel: DetailsViewModel = viewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + LaunchedEffect(uiState.requestedOrientation) { + uiState.requestedOrientation?.let { orientation -> + activity.requestedOrientation = orientation + viewModel.onOrientationHandled() + } + } + + LaunchedEffect(Unit) { + viewModel.setOriginalOrientation(activity.requestedOrientation) + } + + BackHandler(enabled = uiState.isReaderMode) { + viewModel.toggleReaderMode() + } + + LaunchedEffect(scrollState.value) { + if (scrollState.isScrollInProgress) { + viewModel.onScrollDetected() + } + } + + Scaffold( + topBar = { + AnimatedVisibility( + visible = !uiState.isReaderMode || uiState.isUiVisible, + enter = fadeIn(animationSpec = tween(300)) + slideInVertically( + animationSpec = tween(300) + ) { -it }, + exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( + animationSpec = tween(300) + ) { -it } + ) { + TopAppBar( + title = { + Text( + text = stringResource(R.string.all_notes).uppercase(), + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 1.0.sp, + fontFamily = FontFamily(Font(R.font.space_grotesk_regular)), + ) + }, + navigationIcon = { + IconButton( + onClick = { + if (uiState.isReaderMode) viewModel.toggleReaderMode() else navController.popBackStack() + } + ) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.ios_arrow_left), + contentDescription = "Navigate up", + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + } + ) { innerPadding -> + Box( + modifier = modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.onPrimary) + .padding( + if (!uiState.isReaderMode || uiState.isUiVisible) innerPadding else PaddingValues( + 0.dp + ) + ) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + viewModel.onScreenTap() + }, + ) { + if (note != null && note.id == noteId) { + Column( + modifier = Modifier.verticalScroll(scrollState) + ) { + Text( + text = note.title, + style = MaterialTheme.typography.titleLarge.copy( + color = MaterialTheme.colorScheme.onSurface, + ), + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) + + HorizontalDivider() + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + ) { + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = stringResource(R.string.date_created), + style = MaterialTheme.typography.bodySmall.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + ) + Text( + text = note.getFormattedUpdatedAt(), + style = MaterialTheme.typography.titleSmall.copy( + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.Bold + ) + ) + } + if (!note.getFormattedUpdatedAt().isEmpty()){ + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = stringResource(R.string.last_edited), + style = MaterialTheme.typography.bodySmall.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + ) + Text( + text = note.getFormattedUpdatedAt(), + style = MaterialTheme.typography.titleSmall.copy( + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.Bold + ) + ) + } + } + } + + HorizontalDivider() + + Text( + text = note.content, + style = MaterialTheme.typography.bodyLarge.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + ), + modifier = Modifier + .fillMaxWidth() + .padding( + if (uiState.isReaderMode && !uiState.isUiVisible) { + PaddingValues(horizontal = 24.dp, vertical = 32.dp) + } else { + PaddingValues(16.dp) + } + ) + ) + } + } else { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + } + + AnimatedVisibility( + visible = !uiState.isReaderMode || uiState.isUiVisible, + enter = fadeIn(animationSpec = tween(300)) + slideInVertically( + animationSpec = tween(300) + ) { it }, + exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( + animationSpec = tween(300) + ) { it }, + modifier = Modifier.align(Alignment.BottomCenter) + ) { + ExtendedFabFSheet( + onEditClick = { + // if we are in reader mode, first exit reader mode then handle the navigation +// navController.navigate( +// HomeScreens.EditNote( +// noteId = noteId ?: "" +// ) +// ) + }, + onReaderModeClick = { + viewModel.toggleReaderMode() + }, + isReaderMode = uiState.isReaderMode + ) + } + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/note_details/components/ExtendedFabFSheet.kt b/note/presentation/src/main/java/com/example/presentation/note_details/components/ExtendedFabFSheet.kt new file mode 100644 index 0000000..b120b70 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/note_details/components/ExtendedFabFSheet.kt @@ -0,0 +1,69 @@ +package com.example.presentation.note_details.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.unit.dp +import com.example.notemark.core.presentation.R + +@Composable +internal fun ExtendedFabFSheet( + modifier: Modifier = Modifier, + onEditClick: () -> Unit, + onReaderModeClick: () -> Unit, + isReaderMode: Boolean = false +) { + Row( + modifier = modifier + .padding(16.dp) + .background( + MaterialTheme.colorScheme.surface, + shape = MaterialTheme.shapes.medium + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + IconButton( + onClick = onEditClick + ) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.edit), + contentDescription = null + ) + } + + IconButton( + onClick = onReaderModeClick, + modifier = Modifier + .then( + if (isReaderMode) { + Modifier + .padding(4.dp) + .background( + color = Color(0x1A5977F7), + shape = MaterialTheme.shapes.medium + ) + } else { + Modifier + } + ) + ) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.book_open), + contentDescription = null, + tint = if (isReaderMode) MaterialTheme.colorScheme.primary else LocalContentColor.current + ) + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/note_details/components/LandscapeDetailsScreenContent.kt b/note/presentation/src/main/java/com/example/presentation/note_details/components/LandscapeDetailsScreenContent.kt new file mode 100644 index 0000000..2b453c4 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/note_details/components/LandscapeDetailsScreenContent.kt @@ -0,0 +1,267 @@ +package com.example.presentation.note_details.components + +import android.app.Activity +import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import com.example.notemark.core.presentation.R +import com.example.domain.Note +import com.example.presentation.getFormattedUpdatedAt +import com.example.presentation.note_details.DetailsViewModel + +@Composable +internal fun LandscapeDetailsScreenContent( + modifier: Modifier, + navController: NavHostController, + note: Note?, + noteId: String? +) { + val context = LocalContext.current + val activity = context as Activity + val scrollState = rememberScrollState() + val viewModel: DetailsViewModel = viewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + LaunchedEffect(uiState.requestedOrientation) { + uiState.requestedOrientation?.let { orientation -> + activity.requestedOrientation = orientation + viewModel.onOrientationHandled() + } + } + + LaunchedEffect(Unit) { + viewModel.setOriginalOrientation(activity.requestedOrientation) + } + + BackHandler(enabled = uiState.isReaderMode) { + viewModel.toggleReaderMode() + } + + LaunchedEffect(scrollState.value) { + if (scrollState.isScrollInProgress) { + viewModel.onScrollDetected() + } + } + + Box( + modifier = modifier.fillMaxSize() + ) { + // Main content - this stays in place + Row( + modifier = Modifier + .fillMaxSize() + .padding(start = 80.dp) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + viewModel.onScreenTap() + } + ) { + // Left spacer to account for back button (keep content centered) + Spacer(modifier = Modifier.width(64.dp)) // Adjust based on your back button width + + // Content area + Box( + modifier = Modifier + .fillMaxSize() + .padding(top = 24.dp, bottom = 80.dp) // Add bottom padding for FAB + ) { + if (note != null && note.id == noteId) { + Column( + modifier = Modifier.verticalScroll(scrollState) + ) { + Text( + text = note.title, + style = MaterialTheme.typography.titleLarge.copy( + color = MaterialTheme.colorScheme.onSurface, + ), + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) + + HorizontalDivider() + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + ) { + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = stringResource(R.string.date_created), + style = MaterialTheme.typography.bodySmall.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + ) + Text( + text = note.getFormattedUpdatedAt(), + style = MaterialTheme.typography.titleSmall.copy( + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.Bold + ) + ) + } + if (!note.getFormattedUpdatedAt().isEmpty()) { + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = stringResource(R.string.last_edited), + style = MaterialTheme.typography.bodySmall.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + ) + Text( + text = note.getFormattedUpdatedAt(), + style = MaterialTheme.typography.titleSmall.copy( + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.Bold + ) + ) + } + } + } + + HorizontalDivider() + + Text( + text = note.content, + style = MaterialTheme.typography.bodyLarge.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + ), + modifier = Modifier + .fillMaxWidth() + .padding( + if (uiState.isReaderMode && !uiState.isUiVisible) { + PaddingValues(horizontal = 16.dp, vertical = 32.dp) + } else { + PaddingValues(horizontal = 16.dp, vertical = 32.dp) + } + ) + ) + } + } else { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + } + } + } + + // Back button overlay - positioned absolutely at top-left + AnimatedVisibility( + visible = !uiState.isReaderMode || uiState.isUiVisible, + enter = fadeIn(animationSpec = tween(300)) + slideInVertically( + animationSpec = tween(300) + ) { -it }, + exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( + animationSpec = tween(300) + ) { -it }, + modifier = Modifier + .align(Alignment.TopStart) + .padding(top = 24.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + IconButton( + onClick = { + if (uiState.isReaderMode) viewModel.toggleReaderMode() else navController.popBackStack() + } + ) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.ios_arrow_left), + contentDescription = "Navigate up", + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + Spacer(modifier = Modifier.width(8.dp)) + + Text( + text = stringResource(R.string.all_notes).uppercase(), + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 1.0.sp, + fontFamily = FontFamily(Font(R.font.space_grotesk_regular)), + ) + } + } + + // FAB overlay - positioned absolutely at bottom-center + AnimatedVisibility( + visible = !uiState.isReaderMode || uiState.isUiVisible, + enter = fadeIn(animationSpec = tween(300)) + slideInVertically( + animationSpec = tween(300) + ) { it }, + exit = fadeOut(animationSpec = tween(300)) + slideOutVertically( + animationSpec = tween(300) + ) { it }, + modifier = Modifier.align(Alignment.BottomCenter) + ) { + ExtendedFabFSheet( + onEditClick = { +// navController.navigate( +// HomeScreens.EditNote( +// noteId = noteId ?: "" +// ) +// ) + }, + onReaderModeClick = { viewModel.toggleReaderMode() }, + isReaderMode = uiState.isReaderMode + ) + } + } +} diff --git a/note/presentation/src/main/java/com/example/presentation/settings/SettingsScreen.kt b/note/presentation/src/main/java/com/example/presentation/settings/SettingsScreen.kt new file mode 100644 index 0000000..76e7002 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/settings/SettingsScreen.kt @@ -0,0 +1,40 @@ +package com.example.presentation.settings + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable +import com.example.presentation.DeviceConfiguration +import com.example.presentation.settings.components.SettingsItem + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsScreen( + onNavigateUp: () -> Unit = {}, + onNavigateToLanding: () -> Unit = {} +) { + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val deviceConfiguration = DeviceConfiguration.fromWindowSizeClass(windowSizeClass) + + when(deviceConfiguration) { + DeviceConfiguration.MOBILE_PORTRAIT -> { + SettingsItem( + onNavigateUp = onNavigateUp, + onNavigateToLanding = onNavigateToLanding + ) + } + DeviceConfiguration.MOBILE_LANDSCAPE -> { + SettingsItem( + onNavigateUp = onNavigateUp, + onNavigateToLanding = onNavigateToLanding + ) + } + DeviceConfiguration.TABLET_PORTRAIT, + DeviceConfiguration.TABLET_LANDSCAPE, + DeviceConfiguration.DESKTOP -> { + SettingsItem( + onNavigateUp = onNavigateUp, + onNavigateToLanding = onNavigateToLanding + ) + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/settings/components/SettingsContent.kt b/note/presentation/src/main/java/com/example/presentation/settings/components/SettingsContent.kt new file mode 100644 index 0000000..303a80e --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/settings/components/SettingsContent.kt @@ -0,0 +1,111 @@ +package com.example.presentation.settings.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.unit.dp +import com.example.notemark.core.presentation.R +import com.example.presentation.SyncInterval + +@Composable +internal fun SettingsContent( + onLogoutClick: () -> Unit, + onSyncClick: () -> Unit, + onSyncIntervalClick: () -> Unit, + showSyncIntervalDropdown: Boolean, + onDismissSyncIntervalDropdown: () -> Unit, + selectedSyncInterval: SyncInterval, + onSyncIntervalSelected: (SyncInterval) -> Unit +) { + SingleItem( + onEndIconAndTextClick = onSyncIntervalClick, + supportingText = null, + headline = stringResource(R.string.sync_interval), + headlineTextColor = MaterialTheme.colorScheme.onSurface, + leadingIcon = ImageVector.vectorResource(R.drawable.clock), + iconTint = MaterialTheme.colorScheme.onSurfaceVariant, + endIcon = ImageVector.vectorResource(R.drawable.chevron_right), + endIconTint = MaterialTheme.colorScheme.onSurfaceVariant, + endText = selectedSyncInterval.displayName, + endTextColor = MaterialTheme.colorScheme.onSurfaceVariant, + showDropdown = showSyncIntervalDropdown, + onDismissDropdown = onDismissSyncIntervalDropdown, + dropdownContent = { + SyncInterval.entries.forEach { interval -> + DropdownMenuItem( + modifier = Modifier + .width(190.dp) + .background( + color = MaterialTheme.colorScheme.surface, + shape = RoundedCornerShape(16.dp) + ), + text = { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = interval.displayName + ) + + if (interval == selectedSyncInterval) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.check), + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(20.dp) + ) + } + } + }, + onClick = { + onSyncIntervalSelected(interval) + } + ) + } + } + ) + + SingleItem( + onClick = onSyncClick, + supportingText = stringResource(R.string.last_sync), + headline = stringResource(R.string.sync_data), + headlineTextColor = MaterialTheme.colorScheme.onSurface, + supportingTextColor = MaterialTheme.colorScheme.onSurfaceVariant, + leadingIcon = ImageVector.vectorResource(R.drawable.sync_icon), + iconTint = MaterialTheme.colorScheme.onSurfaceVariant, + endIcon = null, + endIconTint = null, + endText = null, + endTextColor = null + ) + + SingleItem( + onClick = onLogoutClick, + headline = stringResource(R.string.logout), + supportingText = null, + headlineTextColor = MaterialTheme.colorScheme.error, + supportingTextColor = null, + leadingIcon = ImageVector.vectorResource(R.drawable.logout), + iconTint = MaterialTheme.colorScheme.error, + endIcon = null, + endIconTint = null, + endText = null, + endTextColor = null + ) +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/settings/components/SettingsItem.kt b/note/presentation/src/main/java/com/example/presentation/settings/components/SettingsItem.kt new file mode 100644 index 0000000..3d9fac8 --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/settings/components/SettingsItem.kt @@ -0,0 +1,148 @@ +package com.example.presentation.settings.components + +import android.widget.Toast +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.sp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.example.presentation.NotesViewModel +import com.example.notemark.core.presentation.R +import com.example.presentation.SyncInterval +import com.example.presentation.login.LoginViewModel +import com.example.presentation.login.LogoutState + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +internal fun SettingsItem( + onNavigateUp: () -> Unit = {}, + onNavigateToLanding: () -> Unit = {}, +) { + val context = LocalContext.current + val loginViewModel: LoginViewModel = hiltViewModel() + val notesViewModel: NotesViewModel = hiltViewModel() + var showSyncIntervalDropdown by remember { mutableStateOf(false) } + val logoutState by loginViewModel.logoutState.collectAsStateWithLifecycle() + var selectedSyncInterval by remember { mutableStateOf(SyncInterval.MANUAL_ONLY) } + val refreshToken by notesViewModel.refreshToken.collectAsStateWithLifecycle() + + LaunchedEffect(logoutState) { + when (logoutState) { + is LogoutState.Error -> { + Toast.makeText( + context, + (logoutState as LogoutState.Error).message, + Toast.LENGTH_SHORT + ).show() + loginViewModel.clearState() + } + + is LogoutState.Success -> { + notesViewModel.clear() + onNavigateToLanding() + loginViewModel.clearState() + } + LogoutState.Loading, + LogoutState.Idle -> {} + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { + Text( + text = stringResource(R.string.settings).uppercase(), + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 1.0.sp, + fontFamily = FontFamily(Font(R.font.space_grotesk_regular)), + ) + }, + navigationIcon = { + IconButton( + onClick = { onNavigateUp() } + ) { + Icon( + tint = MaterialTheme.colorScheme.onSurfaceVariant, + imageVector = ImageVector.vectorResource(R.drawable.ios_arrow_left), + contentDescription = "Navigate up" + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.surface + ) + ) + } + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.surface) + .padding(innerPadding) + ) { + + if (logoutState is LogoutState.Loading) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + } else { + SettingsContent( + onLogoutClick = { + loginViewModel.logoutUser(refreshToken = refreshToken ?: "") + }, + onSyncClick = { + Toast.makeText( + context, + "This page is not available yet!", + Toast.LENGTH_SHORT + ).show() + }, + onSyncIntervalClick = { + showSyncIntervalDropdown = true + }, + showSyncIntervalDropdown = showSyncIntervalDropdown, + onDismissSyncIntervalDropdown = { + showSyncIntervalDropdown = false + }, + selectedSyncInterval = selectedSyncInterval, + onSyncIntervalSelected = { interval -> + selectedSyncInterval = interval + showSyncIntervalDropdown = false + } + ) + } + } + } +} \ No newline at end of file diff --git a/note/presentation/src/main/java/com/example/presentation/settings/components/SingleItem.kt b/note/presentation/src/main/java/com/example/presentation/settings/components/SingleItem.kt new file mode 100644 index 0000000..6f9e3ab --- /dev/null +++ b/note/presentation/src/main/java/com/example/presentation/settings/components/SingleItem.kt @@ -0,0 +1,131 @@ +package com.example.presentation.settings.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.dp + +@Composable +internal fun SingleItem( + modifier: Modifier = Modifier, + onEndIconAndTextClick: (() -> Unit)? = null, + onClick: (() -> Unit)? = null, + supportingText: String? = null, + supportingTextColor: Color? = null, + headline: String, + headlineTextColor: Color, + leadingIcon: ImageVector? = null, + iconTint: Color? = null, + endIcon: ImageVector? = null, + endIconTint: Color? = null, + endText: String? = null, + endTextColor: Color? = null, + showDropdown: Boolean = false, + onDismissDropdown: (() -> Unit)? = null, + dropdownContent: (@Composable ColumnScope.() -> Unit)? = null, +) { + Row( + modifier = modifier + .fillMaxWidth() + .heightIn(min = 56.dp) + .padding(horizontal = 16.dp, vertical = 8.dp) + .then( + if (onClick != null) { + Modifier.clickable { onClick() } + } else { + Modifier + } + ), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + leadingIcon?.let { icon -> + Icon( + imageVector = icon, + contentDescription = null, + tint = iconTint ?: MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.Start + ) { + Text( + text = headline, + style = MaterialTheme.typography.titleSmall.copy( + color = headlineTextColor + ) + ) + + if (!supportingText.isNullOrBlank()) { + Text( + text = supportingText, + style = MaterialTheme.typography.bodySmall.copy( + color = supportingTextColor ?: MaterialTheme.colorScheme.onSurfaceVariant + ) + ) + } + } + + val hasEndContent = !endText.isNullOrBlank() || endIcon != null + if (hasEndContent) { + Box { + Row( + modifier = Modifier.then( + if (onEndIconAndTextClick != null) { + Modifier.clickable { onEndIconAndTextClick() } + } else { + Modifier + } + ), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (!endText.isNullOrBlank()) { + Text( + text = endText, + style = MaterialTheme.typography.bodySmall.copy( + color = endTextColor ?: MaterialTheme.colorScheme.onSurfaceVariant + ) + ) + } + + endIcon?.let { icon -> + Icon( + imageVector = icon, + contentDescription = null, + tint = endIconTint ?: MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + if (dropdownContent != null) { + DropdownMenu( + expanded = showDropdown, + onDismissRequest = onDismissDropdown ?: {} + ) { + dropdownContent() + } + } + } + } + } +} \ No newline at end of file diff --git a/releases/data/build.gradle.kts b/releases/data/build.gradle.kts index 2582fe0..a32890c 100644 --- a/releases/data/build.gradle.kts +++ b/releases/data/build.gradle.kts @@ -1,11 +1,18 @@ plugins { alias(libs.plugins.notemark.android.library) + alias(libs.plugins.ktor.client.convention) + alias(libs.plugins.compose.compiler) + } android { - namespace = "com.example.data" + namespace = "com.example.notemark.releases.data" } dependencies { - implementation(projects.releases.domain) + + with(projects){ + implementation(core.domain) + implementation(releases.domain) + } } \ No newline at end of file diff --git a/releases/data/src/main/java/com/example/data/ReleasesService.kt b/releases/data/src/main/java/com/example/data/ReleasesService.kt new file mode 100644 index 0000000..7b64845 --- /dev/null +++ b/releases/data/src/main/java/com/example/data/ReleasesService.kt @@ -0,0 +1,6 @@ +package com.example.data + +//interface ReleasesService { +// +// suspend fun getLatestUpdate() +//} \ No newline at end of file diff --git a/releases/data/src/main/java/com/example/data/ReleasesServiceImpl.kt b/releases/data/src/main/java/com/example/data/ReleasesServiceImpl.kt new file mode 100644 index 0000000..0db6b4e --- /dev/null +++ b/releases/data/src/main/java/com/example/data/ReleasesServiceImpl.kt @@ -0,0 +1,22 @@ +package com.example.data + +import com.example.domain.HttpRoutes +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.http.cio.Response + +//class ReleasesServiceImpl( +// private val client: HttpClient, +//): ReleasesService { +// +// // override suspend fun getLatestUpdate(): Response { +//// return try { +//// client.get(HttpRoutes.UPDATES) +//// } catch (e: Exception) { +//// Response.Failure(e) +//// } +//// } +// override suspend fun getLatestUpdate() { +// TODO("Not yet implemented") +// } +//} \ No newline at end of file diff --git a/releases/presentation/build.gradle.kts b/releases/presentation/build.gradle.kts index 4bd5b53..af3f4b0 100644 --- a/releases/presentation/build.gradle.kts +++ b/releases/presentation/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } android { - namespace = "com.example.presentation" + namespace = "com.example.notemark.releases.presentation" } dependencies { diff --git a/releases/presentation/src/main/java/com/example/presentation/UpdateScreen.kt b/releases/presentation/src/main/java/com/example/presentation/UpdateScreen.kt new file mode 100644 index 0000000..2cfda3f --- /dev/null +++ b/releases/presentation/src/main/java/com/example/presentation/UpdateScreen.kt @@ -0,0 +1,17 @@ +package com.example.presentation + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +fun UpdateScreenRoot(modifier: Modifier = Modifier) { + + UpdateScreen() +} + +@Composable +private fun UpdateScreen( + modifier: Modifier = Modifier +) { + +} \ No newline at end of file