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