From 7d6206d2502e0b3c154a1bc80621fc5e071c1503 Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 15 May 2024 16:40:37 +0900 Subject: [PATCH 01/47] =?UTF-8?q?[CT-3]=20chore:=20buildSrc=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 10 +++++----- buildSrc/src/main/kotlin/Dependency.kt | 25 ++++++++++++++++++------- data/build.gradle.kts | 8 ++++---- domain/build.gradle.kts | 4 ++-- presentation/build.gradle.kts | 12 +++++++----- 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 76e9b77..5cb17ff 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,12 +51,12 @@ dependencies { implementation(project(path = ":domain")) implementation(project(path = ":presentation")) - implementation(Dependency.HILT) - kapt(Dependency.HILT_COMPILER) + implementation(Dependency.Common.HILT) + kapt(Dependency.Common.HILT_COMPILER) - implementation(Dependency.ANDROIDX_CORE) - testImplementation(Dependency.Test.JUNIT) - androidTestImplementation(Dependency.Test.JUNIT_EXT) + implementation(Dependency.Common.ANDROIDX_CORE) + testImplementation(Dependency.Common.JUNIT) + androidTestImplementation(Dependency.Common.JUNIT_EXT) } configure { diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 49fc2b1..1b5a5be 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -1,10 +1,22 @@ object Dependency { - const val HILT = "com.google.dagger:hilt-android:2.44" - const val HILT_COMPILER = "com.google.dagger:hilt-android-compiler:2.44" - const val JAVAX_INJECT = "javax.inject:javax.inject:1" - const val KOTLINX_COROUTINSE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1" + object Common { + const val HILT = "com.google.dagger:hilt-android:2.44" + const val HILT_COMPILER = "com.google.dagger:hilt-android-compiler:2.44" - const val ANDROIDX_CORE = "androidx.core:core-ktx:1.9.0" // 1.13.1 + const val ANDROIDX_CORE = "androidx.core:core-ktx:1.9.0" // 1.13.1 + + const val JUNIT = "junit:junit:4.13.2" + const val JUNIT_EXT = "androidx.test.ext:junit:1.1.5" + } + + object PlatformIndependent { + const val JAVAX_INJECT = "javax.inject:javax.inject:1" + const val KOTLINX_COROUTINSE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1" + } + + object Data { + const val RETROFIT = "com.squareup.retrofit2:retrofit:2.11.0" + } object Compose { const val BOM = "androidx.compose:compose-bom:2023.03.00" @@ -21,8 +33,7 @@ object Dependency { } object Test { - const val JUNIT = "junit:junit:4.13.2" - const val JUNIT_EXT = "androidx.test.ext:junit:1.1.5" + } } diff --git a/data/build.gradle.kts b/data/build.gradle.kts index b4309b1..5fae706 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -38,9 +38,9 @@ android { dependencies { implementation(project(path = ":domain")) - implementation(Dependency.HILT) - kapt(Dependency.HILT_COMPILER) + implementation(Dependency.Common.HILT) + kapt(Dependency.Common.HILT_COMPILER) - testImplementation(Dependency.Test.JUNIT) - androidTestImplementation(Dependency.Test.JUNIT_EXT) + testImplementation(Dependency.Common.JUNIT) + androidTestImplementation(Dependency.Common.JUNIT_EXT) } diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 5ce545c..4f1760c 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -12,6 +12,6 @@ java { } dependencies { - implementation(Dependency.JAVAX_INJECT) - implementation(Dependency.KOTLINX_COROUTINSE) + implementation(Dependency.PlatformIndependent.JAVAX_INJECT) + implementation(Dependency.PlatformIndependent.KOTLINX_COROUTINSE) } diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts index 1ba22c1..8e58a7f 100644 --- a/presentation/build.gradle.kts +++ b/presentation/build.gradle.kts @@ -48,8 +48,10 @@ android { dependencies { implementation(project(path = ":domain")) - implementation(Dependency.HILT) - kapt(Dependency.HILT_COMPILER) + implementation(Dependency.Common.HILT) + kapt(Dependency.Common.HILT_COMPILER) + + implementation(Dependency.Compose.LIFECYCLE_RUNTIME) implementation(Dependency.Compose.ACTIVITY_COMPOSE) // 1.9.0 @@ -63,9 +65,9 @@ dependencies { debugImplementation(Dependency.Compose.UI_TOOLING) debugImplementation(Dependency.Compose.UI_TEST_MANIFEST) - implementation(Dependency.ANDROIDX_CORE) - testImplementation(Dependency.Test.JUNIT) - androidTestImplementation(Dependency.Test.JUNIT_EXT) + implementation(Dependency.Common.ANDROIDX_CORE) + testImplementation(Dependency.Common.JUNIT) + androidTestImplementation(Dependency.Common.JUNIT_EXT) } configure { From 069524e09f73fe4d4f7bf478c18a54c872d45eb9 Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 15 May 2024 16:54:42 +0900 Subject: [PATCH 02/47] =?UTF-8?q?[CT-3]=20BuildConfig=20=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94,=20Retrofit,=20Gson,=20OkHttp=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 2 ++ data/build.gradle.kts | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 1b5a5be..8e8bac3 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -16,6 +16,8 @@ object Dependency { object Data { const val RETROFIT = "com.squareup.retrofit2:retrofit:2.11.0" + const val GSON = "com.google.code.gson:gson:2.10.1" + const val OK_HTTP_3 = "com.squareup.okhttp3:logging-interceptor:4.12.0" } object Compose { diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 5fae706..29d6305 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -26,18 +26,28 @@ android { ) } } + compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } + kotlinOptions { jvmTarget = "17" } + + buildFeatures { + buildConfig = true + } } dependencies { implementation(project(path = ":domain")) + implementation(Dependency.Data.RETROFIT) + implementation(Dependency.Data.GSON) + implementation(Dependency.Data.OK_HTTP_3) + implementation(Dependency.Common.HILT) kapt(Dependency.Common.HILT_COMPILER) From 57834a223744baff38c91445bce9836177faa00b Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 15 May 2024 19:32:29 +0900 Subject: [PATCH 03/47] =?UTF-8?q?[CT-3]=20=EC=9D=B8=ED=84=B0=EB=84=B7=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=20=EA=B6=8C=ED=95=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3d1cc16..60ea500 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + Date: Wed, 15 May 2024 19:35:11 +0900 Subject: [PATCH 04/47] =?UTF-8?q?[CT-3]=20retrofit=20gson=20converter=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20BuildConfig=20=EC=97=90=20=EB=A1=9C?= =?UTF-8?q?=EC=BB=AC=ED=94=84=EB=A1=9C=ED=8D=BC=ED=8B=B0=EB=A1=9C=20API=5F?= =?UTF-8?q?KEY=20=EC=B6=94=EA=B0=80,=20CoreLibraryDesugaringEnabled=20?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 8 ++++++-- data/build.gradle.kts | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 8e8bac3..23dd667 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -15,9 +15,13 @@ object Dependency { } object Data { - const val RETROFIT = "com.squareup.retrofit2:retrofit:2.11.0" - const val GSON = "com.google.code.gson:gson:2.10.1" + const val RETROFIT = "com.squareup.retrofit2:retrofit:${Version.RETROFIT}" + const val RETROFIT_GSON_CONVERTER = "com.squareup.retrofit2:converter-gson:${Version.RETROFIT}" const val OK_HTTP_3 = "com.squareup.okhttp3:logging-interceptor:4.12.0" + + object Version { + const val RETROFIT = "2.11.0" + } } object Compose { diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 29d6305..da6daaa 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + plugins { id(Plugin.ANDROID_LIBRARY) id(Plugin.KOTLIN_ANDROID) @@ -6,6 +8,11 @@ plugins { kotlin(Plugin.KAPT) } +val properties = Properties() +val localPropertiesFile = rootProject.file("local.properties").inputStream() +properties.load(localPropertiesFile) +localPropertiesFile.close() + android { namespace = "com.yessorae.data" compileSdk = 34 @@ -18,6 +25,14 @@ android { } buildTypes { + defaultConfig { + buildConfigField( + "String", + "POLYGON_API_KEY", + "${properties["POLYGON_API_KEY"]}" + ) + } + release { isMinifyEnabled = false proguardFiles( @@ -26,10 +41,11 @@ android { ) } } - + compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 + isCoreLibraryDesugaringEnabled = true } kotlinOptions { @@ -45,7 +61,7 @@ dependencies { implementation(project(path = ":domain")) implementation(Dependency.Data.RETROFIT) - implementation(Dependency.Data.GSON) + implementation(Dependency.Data.RETROFIT_GSON_CONVERTER) implementation(Dependency.Data.OK_HTTP_3) implementation(Dependency.Common.HILT) From 5164c938966c397bb5f122d9bac26a553ebb7c53 Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 15 May 2024 19:42:48 +0900 Subject: [PATCH 05/47] =?UTF-8?q?[CT-3]=20Tick=20=EC=97=90=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/yessorae/domain/entity/tick/Tick.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt b/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt index b58f64d..28f3d42 100644 --- a/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt +++ b/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt @@ -20,9 +20,5 @@ data class Tick( // 거래량가중평균가격. // Volume Weighted Average Price의 약어로, // 조회 대상 종목의 거래일에 발생한 전체 거래대금을 전체 거래량으로 나눈 가격을 의미 - val volumeWeightedAveragePrice: Double, - // 장외거래(場外去來, Over-the-counter)는 - // 주식, 채권, 상품선물, 파생금융상품과 같은 투자자산을 거래소(exchange)를 거치지 않고, - // 양 당사자가 직접 거래하는 것을 의미 - val isOverTheCounter: Boolean + val volumeWeightedAveragePrice: Double ) From 3c4260687cce86ad5d81caeb40f34f253249acd2 Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 15 May 2024 19:53:40 +0900 Subject: [PATCH 06/47] =?UTF-8?q?[CT-3]=20DataSource=20=EC=B6=94=EA=B0=80,?= =?UTF-8?q?=20Polygon.io=20API=20=ED=98=B8=EC=B6=9C=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yessorae/data/common/LocalDateTimeExt.kt | 8 ++++ .../yessorae/data/di/CommonNetworkModule.kt | 28 +++++++++++ .../com/yessorae/data/di/DataSourceModule.kt | 17 +++++++ .../yessorae/data/di/PolygonNetworkModule.kt | 48 +++++++++++++++++++ .../source/network/ChartNetworkDataSource.kt | 13 +++++ .../polygon/PolygonChartNetworkDataSource.kt | 36 ++++++++++++++ .../network/polygon/api/PolygonChartApi.kt | 32 +++++++++++++ .../network/polygon/common/PolygonConstant.kt | 25 ++++++++++ .../network/polygon/model/chart/ChartDto.kt | 30 ++++++++++++ .../network/polygon/model/chart/TickDto.kt | 36 ++++++++++++++ 10 files changed, 273 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt create mode 100644 data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt create mode 100644 data/src/main/java/com/yessorae/data/di/DataSourceModule.kt create mode 100644 data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/common/PolygonConstant.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt diff --git a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt b/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt new file mode 100644 index 0000000..653e808 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt @@ -0,0 +1,8 @@ +package com.yessorae.data.common + +import java.time.LocalDateTime +import java.time.ZoneOffset + +fun Long.toLocalDateTime(): LocalDateTime { + return LocalDateTime.ofEpochSecond(this / 1000, 0, ZoneOffset.UTC) +} \ No newline at end of file diff --git a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt new file mode 100644 index 0000000..0ccb806 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt @@ -0,0 +1,28 @@ +package com.yessorae.data.di + +import com.yessorae.data.BuildConfig +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.Call +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object CommonNetworkModule { + @Provides + @Singleton + fun provideOkHttpCallFactory(): Call.Factory = OkHttpClient.Builder() + .addInterceptor( + HttpLoggingInterceptor() + .apply { + if (BuildConfig.DEBUG) { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + }, + ) + .build() +} diff --git a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt new file mode 100644 index 0000000..6004e0e --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt @@ -0,0 +1,17 @@ +package com.yessorae.data.di + +import com.yessorae.data.source.network.ChartNetworkDataSource +import com.yessorae.data.source.network.polygon.PolygonChartNetworkDataSource +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class DataSourceModule { + @Binds + @Singleton + abstract fun bindsChartNetworkDataSource(polygonChartNetworkDataSource: PolygonChartNetworkDataSource): ChartNetworkDataSource +} \ No newline at end of file diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt new file mode 100644 index 0000000..e87306d --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.yessorae.data.di + +import com.yessorae.data.source.network.polygon.api.PolygonChartApi +import com.yessorae.data.source.network.polygon.common.PolygonConstant +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.Call +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object PolygonNetworkModule { + @Provides + @Singleton + fun provideRetrofit( + okhttpCallFactory: Call.Factory + ): Retrofit = Retrofit.Builder() + .baseUrl(PolygonConstant.BASE_URL) + .callFactory(okhttpCallFactory) + .addConverterFactory(GsonConverterFactory.create()) + .build() + + @Provides + @Singleton + fun provideChartApi( + retrofit: Retrofit + ): PolygonChartApi = retrofit.create(PolygonChartApi::class.java) +} diff --git a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt new file mode 100644 index 0000000..43820f8 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt @@ -0,0 +1,13 @@ +package com.yessorae.data.source.network + +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.tick.TickUnit + +interface ChartNetworkDataSource { + suspend fun getChart( + ticker: String, + tickUnit: TickUnit, + from: String, + to: String + ): Chart +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt new file mode 100644 index 0000000..c498381 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt @@ -0,0 +1,36 @@ +package com.yessorae.data.source.network.polygon + +import com.yessorae.data.source.network.ChartNetworkDataSource +import com.yessorae.data.source.network.polygon.api.PolygonChartApi +import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_DAY_PATH_VALUE +import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_HOUR_PATH_VALUE +import com.yessorae.data.source.network.polygon.model.chart.asDomainModel +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.tick.TickUnit +import javax.inject.Inject + +class PolygonChartNetworkDataSource @Inject constructor( + private val api: PolygonChartApi +) : ChartNetworkDataSource { + override suspend fun getChart( + ticker: String, + tickUnit: TickUnit, + from: String, + to: String + ): Chart { + return api + .getChartData( + ticker = ticker, + timeSpan = tickUnit.toPathValue(), + from = from, + to = to + ).asDomainModel(tickUnit = tickUnit) + } +} + +private fun TickUnit.toPathValue(): String { + return when (this) { + TickUnit.DAY -> TIME_SPAN_DAY_PATH_VALUE + TickUnit.HOUR -> TIME_SPAN_HOUR_PATH_VALUE + } +} \ No newline at end of file diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt new file mode 100644 index 0000000..3128123 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt @@ -0,0 +1,32 @@ +package com.yessorae.data.source.network.polygon.api + +import com.yessorae.data.BuildConfig +import com.yessorae.data.source.network.polygon.common.PolygonConstant +import com.yessorae.data.source.network.polygon.common.PolygonConstant.ADJUSTED_QUERY_KEY +import com.yessorae.data.source.network.polygon.common.PolygonConstant.API_KEY_QUERY_KEY +import com.yessorae.data.source.network.polygon.common.PolygonConstant.DEFAULT_MULTIPLIER_PATH_VALUE +import com.yessorae.data.source.network.polygon.common.PolygonConstant.FROM_PATH_NAME +import com.yessorae.data.source.network.polygon.common.PolygonConstant.GET_CHART_PATH +import com.yessorae.data.source.network.polygon.common.PolygonConstant.MULTIPLIER_PATH_NAME +import com.yessorae.data.source.network.polygon.common.PolygonConstant.SORT_QUERY_KEY +import com.yessorae.data.source.network.polygon.common.PolygonConstant.STOCK_TICKER_PATH_NAME +import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_PATH_NAME +import com.yessorae.data.source.network.polygon.common.PolygonConstant.TO_PATH_NAME +import com.yessorae.data.source.network.polygon.model.chart.ChartDto +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface PolygonChartApi { + @GET(GET_CHART_PATH) + suspend fun getChartData( + @Path(STOCK_TICKER_PATH_NAME) ticker: String, + @Path(TIME_SPAN_PATH_NAME) timeSpan: String, + @Path(FROM_PATH_NAME) from: String, + @Path(TO_PATH_NAME) to: String, + @Path(MULTIPLIER_PATH_NAME) multiplier: Int = DEFAULT_MULTIPLIER_PATH_VALUE, + @Query(ADJUSTED_QUERY_KEY) adjusted: Boolean = true, + @Query(SORT_QUERY_KEY) sort: String = PolygonConstant.DEFAULT_SORT_QUERY_VALUE, + @Query(API_KEY_QUERY_KEY) apiKey: String = BuildConfig.POLYGON_API_KEY + ): ChartDto +} \ No newline at end of file diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/common/PolygonConstant.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/common/PolygonConstant.kt new file mode 100644 index 0000000..2b7670d --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/common/PolygonConstant.kt @@ -0,0 +1,25 @@ +package com.yessorae.data.source.network.polygon.common + +/** + * polygon.io 의 API 요청과 응답에 필요한 상수들의 모음 + * [API 문서 참고](https://polygon.io/docs/stocks/getting-started) + */ +object PolygonConstant { + const val BASE_URL = "https://api.polygon.io/" + + const val GET_CHART_PATH = + "/v2/aggs/ticker/{stocksTicker}/range/{multiplier}/{timespan}/{from}/{to}" + const val STOCK_TICKER_PATH_NAME = "stocksTicker" + const val MULTIPLIER_PATH_NAME = "multiplier" + const val TIME_SPAN_PATH_NAME = "timespan" + const val FROM_PATH_NAME = "from" + const val TO_PATH_NAME = "to" + const val ADJUSTED_QUERY_KEY = "adjusted" + const val SORT_QUERY_KEY = "sort" + const val API_KEY_QUERY_KEY = "apiKey" + + const val DEFAULT_SORT_QUERY_VALUE = "asc" + const val DEFAULT_MULTIPLIER_PATH_VALUE = 1 + const val TIME_SPAN_DAY_PATH_VALUE = "day" + const val TIME_SPAN_HOUR_PATH_VALUE = "day" +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt new file mode 100644 index 0000000..62e15fa --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt @@ -0,0 +1,30 @@ +package com.yessorae.data.source.network.polygon.model.chart + +import com.google.gson.annotations.SerializedName +import com.yessorae.data.common.toLocalDateTime +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.tick.TickUnit + +data class ChartDto( + val adjusted: Boolean, + val count: Int, + val queryCount: Int, + @SerializedName("request_id") + val requestId: String, + @SerializedName("results") + val ticks: List, + @SerializedName("resultsCount") + val ticksCount: Int, + val status: String, + val ticker: String +) + +fun ChartDto.asDomainModel(tickUnit: TickUnit): Chart { + return Chart( + tickerSymbol = ticker, + startDateTime = ticks.first().startTimestamp.toLocalDateTime(), + endDateTime = ticks.last().startTimestamp.toLocalDateTime(), + ticks = ticks.map(TickDto::asDomainModel), + tickUnit = tickUnit + ) +} \ No newline at end of file diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt new file mode 100644 index 0000000..d69326d --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt @@ -0,0 +1,36 @@ +package com.yessorae.data.source.network.polygon.model.chart + +import com.google.gson.annotations.SerializedName +import com.yessorae.data.common.toLocalDateTime +import com.yessorae.domain.entity.tick.Tick + +data class TickDto( // TODO SR-N 이름 수정 + @SerializedName("c") + val closePrice: Double, + @SerializedName("h") + val maxPrice: Double, + @SerializedName("l") + val minPrice: Double, + @SerializedName("n") + val transactionCount: Int, + @SerializedName("o") + val openPrice: Double, + @SerializedName("t") + // The Unix Msec timestamp for the start of the aggregate window. + val startTimestamp: Long, + @SerializedName("v") + val tradingVolume: Int, + @SerializedName("vw") + val volumeWeightedAveragePrice: Double +) + +internal fun TickDto.asDomainModel() = Tick( + openPrice = openPrice, + closePrice = closePrice, + maxPrice = maxPrice, + minPrice = minPrice, + transactionCount = transactionCount, + startTimestamp = startTimestamp.toLocalDateTime(), + tradingVolume = tradingVolume, + volumeWeightedAveragePrice = volumeWeightedAveragePrice +) From 1ab53351349abe8a9e92d59c60783e495af11a74 Mon Sep 17 00:00:00 2001 From: yessorae Date: Fri, 17 May 2024 21:54:46 +0900 Subject: [PATCH 07/47] [CT-4] chore: ktlintFormat --- .../yessorae/data/common/LocalDateTimeExt.kt | 2 +- .../yessorae/data/di/CommonNetworkModule.kt | 19 ++++++++------- .../com/yessorae/data/di/DataSourceModule.kt | 6 +++-- .../yessorae/data/di/PolygonNetworkModule.kt | 18 +++++++------- .../polygon/PolygonChartNetworkDataSource.kt | 5 ++-- .../network/polygon/api/PolygonChartApi.kt | 2 +- .../network/polygon/model/chart/ChartDto.kt | 2 +- .../network/polygon/model/chart/TickDto.kt | 24 +++++++++---------- presentation/build.gradle.kts | 2 -- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt b/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt index 653e808..0cc2190 100644 --- a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt +++ b/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt @@ -5,4 +5,4 @@ import java.time.ZoneOffset fun Long.toLocalDateTime(): LocalDateTime { return LocalDateTime.ofEpochSecond(this / 1000, 0, ZoneOffset.UTC) -} \ No newline at end of file +} diff --git a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt index 0ccb806..45f14f3 100644 --- a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt @@ -15,14 +15,15 @@ import javax.inject.Singleton object CommonNetworkModule { @Provides @Singleton - fun provideOkHttpCallFactory(): Call.Factory = OkHttpClient.Builder() - .addInterceptor( - HttpLoggingInterceptor() - .apply { - if (BuildConfig.DEBUG) { - setLevel(HttpLoggingInterceptor.Level.BODY) + fun provideOkHttpCallFactory(): Call.Factory = + OkHttpClient.Builder() + .addInterceptor( + HttpLoggingInterceptor() + .apply { + if (BuildConfig.DEBUG) { + setLevel(HttpLoggingInterceptor.Level.BODY) + } } - }, - ) - .build() + ) + .build() } diff --git a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt index 6004e0e..170f1d1 100644 --- a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt +++ b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt @@ -13,5 +13,7 @@ import javax.inject.Singleton abstract class DataSourceModule { @Binds @Singleton - abstract fun bindsChartNetworkDataSource(polygonChartNetworkDataSource: PolygonChartNetworkDataSource): ChartNetworkDataSource -} \ No newline at end of file + abstract fun bindsChartNetworkDataSource( + polygonChartNetworkDataSource: PolygonChartNetworkDataSource + ): ChartNetworkDataSource +} diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt index e87306d..e0cb4a6 100644 --- a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt @@ -32,17 +32,15 @@ import javax.inject.Singleton object PolygonNetworkModule { @Provides @Singleton - fun provideRetrofit( - okhttpCallFactory: Call.Factory - ): Retrofit = Retrofit.Builder() - .baseUrl(PolygonConstant.BASE_URL) - .callFactory(okhttpCallFactory) - .addConverterFactory(GsonConverterFactory.create()) - .build() + fun provideRetrofit(okhttpCallFactory: Call.Factory): Retrofit = + Retrofit.Builder() + .baseUrl(PolygonConstant.BASE_URL) + .callFactory(okhttpCallFactory) + .addConverterFactory(GsonConverterFactory.create()) + .build() @Provides @Singleton - fun provideChartApi( - retrofit: Retrofit - ): PolygonChartApi = retrofit.create(PolygonChartApi::class.java) + fun provideChartApi(retrofit: Retrofit): PolygonChartApi = + retrofit.create(PolygonChartApi::class.java) } diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt index c498381..9e68d8a 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt @@ -24,7 +24,8 @@ class PolygonChartNetworkDataSource @Inject constructor( timeSpan = tickUnit.toPathValue(), from = from, to = to - ).asDomainModel(tickUnit = tickUnit) + ) + .asDomainModel(tickUnit = tickUnit) } } @@ -33,4 +34,4 @@ private fun TickUnit.toPathValue(): String { TickUnit.DAY -> TIME_SPAN_DAY_PATH_VALUE TickUnit.HOUR -> TIME_SPAN_HOUR_PATH_VALUE } -} \ No newline at end of file +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt index 3128123..a843ad8 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/api/PolygonChartApi.kt @@ -29,4 +29,4 @@ interface PolygonChartApi { @Query(SORT_QUERY_KEY) sort: String = PolygonConstant.DEFAULT_SORT_QUERY_VALUE, @Query(API_KEY_QUERY_KEY) apiKey: String = BuildConfig.POLYGON_API_KEY ): ChartDto -} \ No newline at end of file +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt index 62e15fa..910b54a 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt @@ -27,4 +27,4 @@ fun ChartDto.asDomainModel(tickUnit: TickUnit): Chart { ticks = ticks.map(TickDto::asDomainModel), tickUnit = tickUnit ) -} \ No newline at end of file +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt index d69326d..998d7b3 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt @@ -4,7 +4,7 @@ import com.google.gson.annotations.SerializedName import com.yessorae.data.common.toLocalDateTime import com.yessorae.domain.entity.tick.Tick -data class TickDto( // TODO SR-N 이름 수정 +data class TickDto( @SerializedName("c") val closePrice: Double, @SerializedName("h") @@ -16,7 +16,6 @@ data class TickDto( // TODO SR-N 이름 수정 @SerializedName("o") val openPrice: Double, @SerializedName("t") - // The Unix Msec timestamp for the start of the aggregate window. val startTimestamp: Long, @SerializedName("v") val tradingVolume: Int, @@ -24,13 +23,14 @@ data class TickDto( // TODO SR-N 이름 수정 val volumeWeightedAveragePrice: Double ) -internal fun TickDto.asDomainModel() = Tick( - openPrice = openPrice, - closePrice = closePrice, - maxPrice = maxPrice, - minPrice = minPrice, - transactionCount = transactionCount, - startTimestamp = startTimestamp.toLocalDateTime(), - tradingVolume = tradingVolume, - volumeWeightedAveragePrice = volumeWeightedAveragePrice -) +internal fun TickDto.asDomainModel() = + Tick( + openPrice = openPrice, + closePrice = closePrice, + maxPrice = maxPrice, + minPrice = minPrice, + transactionCount = transactionCount, + startTimestamp = startTimestamp.toLocalDateTime(), + tradingVolume = tradingVolume, + volumeWeightedAveragePrice = volumeWeightedAveragePrice + ) diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts index 8e58a7f..a24633e 100644 --- a/presentation/build.gradle.kts +++ b/presentation/build.gradle.kts @@ -51,8 +51,6 @@ dependencies { implementation(Dependency.Common.HILT) kapt(Dependency.Common.HILT_COMPILER) - - implementation(Dependency.Compose.LIFECYCLE_RUNTIME) implementation(Dependency.Compose.ACTIVITY_COMPOSE) // 1.9.0 implementation(platform(Dependency.Compose.BOM)) From 69897baa0e6f1179fa53446d350b8b5c8f8dbad2 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 00:13:08 +0900 Subject: [PATCH 08/47] =?UTF-8?q?[CT-3-database]=20Room=20Database=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 5 +++++ data/build.gradle.kts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 23dd667..442c5c4 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -15,12 +15,17 @@ object Dependency { } object Data { + const val ROOM_RUNTIME = "androidx.room:room-runtime:${Version.ROOM}" + const val ROOM_COMPILER = "androidx.room:room-compiler:${Version.ROOM}" + const val ROOM_KAPT = "androidx.room:room-compiler:${Version.ROOM}" + const val ROOM_COROUTINE = "androidx.room:room-ktx:${Version.ROOM}" const val RETROFIT = "com.squareup.retrofit2:retrofit:${Version.RETROFIT}" const val RETROFIT_GSON_CONVERTER = "com.squareup.retrofit2:converter-gson:${Version.RETROFIT}" const val OK_HTTP_3 = "com.squareup.okhttp3:logging-interceptor:4.12.0" object Version { const val RETROFIT = "2.11.0" + const val ROOM = "2.6.1" } } diff --git a/data/build.gradle.kts b/data/build.gradle.kts index da6daaa..f961a53 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -60,6 +60,11 @@ android { dependencies { implementation(project(path = ":domain")) + implementation(Dependency.Data.ROOM_RUNTIME) + annotationProcessor(Dependency.Data.ROOM_COMPILER) + kapt(Dependency.Data.ROOM_KAPT) + implementation(Dependency.Data.ROOM_COROUTINE) + implementation(Dependency.Data.RETROFIT) implementation(Dependency.Data.RETROFIT_GSON_CONVERTER) implementation(Dependency.Data.OK_HTTP_3) From 5da6e04f403ea164c317bfd54108f6a36dd79f8a Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 00:20:55 +0900 Subject: [PATCH 09/47] =?UTF-8?q?[CT-3-database]=20Table=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../local/database/model/ChartGameTable.kt | 28 +++++++++++ .../source/local/database/model/ChartTable.kt | 36 ++++++++++++++ .../source/local/database/model/TickTable.kt | 49 +++++++++++++++++++ .../source/local/database/model/TradeTable.kt | 38 ++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt new file mode 100644 index 0000000..270feca --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt @@ -0,0 +1,28 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.value.Money + +data class ChartGameTable( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_CURRENT_TURN) + val currentTurn: Int, + @ColumnInfo(name = COL_TOTAL_TURN) + val totalTurn: Int, + @ColumnInfo(name = COL_START_BALANCE) + val startBalance: Money, + @ColumnInfo(name = COL_CURRENT_BALANCE) + val currentBalance: Money, + @ColumnInfo(name = COL_IS_QUIT) + val isQuit: Boolean +) { + companion object { + const val COL_CURRENT_TURN = "current_turn" + const val COL_TOTAL_TURN = "total_turn" + const val COL_START_BALANCE = "start_balance" + const val COL_CURRENT_BALANCE = "current_balance" + const val COL_IS_QUIT = "is_quit" + } +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt new file mode 100644 index 0000000..71b4cbb --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt @@ -0,0 +1,36 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.tick.Tick +import com.yessorae.domain.entity.tick.TickUnit +import java.time.LocalDateTime + +@Entity(tableName = ChartTable.NAME) +data class ChartTable( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_GAME_ID) + val gameId: Long, + @ColumnInfo(name = COL_TICKER_SYMBOL) + val tickerSymbol: String, + @ColumnInfo(name = COL_START_DATE_TIME) + val startDateTime: LocalDateTime, + @ColumnInfo(name = COL_END_DATE_TIME) + val endDateTime: LocalDateTime, + @ColumnInfo(name = COL_TICKS) + val ticks: List, + @ColumnInfo(name = COL_TICK_UNIT) + val tickUnit: TickUnit +) { + companion object { + const val NAME = "chart_table" + const val COL_GAME_ID = "game_id" + const val COL_TICKER_SYMBOL = "ticker_symbol" + const val COL_START_DATE_TIME = "start_date_time" + const val COL_END_DATE_TIME = "end_date_time" + const val COL_TICKS = "ticks" + const val COL_TICK_UNIT = "tick_unit" + } +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt new file mode 100644 index 0000000..df00886 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt @@ -0,0 +1,49 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import java.time.LocalDateTime + +@Entity( + tableName = TickTable.NAME, + primaryKeys = [ + TickTable.COL_GAME_ID, + TickTable.COL_CHART_ID + ] +) +data class TickTable( + @ColumnInfo(name = COL_GAME_ID) + val gameId: Long, + @ColumnInfo(name = COL_CHART_ID) + val chartId: Long, + @ColumnInfo(name = COL_OPEN_PRICE) + val openPrice: Double, + @ColumnInfo(name = COL_MAX_PRICE) + val maxPrice: Double, + @ColumnInfo(name = COL_MIN_PRICE) + val minPrice: Double, + @ColumnInfo(name = COL_CLOSE_PRICE) + val closePrice: Double, + @ColumnInfo(name = COL_TRANSACTION_COUNT) + val transactionCount: Int, + @ColumnInfo(name = COL_START_TIMESTAMP) + val startTimestamp: LocalDateTime, + @ColumnInfo(name = COL_TRADING_VOLUME) + val tradingVolume: Int, + @ColumnInfo(name = COL_VOLUME_WEIGHTED_AVERAGE_PRICE) + val volumeWeightedAveragePrice: Double +) { + companion object { + const val NAME = "table_tick" + const val COL_GAME_ID = "game_id" + const val COL_CHART_ID = "chart_id" + const val COL_OPEN_PRICE = "open_price" + const val COL_MAX_PRICE = "max_price" + const val COL_MIN_PRICE = "min_price" + const val COL_CLOSE_PRICE = "close_price" + const val COL_TRANSACTION_COUNT = "transaction_count" + const val COL_START_TIMESTAMP = "start_timestamp" + const val COL_TRADING_VOLUME = "trading_volume" + const val COL_VOLUME_WEIGHTED_AVERAGE_PRICE = "volume_weighted_average_price" + } +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt new file mode 100644 index 0000000..4667ff8 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt @@ -0,0 +1,38 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.trade.TradeType +import com.yessorae.domain.entity.value.Money + +@Entity(tableName = TradeTable.NAME) +data class TradeTable( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_GAME_ID) + val gameId: Long, + @ColumnInfo(name = COL_OWNED_AVERAGE_STOCK_PRICE) + val ownedAverageStockPrice: Money, + @ColumnInfo(name = COL_STOCK_PRICE) + val stockPrice: Money, + @ColumnInfo(name = COL_COUNT) + val count: Int, + @ColumnInfo(name = COL_TURN) + val turn: Int, + @ColumnInfo(name = COL_TYPE) + val type: TradeType, + @ColumnInfo(name = COL_COMMISSION_RATE) + val commissionRate: Double +) { + companion object { + const val NAME = "trade_table" + const val COL_GAME_ID = "game_id" + const val COL_OWNED_AVERAGE_STOCK_PRICE = "owned_average_price" + const val COL_STOCK_PRICE = "stock_price" + const val COL_COUNT = "count" + const val COL_TURN = "turn" + const val COL_TYPE = "type" + const val COL_COMMISSION_RATE = "commission_rate" + } +} From 31ad21a3255697e59586830a3c57efef838bac02 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 00:23:31 +0900 Subject: [PATCH 10/47] =?UTF-8?q?[CT-3-database]=20RoomDatabase=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/common/LocalDateTimeConverter.kt | 12 ++++++++++ .../yessorae/data/common/LocalDateTimeExt.kt | 4 ++++ .../com/yessorae/data/di/DatabaseModule.kt | 24 +++++++++++++++++++ .../local/database/ChartTrainerDatabase.kt | 24 +++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/common/LocalDateTimeConverter.kt create mode 100644 data/src/main/java/com/yessorae/data/di/DatabaseModule.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt diff --git a/data/src/main/java/com/yessorae/data/common/LocalDateTimeConverter.kt b/data/src/main/java/com/yessorae/data/common/LocalDateTimeConverter.kt new file mode 100644 index 0000000..dc2eac3 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/common/LocalDateTimeConverter.kt @@ -0,0 +1,12 @@ +package com.yessorae.data.common + +import androidx.room.TypeConverter +import java.time.LocalDateTime + +class LocalDateTimeConverter { + @TypeConverter + fun longToLocalDateTime(value: Long?): LocalDateTime? = value?.toLocalDateTime() + + @TypeConverter + fun localDateTimeToLong(instant: LocalDateTime?): Long? = instant?.toMilliSecond() +} diff --git a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt b/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt index 0cc2190..f9697ca 100644 --- a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt +++ b/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt @@ -3,6 +3,10 @@ package com.yessorae.data.common import java.time.LocalDateTime import java.time.ZoneOffset +fun LocalDateTime.toMilliSecond(): Long { + return this.toEpochSecond(ZoneOffset.UTC) * 1000 +} + fun Long.toLocalDateTime(): LocalDateTime { return LocalDateTime.ofEpochSecond(this / 1000, 0, ZoneOffset.UTC) } diff --git a/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt b/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt new file mode 100644 index 0000000..fb587d9 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt @@ -0,0 +1,24 @@ +package com.yessorae.data.di + +import android.content.Context +import androidx.room.Room +import com.yessorae.data.source.local.database.ChartTrainerDatabase +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 DatabaseModule { + @Provides + @Singleton + fun providesChartTrainerDatabase(@ApplicationContext context: Context): ChartTrainerDatabase = + Room.databaseBuilder( + context = context, + klass = ChartTrainerDatabase::class.java, + name = "chart-trainer-database" + ).build() +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt new file mode 100644 index 0000000..69bc1d2 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt @@ -0,0 +1,24 @@ +package com.yessorae.data.source.local.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import com.yessorae.data.common.LocalDateTimeConverter +import com.yessorae.data.source.local.database.model.ChartGameTable +import com.yessorae.data.source.local.database.model.ChartTable +import com.yessorae.data.source.local.database.model.TickTable +import com.yessorae.data.source.local.database.model.TradeTable + +@Database( + entities = [ + ChartGameTable::class, + ChartTable::class, + TickTable::class, + TradeTable::class + ], + version = 1 +) +@TypeConverters( + LocalDateTimeConverter::class +) +abstract class ChartTrainerDatabase : RoomDatabase() From f576d36a461a917c36b0fea0ba9f6f62be8161eb Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 00:25:06 +0900 Subject: [PATCH 11/47] =?UTF-8?q?[CT-3-database]=20Dao=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(Dao=20=EC=BF=BC=EB=A6=AC=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=EB=8A=94=20Repository=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EA=B3=BC=20=ED=95=A8=EA=BB=98=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yessorae/data/di/DaoModule.kt | 28 +++++++++++++++++++ .../local/database/ChartTrainerDatabase.kt | 11 +++++++- .../data/source/local/database/dao/BaseDao.kt | 20 +++++++++++++ .../source/local/database/dao/ChartDao.kt | 7 +++++ .../source/local/database/dao/ChartGameDao.kt | 23 +++++++++++++++ .../data/source/local/database/dao/TickDao.kt | 7 +++++ .../source/local/database/dao/TradeDao.kt | 7 +++++ 7 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 data/src/main/java/com/yessorae/data/di/DaoModule.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt diff --git a/data/src/main/java/com/yessorae/data/di/DaoModule.kt b/data/src/main/java/com/yessorae/data/di/DaoModule.kt new file mode 100644 index 0000000..28b4aa9 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/DaoModule.kt @@ -0,0 +1,28 @@ +package com.yessorae.data.di + +import com.yessorae.data.source.local.database.ChartTrainerDatabase +import com.yessorae.data.source.local.database.dao.ChartDao +import com.yessorae.data.source.local.database.dao.ChartGameDao +import com.yessorae.data.source.local.database.dao.TickDao +import com.yessorae.data.source.local.database.dao.TradeDao +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +object DaoModule { + @Provides + fun providesChartDao(database: ChartTrainerDatabase): ChartDao = database.getChartDao() + + @Provides + fun provideChartGameDao(database: ChartTrainerDatabase): ChartGameDao = + database.getChartGameDao() + + @Provides + fun provideTickDao(database: ChartTrainerDatabase): TickDao = database.getTickDao() + + @Provides + fun provideTradeDao(database: ChartTrainerDatabase): TradeDao = database.getTradeDao() +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt index 69bc1d2..b9f1e45 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt @@ -4,6 +4,10 @@ import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters import com.yessorae.data.common.LocalDateTimeConverter +import com.yessorae.data.source.local.database.dao.ChartDao +import com.yessorae.data.source.local.database.dao.ChartGameDao +import com.yessorae.data.source.local.database.dao.TickDao +import com.yessorae.data.source.local.database.dao.TradeDao import com.yessorae.data.source.local.database.model.ChartGameTable import com.yessorae.data.source.local.database.model.ChartTable import com.yessorae.data.source.local.database.model.TickTable @@ -21,4 +25,9 @@ import com.yessorae.data.source.local.database.model.TradeTable @TypeConverters( LocalDateTimeConverter::class ) -abstract class ChartTrainerDatabase : RoomDatabase() +abstract class ChartTrainerDatabase : RoomDatabase() { + abstract fun getChartDao(): ChartDao + abstract fun getChartGameDao(): ChartGameDao + abstract fun getTickDao(): TickDao + abstract fun getTradeDao(): TradeDao +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt new file mode 100644 index 0000000..80e3fc5 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt @@ -0,0 +1,20 @@ +package com.yessorae.data.source.local.database.dao + +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Update + +interface BaseDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAll(entities: List) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(entity: T): Long + + @Update + suspend fun update(entity: T) + + @Delete + suspend fun delete(entity: T) +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt new file mode 100644 index 0000000..5352eb5 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt @@ -0,0 +1,7 @@ +package com.yessorae.data.source.local.database.dao + +import androidx.room.Dao +import com.yessorae.data.source.local.database.model.ChartTable + +@Dao +interface ChartDao : BaseDao diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt new file mode 100644 index 0000000..fe5d26a --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.yessorae.data.source.local.database.dao + +import androidx.room.Dao +import com.yessorae.data.source.local.database.model.ChartGameTable + +@Dao +interface ChartGameDao : BaseDao diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt new file mode 100644 index 0000000..1987b6a --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt @@ -0,0 +1,7 @@ +package com.yessorae.data.source.local.database.dao + +import androidx.room.Dao +import com.yessorae.data.source.local.database.model.TickTable + +@Dao +interface TickDao : BaseDao diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt new file mode 100644 index 0000000..62a2025 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt @@ -0,0 +1,7 @@ +package com.yessorae.data.source.local.database.dao + +import androidx.room.Dao +import com.yessorae.data.source.local.database.model.TradeTable + +@Dao +interface TradeDao : BaseDao From 566c103a4171b4ca47c37e0380337ff30b4d819b Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 12:07:00 +0900 Subject: [PATCH 12/47] =?UTF-8?q?[CT-3-database]=20ChartGameTable=20?= =?UTF-8?q?=EC=97=90=20Entity=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EB=88=84=EB=9D=BD=EB=90=9C=20=EA=B2=83=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20asDto=20=EB=A7=B5=ED=95=91=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source/local/database/model/ChartGameTable.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt index 270feca..fd1bfb7 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt @@ -1,9 +1,12 @@ package com.yessorae.data.source.local.database.model import androidx.room.ColumnInfo +import androidx.room.Entity import androidx.room.PrimaryKey +import com.yessorae.domain.entity.ChartGame import com.yessorae.domain.entity.value.Money +@Entity(ChartGameTable.NAME) data class ChartGameTable( @PrimaryKey(autoGenerate = true) val id: Long, @@ -19,6 +22,7 @@ data class ChartGameTable( val isQuit: Boolean ) { companion object { + const val NAME = "chart_game_table" const val COL_CURRENT_TURN = "current_turn" const val COL_TOTAL_TURN = "total_turn" const val COL_START_BALANCE = "start_balance" @@ -26,3 +30,12 @@ data class ChartGameTable( const val COL_IS_QUIT = "is_quit" } } + +fun ChartGame.asDto() = ChartGameTable( + id = id, + currentTurn = currentTurn, + totalTurn = totalTurn, + startBalance = startBalance, + currentBalance = currentBalance, + isQuit = isQuit +) From 6747d33dec4d607ee718fc70c3dae64fafd54312 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 21:35:09 +0900 Subject: [PATCH 13/47] =?UTF-8?q?[CT-17]=20refactor:=20common=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=A6=84=EB=B3=80=EA=B2=BD,=20?= =?UTF-8?q?=ED=9E=90=ED=8A=B8=EB=AA=A8=EB=93=88=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=EB=B3=80=EA=B2=BD,=20ktlintFormat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/yessorae/data/di/CommonNetworkModule.kt | 2 +- .../di/{DataSourceModule.kt => NetworkDataSourceModule.kt} | 2 +- .../main/java/com/yessorae/data/di/PolygonNetworkModule.kt | 2 +- .../yessorae/data/source/network/ChartNetworkDataSource.kt | 4 ++-- .../source/network/polygon/PolygonChartNetworkDataSource.kt | 6 ++---- .../data/source/network/polygon/model/chart/ChartDto.kt | 2 +- .../data/source/network/polygon/model/chart/TickDto.kt | 2 +- .../com/yessorae/data/{common => util}/LocalDateTimeExt.kt | 2 +- 8 files changed, 10 insertions(+), 12 deletions(-) rename data/src/main/java/com/yessorae/data/di/{DataSourceModule.kt => NetworkDataSourceModule.kt} (92%) rename data/src/main/java/com/yessorae/data/{common => util}/LocalDateTimeExt.kt (84%) diff --git a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt index 45f14f3..ff46175 100644 --- a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt @@ -5,10 +5,10 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) diff --git a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt similarity index 92% rename from data/src/main/java/com/yessorae/data/di/DataSourceModule.kt rename to data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt index 170f1d1..e1886f6 100644 --- a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt +++ b/data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt @@ -10,7 +10,7 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -abstract class DataSourceModule { +abstract class NetworkDataSourceModule { @Binds @Singleton abstract fun bindsChartNetworkDataSource( diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt index e0cb4a6..f5e5a4d 100644 --- a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt @@ -22,10 +22,10 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton import okhttp3.Call import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory -import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) diff --git a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt index 43820f8..876ab1a 100644 --- a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt @@ -1,6 +1,6 @@ package com.yessorae.data.source.network -import com.yessorae.domain.entity.Chart +import com.yessorae.data.source.network.polygon.model.chart.ChartDto import com.yessorae.domain.entity.tick.TickUnit interface ChartNetworkDataSource { @@ -9,5 +9,5 @@ interface ChartNetworkDataSource { tickUnit: TickUnit, from: String, to: String - ): Chart + ): ChartDto } diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt index 9e68d8a..cb30c77 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt @@ -4,8 +4,7 @@ import com.yessorae.data.source.network.ChartNetworkDataSource import com.yessorae.data.source.network.polygon.api.PolygonChartApi import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_DAY_PATH_VALUE import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_HOUR_PATH_VALUE -import com.yessorae.data.source.network.polygon.model.chart.asDomainModel -import com.yessorae.domain.entity.Chart +import com.yessorae.data.source.network.polygon.model.chart.ChartDto import com.yessorae.domain.entity.tick.TickUnit import javax.inject.Inject @@ -17,7 +16,7 @@ class PolygonChartNetworkDataSource @Inject constructor( tickUnit: TickUnit, from: String, to: String - ): Chart { + ): ChartDto { return api .getChartData( ticker = ticker, @@ -25,7 +24,6 @@ class PolygonChartNetworkDataSource @Inject constructor( from = from, to = to ) - .asDomainModel(tickUnit = tickUnit) } } diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt index 910b54a..122d49f 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt @@ -1,7 +1,7 @@ package com.yessorae.data.source.network.polygon.model.chart import com.google.gson.annotations.SerializedName -import com.yessorae.data.common.toLocalDateTime +import com.yessorae.data.util.toLocalDateTime import com.yessorae.domain.entity.Chart import com.yessorae.domain.entity.tick.TickUnit diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt index 998d7b3..35c50dd 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt @@ -1,7 +1,7 @@ package com.yessorae.data.source.network.polygon.model.chart import com.google.gson.annotations.SerializedName -import com.yessorae.data.common.toLocalDateTime +import com.yessorae.data.util.toLocalDateTime import com.yessorae.domain.entity.tick.Tick data class TickDto( diff --git a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt b/data/src/main/java/com/yessorae/data/util/LocalDateTimeExt.kt similarity index 84% rename from data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt rename to data/src/main/java/com/yessorae/data/util/LocalDateTimeExt.kt index 0cc2190..35efeeb 100644 --- a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt +++ b/data/src/main/java/com/yessorae/data/util/LocalDateTimeExt.kt @@ -1,4 +1,4 @@ -package com.yessorae.data.common +package com.yessorae.data.util import java.time.LocalDateTime import java.time.ZoneOffset From 4d317dc8cf3e831bbaacf43b42fa79a8ab490397 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 21:35:09 +0900 Subject: [PATCH 14/47] =?UTF-8?q?[CT-3]=20refactor:=20common=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=A6=84=EB=B3=80=EA=B2=BD,=20?= =?UTF-8?q?=ED=9E=90=ED=8A=B8=EB=AA=A8=EB=93=88=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=EB=B3=80=EA=B2=BD,=20ktlintFormat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/yessorae/data/di/CommonNetworkModule.kt | 2 +- .../di/{DataSourceModule.kt => NetworkDataSourceModule.kt} | 2 +- .../main/java/com/yessorae/data/di/PolygonNetworkModule.kt | 2 +- .../yessorae/data/source/network/ChartNetworkDataSource.kt | 4 ++-- .../source/network/polygon/PolygonChartNetworkDataSource.kt | 6 ++---- .../data/source/network/polygon/model/chart/ChartDto.kt | 2 +- .../data/source/network/polygon/model/chart/TickDto.kt | 2 +- .../com/yessorae/data/{common => util}/LocalDateTimeExt.kt | 2 +- 8 files changed, 10 insertions(+), 12 deletions(-) rename data/src/main/java/com/yessorae/data/di/{DataSourceModule.kt => NetworkDataSourceModule.kt} (92%) rename data/src/main/java/com/yessorae/data/{common => util}/LocalDateTimeExt.kt (84%) diff --git a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt index 45f14f3..ff46175 100644 --- a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt @@ -5,10 +5,10 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) diff --git a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt similarity index 92% rename from data/src/main/java/com/yessorae/data/di/DataSourceModule.kt rename to data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt index 170f1d1..e1886f6 100644 --- a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt +++ b/data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt @@ -10,7 +10,7 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -abstract class DataSourceModule { +abstract class NetworkDataSourceModule { @Binds @Singleton abstract fun bindsChartNetworkDataSource( diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt index e0cb4a6..f5e5a4d 100644 --- a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt @@ -22,10 +22,10 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton import okhttp3.Call import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory -import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) diff --git a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt index 43820f8..876ab1a 100644 --- a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt @@ -1,6 +1,6 @@ package com.yessorae.data.source.network -import com.yessorae.domain.entity.Chart +import com.yessorae.data.source.network.polygon.model.chart.ChartDto import com.yessorae.domain.entity.tick.TickUnit interface ChartNetworkDataSource { @@ -9,5 +9,5 @@ interface ChartNetworkDataSource { tickUnit: TickUnit, from: String, to: String - ): Chart + ): ChartDto } diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt index 9e68d8a..cb30c77 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt @@ -4,8 +4,7 @@ import com.yessorae.data.source.network.ChartNetworkDataSource import com.yessorae.data.source.network.polygon.api.PolygonChartApi import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_DAY_PATH_VALUE import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_HOUR_PATH_VALUE -import com.yessorae.data.source.network.polygon.model.chart.asDomainModel -import com.yessorae.domain.entity.Chart +import com.yessorae.data.source.network.polygon.model.chart.ChartDto import com.yessorae.domain.entity.tick.TickUnit import javax.inject.Inject @@ -17,7 +16,7 @@ class PolygonChartNetworkDataSource @Inject constructor( tickUnit: TickUnit, from: String, to: String - ): Chart { + ): ChartDto { return api .getChartData( ticker = ticker, @@ -25,7 +24,6 @@ class PolygonChartNetworkDataSource @Inject constructor( from = from, to = to ) - .asDomainModel(tickUnit = tickUnit) } } diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt index 910b54a..122d49f 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/ChartDto.kt @@ -1,7 +1,7 @@ package com.yessorae.data.source.network.polygon.model.chart import com.google.gson.annotations.SerializedName -import com.yessorae.data.common.toLocalDateTime +import com.yessorae.data.util.toLocalDateTime import com.yessorae.domain.entity.Chart import com.yessorae.domain.entity.tick.TickUnit diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt index 998d7b3..35c50dd 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt @@ -1,7 +1,7 @@ package com.yessorae.data.source.network.polygon.model.chart import com.google.gson.annotations.SerializedName -import com.yessorae.data.common.toLocalDateTime +import com.yessorae.data.util.toLocalDateTime import com.yessorae.domain.entity.tick.Tick data class TickDto( diff --git a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt b/data/src/main/java/com/yessorae/data/util/LocalDateTimeExt.kt similarity index 84% rename from data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt rename to data/src/main/java/com/yessorae/data/util/LocalDateTimeExt.kt index 0cc2190..35efeeb 100644 --- a/data/src/main/java/com/yessorae/data/common/LocalDateTimeExt.kt +++ b/data/src/main/java/com/yessorae/data/util/LocalDateTimeExt.kt @@ -1,4 +1,4 @@ -package com.yessorae.data.common +package com.yessorae.data.util import java.time.LocalDateTime import java.time.ZoneOffset From 660bff1f758eda821898229c4ce6f189c75080ae Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 21:49:39 +0900 Subject: [PATCH 15/47] =?UTF-8?q?[CT-3]=20=EC=B0=A8=ED=8A=B8=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=9D=B8=EC=9E=90=20=EB=A7=8C=EB=93=A4=EC=96=B4?= =?UTF-8?q?=EC=A3=BC=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20UtilModule.kt=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yessorae/data/di/UtilModule.kt | 19 +++++ .../util/DefaultChartRequestArgumentHelper.kt | 75 +++++++++++++++++++ .../common/ChartRequestArgumentHelper.kt | 7 ++ 3 files changed, 101 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/di/UtilModule.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/util/DefaultChartRequestArgumentHelper.kt create mode 100644 domain/src/main/java/com/yessorae/domain/common/ChartRequestArgumentHelper.kt diff --git a/data/src/main/java/com/yessorae/data/di/UtilModule.kt b/data/src/main/java/com/yessorae/data/di/UtilModule.kt new file mode 100644 index 0000000..3d4674f --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/UtilModule.kt @@ -0,0 +1,19 @@ +package com.yessorae.data.di + +import com.yessorae.data.source.network.polygon.util.DefaultChartRequestArgumentHelper +import com.yessorae.domain.common.ChartRequestArgumentHelper +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class UtilModule { + @Binds + @Singleton + abstract fun bindsRandomChartArgumentGenerator( + defaultRandomChartArgumentGenerator: DefaultChartRequestArgumentHelper + ): ChartRequestArgumentHelper +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/util/DefaultChartRequestArgumentHelper.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/util/DefaultChartRequestArgumentHelper.kt new file mode 100644 index 0000000..9d7cb53 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/util/DefaultChartRequestArgumentHelper.kt @@ -0,0 +1,75 @@ +package com.yessorae.data.source.network.polygon.util + +import com.yessorae.domain.common.ChartRequestArgumentHelper +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import javax.inject.Inject + +class DefaultChartRequestArgumentHelper @Inject constructor() : ChartRequestArgumentHelper { + // The full set should be 500 tickers + private val tickers: Set by lazy { + setOf( + "AAPL", "MSFT", "GOOGL", "AMZN", "META", "BRK.B", "JNJ", "V", "PG", "NVDA", + "JPM", "UNH", "HD", "DIS", "MA", "PYPL", "NFLX", "ADBE", "INTC", "CMCSA", + "XOM", "KO", "PFE", "CSCO", "T", "PEP", "ABBV", "MRK", "AVGO", "WMT", + "MCD", "CVX", "CRM", "ABT", "ACN", "MDT", "QCOM", "NEE", "LLY", "NKE", + "TXN", "PM", "ORCL", "BA", "IBM", "HON", "COST", "WFC", "UNP", "AMGN", + "DHR", "LIN", "MMM", "LOW", "SPGI", "CAT", "TMO", "AXP", "GS", "MS", + "GE", "LMT", "NOW", "BLK", "RTX", "ELV", "ISRG", "BKNG", "ADP", "GILD", + "SCHW", "MDLZ", "INTU", "FIS", "CHTR", "CB", "SYK", "ZTS", "PLD", "LRCX", + "DUK", "CI", "APD", "MU", "SO", "MMC", "CME", "CCI", "ICE", "ECL", + "NSC", "GM", "SBUX", "ETN", "D", "ITW", "DE", "EW", "BDX", "MCO", + "SPG", "BSX", "TEL", "ROP", "TRV", "AON", "MET", "USB", "PNC", "WM", + "AEP", "TGT", "ADSK", "NOC", "NSC", "FDX", "CL", "MNST", "KDP", "EOG", + "F", "C", "VRTX", "CSX", "AFL", "PSA", "ADI", "MRNA", "IDXX", "IQV", + "CTAS", "KLAC", "APH", "NXPI", "EXC", "KHC", "APH", "STZ", "DG", "JCI", + "ALL", "ILMN", "SRE", "ADSK", "ROP", "CDNS", "MCHP", "ORLY", "ANET", "TT", + "OXY", "PXD", "DVN", "FANG", "CTRA", "FTNT", "TSLA", "PAYC", "CTLT", "AVB", + "DLR", "ARE", "O", "SBAC", "AMT", "CCI", "EXR", "PSA", "RMD", "CSGP", + "PPL", "PEG", "ED", "XEL", "ES", "WEC", "EIX", "AEE", "LNT", "AEP", + "FE", "NI", "CMS", "DTE", "ETR", "EVRG", "PNW", "SO", "D", "EXC", + "MHK", "BWA", "LEG", "FBHS", "MAS", "PH", "ROK", "SWK", "EMR", "ETN", + "HWM", "JCI", "LII", "MMM", "IR", "CMI", "DOV", "FLS", "GWW", "XYL", + "AOS", "BKR", "BA", "LMT", "GD", "NOC", "RTX", "HII", "TDG", "TXT", + "LHX", "AME", "HON", "RSG", "WM", "NUE", "STLD", "X", "AKS", "MT", + "FCX", "AA", "CENX", "STLD", "ATI", "SLGN", "PKG", "IP", "WRK", "SEE", + "SON", "AVY", "BMS", "NLSN", "GPC", "AAP", "AZO", "ORLY", "SIG", "TIF", + "BBY", "BBWI", "KSS", "M", "JWN", "RL", "GPS", "ANF", "URBN", "LB", + "TGT", "WMT", "COST", "DG", "DLTR", "BBBY", "CVS", "WBA", "RAD", "GME", + "PLCE", "EXPE", "BKNG", "CCL", "RCL", "NCLH", "MAR", "HLT", "H", "WH", + "PK", "APLE", "DRH", "HST", "XOM", "CVX", "COP", "OXY", "PXD", "MPC", + "VLO", "PSX", "HES", "MRO", "HFC", "DVN", "APA", "CLR", "FANG", "CXO", + "EOG", "PBF", "HFC", "XEC", "MUR", "WES", "OKE", "KMI", "WMB", "EPD", + "ENB", "ET", "PAGP", "TRGP", "MPLX", "ONEOK", "CEQP", "MMP", "AMLP", "GEL", + "GLOP", "HMLP", "KNOP", "CQP", "USAC", "NS", "NGL", "DCP", "PAA", "SUN", + "HEP", "BPMP", "SHLX", "ENBL", "CPG", "ERF", "CVE", "CNQ", "IMO", "SU", + "AR", "COG", "CHK", "EQT", "MTDR", "RRC", "SWN", "APA", "DVN", "MRO", + "CVE", "XOM", "PXD", "APA", "FANG", "CLR", "MTDR", "PAA", "MMP", "ENB", + "ET", "BPMP", "AMLP", "EPD", "GEL", "GLOP", "HMLP", "KNOP", "CQP", "USAC", + "NS", "NGL", "DCP", "PAA", "SUN", "HEP", "BPMP", "SHLX", "ENBL", "CEQP" + ) + } + + override fun getRandomTicker(): String { + return tickers.random() + } + + override fun getStartDate(): String { + return LocalDate.now() + .minusDays(1) + .convertToString() + } + + override fun getEndDate(): String { + return LocalDate.now() + .minusDays(1) + .minusYears(1) + .minusMonths(6) + .convertToString() + } + + private fun LocalDate.convertToString(): String { + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + return this.format(formatter) + } +} diff --git a/domain/src/main/java/com/yessorae/domain/common/ChartRequestArgumentHelper.kt b/domain/src/main/java/com/yessorae/domain/common/ChartRequestArgumentHelper.kt new file mode 100644 index 0000000..f66bbe5 --- /dev/null +++ b/domain/src/main/java/com/yessorae/domain/common/ChartRequestArgumentHelper.kt @@ -0,0 +1,7 @@ +package com.yessorae.domain.common + +interface ChartRequestArgumentHelper { + fun getRandomTicker(): String + fun getStartDate(): String + fun getEndDate(): String +} From 8a3b9f442a5fd5b373e0aaa4b0d5485af9f730d1 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:04:20 +0900 Subject: [PATCH 16/47] =?UTF-8?q?[CT-3-local]=20Room=20Database=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20(Database,=20Entity,?= =?UTF-8?q?=20Dao,=20Converter)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../local/database/ChartTrainerDatabase.kt | 18 ++++-- .../converter}/LocalDateTimeConverter.kt | 4 +- .../database/converter/MoneyConverter.kt | 12 ++++ .../data/source/local/database/dao/BaseDao.kt | 10 +++ .../source/local/database/dao/ChartDao.kt | 12 +++- .../source/local/database/dao/ChartGameDao.kt | 20 +++++- .../data/source/local/database/dao/TickDao.kt | 12 +++- .../source/local/database/dao/TradeDao.kt | 20 +++++- .../local/database/model/ChartEntity.kt | 50 +++++++++++++++ .../local/database/model/ChartGameEntity.kt | 62 ++++++++++++++++++ .../source/local/database/model/TickEntity.kt | 57 +++++++++++++++++ .../local/database/model/TradeEntity.kt | 63 +++++++++++++++++++ 12 files changed, 325 insertions(+), 15 deletions(-) rename data/src/main/java/com/yessorae/data/{util => source/local/database/converter}/LocalDateTimeConverter.kt (67%) create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt index b9f1e45..24ab547 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt @@ -3,27 +3,33 @@ package com.yessorae.data.source.local.database import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters -import com.yessorae.data.common.LocalDateTimeConverter +import com.yessorae.data.source.local.database.converter.LocalDateTimeConverter +import com.yessorae.data.source.local.database.converter.MoneyConverter import com.yessorae.data.source.local.database.dao.ChartDao import com.yessorae.data.source.local.database.dao.ChartGameDao import com.yessorae.data.source.local.database.dao.TickDao import com.yessorae.data.source.local.database.dao.TradeDao +import com.yessorae.data.source.local.database.model.ChartEntity +import com.yessorae.data.source.local.database.model.ChartGameEntity import com.yessorae.data.source.local.database.model.ChartGameTable import com.yessorae.data.source.local.database.model.ChartTable +import com.yessorae.data.source.local.database.model.TickEntity import com.yessorae.data.source.local.database.model.TickTable +import com.yessorae.data.source.local.database.model.TradeEntity import com.yessorae.data.source.local.database.model.TradeTable @Database( entities = [ - ChartGameTable::class, - ChartTable::class, - TickTable::class, - TradeTable::class + ChartGameEntity::class, + ChartEntity::class, + TickEntity::class, + TradeEntity::class ], version = 1 ) @TypeConverters( - LocalDateTimeConverter::class + LocalDateTimeConverter::class, + MoneyConverter::class ) abstract class ChartTrainerDatabase : RoomDatabase() { abstract fun getChartDao(): ChartDao diff --git a/data/src/main/java/com/yessorae/data/util/LocalDateTimeConverter.kt b/data/src/main/java/com/yessorae/data/source/local/database/converter/LocalDateTimeConverter.kt similarity index 67% rename from data/src/main/java/com/yessorae/data/util/LocalDateTimeConverter.kt rename to data/src/main/java/com/yessorae/data/source/local/database/converter/LocalDateTimeConverter.kt index dc2eac3..4377369 100644 --- a/data/src/main/java/com/yessorae/data/util/LocalDateTimeConverter.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/converter/LocalDateTimeConverter.kt @@ -1,6 +1,8 @@ -package com.yessorae.data.common +package com.yessorae.data.source.local.database.converter import androidx.room.TypeConverter +import com.yessorae.data.util.toLocalDateTime +import com.yessorae.data.util.toMilliSecond import java.time.LocalDateTime class LocalDateTimeConverter { diff --git a/data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt b/data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt new file mode 100644 index 0000000..3da5943 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt @@ -0,0 +1,12 @@ +package com.yessorae.data.source.local.database.converter + +import androidx.room.TypeConverter +import com.yessorae.domain.entity.value.Money + +class MoneyConverter { + @TypeConverter + fun valueToMoney(value: Double?): Money? = value?.let { Money(it) } + + @TypeConverter + fun moneyToValue(money: Money?): Double? = money?.value +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt index 80e3fc5..2852e85 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt @@ -4,6 +4,7 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Update +import androidx.room.Upsert interface BaseDao { @Insert(onConflict = OnConflictStrategy.REPLACE) @@ -12,9 +13,18 @@ interface BaseDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(entity: T): Long + @Update + suspend fun updateAll(entities: List) + @Update suspend fun update(entity: T) + @Upsert + suspend fun insertOrReplaceAll(entities: List) + + @Upsert + suspend fun insertOrReplace(entity: T) + @Delete suspend fun delete(entity: T) } diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt index 5352eb5..b2fe144 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt @@ -1,7 +1,15 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.ChartTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.ChartEntity @Dao -interface ChartDao : BaseDao +interface ChartDao : BaseDao { + @Query( + """ + SELECT * FROM ${ChartEntity.NAME} WHERE id = :id + """ + ) + suspend fun getChart(id: Long): ChartEntity +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt index fe5d26a..3401277 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt @@ -17,7 +17,23 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.ChartGameTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.ChartGameEntity +import kotlinx.coroutines.flow.Flow @Dao -interface ChartGameDao : BaseDao +interface ChartGameDao : BaseDao { + @Query( + """ + SELECT * from ${ChartGameEntity.NAME} WHERE id = (:id) + """ + ) + fun getChartGameAsFlow(id: Long): Flow + + @Query( + """ + SELECT * from ${ChartGameEntity.NAME} WHERE id = (:id) + """ + ) + suspend fun getChartGame(id: Long): ChartGameEntity +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt index 1987b6a..56e709b 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt @@ -1,7 +1,15 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.TickTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.TickEntity @Dao -interface TickDao : BaseDao +interface TickDao : BaseDao { + @Query( + """ + SELECT * FROM ${TickEntity.NAME} WHERE ${TickEntity.COL_CHART_ID} = :chartId + """ + ) + suspend fun getTicks(chartId: Long): List +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt index 62a2025..c12b131 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt @@ -1,7 +1,23 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.TradeTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.TradeEntity +import kotlinx.coroutines.flow.Flow @Dao -interface TradeDao : BaseDao +interface TradeDao : BaseDao { + @Query( + """ + SELECT * FROM ${TradeEntity.NAME} WHERE ${TradeEntity.COL_GAME_ID} = :gameId + """ + ) + fun getTradesAsFlow(gameId: Long): Flow> + + @Query( + """ + SELECT * FROM ${TradeEntity.NAME} WHERE ${TradeEntity.COL_GAME_ID} = :gameId + """ + ) + suspend fun getTrades(gameId: Long): List +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt new file mode 100644 index 0000000..581b274 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt @@ -0,0 +1,50 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.tick.Tick +import com.yessorae.domain.entity.tick.TickUnit +import java.time.LocalDateTime + +@Entity(tableName = ChartEntity.NAME) +data class ChartEntity( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_TICKER_SYMBOL) + val tickerSymbol: String, + @ColumnInfo(name = COL_START_DATE_TIME) + val startDateTime: LocalDateTime, + @ColumnInfo(name = COL_END_DATE_TIME) + val endDateTime: LocalDateTime, + @ColumnInfo(name = COL_TICK_UNIT) + val tickUnit: TickUnit +) { + companion object { + const val NAME = "chart_table" + const val COL_TICKER_SYMBOL = "ticker_symbol" + const val COL_START_DATE_TIME = "start_date_time" + const val COL_END_DATE_TIME = "end_date_time" + const val COL_TICK_UNIT = "tick_unit" + } +} + +fun Chart.asEntity() = + ChartEntity( + id = id, + tickerSymbol = tickerSymbol, + startDateTime = startDateTime, + endDateTime = endDateTime, + tickUnit = tickUnit + ) + +fun ChartEntity.asDomainModel(ticks: List) = + Chart( + id = id, + tickerSymbol = tickerSymbol, + startDateTime = startDateTime, + endDateTime = endDateTime, + ticks = ticks, + tickUnit = tickUnit + ) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt new file mode 100644 index 0000000..98285b0 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt @@ -0,0 +1,62 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.ChartGame +import com.yessorae.domain.entity.trade.Trade +import com.yessorae.domain.entity.value.Money + +@Entity(ChartGameEntity.NAME) +data class ChartGameEntity( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_CHART_ID) + val chartId: Long, + @ColumnInfo(name = COL_CURRENT_TURN) + val currentTurn: Int, + @ColumnInfo(name = COL_TOTAL_TURN) + val totalTurn: Int, + @ColumnInfo(name = COL_START_BALANCE) + val startBalance: Money, + @ColumnInfo(name = COL_CURRENT_BALANCE) + val currentBalance: Money, + @ColumnInfo(name = COL_IS_QUIT) + val isQuit: Boolean +) { + companion object { + const val NAME = "chart_game_table" + const val COL_CHART_ID = "chart_id" + const val COL_CURRENT_TURN = "current_turn" + const val COL_TOTAL_TURN = "total_turn" + const val COL_START_BALANCE = "start_balance" + const val COL_CURRENT_BALANCE = "current_balance" + const val COL_IS_QUIT = "is_quit" + } +} + +fun ChartGame.asEntity() = + ChartGameEntity( + id = id, + chartId = chart.id, + currentTurn = currentTurn, + totalTurn = totalTurn, + startBalance = startBalance, + currentBalance = currentBalance, + isQuit = isQuit + ) + +fun ChartGameEntity.asDomainModel( + chart: Chart, + trades: List +) = ChartGame( + id = id, + chart = chart, + trades = trades, + currentTurn = currentTurn, + totalTurn = totalTurn, + startBalance = startBalance, + currentBalance = currentBalance, + isQuit = isQuit +) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt new file mode 100644 index 0000000..2a7ea42 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt @@ -0,0 +1,57 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.tick.Tick +import java.time.LocalDateTime + +@Entity(tableName = TickEntity.NAME) +data class TickEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + @ColumnInfo(name = COL_CHART_ID) + val chartId: Long, + @ColumnInfo(name = COL_OPEN_PRICE) + val openPrice: Double, + @ColumnInfo(name = COL_MAX_PRICE) + val maxPrice: Double, + @ColumnInfo(name = COL_MIN_PRICE) + val minPrice: Double, + @ColumnInfo(name = COL_CLOSE_PRICE) + val closePrice: Double, + @ColumnInfo(name = COL_TRANSACTION_COUNT) + val transactionCount: Int, + @ColumnInfo(name = COL_START_TIMESTAMP) + val startTimestamp: LocalDateTime, + @ColumnInfo(name = COL_TRADING_VOLUME) + val tradingVolume: Int, + @ColumnInfo(name = COL_VOLUME_WEIGHTED_AVERAGE_PRICE) + val volumeWeightedAveragePrice: Double +) { + companion object { + const val NAME = "table_tick" + const val COL_GAME_ID = "game_id" + const val COL_CHART_ID = "chart_id" + const val COL_OPEN_PRICE = "open_price" + const val COL_MAX_PRICE = "max_price" + const val COL_MIN_PRICE = "min_price" + const val COL_CLOSE_PRICE = "close_price" + const val COL_TRANSACTION_COUNT = "transaction_count" + const val COL_START_TIMESTAMP = "start_timestamp" + const val COL_TRADING_VOLUME = "trading_volume" + const val COL_VOLUME_WEIGHTED_AVERAGE_PRICE = "volume_weighted_average_price" + } +} + +fun TickEntity.asDomainModel() = + Tick( + openPrice = openPrice, + maxPrice = maxPrice, + minPrice = minPrice, + closePrice = closePrice, + transactionCount = transactionCount, + startTimestamp = startTimestamp, + tradingVolume = tradingVolume, + volumeWeightedAveragePrice = volumeWeightedAveragePrice + ) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt new file mode 100644 index 0000000..7b00385 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt @@ -0,0 +1,63 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.trade.Trade +import com.yessorae.domain.entity.trade.TradeType +import com.yessorae.domain.entity.value.Money + +@Entity(tableName = TradeEntity.NAME) +data class TradeEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + @ColumnInfo(name = COL_GAME_ID) + val gameId: Long, + @ColumnInfo(name = COL_OWNED_AVERAGE_STOCK_PRICE) + val ownedAverageStockPrice: Money, + @ColumnInfo(name = COL_STOCK_PRICE) + val stockPrice: Money, + @ColumnInfo(name = COL_COUNT) + val count: Int, + @ColumnInfo(name = COL_TURN) + val turn: Int, + @ColumnInfo(name = COL_TYPE) + val type: TradeType, + @ColumnInfo(name = COL_COMMISSION_RATE) + val commissionRate: Double +) { + companion object { + const val NAME = "trade_table" + const val COL_GAME_ID = "game_id" + const val COL_OWNED_AVERAGE_STOCK_PRICE = "owned_average_price" + const val COL_STOCK_PRICE = "stock_price" + const val COL_COUNT = "count" + const val COL_TURN = "turn" + const val COL_TYPE = "type" + const val COL_COMMISSION_RATE = "commission_rate" + } +} + +fun Trade.asEntity() = + TradeEntity( + id = id, + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + stockPrice = stockPrice, + count = count, + turn = turn, + type = type, + commissionRate = commissionRate + ) + +fun TradeEntity.asDomainModel() = + Trade( + id = id, + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + stockPrice = stockPrice, + count = count, + turn = turn, + type = type, + commissionRate = commissionRate + ) From cdd3a14f4a2c11564147e34e7bc1abeb0c8d26d2 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:08:52 +0900 Subject: [PATCH 17/47] =?UTF-8?q?[CT-3-local]=20Room=20Database=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20(Database,=20Entity,?= =?UTF-8?q?=20Dao,=20Converter)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../local/database/ChartTrainerDatabase.kt | 18 ++++-- .../converter}/LocalDateTimeConverter.kt | 4 +- .../database/converter/MoneyConverter.kt | 12 ++++ .../data/source/local/database/dao/BaseDao.kt | 10 +++ .../source/local/database/dao/ChartDao.kt | 12 +++- .../source/local/database/dao/ChartGameDao.kt | 20 +++++- .../data/source/local/database/dao/TickDao.kt | 12 +++- .../source/local/database/dao/TradeDao.kt | 20 +++++- .../local/database/model/ChartEntity.kt | 50 +++++++++++++++ .../local/database/model/ChartGameEntity.kt | 62 ++++++++++++++++++ .../source/local/database/model/TickEntity.kt | 57 +++++++++++++++++ .../local/database/model/TradeEntity.kt | 63 +++++++++++++++++++ .../com/yessorae/domain/entity/trade/Trade.kt | 1 + 13 files changed, 326 insertions(+), 15 deletions(-) rename data/src/main/java/com/yessorae/data/{util => source/local/database/converter}/LocalDateTimeConverter.kt (67%) create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt index b9f1e45..24ab547 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt @@ -3,27 +3,33 @@ package com.yessorae.data.source.local.database import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters -import com.yessorae.data.common.LocalDateTimeConverter +import com.yessorae.data.source.local.database.converter.LocalDateTimeConverter +import com.yessorae.data.source.local.database.converter.MoneyConverter import com.yessorae.data.source.local.database.dao.ChartDao import com.yessorae.data.source.local.database.dao.ChartGameDao import com.yessorae.data.source.local.database.dao.TickDao import com.yessorae.data.source.local.database.dao.TradeDao +import com.yessorae.data.source.local.database.model.ChartEntity +import com.yessorae.data.source.local.database.model.ChartGameEntity import com.yessorae.data.source.local.database.model.ChartGameTable import com.yessorae.data.source.local.database.model.ChartTable +import com.yessorae.data.source.local.database.model.TickEntity import com.yessorae.data.source.local.database.model.TickTable +import com.yessorae.data.source.local.database.model.TradeEntity import com.yessorae.data.source.local.database.model.TradeTable @Database( entities = [ - ChartGameTable::class, - ChartTable::class, - TickTable::class, - TradeTable::class + ChartGameEntity::class, + ChartEntity::class, + TickEntity::class, + TradeEntity::class ], version = 1 ) @TypeConverters( - LocalDateTimeConverter::class + LocalDateTimeConverter::class, + MoneyConverter::class ) abstract class ChartTrainerDatabase : RoomDatabase() { abstract fun getChartDao(): ChartDao diff --git a/data/src/main/java/com/yessorae/data/util/LocalDateTimeConverter.kt b/data/src/main/java/com/yessorae/data/source/local/database/converter/LocalDateTimeConverter.kt similarity index 67% rename from data/src/main/java/com/yessorae/data/util/LocalDateTimeConverter.kt rename to data/src/main/java/com/yessorae/data/source/local/database/converter/LocalDateTimeConverter.kt index dc2eac3..4377369 100644 --- a/data/src/main/java/com/yessorae/data/util/LocalDateTimeConverter.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/converter/LocalDateTimeConverter.kt @@ -1,6 +1,8 @@ -package com.yessorae.data.common +package com.yessorae.data.source.local.database.converter import androidx.room.TypeConverter +import com.yessorae.data.util.toLocalDateTime +import com.yessorae.data.util.toMilliSecond import java.time.LocalDateTime class LocalDateTimeConverter { diff --git a/data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt b/data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt new file mode 100644 index 0000000..3da5943 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/converter/MoneyConverter.kt @@ -0,0 +1,12 @@ +package com.yessorae.data.source.local.database.converter + +import androidx.room.TypeConverter +import com.yessorae.domain.entity.value.Money + +class MoneyConverter { + @TypeConverter + fun valueToMoney(value: Double?): Money? = value?.let { Money(it) } + + @TypeConverter + fun moneyToValue(money: Money?): Double? = money?.value +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt index 80e3fc5..2852e85 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/BaseDao.kt @@ -4,6 +4,7 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Update +import androidx.room.Upsert interface BaseDao { @Insert(onConflict = OnConflictStrategy.REPLACE) @@ -12,9 +13,18 @@ interface BaseDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(entity: T): Long + @Update + suspend fun updateAll(entities: List) + @Update suspend fun update(entity: T) + @Upsert + suspend fun insertOrReplaceAll(entities: List) + + @Upsert + suspend fun insertOrReplace(entity: T) + @Delete suspend fun delete(entity: T) } diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt index 5352eb5..b2fe144 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt @@ -1,7 +1,15 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.ChartTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.ChartEntity @Dao -interface ChartDao : BaseDao +interface ChartDao : BaseDao { + @Query( + """ + SELECT * FROM ${ChartEntity.NAME} WHERE id = :id + """ + ) + suspend fun getChart(id: Long): ChartEntity +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt index fe5d26a..3401277 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt @@ -17,7 +17,23 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.ChartGameTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.ChartGameEntity +import kotlinx.coroutines.flow.Flow @Dao -interface ChartGameDao : BaseDao +interface ChartGameDao : BaseDao { + @Query( + """ + SELECT * from ${ChartGameEntity.NAME} WHERE id = (:id) + """ + ) + fun getChartGameAsFlow(id: Long): Flow + + @Query( + """ + SELECT * from ${ChartGameEntity.NAME} WHERE id = (:id) + """ + ) + suspend fun getChartGame(id: Long): ChartGameEntity +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt index 1987b6a..56e709b 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/TickDao.kt @@ -1,7 +1,15 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.TickTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.TickEntity @Dao -interface TickDao : BaseDao +interface TickDao : BaseDao { + @Query( + """ + SELECT * FROM ${TickEntity.NAME} WHERE ${TickEntity.COL_CHART_ID} = :chartId + """ + ) + suspend fun getTicks(chartId: Long): List +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt index 62a2025..c12b131 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/TradeDao.kt @@ -1,7 +1,23 @@ package com.yessorae.data.source.local.database.dao import androidx.room.Dao -import com.yessorae.data.source.local.database.model.TradeTable +import androidx.room.Query +import com.yessorae.data.source.local.database.model.TradeEntity +import kotlinx.coroutines.flow.Flow @Dao -interface TradeDao : BaseDao +interface TradeDao : BaseDao { + @Query( + """ + SELECT * FROM ${TradeEntity.NAME} WHERE ${TradeEntity.COL_GAME_ID} = :gameId + """ + ) + fun getTradesAsFlow(gameId: Long): Flow> + + @Query( + """ + SELECT * FROM ${TradeEntity.NAME} WHERE ${TradeEntity.COL_GAME_ID} = :gameId + """ + ) + suspend fun getTrades(gameId: Long): List +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt new file mode 100644 index 0000000..581b274 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartEntity.kt @@ -0,0 +1,50 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.tick.Tick +import com.yessorae.domain.entity.tick.TickUnit +import java.time.LocalDateTime + +@Entity(tableName = ChartEntity.NAME) +data class ChartEntity( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_TICKER_SYMBOL) + val tickerSymbol: String, + @ColumnInfo(name = COL_START_DATE_TIME) + val startDateTime: LocalDateTime, + @ColumnInfo(name = COL_END_DATE_TIME) + val endDateTime: LocalDateTime, + @ColumnInfo(name = COL_TICK_UNIT) + val tickUnit: TickUnit +) { + companion object { + const val NAME = "chart_table" + const val COL_TICKER_SYMBOL = "ticker_symbol" + const val COL_START_DATE_TIME = "start_date_time" + const val COL_END_DATE_TIME = "end_date_time" + const val COL_TICK_UNIT = "tick_unit" + } +} + +fun Chart.asEntity() = + ChartEntity( + id = id, + tickerSymbol = tickerSymbol, + startDateTime = startDateTime, + endDateTime = endDateTime, + tickUnit = tickUnit + ) + +fun ChartEntity.asDomainModel(ticks: List) = + Chart( + id = id, + tickerSymbol = tickerSymbol, + startDateTime = startDateTime, + endDateTime = endDateTime, + ticks = ticks, + tickUnit = tickUnit + ) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt new file mode 100644 index 0000000..98285b0 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameEntity.kt @@ -0,0 +1,62 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.ChartGame +import com.yessorae.domain.entity.trade.Trade +import com.yessorae.domain.entity.value.Money + +@Entity(ChartGameEntity.NAME) +data class ChartGameEntity( + @PrimaryKey(autoGenerate = true) + val id: Long, + @ColumnInfo(name = COL_CHART_ID) + val chartId: Long, + @ColumnInfo(name = COL_CURRENT_TURN) + val currentTurn: Int, + @ColumnInfo(name = COL_TOTAL_TURN) + val totalTurn: Int, + @ColumnInfo(name = COL_START_BALANCE) + val startBalance: Money, + @ColumnInfo(name = COL_CURRENT_BALANCE) + val currentBalance: Money, + @ColumnInfo(name = COL_IS_QUIT) + val isQuit: Boolean +) { + companion object { + const val NAME = "chart_game_table" + const val COL_CHART_ID = "chart_id" + const val COL_CURRENT_TURN = "current_turn" + const val COL_TOTAL_TURN = "total_turn" + const val COL_START_BALANCE = "start_balance" + const val COL_CURRENT_BALANCE = "current_balance" + const val COL_IS_QUIT = "is_quit" + } +} + +fun ChartGame.asEntity() = + ChartGameEntity( + id = id, + chartId = chart.id, + currentTurn = currentTurn, + totalTurn = totalTurn, + startBalance = startBalance, + currentBalance = currentBalance, + isQuit = isQuit + ) + +fun ChartGameEntity.asDomainModel( + chart: Chart, + trades: List +) = ChartGame( + id = id, + chart = chart, + trades = trades, + currentTurn = currentTurn, + totalTurn = totalTurn, + startBalance = startBalance, + currentBalance = currentBalance, + isQuit = isQuit +) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt new file mode 100644 index 0000000..2a7ea42 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt @@ -0,0 +1,57 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.tick.Tick +import java.time.LocalDateTime + +@Entity(tableName = TickEntity.NAME) +data class TickEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + @ColumnInfo(name = COL_CHART_ID) + val chartId: Long, + @ColumnInfo(name = COL_OPEN_PRICE) + val openPrice: Double, + @ColumnInfo(name = COL_MAX_PRICE) + val maxPrice: Double, + @ColumnInfo(name = COL_MIN_PRICE) + val minPrice: Double, + @ColumnInfo(name = COL_CLOSE_PRICE) + val closePrice: Double, + @ColumnInfo(name = COL_TRANSACTION_COUNT) + val transactionCount: Int, + @ColumnInfo(name = COL_START_TIMESTAMP) + val startTimestamp: LocalDateTime, + @ColumnInfo(name = COL_TRADING_VOLUME) + val tradingVolume: Int, + @ColumnInfo(name = COL_VOLUME_WEIGHTED_AVERAGE_PRICE) + val volumeWeightedAveragePrice: Double +) { + companion object { + const val NAME = "table_tick" + const val COL_GAME_ID = "game_id" + const val COL_CHART_ID = "chart_id" + const val COL_OPEN_PRICE = "open_price" + const val COL_MAX_PRICE = "max_price" + const val COL_MIN_PRICE = "min_price" + const val COL_CLOSE_PRICE = "close_price" + const val COL_TRANSACTION_COUNT = "transaction_count" + const val COL_START_TIMESTAMP = "start_timestamp" + const val COL_TRADING_VOLUME = "trading_volume" + const val COL_VOLUME_WEIGHTED_AVERAGE_PRICE = "volume_weighted_average_price" + } +} + +fun TickEntity.asDomainModel() = + Tick( + openPrice = openPrice, + maxPrice = maxPrice, + minPrice = minPrice, + closePrice = closePrice, + transactionCount = transactionCount, + startTimestamp = startTimestamp, + tradingVolume = tradingVolume, + volumeWeightedAveragePrice = volumeWeightedAveragePrice + ) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt new file mode 100644 index 0000000..7b00385 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeEntity.kt @@ -0,0 +1,63 @@ +package com.yessorae.data.source.local.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.yessorae.domain.entity.trade.Trade +import com.yessorae.domain.entity.trade.TradeType +import com.yessorae.domain.entity.value.Money + +@Entity(tableName = TradeEntity.NAME) +data class TradeEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + @ColumnInfo(name = COL_GAME_ID) + val gameId: Long, + @ColumnInfo(name = COL_OWNED_AVERAGE_STOCK_PRICE) + val ownedAverageStockPrice: Money, + @ColumnInfo(name = COL_STOCK_PRICE) + val stockPrice: Money, + @ColumnInfo(name = COL_COUNT) + val count: Int, + @ColumnInfo(name = COL_TURN) + val turn: Int, + @ColumnInfo(name = COL_TYPE) + val type: TradeType, + @ColumnInfo(name = COL_COMMISSION_RATE) + val commissionRate: Double +) { + companion object { + const val NAME = "trade_table" + const val COL_GAME_ID = "game_id" + const val COL_OWNED_AVERAGE_STOCK_PRICE = "owned_average_price" + const val COL_STOCK_PRICE = "stock_price" + const val COL_COUNT = "count" + const val COL_TURN = "turn" + const val COL_TYPE = "type" + const val COL_COMMISSION_RATE = "commission_rate" + } +} + +fun Trade.asEntity() = + TradeEntity( + id = id, + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + stockPrice = stockPrice, + count = count, + turn = turn, + type = type, + commissionRate = commissionRate + ) + +fun TradeEntity.asDomainModel() = + Trade( + id = id, + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + stockPrice = stockPrice, + count = count, + turn = turn, + type = type, + commissionRate = commissionRate + ) diff --git a/domain/src/main/java/com/yessorae/domain/entity/trade/Trade.kt b/domain/src/main/java/com/yessorae/domain/entity/trade/Trade.kt index 6ceaee2..3dd7bc2 100644 --- a/domain/src/main/java/com/yessorae/domain/entity/trade/Trade.kt +++ b/domain/src/main/java/com/yessorae/domain/entity/trade/Trade.kt @@ -3,6 +3,7 @@ package com.yessorae.domain.entity.trade import com.yessorae.domain.entity.value.Money data class Trade( + val id: Long = 0, // 차트게임 아이디 val gameId: Long, // 현재 가지고 있는 가격 From ea4fbfc5b034cf2bdd77a0f7bdbf96454fe62afa Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:09:12 +0900 Subject: [PATCH 18/47] =?UTF-8?q?[CT-3]=20datastore=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 2 ++ data/build.gradle.kts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 442c5c4..4cde560 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -15,6 +15,7 @@ object Dependency { } object Data { + const val DATA_STORE = "androidx.datastore:datastore-preferences:${Version.DATA_STORE}" const val ROOM_RUNTIME = "androidx.room:room-runtime:${Version.ROOM}" const val ROOM_COMPILER = "androidx.room:room-compiler:${Version.ROOM}" const val ROOM_KAPT = "androidx.room:room-compiler:${Version.ROOM}" @@ -24,6 +25,7 @@ object Dependency { const val OK_HTTP_3 = "com.squareup.okhttp3:logging-interceptor:4.12.0" object Version { + const val DATA_STORE = "1.1.1" const val RETROFIT = "2.11.0" const val ROOM = "2.6.1" } diff --git a/data/build.gradle.kts b/data/build.gradle.kts index f961a53..8234a67 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -60,6 +60,8 @@ android { dependencies { implementation(project(path = ":domain")) + implementation(Dependency.Data.DATA_STORE) + implementation(Dependency.Data.ROOM_RUNTIME) annotationProcessor(Dependency.Data.ROOM_COMPILER) kapt(Dependency.Data.ROOM_KAPT) From a5fc11f35b770935aa0cc1cb44891655abda11b6 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:10:52 +0900 Subject: [PATCH 19/47] =?UTF-8?q?[CT-3]=20ChartTrainerPreferencesDataSourc?= =?UTF-8?q?e=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/di/DataStoreModule.kt | 26 +++++++++ .../ChartTrainerPreferencesDataSource.kt | 56 +++++++++++++++++++ .../yessorae/domain/common/DefaultValues.kt | 10 ++++ 3 files changed, 92 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/di/DataStoreModule.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/preference/ChartTrainerPreferencesDataSource.kt create mode 100644 domain/src/main/java/com/yessorae/domain/common/DefaultValues.kt diff --git a/data/src/main/java/com/yessorae/data/di/DataStoreModule.kt b/data/src/main/java/com/yessorae/data/di/DataStoreModule.kt new file mode 100644 index 0000000..2f941dd --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/DataStoreModule.kt @@ -0,0 +1,26 @@ +package com.yessorae.data.di + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.preferencesDataStore +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 DataStoreModule { + private val Context.appDatastore: DataStore by preferencesDataStore( + name = "chart_trainer_app_preference" + ) + + @Provides + @Singleton + fun providesAppPreferencesDataStore( + @ApplicationContext context: Context + ): DataStore = context.appDatastore +} diff --git a/data/src/main/java/com/yessorae/data/source/local/preference/ChartTrainerPreferencesDataSource.kt b/data/src/main/java/com/yessorae/data/source/local/preference/ChartTrainerPreferencesDataSource.kt new file mode 100644 index 0000000..97c17da --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/preference/ChartTrainerPreferencesDataSource.kt @@ -0,0 +1,56 @@ +package com.yessorae.data.source.local.preference + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.doublePreferencesKey +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.stringPreferencesKey +import com.yessorae.domain.common.DefaultValues.DEFAULT_COMMISSION_RATE +import com.yessorae.domain.common.DefaultValues.DEFAULT_TOTAL_TURN +import com.yessorae.domain.common.DefaultValues.FIRST_CURRENT_BALANCE +import com.yessorae.domain.common.DefaultValues.defaultTickUnit +import com.yessorae.domain.entity.tick.TickUnit +import com.yessorae.domain.entity.value.Money +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.map + +class ChartTrainerPreferencesDataSource @Inject constructor( + private val appPreference: DataStore +) { + private val commissionRateKey = doublePreferencesKey("commission_rate") + private val totalTurnKey = intPreferencesKey("total_turn") + private val currentBalanceKey = doublePreferencesKey("current_balance") + private val tickUnitKey = stringPreferencesKey("tick_unit") + + private val data: Flow = appPreference.data + + val commissionRateFlow: Flow = data.map { preferences -> + preferences[commissionRateKey] ?: DEFAULT_COMMISSION_RATE + } + + val totalTurnFlow: Flow = data.map { preferences -> + preferences[totalTurnKey] ?: DEFAULT_TOTAL_TURN + } + + val currentBalanceFlow: Flow = data.map { preferences -> + Money(value = preferences[currentBalanceKey] ?: FIRST_CURRENT_BALANCE) + } + + val tickUnitFlow: Flow = data.map { preferences -> + preferences[tickUnitKey]?.let { value -> + TickUnit.valueOf(value) + } ?: defaultTickUnit + } + + suspend fun getCommissionRate(): Double = + commissionRateFlow.firstOrNull() ?: DEFAULT_COMMISSION_RATE + + suspend fun getTotalTurn(): Int = totalTurnFlow.firstOrNull() ?: DEFAULT_TOTAL_TURN + + suspend fun getCurrentBalance(): Money = + currentBalanceFlow.firstOrNull() ?: Money(FIRST_CURRENT_BALANCE) + + suspend fun getTickUnit(): TickUnit = tickUnitFlow.firstOrNull() ?: defaultTickUnit +} diff --git a/domain/src/main/java/com/yessorae/domain/common/DefaultValues.kt b/domain/src/main/java/com/yessorae/domain/common/DefaultValues.kt new file mode 100644 index 0000000..482b7cd --- /dev/null +++ b/domain/src/main/java/com/yessorae/domain/common/DefaultValues.kt @@ -0,0 +1,10 @@ +package com.yessorae.domain.common + +import com.yessorae.domain.entity.tick.TickUnit + +object DefaultValues { + const val DEFAULT_COMMISSION_RATE = 0.1 + const val DEFAULT_TOTAL_TURN = 50 + const val FIRST_CURRENT_BALANCE = 1000.0 + val defaultTickUnit = TickUnit.DAY +} From 3cf9c3dc8e14e3592507e28c9d25173c468a574e Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:22:38 +0900 Subject: [PATCH 20/47] =?UTF-8?q?[CT-3]=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../local/database/ChartTrainerDatabase.kt | 4 -- .../local/database/model/ChartGameTable.kt | 41 ---------------- .../source/local/database/model/ChartTable.kt | 36 -------------- .../source/local/database/model/TickTable.kt | 49 ------------------- .../source/local/database/model/TradeTable.kt | 38 -------------- 5 files changed, 168 deletions(-) delete mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt delete mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt delete mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt delete mode 100644 data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt index 24ab547..c3f0fb1 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt @@ -11,12 +11,8 @@ import com.yessorae.data.source.local.database.dao.TickDao import com.yessorae.data.source.local.database.dao.TradeDao import com.yessorae.data.source.local.database.model.ChartEntity import com.yessorae.data.source.local.database.model.ChartGameEntity -import com.yessorae.data.source.local.database.model.ChartGameTable -import com.yessorae.data.source.local.database.model.ChartTable import com.yessorae.data.source.local.database.model.TickEntity -import com.yessorae.data.source.local.database.model.TickTable import com.yessorae.data.source.local.database.model.TradeEntity -import com.yessorae.data.source.local.database.model.TradeTable @Database( entities = [ diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt deleted file mode 100644 index fd1bfb7..0000000 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartGameTable.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.yessorae.data.source.local.database.model - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.yessorae.domain.entity.ChartGame -import com.yessorae.domain.entity.value.Money - -@Entity(ChartGameTable.NAME) -data class ChartGameTable( - @PrimaryKey(autoGenerate = true) - val id: Long, - @ColumnInfo(name = COL_CURRENT_TURN) - val currentTurn: Int, - @ColumnInfo(name = COL_TOTAL_TURN) - val totalTurn: Int, - @ColumnInfo(name = COL_START_BALANCE) - val startBalance: Money, - @ColumnInfo(name = COL_CURRENT_BALANCE) - val currentBalance: Money, - @ColumnInfo(name = COL_IS_QUIT) - val isQuit: Boolean -) { - companion object { - const val NAME = "chart_game_table" - const val COL_CURRENT_TURN = "current_turn" - const val COL_TOTAL_TURN = "total_turn" - const val COL_START_BALANCE = "start_balance" - const val COL_CURRENT_BALANCE = "current_balance" - const val COL_IS_QUIT = "is_quit" - } -} - -fun ChartGame.asDto() = ChartGameTable( - id = id, - currentTurn = currentTurn, - totalTurn = totalTurn, - startBalance = startBalance, - currentBalance = currentBalance, - isQuit = isQuit -) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt deleted file mode 100644 index 71b4cbb..0000000 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/ChartTable.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.yessorae.data.source.local.database.model - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.yessorae.domain.entity.tick.Tick -import com.yessorae.domain.entity.tick.TickUnit -import java.time.LocalDateTime - -@Entity(tableName = ChartTable.NAME) -data class ChartTable( - @PrimaryKey(autoGenerate = true) - val id: Long, - @ColumnInfo(name = COL_GAME_ID) - val gameId: Long, - @ColumnInfo(name = COL_TICKER_SYMBOL) - val tickerSymbol: String, - @ColumnInfo(name = COL_START_DATE_TIME) - val startDateTime: LocalDateTime, - @ColumnInfo(name = COL_END_DATE_TIME) - val endDateTime: LocalDateTime, - @ColumnInfo(name = COL_TICKS) - val ticks: List, - @ColumnInfo(name = COL_TICK_UNIT) - val tickUnit: TickUnit -) { - companion object { - const val NAME = "chart_table" - const val COL_GAME_ID = "game_id" - const val COL_TICKER_SYMBOL = "ticker_symbol" - const val COL_START_DATE_TIME = "start_date_time" - const val COL_END_DATE_TIME = "end_date_time" - const val COL_TICKS = "ticks" - const val COL_TICK_UNIT = "tick_unit" - } -} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt deleted file mode 100644 index df00886..0000000 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/TickTable.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.yessorae.data.source.local.database.model - -import androidx.room.ColumnInfo -import androidx.room.Entity -import java.time.LocalDateTime - -@Entity( - tableName = TickTable.NAME, - primaryKeys = [ - TickTable.COL_GAME_ID, - TickTable.COL_CHART_ID - ] -) -data class TickTable( - @ColumnInfo(name = COL_GAME_ID) - val gameId: Long, - @ColumnInfo(name = COL_CHART_ID) - val chartId: Long, - @ColumnInfo(name = COL_OPEN_PRICE) - val openPrice: Double, - @ColumnInfo(name = COL_MAX_PRICE) - val maxPrice: Double, - @ColumnInfo(name = COL_MIN_PRICE) - val minPrice: Double, - @ColumnInfo(name = COL_CLOSE_PRICE) - val closePrice: Double, - @ColumnInfo(name = COL_TRANSACTION_COUNT) - val transactionCount: Int, - @ColumnInfo(name = COL_START_TIMESTAMP) - val startTimestamp: LocalDateTime, - @ColumnInfo(name = COL_TRADING_VOLUME) - val tradingVolume: Int, - @ColumnInfo(name = COL_VOLUME_WEIGHTED_AVERAGE_PRICE) - val volumeWeightedAveragePrice: Double -) { - companion object { - const val NAME = "table_tick" - const val COL_GAME_ID = "game_id" - const val COL_CHART_ID = "chart_id" - const val COL_OPEN_PRICE = "open_price" - const val COL_MAX_PRICE = "max_price" - const val COL_MIN_PRICE = "min_price" - const val COL_CLOSE_PRICE = "close_price" - const val COL_TRANSACTION_COUNT = "transaction_count" - const val COL_START_TIMESTAMP = "start_timestamp" - const val COL_TRADING_VOLUME = "trading_volume" - const val COL_VOLUME_WEIGHTED_AVERAGE_PRICE = "volume_weighted_average_price" - } -} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt deleted file mode 100644 index 4667ff8..0000000 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/TradeTable.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.yessorae.data.source.local.database.model - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.yessorae.domain.entity.trade.TradeType -import com.yessorae.domain.entity.value.Money - -@Entity(tableName = TradeTable.NAME) -data class TradeTable( - @PrimaryKey(autoGenerate = true) - val id: Long, - @ColumnInfo(name = COL_GAME_ID) - val gameId: Long, - @ColumnInfo(name = COL_OWNED_AVERAGE_STOCK_PRICE) - val ownedAverageStockPrice: Money, - @ColumnInfo(name = COL_STOCK_PRICE) - val stockPrice: Money, - @ColumnInfo(name = COL_COUNT) - val count: Int, - @ColumnInfo(name = COL_TURN) - val turn: Int, - @ColumnInfo(name = COL_TYPE) - val type: TradeType, - @ColumnInfo(name = COL_COMMISSION_RATE) - val commissionRate: Double -) { - companion object { - const val NAME = "trade_table" - const val COL_GAME_ID = "game_id" - const val COL_OWNED_AVERAGE_STOCK_PRICE = "owned_average_price" - const val COL_STOCK_PRICE = "stock_price" - const val COL_COUNT = "count" - const val COL_TURN = "turn" - const val COL_TYPE = "type" - const val COL_COMMISSION_RATE = "commission_rate" - } -} From 6c9f5142783b4841dbbb4085e7d38ca84e9b39e2 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:25:48 +0900 Subject: [PATCH 21/47] =?UTF-8?q?[CT-3]=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/source/local/database/model/TickEntity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt index 2a7ea42..8b5af63 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt @@ -31,7 +31,6 @@ data class TickEntity( ) { companion object { const val NAME = "table_tick" - const val COL_GAME_ID = "game_id" const val COL_CHART_ID = "chart_id" const val COL_OPEN_PRICE = "open_price" const val COL_MAX_PRICE = "max_price" From 582d414d18179a340b841f3db6147d3b2e40459d Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:40:57 +0900 Subject: [PATCH 22/47] =?UTF-8?q?[CT-3]=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/di/PolygonNetworkModule.kt | 16 ---------------- .../source/local/database/dao/ChartGameDao.kt | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt index f5e5a4d..e19f9e7 100644 --- a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt @@ -1,19 +1,3 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.yessorae.data.di import com.yessorae.data.source.network.polygon.api.PolygonChartApi diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt index 3401277..0ab7be2 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartGameDao.kt @@ -1,19 +1,3 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.yessorae.data.source.local.database.dao import androidx.room.Dao From 2fe043fb2a590192401443dd10e61c0fa893a84c Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 18 May 2024 22:42:09 +0900 Subject: [PATCH 23/47] =?UTF-8?q?[CT-3]=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/di/PolygonNetworkModule.kt | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt index f5e5a4d..e19f9e7 100644 --- a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt @@ -1,19 +1,3 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.yessorae.data.di import com.yessorae.data.source.network.polygon.api.PolygonChartApi From e87ca7dafb9eb37f338e22d95df3e45454086066 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 19 May 2024 00:58:33 +0900 Subject: [PATCH 24/47] =?UTF-8?q?[CT-3]=20TradeRepository.kt=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C.=20=EB=B6=88=ED=95=84=EC=9A=94.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/domain/repository/TradeRepository.kt | 9 --------- .../com/yessorae/domain/usecase/TradeStockUseCase.kt | 4 ---- 2 files changed, 13 deletions(-) delete mode 100644 domain/src/main/java/com/yessorae/domain/repository/TradeRepository.kt diff --git a/domain/src/main/java/com/yessorae/domain/repository/TradeRepository.kt b/domain/src/main/java/com/yessorae/domain/repository/TradeRepository.kt deleted file mode 100644 index fca2c46..0000000 --- a/domain/src/main/java/com/yessorae/domain/repository/TradeRepository.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.yessorae.domain.repository - -import com.yessorae.domain.entity.trade.Trade - -interface TradeRepository { - suspend fun saveTradeHistory(trade: Trade) - - suspend fun deleteTradeHistoryAt(gameId: Long) -} diff --git a/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt index 2b51e5a..2348881 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt @@ -6,7 +6,6 @@ import com.yessorae.domain.entity.trade.Trade import com.yessorae.domain.entity.trade.TradeType import com.yessorae.domain.entity.value.Money import com.yessorae.domain.repository.ChartGameRepository -import com.yessorae.domain.repository.TradeRepository import com.yessorae.domain.repository.UserRepository import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -14,7 +13,6 @@ import kotlinx.coroutines.flow.flow class TradeStockUseCase @Inject constructor( private val chartGameRepository: ChartGameRepository, - private val tradeRepository: TradeRepository, private val userRepository: UserRepository ) { suspend operator fun invoke( @@ -36,8 +34,6 @@ class TradeStockUseCase @Inject constructor( commissionRate = userRepository.fetchCommissionRateConfig() ) - tradeRepository.saveTradeHistory(trade = trade) - chartGameRepository.updateChartGame( chartGame = chartGameRepository.fetchChartGame( gameId = gameId From b20965826b853752ffa23ef80ef21e6d5b3cae3b Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 19 May 2024 01:13:16 +0900 Subject: [PATCH 25/47] =?UTF-8?q?[CT-3]=20Dispatcher=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/di/CoroutineDispatcherModule.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/di/CoroutineDispatcherModule.kt diff --git a/data/src/main/java/com/yessorae/data/di/CoroutineDispatcherModule.kt b/data/src/main/java/com/yessorae/data/di/CoroutineDispatcherModule.kt new file mode 100644 index 0000000..1bf41ad --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/CoroutineDispatcherModule.kt @@ -0,0 +1,32 @@ +package com.yessorae.data.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Qualifier +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +// TODO::Later common 모듈 만들고 이동 + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class Dispatcher(val dispatcher: ChartTrainerDispatcher) + +enum class ChartTrainerDispatcher { + Default, + IO +} + +@Module +@InstallIn(SingletonComponent::class) +object CoroutineDispatcherModule { + @Provides + @Dispatcher(ChartTrainerDispatcher.IO) + fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO + + @Provides + @Dispatcher(ChartTrainerDispatcher.Default) + fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default +} From 6cf010113b1ffebcd5291c712d70849d0b5c3ed0 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 19 May 2024 01:13:45 +0900 Subject: [PATCH 26/47] =?UTF-8?q?[CT-3]=20ChartGameRepository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(+=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ChartGameRepositoryImpl.kt | 88 +++++++++++++++++++ .../domain/repository/ChartGameRepository.kt | 6 +- .../usecase/SubscribeChartGameUseCase.kt | 6 +- 3 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt diff --git a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt new file mode 100644 index 0000000..3d72242 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt @@ -0,0 +1,88 @@ +package com.yessorae.data.repository + +import com.yessorae.data.di.ChartTrainerDispatcher +import com.yessorae.data.di.Dispatcher +import com.yessorae.data.source.local.database.dao.ChartDao +import com.yessorae.data.source.local.database.dao.ChartGameDao +import com.yessorae.data.source.local.database.dao.TickDao +import com.yessorae.data.source.local.database.dao.TradeDao +import com.yessorae.data.source.local.database.model.TickEntity +import com.yessorae.data.source.local.database.model.TradeEntity +import com.yessorae.data.source.local.database.model.asDomainModel +import com.yessorae.data.source.local.database.model.asEntity +import com.yessorae.domain.entity.ChartGame +import com.yessorae.domain.entity.trade.Trade +import com.yessorae.domain.repository.ChartGameRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.async +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.joinAll +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class ChartGameRepositoryImpl @Inject constructor( + private val chartGameDao: ChartGameDao, + private val chartDao: ChartDao, + private val tradeDao: TradeDao, + private val tickDao: TickDao, + @Dispatcher(ChartTrainerDispatcher.IO) + private val dispatcher: CoroutineDispatcher +) : ChartGameRepository { + override suspend fun createNewChartGame(chartGame: ChartGame): Long = + withContext(dispatcher) { + chartGameDao.insert(entity = chartGame.asEntity()) + } + + override fun fetchChartFlow(gameId: Long): Flow { + return combine( + chartGameDao.getChartGameAsFlow(id = gameId), + tradeDao.getTradesAsFlow(gameId = gameId), + ::Pair + ) + .distinctUntilChanged() + .map { (chartGame, newTrades) -> + val chart = chartDao.getChart(id = chartGame.chartId) + val ticks = tickDao.getTicks(chartId = chart.id).map(TickEntity::asDomainModel) + chartGame.asDomainModel( + chart = chart.asDomainModel(ticks = ticks), + trades = newTrades.map(transform = TradeEntity::asDomainModel) + ) + } + .flowOn(dispatcher) + } + + override suspend fun fetchChartGame(gameId: Long): ChartGame = + withContext(dispatcher) { + val chartGameJob = async { chartGameDao.getChartGame(id = gameId) } + val tradesJob = async { tradeDao.getTrades(gameId = gameId) } + + val chartGame = chartGameJob.await() + val chart = chartDao.getChart(id = chartGame.chartId) + val ticks = tickDao.getTicks(chartId = chart.id).map(TickEntity::asDomainModel) + + chartGame.asDomainModel( + chart = chart.asDomainModel(ticks = ticks), + trades = tradesJob.await().map(transform = TradeEntity::asDomainModel) + ) + } + + override suspend fun updateChartGame(chartGame: ChartGame) = + withContext(dispatcher) { + listOf( + launch { + tradeDao.insertOrReplaceAll(entities = chartGame.trades.map(Trade::asEntity)) + }, + launch { + chartDao.update(entity = chartGame.chart.asEntity()) + }, + launch { + chartGameDao.update(chartGame.asEntity()) + } + ).joinAll() + } +} diff --git a/domain/src/main/java/com/yessorae/domain/repository/ChartGameRepository.kt b/domain/src/main/java/com/yessorae/domain/repository/ChartGameRepository.kt index 20c1eab..e33501e 100644 --- a/domain/src/main/java/com/yessorae/domain/repository/ChartGameRepository.kt +++ b/domain/src/main/java/com/yessorae/domain/repository/ChartGameRepository.kt @@ -4,13 +4,11 @@ import com.yessorae.domain.entity.ChartGame import kotlinx.coroutines.flow.Flow interface ChartGameRepository { - suspend fun saveChartGame(chartGame: ChartGame): Long + suspend fun createNewChartGame(chartGame: ChartGame): Long - fun fetchChartFlowStream(gameId: Long): Flow + fun fetchChartFlow(gameId: Long): Flow suspend fun fetchChartGame(gameId: Long): ChartGame suspend fun updateChartGame(chartGame: ChartGame) - - suspend fun deleteChartGame(gameId: Long) } diff --git a/domain/src/main/java/com/yessorae/domain/usecase/SubscribeChartGameUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/SubscribeChartGameUseCase.kt index 6522848..5da6756 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/SubscribeChartGameUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/SubscribeChartGameUseCase.kt @@ -16,7 +16,7 @@ class SubscribeChartGameUseCase @Inject constructor( ) { suspend operator fun invoke(gameId: Long?): Flow> { if (gameId == null) { - val newGameId = chartGameRepository.saveChartGame( + val newGameId = chartGameRepository.createNewChartGame( chartGame = ChartGame.new( chart = chartRepository.fetchNewChartRandomly(), totalTurn = userRepository.fetchTotalTurnConfig(), @@ -25,12 +25,12 @@ class SubscribeChartGameUseCase @Inject constructor( ) return chartGameRepository - .fetchChartFlowStream(gameId = newGameId) + .fetchChartFlow(gameId = newGameId) .delegateValueResultFlow() } return chartGameRepository - .fetchChartFlowStream(gameId = gameId) + .fetchChartFlow(gameId = gameId) .delegateValueResultFlow() } } From cbaa2deb5f3494050128a984a3e7d95d6a020cf7 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 19 May 2024 01:14:23 +0900 Subject: [PATCH 27/47] =?UTF-8?q?[CT-3]=20ChartRepository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/ChartRepositoryImpl.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt diff --git a/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt new file mode 100644 index 0000000..a5937aa --- /dev/null +++ b/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt @@ -0,0 +1,34 @@ +package com.yessorae.data.repository + +import com.yessorae.data.di.ChartTrainerDispatcher +import com.yessorae.data.di.Dispatcher +import com.yessorae.data.source.local.preference.ChartTrainerPreferencesDataSource +import com.yessorae.data.source.network.ChartNetworkDataSource +import com.yessorae.data.source.network.polygon.model.chart.asDomainModel +import com.yessorae.domain.common.ChartRequestArgumentHelper +import com.yessorae.domain.entity.Chart +import com.yessorae.domain.entity.tick.TickUnit +import com.yessorae.domain.repository.ChartRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +class ChartRepositoryImpl @Inject constructor( + private val networkDataSource: ChartNetworkDataSource, + private val appPreferences: ChartTrainerPreferencesDataSource, + private val chartRequestArgumentHelper: ChartRequestArgumentHelper, + @Dispatcher(ChartTrainerDispatcher.IO) + private val dispatcher: CoroutineDispatcher +) : ChartRepository { + override suspend fun fetchNewChartRandomly(): Chart = + withContext(dispatcher) { + networkDataSource + .getChart( + ticker = chartRequestArgumentHelper.getRandomTicker(), + tickUnit = appPreferences.getTickUnit(), + from = chartRequestArgumentHelper.getStartDate(), + to = chartRequestArgumentHelper.getEndDate() + ) + .asDomainModel(tickUnit = TickUnit.DAY) + } +} From 99dba4b5e14764dc30ea84278b38857f0ccaf0b7 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 19 May 2024 01:14:32 +0900 Subject: [PATCH 28/47] =?UTF-8?q?[CT-3]=20UserRepository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/UserRepositoryImpl.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/repository/UserRepositoryImpl.kt diff --git a/data/src/main/java/com/yessorae/data/repository/UserRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/UserRepositoryImpl.kt new file mode 100644 index 0000000..34ab5b9 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/repository/UserRepositoryImpl.kt @@ -0,0 +1,31 @@ +package com.yessorae.data.repository + +import com.yessorae.data.di.ChartTrainerDispatcher +import com.yessorae.data.di.Dispatcher +import com.yessorae.data.source.local.preference.ChartTrainerPreferencesDataSource +import com.yessorae.domain.entity.value.Money +import com.yessorae.domain.repository.UserRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +class UserRepositoryImpl @Inject constructor( + private val appPreference: ChartTrainerPreferencesDataSource, + @Dispatcher(ChartTrainerDispatcher.IO) + private val dispatcher: CoroutineDispatcher +) : UserRepository { + override suspend fun fetchCommissionRateConfig(): Double = + withContext(dispatcher) { + appPreference.getCommissionRate() + } + + override suspend fun fetchTotalTurnConfig(): Int = + withContext(dispatcher) { + appPreference.getTotalTurn() + } + + override suspend fun fetchCurrentBalance(): Money = + withContext(dispatcher) { + appPreference.getCurrentBalance() + } +} From 2c144cb73f1e08684d147a9810e0cd55eaad786b Mon Sep 17 00:00:00 2001 From: yessorae Date: Mon, 20 May 2024 19:59:10 +0900 Subject: [PATCH 29/47] =?UTF-8?q?[CT-3]=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20-=20buildSrc=20=EB=94=94=ED=8E=9C=EB=8D=98=EC=8B=9C?= =?UTF-8?q?=20=EC=83=81=EC=88=98=20Version=20=EB=B6=84=EB=A6=AC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 48 ++++++++++++++++++-------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 23dd667..a175810 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -1,45 +1,63 @@ object Dependency { object Common { - const val HILT = "com.google.dagger:hilt-android:2.44" - const val HILT_COMPILER = "com.google.dagger:hilt-android-compiler:2.44" + const val HILT = "com.google.dagger:hilt-android:${Version.HILT}" + const val HILT_COMPILER = "com.google.dagger:hilt-android-compiler:${Version.HILT}" - const val ANDROIDX_CORE = "androidx.core:core-ktx:1.9.0" // 1.13.1 + const val ANDROIDX_CORE = "androidx.core:core-ktx:${Version.ANDROIDX_CORE}" // 1.13.1 - const val JUNIT = "junit:junit:4.13.2" - const val JUNIT_EXT = "androidx.test.ext:junit:1.1.5" + const val JUNIT = "junit:junit:${Version.JUNIT}" + const val JUNIT_EXT = "androidx.test.ext:junit:${Version.JUNIT_EXT}" + + object Version { + const val HILT = "2.44" + const val ANDROIDX_CORE = "1.9.0" + const val JUNIT = "4.13.2" + const val JUNIT_EXT = "1.1.5" + } } object PlatformIndependent { - const val JAVAX_INJECT = "javax.inject:javax.inject:1" - const val KOTLINX_COROUTINSE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1" + const val JAVAX_INJECT = "javax.inject:javax.inject:${Version.JAVAX_INJECT}" + const val KOTLINX_COROUTINSE = + "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Version.KOTLINX_COROUTINSE}" + + object Version { + const val JAVAX_INJECT = "1" + const val KOTLINX_COROUTINSE = "1.8.1" + } } object Data { const val RETROFIT = "com.squareup.retrofit2:retrofit:${Version.RETROFIT}" - const val RETROFIT_GSON_CONVERTER = "com.squareup.retrofit2:converter-gson:${Version.RETROFIT}" - const val OK_HTTP_3 = "com.squareup.okhttp3:logging-interceptor:4.12.0" + const val RETROFIT_GSON_CONVERTER = + "com.squareup.retrofit2:converter-gson:${Version.RETROFIT}" + const val OK_HTTP_3 = "com.squareup.okhttp3:logging-interceptor:${Version.OK_HTTP_3}" object Version { const val RETROFIT = "2.11.0" + const val OK_HTTP_3 = "4.12.0" } } object Compose { - const val BOM = "androidx.compose:compose-bom:2023.03.00" + const val BOM = "androidx.compose:compose-bom:${Version.BOM}" const val UI = "androidx.compose.ui:ui" const val UI_GRAPHICS = "androidx.compose.ui:ui-graphics" const val MATERIAL_3 = "androidx.compose.material3:material3" - const val LIFECYCLE_RUNTIME = "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0" - const val ACTIVITY_COMPOSE = "androidx.activity:activity-compose:1.8.2" + const val LIFECYCLE_RUNTIME = "androidx.lifecycle:lifecycle-runtime-ktx:${Version.LIFECYCLE_RUNTIME}" + const val ACTIVITY_COMPOSE = "androidx.activity:activity-compose:${Version.ACTIVITY_COMPOSE}" const val UI_TOOLING = "androidx.compose.ui:ui-tooling" const val UI_TOOLING_PREVIEW = "androidx.compose.ui:ui-tooling-preview" const val JUNIT = "androidx.compose.ui:ui-test-junit4" const val UI_TEST_MANIFEST = "androidx.compose.ui:ui-test-manifest" - } - - object Test { + object Version { + const val BOM = "2023.03.00" + const val LIFECYCLE_RUNTIME = "2.7.0" + const val ACTIVITY_COMPOSE = "1.8.2" + } + } } From 2142c0efde69734b36f4c996649c98ffcb7ad851 Mon Sep 17 00:00:00 2001 From: yessorae Date: Mon, 20 May 2024 22:04:05 +0900 Subject: [PATCH 30/47] =?UTF-8?q?[CT-3]=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20-=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/src/main/java/com/yessorae/data/di/DatabaseModule.kt | 2 +- .../data/source/local/database/ChartTrainerDatabase.kt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt b/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt index fb587d9..8c7e50a 100644 --- a/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt +++ b/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt @@ -19,6 +19,6 @@ object DatabaseModule { Room.databaseBuilder( context = context, klass = ChartTrainerDatabase::class.java, - name = "chart-trainer-database" + name = ChartTrainerDatabase.NAME ).build() } diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt index c3f0fb1..e75f817 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerDatabase.kt @@ -32,4 +32,8 @@ abstract class ChartTrainerDatabase : RoomDatabase() { abstract fun getChartGameDao(): ChartGameDao abstract fun getTickDao(): TickDao abstract fun getTradeDao(): TradeDao + + companion object { + const val NAME = "chart-trainer-database" + } } From 802e0065e716f724babcb21bbc8108a714935101 Mon Sep 17 00:00:00 2001 From: yessorae Date: Mon, 20 May 2024 22:06:59 +0900 Subject: [PATCH 31/47] =?UTF-8?q?[CT-3]=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20-=20Dao=20=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EB=88=84=EB=9D=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/source/local/database/dao/ChartDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt index b2fe144..a855679 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/dao/ChartDao.kt @@ -8,7 +8,7 @@ import com.yessorae.data.source.local.database.model.ChartEntity interface ChartDao : BaseDao { @Query( """ - SELECT * FROM ${ChartEntity.NAME} WHERE id = :id + SELECT * FROM ${ChartEntity.NAME} WHERE id = :id """ ) suspend fun getChart(id: Long): ChartEntity From d3f1408580aed61b5d204915b05806e5469bff81 Mon Sep 17 00:00:00 2001 From: yessorae Date: Mon, 20 May 2024 22:24:24 +0900 Subject: [PATCH 32/47] =?UTF-8?q?[CT-3]=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20-=20Module=20=ED=86=B5=ED=8F=90=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yessorae/data/di/CommonNetworkModule.kt | 29 ------------------- .../java/com/yessorae/data/di/DaoModule.kt | 28 ------------------ ...ataSourceModule.kt => DataSourceModule.kt} | 2 +- .../com/yessorae/data/di/DatabaseModule.kt | 17 +++++++++++ ...lygonNetworkModule.kt => NetworkModule.kt} | 23 +++++++++++++-- 5 files changed, 38 insertions(+), 61 deletions(-) delete mode 100644 data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt delete mode 100644 data/src/main/java/com/yessorae/data/di/DaoModule.kt rename data/src/main/java/com/yessorae/data/di/{NetworkDataSourceModule.kt => DataSourceModule.kt} (92%) rename data/src/main/java/com/yessorae/data/di/{PolygonNetworkModule.kt => NetworkModule.kt} (53%) diff --git a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt deleted file mode 100644 index ff46175..0000000 --- a/data/src/main/java/com/yessorae/data/di/CommonNetworkModule.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.yessorae.data.di - -import com.yessorae.data.BuildConfig -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton -import okhttp3.Call -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor - -@Module -@InstallIn(SingletonComponent::class) -object CommonNetworkModule { - @Provides - @Singleton - fun provideOkHttpCallFactory(): Call.Factory = - OkHttpClient.Builder() - .addInterceptor( - HttpLoggingInterceptor() - .apply { - if (BuildConfig.DEBUG) { - setLevel(HttpLoggingInterceptor.Level.BODY) - } - } - ) - .build() -} diff --git a/data/src/main/java/com/yessorae/data/di/DaoModule.kt b/data/src/main/java/com/yessorae/data/di/DaoModule.kt deleted file mode 100644 index 28b4aa9..0000000 --- a/data/src/main/java/com/yessorae/data/di/DaoModule.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.yessorae.data.di - -import com.yessorae.data.source.local.database.ChartTrainerDatabase -import com.yessorae.data.source.local.database.dao.ChartDao -import com.yessorae.data.source.local.database.dao.ChartGameDao -import com.yessorae.data.source.local.database.dao.TickDao -import com.yessorae.data.source.local.database.dao.TradeDao -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -object DaoModule { - @Provides - fun providesChartDao(database: ChartTrainerDatabase): ChartDao = database.getChartDao() - - @Provides - fun provideChartGameDao(database: ChartTrainerDatabase): ChartGameDao = - database.getChartGameDao() - - @Provides - fun provideTickDao(database: ChartTrainerDatabase): TickDao = database.getTickDao() - - @Provides - fun provideTradeDao(database: ChartTrainerDatabase): TradeDao = database.getTradeDao() -} diff --git a/data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt similarity index 92% rename from data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt rename to data/src/main/java/com/yessorae/data/di/DataSourceModule.kt index e1886f6..170f1d1 100644 --- a/data/src/main/java/com/yessorae/data/di/NetworkDataSourceModule.kt +++ b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt @@ -10,7 +10,7 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -abstract class NetworkDataSourceModule { +abstract class DataSourceModule { @Binds @Singleton abstract fun bindsChartNetworkDataSource( diff --git a/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt b/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt index 8c7e50a..b1ae7b6 100644 --- a/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt +++ b/data/src/main/java/com/yessorae/data/di/DatabaseModule.kt @@ -3,6 +3,10 @@ package com.yessorae.data.di import android.content.Context import androidx.room.Room import com.yessorae.data.source.local.database.ChartTrainerDatabase +import com.yessorae.data.source.local.database.dao.ChartDao +import com.yessorae.data.source.local.database.dao.ChartGameDao +import com.yessorae.data.source.local.database.dao.TickDao +import com.yessorae.data.source.local.database.dao.TradeDao import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -21,4 +25,17 @@ object DatabaseModule { klass = ChartTrainerDatabase::class.java, name = ChartTrainerDatabase.NAME ).build() + + @Provides + fun providesChartDao(database: ChartTrainerDatabase): ChartDao = database.getChartDao() + + @Provides + fun provideChartGameDao(database: ChartTrainerDatabase): ChartGameDao = + database.getChartGameDao() + + @Provides + fun provideTickDao(database: ChartTrainerDatabase): TickDao = database.getTickDao() + + @Provides + fun provideTradeDao(database: ChartTrainerDatabase): TradeDao = database.getTradeDao() } diff --git a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt b/data/src/main/java/com/yessorae/data/di/NetworkModule.kt similarity index 53% rename from data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt rename to data/src/main/java/com/yessorae/data/di/NetworkModule.kt index e19f9e7..b13d0eb 100644 --- a/data/src/main/java/com/yessorae/data/di/PolygonNetworkModule.kt +++ b/data/src/main/java/com/yessorae/data/di/NetworkModule.kt @@ -1,5 +1,6 @@ package com.yessorae.data.di +import com.yessorae.data.BuildConfig import com.yessorae.data.source.network.polygon.api.PolygonChartApi import com.yessorae.data.source.network.polygon.common.PolygonConstant import dagger.Module @@ -8,15 +9,31 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton import okhttp3.Call +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory @Module @InstallIn(SingletonComponent::class) -object PolygonNetworkModule { +object NetworkModule { @Provides @Singleton - fun provideRetrofit(okhttpCallFactory: Call.Factory): Retrofit = + fun provideOkHttpCallFactory(): Call.Factory = + OkHttpClient.Builder() + .addInterceptor( + HttpLoggingInterceptor() + .apply { + if (BuildConfig.DEBUG) { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + } + ) + .build() + + @Provides + @Singleton + fun providePolygonRetrofit(okhttpCallFactory: Call.Factory): Retrofit = Retrofit.Builder() .baseUrl(PolygonConstant.BASE_URL) .callFactory(okhttpCallFactory) @@ -25,6 +42,6 @@ object PolygonNetworkModule { @Provides @Singleton - fun provideChartApi(retrofit: Retrofit): PolygonChartApi = + fun providePolygonChartApi(retrofit: Retrofit): PolygonChartApi = retrofit.create(PolygonChartApi::class.java) } From 9118e308b5e60e120ae7e5a4d83c140fbab86525 Mon Sep 17 00:00:00 2001 From: yessorae Date: Tue, 21 May 2024 20:45:10 +0900 Subject: [PATCH 33/47] =?UTF-8?q?[CT-3]=20=EC=84=B8=20=EA=B0=9C=20?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=8F=99=EC=8B=9C=EC=97=90=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20Transa?= =?UTF-8?q?ction=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yessorae/data/di/UtilModule.kt | 8 +++++ .../repository/ChartGameRepositoryImpl.kt | 30 +++++++++++-------- .../ChartTrainerDatabaseTransactionHelper.kt | 13 ++++++++ .../polygon/util/DatabaseTransactionHelper.kt | 8 +++++ 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt create mode 100644 data/src/main/java/com/yessorae/data/source/network/polygon/util/DatabaseTransactionHelper.kt diff --git a/data/src/main/java/com/yessorae/data/di/UtilModule.kt b/data/src/main/java/com/yessorae/data/di/UtilModule.kt index 3d4674f..2b87ccb 100644 --- a/data/src/main/java/com/yessorae/data/di/UtilModule.kt +++ b/data/src/main/java/com/yessorae/data/di/UtilModule.kt @@ -1,5 +1,7 @@ package com.yessorae.data.di +import com.yessorae.data.source.network.polygon.util.ChartTrainerDatabaseTransactionHelper +import com.yessorae.data.source.network.polygon.util.DatabaseTransactionHelper import com.yessorae.data.source.network.polygon.util.DefaultChartRequestArgumentHelper import com.yessorae.domain.common.ChartRequestArgumentHelper import dagger.Binds @@ -16,4 +18,10 @@ abstract class UtilModule { abstract fun bindsRandomChartArgumentGenerator( defaultRandomChartArgumentGenerator: DefaultChartRequestArgumentHelper ): ChartRequestArgumentHelper + + @Binds + @Singleton + abstract fun bindsChartTrainerDatabaseTransactionHelper( + chartTrainerDatabaseTransactionHelper: ChartTrainerDatabaseTransactionHelper + ): DatabaseTransactionHelper } diff --git a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt index 3d72242..65a2a04 100644 --- a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt +++ b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt @@ -10,6 +10,7 @@ import com.yessorae.data.source.local.database.model.TickEntity import com.yessorae.data.source.local.database.model.TradeEntity import com.yessorae.data.source.local.database.model.asDomainModel import com.yessorae.data.source.local.database.model.asEntity +import com.yessorae.data.source.network.polygon.util.DatabaseTransactionHelper import com.yessorae.domain.entity.ChartGame import com.yessorae.domain.entity.trade.Trade import com.yessorae.domain.repository.ChartGameRepository @@ -31,7 +32,8 @@ class ChartGameRepositoryImpl @Inject constructor( private val tradeDao: TradeDao, private val tickDao: TickDao, @Dispatcher(ChartTrainerDispatcher.IO) - private val dispatcher: CoroutineDispatcher + private val dispatcher: CoroutineDispatcher, + private val transactionHelper: DatabaseTransactionHelper ) : ChartGameRepository { override suspend fun createNewChartGame(chartGame: ChartGame): Long = withContext(dispatcher) { @@ -73,16 +75,20 @@ class ChartGameRepositoryImpl @Inject constructor( override suspend fun updateChartGame(chartGame: ChartGame) = withContext(dispatcher) { - listOf( - launch { - tradeDao.insertOrReplaceAll(entities = chartGame.trades.map(Trade::asEntity)) - }, - launch { - chartDao.update(entity = chartGame.chart.asEntity()) - }, - launch { - chartGameDao.update(chartGame.asEntity()) - } - ).joinAll() + transactionHelper.runTransaction { + listOf( + launch { + tradeDao.insertOrReplaceAll( + entities = chartGame.trades.map(Trade::asEntity) + ) + }, + launch { + chartDao.update(entity = chartGame.chart.asEntity()) + }, + launch { + chartGameDao.update(chartGame.asEntity()) + } + ).joinAll() + } } } diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt new file mode 100644 index 0000000..62efbcb --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt @@ -0,0 +1,13 @@ +package com.yessorae.data.source.network.polygon.util + +import androidx.room.RoomDatabase +import androidx.room.withTransaction +import javax.inject.Inject + +class ChartTrainerDatabaseTransactionHelper @Inject constructor( + private val roomDatabase: RoomDatabase +) : DatabaseTransactionHelper { + override suspend fun runTransaction(run: suspend () -> Unit) { + roomDatabase.withTransaction(run) + } +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/util/DatabaseTransactionHelper.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/util/DatabaseTransactionHelper.kt new file mode 100644 index 0000000..dcb6021 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/util/DatabaseTransactionHelper.kt @@ -0,0 +1,8 @@ +package com.yessorae.data.source.network.polygon.util + +/** + * 여러 테이블에 대해 데이터베이스를 업데이트할 때 사용 + */ +interface DatabaseTransactionHelper { + suspend fun runTransaction(run: suspend () -> Unit) +} From eb30457e0f240b84804f7e112fba0e52b30ddb89 Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 22 May 2024 20:01:11 +0900 Subject: [PATCH 34/47] =?UTF-8?q?[CT-3]=20launch=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=99=80=20joinAll=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ChartGameRepositoryImpl.kt | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt index 65a2a04..7551ecc 100644 --- a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt +++ b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt @@ -76,19 +76,17 @@ class ChartGameRepositoryImpl @Inject constructor( override suspend fun updateChartGame(chartGame: ChartGame) = withContext(dispatcher) { transactionHelper.runTransaction { - listOf( - launch { - tradeDao.insertOrReplaceAll( - entities = chartGame.trades.map(Trade::asEntity) - ) - }, - launch { - chartDao.update(entity = chartGame.chart.asEntity()) - }, - launch { - chartGameDao.update(chartGame.asEntity()) - } - ).joinAll() + launch { + tradeDao.insertOrReplaceAll( + entities = chartGame.trades.map(Trade::asEntity) + ) + } + launch { + chartDao.update(entity = chartGame.chart.asEntity()) + } + launch { + chartGameDao.update(chartGame.asEntity()) + } } } } From 9b109b085c040b02ceaedaddd0b6e09575125330 Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 22 May 2024 20:01:28 +0900 Subject: [PATCH 35/47] =?UTF-8?q?[CT-3]=20launch=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=99=80=20joinAll=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ChartGameRepositoryImpl.kt | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt index 65a2a04..2a2e106 100644 --- a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt +++ b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt @@ -14,7 +14,6 @@ import com.yessorae.data.source.network.polygon.util.DatabaseTransactionHelper import com.yessorae.domain.entity.ChartGame import com.yessorae.domain.entity.trade.Trade import com.yessorae.domain.repository.ChartGameRepository -import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.async import kotlinx.coroutines.flow.Flow @@ -22,9 +21,9 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import javax.inject.Inject class ChartGameRepositoryImpl @Inject constructor( private val chartGameDao: ChartGameDao, @@ -76,19 +75,17 @@ class ChartGameRepositoryImpl @Inject constructor( override suspend fun updateChartGame(chartGame: ChartGame) = withContext(dispatcher) { transactionHelper.runTransaction { - listOf( - launch { - tradeDao.insertOrReplaceAll( - entities = chartGame.trades.map(Trade::asEntity) - ) - }, - launch { - chartDao.update(entity = chartGame.chart.asEntity()) - }, - launch { - chartGameDao.update(chartGame.asEntity()) - } - ).joinAll() + launch { + tradeDao.insertOrReplaceAll( + entities = chartGame.trades.map(Trade::asEntity) + ) + } + launch { + chartDao.update(entity = chartGame.chart.asEntity()) + } + launch { + chartGameDao.update(chartGame.asEntity()) + } } } } From 4afa81acec83971a7fd7062aa43b6267d7b1d82f Mon Sep 17 00:00:00 2001 From: yessorae Date: Wed, 22 May 2024 21:12:45 +0900 Subject: [PATCH 36/47] =?UTF-8?q?[CT-3]=20LocalDataSource=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=ED=99=94=20=ED=95=98?= =?UTF-8?q?=EC=97=AC=20Repository=EA=B0=80=20Database=EC=97=90=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B2=8C=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/di/DataSourceModule.kt | 2 +- .../repository/ChartGameRepositoryImpl.kt | 37 ++++++------- .../data/repository/ChartRepositoryImpl.kt | 2 +- .../{network => }/ChartNetworkDataSource.kt | 2 +- .../source/ChartTrainerLocalDBDataSource.kt | 21 ++++++++ .../ChartTrainerLocalDBDataSourceImpl.kt | 54 +++++++++++++++++++ .../polygon/PolygonChartNetworkDataSource.kt | 2 +- 7 files changed, 95 insertions(+), 25 deletions(-) rename data/src/main/java/com/yessorae/data/source/{network => }/ChartNetworkDataSource.kt (87%) create mode 100644 data/src/main/java/com/yessorae/data/source/ChartTrainerLocalDBDataSource.kt create mode 100644 data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerLocalDBDataSourceImpl.kt diff --git a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt index 170f1d1..b08e981 100644 --- a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt +++ b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt @@ -1,6 +1,6 @@ package com.yessorae.data.di -import com.yessorae.data.source.network.ChartNetworkDataSource +import com.yessorae.data.source.ChartNetworkDataSource import com.yessorae.data.source.network.polygon.PolygonChartNetworkDataSource import dagger.Binds import dagger.Module diff --git a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt index 2a2e106..8ad193c 100644 --- a/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt +++ b/data/src/main/java/com/yessorae/data/repository/ChartGameRepositoryImpl.kt @@ -2,10 +2,7 @@ package com.yessorae.data.repository import com.yessorae.data.di.ChartTrainerDispatcher import com.yessorae.data.di.Dispatcher -import com.yessorae.data.source.local.database.dao.ChartDao -import com.yessorae.data.source.local.database.dao.ChartGameDao -import com.yessorae.data.source.local.database.dao.TickDao -import com.yessorae.data.source.local.database.dao.TradeDao +import com.yessorae.data.source.ChartTrainerLocalDBDataSource import com.yessorae.data.source.local.database.model.TickEntity import com.yessorae.data.source.local.database.model.TradeEntity import com.yessorae.data.source.local.database.model.asDomainModel @@ -14,6 +11,7 @@ import com.yessorae.data.source.network.polygon.util.DatabaseTransactionHelper import com.yessorae.domain.entity.ChartGame import com.yessorae.domain.entity.trade.Trade import com.yessorae.domain.repository.ChartGameRepository +import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.async import kotlinx.coroutines.flow.Flow @@ -23,32 +21,29 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import javax.inject.Inject class ChartGameRepositoryImpl @Inject constructor( - private val chartGameDao: ChartGameDao, - private val chartDao: ChartDao, - private val tradeDao: TradeDao, - private val tickDao: TickDao, + private val localDataSource: ChartTrainerLocalDBDataSource, @Dispatcher(ChartTrainerDispatcher.IO) private val dispatcher: CoroutineDispatcher, private val transactionHelper: DatabaseTransactionHelper ) : ChartGameRepository { override suspend fun createNewChartGame(chartGame: ChartGame): Long = withContext(dispatcher) { - chartGameDao.insert(entity = chartGame.asEntity()) + localDataSource.insertCharGame(entity = chartGame.asEntity()) } override fun fetchChartFlow(gameId: Long): Flow { return combine( - chartGameDao.getChartGameAsFlow(id = gameId), - tradeDao.getTradesAsFlow(gameId = gameId), + localDataSource.getChartGameAsFlow(id = gameId), + localDataSource.getTradesAsFlow(gameId = gameId), ::Pair ) .distinctUntilChanged() .map { (chartGame, newTrades) -> - val chart = chartDao.getChart(id = chartGame.chartId) - val ticks = tickDao.getTicks(chartId = chart.id).map(TickEntity::asDomainModel) + val chart = localDataSource.getChart(id = chartGame.chartId) + val ticks = + localDataSource.getTicks(chartId = chart.id).map(TickEntity::asDomainModel) chartGame.asDomainModel( chart = chart.asDomainModel(ticks = ticks), trades = newTrades.map(transform = TradeEntity::asDomainModel) @@ -59,12 +54,12 @@ class ChartGameRepositoryImpl @Inject constructor( override suspend fun fetchChartGame(gameId: Long): ChartGame = withContext(dispatcher) { - val chartGameJob = async { chartGameDao.getChartGame(id = gameId) } - val tradesJob = async { tradeDao.getTrades(gameId = gameId) } + val chartGameJob = async { localDataSource.getChartGame(id = gameId) } + val tradesJob = async { localDataSource.getTrades(gameId = gameId) } val chartGame = chartGameJob.await() - val chart = chartDao.getChart(id = chartGame.chartId) - val ticks = tickDao.getTicks(chartId = chart.id).map(TickEntity::asDomainModel) + val chart = localDataSource.getChart(id = chartGame.chartId) + val ticks = localDataSource.getTicks(chartId = chart.id).map(TickEntity::asDomainModel) chartGame.asDomainModel( chart = chart.asDomainModel(ticks = ticks), @@ -76,15 +71,15 @@ class ChartGameRepositoryImpl @Inject constructor( withContext(dispatcher) { transactionHelper.runTransaction { launch { - tradeDao.insertOrReplaceAll( + localDataSource.insertOrReplaceAllTrades( entities = chartGame.trades.map(Trade::asEntity) ) } launch { - chartDao.update(entity = chartGame.chart.asEntity()) + localDataSource.updateChart(entity = chartGame.chart.asEntity()) } launch { - chartGameDao.update(chartGame.asEntity()) + localDataSource.updateChartGame(chartGame.asEntity()) } } } diff --git a/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt b/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt index a5937aa..8818f26 100644 --- a/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt +++ b/data/src/main/java/com/yessorae/data/repository/ChartRepositoryImpl.kt @@ -2,8 +2,8 @@ package com.yessorae.data.repository import com.yessorae.data.di.ChartTrainerDispatcher import com.yessorae.data.di.Dispatcher +import com.yessorae.data.source.ChartNetworkDataSource import com.yessorae.data.source.local.preference.ChartTrainerPreferencesDataSource -import com.yessorae.data.source.network.ChartNetworkDataSource import com.yessorae.data.source.network.polygon.model.chart.asDomainModel import com.yessorae.domain.common.ChartRequestArgumentHelper import com.yessorae.domain.entity.Chart diff --git a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/ChartNetworkDataSource.kt similarity index 87% rename from data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt rename to data/src/main/java/com/yessorae/data/source/ChartNetworkDataSource.kt index 876ab1a..fda8eba 100644 --- a/data/src/main/java/com/yessorae/data/source/network/ChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/ChartNetworkDataSource.kt @@ -1,4 +1,4 @@ -package com.yessorae.data.source.network +package com.yessorae.data.source import com.yessorae.data.source.network.polygon.model.chart.ChartDto import com.yessorae.domain.entity.tick.TickUnit diff --git a/data/src/main/java/com/yessorae/data/source/ChartTrainerLocalDBDataSource.kt b/data/src/main/java/com/yessorae/data/source/ChartTrainerLocalDBDataSource.kt new file mode 100644 index 0000000..b5a3359 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/ChartTrainerLocalDBDataSource.kt @@ -0,0 +1,21 @@ +package com.yessorae.data.source + +import com.yessorae.data.source.local.database.model.ChartEntity +import com.yessorae.data.source.local.database.model.ChartGameEntity +import com.yessorae.data.source.local.database.model.TickEntity +import com.yessorae.data.source.local.database.model.TradeEntity +import kotlinx.coroutines.flow.Flow + +// Repository 가 Dao 에 직접적으로 의존하지 않는 것에 중점을 둠 +interface ChartTrainerLocalDBDataSource { + fun getChartGameAsFlow(id: Long): Flow + fun getTradesAsFlow(gameId: Long): Flow> + suspend fun getChartGame(id: Long): ChartGameEntity + suspend fun getTrades(gameId: Long): List + suspend fun getChart(id: Long): ChartEntity + suspend fun getTicks(chartId: Long): List + suspend fun insertCharGame(entity: ChartGameEntity): Long + suspend fun updateChartGame(entity: ChartGameEntity) + suspend fun insertOrReplaceAllTrades(entities: List) + suspend fun updateChart(entity: ChartEntity) +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerLocalDBDataSourceImpl.kt b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerLocalDBDataSourceImpl.kt new file mode 100644 index 0000000..2efa939 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/source/local/database/ChartTrainerLocalDBDataSourceImpl.kt @@ -0,0 +1,54 @@ +package com.yessorae.data.source.local.database + +import com.yessorae.data.source.ChartTrainerLocalDBDataSource +import com.yessorae.data.source.local.database.dao.ChartDao +import com.yessorae.data.source.local.database.dao.ChartGameDao +import com.yessorae.data.source.local.database.dao.TickDao +import com.yessorae.data.source.local.database.dao.TradeDao +import com.yessorae.data.source.local.database.model.ChartEntity +import com.yessorae.data.source.local.database.model.ChartGameEntity +import com.yessorae.data.source.local.database.model.TickEntity +import com.yessorae.data.source.local.database.model.TradeEntity +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +class ChartTrainerLocalDBDataSourceImpl @Inject constructor( + private val chartGameDao: ChartGameDao, + private val chartDao: ChartDao, + private val tradeDao: TradeDao, + private val tickDao: TickDao +) : ChartTrainerLocalDBDataSource { + override fun getChartGameAsFlow(id: Long): Flow = + chartGameDao.getChartGameAsFlow(id = id) + + override fun getTradesAsFlow(gameId: Long): Flow> = + tradeDao.getTradesAsFlow(gameId = gameId) + + override suspend fun getChartGame(id: Long): ChartGameEntity = + chartGameDao.getChartGame(id = id) + + override suspend fun getTrades(gameId: Long): List = + tradeDao.getTrades(gameId = gameId) + + override suspend fun getChart(id: Long): ChartEntity = chartDao.getChart(id = id) + + override suspend fun getTicks(chartId: Long): List = + tickDao.getTicks(chartId = chartId) + + override suspend fun insertCharGame(entity: ChartGameEntity): Long = + chartGameDao.insert( + entity = entity + ) + + override suspend fun updateChartGame(entity: ChartGameEntity) = + chartGameDao.update( + entity = entity + ) + + override suspend fun insertOrReplaceAllTrades(entities: List) = + tradeDao.insertOrReplaceAll( + entities = entities + ) + + override suspend fun updateChart(entity: ChartEntity) = chartDao.update(entity = entity) +} diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt index cb30c77..b625b82 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/PolygonChartNetworkDataSource.kt @@ -1,6 +1,6 @@ package com.yessorae.data.source.network.polygon -import com.yessorae.data.source.network.ChartNetworkDataSource +import com.yessorae.data.source.ChartNetworkDataSource import com.yessorae.data.source.network.polygon.api.PolygonChartApi import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_DAY_PATH_VALUE import com.yessorae.data.source.network.polygon.common.PolygonConstant.TIME_SPAN_HOUR_PATH_VALUE From ab6f833c4d7b83c82b2699bea684e044f8bae848 Mon Sep 17 00:00:00 2001 From: yessorae Date: Thu, 23 May 2024 22:51:09 +0900 Subject: [PATCH 37/47] =?UTF-8?q?[CT-2-1]=20=EC=B0=A8=ED=8A=B8=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=20=ED=99=94=EB=A9=B4=20=EB=AA=A8=EB=8D=B8=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chartgame/model/ChartGameScreenEvent.kt | 5 +++++ .../chartgame/model/ChartGameScreenState.kt | 19 +++++++++++++++++++ .../ui/chartgame/model/ChartGameUserAction.kt | 11 +++++++++++ 3 files changed, 35 insertions(+) create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt new file mode 100644 index 0000000..351332a --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt @@ -0,0 +1,5 @@ +package com.yessorae.presentation.ui.chartgame.model + +sealed interface ChartGameScreenEvent { + data class Toast(val text: String) : ChartGameScreenEvent +} \ No newline at end of file diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt new file mode 100644 index 0000000..cbf5c23 --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt @@ -0,0 +1,19 @@ +package com.yessorae.presentation.ui.chartgame.model + +data class ChartGameScreenState( + val screenTitle: String, + val currentTurn: Int, + val totalTurn: Int, + val gameProgress: Float, + val showLoading: Boolean, + //아래와 같이 라이브러리에 맞춘 형태로 지양하는 UI 모델 형태이다. 변경 고민중. + val transactionVolume: List, + val candleStickChart: CandleStickChartUiState, +) + +data class CandleStickChartUiState( + val opening: List, + val closing: List, + val log: List, + val high: List, +) diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt new file mode 100644 index 0000000..9749d63 --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt @@ -0,0 +1,11 @@ +package com.yessorae.presentation.ui.chartgame.model + +sealed interface ChartGameUserAction { + object ClickNewChartButton : ChartGameUserAction + object ClickChartGameHistoryButton : ChartGameUserAction + object ClickQuitGameButton : ChartGameUserAction + object ClickStartGameButton : ChartGameUserAction + object ClickBuyButton : ChartGameUserAction + object ClickSellButton : ChartGameUserAction + object ClickNextTickButton : ChartGameUserAction +} \ No newline at end of file From 5bb2f9d3de2d3c13d69e0f329b7c7c761c1b86e3 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 25 May 2024 18:12:37 +0900 Subject: [PATCH 38/47] =?UTF-8?q?[CT-2-1]=20ChartTrainerLogger=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(CEH=EB=A1=9C=20=EC=9E=A1=EC=9D=80=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EA=B8=B0=EB=A1=9D=ED=95=98=EB=A0=A4=EB=8B=A4?= =?UTF-8?q?=EA=B0=80=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yessorae/data/di/UtilModule.kt | 8 ++++++ .../util/DefaultChartTrainerLoggerImpl.kt | 28 +++++++++++++++++++ .../domain/common/ChartTrainerLogger.kt | 5 ++++ 3 files changed, 41 insertions(+) create mode 100644 data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt create mode 100644 domain/src/main/java/com/yessorae/domain/common/ChartTrainerLogger.kt diff --git a/data/src/main/java/com/yessorae/data/di/UtilModule.kt b/data/src/main/java/com/yessorae/data/di/UtilModule.kt index 2b87ccb..a12b049 100644 --- a/data/src/main/java/com/yessorae/data/di/UtilModule.kt +++ b/data/src/main/java/com/yessorae/data/di/UtilModule.kt @@ -3,7 +3,9 @@ package com.yessorae.data.di import com.yessorae.data.source.network.polygon.util.ChartTrainerDatabaseTransactionHelper import com.yessorae.data.source.network.polygon.util.DatabaseTransactionHelper import com.yessorae.data.source.network.polygon.util.DefaultChartRequestArgumentHelper +import com.yessorae.data.util.DefaultChartTrainerLoggerImpl import com.yessorae.domain.common.ChartRequestArgumentHelper +import com.yessorae.domain.common.ChartTrainerLogger import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -24,4 +26,10 @@ abstract class UtilModule { abstract fun bindsChartTrainerDatabaseTransactionHelper( chartTrainerDatabaseTransactionHelper: ChartTrainerDatabaseTransactionHelper ): DatabaseTransactionHelper + + @Binds + @Singleton + abstract fun bindsDefaultChartTrainerLogger( + chartTrainerLogger: DefaultChartTrainerLoggerImpl + ): ChartTrainerLogger } diff --git a/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt b/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt new file mode 100644 index 0000000..d5e3ff3 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt @@ -0,0 +1,28 @@ +package com.yessorae.data.util + +import android.util.Log +import com.yessorae.data.BuildConfig +import com.yessorae.domain.common.ChartTrainerLogger +import javax.inject.Inject + +// TODO::LATER 모듈 더 나누는 작업 후, common 모듈로 이동 +class DefaultChartTrainerLoggerImpl @Inject constructor() : ChartTrainerLogger { + override fun cehLog(throwable: Throwable) { + if (!BuildConfig.DEBUG) return + Log.d(TAG, "[Throwable]\n$throwable") + Log.d(TAG, "[StackTrace]") + Log.d( + TAG, + Thread.currentThread().stackTrace + .take(STACK_TRACE_DEPTH) + .joinToString("\n") { it.toString() } + ) + // crashlytics 같은 것을 추가할 수 있음 + } + + + companion object { + const val TAG = "SR-N" + const val STACK_TRACE_DEPTH = 5 + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/yessorae/domain/common/ChartTrainerLogger.kt b/domain/src/main/java/com/yessorae/domain/common/ChartTrainerLogger.kt new file mode 100644 index 0000000..6fc3122 --- /dev/null +++ b/domain/src/main/java/com/yessorae/domain/common/ChartTrainerLogger.kt @@ -0,0 +1,5 @@ +package com.yessorae.domain.common + +interface ChartTrainerLogger { + fun cehLog(throwable: Throwable) +} From f6617d2ade791ef2179c0bedff6fe39ce75fb86e Mon Sep 17 00:00:00 2001 From: yessorae Date: Sat, 25 May 2024 18:13:14 +0900 Subject: [PATCH 39/47] =?UTF-8?q?[CT-2-1]=20VICO=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 13 +++++++++---- presentation/build.gradle.kts | 27 +++++++++++++++----------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index c5d6ca8..2f3a8e3 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -46,14 +46,19 @@ object Dependency { } } - object Compose { + object Presentation { const val BOM = "androidx.compose:compose-bom:${Version.BOM}" const val UI = "androidx.compose.ui:ui" const val UI_GRAPHICS = "androidx.compose.ui:ui-graphics" const val MATERIAL_3 = "androidx.compose.material3:material3" - const val LIFECYCLE_RUNTIME = "androidx.lifecycle:lifecycle-runtime-ktx:${Version.LIFECYCLE_RUNTIME}" - const val ACTIVITY_COMPOSE = "androidx.activity:activity-compose:${Version.ACTIVITY_COMPOSE}" + const val LIFECYCLE_RUNTIME = + "androidx.lifecycle:lifecycle-runtime-ktx:${Version.LIFECYCLE_RUNTIME}" + const val ACTIVITY_COMPOSE = + "androidx.activity:activity-compose:${Version.ACTIVITY_COMPOSE}" + const val VICO_COMPOSE = "com.patrykandpatrick.vico:compose:${Version.VICO}" + const val VICO_COMPOSE_M3 = "com.patrykandpatrick.vico:compose-m3:${Version.VICO}" + const val VICO_CORE = "com.patrykandpatrick.vico:core:${Version.VICO}" const val UI_TOOLING = "androidx.compose.ui:ui-tooling" const val UI_TOOLING_PREVIEW = "androidx.compose.ui:ui-tooling-preview" const val JUNIT = "androidx.compose.ui:ui-test-junit4" @@ -63,8 +68,8 @@ object Dependency { const val BOM = "2023.03.00" const val LIFECYCLE_RUNTIME = "2.7.0" const val ACTIVITY_COMPOSE = "1.8.2" + const val VICO = "2.0.0-alpha.19"// "1.14.0" } - } } diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts index a24633e..2262008 100644 --- a/presentation/build.gradle.kts +++ b/presentation/build.gradle.kts @@ -49,19 +49,24 @@ dependencies { implementation(project(path = ":domain")) implementation(Dependency.Common.HILT) + implementation("androidx.navigation:navigation-runtime-ktx:2.7.7") kapt(Dependency.Common.HILT_COMPILER) - implementation(Dependency.Compose.LIFECYCLE_RUNTIME) - implementation(Dependency.Compose.ACTIVITY_COMPOSE) // 1.9.0 - implementation(platform(Dependency.Compose.BOM)) - implementation(Dependency.Compose.UI) - implementation(Dependency.Compose.UI_GRAPHICS) - implementation(Dependency.Compose.UI_TOOLING_PREVIEW) - implementation(Dependency.Compose.MATERIAL_3) - androidTestImplementation(platform(Dependency.Compose.BOM)) - androidTestImplementation(Dependency.Compose.JUNIT) - debugImplementation(Dependency.Compose.UI_TOOLING) - debugImplementation(Dependency.Compose.UI_TEST_MANIFEST) + implementation(Dependency.Presentation.LIFECYCLE_RUNTIME) + implementation(Dependency.Presentation.ACTIVITY_COMPOSE) // 1.9.0 + implementation(platform(Dependency.Presentation.BOM)) + implementation(Dependency.Presentation.UI) + implementation(Dependency.Presentation.UI_GRAPHICS) + implementation(Dependency.Presentation.UI_TOOLING_PREVIEW) + implementation(Dependency.Presentation.MATERIAL_3) + androidTestImplementation(platform(Dependency.Presentation.BOM)) + androidTestImplementation(Dependency.Presentation.JUNIT) + debugImplementation(Dependency.Presentation.UI_TOOLING) + debugImplementation(Dependency.Presentation.UI_TEST_MANIFEST) + + implementation(Dependency.Presentation.VICO_CORE) + implementation(Dependency.Presentation.VICO_COMPOSE) + implementation(Dependency.Presentation.VICO_COMPOSE_M3) implementation(Dependency.Common.ANDROIDX_CORE) testImplementation(Dependency.Common.JUNIT) From 66b7273e593c8de57ecc84c7201d14f836442ab9 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 11:21:42 +0900 Subject: [PATCH 40/47] =?UTF-8?q?[CT-2-1]=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=88=98=EC=A0=95=20(Tick=20=EC=9D=98=20?= =?UTF-8?q?=EA=B0=80=EA=B2=A9=EB=93=A4=20=ED=83=80=EC=9E=85=20Money?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/yessorae/domain/entity/tick/Tick.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt b/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt index 28f3d42..f5c7eb3 100644 --- a/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt +++ b/domain/src/main/java/com/yessorae/domain/entity/tick/Tick.kt @@ -1,16 +1,17 @@ package com.yessorae.domain.entity.tick +import com.yessorae.domain.entity.value.Money import java.time.LocalDateTime data class Tick( // 시가 - val openPrice: Double, + val openPrice: Money, // 최고가 - val maxPrice: Double, + val maxPrice: Money, // 최저가 - val minPrice: Double, + val minPrice: Money, // 종가 - val closePrice: Double, + val closePrice: Money, // 거래 횟수 val transactionCount: Int, // The Unix Msec timestamp for the start of the aggregate window. @@ -20,5 +21,5 @@ data class Tick( // 거래량가중평균가격. // Volume Weighted Average Price의 약어로, // 조회 대상 종목의 거래일에 발생한 전체 거래대금을 전체 거래량으로 나눈 가격을 의미 - val volumeWeightedAveragePrice: Double + val volumeWeightedAveragePrice: Money ) From d0d5ccead14921643f033b823e8a390703fa230a Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 11:29:19 +0900 Subject: [PATCH 41/47] =?UTF-8?q?[CT-2-1]=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=88=98=EC=A0=95=20(ChartGame=20?= =?UTF-8?q?=EC=97=90=20=EC=83=9D=EC=84=B1=EC=9E=90=20=ED=95=84=EB=93=9C?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=80=ED=84=B0=20=EC=9D=B4=EB=81=8C=EC=96=B4?= =?UTF-8?q?=EC=A7=80=EB=8A=94=20=ED=94=84=EB=A1=9C=ED=8D=BC=ED=8B=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/yessorae/domain/entity/ChartGame.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/domain/src/main/java/com/yessorae/domain/entity/ChartGame.kt b/domain/src/main/java/com/yessorae/domain/entity/ChartGame.kt index 62b3a86..9f5b0ee 100644 --- a/domain/src/main/java/com/yessorae/domain/entity/ChartGame.kt +++ b/domain/src/main/java/com/yessorae/domain/entity/ChartGame.kt @@ -35,6 +35,16 @@ data class ChartGame( .sortedBy { it.startTimestamp } .subList(0, chart.ticks.size - totalTurn + currentTurn - 1) + val ownedStockCount = trades.sumOf { trade -> trade.count } + + private val ownedTotalStockPrice = trades.sumOf { trade -> trade.totalTradeMoney.value } + + val ownedAverageStockPrice = Money(ownedTotalStockPrice / ownedStockCount) + + val currentStockPrice: Money = visibleTicks.last().closePrice + + val currentGameProgress: Float = currentTurn / totalTurn.toFloat() * 100f + // 게임 모든 턴을 끝까지 완료한 경우 true val isGameComplete: Boolean = currentTurn == totalTurn From b443aca9592295a9a746f753f83d1ba3a3863ea8 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 11:30:23 +0900 Subject: [PATCH 42/47] =?UTF-8?q?[CT-2-1]=20UseCase=20invoke=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EC=97=90=20suspend=20=EC=98=88=EC=95=BD=EC=96=B4=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(Flow=20=EB=B0=98=ED=99=98=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=ED=95=98=EC=97=AC=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/usecase/ChangeChartUseCase.kt | 2 +- .../domain/usecase/QuitChartGameUseCase.kt | 2 +- .../domain/usecase/TradeStockUseCase.kt | 33 +++++++++++-------- .../domain/usecase/UpdateNextTickUseCase.kt | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/domain/src/main/java/com/yessorae/domain/usecase/ChangeChartUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/ChangeChartUseCase.kt index 3ead358..a4fe64b 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/ChangeChartUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/ChangeChartUseCase.kt @@ -13,7 +13,7 @@ class ChangeChartUseCase @Inject constructor( private val chartRepository: ChartRepository, private val chartGameRepository: ChartGameRepository ) { - suspend operator fun invoke(gameId: Long): Flow> = + operator fun invoke(gameId: Long): Flow> = flow { val oldChartGame = chartGameRepository.fetchChartGame(gameId = gameId) diff --git a/domain/src/main/java/com/yessorae/domain/usecase/QuitChartGameUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/QuitChartGameUseCase.kt index 91e0586..b4a46ee 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/QuitChartGameUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/QuitChartGameUseCase.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.flow class QuitChartGameUseCase @Inject constructor( private val chartGameRepository: ChartGameRepository ) { - suspend operator fun invoke(gameId: Long): Flow> = + operator fun invoke(gameId: Long): Flow> = flow { val oldChartGame = chartGameRepository.fetchChartGame(gameId = gameId) chartGameRepository.updateChartGame(chartGame = oldChartGame.createFromQuit()) diff --git a/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt index 2348881..f9bd3b6 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt @@ -15,31 +15,36 @@ class TradeStockUseCase @Inject constructor( private val chartGameRepository: ChartGameRepository, private val userRepository: UserRepository ) { - suspend operator fun invoke( - gameId: Long, - ownedAverageStockPrice: Money, - stockPrice: Money, - count: Int, - turn: Int, - type: TradeType + operator fun invoke( + param: Param ): Flow> = flow { val trade = Trade.new( - gameId = gameId, - ownedAverageStockPrice = ownedAverageStockPrice, - stockPrice = stockPrice, - count = count, - turn = turn, - type = type, + gameId = param.gameId, + ownedAverageStockPrice = param.ownedAverageStockPrice, + stockPrice = param.stockPrice, + count = param.count, + turn = param.turn, + type = param.type, commissionRate = userRepository.fetchCommissionRateConfig() ) chartGameRepository.updateChartGame( chartGame = chartGameRepository.fetchChartGame( - gameId = gameId + gameId = param.gameId ).copyFrom( newTrade = trade ) ) }.delegateEmptyResultFlow() + + + data class Param( + val gameId: Long, + val ownedAverageStockPrice: Money, + val stockPrice: Money, + val count: Int, + val turn: Int, + val type: TradeType + ) } diff --git a/domain/src/main/java/com/yessorae/domain/usecase/UpdateNextTickUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/UpdateNextTickUseCase.kt index 7e3e10d..bb2b98a 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/UpdateNextTickUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/UpdateNextTickUseCase.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.flow class UpdateNextTickUseCase @Inject constructor( private val chartGameRepository: ChartGameRepository ) { - suspend operator fun invoke(gameId: Long): Flow> = + operator fun invoke(gameId: Long): Flow> = flow { val newChartGame = chartGameRepository.fetchChartGame(gameId = gameId).getNextTurn() From 47296a63ce5b619d7af28eb53ccf512716ab60d2 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 11:47:35 +0900 Subject: [PATCH 43/47] =?UTF-8?q?[CT-2-1]=20=ED=99=94=EB=A9=B4=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EC=A0=95=EC=9D=98=20(=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/chartgame/model/ChartGameEvent.kt | 9 +++ .../chartgame/model/ChartGameScreenEvent.kt | 5 -- .../chartgame/model/ChartGameScreenState.kt | 19 ------- .../ui/chartgame/model/ChartGameState.kt | 56 +++++++++++++++++++ .../ui/chartgame/model/ChartGameUserAction.kt | 46 ++++++++++++--- .../ui/chartgame/model/TradeOrderKeyPad.kt | 11 ++++ 6 files changed, 113 insertions(+), 33 deletions(-) create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt delete mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt delete mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt new file mode 100644 index 0000000..eeda5ea --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt @@ -0,0 +1,9 @@ +package com.yessorae.presentation.ui.chartgame.model + +sealed interface ChartGameEvent { + object InputBuyingStockCount : ChartGameEvent + object InputSellingStockCount : ChartGameEvent + object TradeFail : ChartGameEvent + object BackToPrev : ChartGameEvent + data class MoveToTradeHistory(val gameId: Long) : ChartGameEvent +} \ No newline at end of file diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt deleted file mode 100644 index 351332a..0000000 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenEvent.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.yessorae.presentation.ui.chartgame.model - -sealed interface ChartGameScreenEvent { - data class Toast(val text: String) : ChartGameScreenEvent -} \ No newline at end of file diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt deleted file mode 100644 index cbf5c23..0000000 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameScreenState.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.yessorae.presentation.ui.chartgame.model - -data class ChartGameScreenState( - val screenTitle: String, - val currentTurn: Int, - val totalTurn: Int, - val gameProgress: Float, - val showLoading: Boolean, - //아래와 같이 라이브러리에 맞춘 형태로 지양하는 UI 모델 형태이다. 변경 고민중. - val transactionVolume: List, - val candleStickChart: CandleStickChartUiState, -) - -data class CandleStickChartUiState( - val opening: List, - val closing: List, - val log: List, - val high: List, -) diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt new file mode 100644 index 0000000..fe334fe --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt @@ -0,0 +1,56 @@ +package com.yessorae.presentation.ui.chartgame.model + +import com.yessorae.domain.entity.tick.Tick + +data class ChartGameScreenState( + val currentTurn: String = "", + val totalTurn: String = "", + val gameProgress: Float = 0f, + val showLoading: Boolean = false, + //아래와 같이 라이브러리에 맞춘 형태로 지양하는 UI 모델 형태이다. 변경 고민중. + val transactionVolume: List = listOf(), + val candleStickChart: CandleStickChartUi = CandleStickChartUi(), + val buyingOrderUi: BuyingOrderUi? = null, + val sellingOrderUi: SellingOrderUi? = null, + val onUserAction: (ChartGameScreenUserAction) -> Unit = {} +) + +data class CandleStickChartUi( + val opening: List = listOf(), + val closing: List = listOf(), + val low: List = listOf(), + val high: List = listOf(), +) + +data class BuyingOrderUi( + val show: Boolean = false, + val showKeyPad: Boolean = false, + val maxAvailableStockCount: Int = 0, + val currentStockPrice: Double = 0.0, + val stockCountInput: String? = null, + val onUserAction: (BuyingOrderUiUserAction) -> Unit = {} +) { + val totalBuyingStockPrice: Double = currentStockPrice * (stockCountInput?.toInt() ?: 0) +} + +data class SellingOrderUi( + val show: Boolean = false, + val showKeyPad: Boolean = false, + val maxAvailableStockCount: Int = 0, + val currentStockPrice: Double = 0.0, + val stockCountInput: String? = null, + val onUserAction: (SellingOrderUiUserAction) -> Unit = {} +) { + val totalSellingStockPrice: Double = currentStockPrice * (stockCountInput?.toInt() ?: 0) +} + +fun List.asTransactionVolume(): List = this.map { tick -> + tick.transactionCount.toDouble() +} + +fun List.asCandleStickChartUiState(): CandleStickChartUi = CandleStickChartUi( + opening = this.map { tick -> tick.openPrice.value }, + closing = this.map { tick -> tick.closePrice.value }, + low = this.map { tick -> tick.minPrice.value }, + high = this.map { tick -> tick.maxPrice.value }, +) diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt index 9749d63..b15bde0 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt @@ -1,11 +1,39 @@ package com.yessorae.presentation.ui.chartgame.model -sealed interface ChartGameUserAction { - object ClickNewChartButton : ChartGameUserAction - object ClickChartGameHistoryButton : ChartGameUserAction - object ClickQuitGameButton : ChartGameUserAction - object ClickStartGameButton : ChartGameUserAction - object ClickBuyButton : ChartGameUserAction - object ClickSellButton : ChartGameUserAction - object ClickNextTickButton : ChartGameUserAction -} \ No newline at end of file +sealed interface ChartGameScreenUserAction { + object ClickNewChartButtonScreen : ChartGameScreenUserAction + object ClickChartGameScreenHistoryButton : ChartGameScreenUserAction + object ClickQuitGameButtonScreen : ChartGameScreenUserAction + object ClickBuyButton : ChartGameScreenUserAction + object ClickSellButton : ChartGameScreenUserAction + object ClickNextTickButton : ChartGameScreenUserAction +} + +sealed interface BuyingOrderUiUserAction { + object ClickInput : BuyingOrderUiUserAction + object ClickSellButton : BuyingOrderUiUserAction + object ClickCancelButton : BuyingOrderUiUserAction + object DoSystemBack : BuyingOrderUiUserAction + data class ClickKeyPad( + val keyPad: TradeOrderKeyPad + ) : BuyingOrderUiUserAction + + data class ClickPercentageShortCut( + val percent: Int + ) : BuyingOrderUiUserAction +} + +sealed interface SellingOrderUiUserAction { + object ClickInput : SellingOrderUiUserAction + object ClickSellingButton : SellingOrderUiUserAction + object ClickCancelButton : SellingOrderUiUserAction + object DoSystemBack : SellingOrderUiUserAction + data class ClickPercentageShortCut( + val percent: Int + ) : SellingOrderUiUserAction + + data class ClickKeyPad( + val keyPad: TradeOrderKeyPad + ) : SellingOrderUiUserAction +} + diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt new file mode 100644 index 0000000..6c9cd9e --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt @@ -0,0 +1,11 @@ +package com.yessorae.presentation.ui.chartgame.model + +sealed interface TradeOrderKeyPad { + data class Number( + val value: String + ) : TradeOrderKeyPad + + object DeleteAll : TradeOrderKeyPad + + object Delete : TradeOrderKeyPad +} \ No newline at end of file From 506b03584842129c62b8f3f3d7934e9f1a9a0f39 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 11:48:05 +0900 Subject: [PATCH 44/47] =?UTF-8?q?[CT-2-1]=20ViewModel=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/chartgame/ChartGameViewModel.kt | 453 ++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt new file mode 100644 index 0000000..6e46d5e --- /dev/null +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt @@ -0,0 +1,453 @@ +package com.yessorae.presentation.ui.chartgame + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.yessorae.domain.common.ChartTrainerLogger +import com.yessorae.domain.common.Result +import com.yessorae.domain.entity.ChartGame +import com.yessorae.domain.entity.trade.TradeType +import com.yessorae.domain.entity.value.Money +import com.yessorae.domain.usecase.ChangeChartUseCase +import com.yessorae.domain.usecase.QuitChartGameUseCase +import com.yessorae.domain.usecase.SubscribeChartGameUseCase +import com.yessorae.domain.usecase.TradeStockUseCase +import com.yessorae.domain.usecase.UpdateNextTickUseCase +import com.yessorae.presentation.ui.chartgame.model.BuyingOrderUi +import com.yessorae.presentation.ui.chartgame.model.BuyingOrderUiUserAction +import com.yessorae.presentation.ui.chartgame.model.ChartGameEvent +import com.yessorae.presentation.ui.chartgame.model.ChartGameScreenState +import com.yessorae.presentation.ui.chartgame.model.ChartGameScreenUserAction +import com.yessorae.presentation.ui.chartgame.model.SellingOrderUi +import com.yessorae.presentation.ui.chartgame.model.SellingOrderUiUserAction +import com.yessorae.presentation.ui.chartgame.model.TradeOrderKeyPad +import com.yessorae.presentation.ui.chartgame.model.asCandleStickChartUiState +import com.yessorae.presentation.ui.chartgame.model.asTransactionVolume +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onSubscription +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ChartGameViewModel @Inject constructor( + private val subscribeChartGameUseCase: SubscribeChartGameUseCase, + private val changeChartUseCase: ChangeChartUseCase, + private val tradeStockUseCase: TradeStockUseCase, + private val updateNextTickUseCase: UpdateNextTickUseCase, + private val quitChartGameUseCase: QuitChartGameUseCase, + private val logger: ChartTrainerLogger, + savedStateHandle: SavedStateHandle +) : ViewModel() { + private val gameIdFromPrevScreen: Long? = savedStateHandle[ARG_KEY_GAME_ID] + + private val _screenState = MutableStateFlow(ChartGameScreenState()) + val screenState: StateFlow = + _screenState + .onSubscription { + subscribeChartGame() + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = ChartGameScreenState() + ) + + private val _screenEvent = MutableSharedFlow() + val screenEvent: SharedFlow = _screenEvent.asSharedFlow() + + private fun subscribeChartGame() = viewModelScope.launch { + subscribeChartGameUseCase(gameId = gameIdFromPrevScreen).collectLatest { result -> + when (result) { + is Result.Loading -> _screenState.update { old -> old.copy(showLoading = true) } + is Result.Success -> updateGameData(result.data) + is Result.Failure -> handleError(result.throwable) + } + } + } + + private fun updateGameData(data: ChartGame) { + _screenState.update { old -> + old.copy( + currentTurn = data.currentTurn.toString(), + totalTurn = data.totalTurn.toString(), + gameProgress = data.currentGameProgress, + showLoading = false, + transactionVolume = data.chart.ticks.asTransactionVolume(), + candleStickChart = data.chart.ticks.asCandleStickChartUiState(), + onUserAction = { userAction -> + handleChartGameScreenUserAction( + userAction = userAction, + gameId = data.id, + ownedAverageStockPrice = data.ownedAverageStockPrice, + currentBalance = data.currentBalance, + currentStockPrice = data.currentStockPrice, + currentTurn = data.currentTurn, + ownedStockCount = data.ownedStockCount + ) + } + ) + } + } + + private fun handleChartGameScreenUserAction( + userAction: ChartGameScreenUserAction, + gameId: Long, + ownedAverageStockPrice: Money, + currentBalance: Money, + currentStockPrice: Money, + currentTurn: Int, + ownedStockCount: Int + ) { + when (userAction) { + is ChartGameScreenUserAction.ClickNewChartButtonScreen -> { + changeChart(gameId = gameId) + } + + is ChartGameScreenUserAction.ClickQuitGameButtonScreen -> { + quitChartGame(gameId = gameId) + } + + is ChartGameScreenUserAction.ClickBuyButton -> { + showBuyOrderUi( + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + currentBalance = currentBalance, + currentStockPrice = currentStockPrice, + currentTurn = currentTurn + ) + } + + is ChartGameScreenUserAction.ClickSellButton -> { + showSellOrderUi( + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + currentStockPrice = currentStockPrice, + currentTurn = currentTurn, + ownedStockCount = ownedStockCount + ) + } + + is ChartGameScreenUserAction.ClickNextTickButton -> { + updateNextTick(gameId = gameId) + } + + is ChartGameScreenUserAction.ClickChartGameScreenHistoryButton -> { + moveToChartTradeHistoryScreen(gameId = gameId) + } + } + } + + private fun changeChart(gameId: Long) { + changeChartUseCase(gameId = gameId).launchIn(viewModelScope) + } + + private fun showBuyOrderUi( + gameId: Long, + ownedAverageStockPrice: Money, + currentBalance: Money, + currentStockPrice: Money, + currentTurn: Int + ) { + val maxAvailableStockCount = (currentBalance / currentStockPrice).value.toInt() + _screenState.update { old -> + old.copy( + buyingOrderUi = BuyingOrderUi( + show = true, + showKeyPad = false, + maxAvailableStockCount = maxAvailableStockCount, + currentStockPrice = currentStockPrice.value, + onUserAction = { userAction -> + handleBuyingOrderUiUserAction( + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + currentStockPrice = currentStockPrice, + currentTurn = currentTurn, + maxAvailableStockCount = maxAvailableStockCount, + userAction = userAction + ) + } + ) + ) + } + } + + private fun handleBuyingOrderUiUserAction( + gameId: Long, + maxAvailableStockCount: Int, + ownedAverageStockPrice: Money, + currentStockPrice: Money, + currentTurn: Int, + userAction: BuyingOrderUiUserAction + ) { + when (userAction) { + is BuyingOrderUiUserAction.ClickInput -> { + _screenState.update { old -> + old.copy( + buyingOrderUi = old.buyingOrderUi?.copy( + showKeyPad = true + ) + ) + } + } + + is BuyingOrderUiUserAction.ClickSellButton -> { + val count = screenState.value.buyingOrderUi?.stockCountInput + + if (count == null) { + emitScreenEvent(event = ChartGameEvent.InputBuyingStockCount) + return + } + + tradeStock( + TradeStockUseCase.Param( + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + stockPrice = currentStockPrice, + count = count.toInt(), + turn = currentTurn, + type = TradeType.Buy + ) + ) + } + + is BuyingOrderUiUserAction.ClickCancelButton -> { + hideBuyOrderUi() + } + + is BuyingOrderUiUserAction.DoSystemBack -> { + hideBuyOrderUi() + } + + is BuyingOrderUiUserAction.ClickPercentageShortCut -> { + _screenState.update { old -> + old.copy( + buyingOrderUi = old.buyingOrderUi?.copy( + stockCountInput = + (maxAvailableStockCount * (userAction.percent / 100.0)).toString() + ) + ) + } + } + + is BuyingOrderUiUserAction.ClickKeyPad -> { + _screenState.update { old -> + old.copy( + buyingOrderUi = old.buyingOrderUi?.copy( + stockCountInput = when (val keyPad = userAction.keyPad) { + is TradeOrderKeyPad.Number -> { + val oldValue = old.buyingOrderUi.stockCountInput ?: "" + val newValue = oldValue + keyPad.value + newValue.toInt().coerceAtMost(maxAvailableStockCount).toString() + } + + is TradeOrderKeyPad.Delete -> { + val oldInput = old.buyingOrderUi.stockCountInput + if (oldInput.isNullOrEmpty()) { + null + } else { + oldInput.take(oldInput.length - 1) + } + } + + is TradeOrderKeyPad.DeleteAll -> null + } + ) + ) + } + } + } + } + + private fun showSellOrderUi( + gameId: Long, + ownedAverageStockPrice: Money, + currentStockPrice: Money, + currentTurn: Int, + ownedStockCount: Int + ) { + _screenState.update { old -> + old.copy( + sellingOrderUi = SellingOrderUi( + show = true, + showKeyPad = false, + maxAvailableStockCount = ownedStockCount, + currentStockPrice = currentStockPrice.value, + onUserAction = { userAction -> + handleSellingOrderUiUserAction( + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + currentStockPrice = currentStockPrice, + currentTurn = currentTurn, + ownedStockCount = ownedStockCount, + userAction = userAction + ) + } + ) + ) + } + } + + private fun handleSellingOrderUiUserAction( + gameId: Long, + ownedAverageStockPrice: Money, + currentStockPrice: Money, + currentTurn: Int, + ownedStockCount: Int, + userAction: SellingOrderUiUserAction + ) { + when (userAction) { + is SellingOrderUiUserAction.ClickInput -> { + _screenState.update { old -> + old.copy( + sellingOrderUi = old.sellingOrderUi?.copy( + showKeyPad = true + ) + ) + } + } + + is SellingOrderUiUserAction.ClickSellingButton -> { + val count = screenState.value.sellingOrderUi?.stockCountInput + + if (count == null) { + emitScreenEvent(event = ChartGameEvent.InputSellingStockCount) + return + } + tradeStock( + tradeStockParam = TradeStockUseCase.Param( + gameId = gameId, + ownedAverageStockPrice = ownedAverageStockPrice, + stockPrice = currentStockPrice, + count = count.toInt(), + turn = currentTurn, + type = TradeType.Sell + ) + ) + } + + is SellingOrderUiUserAction.ClickCancelButton -> { + hideSellOrderUi() + } + + is SellingOrderUiUserAction.DoSystemBack -> { + hideSellOrderUi() + } + + is SellingOrderUiUserAction.ClickPercentageShortCut -> { + _screenState.update { old -> + old.copy( + sellingOrderUi = old.sellingOrderUi?.copy( + stockCountInput = + (ownedStockCount * (userAction.percent / 100.0)).toString() + ) + ) + } + } + + is SellingOrderUiUserAction.ClickKeyPad -> { + _screenState.update { old -> + old.copy( + sellingOrderUi = old.sellingOrderUi?.copy( + stockCountInput = when (val keyPad = userAction.keyPad) { + is TradeOrderKeyPad.Number -> { + val oldValue = old.sellingOrderUi.stockCountInput ?: "" + val newValue = oldValue + keyPad.value + newValue.toInt().coerceAtMost(ownedStockCount).toString() + } + + is TradeOrderKeyPad.Delete -> { + val oldInput = old.sellingOrderUi.stockCountInput + if (oldInput.isNullOrEmpty()) { + null + } else { + oldInput.take(oldInput.length - 1) + } + } + + is TradeOrderKeyPad.DeleteAll -> null + } + ) + ) + } + } + } + } + + + private fun hideBuyOrderUi() { + _screenState.update { old -> + old.copy( + showLoading = false, + buyingOrderUi = BuyingOrderUi() + ) + } + } + + private fun hideSellOrderUi() { + _screenState.update { old -> + old.copy( + showLoading = false, + sellingOrderUi = SellingOrderUi() + ) + } + } + + private fun tradeStock(tradeStockParam: TradeStockUseCase.Param) = viewModelScope.launch { + tradeStockUseCase(param = tradeStockParam).collectLatest { result -> + when (result) { + is Result.Loading -> { + _screenState.update { old -> old.copy(showLoading = true) } + } + + is Result.Success -> { + when (tradeStockParam.type) { + TradeType.Buy -> hideBuyOrderUi() + TradeType.Sell -> hideSellOrderUi() + } + } + + is Result.Failure -> { + emitScreenEvent(ChartGameEvent.TradeFail) + } + } + } + } + + private fun updateNextTick(gameId: Long) { + updateNextTickUseCase(gameId = gameId).launchIn(viewModelScope) + } + + private fun quitChartGame(gameId: Long) { + // TODO::LATER 바로 뒤로가지 않고 컨펌 다이얼로그 보여주기 + quitChartGameUseCase(gameId = gameId).launchIn(viewModelScope) + emitScreenEvent(event = ChartGameEvent.BackToPrev) + } + + private fun moveToChartTradeHistoryScreen(gameId: Long) = viewModelScope.launch { + emitScreenEvent(event = ChartGameEvent.MoveToTradeHistory(gameId = gameId)) + } + + private fun emitScreenEvent(event: ChartGameEvent) = viewModelScope.launch { + _screenEvent.emit(event) + } + + private fun handleError(throwable: Throwable) { + logger.cehLog( + throwable = throwable + ) + } + + companion object { + // navigation 셋업하면서 위치 다른 파일로 이동할 수 있음 + const val ARG_KEY_GAME_ID = "chart_game_id" + } +} From c81a456efa6f7437cf1b7b4f854ca07029ec163e Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 11:50:17 +0900 Subject: [PATCH 45/47] [CT-2-1] chore: ktlintFormat --- .../util/DefaultChartTrainerLoggerImpl.kt | 3 +- .../domain/usecase/TradeStockUseCase.kt | 5 +- .../ui/chartgame/ChartGameViewModel.kt | 61 ++++++++++--------- .../ui/chartgame/model/ChartGameEvent.kt | 2 +- .../ui/chartgame/model/ChartGameState.kt | 24 ++++---- .../ui/chartgame/model/ChartGameUserAction.kt | 1 - .../ui/chartgame/model/TradeOrderKeyPad.kt | 2 +- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt b/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt index d5e3ff3..1ee7322 100644 --- a/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt +++ b/data/src/main/java/com/yessorae/data/util/DefaultChartTrainerLoggerImpl.kt @@ -20,9 +20,8 @@ class DefaultChartTrainerLoggerImpl @Inject constructor() : ChartTrainerLogger { // crashlytics 같은 것을 추가할 수 있음 } - companion object { const val TAG = "SR-N" const val STACK_TRACE_DEPTH = 5 } -} \ No newline at end of file +} diff --git a/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt b/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt index f9bd3b6..212f5ad 100644 --- a/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt +++ b/domain/src/main/java/com/yessorae/domain/usecase/TradeStockUseCase.kt @@ -15,9 +15,7 @@ class TradeStockUseCase @Inject constructor( private val chartGameRepository: ChartGameRepository, private val userRepository: UserRepository ) { - operator fun invoke( - param: Param - ): Flow> = + operator fun invoke(param: Param): Flow> = flow { val trade = Trade.new( gameId = param.gameId, @@ -38,7 +36,6 @@ class TradeStockUseCase @Inject constructor( ) }.delegateEmptyResultFlow() - data class Param( val gameId: Long, val ownedAverageStockPrice: Money, diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt index 6e46d5e..9098fca 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt @@ -24,6 +24,7 @@ import com.yessorae.presentation.ui.chartgame.model.TradeOrderKeyPad import com.yessorae.presentation.ui.chartgame.model.asCandleStickChartUiState import com.yessorae.presentation.ui.chartgame.model.asTransactionVolume import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow @@ -36,7 +37,6 @@ import kotlinx.coroutines.flow.onSubscription import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import javax.inject.Inject @HiltViewModel class ChartGameViewModel @Inject constructor( @@ -64,15 +64,16 @@ class ChartGameViewModel @Inject constructor( private val _screenEvent = MutableSharedFlow() val screenEvent: SharedFlow = _screenEvent.asSharedFlow() - private fun subscribeChartGame() = viewModelScope.launch { - subscribeChartGameUseCase(gameId = gameIdFromPrevScreen).collectLatest { result -> - when (result) { - is Result.Loading -> _screenState.update { old -> old.copy(showLoading = true) } - is Result.Success -> updateGameData(result.data) - is Result.Failure -> handleError(result.throwable) + private fun subscribeChartGame() = + viewModelScope.launch { + subscribeChartGameUseCase(gameId = gameIdFromPrevScreen).collectLatest { result -> + when (result) { + is Result.Loading -> _screenState.update { old -> old.copy(showLoading = true) } + is Result.Success -> updateGameData(result.data) + is Result.Failure -> handleError(result.throwable) + } } } - } private fun updateGameData(data: ChartGame) { _screenState.update { old -> @@ -382,7 +383,6 @@ class ChartGameViewModel @Inject constructor( } } - private fun hideBuyOrderUi() { _screenState.update { old -> old.copy( @@ -401,26 +401,27 @@ class ChartGameViewModel @Inject constructor( } } - private fun tradeStock(tradeStockParam: TradeStockUseCase.Param) = viewModelScope.launch { - tradeStockUseCase(param = tradeStockParam).collectLatest { result -> - when (result) { - is Result.Loading -> { - _screenState.update { old -> old.copy(showLoading = true) } - } + private fun tradeStock(tradeStockParam: TradeStockUseCase.Param) = + viewModelScope.launch { + tradeStockUseCase(param = tradeStockParam).collectLatest { result -> + when (result) { + is Result.Loading -> { + _screenState.update { old -> old.copy(showLoading = true) } + } - is Result.Success -> { - when (tradeStockParam.type) { - TradeType.Buy -> hideBuyOrderUi() - TradeType.Sell -> hideSellOrderUi() + is Result.Success -> { + when (tradeStockParam.type) { + TradeType.Buy -> hideBuyOrderUi() + TradeType.Sell -> hideSellOrderUi() + } } - } - is Result.Failure -> { - emitScreenEvent(ChartGameEvent.TradeFail) + is Result.Failure -> { + emitScreenEvent(ChartGameEvent.TradeFail) + } } } } - } private fun updateNextTick(gameId: Long) { updateNextTickUseCase(gameId = gameId).launchIn(viewModelScope) @@ -432,13 +433,15 @@ class ChartGameViewModel @Inject constructor( emitScreenEvent(event = ChartGameEvent.BackToPrev) } - private fun moveToChartTradeHistoryScreen(gameId: Long) = viewModelScope.launch { - emitScreenEvent(event = ChartGameEvent.MoveToTradeHistory(gameId = gameId)) - } + private fun moveToChartTradeHistoryScreen(gameId: Long) = + viewModelScope.launch { + emitScreenEvent(event = ChartGameEvent.MoveToTradeHistory(gameId = gameId)) + } - private fun emitScreenEvent(event: ChartGameEvent) = viewModelScope.launch { - _screenEvent.emit(event) - } + private fun emitScreenEvent(event: ChartGameEvent) = + viewModelScope.launch { + _screenEvent.emit(event) + } private fun handleError(throwable: Throwable) { logger.cehLog( diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt index eeda5ea..b08d434 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt @@ -6,4 +6,4 @@ sealed interface ChartGameEvent { object TradeFail : ChartGameEvent object BackToPrev : ChartGameEvent data class MoveToTradeHistory(val gameId: Long) : ChartGameEvent -} \ No newline at end of file +} diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt index fe334fe..9a5c791 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameState.kt @@ -7,7 +7,7 @@ data class ChartGameScreenState( val totalTurn: String = "", val gameProgress: Float = 0f, val showLoading: Boolean = false, - //아래와 같이 라이브러리에 맞춘 형태로 지양하는 UI 모델 형태이다. 변경 고민중. + // 아래와 같이 라이브러리에 맞춘 형태로 지양하는 UI 모델 형태이다. 변경 고민중. val transactionVolume: List = listOf(), val candleStickChart: CandleStickChartUi = CandleStickChartUi(), val buyingOrderUi: BuyingOrderUi? = null, @@ -19,7 +19,7 @@ data class CandleStickChartUi( val opening: List = listOf(), val closing: List = listOf(), val low: List = listOf(), - val high: List = listOf(), + val high: List = listOf() ) data class BuyingOrderUi( @@ -44,13 +44,15 @@ data class SellingOrderUi( val totalSellingStockPrice: Double = currentStockPrice * (stockCountInput?.toInt() ?: 0) } -fun List.asTransactionVolume(): List = this.map { tick -> - tick.transactionCount.toDouble() -} +fun List.asTransactionVolume(): List = + this.map { tick -> + tick.transactionCount.toDouble() + } -fun List.asCandleStickChartUiState(): CandleStickChartUi = CandleStickChartUi( - opening = this.map { tick -> tick.openPrice.value }, - closing = this.map { tick -> tick.closePrice.value }, - low = this.map { tick -> tick.minPrice.value }, - high = this.map { tick -> tick.maxPrice.value }, -) +fun List.asCandleStickChartUiState(): CandleStickChartUi = + CandleStickChartUi( + opening = this.map { tick -> tick.openPrice.value }, + closing = this.map { tick -> tick.closePrice.value }, + low = this.map { tick -> tick.minPrice.value }, + high = this.map { tick -> tick.maxPrice.value } + ) diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt index b15bde0..d163c60 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameUserAction.kt @@ -36,4 +36,3 @@ sealed interface SellingOrderUiUserAction { val keyPad: TradeOrderKeyPad ) : SellingOrderUiUserAction } - diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt index 6c9cd9e..09ba627 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/TradeOrderKeyPad.kt @@ -8,4 +8,4 @@ sealed interface TradeOrderKeyPad { object DeleteAll : TradeOrderKeyPad object Delete : TradeOrderKeyPad -} \ No newline at end of file +} From 0e5f0bd5cd6c0887940b6fa2fd3a465808bed8f8 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 13:50:49 +0900 Subject: [PATCH 46/47] =?UTF-8?q?[CT-2-1]=20=ED=99=94=EB=A9=B4=20=EB=92=A4?= =?UTF-8?q?=EB=A1=9C=EA=B0=80=EA=B8=B0=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yessorae/presentation/ui/chartgame/ChartGameViewModel.kt | 2 +- .../yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt index 9098fca..9daacf8 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/ChartGameViewModel.kt @@ -430,7 +430,7 @@ class ChartGameViewModel @Inject constructor( private fun quitChartGame(gameId: Long) { // TODO::LATER 바로 뒤로가지 않고 컨펌 다이얼로그 보여주기 quitChartGameUseCase(gameId = gameId).launchIn(viewModelScope) - emitScreenEvent(event = ChartGameEvent.BackToPrev) + emitScreenEvent(event = ChartGameEvent.MoveToBack) } private fun moveToChartTradeHistoryScreen(gameId: Long) = diff --git a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt index b08d434..db62586 100644 --- a/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt +++ b/presentation/src/main/java/com/yessorae/presentation/ui/chartgame/model/ChartGameEvent.kt @@ -4,6 +4,6 @@ sealed interface ChartGameEvent { object InputBuyingStockCount : ChartGameEvent object InputSellingStockCount : ChartGameEvent object TradeFail : ChartGameEvent - object BackToPrev : ChartGameEvent + object MoveToBack : ChartGameEvent data class MoveToTradeHistory(val gameId: Long) : ChartGameEvent } From db60f99054de9eacea03d59126f25865d733b614 Mon Sep 17 00:00:00 2001 From: yessorae Date: Sun, 26 May 2024 14:17:40 +0900 Subject: [PATCH 47/47] =?UTF-8?q?[CT-2-1]=20=EB=B9=8C=EB=93=9C=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=88=98=EC=A0=95=20(=ED=81=B4=EB=9E=98=EC=8A=A4-?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=94=EC=9D=B8=EB=94=A9,=20Tick=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=9C=20=EA=B2=83=20=EB=B0=98=EC=98=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yessorae/data/di/DataSourceModule.kt | 8 +++++ .../com/yessorae/data/di/RepositoryModule.kt | 31 +++++++++++++++++++ .../source/local/database/model/TickEntity.kt | 11 ++++--- .../network/polygon/model/chart/TickDto.kt | 11 ++++--- .../ChartTrainerDatabaseTransactionHelper.kt | 4 +-- 5 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 data/src/main/java/com/yessorae/data/di/RepositoryModule.kt diff --git a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt index b08e981..20f5987 100644 --- a/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt +++ b/data/src/main/java/com/yessorae/data/di/DataSourceModule.kt @@ -1,6 +1,8 @@ package com.yessorae.data.di import com.yessorae.data.source.ChartNetworkDataSource +import com.yessorae.data.source.ChartTrainerLocalDBDataSource +import com.yessorae.data.source.local.database.ChartTrainerLocalDBDataSourceImpl import com.yessorae.data.source.network.polygon.PolygonChartNetworkDataSource import dagger.Binds import dagger.Module @@ -16,4 +18,10 @@ abstract class DataSourceModule { abstract fun bindsChartNetworkDataSource( polygonChartNetworkDataSource: PolygonChartNetworkDataSource ): ChartNetworkDataSource + + @Binds + @Singleton + abstract fun bindsChartTrainerLocalDBDataSource( + chartTrainerLocalDBDataSource: ChartTrainerLocalDBDataSourceImpl + ): ChartTrainerLocalDBDataSource } diff --git a/data/src/main/java/com/yessorae/data/di/RepositoryModule.kt b/data/src/main/java/com/yessorae/data/di/RepositoryModule.kt new file mode 100644 index 0000000..a31cd15 --- /dev/null +++ b/data/src/main/java/com/yessorae/data/di/RepositoryModule.kt @@ -0,0 +1,31 @@ +package com.yessorae.data.di + +import com.yessorae.data.repository.ChartGameRepositoryImpl +import com.yessorae.data.repository.ChartRepositoryImpl +import com.yessorae.data.repository.UserRepositoryImpl +import com.yessorae.domain.repository.ChartGameRepository +import com.yessorae.domain.repository.ChartRepository +import com.yessorae.domain.repository.UserRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class RepositoryModule { + @Binds + @Singleton + abstract fun bindsChartGameRepository( + chartGameRepository: ChartGameRepositoryImpl + ): ChartGameRepository + + @Binds + @Singleton + abstract fun bindsChartRepository(chartRepository: ChartRepositoryImpl): ChartRepository + + @Binds + @Singleton + abstract fun bindsUserRepository(userRepository: UserRepositoryImpl): UserRepository +} diff --git a/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt index 8b5af63..9df06aa 100644 --- a/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt +++ b/data/src/main/java/com/yessorae/data/source/local/database/model/TickEntity.kt @@ -4,6 +4,7 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import com.yessorae.domain.entity.tick.Tick +import com.yessorae.domain.entity.value.Money import java.time.LocalDateTime @Entity(tableName = TickEntity.NAME) @@ -45,12 +46,12 @@ data class TickEntity( fun TickEntity.asDomainModel() = Tick( - openPrice = openPrice, - maxPrice = maxPrice, - minPrice = minPrice, - closePrice = closePrice, + openPrice = Money(openPrice), + maxPrice = Money(maxPrice), + minPrice = Money(minPrice), + closePrice = Money(closePrice), transactionCount = transactionCount, startTimestamp = startTimestamp, tradingVolume = tradingVolume, - volumeWeightedAveragePrice = volumeWeightedAveragePrice + volumeWeightedAveragePrice = Money(volumeWeightedAveragePrice) ) diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt index 35c50dd..6975fe3 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/model/chart/TickDto.kt @@ -3,6 +3,7 @@ package com.yessorae.data.source.network.polygon.model.chart import com.google.gson.annotations.SerializedName import com.yessorae.data.util.toLocalDateTime import com.yessorae.domain.entity.tick.Tick +import com.yessorae.domain.entity.value.Money data class TickDto( @SerializedName("c") @@ -25,12 +26,12 @@ data class TickDto( internal fun TickDto.asDomainModel() = Tick( - openPrice = openPrice, - closePrice = closePrice, - maxPrice = maxPrice, - minPrice = minPrice, + openPrice = Money(openPrice), + closePrice = Money(closePrice), + maxPrice = Money(maxPrice), + minPrice = Money(minPrice), transactionCount = transactionCount, startTimestamp = startTimestamp.toLocalDateTime(), tradingVolume = tradingVolume, - volumeWeightedAveragePrice = volumeWeightedAveragePrice + volumeWeightedAveragePrice = Money(volumeWeightedAveragePrice) ) diff --git a/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt b/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt index 62efbcb..4684052 100644 --- a/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt +++ b/data/src/main/java/com/yessorae/data/source/network/polygon/util/ChartTrainerDatabaseTransactionHelper.kt @@ -1,11 +1,11 @@ package com.yessorae.data.source.network.polygon.util -import androidx.room.RoomDatabase import androidx.room.withTransaction +import com.yessorae.data.source.local.database.ChartTrainerDatabase import javax.inject.Inject class ChartTrainerDatabaseTransactionHelper @Inject constructor( - private val roomDatabase: RoomDatabase + private val roomDatabase: ChartTrainerDatabase ) : DatabaseTransactionHelper { override suspend fun runTransaction(run: suspend () -> Unit) { roomDatabase.withTransaction(run)