diff --git a/.kotlin/errors/errors-1735189166798.log b/.kotlin/errors/errors-1735189166798.log deleted file mode 100644 index 7dcd5ff..0000000 --- a/.kotlin/errors/errors-1735189166798.log +++ /dev/null @@ -1,49 +0,0 @@ -kotlin version: 2.1.0 -error message: java.lang.IllegalStateException: Unexpected member: class org.jetbrains.kotlin.fir.declarations.impl.FirDanglingModifierListImpl - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processMemberDeclaration(Fir2IrConverter.kt:553) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processFileAndClassMembers(Fir2IrConverter.kt:188) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.runSourcesConversion(Fir2IrConverter.kt:90) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.access$runSourcesConversion(Fir2IrConverter.kt:64) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter$Companion.generateIrModuleFragment(Fir2IrConverter.kt:667) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.runFir2IrConversion(convertToIr.kt:162) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.convertToIrAndActualize(convertToIr.kt:129) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize(convertToIr.kt:100) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize$default(convertToIr.kt:75) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertToIrAndActualizeForJvm(jvmCompilerPipeline.kt:134) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertAnalyzedFirToIr(jvmCompilerPipeline.kt:107) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.contextForStubGeneration(FirKaptAnalysisHandlerExtension.kt:220) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.doAnalysis(FirKaptAnalysisHandlerExtension.kt:116) - at org.jetbrains.kotlin.fir.extensions.FirAnalysisHandlerExtension$Companion.analyze(FirAnalysisHandlerExtension.kt:29) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineLightTreeKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipelineLightTree.kt:72) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:146) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) - at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:102) - at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.kt:316) - 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:674) - at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:91) - at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) - at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) - at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) - at java.base/java.lang.Thread.run(Thread.java:842) - - diff --git a/.kotlin/errors/errors-1735189248165.log b/.kotlin/errors/errors-1735189248165.log deleted file mode 100644 index 7dcd5ff..0000000 --- a/.kotlin/errors/errors-1735189248165.log +++ /dev/null @@ -1,49 +0,0 @@ -kotlin version: 2.1.0 -error message: java.lang.IllegalStateException: Unexpected member: class org.jetbrains.kotlin.fir.declarations.impl.FirDanglingModifierListImpl - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processMemberDeclaration(Fir2IrConverter.kt:553) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processFileAndClassMembers(Fir2IrConverter.kt:188) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.runSourcesConversion(Fir2IrConverter.kt:90) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.access$runSourcesConversion(Fir2IrConverter.kt:64) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter$Companion.generateIrModuleFragment(Fir2IrConverter.kt:667) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.runFir2IrConversion(convertToIr.kt:162) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.convertToIrAndActualize(convertToIr.kt:129) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize(convertToIr.kt:100) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize$default(convertToIr.kt:75) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertToIrAndActualizeForJvm(jvmCompilerPipeline.kt:134) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertAnalyzedFirToIr(jvmCompilerPipeline.kt:107) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.contextForStubGeneration(FirKaptAnalysisHandlerExtension.kt:220) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.doAnalysis(FirKaptAnalysisHandlerExtension.kt:116) - at org.jetbrains.kotlin.fir.extensions.FirAnalysisHandlerExtension$Companion.analyze(FirAnalysisHandlerExtension.kt:29) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineLightTreeKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipelineLightTree.kt:72) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:146) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) - at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:102) - at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.kt:316) - 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:674) - at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:91) - at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) - at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) - at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) - at java.base/java.lang.Thread.run(Thread.java:842) - - diff --git a/.kotlin/errors/errors-1735189324419.log b/.kotlin/errors/errors-1735189324419.log deleted file mode 100644 index 7dcd5ff..0000000 --- a/.kotlin/errors/errors-1735189324419.log +++ /dev/null @@ -1,49 +0,0 @@ -kotlin version: 2.1.0 -error message: java.lang.IllegalStateException: Unexpected member: class org.jetbrains.kotlin.fir.declarations.impl.FirDanglingModifierListImpl - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processMemberDeclaration(Fir2IrConverter.kt:553) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processFileAndClassMembers(Fir2IrConverter.kt:188) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.runSourcesConversion(Fir2IrConverter.kt:90) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.access$runSourcesConversion(Fir2IrConverter.kt:64) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter$Companion.generateIrModuleFragment(Fir2IrConverter.kt:667) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.runFir2IrConversion(convertToIr.kt:162) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.convertToIrAndActualize(convertToIr.kt:129) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize(convertToIr.kt:100) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize$default(convertToIr.kt:75) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertToIrAndActualizeForJvm(jvmCompilerPipeline.kt:134) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertAnalyzedFirToIr(jvmCompilerPipeline.kt:107) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.contextForStubGeneration(FirKaptAnalysisHandlerExtension.kt:220) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.doAnalysis(FirKaptAnalysisHandlerExtension.kt:116) - at org.jetbrains.kotlin.fir.extensions.FirAnalysisHandlerExtension$Companion.analyze(FirAnalysisHandlerExtension.kt:29) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineLightTreeKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipelineLightTree.kt:72) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:146) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) - at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:102) - at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.kt:316) - 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:674) - at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:91) - at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) - at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) - at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) - at java.base/java.lang.Thread.run(Thread.java:842) - - diff --git a/.kotlin/errors/errors-1735189739315.log b/.kotlin/errors/errors-1735189739315.log deleted file mode 100644 index 7dcd5ff..0000000 --- a/.kotlin/errors/errors-1735189739315.log +++ /dev/null @@ -1,49 +0,0 @@ -kotlin version: 2.1.0 -error message: java.lang.IllegalStateException: Unexpected member: class org.jetbrains.kotlin.fir.declarations.impl.FirDanglingModifierListImpl - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processMemberDeclaration(Fir2IrConverter.kt:553) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.processFileAndClassMembers(Fir2IrConverter.kt:188) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.runSourcesConversion(Fir2IrConverter.kt:90) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter.access$runSourcesConversion(Fir2IrConverter.kt:64) - at org.jetbrains.kotlin.fir.backend.Fir2IrConverter$Companion.generateIrModuleFragment(Fir2IrConverter.kt:667) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.runFir2IrConversion(convertToIr.kt:162) - at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.convertToIrAndActualize(convertToIr.kt:129) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize(convertToIr.kt:100) - at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize$default(convertToIr.kt:75) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertToIrAndActualizeForJvm(jvmCompilerPipeline.kt:134) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.convertAnalyzedFirToIr(jvmCompilerPipeline.kt:107) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.contextForStubGeneration(FirKaptAnalysisHandlerExtension.kt:220) - at org.jetbrains.kotlin.kapt4.FirKaptAnalysisHandlerExtension.doAnalysis(FirKaptAnalysisHandlerExtension.kt:116) - at org.jetbrains.kotlin.fir.extensions.FirAnalysisHandlerExtension$Companion.analyze(FirAnalysisHandlerExtension.kt:29) - at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineLightTreeKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipelineLightTree.kt:72) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:146) - at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) - at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:102) - at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.kt:316) - 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:674) - at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:91) - at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:568) - at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) - at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) - at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) - at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705) - at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) - at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) - at java.base/java.lang.Thread.run(Thread.java:842) - - diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bf7e595..51e95c0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,6 +8,7 @@ plugins { alias(libs.plugins.kotlin.android) alias(libs.plugins.hilt.android) alias(libs.plugins.ksp) + alias(libs.plugins.parcelize) } android { namespace = "com.flab.deepsleep" @@ -23,6 +24,12 @@ android { val unsplashAccessKey = localProperties.getProperty("UNSPLASH_ACCESS_KEY") ?: "" buildConfigField("String", "UNSPLASH_ACCESS_KEY", "\"$unsplashAccessKey\"") testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + javaCompileOptions { + annotationProcessorOptions { + arguments["room.schemaLocation"] = "$projectDir/schemas" + } + } } buildTypes { release { @@ -67,6 +74,9 @@ dependencies { implementation(libs.okhttp.profiler) implementation(libs.room.runtime) implementation(libs.room.ktx) + implementation(libs.fragment.ktx) + implementation(libs.activity.ktx) + implementation(libs.viewpager2) implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) diff --git a/app/src/main/java/com/flab/deepsleep/MainActivity.kt b/app/src/main/java/com/flab/deepsleep/MainActivity.kt index 836c172..6c50a36 100644 --- a/app/src/main/java/com/flab/deepsleep/MainActivity.kt +++ b/app/src/main/java/com/flab/deepsleep/MainActivity.kt @@ -1,56 +1,34 @@ package com.flab.deepsleep -import PhotoAdapter import android.os.Bundle import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.core.widget.doOnTextChanged -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.Observer -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.flab.deepsleep.data.entity.photos.SinglePhoto +import androidx.viewpager2.widget.ViewPager2 import com.flab.deepsleep.databinding.ActivityMainBinding +import com.flab.deepsleep.ui.adapter.ViewPagerAdapter import com.flab.deepsleep.ui.photo.PhotoViewModel -import com.flab.deepsleep.ui.photo.OnButtonClick +import com.flab.deepsleep.utils.Index +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import timber.log.Timber @AndroidEntryPoint class MainActivity : AppCompatActivity() { private val photoViewModel: PhotoViewModel by viewModels() private val binding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } - private val photoRecyclerView: RecyclerView by lazy { binding.photosRecyclerView } - private val photoAdapter: PhotoAdapter by lazy { - PhotoAdapter { singlePhoto -> - photoViewModel.insertPhoto(singlePhoto) - } - } - - private fun setRecyclerView() { - photoRecyclerView.layoutManager = GridLayoutManager(this, 2) - photoRecyclerView.adapter = photoAdapter - } + private val tabLayout: TabLayout by lazy { binding.tabLayout } + private val viewPager: ViewPager2 by lazy { binding.viewPager } + private val viewPagerAdapter: ViewPagerAdapter by lazy { ViewPagerAdapter(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(binding.root) - setRecyclerView() - - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - photoViewModel.items.collectLatest { - photoAdapter.submitData(it) - } - } - } + setViewPager() /* 검색어 입력시 자동 호출 */ binding.editText.doOnTextChanged { text, start, before, count -> @@ -59,12 +37,22 @@ class MainActivity : AppCompatActivity() { /* 에러 관찰 */ photoViewModel.errorMessage.observe(/* owner = */ this) { it -> - it?.let { - showErrorDialog(it) - } + it?.let { showErrorDialog(it) } } } + private fun setViewPager() { + viewPager.adapter = viewPagerAdapter + val tabIcons = listOf(R.drawable.ic_home, R.drawable.ic_bookmark) + TabLayoutMediator(tabLayout, viewPager) { tab, position -> + tab.icon = ContextCompat.getDrawable(this, tabIcons[position]) + tab.text = when (Index.positionOfIndex(position)) { + Index.HOME -> getString(R.string.home) + Index.BOOKMARK -> getString(R.string.bookmark) + } + }.attach() + } + private fun showErrorDialog(message: String) { AlertDialog.Builder(this) .setTitle("Error") diff --git a/app/src/main/java/com/flab/deepsleep/data/api/UnplashService.kt b/app/src/main/java/com/flab/deepsleep/data/api/UnplashService.kt index 92833d4..8cdab95 100644 --- a/app/src/main/java/com/flab/deepsleep/data/api/UnplashService.kt +++ b/app/src/main/java/com/flab/deepsleep/data/api/UnplashService.kt @@ -1,21 +1,18 @@ package com.flab.deepsleep.data.api import com.flab.deepsleep.data.entity.photos.SinglePhoto - import com.flab.deepsleep.data.entity.photos.SearchPhotos import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query interface UnplashService { - @GET("/photos/random") suspend fun getRandomPhotos( @Query("client_id") clientId: String, @Query("count") count: Int = 1 ): List - @GET("/search/photos") suspend fun getSearchPhotos( @Query("client_id") clientId: String, @@ -27,6 +24,4 @@ interface UnplashService { @Path("id") photoId: String, @Query("client_id") clientId: String ): SinglePhoto - - } \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/data/entity/photos/Exif.kt b/app/src/main/java/com/flab/deepsleep/data/entity/photos/Exif.kt index df47b87..1fd5ef5 100644 --- a/app/src/main/java/com/flab/deepsleep/data/entity/photos/Exif.kt +++ b/app/src/main/java/com/flab/deepsleep/data/entity/photos/Exif.kt @@ -1,9 +1,10 @@ package com.flab.deepsleep.data.entity.photos -import android.os.Parcel import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.parcelize.Parcelize +@Parcelize data class Exif( @SerializedName("aperture") val aperture: String?, @@ -19,39 +20,4 @@ data class Exif( val model: String?, @SerializedName("name") val name: String? -) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readInt(), - parcel.readString(), - parcel.readString(), - parcel.readString() - ) { - } - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(aperture) - parcel.writeString(exposureTime) - parcel.writeString(focalLength) - parcel.writeInt(iso) - parcel.writeString(make) - parcel.writeString(model) - parcel.writeString(name) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): Exif { - return Exif(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} +) : Parcelable diff --git a/app/src/main/java/com/flab/deepsleep/data/entity/photos/SinglePhoto.kt b/app/src/main/java/com/flab/deepsleep/data/entity/photos/SinglePhoto.kt index 545595d..45db2e5 100644 --- a/app/src/main/java/com/flab/deepsleep/data/entity/photos/SinglePhoto.kt +++ b/app/src/main/java/com/flab/deepsleep/data/entity/photos/SinglePhoto.kt @@ -1,10 +1,11 @@ package com.flab.deepsleep.data.entity.photos -import android.os.Parcel import android.os.Parcelable import com.flab.deepsleep.data.entity.room.Photo import com.google.gson.annotations.SerializedName +import kotlinx.parcelize.Parcelize +@Parcelize data class SinglePhoto( @SerializedName("blur_hash") val blurHash: String?, @@ -36,60 +37,14 @@ data class SinglePhoto( val urls: Urls?, @SerializedName("user") val user: User? -) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readInt(), - parcel.readInt(), - parcel.readString(), - parcel.readValue(Boolean::class.java.classLoader) as? Boolean, - parcel.readInt(), - parcel.readValue(Boolean::class.java.classLoader) as? Boolean, - parcel.readString(), - parcel.readInt(), - TODO("exif"), - TODO("urls"), - TODO("user") - ) - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(blurHash) - parcel.writeString(color) - parcel.writeString(createdAt) - parcel.writeString(description) - parcel.writeInt(downloads) - parcel.writeInt(height) - parcel.writeString(id) - parcel.writeValue(likedByUser) - parcel.writeInt(likes) - parcel.writeValue(publicDomain) - parcel.writeString(updatedAt) - parcel.writeInt(width) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): SinglePhoto { - return SinglePhoto(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} +) : Parcelable fun SinglePhoto.toPhoto(): Photo { return Photo( - id = this.id?.toIntOrNull() ?: 0, + id = this.id, likes = this.likes, urls = this.urls?.raw, + description = this.description, createdAt = this.createdAt, username = this.user?.username, isLike = true diff --git a/app/src/main/java/com/flab/deepsleep/data/entity/photos/Urls.kt b/app/src/main/java/com/flab/deepsleep/data/entity/photos/Urls.kt index 53d0d18..7cf3fcb 100644 --- a/app/src/main/java/com/flab/deepsleep/data/entity/photos/Urls.kt +++ b/app/src/main/java/com/flab/deepsleep/data/entity/photos/Urls.kt @@ -1,9 +1,10 @@ package com.flab.deepsleep.data.entity.photos -import android.os.Parcel import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.parcelize.Parcelize +@Parcelize data class Urls( @SerializedName("full") val full: String?, @@ -15,35 +16,4 @@ data class Urls( val small: String?, @SerializedName("thumb") val thumb: String? -) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readString() - ) { - } - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(full) - parcel.writeString(raw) - parcel.writeString(regular) - parcel.writeString(small) - parcel.writeString(thumb) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): Urls { - return Urls(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} +) : Parcelable diff --git a/app/src/main/java/com/flab/deepsleep/data/entity/photos/User.kt b/app/src/main/java/com/flab/deepsleep/data/entity/photos/User.kt index 30dde66..b610431 100644 --- a/app/src/main/java/com/flab/deepsleep/data/entity/photos/User.kt +++ b/app/src/main/java/com/flab/deepsleep/data/entity/photos/User.kt @@ -1,9 +1,10 @@ package com.flab.deepsleep.data.entity.photos -import android.os.Parcel import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.parcelize.Parcelize +@Parcelize data class User( @SerializedName("bio") val bio: String?, @@ -25,45 +26,4 @@ data class User( val updatedAt: String?, @SerializedName("username") val username: String? -) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readString(), - parcel.readInt(), - parcel.readInt(), - parcel.readInt(), - parcel.readString(), - parcel.readString() - ) { - } - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(bio) - parcel.writeString(id) - parcel.writeString(location) - parcel.writeString(name) - parcel.writeString(portfolioUrl) - parcel.writeInt(totalCollections) - parcel.writeInt(totalLikes) - parcel.writeInt(totalPhotos) - parcel.writeString(updatedAt) - parcel.writeString(username) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): User { - return User(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} +) : Parcelable diff --git a/app/src/main/java/com/flab/deepsleep/data/entity/room/AppDatabase.kt b/app/src/main/java/com/flab/deepsleep/data/entity/room/AppDatabase.kt index 983943b..29073e4 100644 --- a/app/src/main/java/com/flab/deepsleep/data/entity/room/AppDatabase.kt +++ b/app/src/main/java/com/flab/deepsleep/data/entity/room/AppDatabase.kt @@ -5,7 +5,7 @@ import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase -@Database(entities = [Photo::class], version = 2) +@Database(entities = [Photo::class], version = 4, exportSchema = false) abstract class AppDatabase : RoomDatabase() { abstract fun photoDao(): PhotoDao diff --git a/app/src/main/java/com/flab/deepsleep/data/entity/room/Photo.kt b/app/src/main/java/com/flab/deepsleep/data/entity/room/Photo.kt index b44337e..6e750c8 100644 --- a/app/src/main/java/com/flab/deepsleep/data/entity/room/Photo.kt +++ b/app/src/main/java/com/flab/deepsleep/data/entity/room/Photo.kt @@ -7,9 +7,10 @@ import androidx.room.PrimaryKey @Entity(tableName = "photo") data class Photo( @PrimaryKey(autoGenerate = true) val pk: Int = 0, - @ColumnInfo(name = "id") val id: Int, + @ColumnInfo(name = "id") val id: String?, @ColumnInfo(name = "likes") val likes: Int, @ColumnInfo(name = "urls") val urls: String?, + @ColumnInfo(name = "description") val description: String?, @ColumnInfo(name = "created_at") val createdAt: String?, @ColumnInfo(name = "username") val username: String?, @ColumnInfo(name = "is_like", defaultValue = "0") val isLike: Boolean = false, diff --git a/app/src/main/java/com/flab/deepsleep/data/source/PhotoPagingSource.kt b/app/src/main/java/com/flab/deepsleep/data/source/PhotoPagingSource.kt index e5e6f35..d495796 100644 --- a/app/src/main/java/com/flab/deepsleep/data/source/PhotoPagingSource.kt +++ b/app/src/main/java/com/flab/deepsleep/data/source/PhotoPagingSource.kt @@ -3,6 +3,7 @@ package com.flab.deepsleep.data.source import androidx.paging.PagingSource import androidx.paging.PagingState import com.flab.deepsleep.data.entity.photos.SinglePhoto +import timber.log.Timber class PhotoPagingSource( private val photos: List diff --git a/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoAdapter.kt b/app/src/main/java/com/flab/deepsleep/ui/adapter/PagingAdapter.kt similarity index 84% rename from app/src/main/java/com/flab/deepsleep/ui/photo/PhotoAdapter.kt rename to app/src/main/java/com/flab/deepsleep/ui/adapter/PagingAdapter.kt index 13e3744..d3cccac 100644 --- a/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoAdapter.kt +++ b/app/src/main/java/com/flab/deepsleep/ui/adapter/PagingAdapter.kt @@ -1,3 +1,5 @@ +package com.flab.deepsleep.ui.adapter + import android.view.LayoutInflater import android.view.ViewGroup import android.widget.ImageView @@ -10,11 +12,12 @@ import com.flab.deepsleep.data.entity.photos.SinglePhoto import com.flab.deepsleep.databinding.ItemPhotoBinding import com.flab.deepsleep.ui.photo.OnButtonClick -class PhotoAdapter(private val buttonClick: OnButtonClick) : - PagingDataAdapter(ARTICLE_DIFF_CALLBACK) { +class PagingAdapter(private val buttonClick: OnButtonClick) : + PagingDataAdapter(ARTICLE_DIFF_CALLBACK) { - inner class ImageViewHolder( + class ImageViewHolder( private val binding: ItemPhotoBinding, + private val buttonClick: OnButtonClick ) : RecyclerView.ViewHolder(binding.root) { private val imageView: ImageView = binding.photoImageView @@ -26,7 +29,7 @@ class PhotoAdapter(private val buttonClick: OnButtonClick) : buttonClick.onButtonClick(photo) } - val imageUrl = photo?.urls?.raw + val imageUrl = photo.urls?.raw if (imageUrl != null) { Glide.with(imageView.context) .load(imageUrl) @@ -40,7 +43,7 @@ class PhotoAdapter(private val buttonClick: OnButtonClick) : override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder { val binding = ItemPhotoBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return ImageViewHolder(binding) + return ImageViewHolder(binding, buttonClick) } override fun onBindViewHolder(holder: ImageViewHolder, position: Int) { diff --git a/app/src/main/java/com/flab/deepsleep/ui/adapter/PhotoAdapter.kt b/app/src/main/java/com/flab/deepsleep/ui/adapter/PhotoAdapter.kt new file mode 100644 index 0000000..624cbad --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/ui/adapter/PhotoAdapter.kt @@ -0,0 +1,57 @@ +package com.flab.deepsleep.ui.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.flab.deepsleep.R +import com.flab.deepsleep.data.entity.room.Photo +import com.flab.deepsleep.databinding.ItemPhotoBinding + +class PhotoAdapter : ListAdapter(ITEM_DIFF_CALLBACK) { + + class ItemViewHolder(private val binding: ItemPhotoBinding) : + RecyclerView.ViewHolder(binding.root) { + private val imageView: ImageView = binding.photoImageView + private val title: TextView = binding.photoTitle + + fun bind(photo: Photo) { + title.text = photo.description + + val imageUrl = photo.urls + if (imageUrl != null) { + Glide.with(imageView.context) + .load(imageUrl) + .placeholder(R.drawable.ic_launcher_foreground) + .into(imageView) + } else { + imageView.setImageResource(R.drawable.ic_launcher_foreground) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { + val binding = ItemPhotoBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ItemViewHolder(binding) + } + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + companion object { + private val ITEM_DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Photo, newItem: Photo): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: Photo, newItem: Photo): Boolean { + return oldItem == newItem + } + } + } +} diff --git a/app/src/main/java/com/flab/deepsleep/ui/adapter/ViewPagerAdapter.kt b/app/src/main/java/com/flab/deepsleep/ui/adapter/ViewPagerAdapter.kt new file mode 100644 index 0000000..ff2da94 --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/ui/adapter/ViewPagerAdapter.kt @@ -0,0 +1,19 @@ +package com.flab.deepsleep.ui.adapter + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.flab.deepsleep.MainActivity +import com.flab.deepsleep.ui.fragment.BookmarkFragment +import com.flab.deepsleep.ui.fragment.HomeFragment +import com.flab.deepsleep.utils.Index + +class ViewPagerAdapter(mainActivity: MainActivity) : FragmentStateAdapter(mainActivity) { + override fun getItemCount(): Int = 2 + + override fun createFragment(position: Int): Fragment { + return when (Index.positionOfIndex(position)) { + Index.HOME -> HomeFragment() + Index.BOOKMARK -> BookmarkFragment() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/ui/fragment/BookmarkFragment.kt b/app/src/main/java/com/flab/deepsleep/ui/fragment/BookmarkFragment.kt new file mode 100644 index 0000000..92f6854 --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/ui/fragment/BookmarkFragment.kt @@ -0,0 +1,54 @@ +package com.flab.deepsleep.ui.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.flab.deepsleep.databinding.FragmentBookmarkBinding +import com.flab.deepsleep.ui.adapter.PhotoAdapter +import com.flab.deepsleep.ui.photo.PhotoViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class BookmarkFragment : Fragment() { + private var _binding: FragmentBookmarkBinding? = null + private val binding get() = _binding!! + private val photoRecyclerView: RecyclerView by lazy { binding.bookmarkRecyclerview } + private val photoAdapter: PhotoAdapter by lazy { PhotoAdapter() } + private val photoViewModel: PhotoViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + _binding = FragmentBookmarkBinding.inflate(inflater, container, false) + val view = binding.root + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setRecyclerView() + + lifecycleScope.launch { + photoViewModel.allPhotos.collect { photos -> + photoAdapter.submitList(photos) + } + } + } + + private fun setRecyclerView() { + photoRecyclerView.layoutManager = GridLayoutManager(context, 2) + photoRecyclerView.adapter = photoAdapter + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/ui/fragment/HomeFragment.kt b/app/src/main/java/com/flab/deepsleep/ui/fragment/HomeFragment.kt new file mode 100644 index 0000000..5e273aa --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/ui/fragment/HomeFragment.kt @@ -0,0 +1,60 @@ +package com.flab.deepsleep.ui.fragment + +import com.flab.deepsleep.ui.adapter.PagingAdapter +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.flab.deepsleep.databinding.FragmentHomeBinding +import com.flab.deepsleep.ui.photo.PhotoViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class HomeFragment : Fragment() { + private var _binding: FragmentHomeBinding? = null + private val binding get() = _binding!! + private val photoViewModel: PhotoViewModel by activityViewModels() + private val photoRecyclerView: RecyclerView by lazy { binding.photosRecyclerView } + private val pagingAdapter: PagingAdapter by lazy { + PagingAdapter { singlePhoto -> + photoViewModel.insertPhoto(singlePhoto) + } + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + _binding = FragmentHomeBinding.inflate(inflater, container, false) + val view = binding.root + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setRecyclerView() + + viewLifecycleOwner.lifecycleScope.launch { + photoViewModel.items.collectLatest { pagingData -> + pagingAdapter.submitData(pagingData) + } + } + } + + private fun setRecyclerView() { + photoRecyclerView.layoutManager = GridLayoutManager(context, 2) + photoRecyclerView.adapter = pagingAdapter + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoViewModel.kt b/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoViewModel.kt index 2b746e2..619f8c3 100644 --- a/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoViewModel.kt +++ b/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoViewModel.kt @@ -18,14 +18,17 @@ import com.flab.deepsleep.data.source.PhotoPagingSource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject @@ -44,10 +47,7 @@ class PhotoViewModel @Inject constructor( private val _photoState = MutableLiveData?>() val photoState: MutableLiveData?> get() = _photoState - /* Photo Database */ - val allPhotos: Flow> = photoRepository.getAllPhotos() - - + @OptIn(ExperimentalCoroutinesApi::class) val items: Flow> = _photoState.asFlow() .map { state -> state ?: emptyList() } .flatMapLatest { photos -> @@ -58,6 +58,14 @@ class PhotoViewModel @Inject constructor( } .cachedIn(viewModelScope) + /* Room Flow */ + val allPhotos: Flow> = photoRepository.getAllPhotos() + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(5000), + emptyList() + ) + /* 사진 검색 */ fun searchPhotos(query: String) { searchDebouncer(query) @@ -70,7 +78,7 @@ class PhotoViewModel @Inject constructor( } } - suspend fun getSearchPhotos(query: String): List { + private suspend fun getSearchPhotos(query: String): List { return coroutineScope { try { unplashRepository.getSearchPhotos(query) diff --git a/app/src/main/java/com/flab/deepsleep/utils/Constants.kt b/app/src/main/java/com/flab/deepsleep/utils/Constants.kt deleted file mode 100644 index 20b6415..0000000 --- a/app/src/main/java/com/flab/deepsleep/utils/Constants.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.flab.deepsleep.utils - -object Constants { - const val NETWORK_PAGE_SIZE = 20 - const val DEFAULT_QUERY = "kotlin" -} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/utils/EditTextExtensions.kt b/app/src/main/java/com/flab/deepsleep/utils/EditTextExtensions.kt deleted file mode 100644 index 3750a1a..0000000 --- a/app/src/main/java/com/flab/deepsleep/utils/EditTextExtensions.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.flab.deepsleep.utils - -import android.text.Editable -import android.text.TextWatcher -import android.widget.EditText - -fun EditText.setOnTextChangedListener(onTextChanged: (String) -> Unit) { - this.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - onTextChanged(s.toString()) - } - override fun afterTextChanged(s: Editable?) {} - }) -} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/utils/Index.kt b/app/src/main/java/com/flab/deepsleep/utils/Index.kt new file mode 100644 index 0000000..541b193 --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/utils/Index.kt @@ -0,0 +1,13 @@ +package com.flab.deepsleep.utils + +enum class Index(private val position: Int) { + HOME(0), + BOOKMARK(1); + + companion object { + fun positionOfIndex(position: Int): Index { + return entries.find { it.position == position } + ?: throw IllegalArgumentException("Unexpected position $position") + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark.xml b/app/src/main/res/drawable/ic_bookmark.xml new file mode 100644 index 0000000..2989e8d --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml new file mode 100644 index 0000000..5f0e5bf --- /dev/null +++ b/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ab5b7f2..8a1e3dd 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,58 +5,67 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" tools:context=".MainActivity"> + app:layout_constraintTop_toTopOf="parent"> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintStart_toEndOf="@+id/editText" + app:layout_constraintTop_toTopOf="@+id/editText" /> - - + + + app:layout_constraintTop_toBottomOf="@+id/search_bar" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bookmark.xml b/app/src/main/res/layout/fragment_bookmark.xml new file mode 100644 index 0000000..967ab14 --- /dev/null +++ b/app/src/main/res/layout/fragment_bookmark.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..0142a56 --- /dev/null +++ b/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_photo.xml b/app/src/main/res/layout/item_photo.xml index c3ca639..b94fc4a 100644 --- a/app/src/main/res/layout/item_photo.xml +++ b/app/src/main/res/layout/item_photo.xml @@ -30,7 +30,6 @@ android:id="@+id/photo_title" android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@string/test" android:textSize="15sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/bt_heart" diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c8524cd..f5b12e0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,7 @@ #FF000000 #FFFFFFFF + + #F2F2F2 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 53e662b..7b0b0e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,8 @@ 검색 입력 테스트 + + 북마크 8dp diff --git a/build.gradle.kts b/build.gradle.kts index 177123c..6734cad 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,14 +5,17 @@ plugins { alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.hilt.android) apply false alias(libs.plugins.ksp) apply false + alias(libs.plugins.parcelize) apply false } buildscript { repositories { google() mavenCentral() + gradlePluginPortal() } dependencies { classpath("com.android.tools.build:gradle:8.0.2") // Android Gradle Plugin classpath("com.google.dagger:hilt-android-gradle-plugin:2.51.1") // Hilt 플러그인 + classpath("org.jetbrains.kotlin.plugin.parcelize:org.jetbrains.kotlin.plugin.parcelize.gradle.plugin:2.1.20-Beta1") // Parcelize Plugin } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index db7022a..d9fdb7e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,14 +2,14 @@ agp = "8.7.3" gson = "2.11.0" hiltAndroidCompiler = "2.51.1" -kotlin = "1.9.24" +kotlin = "2.1.0" coreKtx = "1.15.0" junit = "4.13.2" junitVersion = "1.2.1" espressoCore = "3.6.1" appcompat = "1.7.0" material = "1.12.0" -activity = "1.9.3" +activity = "1.10.0" constraintlayout = "2.2.0" retrofit = "2.9.0" hilt = "2.51.1" @@ -26,7 +26,11 @@ kotlinx-coroutines-android = "1.7.3" okhttp = "4.12.0" okhttp-profiler = "1.0.8" room = "2.6.1" -ksp = "2.0.21-1.0.27" +ksp = "2.1.20-Beta1-1.0.29" +fragment-ktx = "1.8.5" +activity-ktx = "1.10.0" +viewpager2 = "1.1.0" +parcelize = "2.1.20-Beta1" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -58,9 +62,13 @@ okhttp-profiler = { module = "com.localebro:okhttpprofiler", version.ref = "okht room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } +fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" } +activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activity-ktx" } +viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "parcelize" } \ No newline at end of file